mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-13 18:32:12 +03:00
Validado numa worktree combinada com as 16 PRs desta leva sobre `release/v3.8.51`: typecheck:core limpo, check-file-size e check-changelog-integrity OK, complexity 2788/3218 e cognitive 1261/1437, ESLint 0 erros nos 152 arquivos alterados, 771 testes unitários focados, 49 de integração e a suíte vitest:ui completa (2149) verdes. O ponto que sustenta a PR é o `models.dev` virar overlay de preço em vez de fonte de catálogo. Um catálogo estático que sobrevive à conta já ter listado ids mais novos é o tipo de defeito que só aparece quando o modelo novo é justamente o que se quer usar. Nota de integração: `activeSyncedCatalog.ts` colidiu com o #12934 (união dos `customModels` do picker no catálogo de despacho). Como você extraiu o bloco original para `loadConnectionCatalog`, os dois se compõem: a união dos irmãos agy/antigravity primeiro, o `unionCustomModels` por cima. Revalidei com `custom-models-live-catalog-12597`, `live-model-catalog-reconciliation-8926`, `sync-models-degraded-cached-catalog-9683`, `models-dev-catalog-read-gate`, `discovery-class`, `reactive-model-sync` e `l1-oauth-autosync-default` juntos — 48/48 — mais typecheck:core limpo. Sobre o `autoSync` padrão em Claude/Codex/Copilot com scheduler de 6h: passei isso pelo dono antes de mergear e a decisão foi manter como está.
130 lines
5.3 KiB
TypeScript
130 lines
5.3 KiB
TypeScript
/**
|
|
* tests/unit/claude-codex-identity-version-sync.test.ts
|
|
*
|
|
* Guards the pinned CLI identity versions against drift. The Claude Code version
|
|
* lives in FOUR places (claudeIdentity, anthropicHeaders, claudeCodeCompatible,
|
|
* ccBridgeTransforms) and MUST stay in lockstep — a partial bump produces an
|
|
* inconsistent wire fingerprint. The Codex client version lives in codexClient.
|
|
*
|
|
* When you capture a newer claude-cli / codex release, bump ALL constants and
|
|
* update the pinned values below in the same change.
|
|
*/
|
|
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
const id = await import("../../open-sse/executors/claudeIdentity.ts");
|
|
const hdr = await import("../../open-sse/config/anthropicHeaders.ts");
|
|
const compat = await import("../../open-sse/services/claudeCodeCompatible.ts");
|
|
const bridge = await import("../../open-sse/services/ccBridgeTransforms.ts");
|
|
const codexCfg = await import("../../open-sse/config/codexClient.ts");
|
|
const canonical = await import("../../src/shared/constants/claudeCodeClient.ts");
|
|
|
|
test("Claude CLI version constants are in lockstep across all 4 sources", () => {
|
|
const V = canonical.CLAUDE_CODE_CLIENT_VERSION;
|
|
assert.equal(id.CLAUDE_CODE_VERSION, V, "claudeIdentity.CLAUDE_CODE_VERSION drift");
|
|
assert.equal(hdr.CLAUDE_CLI_VERSION, V, "anthropicHeaders.CLAUDE_CLI_VERSION drift");
|
|
assert.equal(compat.CLAUDE_CODE_COMPATIBLE_VERSION, V, "claudeCodeCompatible version drift");
|
|
assert.equal(bridge.DEFAULT_CLAUDE_CODE_VERSION, V, "ccBridgeTransforms version drift");
|
|
assert.equal(
|
|
hdr.CLAUDE_CLI_USER_AGENT,
|
|
`claude-cli/${V} (external, cli)`,
|
|
"CLAUDE_CLI_USER_AGENT drift"
|
|
);
|
|
assert.equal(
|
|
compat.CLAUDE_CODE_COMPATIBLE_USER_AGENT,
|
|
`claude-cli/${V} (external, sdk-cli)`,
|
|
"CLAUDE_CODE_COMPATIBLE_USER_AGENT drift"
|
|
);
|
|
});
|
|
|
|
test("Claude CLI wire versions match the captured 2.1.258 binary", () => {
|
|
assert.equal(canonical.CLAUDE_CODE_CLIENT_VERSION, "2.1.258");
|
|
assert.equal(canonical.CLAUDE_CODE_CLIENT_BUILD_REVISION, "1e2");
|
|
assert.equal(canonical.CLAUDE_CODE_CLIENT_BILLING_VERSION, "2.1.258.1e2");
|
|
assert.equal(canonical.CLAUDE_CODE_SDK_PACKAGE_VERSION, "0.112.1");
|
|
assert.equal(canonical.CLAUDE_CODE_RUNTIME_VERSION, "v26.3.0");
|
|
assert.equal(
|
|
compat.CLAUDE_CODE_COMPATIBLE_STAINLESS_PACKAGE_VERSION,
|
|
canonical.CLAUDE_CODE_SDK_PACKAGE_VERSION
|
|
);
|
|
assert.equal(
|
|
compat.CLAUDE_CODE_COMPATIBLE_STAINLESS_RUNTIME_VERSION,
|
|
canonical.CLAUDE_CODE_RUNTIME_VERSION
|
|
);
|
|
assert.equal(hdr.CLAUDE_CLI_STAINLESS_PACKAGE_VERSION, canonical.CLAUDE_CODE_SDK_PACKAGE_VERSION);
|
|
assert.equal(hdr.CLAUDE_CLI_STAINLESS_RUNTIME_VERSION, canonical.CLAUDE_CODE_RUNTIME_VERSION);
|
|
assert.equal(hdr.CLAUDE_CLI_BILLING_VERSION, canonical.CLAUDE_CODE_CLIENT_BILLING_VERSION);
|
|
});
|
|
|
|
async function withEnv<T>(
|
|
entries: Record<string, string | undefined>,
|
|
fn: () => T | Promise<T>
|
|
): Promise<T> {
|
|
const previous = new Map<string, string | undefined>();
|
|
for (const [key, value] of Object.entries(entries)) {
|
|
previous.set(key, process.env[key]);
|
|
if (value === undefined) {
|
|
delete process.env[key];
|
|
} else {
|
|
process.env[key] = value;
|
|
}
|
|
}
|
|
try {
|
|
return await fn();
|
|
} finally {
|
|
for (const [key, value] of previous.entries()) {
|
|
if (value === undefined) {
|
|
delete process.env[key];
|
|
} else {
|
|
process.env[key] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
test("Codex client version locksteps Dockerfile @openai/codex", () => {
|
|
const dockerfile = fs.readFileSync(path.join(process.cwd(), "Dockerfile"), "utf8");
|
|
const match = dockerfile.match(/@openai\/codex@([0-9]+\.[0-9]+\.[0-9]+)/);
|
|
assert.ok(match, "Dockerfile must pin @openai/codex@x.y.z");
|
|
const pinned = match[1];
|
|
assert.notEqual(pinned, "0.149.0");
|
|
assert.equal(codexCfg.DEFAULT_CODEX_CLIENT_VERSION, pinned);
|
|
assert.equal(codexCfg.getCodexClientVersion(), pinned);
|
|
assert.equal(codexCfg.getCodexDefaultHeaders().Version, pinned);
|
|
assert.equal(
|
|
codexCfg.getCodexCliRsHeaders()["User-Agent"],
|
|
`codex_cli_rs/${pinned}`,
|
|
);
|
|
});
|
|
|
|
test("Codex client version env override still wins", async () => {
|
|
await withEnv({ CODEX_CLIENT_VERSION: "0.99.0" }, () => {
|
|
assert.equal(codexCfg.getCodexClientVersion(), "0.99.0");
|
|
assert.equal(codexCfg.getCodexDefaultHeaders().Version, "0.99.0");
|
|
});
|
|
});
|
|
|
|
test("test 7: live-empty GitHub catalog path does not call persist", () => {
|
|
const src = fs.readFileSync(
|
|
path.join(process.cwd(), "src/app/api/providers/[id]/models/route.ts"),
|
|
"utf8",
|
|
);
|
|
// The githubCatalogModels fallback must use buildResponse, not buildApiDiscoveryResponse.
|
|
const idx = src.indexOf("Codex live catalog unavailable — using GitHub model catalog");
|
|
assert.ok(idx > 0);
|
|
const start = src.lastIndexOf("if (githubCatalogModels", idx);
|
|
const end = src.indexOf("if (cachedDiscoveryModels", idx);
|
|
assert.ok(start > 0 && end > start);
|
|
const window = src.slice(start, end);
|
|
assert.match(window, /buildResponse\s*\(/);
|
|
assert.doesNotMatch(window, /buildApiDiscoveryResponse\s*\(/);
|
|
|
|
const liveIdx = src.lastIndexOf("if (liveModels && liveModels.length > 0)");
|
|
assert.ok(liveIdx > 0 && liveIdx < start);
|
|
const liveWindow = src.slice(liveIdx, start);
|
|
assert.match(liveWindow, /buildApiDiscoveryResponse\s*\(/);
|
|
});
|