@childclm/codexx 0.1.2 → 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 CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@childclm/codexx",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Cross-platform launcher for Codex CLI with project-scoped session trees and provider switching.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -144,50 +144,46 @@ 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
- const localShims = [
148
- path.join(npmRoot, "codex.exe"),
149
- path.join(npmRoot, "codex.cmd"),
150
- path.join(npmRoot, "codex"),
151
- ];
152
- candidates.push(...localShims);
153
147
 
154
- const finder = spawnSync("where", ["codex.exe"], { encoding: "utf8" });
155
- const foundExe = (finder.stdout || "")
156
- .trim()
157
- .split(/\r?\n/)
158
- .filter(Boolean);
159
- candidates.push(...foundExe);
160
-
161
- const foundCmd = spawnSync("where", ["codex.cmd"], { encoding: "utf8" });
162
- const cmdHits = (foundCmd.stdout || "")
163
- .trim()
164
- .split(/\r?\n/)
165
- .filter(Boolean);
166
- candidates.push(...cmdHits);
167
-
168
- const directVendorParent = path.join(
148
+ const nativePackageScope = path.join(
169
149
  npmRoot,
170
150
  "node_modules",
171
151
  "@openai",
172
152
  "codex",
173
153
  "node_modules",
154
+ "@openai",
174
155
  );
175
- if (fileExists(directVendorParent)) {
156
+ if (fileExists(nativePackageScope)) {
176
157
  try {
177
- const dirs = fs.readdirSync(directVendorParent);
158
+ const dirs = fs.readdirSync(nativePackageScope);
178
159
  for (const dir of dirs) {
179
- if (!dir.includes("codex-win32-")) continue;
180
- const vendorRoot = path.join(directVendorParent, dir, "vendor");
160
+ if (!dir.startsWith("codex-win32-")) continue;
161
+ const vendorRoot = path.join(nativePackageScope, dir, "vendor");
181
162
  if (!fileExists(vendorRoot)) continue;
182
163
  const vendorDirs = fs.readdirSync(vendorRoot);
183
164
  for (const vendorDir of vendorDirs) {
184
- const exePath = path.join(vendorRoot, vendorDir, "bin", "codex.exe");
185
- candidates.push(exePath);
165
+ candidates.push(path.join(vendorRoot, vendorDir, "bin", "codex.exe"));
186
166
  }
187
167
  }
188
168
  } catch {}
189
169
  }
190
170
 
171
+ candidates.push(path.join(npmRoot, "codex.cmd"), path.join(npmRoot, "codex"));
172
+
173
+ const finder = spawnSync("where", ["codex.exe"], { encoding: "utf8" });
174
+ const foundExe = (finder.stdout || "")
175
+ .trim()
176
+ .split(/\r?\n/)
177
+ .filter(Boolean);
178
+ candidates.push(...foundExe);
179
+
180
+ const foundCmd = spawnSync("where", ["codex.cmd"], { encoding: "utf8" });
181
+ const cmdHits = (foundCmd.stdout || "")
182
+ .trim()
183
+ .split(/\r?\n/)
184
+ .filter(Boolean);
185
+ candidates.push(...cmdHits);
186
+
191
187
  return [...new Set(candidates)].filter(Boolean);
192
188
  }
193
189
 
@@ -268,6 +264,30 @@ function clearScreen() {
268
264
  process.stdout.write("\x1b[2J\x1b[0f");
269
265
  }
270
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
+
271
291
  function prompt(rl, text) {
272
292
  return new Promise((resolve) => rl.question(text, resolve));
273
293
  }
@@ -477,18 +497,29 @@ function buildCodexEnv(provider) {
477
497
  };
478
498
  }
479
499
 
480
- function runCodex(args, env, cwd = process.cwd()) {
500
+ function runCodex(args, env, cwd = process.cwd(), rl = null) {
481
501
  return new Promise((resolve, reject) => {
482
502
  const cmd = resolveCodexCommand();
483
503
  const launch = buildCodexLaunch(cmd, args);
484
- const child = spawn(launch.command, launch.args, {
485
- cwd,
486
- stdio: "inherit",
487
- env: { ...process.env, ...env },
488
- shell: launch.shell,
489
- });
490
- child.on("error", reject);
491
- child.on("exit", (code) => resolve(code ?? 0));
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
+ }
492
523
  });
493
524
  }
494
525
 
@@ -848,10 +879,8 @@ async function launchNewSession(rl, cwd = process.cwd()) {
848
879
  console.log(`准备启动新主线会话 · provider=${provider.name}`);
849
880
  await pause(rl, "按回车进入 Codex...");
850
881
 
851
- setRawMode(false);
852
882
  const startedAtMs = Date.now();
853
- await runCodex([], buildCodexEnv(provider), projectState.root);
854
- setRawMode(true);
883
+ await runCodex([], buildCodexEnv(provider), projectState.root, rl);
855
884
 
856
885
  const linkedSessionId = await maybeLinkLatestSession(
857
886
  projectState.root,
@@ -939,9 +968,7 @@ async function resumeSpecificSession(rl, sessionId, cwd = process.cwd()) {
939
968
  console.log(`provider=${provider.name}`);
940
969
  await pause(rl, "按回车进入 Codex...");
941
970
 
942
- setRawMode(false);
943
- await runCodex(["resume", sessionId], buildCodexEnv(provider), projectState.root);
944
- setRawMode(true);
971
+ await runCodex(["resume", sessionId], buildCodexEnv(provider), projectState.root, rl);
945
972
  }
946
973
 
947
974
  async function pickSessionAndResume(rl, cwd = process.cwd()) {
@@ -1087,10 +1114,8 @@ async function forkFromSession(rl, source, cwd = process.cwd()) {
1087
1114
  console.log(`provider=${provider.name}`);
1088
1115
  await pause(rl, "按回车进入 Codex...");
1089
1116
 
1090
- setRawMode(false);
1091
1117
  const startedAtMs = Date.now();
1092
- await runCodex(["fork", source.sessionId], buildCodexEnv(provider), projectState.root);
1093
- setRawMode(true);
1118
+ await runCodex(["fork", source.sessionId], buildCodexEnv(provider), projectState.root, rl);
1094
1119
 
1095
1120
  const linkedSessionId = await maybeLinkLatestSession(
1096
1121
  projectState.root,
@@ -1143,13 +1168,12 @@ async function deleteSpecificSession(rl, target, cwd = process.cwd()) {
1143
1168
  };
1144
1169
  }
1145
1170
 
1146
- setRawMode(false);
1147
1171
  const exitCode = await runCodex(
1148
1172
  ["delete", "--force", target.sessionId],
1149
1173
  {},
1150
1174
  projectState.root,
1175
+ rl,
1151
1176
  );
1152
- setRawMode(true);
1153
1177
 
1154
1178
  const stillExists = hasOfficialSession(target.sessionId, projectState.root);
1155
1179
  if (exitCode !== 0 || stillExists) {