@childclm/codexx 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/codexx.js +0 -0
- package/package.json +1 -1
- package/src/index.js +104 -121
package/bin/codexx.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -137,38 +137,39 @@ function saveProjectSessionsMeta(data, cwd = process.cwd()) {
|
|
|
137
137
|
|
|
138
138
|
function detectCodex() {
|
|
139
139
|
const settings = loadSettings();
|
|
140
|
-
return settings.codexCommand || "codex";
|
|
140
|
+
return String(settings.codexCommand || "codex").trim().replace(/^"(.*)"$/, "$1");
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
function resolveWindowsCodexCandidates() {
|
|
144
144
|
const candidates = [];
|
|
145
145
|
const appData = process.env.APPDATA || path.join(HOME, "AppData", "Roaming");
|
|
146
146
|
const npmRoot = path.join(appData, "npm");
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
path.join(npmRoot, "codex.cmd"),
|
|
150
|
-
path.join(npmRoot, "codex"),
|
|
151
|
-
];
|
|
152
|
-
candidates.push(...localShims);
|
|
153
|
-
|
|
154
|
-
const openaiCodexRoot = path.join(
|
|
147
|
+
|
|
148
|
+
const nativePackageScope = path.join(
|
|
155
149
|
npmRoot,
|
|
156
150
|
"node_modules",
|
|
157
151
|
"@openai",
|
|
158
152
|
"codex",
|
|
159
153
|
"node_modules",
|
|
154
|
+
"@openai",
|
|
160
155
|
);
|
|
161
|
-
if (fileExists(
|
|
156
|
+
if (fileExists(nativePackageScope)) {
|
|
162
157
|
try {
|
|
163
|
-
const
|
|
164
|
-
for (const
|
|
165
|
-
if (!
|
|
166
|
-
|
|
158
|
+
const dirs = fs.readdirSync(nativePackageScope);
|
|
159
|
+
for (const dir of dirs) {
|
|
160
|
+
if (!dir.startsWith("codex-win32-")) continue;
|
|
161
|
+
const vendorRoot = path.join(nativePackageScope, dir, "vendor");
|
|
162
|
+
if (!fileExists(vendorRoot)) continue;
|
|
163
|
+
const vendorDirs = fs.readdirSync(vendorRoot);
|
|
164
|
+
for (const vendorDir of vendorDirs) {
|
|
165
|
+
candidates.push(path.join(vendorRoot, vendorDir, "bin", "codex.exe"));
|
|
167
166
|
}
|
|
168
167
|
}
|
|
169
168
|
} catch {}
|
|
170
169
|
}
|
|
171
170
|
|
|
171
|
+
candidates.push(path.join(npmRoot, "codex.cmd"), path.join(npmRoot, "codex"));
|
|
172
|
+
|
|
172
173
|
const finder = spawnSync("where", ["codex.exe"], { encoding: "utf8" });
|
|
173
174
|
const foundExe = (finder.stdout || "")
|
|
174
175
|
.trim()
|
|
@@ -183,93 +184,6 @@ function resolveWindowsCodexCandidates() {
|
|
|
183
184
|
.filter(Boolean);
|
|
184
185
|
candidates.push(...cmdHits);
|
|
185
186
|
|
|
186
|
-
const vendorGlobRoot = path.join(
|
|
187
|
-
npmRoot,
|
|
188
|
-
"node_modules",
|
|
189
|
-
"@openai",
|
|
190
|
-
"codex",
|
|
191
|
-
"node_modules",
|
|
192
|
-
);
|
|
193
|
-
if (fileExists(vendorGlobRoot)) {
|
|
194
|
-
try {
|
|
195
|
-
const dirs = fs.readdirSync(vendorGlobRoot);
|
|
196
|
-
for (const dir of dirs) {
|
|
197
|
-
if (!dir.startsWith("@openai")) continue;
|
|
198
|
-
}
|
|
199
|
-
} catch {}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const packageRoot = path.join(
|
|
203
|
-
npmRoot,
|
|
204
|
-
"node_modules",
|
|
205
|
-
"@openai",
|
|
206
|
-
"codex",
|
|
207
|
-
"node_modules",
|
|
208
|
-
);
|
|
209
|
-
if (fileExists(packageRoot)) {
|
|
210
|
-
try {
|
|
211
|
-
const entries = fs.readdirSync(packageRoot);
|
|
212
|
-
for (const entry of entries) {
|
|
213
|
-
if (!entry.startsWith("@openai")) continue;
|
|
214
|
-
}
|
|
215
|
-
} catch {}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const openaiNodeModules = path.join(
|
|
219
|
-
npmRoot,
|
|
220
|
-
"node_modules",
|
|
221
|
-
"@openai",
|
|
222
|
-
"codex",
|
|
223
|
-
"node_modules",
|
|
224
|
-
);
|
|
225
|
-
if (fileExists(openaiNodeModules)) {
|
|
226
|
-
try {
|
|
227
|
-
const entries = fs.readdirSync(openaiNodeModules);
|
|
228
|
-
for (const entry of entries) {
|
|
229
|
-
if (!entry.startsWith("@openai")) continue;
|
|
230
|
-
}
|
|
231
|
-
} catch {}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const codexNodeModules = path.join(
|
|
235
|
-
npmRoot,
|
|
236
|
-
"node_modules",
|
|
237
|
-
"@openai",
|
|
238
|
-
"codex",
|
|
239
|
-
"node_modules",
|
|
240
|
-
);
|
|
241
|
-
if (fileExists(codexNodeModules)) {
|
|
242
|
-
try {
|
|
243
|
-
const entries = fs.readdirSync(codexNodeModules);
|
|
244
|
-
for (const entry of entries) {
|
|
245
|
-
if (!entry.startsWith("@openai")) continue;
|
|
246
|
-
}
|
|
247
|
-
} catch {}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const directVendorParent = path.join(
|
|
251
|
-
npmRoot,
|
|
252
|
-
"node_modules",
|
|
253
|
-
"@openai",
|
|
254
|
-
"codex",
|
|
255
|
-
"node_modules",
|
|
256
|
-
);
|
|
257
|
-
if (fileExists(directVendorParent)) {
|
|
258
|
-
try {
|
|
259
|
-
const dirs = fs.readdirSync(directVendorParent);
|
|
260
|
-
for (const dir of dirs) {
|
|
261
|
-
if (!dir.includes("codex-win32-")) continue;
|
|
262
|
-
const vendorRoot = path.join(directVendorParent, dir, "vendor");
|
|
263
|
-
if (!fileExists(vendorRoot)) continue;
|
|
264
|
-
const vendorDirs = fs.readdirSync(vendorRoot);
|
|
265
|
-
for (const vendorDir of vendorDirs) {
|
|
266
|
-
const exePath = path.join(vendorRoot, vendorDir, "bin", "codex.exe");
|
|
267
|
-
candidates.push(exePath);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
} catch {}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
187
|
return [...new Set(candidates)].filter(Boolean);
|
|
274
188
|
}
|
|
275
189
|
|
|
@@ -306,10 +220,74 @@ function codexPath() {
|
|
|
306
220
|
return resolveCodexCommand();
|
|
307
221
|
}
|
|
308
222
|
|
|
223
|
+
function buildCodexLaunch(cmd, args) {
|
|
224
|
+
const ext = path.extname(cmd).toLowerCase();
|
|
225
|
+
if (process.platform !== "win32") {
|
|
226
|
+
return {
|
|
227
|
+
command: cmd,
|
|
228
|
+
args,
|
|
229
|
+
shell: false,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (ext === ".ps1") {
|
|
234
|
+
return {
|
|
235
|
+
command: "powershell.exe",
|
|
236
|
+
args: [
|
|
237
|
+
"-NoProfile",
|
|
238
|
+
"-ExecutionPolicy",
|
|
239
|
+
"Bypass",
|
|
240
|
+
"-File",
|
|
241
|
+
cmd,
|
|
242
|
+
...args,
|
|
243
|
+
],
|
|
244
|
+
shell: false,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (ext === ".cmd" || ext === ".bat") {
|
|
249
|
+
return {
|
|
250
|
+
command: "cmd.exe",
|
|
251
|
+
args: ["/d", "/s", "/c", cmd, ...args],
|
|
252
|
+
shell: false,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
command: cmd,
|
|
258
|
+
args,
|
|
259
|
+
shell: false,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
309
263
|
function clearScreen() {
|
|
310
264
|
process.stdout.write("\x1b[2J\x1b[0f");
|
|
311
265
|
}
|
|
312
266
|
|
|
267
|
+
function resetTerminalForChild() {
|
|
268
|
+
process.stdout.write("\x1b[0m\x1b[2J\x1b[3J\x1b[H");
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function suspendTerminalForChild(rl) {
|
|
272
|
+
setRawMode(false);
|
|
273
|
+
if (rl && typeof rl.pause === "function") {
|
|
274
|
+
rl.pause();
|
|
275
|
+
}
|
|
276
|
+
if (typeof process.stdin.pause === "function") {
|
|
277
|
+
process.stdin.pause();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function resumeTerminalAfterChild(rl) {
|
|
282
|
+
if (typeof process.stdin.resume === "function") {
|
|
283
|
+
process.stdin.resume();
|
|
284
|
+
}
|
|
285
|
+
if (rl && typeof rl.resume === "function") {
|
|
286
|
+
rl.resume();
|
|
287
|
+
}
|
|
288
|
+
setRawMode(true);
|
|
289
|
+
}
|
|
290
|
+
|
|
313
291
|
function prompt(rl, text) {
|
|
314
292
|
return new Promise((resolve) => rl.question(text, resolve));
|
|
315
293
|
}
|
|
@@ -519,17 +497,29 @@ function buildCodexEnv(provider) {
|
|
|
519
497
|
};
|
|
520
498
|
}
|
|
521
499
|
|
|
522
|
-
function runCodex(args, env, cwd = process.cwd()) {
|
|
500
|
+
function runCodex(args, env, cwd = process.cwd(), rl = null) {
|
|
523
501
|
return new Promise((resolve, reject) => {
|
|
524
502
|
const cmd = resolveCodexCommand();
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
503
|
+
const launch = buildCodexLaunch(cmd, args);
|
|
504
|
+
const settle = (done, value) => {
|
|
505
|
+
resumeTerminalAfterChild(rl);
|
|
506
|
+
done(value);
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
try {
|
|
510
|
+
suspendTerminalForChild(rl);
|
|
511
|
+
resetTerminalForChild();
|
|
512
|
+
const child = spawn(launch.command, launch.args, {
|
|
513
|
+
cwd,
|
|
514
|
+
stdio: "inherit",
|
|
515
|
+
env: { ...process.env, ...env },
|
|
516
|
+
shell: launch.shell,
|
|
517
|
+
});
|
|
518
|
+
child.on("error", (error) => settle(reject, error));
|
|
519
|
+
child.on("exit", (code) => settle(resolve, code ?? 0));
|
|
520
|
+
} catch (error) {
|
|
521
|
+
settle(reject, error);
|
|
522
|
+
}
|
|
533
523
|
});
|
|
534
524
|
}
|
|
535
525
|
|
|
@@ -889,10 +879,8 @@ async function launchNewSession(rl, cwd = process.cwd()) {
|
|
|
889
879
|
console.log(`准备启动新主线会话 · provider=${provider.name}`);
|
|
890
880
|
await pause(rl, "按回车进入 Codex...");
|
|
891
881
|
|
|
892
|
-
setRawMode(false);
|
|
893
882
|
const startedAtMs = Date.now();
|
|
894
|
-
await runCodex([], buildCodexEnv(provider), projectState.root);
|
|
895
|
-
setRawMode(true);
|
|
883
|
+
await runCodex([], buildCodexEnv(provider), projectState.root, rl);
|
|
896
884
|
|
|
897
885
|
const linkedSessionId = await maybeLinkLatestSession(
|
|
898
886
|
projectState.root,
|
|
@@ -980,9 +968,7 @@ async function resumeSpecificSession(rl, sessionId, cwd = process.cwd()) {
|
|
|
980
968
|
console.log(`provider=${provider.name}`);
|
|
981
969
|
await pause(rl, "按回车进入 Codex...");
|
|
982
970
|
|
|
983
|
-
|
|
984
|
-
await runCodex(["resume", sessionId], buildCodexEnv(provider), projectState.root);
|
|
985
|
-
setRawMode(true);
|
|
971
|
+
await runCodex(["resume", sessionId], buildCodexEnv(provider), projectState.root, rl);
|
|
986
972
|
}
|
|
987
973
|
|
|
988
974
|
async function pickSessionAndResume(rl, cwd = process.cwd()) {
|
|
@@ -1128,10 +1114,8 @@ async function forkFromSession(rl, source, cwd = process.cwd()) {
|
|
|
1128
1114
|
console.log(`provider=${provider.name}`);
|
|
1129
1115
|
await pause(rl, "按回车进入 Codex...");
|
|
1130
1116
|
|
|
1131
|
-
setRawMode(false);
|
|
1132
1117
|
const startedAtMs = Date.now();
|
|
1133
|
-
await runCodex(["fork", source.sessionId], buildCodexEnv(provider), projectState.root);
|
|
1134
|
-
setRawMode(true);
|
|
1118
|
+
await runCodex(["fork", source.sessionId], buildCodexEnv(provider), projectState.root, rl);
|
|
1135
1119
|
|
|
1136
1120
|
const linkedSessionId = await maybeLinkLatestSession(
|
|
1137
1121
|
projectState.root,
|
|
@@ -1184,13 +1168,12 @@ async function deleteSpecificSession(rl, target, cwd = process.cwd()) {
|
|
|
1184
1168
|
};
|
|
1185
1169
|
}
|
|
1186
1170
|
|
|
1187
|
-
setRawMode(false);
|
|
1188
1171
|
const exitCode = await runCodex(
|
|
1189
1172
|
["delete", "--force", target.sessionId],
|
|
1190
1173
|
{},
|
|
1191
1174
|
projectState.root,
|
|
1175
|
+
rl,
|
|
1192
1176
|
);
|
|
1193
|
-
setRawMode(true);
|
|
1194
1177
|
|
|
1195
1178
|
const stillExists = hasOfficialSession(target.sessionId, projectState.root);
|
|
1196
1179
|
if (exitCode !== 0 || stillExists) {
|