Repository navigation
Expand file tree
/
Copy pathcodex-runner.js
More file actions
127 lines (111 loc) · 2.78 KB
/
Copy pathcodex-runner.js
File metadata and controls
127 lines (111 loc) · 2.78 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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { spawn } from "node:child_process";
import { join } from "node:path";
const ALLOWED_SANDBOXES = new Set(["read-only", "workspace-write"]);
const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000;
export function getCodexBin(platform = process.platform) {
return platform === "win32" ? "codex.cmd" : "codex";
}
export function getWindowsCodexScript(env = process.env) {
if (!env.APPDATA) {
return null;
}
return join(env.APPDATA, "npm", "node_modules", "@openai", "codex", "bin", "codex.js");
}
export function buildCodexSpawn(args, platform = process.platform, env = process.env) {
if (platform === "win32") {
const script = getWindowsCodexScript(env);
if (script) {
return {
bin: "node",
args: [script, ...args],
};
}
return {
bin: "cmd.exe",
args: ["/d", "/s", "/c", getCodexBin(platform), ...args],
};
}
return {
bin: getCodexBin(platform),
args,
};
}
export function buildCodexArgs(input) {
const sandbox = ALLOWED_SANDBOXES.has(input.sandbox)
? input.sandbox
: "read-only";
const args = [
"exec",
"--color",
"never",
"--sandbox",
sandbox,
"--skip-git-repo-check",
"--ephemeral",
];
if (input.model) {
args.push("--model", input.model);
}
if (input.cwd) {
args.push("--cd", input.cwd);
}
args.push(input.prompt);
return args;
}
export function runCodexExec(input, options = {}) {
const timeoutMs = Number(input.timeoutMs ?? options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
const args = buildCodexArgs(input);
return new Promise((resolve) => {
let stdout = "";
let stderr = "";
let timedOut = false;
let child;
try {
const spawnConfig = options.bin
? { bin: options.bin, args }
: buildCodexSpawn(args);
child = spawn(spawnConfig.bin, spawnConfig.args, {
cwd: options.cwd ?? process.cwd(),
shell: false,
stdio: ["ignore", "pipe", "pipe"],
windowsHide: true,
});
} catch (error) {
resolve({
stdout,
stderr: error instanceof Error ? error.message : String(error),
exitCode: 1,
timedOut,
});
return;
}
const timer = setTimeout(() => {
timedOut = true;
child.kill("SIGTERM");
}, timeoutMs);
child.stdout.on("data", (chunk) => {
stdout += chunk.toString();
});
child.stderr.on("data", (chunk) => {
stderr += chunk.toString();
});
child.on("error", (error) => {
clearTimeout(timer);
resolve({
stdout,
stderr: stderr || error.message,
exitCode: 1,
timedOut,
});
});
child.on("close", (exitCode) => {
clearTimeout(timer);
resolve({
stdout,
stderr,
exitCode,
timedOut,
});
});
});
}