codex-multi-auth 0.1.5 → 0.1.8

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 (75) hide show
  1. package/LICENSE +21 -1
  2. package/README.md +19 -6
  3. package/assets/readme-hero.svg +31 -31
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/lib/codex-cli/state.js +4 -4
  9. package/dist/lib/codex-cli/state.js.map +1 -1
  10. package/dist/lib/codex-cli/sync.d.ts +9 -16
  11. package/dist/lib/codex-cli/sync.d.ts.map +1 -1
  12. package/dist/lib/codex-cli/sync.js +51 -284
  13. package/dist/lib/codex-cli/sync.js.map +1 -1
  14. package/dist/lib/codex-cli/writer.d.ts.map +1 -1
  15. package/dist/lib/codex-cli/writer.js +62 -5
  16. package/dist/lib/codex-cli/writer.js.map +1 -1
  17. package/dist/lib/codex-manager/settings-hub.d.ts +44 -2
  18. package/dist/lib/codex-manager/settings-hub.d.ts.map +1 -1
  19. package/dist/lib/codex-manager/settings-hub.js +746 -117
  20. package/dist/lib/codex-manager/settings-hub.js.map +1 -1
  21. package/dist/lib/codex-manager.d.ts.map +1 -1
  22. package/dist/lib/codex-manager.js +3 -8
  23. package/dist/lib/codex-manager.js.map +1 -1
  24. package/dist/lib/context-overflow.js +10 -10
  25. package/dist/lib/named-backup-export.d.ts +69 -0
  26. package/dist/lib/named-backup-export.d.ts.map +1 -0
  27. package/dist/lib/named-backup-export.js +207 -0
  28. package/dist/lib/named-backup-export.js.map +1 -0
  29. package/dist/lib/oauth-success.html +66 -210
  30. package/dist/lib/oc-chatgpt-import-adapter.d.ts +64 -0
  31. package/dist/lib/oc-chatgpt-import-adapter.d.ts.map +1 -0
  32. package/dist/lib/oc-chatgpt-import-adapter.js +506 -0
  33. package/dist/lib/oc-chatgpt-import-adapter.js.map +1 -0
  34. package/dist/lib/oc-chatgpt-orchestrator.d.ts +80 -0
  35. package/dist/lib/oc-chatgpt-orchestrator.d.ts.map +1 -0
  36. package/dist/lib/oc-chatgpt-orchestrator.js +130 -0
  37. package/dist/lib/oc-chatgpt-orchestrator.js.map +1 -0
  38. package/dist/lib/oc-chatgpt-target-detection.d.ts +59 -0
  39. package/dist/lib/oc-chatgpt-target-detection.d.ts.map +1 -0
  40. package/dist/lib/oc-chatgpt-target-detection.js +327 -0
  41. package/dist/lib/oc-chatgpt-target-detection.js.map +1 -0
  42. package/dist/lib/prompts/codex.js +2 -2
  43. package/dist/lib/runtime-paths.d.ts.map +1 -1
  44. package/dist/lib/runtime-paths.js +44 -2
  45. package/dist/lib/runtime-paths.js.map +1 -1
  46. package/dist/lib/storage.d.ts +42 -3
  47. package/dist/lib/storage.d.ts.map +1 -1
  48. package/dist/lib/storage.js +634 -49
  49. package/dist/lib/storage.js.map +1 -1
  50. package/dist/lib/ui/auth-menu.d.ts.map +1 -1
  51. package/dist/lib/ui/auth-menu.js +13 -1
  52. package/dist/lib/ui/auth-menu.js.map +1 -1
  53. package/dist/lib/ui/copy.d.ts +15 -1
  54. package/dist/lib/ui/copy.d.ts.map +1 -1
  55. package/dist/lib/ui/copy.js +15 -1
  56. package/dist/lib/ui/copy.js.map +1 -1
  57. package/node_modules/@codex-ai/plugin/dist/index.d.ts +1 -1
  58. package/node_modules/@codex-ai/plugin/dist/tool.d.ts +41 -41
  59. package/node_modules/@codex-ai/plugin/dist/tool.js +28 -28
  60. package/package.json +132 -133
  61. package/scripts/bench-format/hashline-v2.mjs +642 -642
  62. package/scripts/bench-format/render.mjs +496 -496
  63. package/scripts/bench-format/stats.mjs +54 -54
  64. package/scripts/bench-format/tasks.mjs +151 -151
  65. package/scripts/benchmark-render-dashboard.mjs +49 -49
  66. package/scripts/codex-multi-auth.js +12 -0
  67. package/scripts/codex.js +315 -2
  68. package/scripts/install-codex-auth.js +9 -9
  69. package/scripts/test-all-models.sh +7 -7
  70. package/scripts/test-model-matrix.js +247 -148
  71. package/scripts/validate-model-map.sh +7 -7
  72. package/vendor/codex-ai-plugin/dist/index.d.ts +1 -1
  73. package/vendor/codex-ai-plugin/dist/tool.d.ts +41 -41
  74. package/vendor/codex-ai-plugin/dist/tool.js +28 -28
  75. package/vendor/codex-ai-sdk/dist/index.d.ts +3 -3
@@ -1,62 +1,66 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { readFile, writeFile, rm, mkdir } from "node:fs/promises";
3
- import { spawnSync } from "node:child_process";
4
- import { dirname, join, resolve } from "node:path";
5
- import { fileURLToPath } from "node:url";
6
- import process from "node:process";
1
+ import { spawnSync } from "node:child_process";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import process from "node:process";
6
+ import { fileURLToPath } from "node:url";
7
7
 
8
8
  const scriptDir = dirname(fileURLToPath(import.meta.url));
9
9
  const repoRoot = resolve(scriptDir, "..");
10
- const localConfigPaths = [join(repoRoot, ".codex.json"), join(repoRoot, "Codex.json")];
10
+ const localConfigPaths = [
11
+ join(repoRoot, ".codex.json"),
12
+ join(repoRoot, "Codex.json"),
13
+ ];
11
14
  const scenarioTemplates = {
12
15
  legacy: join(repoRoot, "config", "codex-legacy.json"),
13
16
  modern: join(repoRoot, "config", "codex-modern.json"),
14
17
  };
15
18
 
16
- const pluginPackageName = "codex-multi-auth";
17
- const DEFAULT_MATRIX_TIMEOUT_MS = 120000;
18
-
19
- function resolveCmdScriptEntry(commandPath) {
20
- if (!/\.cmd$/i.test(commandPath)) {
21
- return null;
22
- }
23
- try {
24
- const raw = readFileSync(commandPath, "utf8");
25
- const match = raw.match(/"%dp0%\\([^"\r\n]+\.js)"/i);
26
- if (!match || typeof match[1] !== "string") {
27
- return null;
28
- }
29
- const relScriptPath = match[1].replace(/[\\/]+/g, "/");
30
- const scriptPath = resolve(dirname(commandPath), relScriptPath);
31
- return existsSync(scriptPath) ? scriptPath : null;
32
- } catch {
33
- return null;
34
- }
35
- }
36
-
37
- function buildExecutable(command) {
38
- const scriptEntry = resolveCmdScriptEntry(command);
39
- if (scriptEntry) {
40
- return {
41
- command: process.execPath,
42
- shell: false,
43
- prefixArgs: [scriptEntry],
44
- displayCommand: command,
45
- };
46
- }
47
- return { command, shell: /\.cmd$/i.test(command) };
48
- }
49
-
50
- export function resolveCodexExecutable() {
51
- const envOverride = process.env.CODEX_BIN;
52
- if (envOverride && envOverride.trim().length > 0) {
53
- const command = envOverride.trim();
54
- return buildExecutable(command);
55
- }
56
-
57
- if (process.platform !== "win32") {
58
- return { command: "codex", shell: false };
59
- }
19
+ const pluginPackageName = "codex-multi-auth";
20
+ const DEFAULT_MATRIX_TIMEOUT_MS = 120000;
21
+ const DEFAULT_SMOKE_MATRIX_TIMEOUT_MS = 15000;
22
+
23
+ function resolveCmdScriptEntry(commandPath) {
24
+ if (!/\.cmd$/i.test(commandPath)) {
25
+ return null;
26
+ }
27
+ try {
28
+ const raw = readFileSync(commandPath, "utf8");
29
+ const match = raw.match(/"%dp0%\\([^"\r\n]+\.js)"/i);
30
+ if (!match || typeof match[1] !== "string") {
31
+ return null;
32
+ }
33
+ const relScriptPath = match[1].replace(/[\\/]+/g, "/");
34
+ const scriptPath = resolve(dirname(commandPath), relScriptPath);
35
+ return existsSync(scriptPath) ? scriptPath : null;
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+
41
+ function buildExecutable(command) {
42
+ const scriptEntry = resolveCmdScriptEntry(command);
43
+ if (scriptEntry) {
44
+ return {
45
+ command: process.execPath,
46
+ shell: false,
47
+ prefixArgs: [scriptEntry],
48
+ displayCommand: command,
49
+ };
50
+ }
51
+ return { command, shell: /\.cmd$/i.test(command) };
52
+ }
53
+
54
+ export function resolveCodexExecutable() {
55
+ const envOverride = process.env.CODEX_BIN;
56
+ if (envOverride && envOverride.trim().length > 0) {
57
+ const command = envOverride.trim();
58
+ return buildExecutable(command);
59
+ }
60
+
61
+ if (process.platform !== "win32") {
62
+ return { command: "codex", shell: false };
63
+ }
60
64
 
61
65
  const whereResult = spawnSync("where", ["Codex"], {
62
66
  encoding: "utf8",
@@ -71,27 +75,27 @@ export function resolveCodexExecutable() {
71
75
  return { command: "codex", shell: false };
72
76
  }
73
77
 
74
- const exactExe = candidates.find((candidate) =>
75
- /npm\\Codex\.exe$/i.test(candidate),
76
- );
77
- if (exactExe) {
78
- return { command: exactExe, shell: false };
79
- }
80
-
81
- const exactCmd = candidates.find((candidate) =>
82
- /npm\\Codex\.cmd$/i.test(candidate),
83
- );
84
- if (exactCmd) {
85
- return buildExecutable(exactCmd);
86
- }
87
-
88
- const anyCmd = candidates.find((candidate) => /\.cmd$/i.test(candidate));
89
- if (anyCmd) {
90
- return buildExecutable(anyCmd);
91
- }
92
-
93
- return { command: candidates[0], shell: false };
94
- }
78
+ const exactExe = candidates.find((candidate) =>
79
+ /npm\\Codex\.exe$/i.test(candidate),
80
+ );
81
+ if (exactExe) {
82
+ return { command: exactExe, shell: false };
83
+ }
84
+
85
+ const exactCmd = candidates.find((candidate) =>
86
+ /npm\\Codex\.cmd$/i.test(candidate),
87
+ );
88
+ if (exactCmd) {
89
+ return buildExecutable(exactCmd);
90
+ }
91
+
92
+ const anyCmd = candidates.find((candidate) => /\.cmd$/i.test(candidate));
93
+ if (anyCmd) {
94
+ return buildExecutable(anyCmd);
95
+ }
96
+
97
+ return { command: candidates[0], shell: false };
98
+ }
95
99
 
96
100
  const CodexExecutable = resolveCodexExecutable();
97
101
 
@@ -130,6 +134,9 @@ function toFileUri(pathValue) {
130
134
  return `file:///${normalized}`;
131
135
  }
132
136
 
137
+ let stopCodexServersQueue = Promise.resolve();
138
+ const spawnedCodexPids = new Set();
139
+
133
140
  function runQuiet(command, commandArgs) {
134
141
  try {
135
142
  spawnSync(command, commandArgs, {
@@ -141,9 +148,6 @@ function runQuiet(command, commandArgs) {
141
148
  }
142
149
  }
143
150
 
144
- let stopCodexServersQueue = Promise.resolve();
145
- const spawnedCodexPids = new Set();
146
-
147
151
  export function registerSpawnedCodex(pid) {
148
152
  if (!Number.isInteger(pid) || pid <= 0) return;
149
153
  spawnedCodexPids.add(pid);
@@ -153,14 +157,72 @@ export function __resetTrackedCodexPidsForTests() {
153
157
  spawnedCodexPids.clear();
154
158
  }
155
159
 
156
- export function resolveMatrixTimeoutMs() {
157
- const parsedTimeout = Number.parseInt(process.env.CODEX_MATRIX_TIMEOUT_MS ?? String(DEFAULT_MATRIX_TIMEOUT_MS), 10);
160
+ export function resolveMatrixTimeoutMs(smoke = false) {
161
+ const fallback = smoke
162
+ ? DEFAULT_SMOKE_MATRIX_TIMEOUT_MS
163
+ : DEFAULT_MATRIX_TIMEOUT_MS;
164
+ const parsedTimeout = Number.parseInt(
165
+ process.env.CODEX_MATRIX_TIMEOUT_MS ?? String(fallback),
166
+ 10,
167
+ );
158
168
  if (!Number.isFinite(parsedTimeout) || parsedTimeout <= 0) {
159
- return DEFAULT_MATRIX_TIMEOUT_MS;
169
+ return fallback;
160
170
  }
161
171
  return parsedTimeout;
162
172
  }
163
173
 
174
+ function hasCompletedSuccessfully(output, token) {
175
+ return (
176
+ output.includes(token) ||
177
+ output.includes('"type":"turn.completed"') ||
178
+ output.includes('"type":"response.completed"')
179
+ );
180
+ }
181
+
182
+ function getSmokeSkipReason(exitCode, output) {
183
+ if (exitCode === 124) {
184
+ return "timed-out";
185
+ }
186
+ if (/not supported when using codex with a chatgpt account/i.test(output)) {
187
+ return "unsupported-model";
188
+ }
189
+ if (
190
+ /unsupported value:\s*['"]xhigh['"]/i.test(output) ||
191
+ /unsupported_value/i.test(output)
192
+ ) {
193
+ return "unsupported-reasoning";
194
+ }
195
+ return null;
196
+ }
197
+
198
+ function finalizeModelCaseResult(caseInfo, exitCode, output, token, smoke) {
199
+ const hasToken = output.includes(token);
200
+ const completed = hasCompletedSuccessfully(output, token);
201
+ const ok = exitCode === 0 && completed;
202
+ const skipReason = !ok && smoke ? getSmokeSkipReason(exitCode, output) : null;
203
+
204
+ return {
205
+ ...caseInfo,
206
+ ok,
207
+ exitCode,
208
+ hasToken,
209
+ completed,
210
+ skipped: skipReason !== null,
211
+ skipReason,
212
+ output,
213
+ };
214
+ }
215
+
216
+ export function __finalizeModelCaseResultForTests(
217
+ caseInfo,
218
+ exitCode,
219
+ output,
220
+ token,
221
+ smoke = false,
222
+ ) {
223
+ return finalizeModelCaseResult(caseInfo, exitCode, output, token, smoke);
224
+ }
225
+
164
226
  function stopCodexServersInternal() {
165
227
  const tracked = [...spawnedCodexPids];
166
228
  spawnedCodexPids.clear();
@@ -244,28 +306,36 @@ function enumerateCases(models, smoke, maxCases) {
244
306
  return selected;
245
307
  }
246
308
 
247
- function executeModelCase(caseInfo, index) {
248
- const token = `MODEL_MATRIX_OK_${index}`;
249
- const message = token;
250
- const args = [
251
- "exec",
252
- message,
253
- "--model",
254
- caseInfo.model,
255
- "--json",
256
- "--skip-git-repo-check",
257
- ];
258
- if (caseInfo.variant) {
259
- args.push("-c", `model_reasoning_effort="${caseInfo.variant}"`);
260
- }
261
-
262
- const timeoutMs = resolveMatrixTimeoutMs();
263
- const commandArgs = [...(CodexExecutable.prefixArgs ?? []), ...args];
264
- const finalized = spawnSync(CodexExecutable.command, commandArgs, {
265
- cwd: repoRoot,
266
- encoding: "utf8",
267
- windowsHide: true,
268
- shell: CodexExecutable.shell,
309
+ function buildModelCaseArgs(caseInfo, index) {
310
+ const token = `MODEL_MATRIX_OK_${index}`;
311
+ const args = [
312
+ "exec",
313
+ token,
314
+ "--model",
315
+ caseInfo.model,
316
+ "--json",
317
+ "--skip-git-repo-check",
318
+ ];
319
+ if (caseInfo.variant) {
320
+ args.push("-c", `model_reasoning_effort="${caseInfo.variant}"`);
321
+ }
322
+ return { token, args };
323
+ }
324
+
325
+ export function __buildModelCaseArgsForTests(caseInfo, index) {
326
+ return buildModelCaseArgs(caseInfo, index);
327
+ }
328
+
329
+ function executeModelCase(caseInfo, index) {
330
+ const { token, args } = buildModelCaseArgs(caseInfo, index);
331
+
332
+ const timeoutMs = resolveMatrixTimeoutMs(caseInfo.smoke === true);
333
+ const commandArgs = [...(CodexExecutable.prefixArgs ?? []), ...args];
334
+ const finalized = spawnSync(CodexExecutable.command, commandArgs, {
335
+ cwd: repoRoot,
336
+ encoding: "utf8",
337
+ windowsHide: true,
338
+ shell: CodexExecutable.shell,
269
339
  timeout: timeoutMs,
270
340
  killSignal: "SIGKILL",
271
341
  env: {
@@ -277,27 +347,25 @@ function executeModelCase(caseInfo, index) {
277
347
  });
278
348
 
279
349
  if (finalized.error && finalized.error.code === "ETIMEDOUT") {
280
- return {
281
- ...caseInfo,
282
- ok: false,
283
- exitCode: 124,
284
- hasToken: false,
285
- output: `Timed out after ${timeoutMs}ms`,
286
- };
350
+ return finalizeModelCaseResult(
351
+ caseInfo,
352
+ 124,
353
+ `Timed out after ${timeoutMs}ms`,
354
+ token,
355
+ caseInfo.smoke === true,
356
+ );
287
357
  }
288
358
 
289
- const combinedOutput = `${finalized.stdout ?? ""}\n${finalized.stderr ?? ""}`.trim();
290
- const hasToken = combinedOutput.includes(token);
291
- const exitCode = finalized.status ?? 1;
292
- const ok = exitCode === 0 && hasToken;
293
-
294
- return {
295
- ...caseInfo,
296
- ok,
359
+ const combinedOutput =
360
+ `${finalized.stdout ?? ""}\n${finalized.stderr ?? ""}`.trim();
361
+ const exitCode = finalized.status ?? 1;
362
+ return finalizeModelCaseResult(
363
+ caseInfo,
297
364
  exitCode,
298
- hasToken,
299
- output: combinedOutput,
300
- };
365
+ combinedOutput,
366
+ token,
367
+ caseInfo.smoke === true,
368
+ );
301
369
  }
302
370
 
303
371
  async function readJson(pathValue) {
@@ -357,31 +425,43 @@ async function prepareScenarioConfig(templatePath, pluginRef) {
357
425
  async function runScenario(scenario, options) {
358
426
  const templatePath = scenarioTemplates[scenario];
359
427
  if (!templatePath || !existsSync(templatePath)) {
360
- throw new Error(`Template not found for scenario '${scenario}': ${templatePath}`);
428
+ throw new Error(
429
+ `Template not found for scenario '${scenario}': ${templatePath}`,
430
+ );
361
431
  }
362
432
 
363
433
  const config = await prepareScenarioConfig(templatePath, options.pluginRef);
364
434
  const models = config?.provider?.openai?.models;
365
435
  if (!models || typeof models !== "object") {
366
- throw new Error(`Scenario '${scenario}' has no provider.openai.models object`);
436
+ throw new Error(
437
+ `Scenario '${scenario}' has no provider.openai.models object`,
438
+ );
367
439
  }
368
440
 
369
- const cases = enumerateCases(models, options.smoke, options.maxCases);
441
+ const cases = enumerateCases(models, options.smoke, options.maxCases).map(
442
+ (caseInfo) => ({
443
+ ...caseInfo,
444
+ smoke: options.smoke,
445
+ }),
446
+ );
370
447
  console.log(`\n=== ${scenario.toUpperCase()} (${cases.length} cases) ===`);
371
448
 
372
449
  const results = [];
373
450
  for (let i = 0; i < cases.length; i += 1) {
374
- const caseInfo = cases[i];
375
- const result = executeModelCase(
376
- caseInfo,
377
- i + 1,
378
- );
451
+ const caseInfo = cases[i];
452
+ const result = executeModelCase(caseInfo, i + 1);
379
453
  results.push(result);
380
454
  const variantLabel = result.variant ? ` [variant=${result.variant}]` : "";
381
455
  if (result.ok) {
382
456
  console.log(`PASS ${result.model}${variantLabel}`);
457
+ } else if (result.skipped) {
458
+ console.log(
459
+ `SKIP ${result.model}${variantLabel} (${result.skipReason})`,
460
+ );
383
461
  } else {
384
- console.log(`FAIL ${result.model}${variantLabel} (exit=${result.exitCode}, token=${result.hasToken})`);
462
+ console.log(
463
+ `FAIL ${result.model}${variantLabel} (exit=${result.exitCode}, token=${result.hasToken})`,
464
+ );
385
465
  const tail = result.output.split(/\r?\n/).slice(-12).join("\n");
386
466
  if (tail.trim().length > 0) {
387
467
  console.log(tail);
@@ -399,8 +479,9 @@ async function main() {
399
479
  return;
400
480
  }
401
481
 
402
- const scenarioValue = parseArgValue(args, "--scenario") ?? "all";
403
482
  const smoke = args.includes("--smoke");
483
+ const scenarioValue =
484
+ parseArgValue(args, "--scenario") ?? (smoke ? "modern" : "all");
404
485
  const pluginMode = parseArgValue(args, "--plugin") ?? "dist";
405
486
  const noRestore = args.includes("--no-restore");
406
487
  const maxCasesRaw = parseArgValue(args, "--max-cases");
@@ -411,13 +492,19 @@ async function main() {
411
492
  : undefined;
412
493
 
413
494
  if (!["all", "legacy", "modern"].includes(scenarioValue)) {
414
- throw new Error(`Invalid --scenario value '${scenarioValue}'. Use legacy, modern, or all.`);
495
+ throw new Error(
496
+ `Invalid --scenario value '${scenarioValue}'. Use legacy, modern, or all.`,
497
+ );
415
498
  }
416
499
  if (!["dist", "package"].includes(pluginMode)) {
417
- throw new Error(`Invalid --plugin value '${pluginMode}'. Use dist or package.`);
500
+ throw new Error(
501
+ `Invalid --plugin value '${pluginMode}'. Use dist or package.`,
502
+ );
418
503
  }
419
504
  if (Number.isNaN(maxCases) || maxCases < 0) {
420
- throw new Error(`Invalid --max-cases value '${maxCasesRaw}'. Use a non-negative integer.`);
505
+ throw new Error(
506
+ `Invalid --max-cases value '${maxCasesRaw}'. Use a non-negative integer.`,
507
+ );
421
508
  }
422
509
 
423
510
  const pluginRef = resolvePluginReference(pluginMode);
@@ -426,10 +513,12 @@ async function main() {
426
513
 
427
514
  console.log("Codex Model Matrix Audit");
428
515
  console.log(`Repo: ${repoRoot}`);
429
- console.log(`Scenarios: ${scenarios.join(", ")}`);
430
- console.log(`Mode: ${smoke ? "smoke" : "full"}`);
431
- console.log(`Plugin: ${pluginRef}`);
432
- console.log(`Codex command: ${CodexExecutable.displayCommand ?? CodexExecutable.command}`);
516
+ console.log(`Scenarios: ${scenarios.join(", ")}`);
517
+ console.log(`Mode: ${smoke ? "smoke" : "full"}`);
518
+ console.log(`Plugin: ${pluginRef}`);
519
+ console.log(
520
+ `Codex command: ${CodexExecutable.displayCommand ?? CodexExecutable.command}`,
521
+ );
433
522
 
434
523
  const backups = await backupLocalConfigs();
435
524
  const allResults = [];
@@ -441,9 +530,10 @@ async function main() {
441
530
  smoke,
442
531
  maxCases,
443
532
  pluginRef,
444
- portStart: 47000 + i * 500,
445
533
  });
446
- allResults.push(...scenarioResults.map((item) => ({ ...item, scenario })));
534
+ allResults.push(
535
+ ...scenarioResults.map((item) => ({ ...item, scenario })),
536
+ );
447
537
  }
448
538
  } finally {
449
539
  if (!noRestore) {
@@ -451,11 +541,13 @@ async function main() {
451
541
  }
452
542
  }
453
543
 
454
- const failed = allResults.filter((result) => !result.ok);
455
- const passed = allResults.length - failed.length;
544
+ const passed = allResults.filter((result) => result.ok);
545
+ const skipped = allResults.filter((result) => result.skipped);
546
+ const failed = allResults.filter((result) => !result.ok && !result.skipped);
456
547
  console.log("\n=== SUMMARY ===");
457
548
  console.log(`Total: ${allResults.length}`);
458
- console.log(`Passed: ${passed}`);
549
+ console.log(`Passed: ${passed.length}`);
550
+ console.log(`Skipped: ${skipped.length}`);
459
551
  console.log(`Failed: ${failed.length}`);
460
552
 
461
553
  if (reportJsonPath) {
@@ -463,18 +555,23 @@ async function main() {
463
555
  generatedAt: new Date().toISOString(),
464
556
  repoRoot,
465
557
  scenarios,
466
- mode: smoke ? "smoke" : "full",
467
- plugin: pluginRef,
468
- CodexCommand: CodexExecutable.displayCommand ?? CodexExecutable.command,
469
- totals: {
558
+ mode: smoke ? "smoke" : "full",
559
+ plugin: pluginRef,
560
+ CodexCommand: CodexExecutable.displayCommand ?? CodexExecutable.command,
561
+ totals: {
470
562
  total: allResults.length,
471
- passed,
563
+ passed: passed.length,
564
+ skipped: skipped.length,
472
565
  failed: failed.length,
473
566
  },
474
567
  results: allResults,
475
568
  };
476
569
  await mkdir(dirname(reportJsonPath), { recursive: true });
477
- await writeFile(reportJsonPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
570
+ await writeFile(
571
+ reportJsonPath,
572
+ `${JSON.stringify(report, null, 2)}\n`,
573
+ "utf8",
574
+ );
478
575
  console.log(`Report written: ${reportJsonPath}`);
479
576
  }
480
577
 
@@ -485,6 +582,10 @@ async function main() {
485
582
  console.log(`- ${result.scenario}: ${result.model}${variantLabel}`);
486
583
  }
487
584
  process.exitCode = 1;
585
+ } else if (smoke && passed.length === 0) {
586
+ console.log(
587
+ "\nSmoke matrix was inconclusive: all cases were skipped for this current runtime/account capability set.",
588
+ );
488
589
  }
489
590
  }
490
591
 
@@ -500,5 +601,3 @@ if (isDirectRun) {
500
601
  process.exit(1);
501
602
  });
502
603
  }
503
-
504
-
@@ -1,7 +1,7 @@
1
- #!/bin/bash
2
-
3
- set -euo pipefail
4
-
5
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
- node "${SCRIPT_DIR}/test-model-matrix.js" --smoke "$@"
7
-
1
+ #!/bin/bash
2
+
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
+ node "${SCRIPT_DIR}/test-model-matrix.js" --smoke "$@"
7
+
@@ -1,2 +1,2 @@
1
- export type PluginInput = any;
1
+ export type PluginInput = any;
2
2
  export type Plugin = any;
@@ -1,42 +1,42 @@
1
- export interface ToolContext {
2
- [key: string]: any;
3
- directory: string;
4
- worktree: string;
5
- ask: (request: any) => Promise<any> | any;
6
- }
7
-
8
- export interface ToolDefinition<TArgs = any, TResult = any> {
9
- description?: string;
10
- args?: Record<string, any>;
11
- parameters?: unknown;
12
- execute: (args: TArgs, context: ToolContext) => Promise<TResult> | TResult;
13
- [key: string]: any;
14
- }
15
-
16
- export interface SchemaNode {
17
- optional: () => SchemaNode;
18
- describe: (_text: string) => SchemaNode;
19
- min: (_value: number) => SchemaNode;
20
- max: (_value: number) => SchemaNode;
21
- default: (_value: unknown) => SchemaNode;
22
- int: () => SchemaNode;
23
- array: (_node?: unknown) => SchemaNode;
24
- [key: string]: any;
25
- }
26
-
27
- export interface ToolFactory {
28
- <TArgs = any, TResult = any>(definition: ToolDefinition<TArgs, TResult>): ToolDefinition<TArgs, TResult>;
29
- schema: {
30
- string: () => SchemaNode;
31
- number: () => SchemaNode;
32
- boolean: () => SchemaNode;
33
- object: (shape: Record<string, unknown>) => SchemaNode;
34
- enum: (values: readonly unknown[]) => SchemaNode;
35
- literal: (value: unknown) => SchemaNode;
36
- array: (node: unknown) => SchemaNode;
37
- any: () => SchemaNode;
38
- unknown: () => SchemaNode;
39
- };
40
- }
41
-
1
+ export interface ToolContext {
2
+ [key: string]: any;
3
+ directory: string;
4
+ worktree: string;
5
+ ask: (request: any) => Promise<any> | any;
6
+ }
7
+
8
+ export interface ToolDefinition<TArgs = any, TResult = any> {
9
+ description?: string;
10
+ args?: Record<string, any>;
11
+ parameters?: unknown;
12
+ execute: (args: TArgs, context: ToolContext) => Promise<TResult> | TResult;
13
+ [key: string]: any;
14
+ }
15
+
16
+ export interface SchemaNode {
17
+ optional: () => SchemaNode;
18
+ describe: (_text: string) => SchemaNode;
19
+ min: (_value: number) => SchemaNode;
20
+ max: (_value: number) => SchemaNode;
21
+ default: (_value: unknown) => SchemaNode;
22
+ int: () => SchemaNode;
23
+ array: (_node?: unknown) => SchemaNode;
24
+ [key: string]: any;
25
+ }
26
+
27
+ export interface ToolFactory {
28
+ <TArgs = any, TResult = any>(definition: ToolDefinition<TArgs, TResult>): ToolDefinition<TArgs, TResult>;
29
+ schema: {
30
+ string: () => SchemaNode;
31
+ number: () => SchemaNode;
32
+ boolean: () => SchemaNode;
33
+ object: (shape: Record<string, unknown>) => SchemaNode;
34
+ enum: (values: readonly unknown[]) => SchemaNode;
35
+ literal: (value: unknown) => SchemaNode;
36
+ array: (node: unknown) => SchemaNode;
37
+ any: () => SchemaNode;
38
+ unknown: () => SchemaNode;
39
+ };
40
+ }
41
+
42
42
  export declare const tool: ToolFactory;