diff --git a/docs/system-architecture/target-adapters.md b/docs/system-architecture/target-adapters.md index 6d785128..a2b11eb4 100644 --- a/docs/system-architecture/target-adapters.md +++ b/docs/system-architecture/target-adapters.md @@ -136,7 +136,7 @@ export function resolveTargetType( // 4. Check profile config if (profileConfig?.target) { - // Persisted targets intentionally exclude runtime-only codex. + // Persisted targets are validated before profile configuration is saved. return profileConfig.target; } diff --git a/src/cliproxy/quota/quota-manager.ts b/src/cliproxy/quota/quota-manager.ts index 8574b079..041e2748 100644 --- a/src/cliproxy/quota/quota-manager.ts +++ b/src/cliproxy/quota/quota-manager.ts @@ -483,9 +483,8 @@ export async function reconcileExhaustedRotationAccounts( return []; } - const { pauseAccountForQuotaCooldown, restoreExpiredQuotaPauses } = await import( - '../accounts/account-safety' - ); + const { pauseAccountForQuotaCooldown, restoreExpiredQuotaPauses } = + await import('../accounts/account-safety'); restoreExpiredQuotaPauses(); const config = loadOrCreateUnifiedConfig(); @@ -593,9 +592,8 @@ export async function preflightCheck(provider: CLIProxyProvider): Promise', 'command')} Default target: claude or droid (create)` + ` ${color('--target ', 'command')} Default target: claude, droid, or codex (create)` ); writeLine(` ${color('--register', 'command')} Register discovered orphan settings`); writeLine(` ${color('--json', 'command')} JSON output for discover command`); diff --git a/src/management/checks/image-analysis-check.ts b/src/management/checks/image-analysis-check.ts index 50e9ba99..d6d2dc05 100644 --- a/src/management/checks/image-analysis-check.ts +++ b/src/management/checks/image-analysis-check.ts @@ -112,9 +112,8 @@ export async function runImageAnalysisCheck(results: HealthCheck): Promise * Fix image analysis configuration issues */ export async function fixImageAnalysisConfig(): Promise { - const { updateConfig, loadOrCreateUnifiedConfig } = await import( - '../../config/config-loader-facade' - ); + const { updateConfig, loadOrCreateUnifiedConfig } = + await import('../../config/config-loader-facade'); const config = loadOrCreateUnifiedConfig(); let fixed = false; diff --git a/src/targets/target-metadata.ts b/src/targets/target-metadata.ts index 035ba432..00b2f60c 100644 --- a/src/targets/target-metadata.ts +++ b/src/targets/target-metadata.ts @@ -23,7 +23,7 @@ export const TARGET_METADATA: Record = { displayName: 'Codex CLI', runtimeAliases: ['ccs-codex', 'ccsx', 'ccsxp'], legacyAliasEnvVar: 'CCS_CODEX_ALIASES', - persistedTarget: false, + persistedTarget: true, }, } satisfies Record; diff --git a/tests/unit/api/profile-reader.test.ts b/tests/unit/api/profile-reader.test.ts index f677b2a1..c7bcc24f 100644 --- a/tests/unit/api/profile-reader.test.ts +++ b/tests/unit/api/profile-reader.test.ts @@ -56,7 +56,7 @@ describe('profile reader target sanitization', () => { } }); - it('normalizes legacy stored codex targets back to claude for profiles and variants', async () => { + it('normalizes legacy invalid stored targets back to claude for profiles and variants', async () => { const ccsDir = getScopedCcsDir(); fs.mkdirSync(ccsDir, { recursive: true }); fs.writeFileSync( @@ -64,12 +64,12 @@ describe('profile reader target sanitization', () => { JSON.stringify( { profiles: { demo: '~/.ccs/demo.settings.json' }, - profile_targets: { demo: 'codex' }, + profile_targets: { demo: 'glm' }, cliproxy: { routed: { provider: 'codex', settings: '~/.ccs/routed.settings.json', - target: 'codex', + target: 'glm', }, }, }, @@ -94,7 +94,7 @@ describe('profile reader target sanitization', () => { expect(result.variants[0]?.target).toBe('claude'); }); - it('normalizes unified stored codex targets back to claude for profiles and variants', async () => { + it('normalizes unified invalid stored targets back to claude for profiles and variants', async () => { const ccsDir = getScopedCcsDir(); fs.mkdirSync(ccsDir, { recursive: true }); process.env.CCS_UNIFIED_CONFIG = '1'; @@ -106,7 +106,7 @@ describe('profile reader target sanitization', () => { ' demo:', ' type: api', ' settings: ~/.ccs/demo.settings.json', - ' target: codex', + ' target: glm', 'cliproxy:', ' oauth_accounts: {}', ' providers: []', @@ -114,7 +114,7 @@ describe('profile reader target sanitization', () => { ' routed:', ' provider: codex', ' settings: ~/.ccs/routed.settings.json', - ' target: codex', + ' target: glm', '', ].join('\n'), 'utf8' diff --git a/tests/unit/commands/api-command-args.test.ts b/tests/unit/commands/api-command-args.test.ts index 83387831..9eebee5d 100644 --- a/tests/unit/commands/api-command-args.test.ts +++ b/tests/unit/commands/api-command-args.test.ts @@ -71,15 +71,15 @@ describe('api-command arg parser', () => { expect(parsed.target).toBeUndefined(); expect(parsed.errors).toEqual([ - 'Invalid --target value "invalid-target". Use: claude or droid', + 'Invalid --target value "invalid-target". Use: claude, droid, or codex', ]); }); - test('rejects runtime-only codex as a persisted API target value', () => { + test('accepts codex as a persisted API target value', () => { const parsed = parseApiCommandArgs(['my-api', '--target', 'codex']); - expect(parsed.target).toBeUndefined(); - expect(parsed.errors).toEqual(['Invalid --target value "codex". Use: claude or droid']); + expect(parsed.target).toBe('codex'); + expect(parsed.errors).toEqual([]); }); test('collects missing-value error for --target with no value', () => { diff --git a/tests/unit/commands/cliproxy-variant-args.test.ts b/tests/unit/commands/cliproxy-variant-args.test.ts index a810bceb..5e3f514c 100644 --- a/tests/unit/commands/cliproxy-variant-args.test.ts +++ b/tests/unit/commands/cliproxy-variant-args.test.ts @@ -26,11 +26,11 @@ describe('cliproxy variant arg parser', () => { expect(parsed.errors).toEqual(['Missing value for --target']); }); - test('rejects runtime-only codex as a persisted variant target value', () => { + test('accepts codex as a persisted variant target value', () => { const parsed = parseProfileArgs(['variant-a', '--target', 'codex']); - expect(parsed.target).toBeUndefined(); - expect(parsed.errors).toEqual(['Invalid --target value "codex". Use: claude or droid']); + expect(parsed.target).toBe('codex'); + expect(parsed.errors).toEqual([]); }); test('uses last --target value when repeated', () => { diff --git a/tests/unit/targets/target-resolver.test.ts b/tests/unit/targets/target-resolver.test.ts index 72bfbdaa..172da6e0 100644 --- a/tests/unit/targets/target-resolver.test.ts +++ b/tests/unit/targets/target-resolver.test.ts @@ -68,9 +68,9 @@ describe('resolveTargetType', () => { expect(resolveTargetType([], { target: 'invalid-target' as never })).toBe('claude'); }); - it('should ignore runtime-only codex target when it appears in persisted profile config', () => { + it('should use codex from persisted profile config', () => { process.argv = ['node', 'ccs']; - expect(resolveTargetType([], { target: 'codex' })).toBe('claude'); + expect(resolveTargetType([], { target: 'codex' })).toBe('codex'); }); it('should prioritize --target flag over profile config', () => { diff --git a/tests/unit/web-server/target-parse-routes.test.ts b/tests/unit/web-server/target-parse-routes.test.ts index b0446dab..d1942308 100644 --- a/tests/unit/web-server/target-parse-routes.test.ts +++ b/tests/unit/web-server/target-parse-routes.test.ts @@ -7,16 +7,16 @@ describe('route target parsing', () => { it('accepts valid target values', () => { expect(parseProfileTarget('claude')).toBe('claude'); expect(parseProfileTarget('DROID')).toBe('droid'); + expect(parseProfileTarget('codex')).toBe('codex'); expect(parseVariantTarget(' claude ')).toBe('claude'); expect(parseVariantTarget('droid')).toBe('droid'); + expect(parseVariantTarget(' codex ')).toBe('codex'); }); it('returns null for invalid target values', () => { expect(parseProfileTarget('glm')).toBeNull(); - expect(parseProfileTarget('codex')).toBeNull(); expect(parseProfileTarget('')).toBeNull(); expect(parseVariantTarget('factory')).toBeNull(); - expect(parseVariantTarget('codex')).toBeNull(); expect(parseVariantTarget(' ')).toBeNull(); });