@fclef819/cdx 0.1.1 → 0.1.2

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.
Files changed (2) hide show
  1. package/bin/cdx.js +96 -17
  2. package/package.json +1 -1
package/bin/cdx.js CHANGED
@@ -15,6 +15,11 @@ function logVerbose(message, enabled) {
15
15
  if (enabled) console.log(message);
16
16
  }
17
17
 
18
+ function escapePowerShellArg(value) {
19
+ if (value === "") return "''";
20
+ return `'${value.replace(/'/g, "''")}'`;
21
+ }
22
+
18
23
  function findCdxFile(startDir, verbose) {
19
24
  let dir = path.resolve(startDir);
20
25
  while (true) {
@@ -148,22 +153,66 @@ function getNewestHistorySessionIdSince(previousId, verbose) {
148
153
 
149
154
  function runCodex(args, cwd, verbose) {
150
155
  logVerbose(`Running codex ${args.join(" ")}`.trim(), verbose);
151
- const check = spawnSync("codex", ["--version"], { stdio: "ignore" });
152
- if (check.error && check.error.code === "ENOENT") {
156
+ const result = spawnSync("codex", args, { stdio: "inherit", cwd });
157
+ if (result.error) {
158
+ if (result.error.code === "ENOENT" && process.platform === "win32") {
159
+ logVerbose("codex not found directly; trying PowerShell fallback", verbose);
160
+ const psArgs = [
161
+ "-NoProfile",
162
+ "-Command",
163
+ ["codex", ...args.map(escapePowerShellArg)].join(" ")
164
+ ];
165
+ const psResult = spawnSync("powershell.exe", psArgs, {
166
+ stdio: "inherit",
167
+ cwd
168
+ });
169
+ if (!psResult.error) {
170
+ if (psResult.status !== 0) process.exit(psResult.status ?? 1);
171
+ return;
172
+ }
173
+ }
153
174
  console.error(
154
175
  "Codex CLI is not available. Please install it and ensure `codex` is on your PATH."
155
176
  );
156
177
  process.exit(1);
157
178
  }
158
- const result = spawnSync("codex", args, { stdio: "inherit", cwd });
159
- if (result.error) {
160
- console.error("Failed to run codex:", result.error.message);
161
- process.exit(result.status ?? 1);
162
- }
163
179
  if (result.status !== 0) process.exit(result.status ?? 1);
164
180
  }
165
181
 
182
+ function printSessionList(entries) {
183
+ console.log("0: new");
184
+ entries.forEach((entry, index) => {
185
+ console.log(`${index + 1}: ${entry.label} (${entry.uuid})`);
186
+ });
187
+ }
188
+
166
189
  async function selectSession(entries) {
190
+ if (!entries.length) {
191
+ return { type: "new" };
192
+ }
193
+
194
+ printSessionList(entries);
195
+ while (true) {
196
+ const numberInput = await prompts({
197
+ type: "text",
198
+ name: "value",
199
+ message: "Select by number (Enter for list selection)",
200
+ validate: (value) => {
201
+ if (!value || !value.trim()) return true;
202
+ if (!/^\d+$/.test(value.trim())) return "Enter a number";
203
+ const index = Number.parseInt(value.trim(), 10);
204
+ if (index < 0 || index > entries.length) return "Out of range";
205
+ return true;
206
+ }
207
+ });
208
+
209
+ if (!numberInput.value && numberInput.value !== "0") break;
210
+ const index = Number.parseInt(String(numberInput.value).trim(), 10);
211
+ if (Number.isNaN(index)) break;
212
+ if (index === 0) return { type: "new" };
213
+ return { type: "resume", entry: entries[index - 1] };
214
+ }
215
+
167
216
  const choices = [
168
217
  { title: "new", value: { type: "new" } },
169
218
  ...entries.map((entry) => ({
@@ -261,18 +310,48 @@ async function runRemove(startDir, verbose) {
261
310
  }
262
311
 
263
312
  console.log(`.cdx: ${targetPath}`);
264
- const response = await prompts({
265
- type: "select",
266
- name: "selection",
267
- message: "Select a session to remove",
268
- choices: entries.map((entry) => ({
269
- title: `${entry.label} (${entry.uuid})`,
270
- value: entry.uuid
271
- }))
313
+ entries.forEach((entry, index) => {
314
+ console.log(`${index + 1}: ${entry.label} (${entry.uuid})`);
272
315
  });
273
316
 
274
- if (!response.selection) return;
275
- const remaining = entries.filter((entry) => entry.uuid !== response.selection);
317
+ let selectedUuid = null;
318
+ while (true) {
319
+ const numberInput = await prompts({
320
+ type: "text",
321
+ name: "value",
322
+ message: "Select by number (Enter for list selection)",
323
+ validate: (value) => {
324
+ if (!value || !value.trim()) return true;
325
+ if (!/^\d+$/.test(value.trim())) return "Enter a number";
326
+ const index = Number.parseInt(value.trim(), 10);
327
+ if (index < 1 || index > entries.length) return "Out of range";
328
+ return true;
329
+ }
330
+ });
331
+
332
+ if (!numberInput.value) break;
333
+ const index = Number.parseInt(String(numberInput.value).trim(), 10);
334
+ if (!Number.isNaN(index)) {
335
+ selectedUuid = entries[index - 1].uuid;
336
+ }
337
+ break;
338
+ }
339
+
340
+ if (!selectedUuid) {
341
+ const response = await prompts({
342
+ type: "select",
343
+ name: "selection",
344
+ message: "Select a session to remove",
345
+ choices: entries.map((entry) => ({
346
+ title: `${entry.label} (${entry.uuid})`,
347
+ value: entry.uuid
348
+ }))
349
+ });
350
+ if (!response.selection) return;
351
+ selectedUuid = response.selection;
352
+ }
353
+
354
+ const remaining = entries.filter((entry) => entry.uuid !== selectedUuid);
276
355
  writeEntries(targetPath, remaining, verbose);
277
356
  }
278
357
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fclef819/cdx",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Codex session wrapper",
5
5
  "keywords": [
6
6
  "codex",