Preserve the active worktree snapshot on dev for follow-on integration

The root checkout already contained a large in-progress proxy, transformer,
and settings refactor. This commit captures that exact work on a dedicated
local dev branch without disturbing the original dirty worktree, so the
changes can be continued or split from dev instead of living only as
uncommitted state.

Constraint: The source checkout was already dirty on another branch, so the move had to preserve that worktree while excluding local .idea and .omx residue from the commit
Rejected: Switch the dirty root checkout directly to dev | risked disrupting the original branch and in-progress state
Confidence: medium
Scope-risk: broad
Reversibility: clean
Directive: Treat this as a transfer snapshot; fix the failing oauth/accountTokens/normalized/docs test regressions before merge or publication
Tested: git diff --check; npm run typecheck; npm run repo:drift-check
Not-tested: Clean test pass; npm test currently fails in oauth routes, accountTokens sync, shared normalized helpers, gemini route expectations, architecture-boundaries, and docs vitepress config
This commit is contained in:
cita-777
2026-04-17 19:41:14 +08:00
parent 6cca74b039
commit 88f40e91f7
133 changed files with 13780 additions and 5670 deletions
@@ -0,0 +1,44 @@
import { describe, expect, it } from 'vitest';
import {
detectCodexOfficialClientApp,
inferCodexOfficialOriginator,
isCodexOfficialClientHeaders,
} from './codexClientFamily.js';
describe('codexClientFamily helpers', () => {
it('detects official codex clients from user-agent and canonicalizes their originator', () => {
expect(detectCodexOfficialClientApp({
'user-agent': 'Mozilla/5.0 codex_exec/1.2.3',
})).toEqual({
clientAppId: 'codex_exec',
clientAppName: 'Codex Exec',
originator: 'codex_exec',
});
expect(inferCodexOfficialOriginator({
'user-agent': 'Mozilla/5.0 codex_chatgpt_desktop/1.2.3',
})).toBe('codex_chatgpt_desktop');
});
it('canonicalizes legacy originator spellings for official codex desktop clients', () => {
expect(detectCodexOfficialClientApp({
originator: 'Codex Desktop',
})).toEqual({
clientAppId: 'codex_chatgpt_desktop',
clientAppName: 'Codex Desktop',
originator: 'codex_chatgpt_desktop',
});
expect(inferCodexOfficialOriginator({
originator: 'Codex Desktop',
})).toBe('codex_chatgpt_desktop');
});
it('keeps generic codex family detection broad without inventing a specific originator', () => {
expect(isCodexOfficialClientHeaders({
'user-agent': 'Codex 1.0',
})).toBe(true);
expect(inferCodexOfficialOriginator({
'user-agent': 'Codex 1.0',
})).toBeNull();
});
});
+166
View File
@@ -0,0 +1,166 @@
type CodexOfficialClientRule = {
clientAppId: string;
clientAppName: string;
originator: string;
userAgentPrefixes: readonly string[];
originatorPrefixes: readonly string[];
};
export type CodexOfficialClientApp = Pick<
CodexOfficialClientRule,
'clientAppId' | 'clientAppName' | 'originator'
>;
const CODEX_OFFICIAL_CLIENT_RULES: readonly CodexOfficialClientRule[] = [
{
clientAppId: 'codex_cli_rs',
clientAppName: 'Codex CLI',
originator: 'codex_cli_rs',
userAgentPrefixes: ['codex_cli_rs/'],
originatorPrefixes: ['codex_cli_rs'],
},
{
clientAppId: 'codex_vscode',
clientAppName: 'Codex VSCode',
originator: 'codex_vscode',
userAgentPrefixes: ['codex_vscode/'],
originatorPrefixes: ['codex_vscode'],
},
{
clientAppId: 'codex_app',
clientAppName: 'Codex App',
originator: 'codex_app',
userAgentPrefixes: ['codex_app/'],
originatorPrefixes: ['codex_app'],
},
{
clientAppId: 'codex_chatgpt_desktop',
clientAppName: 'Codex Desktop',
originator: 'codex_chatgpt_desktop',
userAgentPrefixes: ['codex_chatgpt_desktop/', 'codex desktop/'],
originatorPrefixes: ['codex_chatgpt_desktop', 'codex desktop'],
},
{
clientAppId: 'codex_atlas',
clientAppName: 'Codex Atlas',
originator: 'codex_atlas',
userAgentPrefixes: ['codex_atlas/'],
originatorPrefixes: ['codex_atlas'],
},
{
clientAppId: 'codex_exec',
clientAppName: 'Codex Exec',
originator: 'codex_exec',
userAgentPrefixes: ['codex_exec/'],
originatorPrefixes: ['codex_exec'],
},
{
clientAppId: 'codex_sdk_ts',
clientAppName: 'Codex SDK TS',
originator: 'codex_sdk_ts',
userAgentPrefixes: ['codex_sdk_ts/'],
originatorPrefixes: ['codex_sdk_ts'],
},
];
const CODEX_OFFICIAL_CLIENT_USER_AGENT_PREFIXES = [
...new Set(CODEX_OFFICIAL_CLIENT_RULES.flatMap((rule) => rule.userAgentPrefixes)),
'codex ',
] as const;
const CODEX_OFFICIAL_CLIENT_ORIGINATOR_PREFIXES = [
'codex_',
'codex ',
] as const;
function normalizeHeaderValue(value: string): string {
return value.trim().toLowerCase();
}
function headerValueToStrings(value: unknown): string[] {
if (typeof value === 'string') {
const trimmed = value.trim();
return trimmed ? [trimmed] : [];
}
if (!Array.isArray(value)) return [];
const values: string[] = [];
for (const item of value) {
if (typeof item !== 'string') continue;
const trimmed = item.trim();
if (trimmed) values.push(trimmed);
}
return values;
}
function getHeaderValues(
headers: Record<string, unknown> | undefined,
targetKey: string,
): string[] {
if (!headers) return [];
const normalizedTarget = normalizeHeaderValue(targetKey);
const values: string[] = [];
for (const [rawKey, rawValue] of Object.entries(headers)) {
if (normalizeHeaderValue(rawKey) !== normalizedTarget) continue;
values.push(...headerValueToStrings(rawValue));
}
return values;
}
function matchesCodexClientPrefixes(
value: string | string[] | null | undefined,
prefixes: readonly string[],
): boolean {
const normalizedValues = Array.isArray(value)
? value.map((item) => normalizeHeaderValue(item)).filter(Boolean)
: (typeof value === 'string' ? [normalizeHeaderValue(value)] : []).filter(Boolean);
if (normalizedValues.length <= 0) return false;
return normalizedValues.some((normalizedValue) => prefixes.some((prefix) => {
const normalizedPrefix = normalizeHeaderValue(prefix);
return !!normalizedPrefix
&& (normalizedValue.startsWith(normalizedPrefix) || normalizedValue.includes(normalizedPrefix));
}));
}
export function detectCodexOfficialClientApp(
headers?: Record<string, unknown>,
): CodexOfficialClientApp | null {
for (const rule of CODEX_OFFICIAL_CLIENT_RULES) {
const matchesOriginator = matchesCodexClientPrefixes(
getHeaderValues(headers, 'originator'),
rule.originatorPrefixes,
);
const matchesUserAgent = matchesCodexClientPrefixes(
getHeaderValues(headers, 'user-agent'),
rule.userAgentPrefixes,
);
if (!matchesOriginator && !matchesUserAgent) continue;
return {
clientAppId: rule.clientAppId,
clientAppName: rule.clientAppName,
originator: rule.originator,
};
}
return null;
}
export function inferCodexOfficialOriginator(
headers?: Record<string, unknown>,
): string | null {
return detectCodexOfficialClientApp(headers)?.originator || null;
}
export function isCodexOfficialClientHeaders(
headers?: Record<string, unknown>,
): boolean {
if (detectCodexOfficialClientApp(headers)) return true;
return matchesCodexClientPrefixes(
getHeaderValues(headers, 'originator'),
CODEX_OFFICIAL_CLIENT_ORIGINATOR_PREFIXES,
) || matchesCodexClientPrefixes(
getHeaderValues(headers, 'user-agent'),
CODEX_OFFICIAL_CLIENT_USER_AGENT_PREFIXES,
);
}