codex-multi-auth 0.1.4 → 0.1.5

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.
@@ -1,54 +1,54 @@
1
- export function percentile(values, p) {
2
- if (!Array.isArray(values) || values.length === 0) {
3
- return null;
4
- }
5
- const sorted = [...values].sort((a, b) => a - b);
6
- if (sorted.length === 1) {
7
- return sorted[0];
8
- }
9
- const index = (sorted.length - 1) * p;
10
- const low = Math.floor(index);
11
- const high = Math.ceil(index);
12
- if (low === high) {
13
- return sorted[low];
14
- }
15
- const frac = index - low;
16
- return sorted[low] + (sorted[high] - sorted[low]) * frac;
17
- }
18
-
19
- export function stats(values) {
20
- const nums = values.filter((value) => typeof value === "number" && Number.isFinite(value));
21
- if (nums.length === 0) {
22
- return null;
23
- }
24
- const sum = nums.reduce((acc, value) => acc + value, 0);
25
- return {
26
- n: nums.length,
27
- min: Math.min(...nums),
28
- p50: percentile(nums, 0.5),
29
- p95: percentile(nums, 0.95),
30
- max: Math.max(...nums),
31
- mean: sum / nums.length,
32
- };
33
- }
34
-
35
- export function safePercent(numerator, denominator) {
36
- if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) {
37
- return null;
38
- }
39
- return (numerator / denominator) * 100;
40
- }
41
-
42
- export function round1(value) {
43
- if (typeof value !== "number" || !Number.isFinite(value)) {
44
- return null;
45
- }
46
- return Math.round(value * 10) / 10;
47
- }
48
-
49
- export function pctDelta(current, baseline) {
50
- if (!Number.isFinite(current) || !Number.isFinite(baseline) || baseline === 0) {
51
- return null;
52
- }
53
- return ((current - baseline) / baseline) * 100;
54
- }
1
+ export function percentile(values, p) {
2
+ if (!Array.isArray(values) || values.length === 0) {
3
+ return null;
4
+ }
5
+ const sorted = [...values].sort((a, b) => a - b);
6
+ if (sorted.length === 1) {
7
+ return sorted[0];
8
+ }
9
+ const index = (sorted.length - 1) * p;
10
+ const low = Math.floor(index);
11
+ const high = Math.ceil(index);
12
+ if (low === high) {
13
+ return sorted[low];
14
+ }
15
+ const frac = index - low;
16
+ return sorted[low] + (sorted[high] - sorted[low]) * frac;
17
+ }
18
+
19
+ export function stats(values) {
20
+ const nums = values.filter((value) => typeof value === "number" && Number.isFinite(value));
21
+ if (nums.length === 0) {
22
+ return null;
23
+ }
24
+ const sum = nums.reduce((acc, value) => acc + value, 0);
25
+ return {
26
+ n: nums.length,
27
+ min: Math.min(...nums),
28
+ p50: percentile(nums, 0.5),
29
+ p95: percentile(nums, 0.95),
30
+ max: Math.max(...nums),
31
+ mean: sum / nums.length,
32
+ };
33
+ }
34
+
35
+ export function safePercent(numerator, denominator) {
36
+ if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) {
37
+ return null;
38
+ }
39
+ return (numerator / denominator) * 100;
40
+ }
41
+
42
+ export function round1(value) {
43
+ if (typeof value !== "number" || !Number.isFinite(value)) {
44
+ return null;
45
+ }
46
+ return Math.round(value * 10) / 10;
47
+ }
48
+
49
+ export function pctDelta(current, baseline) {
50
+ if (!Number.isFinite(current) || !Number.isFinite(baseline) || baseline === 0) {
51
+ return null;
52
+ }
53
+ return ((current - baseline) / baseline) * 100;
54
+ }
@@ -1,151 +1,151 @@
1
- export const BENCHMARK_FIXTURE = {
2
- relativePath: "src/TodoApp.tsx",
3
- sourcePath: "bench/format-benchmark/fixtures/TodoApp.tsx",
4
- };
5
-
6
- function hasAll(content, snippets) {
7
- return snippets.every((snippet) => content.includes(snippet));
8
- }
9
-
10
- function lacksAll(content, snippets) {
11
- return snippets.every((snippet) => !content.includes(snippet));
12
- }
13
-
14
- function regex(content, pattern) {
15
- return pattern.test(content);
16
- }
17
-
18
- export const TASKS = [
19
- {
20
- id: "T01",
21
- name: "Rename heading text",
22
- difficulty: "trivial",
23
- timeoutMs: 120000,
24
- prompt: "Change the heading text from \"My Todos\" to \"Task Board\". Only make this text change.",
25
- validate: (content) => hasAll(content, ["Task Board"]) && lacksAll(content, [">My Todos<"]),
26
- },
27
- {
28
- id: "T02",
29
- name: "Rename input placeholder",
30
- difficulty: "trivial",
31
- timeoutMs: 120000,
32
- prompt: "Change the input placeholder from \"Add a todo...\" to \"What needs to be done?\" and make no other changes.",
33
- validate: (content) => hasAll(content, ["What needs to be done?"]) && lacksAll(content, ["Add a todo..."]),
34
- },
35
- {
36
- id: "T03",
37
- name: "Add clearCompleted action",
38
- difficulty: "easy",
39
- timeoutMs: 180000,
40
- prompt: "Add a clearCompleted function that removes completed todos using filter, and add a \"Clear Completed\" button after the closing </ul> that calls it.",
41
- validate: (content) => hasAll(content, ["clearCompleted", "Clear Completed", "filter"]) && regex(content, /clearCompleted\s*=|function\s+clearCompleted/),
42
- },
43
- {
44
- id: "T04",
45
- name: "Add footer count display",
46
- difficulty: "easy",
47
- timeoutMs: 180000,
48
- prompt: "Add a paragraph right after the closing </ul> that displays the remaining todo count using the text \"items left\".",
49
- validate: (content) => hasAll(content, ["items left"]) && regex(content, /<p[^>]*>.*items left/i),
50
- },
51
- {
52
- id: "T05",
53
- name: "Trim input before add",
54
- difficulty: "easy",
55
- timeoutMs: 180000,
56
- prompt: "Update addTodo to trim the input before checking emptiness and before creating the new todo item. Keep behavior otherwise the same.",
57
- validate: (content) => hasAll(content, [".trim()"]),
58
- },
59
- {
60
- id: "T06",
61
- name: "Duplicate guard in addTodo",
62
- difficulty: "medium",
63
- timeoutMs: 180000,
64
- prompt: "Add a duplicate guard in addTodo so case-insensitive duplicate todo text is not added. Use toLowerCase and a todos.some check.",
65
- validate: (content) => hasAll(content, ["toLowerCase()", ".some("]) && regex(content, /duplicate|already exists|some\(/i),
66
- },
67
- {
68
- id: "T07",
69
- name: "Add max todo limit",
70
- difficulty: "medium",
71
- timeoutMs: 180000,
72
- prompt: "Add a MAX_TODOS constant with value 100 and prevent adding a todo when todos.length is already at the limit.",
73
- validate: (content) => hasAll(content, ["MAX_TODOS", "100"]) && regex(content, /todos\.length\s*>?=\s*MAX_TODOS/),
74
- },
75
- {
76
- id: "T08",
77
- name: "Aria label for checkbox",
78
- difficulty: "easy",
79
- timeoutMs: 180000,
80
- prompt: "Add an aria-label to the checkbox input that includes the todo text and starts with \"Toggle todo\".",
81
- validate: (content) => hasAll(content, ["aria-label", "Toggle todo"]),
82
- },
83
- {
84
- id: "T09",
85
- name: "Aria label for delete button",
86
- difficulty: "easy",
87
- timeoutMs: 180000,
88
- prompt: "Add an aria-label to the Delete button that includes the todo text and starts with \"Delete todo\".",
89
- validate: (content) => hasAll(content, ["aria-label", "Delete todo"]),
90
- },
91
- {
92
- id: "T10",
93
- name: "Rename interface TodoItem",
94
- difficulty: "medium",
95
- timeoutMs: 240000,
96
- prompt: "Rename the TodoItem interface to TodoRecord and update all references in the file accordingly without changing behavior.",
97
- validate: (content) => hasAll(content, ["interface TodoRecord"]) && lacksAll(content, ["interface TodoItem {"]),
98
- },
99
- {
100
- id: "T11",
101
- name: "Extract TodoListItem component",
102
- difficulty: "hard",
103
- timeoutMs: 300000,
104
- prompt: "Extract the list item rendering into a new component named TodoListItem in the same file and use <TodoListItem> inside the todos.map call. Pass todo, onToggle, and onDelete props.",
105
- validate: (content) => regex(content, /function\s+TodoListItem|const\s+TodoListItem\s*=/) && hasAll(content, ["<TodoListItem", "onToggle", "onDelete"]),
106
- },
107
- {
108
- id: "T12",
109
- name: "Add empty state conditional",
110
- difficulty: "hard",
111
- timeoutMs: 300000,
112
- prompt: "Render an empty state paragraph with className \"empty-state\" and text \"No todos yet\" when todos.length is 0, otherwise render the existing <ul> list.",
113
- validate: (content) => hasAll(content, ["empty-state", "No todos yet"]) && regex(content, /todos\.length/),
114
- },
115
- {
116
- id: "T13",
117
- name: "Disable clear completed when none",
118
- difficulty: "medium",
119
- timeoutMs: 240000,
120
- prompt: "If you add a Clear Completed button, make it disabled when there are no completed todos. If the button does not exist yet, add it and wire the disabled state.",
121
- validate: (content) => hasAll(content, ["Clear Completed", "disabled"]) && regex(content, /some\(|filter\(/),
122
- },
123
- {
124
- id: "T14",
125
- name: "Memoize remaining count",
126
- difficulty: "medium",
127
- timeoutMs: 240000,
128
- prompt: "Refactor remainingCount to use React useMemo. Update imports if needed and keep the rendered output unchanged.",
129
- validate: (content) => hasAll(content, ["useMemo", "remainingCount"]) && regex(content, /useMemo\(/),
130
- },
131
- {
132
- id: "T15",
133
- name: "Sort completed last in render",
134
- difficulty: "hard",
135
- timeoutMs: 300000,
136
- prompt: "Before rendering the list, sort todos so incomplete items appear before completed items while preserving the rest of the UI. Do not mutate state directly.",
137
- validate: (content) => regex(content, /\.slice\(\)\.sort\(|const\s+sortedTodos/) && regex(content, /completed/),
138
- },
139
- {
140
- id: "T16",
141
- name: "Add footer summary stats",
142
- difficulty: "medium",
143
- timeoutMs: 240000,
144
- prompt: "Add a footer element after the list that shows total todos and completed todos using labels \"Total:\" and \"Completed:\".",
145
- validate: (content) => hasAll(content, ["<footer", "Total:", "Completed:"]),
146
- },
147
- ];
148
-
149
- export function getTaskMap() {
150
- return new Map(TASKS.map((task) => [task.id, task]));
151
- }
1
+ export const BENCHMARK_FIXTURE = {
2
+ relativePath: "src/TodoApp.tsx",
3
+ sourcePath: "bench/format-benchmark/fixtures/TodoApp.tsx",
4
+ };
5
+
6
+ function hasAll(content, snippets) {
7
+ return snippets.every((snippet) => content.includes(snippet));
8
+ }
9
+
10
+ function lacksAll(content, snippets) {
11
+ return snippets.every((snippet) => !content.includes(snippet));
12
+ }
13
+
14
+ function regex(content, pattern) {
15
+ return pattern.test(content);
16
+ }
17
+
18
+ export const TASKS = [
19
+ {
20
+ id: "T01",
21
+ name: "Rename heading text",
22
+ difficulty: "trivial",
23
+ timeoutMs: 120000,
24
+ prompt: "Change the heading text from \"My Todos\" to \"Task Board\". Only make this text change.",
25
+ validate: (content) => hasAll(content, ["Task Board"]) && lacksAll(content, [">My Todos<"]),
26
+ },
27
+ {
28
+ id: "T02",
29
+ name: "Rename input placeholder",
30
+ difficulty: "trivial",
31
+ timeoutMs: 120000,
32
+ prompt: "Change the input placeholder from \"Add a todo...\" to \"What needs to be done?\" and make no other changes.",
33
+ validate: (content) => hasAll(content, ["What needs to be done?"]) && lacksAll(content, ["Add a todo..."]),
34
+ },
35
+ {
36
+ id: "T03",
37
+ name: "Add clearCompleted action",
38
+ difficulty: "easy",
39
+ timeoutMs: 180000,
40
+ prompt: "Add a clearCompleted function that removes completed todos using filter, and add a \"Clear Completed\" button after the closing </ul> that calls it.",
41
+ validate: (content) => hasAll(content, ["clearCompleted", "Clear Completed", "filter"]) && regex(content, /clearCompleted\s*=|function\s+clearCompleted/),
42
+ },
43
+ {
44
+ id: "T04",
45
+ name: "Add footer count display",
46
+ difficulty: "easy",
47
+ timeoutMs: 180000,
48
+ prompt: "Add a paragraph right after the closing </ul> that displays the remaining todo count using the text \"items left\".",
49
+ validate: (content) => hasAll(content, ["items left"]) && regex(content, /<p[^>]*>.*items left/i),
50
+ },
51
+ {
52
+ id: "T05",
53
+ name: "Trim input before add",
54
+ difficulty: "easy",
55
+ timeoutMs: 180000,
56
+ prompt: "Update addTodo to trim the input before checking emptiness and before creating the new todo item. Keep behavior otherwise the same.",
57
+ validate: (content) => hasAll(content, [".trim()"]),
58
+ },
59
+ {
60
+ id: "T06",
61
+ name: "Duplicate guard in addTodo",
62
+ difficulty: "medium",
63
+ timeoutMs: 180000,
64
+ prompt: "Add a duplicate guard in addTodo so case-insensitive duplicate todo text is not added. Use toLowerCase and a todos.some check.",
65
+ validate: (content) => hasAll(content, ["toLowerCase()", ".some("]) && regex(content, /duplicate|already exists|some\(/i),
66
+ },
67
+ {
68
+ id: "T07",
69
+ name: "Add max todo limit",
70
+ difficulty: "medium",
71
+ timeoutMs: 180000,
72
+ prompt: "Add a MAX_TODOS constant with value 100 and prevent adding a todo when todos.length is already at the limit.",
73
+ validate: (content) => hasAll(content, ["MAX_TODOS", "100"]) && regex(content, /todos\.length\s*>?=\s*MAX_TODOS/),
74
+ },
75
+ {
76
+ id: "T08",
77
+ name: "Aria label for checkbox",
78
+ difficulty: "easy",
79
+ timeoutMs: 180000,
80
+ prompt: "Add an aria-label to the checkbox input that includes the todo text and starts with \"Toggle todo\".",
81
+ validate: (content) => hasAll(content, ["aria-label", "Toggle todo"]),
82
+ },
83
+ {
84
+ id: "T09",
85
+ name: "Aria label for delete button",
86
+ difficulty: "easy",
87
+ timeoutMs: 180000,
88
+ prompt: "Add an aria-label to the Delete button that includes the todo text and starts with \"Delete todo\".",
89
+ validate: (content) => hasAll(content, ["aria-label", "Delete todo"]),
90
+ },
91
+ {
92
+ id: "T10",
93
+ name: "Rename interface TodoItem",
94
+ difficulty: "medium",
95
+ timeoutMs: 240000,
96
+ prompt: "Rename the TodoItem interface to TodoRecord and update all references in the file accordingly without changing behavior.",
97
+ validate: (content) => hasAll(content, ["interface TodoRecord"]) && lacksAll(content, ["interface TodoItem {"]),
98
+ },
99
+ {
100
+ id: "T11",
101
+ name: "Extract TodoListItem component",
102
+ difficulty: "hard",
103
+ timeoutMs: 300000,
104
+ prompt: "Extract the list item rendering into a new component named TodoListItem in the same file and use <TodoListItem> inside the todos.map call. Pass todo, onToggle, and onDelete props.",
105
+ validate: (content) => regex(content, /function\s+TodoListItem|const\s+TodoListItem\s*=/) && hasAll(content, ["<TodoListItem", "onToggle", "onDelete"]),
106
+ },
107
+ {
108
+ id: "T12",
109
+ name: "Add empty state conditional",
110
+ difficulty: "hard",
111
+ timeoutMs: 300000,
112
+ prompt: "Render an empty state paragraph with className \"empty-state\" and text \"No todos yet\" when todos.length is 0, otherwise render the existing <ul> list.",
113
+ validate: (content) => hasAll(content, ["empty-state", "No todos yet"]) && regex(content, /todos\.length/),
114
+ },
115
+ {
116
+ id: "T13",
117
+ name: "Disable clear completed when none",
118
+ difficulty: "medium",
119
+ timeoutMs: 240000,
120
+ prompt: "If you add a Clear Completed button, make it disabled when there are no completed todos. If the button does not exist yet, add it and wire the disabled state.",
121
+ validate: (content) => hasAll(content, ["Clear Completed", "disabled"]) && regex(content, /some\(|filter\(/),
122
+ },
123
+ {
124
+ id: "T14",
125
+ name: "Memoize remaining count",
126
+ difficulty: "medium",
127
+ timeoutMs: 240000,
128
+ prompt: "Refactor remainingCount to use React useMemo. Update imports if needed and keep the rendered output unchanged.",
129
+ validate: (content) => hasAll(content, ["useMemo", "remainingCount"]) && regex(content, /useMemo\(/),
130
+ },
131
+ {
132
+ id: "T15",
133
+ name: "Sort completed last in render",
134
+ difficulty: "hard",
135
+ timeoutMs: 300000,
136
+ prompt: "Before rendering the list, sort todos so incomplete items appear before completed items while preserving the rest of the UI. Do not mutate state directly.",
137
+ validate: (content) => regex(content, /\.slice\(\)\.sort\(|const\s+sortedTodos/) && regex(content, /completed/),
138
+ },
139
+ {
140
+ id: "T16",
141
+ name: "Add footer summary stats",
142
+ difficulty: "medium",
143
+ timeoutMs: 240000,
144
+ prompt: "Add a footer element after the list that shows total todos and completed todos using labels \"Total:\" and \"Completed:\".",
145
+ validate: (content) => hasAll(content, ["<footer", "Total:", "Completed:"]),
146
+ },
147
+ ];
148
+
149
+ export function getTaskMap() {
150
+ return new Map(TASKS.map((task) => [task.id, task]));
151
+ }
@@ -1,49 +1,49 @@
1
- #!/usr/bin/env node
2
-
3
- import { readFile, writeFile } from "node:fs/promises";
4
- import { resolve } from "node:path";
5
- import process from "node:process";
6
- import { renderDashboardHtml } from "./bench-format/render.mjs";
7
-
8
- function usage() {
9
- console.log([
10
- "Usage: node scripts/benchmark-render-dashboard.mjs --input=PATH [--output=PATH]",
11
- "",
12
- "Options:",
13
- " --input=PATH Path to benchmark summary.json",
14
- " --output=PATH Output HTML path (default: alongside input as dashboard.html)",
15
- ].join("\n"));
16
- }
17
-
18
- function argValue(args, name) {
19
- const prefix = `${name}=`;
20
- const match = args.find((arg) => arg.startsWith(prefix));
21
- return match ? match.slice(prefix.length) : undefined;
22
- }
23
-
24
- async function main() {
25
- const args = process.argv.slice(2);
26
- if (args.includes("--help") || args.includes("-h")) {
27
- usage();
28
- return;
29
- }
30
-
31
- const inputRaw = argValue(args, "--input");
32
- if (!inputRaw) {
33
- usage();
34
- process.exitCode = 1;
35
- return;
36
- }
37
- const inputPath = resolve(inputRaw);
38
- const outputPath = resolve(argValue(args, "--output") ?? inputPath.replace(/summary\.json$/i, "dashboard.html"));
39
-
40
- const summary = JSON.parse(await readFile(inputPath, "utf8"));
41
- const html = renderDashboardHtml(summary);
42
- await writeFile(outputPath, html, "utf8");
43
- console.log(`Dashboard written: ${outputPath}`);
44
- }
45
-
46
- main().catch((error) => {
47
- console.error(`Render failed: ${error instanceof Error ? error.message : String(error)}`);
48
- process.exit(1);
49
- });
1
+ #!/usr/bin/env node
2
+
3
+ import { readFile, writeFile } from "node:fs/promises";
4
+ import { resolve } from "node:path";
5
+ import process from "node:process";
6
+ import { renderDashboardHtml } from "./bench-format/render.mjs";
7
+
8
+ function usage() {
9
+ console.log([
10
+ "Usage: node scripts/benchmark-render-dashboard.mjs --input=PATH [--output=PATH]",
11
+ "",
12
+ "Options:",
13
+ " --input=PATH Path to benchmark summary.json",
14
+ " --output=PATH Output HTML path (default: alongside input as dashboard.html)",
15
+ ].join("\n"));
16
+ }
17
+
18
+ function argValue(args, name) {
19
+ const prefix = `${name}=`;
20
+ const match = args.find((arg) => arg.startsWith(prefix));
21
+ return match ? match.slice(prefix.length) : undefined;
22
+ }
23
+
24
+ async function main() {
25
+ const args = process.argv.slice(2);
26
+ if (args.includes("--help") || args.includes("-h")) {
27
+ usage();
28
+ return;
29
+ }
30
+
31
+ const inputRaw = argValue(args, "--input");
32
+ if (!inputRaw) {
33
+ usage();
34
+ process.exitCode = 1;
35
+ return;
36
+ }
37
+ const inputPath = resolve(inputRaw);
38
+ const outputPath = resolve(argValue(args, "--output") ?? inputPath.replace(/summary\.json$/i, "dashboard.html"));
39
+
40
+ const summary = JSON.parse(await readFile(inputPath, "utf8"));
41
+ const html = renderDashboardHtml(summary);
42
+ await writeFile(outputPath, html, "utf8");
43
+ console.log(`Dashboard written: ${outputPath}`);
44
+ }
45
+
46
+ main().catch((error) => {
47
+ console.error(`Render failed: ${error instanceof Error ? error.message : String(error)}`);
48
+ process.exit(1);
49
+ });
@@ -3,4 +3,4 @@
3
3
  import { runCodexMultiAuthCli } from "../dist/lib/codex-manager.js";
4
4
 
5
5
  const exitCode = await runCodexMultiAuthCli(process.argv.slice(2));
6
- process.exit(exitCode);
6
+ process.exitCode = Number.isInteger(exitCode) ? exitCode : 1;
package/scripts/codex.js CHANGED
@@ -178,39 +178,43 @@ function normalizeExitCode(value) {
178
178
  return 1;
179
179
  }
180
180
 
181
- const rawArgs = process.argv.slice(2);
182
- const normalizedArgs = normalizeAuthAlias(rawArgs);
183
- const bypass = (process.env.CODEX_MULTI_AUTH_BYPASS ?? "").trim() === "1";
184
-
185
- if (!bypass && shouldHandleMultiAuthAuth(normalizedArgs)) {
186
- try {
187
- const runCodexMultiAuthCli = await loadRunCodexMultiAuthCli();
188
- if (!runCodexMultiAuthCli) {
189
- process.exit(1);
181
+ async function main() {
182
+ const rawArgs = process.argv.slice(2);
183
+ const normalizedArgs = normalizeAuthAlias(rawArgs);
184
+ const bypass = (process.env.CODEX_MULTI_AUTH_BYPASS ?? "").trim() === "1";
185
+
186
+ if (!bypass && shouldHandleMultiAuthAuth(normalizedArgs)) {
187
+ try {
188
+ const runCodexMultiAuthCli = await loadRunCodexMultiAuthCli();
189
+ if (!runCodexMultiAuthCli) {
190
+ return 1;
191
+ }
192
+ const exitCode = await runCodexMultiAuthCli(normalizedArgs);
193
+ return normalizeExitCode(exitCode);
194
+ } catch (error) {
195
+ console.error(
196
+ `codex-multi-auth runner failed: ${error instanceof Error ? error.message : String(error)}`,
197
+ );
198
+ return 1;
190
199
  }
191
- const exitCode = await runCodexMultiAuthCli(normalizedArgs);
192
- process.exit(normalizeExitCode(exitCode));
193
- } catch (error) {
200
+ }
201
+
202
+ const realCodexBin = resolveRealCodexBin();
203
+ if (!realCodexBin) {
194
204
  console.error(
195
- `codex-multi-auth runner failed: ${error instanceof Error ? error.message : String(error)}`,
205
+ [
206
+ "Could not locate the official Codex CLI binary (@openai/codex).",
207
+ "Install it globally: npm install -g @openai/codex",
208
+ "Or set CODEX_MULTI_AUTH_REAL_CODEX_BIN to a full bin/codex.js path.",
209
+ ].join("\n"),
196
210
  );
197
- process.exit(1);
211
+ return 1;
198
212
  }
199
- }
200
213
 
201
- const realCodexBin = resolveRealCodexBin();
202
- if (!realCodexBin) {
203
- console.error(
204
- [
205
- "Could not locate the official Codex CLI binary (@openai/codex).",
206
- "Install it globally: npm install -g @openai/codex",
207
- "Or set CODEX_MULTI_AUTH_REAL_CODEX_BIN to a full bin/codex.js path.",
208
- ].join("\n"),
209
- );
210
- process.exit(1);
214
+ await autoSyncManagerActiveSelectionIfEnabled();
215
+ const forwardArgs = buildForwardArgs(rawArgs);
216
+ return forwardToRealCodex(realCodexBin, forwardArgs);
211
217
  }
212
218
 
213
- await autoSyncManagerActiveSelectionIfEnabled();
214
- const forwardArgs = buildForwardArgs(rawArgs);
215
- const forwardExitCode = await forwardToRealCodex(realCodexBin, forwardArgs);
216
- process.exit(forwardExitCode);
219
+ const exitCode = await main();
220
+ process.exitCode = normalizeExitCode(exitCode);
@@ -143,15 +143,15 @@ async function clearCache() {
143
143
  if (dryRun) {
144
144
  log(`[dry-run] Would remove ${cacheNodeModules}`);
145
145
  log(`[dry-run] Would remove ${cacheBunLock}`);
146
- } else {
147
- try {
148
- await withFileOperationRetry(() => rm(cacheNodeModules, { recursive: true, force: true }));
149
- await withFileOperationRetry(() => rm(cacheBunLock, { force: true }));
150
- } catch (error) {
151
- log(
152
- `Warning: Could not fully clear cache (${error instanceof Error ? error.message : String(error)}). You may need to restart Codex.`,
153
- );
154
- }
146
+ } else {
147
+ try {
148
+ await withFileOperationRetry(() => rm(cacheNodeModules, { recursive: true, force: true }));
149
+ await withFileOperationRetry(() => rm(cacheBunLock, { force: true }));
150
+ } catch (error) {
151
+ log(
152
+ `Warning: Could not fully clear cache (${error instanceof Error ? error.message : String(error)}). You may need to restart Codex.`,
153
+ );
154
+ }
155
155
  }
156
156
 
157
157
  await removePluginFromCachePackage();
@@ -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" "$@"
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" "$@"
7
+