-
-
Notifications
You must be signed in to change notification settings - Fork 414
Expand file tree
/
Copy pathcodexLocal.ts
More file actions
93 lines (80 loc) · 2.96 KB
/
codexLocal.ts
File metadata and controls
93 lines (80 loc) · 2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { logger } from '@/ui/logger';
import { restoreTerminalState } from '@/ui/terminalState';
import { spawnWithAbort } from '@/utils/spawnWithAbort';
import { buildMcpServerConfigArgs, buildDeveloperInstructionsArg } from './utils/codexMcpConfig';
import { codexSystemPrompt } from './utils/systemPrompt';
/**
* Filter out HAPI-managed session subcommands which are handled internally.
* Codex CLI format is `codex <subcommand> <session-id>`, so the subcommand is always first.
*/
export function filterManagedSessionSubcommand(args: string[]): string[] {
if (args.length === 0 || (args[0] !== 'resume' && args[0] !== 'fork')) {
return args;
}
// First arg is 'resume' or 'fork'; filter it and optional session ID
if (args.length > 1 && !args[1].startsWith('-')) {
logger.debug(`[CodexLocal] Filtered '${args[0]} ${args[1]}' - session managed by hapi`);
return args.slice(2);
}
logger.debug(`[CodexLocal] Filtered '${args[0]}' - session managed by hapi`);
return args.slice(1);
}
export async function codexLocal(opts: {
abort: AbortSignal;
resumeSessionId: string | null;
forkSessionId?: string;
path: string;
model?: string;
sandbox?: 'read-only' | 'workspace-write' | 'danger-full-access';
onSessionFound: (id: string) => void;
codexArgs?: string[];
mcpServers?: Record<string, { command: string; args: string[] }>;
}): Promise<void> {
const args: string[] = [];
if (opts.forkSessionId) {
args.push('fork', opts.forkSessionId);
} else if (opts.resumeSessionId) {
args.push('resume', opts.resumeSessionId);
opts.onSessionFound(opts.resumeSessionId);
}
if (opts.model) {
args.push('--model', opts.model);
}
if (opts.sandbox) {
args.push('--sandbox', opts.sandbox);
}
// Add MCP server configuration
if (opts.mcpServers && Object.keys(opts.mcpServers).length > 0) {
args.push(...buildMcpServerConfigArgs(opts.mcpServers));
}
// Add developer instructions (system prompt)
args.push(...buildDeveloperInstructionsArg(codexSystemPrompt));
if (opts.codexArgs) {
const safeArgs = filterManagedSessionSubcommand(opts.codexArgs);
args.push(...safeArgs);
}
logger.debug(`[CodexLocal] Spawning codex with args: ${JSON.stringify(args)}`);
if (opts.abort.aborted) {
logger.debug('[CodexLocal] Abort already signaled before spawn; skipping launch');
return;
}
process.stdin.pause();
try {
await spawnWithAbort({
command: 'codex',
args,
cwd: opts.path,
env: process.env,
signal: opts.abort,
logLabel: 'CodexLocal',
spawnName: 'codex',
installHint: 'Codex CLI',
includeCause: true,
logExit: true,
shell: process.platform === 'win32'
});
} finally {
process.stdin.resume();
restoreTerminalState();
}
}