mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 04:18:05 +00:00
fix(codex): pass native ccsx subcommands through (#1290)
This commit is contained in:
+1
-1
@@ -16,7 +16,7 @@
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **codex:** Pass `ccsx resume` through to native Codex instead of treating `resume` as a CCS profile.
|
||||
* **codex:** Pass native `ccsx` Codex subcommands such as `exec`, `apply`, `mcp`, `plugin`, `completion`, and `resume` plus upstream aliases such as `e` and `a` through before CCS profile detection while keeping CCS-owned commands reserved.
|
||||
|
||||
## [7.79.1](https://github.com/kaitranntt/ccs/compare/v7.79.0...v7.79.1) (2026-05-14)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# CCS Codebase Summary
|
||||
|
||||
Last Updated: 2026-04-26
|
||||
Last Updated: 2026-05-18
|
||||
|
||||
Comprehensive overview of the modularized CCS codebase structure following the Phase 9 modularization effort (Settings, Analytics, Auth Monitor splits + Test Infrastructure), v7.1 Remote CLIProxy feature, v7.2 Kiro + GitHub Copilot (ghcp) OAuth providers, v7.14 Hybrid Quota Management, v7.34 Image Analysis Hook, account-context validation hardening, Official Claude Channels runtime support, native Codex runtime target support, native Codex/Droid usage collectors, and models.dev-backed model pricing metadata.
|
||||
|
||||
@@ -273,7 +273,7 @@ src/
|
||||
### Native Codex Runtime Target
|
||||
|
||||
- Dedicated runtime entrypoints: `ccs-codex` and `ccsx` resolve through `src/bin/codex-runtime.ts`, while `ccsxp` resolves through `src/bin/ccsxp-runtime.ts`; all three set `CCS_INTERNAL_ENTRY_TARGET=codex` before delegating to `src/targets/target-resolver.ts`.
|
||||
- Native Codex passthrough: `ccsx --help`, `ccsx --version`, and `ccsx resume ...` short-circuit before CCS profile detection, so Codex diagnostics and session resume behavior stay aligned with the upstream Codex CLI. CCS-owned `ccsx auth` remains the managed Codex profile namespace.
|
||||
- Native Codex passthrough: `ccsx --help`, `ccsx --version`, and known upstream Codex subcommands such as `ccsx exec ...`, `ccsx apply ...`, `ccsx mcp ...`, `ccsx plugin ...`, `ccsx completion ...`, and `ccsx resume ...` short-circuit before CCS profile detection; upstream aliases such as `ccsx e ...` and `ccsx a ...` are included. CCS-owned `ccsx auth`, `ccsx doctor`, and `ccsx update` remain reserved for CCS.
|
||||
- Provider shortcut behavior: `ccsxp` strips user-supplied `--target` overrides and prepends `--config model_provider="cliproxy"` so it behaves like native Codex plus the CLIProxy provider recipe. The stricter CCS-managed bridge remains available explicitly through `ccs codex --target codex`. It pins `CODEX_HOME` to native `~/.codex` by default so inherited launcher state does not send history/config writes to a nonstandard Codex root; `CCSXP_CODEX_HOME` is the explicit override. On launch, CCS repairs the native `[model_providers.cliproxy]` stanza in `config.toml`, preserves a valid custom `base_url`, reads that provider's configured `env_key` (default `CLIPROXY_API_KEY`), and injects the effective CLIProxy auth token into that key for the child Codex process.
|
||||
- Implicit Codex launches such as `ccs --target codex` and `ccsxp` use native Codex default mode even when the CCS default profile is a Claude account. Explicit unsupported profiles such as `ccs work --target codex` still fail fast with native-vs-pool guidance.
|
||||
- `argv[0]` alias mapping still exists in `src/targets/target-resolver.ts` for same-binary/custom alias scenarios, but the built-in npm bins above do not depend on that map at runtime.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Target Adapters
|
||||
|
||||
Last Updated: 2026-03-28
|
||||
Last Updated: 2026-05-18
|
||||
|
||||
Detailed documentation of the target adapter pattern and implementations.
|
||||
|
||||
@@ -515,7 +515,8 @@ ccs-codex
|
||||
ccsx
|
||||
→ dist/bin/codex-runtime.js
|
||||
→ CCS_INTERNAL_ENTRY_TARGET=codex
|
||||
→ passes native Codex diagnostics and `resume` through before CCS profile detection
|
||||
→ passes native Codex diagnostics plus known upstream Codex subcommands and aliases through before CCS profile detection
|
||||
→ reserves CCS-owned `auth`, `doctor`, and `update`
|
||||
|
||||
ccsxp
|
||||
→ dist/bin/ccsxp-runtime.js
|
||||
|
||||
@@ -9,7 +9,37 @@ import { describe, it, expect, beforeEach, afterEach, mock, spyOn } from 'bun:te
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { bootstrapAndParseEarlyCli } from '../cli-argument-parser';
|
||||
import {
|
||||
bootstrapAndParseEarlyCli,
|
||||
CODEX_NATIVE_PASSTHROUGH_SUBCOMMANDS,
|
||||
getNativeCodexPassthroughArgs,
|
||||
} from '../cli-argument-parser';
|
||||
import { setGlobalConfigDir } from '../../utils/config-manager';
|
||||
|
||||
const EXPECTED_NATIVE_CODEX_SUBCOMMANDS = [
|
||||
'a',
|
||||
'app',
|
||||
'app-server',
|
||||
'apply',
|
||||
'cloud',
|
||||
'completion',
|
||||
'debug',
|
||||
'e',
|
||||
'exec',
|
||||
'exec-server',
|
||||
'features',
|
||||
'fork',
|
||||
'help',
|
||||
'login',
|
||||
'logout',
|
||||
'mcp',
|
||||
'mcp-server',
|
||||
'plugin',
|
||||
'remote-control',
|
||||
'resume',
|
||||
'review',
|
||||
'sandbox',
|
||||
];
|
||||
|
||||
// ========== Helpers ==========
|
||||
|
||||
@@ -53,6 +83,7 @@ describe('bootstrapAndParseEarlyCli', () => {
|
||||
configurable: true,
|
||||
});
|
||||
delete process.env['CI'];
|
||||
setGlobalConfigDir(undefined);
|
||||
exitSpy.mockRestore();
|
||||
});
|
||||
|
||||
@@ -150,3 +181,30 @@ describe('bootstrapAndParseEarlyCli', () => {
|
||||
expect(result.browserLaunchOverride).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('native Codex passthrough parsing', () => {
|
||||
it('keeps the native Codex passthrough subcommand list explicit', () => {
|
||||
expect([...CODEX_NATIVE_PASSTHROUGH_SUBCOMMANDS].sort()).toEqual(
|
||||
EXPECTED_NATIVE_CODEX_SUBCOMMANDS
|
||||
);
|
||||
|
||||
for (const subcommand of EXPECTED_NATIVE_CODEX_SUBCOMMANDS) {
|
||||
expect(getNativeCodexPassthroughArgs(['--target', 'codex', subcommand, '--help'])).toEqual([
|
||||
subcommand,
|
||||
'--help',
|
||||
]);
|
||||
expect(
|
||||
getNativeCodexPassthroughArgs(['--target', 'codex', 'codex', subcommand, '--help'])
|
||||
).toEqual([subcommand, '--help']);
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps CCS-owned codex runtime commands out of native passthrough', () => {
|
||||
for (const subcommand of ['auth', 'doctor', 'update']) {
|
||||
expect(getNativeCodexPassthroughArgs(['--target', 'codex', subcommand, '--help'])).toBeNull();
|
||||
expect(
|
||||
getNativeCodexPassthroughArgs(['--target', 'codex', 'codex', subcommand, '--help'])
|
||||
).toBeNull();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -175,7 +175,30 @@ export const CODEX_RUNTIME_REASONING_LEVELS = new Set([
|
||||
]);
|
||||
|
||||
export const CODEX_NATIVE_PASSTHROUGH_FLAGS = new Set(['--help', '-h', '--version', '-v']);
|
||||
export const CODEX_NATIVE_PASSTHROUGH_SUBCOMMANDS = new Set(['resume']);
|
||||
export const CODEX_NATIVE_PASSTHROUGH_SUBCOMMANDS = new Set([
|
||||
'a',
|
||||
'app',
|
||||
'app-server',
|
||||
'apply',
|
||||
'cloud',
|
||||
'completion',
|
||||
'debug',
|
||||
'e',
|
||||
'exec',
|
||||
'exec-server',
|
||||
'features',
|
||||
'fork',
|
||||
'help',
|
||||
'login',
|
||||
'logout',
|
||||
'mcp',
|
||||
'mcp-server',
|
||||
'plugin',
|
||||
'remote-control',
|
||||
'resume',
|
||||
'review',
|
||||
'sandbox',
|
||||
]);
|
||||
|
||||
export const NATIVE_CLAUDE_EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'] as const;
|
||||
|
||||
|
||||
@@ -498,10 +498,32 @@ process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
it('passes ccsx resume straight through to the native Codex binary', () => {
|
||||
for (const subcommand of ['exec', 'e', 'apply', 'a', 'mcp', 'plugin', 'completion', 'resume']) {
|
||||
it(`passes ccsx ${subcommand} straight through to the native Codex binary`, () => {
|
||||
if (process.platform === 'win32') return;
|
||||
|
||||
const result = runCodexAlias([subcommand, '--help'], {
|
||||
...process.env,
|
||||
CI: '1',
|
||||
NO_COLOR: '1',
|
||||
CCS_HOME: tmpHome,
|
||||
CODEX_HOME: path.join(tmpHome, '.codex'),
|
||||
CCS_CODEX_PATH: fakeCodexPath,
|
||||
CCS_TEST_CODEX_ARGS_OUT: codexArgsLogPath,
|
||||
CCS_TEST_CODEX_HELP: `Native ${subcommand} help`,
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(result.stdout).toContain(`Native ${subcommand} help`);
|
||||
expect(result.stderr).not.toContain(`Profile not found: ${subcommand}`);
|
||||
expect(readLoggedCodexCalls(codexArgsLogPath)).toEqual([[subcommand, '--help']]);
|
||||
});
|
||||
}
|
||||
|
||||
it('passes nested ccsx codex subcommands through to the native Codex binary', () => {
|
||||
if (process.platform === 'win32') return;
|
||||
|
||||
const result = runCodexAlias(['resume', '--help'], {
|
||||
const result = runCodexAlias(['codex', 'exec', '--help'], {
|
||||
...process.env,
|
||||
CI: '1',
|
||||
NO_COLOR: '1',
|
||||
@@ -509,13 +531,13 @@ process.exit(0);
|
||||
CODEX_HOME: path.join(tmpHome, '.codex'),
|
||||
CCS_CODEX_PATH: fakeCodexPath,
|
||||
CCS_TEST_CODEX_ARGS_OUT: codexArgsLogPath,
|
||||
CCS_TEST_CODEX_HELP: 'Resume a previous interactive session',
|
||||
CCS_TEST_CODEX_HELP: 'Native exec help',
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(result.stdout).toContain('Resume a previous interactive session');
|
||||
expect(result.stderr).not.toContain('Profile not found: resume');
|
||||
expect(readLoggedCodexCalls(codexArgsLogPath)).toEqual([['resume', '--help']]);
|
||||
expect(result.stdout).toContain('Native exec help');
|
||||
expect(result.stderr).not.toContain('Profile not found: codex');
|
||||
expect(readLoggedCodexCalls(codexArgsLogPath)).toEqual([['exec', '--help']]);
|
||||
});
|
||||
|
||||
it('strips nested Codex session env from passthrough launches while keeping CODEX_HOME', () => {
|
||||
|
||||
Reference in New Issue
Block a user