/** * Single source of truth for assembling `codex` invocations. * * The review flow shells codex two ways — `codex resume ` and the * interactive `codex ''` TUI — both sent to a terminal. Building the * flags in one place keeps `--dangerously-bypass-approvals-and-sandbox` and the * optional model / reasoning-effort `-c` overrides from drifting apart. * * Model and reasoning effort are free-form: an empty value omits the override * so codex falls back to its own `config.toml` default. */ export interface CodexCommandOpts { /** 'resume' = `codex resume `;'interactive' = `codex ''` */ mode: 'resume' | 'interactive' /** resume 模式必填:codex thread id */ sessionId?: string /** interactive 模式的 prompt(positional)。调用方保证不含单引号。 */ prompt?: string /** 空 = 不传 `-c model=`,用 codex 默认 */ model?: string /** 空 = 不传 `-c model_reasoning_effort=`,用 codex 默认。合法值 minimal/low/medium/high/xhigh */ reasoningEffort?: string } const BYPASS_FLAG = '--dangerously-bypass-approvals-and-sandbox' /** * `-c key=value` overrides for model / reasoning effort. Blank values are * dropped so codex keeps its config.toml default. */ function configOverrides(opts: CodexCommandOpts): string[] { const parts: string[] = [] const model = opts.model?.trim() if (model) parts.push('-c', `model=${model}`) const effort = opts.reasoningEffort?.trim() if (effort) parts.push('-c', `model_reasoning_effort=${effort}`) return parts } /** Full shell command string (with `codex` prefix) for `terminal.sendText`. */ export function buildCodexCommandString(opts: CodexCommandOpts): string { const overrides = configOverrides(opts) const parts = opts.mode === 'resume' ? ['resume', ...overrides, BYPASS_FLAG, ...(opts.sessionId ? [opts.sessionId] : [])] : [...overrides, BYPASS_FLAG, ...(opts.prompt ? [`'${opts.prompt}'`] : [])] return ['codex', ...parts].join(' ') }