refactor(dispatcher): scaffold src/dispatcher/ and extract pure helpers from ccs.ts

Phase 1 of #1165. Pure code-motion: moves top-level helpers out of the
1775-LOC CLI entry point into focused dispatcher modules. Zero
behavior change, zero main() changes.

- src/dispatcher/cli-argument-parser.ts (199 LOC):
  DetectedProfile, RuntimeReasoningResolution, NATIVE_CLAUDE_EFFORT
  constants, detectProfile, normalizeLegacyCursorArgs,
  printCursorLegacySubcommandDeprecation, resolveRuntimeReasoningFlags,
  normalizeCodexRuntimeReasoningOverride,
  exitWithRuntimeReasoningFlagError, normalizeNativeClaudeEffortArgs,
  shouldNormalizeNativeClaudeEffort,
  shouldPassthroughNativeCodexFlagCommand,
  getNativeCodexPassthroughArgs.
- src/dispatcher/environment-builder.ts (125 LOC):
  resolveCodexRuntimeConfigOverrides, refreshUpdateCache,
  showCachedUpdateNotification, resolveNativeClaudeLaunchArgs.
- src/dispatcher/target-executor.ts (56 LOC):
  ProfileError, execNativeCodexFlagCommand.

ccs.ts: 1775 -> 1475 LOC (-300). Cleaned up 8 now-orphaned imports.
Behavior unchanged; full suite passes 1824/1824.

Refs #1165
This commit is contained in:
Tam Nhu Tran
2026-05-02 22:49:45 -04:00
parent 74898210f9
commit f759cfeaaa
4 changed files with 402 additions and 322 deletions
+22 -322
View File
@@ -46,11 +46,7 @@ import {
resolveOptionalBrowserAttachRuntime,
syncBrowserMcpToConfigDir,
} from './utils/browser';
import {
getBrowserConfig,
getGlobalEnvConfig,
getOfficialChannelsConfig,
} from './config/unified-config-loader';
import { getBrowserConfig, getGlobalEnvConfig } from './config/unified-config-loader';
import {
ensureProfileHooks as ensureImageAnalyzerHooks,
removeImageAnalysisProfileHook,
@@ -65,13 +61,6 @@ import {
} from './utils/hooks';
import { fail, info, warn } from './utils/ui';
import { isCopilotSubcommandToken } from './copilot/constants';
import {
buildOfficialChannelsArgs,
getOfficialChannelsEnvironmentStatus,
officialChannelRequiresMacOS,
resolveOfficialChannelsLaunchPlan,
} from './channels/official-channels-runtime';
import { getOfficialChannelReadiness } from './channels/official-channels-store';
import { isCursorSubcommandToken, LEGACY_CURSOR_PROFILE_NAME } from './cursor/constants';
import { isCLIProxyProvider } from './cliproxy/provider-capabilities';
@@ -85,7 +74,6 @@ import { isDeprecatedGlmtProfileName, normalizeDeprecatedGlmtEnv } from './utils
import { createOpenAICompatLaunchSettings } from './utils/openai-compat-launch-settings';
import { maybeWarnAboutResumeLaneMismatch } from './auth/resume-lane-warning';
import { createLogger, runWithRequestId } from './services/logging';
import { buildCodexBrowserMcpOverrides } from './utils/browser-codex-overrides';
import type { ProfileDetectionResult } from './auth/profile-detector';
import type { BrowserLaunchOverride } from './utils/browser';
@@ -102,10 +90,7 @@ import {
type TargetCredentials,
} from './targets';
import { resolveTargetType, stripTargetFlag } from './targets/target-resolver';
import {
DroidReasoningFlagError,
resolveDroidReasoningRuntime,
} from './targets/droid-reasoning-runtime';
import { DroidReasoningFlagError } from './targets/droid-reasoning-runtime';
import { DroidCommandRouterError, routeDroidCommandArgs } from './targets/droid-command-router';
import { resolveCliproxyBridgeMetadata } from './api/services/cliproxy-profile-bridge';
import {
@@ -115,316 +100,31 @@ import {
} from './proxy';
// Version and Update check utilities
import { getVersion } from './utils/version';
import {
checkForUpdates,
showUpdateNotification,
checkCachedUpdate,
isCacheStale,
} from './utils/update-checker';
import { isCacheStale } from './utils/update-checker';
// Note: npm is now the only supported installation method
// ========== Profile Detection ==========
interface DetectedProfile {
profile: string;
remainingArgs: string[];
}
interface RuntimeReasoningResolution {
argsWithoutReasoningFlags: string[];
reasoningOverride: string | number | undefined;
reasoningSource: 'flag' | 'env' | undefined;
sourceDisplay: string | undefined;
}
const CODEX_RUNTIME_REASONING_LEVELS = new Set(['minimal', 'low', 'medium', 'high', 'xhigh']);
const CODEX_NATIVE_PASSTHROUGH_FLAGS = new Set(['--help', '-h', '--version', '-v']);
const NATIVE_CLAUDE_EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'] as const;
const NATIVE_CLAUDE_EFFORT_LEVEL_SET = new Set<string>(NATIVE_CLAUDE_EFFORT_LEVELS);
function resolveCodexRuntimeConfigOverrides(
target: ReturnType<typeof resolveTargetType>,
browserLaunchOverride: BrowserLaunchOverride | undefined
): string[] {
if (target !== 'codex') {
return [];
}
const codexBrowserExposure = resolveBrowserExposure(
getBrowserConfig().codex,
browserLaunchOverride
);
if (!codexBrowserExposure.exposeForLaunch) {
return [];
}
return buildCodexBrowserMcpOverrides();
}
/**
* Smart profile detection
*/
function detectProfile(args: string[]): DetectedProfile {
if (args.length === 0 || args[0].startsWith('-')) {
// No args or first arg is a flag → use default profile
return { profile: 'default', remainingArgs: args };
} else {
// First arg doesn't start with '-' → treat as profile name
return { profile: args[0], remainingArgs: args.slice(1) };
}
}
function normalizeLegacyCursorArgs(args: string[]): string[] {
if (args[0] === 'legacy' && args[1] === 'cursor') {
return [LEGACY_CURSOR_PROFILE_NAME, ...args.slice(2)];
}
return args;
}
function printCursorLegacySubcommandDeprecation(subcommand: string): void {
console.error(
info(`\`ccs cursor ${subcommand}\` is deprecated for the legacy Cursor IDE bridge.`)
);
console.error(
info(
`Use \`ccs legacy cursor ${subcommand}\` for the old bridge, or \`ccs cursor --auth|--accounts|--config\` for the CLIProxy provider.`
)
);
console.error('');
}
function resolveRuntimeReasoningFlags(
args: string[],
envThinkingValue: string | undefined
): RuntimeReasoningResolution {
const runtime = resolveDroidReasoningRuntime(args, envThinkingValue);
if (runtime.duplicateDisplays.length > 0) {
console.error(
warn(
`[!] Multiple reasoning flags detected. Using first occurrence: ${runtime.sourceDisplay || '<first-flag>'}`
)
);
}
return {
argsWithoutReasoningFlags: runtime.argsWithoutReasoningFlags,
reasoningOverride: runtime.reasoningOverride,
reasoningSource: runtime.sourceFlag
? 'flag'
: runtime.reasoningOverride !== undefined
? 'env'
: undefined,
sourceDisplay: runtime.sourceDisplay,
};
}
function normalizeCodexRuntimeReasoningOverride(
value: string | number | undefined
): string | undefined {
return typeof value === 'string' && CODEX_RUNTIME_REASONING_LEVELS.has(value) ? value : undefined;
}
function exitWithRuntimeReasoningFlagError(
message: string,
options: {
codexAliasLevels: string;
includeDroidExecExample?: boolean;
}
): never {
console.error(fail(message));
console.error(' Examples: --thinking low, --thinking 8192, --thinking off');
console.error(` Codex alias: --effort ${options.codexAliasLevels}`);
if (options.includeDroidExecExample) {
console.error(' Droid exec: --reasoning-effort high');
}
process.exit(1);
}
function normalizeNativeClaudeEffortArgs(args: string[]): string[] {
const normalizedArgs: string[] = [];
const allowedValues = NATIVE_CLAUDE_EFFORT_LEVELS.join(', ');
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg === '--effort') {
const rawValue = args[i + 1];
if (!rawValue || rawValue.startsWith('-') || !rawValue.trim()) {
throw new Error(`--effort requires a value: ${allowedValues}`);
}
const value = rawValue.toLowerCase();
if (!NATIVE_CLAUDE_EFFORT_LEVEL_SET.has(value)) {
throw new Error(`Invalid --effort value: ${rawValue}. Expected one of: ${allowedValues}.`);
}
normalizedArgs.push(arg, value);
i++;
continue;
}
if (arg.startsWith('--effort=')) {
const rawValue = arg.slice('--effort='.length);
if (!rawValue.trim()) {
throw new Error(`--effort requires a value: ${allowedValues}`);
}
const value = rawValue.toLowerCase();
if (!NATIVE_CLAUDE_EFFORT_LEVEL_SET.has(value)) {
throw new Error(`Invalid --effort value: ${rawValue}. Expected one of: ${allowedValues}.`);
}
normalizedArgs.push(`--effort=${value}`);
continue;
}
normalizedArgs.push(arg);
}
return normalizedArgs;
}
function shouldNormalizeNativeClaudeEffort(profileType: ProfileDetectionResult['type']): boolean {
return profileType === 'default' || profileType === 'account' || profileType === 'settings';
}
// Import extracted dispatcher modules
import {
detectProfile,
normalizeLegacyCursorArgs,
printCursorLegacySubcommandDeprecation,
resolveRuntimeReasoningFlags,
normalizeCodexRuntimeReasoningOverride,
exitWithRuntimeReasoningFlagError,
normalizeNativeClaudeEffortArgs,
shouldNormalizeNativeClaudeEffort,
shouldPassthroughNativeCodexFlagCommand,
} from './dispatcher/cli-argument-parser';
import {
resolveCodexRuntimeConfigOverrides,
refreshUpdateCache,
showCachedUpdateNotification,
resolveNativeClaudeLaunchArgs,
} from './dispatcher/environment-builder';
import { type ProfileError, execNativeCodexFlagCommand } from './dispatcher/target-executor';
// ========== Main Execution ==========
interface ProfileError extends Error {
profileName?: string;
availableProfiles?: string;
suggestions?: string[];
}
/**
* Perform background update check (refreshes cache, no notification)
*/
async function refreshUpdateCache(): Promise<void> {
try {
const currentVersion = getVersion();
// npm is now the only supported installation method
await checkForUpdates(currentVersion, true, 'npm');
} catch (_e) {
// Silently fail - update check shouldn't crash main CLI
}
}
/**
* Show update notification if cached result indicates update available
* Returns true if notification was shown
*/
async function showCachedUpdateNotification(): Promise<boolean> {
try {
const currentVersion = getVersion();
const updateInfo = checkCachedUpdate(currentVersion);
if (updateInfo) {
await showUpdateNotification(updateInfo);
return true;
}
} catch (_e) {
// Silently fail
}
return false;
}
function resolveNativeClaudeLaunchArgs(
args: string[],
profileType: 'default' | 'account',
targetConfigDir?: string
): string[] {
const config = getOfficialChannelsConfig();
const environment = getOfficialChannelsEnvironmentStatus(
targetConfigDir ? { CLAUDE_CONFIG_DIR: targetConfigDir } : undefined
);
const channelReadiness = {
telegram: getOfficialChannelReadiness('telegram'),
discord: getOfficialChannelReadiness('discord'),
imessage: !officialChannelRequiresMacOS('imessage') || process.platform === 'darwin',
};
const plan = resolveOfficialChannelsLaunchPlan({
args,
config,
target: 'claude',
profileType,
environment,
channelReadiness,
});
for (const message of plan.skippedMessages) {
console.error(warn(message));
}
if (
config.selected.length > 0 &&
environment.auth.state === 'eligible' &&
environment.auth.orgRequirementMessage
) {
console.error(warn(environment.auth.orgRequirementMessage));
}
if (!plan.applied) {
return args;
}
return buildOfficialChannelsArgs(args, plan.appliedChannels, plan.wantsPermissionBypass);
}
function shouldPassthroughNativeCodexFlagCommand(args: string[]): boolean {
return getNativeCodexPassthroughArgs(args) !== null;
}
function getNativeCodexPassthroughArgs(args: string[]): string[] | null {
const targetArgs = stripTargetFlag(args);
if (resolveTargetType(args) !== 'codex' || targetArgs.length === 0) {
return null;
}
const firstArg = targetArgs[0] || '';
if (CODEX_NATIVE_PASSTHROUGH_FLAGS.has(firstArg)) {
return targetArgs;
}
const secondArg = targetArgs[1] || '';
if (firstArg === 'codex' && CODEX_NATIVE_PASSTHROUGH_FLAGS.has(secondArg)) {
return targetArgs.slice(1);
}
return null;
}
function execNativeCodexFlagCommand(args: string[]): void {
const adapter = getTarget('codex');
if (!adapter) {
console.error(fail('Target adapter not found for "codex"'));
process.exit(1);
}
const binaryInfo = adapter.detectBinary();
if (!binaryInfo) {
console.error(fail('Codex CLI not found.'));
console.error(info('Install a recent @openai/codex build, then retry.'));
process.exit(1);
}
const targetArgs = getNativeCodexPassthroughArgs(args);
if (!targetArgs) {
console.error(fail('Native Codex passthrough args could not be resolved.'));
process.exit(1);
}
const creds: TargetCredentials = {
profile: 'default',
baseUrl: '',
apiKey: '',
};
const builtArgs = adapter.buildArgs('default', targetArgs, {
creds,
profileType: 'default',
binaryInfo,
});
const targetEnv = adapter.buildEnv(creds, 'default');
adapter.exec(builtArgs, targetEnv, { binaryInfo });
}
async function main(): Promise<void> {
// Register target adapters
registerTarget(new ClaudeAdapter());
+199
View File
@@ -0,0 +1,199 @@
/**
* CLI argument parsing and normalization utilities.
*
* Extracted from src/ccs.ts (lines 129-244, 246-296, 371-392).
* Pure functions — no side effects except console.error and process.exit.
*/
import { fail, warn } from '../utils/ui';
import { LEGACY_CURSOR_PROFILE_NAME } from '../cursor/constants';
import { resolveTargetType, stripTargetFlag } from '../targets/target-resolver';
import { resolveDroidReasoningRuntime } from '../targets/droid-reasoning-runtime';
import type { ProfileDetectionResult } from '../auth/profile-detector';
// ========== Interfaces ==========
export interface DetectedProfile {
profile: string;
remainingArgs: string[];
}
export interface RuntimeReasoningResolution {
argsWithoutReasoningFlags: string[];
reasoningOverride: string | number | undefined;
reasoningSource: 'flag' | 'env' | undefined;
sourceDisplay: string | undefined;
}
// ========== Constants ==========
export const CODEX_RUNTIME_REASONING_LEVELS = new Set([
'minimal',
'low',
'medium',
'high',
'xhigh',
]);
export const CODEX_NATIVE_PASSTHROUGH_FLAGS = new Set(['--help', '-h', '--version', '-v']);
export const NATIVE_CLAUDE_EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'] as const;
export const NATIVE_CLAUDE_EFFORT_LEVEL_SET = new Set<string>(NATIVE_CLAUDE_EFFORT_LEVELS);
// ========== Profile Detection ==========
/**
* Smart profile detection — first non-flag arg is the profile name.
*/
export function detectProfile(args: string[]): DetectedProfile {
if (args.length === 0 || args[0].startsWith('-')) {
// No args or first arg is a flag → use default profile
return { profile: 'default', remainingArgs: args };
} else {
// First arg doesn't start with '-' → treat as profile name
return { profile: args[0], remainingArgs: args.slice(1) };
}
}
export function normalizeLegacyCursorArgs(args: string[]): string[] {
if (args[0] === 'legacy' && args[1] === 'cursor') {
return [LEGACY_CURSOR_PROFILE_NAME, ...args.slice(2)];
}
return args;
}
export function printCursorLegacySubcommandDeprecation(subcommand: string): void {
console.error(
warn(`\`ccs cursor ${subcommand}\` is deprecated for the legacy Cursor IDE bridge.`)
);
console.error(
warn(
`Use \`ccs legacy cursor ${subcommand}\` for the old bridge, or \`ccs cursor --auth|--accounts|--config\` for the CLIProxy provider.`
)
);
console.error('');
}
// ========== Runtime Reasoning Flags ==========
export function resolveRuntimeReasoningFlags(
args: string[],
envThinkingValue: string | undefined
): RuntimeReasoningResolution {
const runtime = resolveDroidReasoningRuntime(args, envThinkingValue);
if (runtime.duplicateDisplays.length > 0) {
console.error(
warn(
`[!] Multiple reasoning flags detected. Using first occurrence: ${runtime.sourceDisplay || '<first-flag>'}`
)
);
}
return {
argsWithoutReasoningFlags: runtime.argsWithoutReasoningFlags,
reasoningOverride: runtime.reasoningOverride,
reasoningSource: runtime.sourceFlag
? 'flag'
: runtime.reasoningOverride !== undefined
? 'env'
: undefined,
sourceDisplay: runtime.sourceDisplay,
};
}
export function normalizeCodexRuntimeReasoningOverride(
value: string | number | undefined
): string | undefined {
return typeof value === 'string' && CODEX_RUNTIME_REASONING_LEVELS.has(value) ? value : undefined;
}
export function exitWithRuntimeReasoningFlagError(
message: string,
options: {
codexAliasLevels: string;
includeDroidExecExample?: boolean;
}
): never {
console.error(fail(message));
console.error(' Examples: --thinking low, --thinking 8192, --thinking off');
console.error(` Codex alias: --effort ${options.codexAliasLevels}`);
if (options.includeDroidExecExample) {
console.error(' Droid exec: --reasoning-effort high');
}
process.exit(1);
}
// ========== Native Claude Effort Normalization ==========
export function normalizeNativeClaudeEffortArgs(args: string[]): string[] {
const normalizedArgs: string[] = [];
const allowedValues = NATIVE_CLAUDE_EFFORT_LEVELS.join(', ');
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg === '--effort') {
const rawValue = args[i + 1];
if (!rawValue || rawValue.startsWith('-') || !rawValue.trim()) {
throw new Error(`--effort requires a value: ${allowedValues}`);
}
const value = rawValue.toLowerCase();
if (!NATIVE_CLAUDE_EFFORT_LEVEL_SET.has(value)) {
throw new Error(`Invalid --effort value: ${rawValue}. Expected one of: ${allowedValues}.`);
}
normalizedArgs.push(arg, value);
i++;
continue;
}
if (arg.startsWith('--effort=')) {
const rawValue = arg.slice('--effort='.length);
if (!rawValue.trim()) {
throw new Error(`--effort requires a value: ${allowedValues}`);
}
const value = rawValue.toLowerCase();
if (!NATIVE_CLAUDE_EFFORT_LEVEL_SET.has(value)) {
throw new Error(`Invalid --effort value: ${rawValue}. Expected one of: ${allowedValues}.`);
}
normalizedArgs.push(`--effort=${value}`);
continue;
}
normalizedArgs.push(arg);
}
return normalizedArgs;
}
export function shouldNormalizeNativeClaudeEffort(
profileType: ProfileDetectionResult['type']
): boolean {
return profileType === 'default' || profileType === 'account' || profileType === 'settings';
}
// ========== Native Codex Passthrough ==========
export function shouldPassthroughNativeCodexFlagCommand(args: string[]): boolean {
return getNativeCodexPassthroughArgs(args) !== null;
}
export function getNativeCodexPassthroughArgs(args: string[]): string[] | null {
const targetArgs = stripTargetFlag(args);
if (resolveTargetType(args) !== 'codex' || targetArgs.length === 0) {
return null;
}
const firstArg = targetArgs[0] || '';
if (CODEX_NATIVE_PASSTHROUGH_FLAGS.has(firstArg)) {
return targetArgs;
}
const secondArg = targetArgs[1] || '';
if (firstArg === 'codex' && CODEX_NATIVE_PASSTHROUGH_FLAGS.has(secondArg)) {
return targetArgs.slice(1);
}
return null;
}
+125
View File
@@ -0,0 +1,125 @@
/**
* Runtime environment and launch-args builders.
*
* Extracted from src/ccs.ts (lines 146-163, 300-327, 329-369).
* Covers update-cache helpers and launch-arg resolution for native Claude/Codex targets.
*/
import { warn } from '../utils/ui';
import { resolveBrowserExposure } from '../utils/browser';
import { getBrowserConfig, getOfficialChannelsConfig } from '../config/unified-config-loader';
import {
buildOfficialChannelsArgs,
getOfficialChannelsEnvironmentStatus,
officialChannelRequiresMacOS,
resolveOfficialChannelsLaunchPlan,
} from '../channels/official-channels-runtime';
import { getOfficialChannelReadiness } from '../channels/official-channels-store';
import { buildCodexBrowserMcpOverrides } from '../utils/browser-codex-overrides';
import { getVersion } from '../utils/version';
import {
checkForUpdates,
showUpdateNotification,
checkCachedUpdate,
} from '../utils/update-checker';
import { resolveTargetType } from '../targets/target-resolver';
import type { BrowserLaunchOverride } from '../utils/browser';
// ========== Codex Runtime Config ==========
export function resolveCodexRuntimeConfigOverrides(
target: ReturnType<typeof resolveTargetType>,
browserLaunchOverride: BrowserLaunchOverride | undefined
): string[] {
if (target !== 'codex') {
return [];
}
const codexBrowserExposure = resolveBrowserExposure(
getBrowserConfig().codex,
browserLaunchOverride
);
if (!codexBrowserExposure.exposeForLaunch) {
return [];
}
return buildCodexBrowserMcpOverrides();
}
// ========== Update Cache Helpers ==========
/**
* Perform background update check (refreshes cache, no notification).
*/
export async function refreshUpdateCache(): Promise<void> {
try {
const currentVersion = getVersion();
// npm is now the only supported installation method
await checkForUpdates(currentVersion, true, 'npm');
} catch (_e) {
// Silently fail - update check shouldn't crash main CLI
}
}
/**
* Show update notification if cached result indicates update available.
* Returns true if notification was shown.
*/
export async function showCachedUpdateNotification(): Promise<boolean> {
try {
const currentVersion = getVersion();
const updateInfo = checkCachedUpdate(currentVersion);
if (updateInfo) {
await showUpdateNotification(updateInfo);
return true;
}
} catch (_e) {
// Silently fail
}
return false;
}
// ========== Native Claude Launch Args ==========
export function resolveNativeClaudeLaunchArgs(
args: string[],
profileType: 'default' | 'account',
targetConfigDir?: string
): string[] {
const config = getOfficialChannelsConfig();
const environment = getOfficialChannelsEnvironmentStatus(
targetConfigDir ? { CLAUDE_CONFIG_DIR: targetConfigDir } : undefined
);
const channelReadiness = {
telegram: getOfficialChannelReadiness('telegram'),
discord: getOfficialChannelReadiness('discord'),
imessage: !officialChannelRequiresMacOS('imessage') || process.platform === 'darwin',
};
const plan = resolveOfficialChannelsLaunchPlan({
args,
config,
target: 'claude',
profileType,
environment,
channelReadiness,
});
for (const message of plan.skippedMessages) {
console.error(warn(message));
}
if (
config.selected.length > 0 &&
environment.auth.state === 'eligible' &&
environment.auth.orgRequirementMessage
) {
console.error(warn(environment.auth.orgRequirementMessage));
}
if (!plan.applied) {
return args;
}
return buildOfficialChannelsArgs(args, plan.appliedChannels, plan.wantsPermissionBypass);
}
+56
View File
@@ -0,0 +1,56 @@
/**
* Native target execution — short-circuit dispatch for passthrough flag commands.
*
* Extracted from src/ccs.ts (lines 291-295, 394-426).
* Handles direct execution of native Codex flag passthrough (--help, --version, etc.)
* before the main profile dispatch loop runs.
*/
import { fail, info } from '../utils/ui';
import { getTarget } from '../targets';
import { getNativeCodexPassthroughArgs } from './cli-argument-parser';
import type { TargetCredentials } from '../targets';
// ========== Interfaces ==========
export interface ProfileError extends Error {
profileName?: string;
availableProfiles?: string;
suggestions?: string[];
}
// ========== Native Codex Flag Command Executor ==========
export function execNativeCodexFlagCommand(args: string[]): void {
const adapter = getTarget('codex');
if (!adapter) {
console.error(fail('Target adapter not found for "codex"'));
process.exit(1);
}
const binaryInfo = adapter.detectBinary();
if (!binaryInfo) {
console.error(fail('Codex CLI not found.'));
console.error(info('Install a recent @openai/codex build, then retry.'));
process.exit(1);
}
const targetArgs = getNativeCodexPassthroughArgs(args);
if (!targetArgs) {
console.error(fail('Native Codex passthrough args could not be resolved.'));
process.exit(1);
}
const creds: TargetCredentials = {
profile: 'default',
baseUrl: '',
apiKey: '',
};
const builtArgs = adapter.buildArgs('default', targetArgs, {
creds,
profileType: 'default',
binaryInfo,
});
const targetEnv = adapter.buildEnv(creds, 'default');
adapter.exec(builtArgs, targetEnv, { binaryInfo });
}