onadit 0.1.0-beta.45 → 1.0.0

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 (38) hide show
  1. package/README.md +1 -1
  2. package/dist/src/cli/commands/onboard.js +2 -2
  3. package/dist/src/cli/commands/onboard.js.map +1 -1
  4. package/dist/src/cli/commands/status.js +1 -1
  5. package/dist/src/cli/commands/status.js.map +1 -1
  6. package/dist/src/cli/commands/update.d.ts +1 -1
  7. package/dist/src/cli/commands/update.d.ts.map +1 -1
  8. package/dist/src/cli/commands/update.js +23 -20
  9. package/dist/src/cli/commands/update.js.map +1 -1
  10. package/dist/src/cli/status/friend-header.d.ts.map +1 -1
  11. package/dist/src/cli/status/friend-header.js +20 -1
  12. package/dist/src/cli/status/friend-header.js.map +1 -1
  13. package/dist/src/diagnostics/codex-preflight.d.ts +10 -0
  14. package/dist/src/diagnostics/codex-preflight.d.ts.map +1 -1
  15. package/dist/src/diagnostics/codex-preflight.js +30 -1
  16. package/dist/src/diagnostics/codex-preflight.js.map +1 -1
  17. package/dist/src/diagnostics/doctor.js +1 -1
  18. package/dist/src/diagnostics/doctor.js.map +1 -1
  19. package/dist/src/observability/version-check.d.ts +7 -3
  20. package/dist/src/observability/version-check.d.ts.map +1 -1
  21. package/dist/src/observability/version-check.js +5 -5
  22. package/dist/src/observability/version-check.js.map +1 -1
  23. package/dist/src/providers/codex-cli-model.d.ts +65 -16
  24. package/dist/src/providers/codex-cli-model.d.ts.map +1 -1
  25. package/dist/src/providers/codex-cli-model.js +187 -43
  26. package/dist/src/providers/codex-cli-model.js.map +1 -1
  27. package/dist/src/providers/codex-cli-runner.d.ts +11 -1
  28. package/dist/src/providers/codex-cli-runner.d.ts.map +1 -1
  29. package/dist/src/providers/codex-cli-runner.js +183 -22
  30. package/dist/src/providers/codex-cli-runner.js.map +1 -1
  31. package/dist/src/retrieval/context-pack.d.ts.map +1 -1
  32. package/dist/src/retrieval/context-pack.js +16 -6
  33. package/dist/src/retrieval/context-pack.js.map +1 -1
  34. package/dist/src/server/routes/friend-status.d.ts +7 -0
  35. package/dist/src/server/routes/friend-status.d.ts.map +1 -1
  36. package/dist/src/server/routes/friend-status.js +7 -3
  37. package/dist/src/server/routes/friend-status.js.map +1 -1
  38. package/package.json +1 -1
@@ -2,35 +2,18 @@ import fs from "node:fs";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  /**
5
- * Codex model resolution for the isolated-CODEX_HOME preflight/exec path.
6
- *
7
- * Onadit launches `codex exec` with an isolated CODEX_HOME that copies only
8
- * `auth.json` (never the user's `config.toml`), so it does NOT inherit the
9
- * user's `model = "..."`. Codex then falls back to its own built-in default,
10
- * which changes between releases — 0.125.0 moved it to `gpt-5.3-codex`, a
11
- * model ChatGPT-auth plans reject, silently breaking every preflight. The
12
- * fix: Onadit pins an explicit `--model` on every run and NEVER inherits codex's
13
- * implicit default. Resolution order:
14
- * 1. Onadit config (`codex_cli.model`) — operator override, authoritative.
15
- * 2. Top-level `model` in the source `~/.codex/config.toml` — the user's
16
- * own proven choice, which the isolated home would otherwise drop.
17
- * 3. A previously probe-verified model persisted under the data dir.
18
- * 4. A live probe across known-good candidates; the first that actually
19
- * runs is persisted (verified, not guessed). If none work, we throw a
20
- * clear, actionable error instead of looping on codex's bad default.
5
+ * How long a refused model stays skipped. A refusal is usually permanent (a
6
+ * retired model), but a plan change can bring a model back, so it is retried
7
+ * after a week rather than banned forever.
21
8
  */
22
- /**
23
- * Evidence-based known-good fallbacks. Codex 0.125.0's implicit default
24
- * (`gpt-5.3-codex`) is rejected by ChatGPT-auth plans; `gpt-5.5` is verified
25
- * working. This list is a last-resort safety net only — operators on a plan
26
- * where these are unavailable should set `codex_cli.model` rather than extend
27
- * it, which is exactly what the thrown error tells them to do.
28
- */
29
- export const CODEX_MODEL_FALLBACK_CANDIDATES = ["gpt-5.5"];
9
+ export const REFUSAL_TTL_MS = 7 * 24 * 60 * 60 * 1000;
10
+ /** Probe at most this many catalog models per resolution — each is a real call. */
11
+ const MAX_CATALOG_PROBES = 4;
30
12
  const PERSISTED_MODEL_FILE = path.join(".internal", "codex-model");
13
+ const MODEL_HISTORY_FILE = path.join(".internal", "codex-model-history.json");
31
14
  /**
32
15
  * Thrown when no model could be resolved from config/source/persisted state
33
- * and every fallback candidate failed to run. Carries the tried candidates so
16
+ * and every catalog candidate was refused. Carries the tried candidates so
34
17
  * the preflight classifier can render an honest, actionable message.
35
18
  */
36
19
  export class CodexModelUnavailableError extends Error {
@@ -45,10 +28,16 @@ export class CodexModelUnavailableError extends Error {
45
28
  let configuredModel;
46
29
  let configuredDataDir;
47
30
  let resolvedModelPromise = null;
31
+ let resolvedModel = null;
32
+ // Set when a refusal invalidates the memoized model; written as the switch
33
+ // record once the next resolution lands on a different model.
34
+ let pendingSwitch = null;
35
+ // Refusals seen by this process — the source of truth when no data dir is set.
36
+ const memoryRefusals = new Map();
48
37
  /**
49
38
  * Wire the Onadit config's model override + data dir into the resolver. Called
50
39
  * once at daemon/CLI bootstrap. Safe to omit: without it, resolution still
51
- * works via the source `config.toml` → persisted → probe chain.
40
+ * works via the source `config.toml` → persisted → catalog chain.
52
41
  */
53
42
  export function configureCodexModel(opts) {
54
43
  if (typeof opts.model === "string" && opts.model.trim().length > 0) {
@@ -59,55 +48,148 @@ export function configureCodexModel(opts) {
59
48
  }
60
49
  // Re-resolve after (re)configuration so a newly-supplied override wins.
61
50
  resolvedModelPromise = null;
51
+ resolvedModel = null;
62
52
  }
63
53
  export function resetCodexModelCacheForTests() {
64
54
  configuredModel = undefined;
65
55
  configuredDataDir = undefined;
66
56
  resolvedModelPromise = null;
57
+ resolvedModel = null;
58
+ pendingSwitch = null;
59
+ memoryRefusals.clear();
67
60
  }
68
61
  /**
69
62
  * Resolve the model to pin on `codex exec`. Memoized for the process so the
70
- * source-config read / probe happens at most once. `probe` is injected by the
71
- * runner (rather than imported) to avoid a module cycle; it returns true when
72
- * a candidate model actually runs.
63
+ * source-config read / catalog probe happens at most once per model. `probe`
64
+ * and `listModels` are injected by the runner (rather than imported) to avoid
65
+ * a module cycle. `probe` resolves true when the model runs and false when
66
+ * Codex refuses it; any other failure (auth, network) throws and aborts the
67
+ * resolution, so it surfaces as itself instead of "no working model".
73
68
  */
74
- export async function resolveCodexModel(probe) {
69
+ export async function resolveCodexModel(probe, listModels = async () => []) {
75
70
  if (resolvedModelPromise) {
76
71
  return resolvedModelPromise;
77
72
  }
78
73
  const pending = (async () => {
79
- if (configuredModel) {
80
- return configuredModel;
74
+ const now = Date.now();
75
+ const usable = (model) => model !== undefined && !isRefused(model, now) ? model : undefined;
76
+ const direct = usable(configuredModel) ??
77
+ usable(readSourceConfigModel()) ??
78
+ usable(readPersistedModel(configuredDataDir));
79
+ if (direct) {
80
+ return direct;
81
81
  }
82
- const sourceModel = readSourceConfigModel();
83
- if (sourceModel) {
84
- return sourceModel;
82
+ let catalog = [];
83
+ try {
84
+ catalog = await listModels();
85
85
  }
86
- const persisted = readPersistedModel(configuredDataDir);
87
- if (persisted) {
88
- return persisted;
86
+ catch {
87
+ // A Codex without `debug models`, or no network: nothing to pick from.
88
+ // The thrown error below then tells the user to set codex_cli.model.
89
89
  }
90
- // Nothing configured/known — actively verify a candidate before committing.
90
+ const candidates = orderCodexModelCandidates(catalog, (model) => isRefused(model, now)).slice(0, MAX_CATALOG_PROBES);
91
91
  const tried = [];
92
- for (const candidate of CODEX_MODEL_FALLBACK_CANDIDATES) {
92
+ for (const candidate of candidates) {
93
93
  tried.push(candidate);
94
94
  if (await probe(candidate)) {
95
95
  persistModel(configuredDataDir, candidate);
96
96
  return candidate;
97
97
  }
98
+ recordRefusal(candidate, new Date());
98
99
  }
99
100
  throw new CodexModelUnavailableError(tried);
100
101
  })();
101
102
  resolvedModelPromise = pending;
102
- // On failure, clear the cache so a later call (e.g. after the user sets a
103
- // model or auth recovers) can retry instead of returning the stale rejection.
104
- pending.catch(() => {
103
+ pending.then((model) => {
104
+ if (resolvedModelPromise !== pending)
105
+ return;
106
+ resolvedModel = model;
107
+ if (pendingSwitch && pendingSwitch.from !== model) {
108
+ recordSwitch({
109
+ from: pendingSwitch.from,
110
+ to: model,
111
+ at: new Date().toISOString(),
112
+ from_config: configuredModel !== undefined && isRefused(configuredModel, Date.now()),
113
+ });
114
+ }
115
+ pendingSwitch = null;
116
+ }, () => {
117
+ // On failure, clear the cache so a later call (e.g. after the user sets a
118
+ // model or auth recovers) can retry instead of returning the stale rejection.
105
119
  if (resolvedModelPromise === pending) {
106
120
  resolvedModelPromise = null;
107
121
  }
108
122
  });
109
123
  return pending;
110
124
  }
125
+ /**
126
+ * Codex refused `model`. Record it (so every resolution skips it) and, when it
127
+ * is the model this process resolved, drop the memo so the next
128
+ * `resolveCodexModel` picks another one. Concurrent callers refused on the same
129
+ * model share that single re-resolution instead of each starting their own.
130
+ */
131
+ export function markCodexModelRefused(model, now = new Date()) {
132
+ if (!isRefused(model, now.getTime())) {
133
+ recordRefusal(model, now);
134
+ }
135
+ if (resolvedModel === model) {
136
+ pendingSwitch ??= { from: model };
137
+ resolvedModelPromise = null;
138
+ resolvedModel = null;
139
+ }
140
+ }
141
+ /**
142
+ * Rough tier from Codex's own description of a model ("Frontier intelligence
143
+ * for the most demanding work", "Latest workhorse model…", "Fast and
144
+ * affordable model…"). Wording can change; a misread only changes which model
145
+ * gets probed first, never whether capture works.
146
+ */
147
+ export function classifyCodexModelTier(description) {
148
+ const text = (description ?? "").toLowerCase();
149
+ if (/frontier|most demanding|most capable/.test(text))
150
+ return "frontier";
151
+ if (/\bfast\b|affordable|efficient|\bmini\b|lightweight/.test(text))
152
+ return "fast";
153
+ return "balanced";
154
+ }
155
+ // Balanced first (the default level); then fast, which is cheap and finishes
156
+ // well inside the triage timeout; frontier last — slowest, and it uses the most
157
+ // of the user's plan on every hourly run.
158
+ const TIER_RANK = {
159
+ balanced: 0,
160
+ fast: 1,
161
+ frontier: 2,
162
+ };
163
+ /**
164
+ * Catalog models worth probing, best first: models shown in Codex's picker
165
+ * (`visibility: "list"`), minus refused ones, ordered by tier and then by
166
+ * Codex's own priority (lower = more recommended).
167
+ */
168
+ export function orderCodexModelCandidates(catalog, isModelRefused = () => false) {
169
+ return catalog
170
+ .filter((model) => model.visibility === undefined || model.visibility === "list")
171
+ .filter((model) => !isModelRefused(model.slug))
172
+ .map((model, index) => ({
173
+ slug: model.slug,
174
+ tier: TIER_RANK[classifyCodexModelTier(model.description)],
175
+ priority: typeof model.priority === "number" ? model.priority : Number.POSITIVE_INFINITY,
176
+ index,
177
+ }))
178
+ .sort((a, b) => a.tier - b.tier || a.priority - b.priority || a.index - b.index)
179
+ .map((model) => model.slug);
180
+ }
181
+ /**
182
+ * The last automatic switch, if it happened within `maxAgeMs` — for status.
183
+ * Reads the data dir directly so the daemon's status route sees switches made
184
+ * by any process (daemon, `onadit capture`, scripted captures).
185
+ */
186
+ export function readCodexModelSwitch(dataDir, nowMs = Date.now(), maxAgeMs = REFUSAL_TTL_MS) {
187
+ const last = readHistory(dataDir).last_switch;
188
+ if (!last)
189
+ return null;
190
+ const at = Date.parse(last.at);
191
+ return Number.isFinite(at) && nowMs - at < maxAgeMs ? last : null;
192
+ }
111
193
  /** The source CODEX_HOME the user actually authenticated, mirroring the runner. */
112
194
  function resolveSourceCodexHome() {
113
195
  if (typeof process.env["CODEX_HOME"] === "string") {
@@ -191,4 +273,66 @@ function persistModel(dataDir, model) {
191
273
  // probe re-runs next cold start. Never fail a capture over it.
192
274
  }
193
275
  }
276
+ function isRefused(model, nowMs) {
277
+ const at = memoryRefusals.get(model) ?? readHistory(configuredDataDir).refused[model];
278
+ if (!at)
279
+ return false;
280
+ const refusedAt = Date.parse(at);
281
+ return Number.isFinite(refusedAt) && nowMs - refusedAt < REFUSAL_TTL_MS;
282
+ }
283
+ function recordRefusal(model, now) {
284
+ memoryRefusals.set(model, now.toISOString());
285
+ if (!configuredDataDir)
286
+ return;
287
+ const history = readHistory(configuredDataDir);
288
+ history.refused[model] = now.toISOString();
289
+ // Drop refusals past their TTL so the file stays a handful of entries.
290
+ for (const [name, at] of Object.entries(history.refused)) {
291
+ const refusedAt = Date.parse(at);
292
+ if (!Number.isFinite(refusedAt) || now.getTime() - refusedAt >= REFUSAL_TTL_MS) {
293
+ delete history.refused[name];
294
+ }
295
+ }
296
+ writeHistory(configuredDataDir, history);
297
+ }
298
+ function recordSwitch(modelSwitch) {
299
+ if (!configuredDataDir)
300
+ return;
301
+ const history = readHistory(configuredDataDir);
302
+ history.last_switch = modelSwitch;
303
+ writeHistory(configuredDataDir, history);
304
+ }
305
+ function readHistory(dataDir) {
306
+ if (!dataDir)
307
+ return { refused: {} };
308
+ try {
309
+ const parsed = JSON.parse(fs.readFileSync(path.join(dataDir, MODEL_HISTORY_FILE), "utf-8"));
310
+ const refused = parsed.refused && typeof parsed.refused === "object" ? parsed.refused : {};
311
+ const last = parsed.last_switch;
312
+ const lastValid = last &&
313
+ typeof last.from === "string" &&
314
+ typeof last.to === "string" &&
315
+ typeof last.at === "string";
316
+ return lastValid
317
+ ? { refused, last_switch: { ...last, from_config: last.from_config === true } }
318
+ : { refused };
319
+ }
320
+ catch {
321
+ return { refused: {} };
322
+ }
323
+ }
324
+ function writeHistory(dataDir, history) {
325
+ const file = path.join(dataDir, MODEL_HISTORY_FILE);
326
+ try {
327
+ fs.mkdirSync(path.dirname(file), { recursive: true });
328
+ // Temp + rename: the daemon and `onadit capture` can write at the same time.
329
+ const tmp = `${file}.${process.pid}.tmp`;
330
+ fs.writeFileSync(tmp, `${JSON.stringify(history, null, 2)}\n`, "utf-8");
331
+ fs.renameSync(tmp, file);
332
+ }
333
+ catch {
334
+ // Best-effort, like the persisted model: the in-memory refusal still holds
335
+ // for this process, and a lost record only costs one refused call later.
336
+ }
337
+ }
194
338
  //# sourceMappingURL=codex-cli-model.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"codex-cli-model.js","sourceRoot":"","sources":["../../../src/providers/codex-cli-model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"codex-cli-model.js","sourceRoot":"","sources":["../../../src/providers/codex-cli-model.ts"],"names":[],"mappings":"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"}
@@ -38,6 +38,16 @@ export declare class CodexCliTimeoutError extends Error {
38
38
  readonly signal: NodeJS.Signals | null;
39
39
  constructor(timeoutMs: number, signal: NodeJS.Signals | null, detail?: string);
40
40
  }
41
+ /**
42
+ * Thrown when Codex exits refusing the pinned model — retired, or not on the
43
+ * account's plan ("The 'gpt-5.5' model is not supported when using Codex with
44
+ * a ChatGPT account."). Found in the FULL output before it is shortened, and
45
+ * named first in the message, so the recorded error always says it.
46
+ */
47
+ export declare class CodexModelRejectedError extends Error {
48
+ readonly model: string;
49
+ constructor(model: string, reason: string, exitCode: number);
50
+ }
41
51
  export declare function runCodexCliJson<T>(options: CodexCliRunOptions): Promise<CodexCliRunResult<T>>;
42
52
  /**
43
53
  * Cheap, synchronous "is the Codex CLI installed?" probe — resolves the
@@ -56,5 +66,5 @@ export declare function resetCodexCliRunnerCacheForTests(): void;
56
66
  * salient `ERROR` lines plus the tail. Short outputs are returned whole.
57
67
  */
58
68
  export declare function summarizeCodexOutput(stderr: string, stdout: string): string;
59
- export declare function resolveCodexExecutableForTests(name: string, pathEnv?: string | undefined, fallbackDirs?: readonly string[]): string | undefined;
69
+ export declare function resolveCodexExecutableForTests(name: string, pathEnv?: string | undefined, fallbackDirs?: readonly string[], keepsCodexHome?: (wrapper: string) => boolean): string | undefined;
60
70
  //# sourceMappingURL=codex-cli-runner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codex-cli-runner.d.ts","sourceRoot":"","sources":["../../../src/providers/codex-cli-runner.ts"],"names":[],"mappings":"AA+BA,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,MAAM,EAAE,CAAC,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;CACf;AA2CD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,GACxD,IAAI,CAGN;AA2DD;;;;;;;;GAQG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;gBAC3B,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,EAAE,MAAM,SAAK;CAS1E;AAMD,wBAAsB,eAAe,CAAC,CAAC,EACrC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAgG/B;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAED,wBAAgB,gCAAgC,IAAI,IAAI,CAOvD;AAgLD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAe3E;AAsGD,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,MAAM,GAAG,SAA+B,EACjD,YAAY,GAAE,SAAS,MAAM,EAAmC,GAC/D,MAAM,GAAG,SAAS,CAepB"}
1
+ {"version":3,"file":"codex-cli-runner.d.ts","sourceRoot":"","sources":["../../../src/providers/codex-cli-runner.ts"],"names":[],"mappings":"AAkCA,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,MAAM,EAAE,CAAC,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;CACf;AAsED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,GACxD,IAAI,CAGN;AA2DD;;;;;;;;GAQG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;gBAC3B,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,EAAE,MAAM,SAAK;CAS1E;AAED;;;;;GAKG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBACX,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAK5D;AASD,wBAAsB,eAAe,CAAC,CAAC,EACrC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CA4C/B;AAwFD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAED,wBAAgB,gCAAgC,IAAI,IAAI,CAQvD;AAiMD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAe3E;AA4GD,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,MAAM,GAAG,SAA+B,EACjD,YAAY,GAAE,SAAS,MAAM,EAAmC,EAChE,cAAc,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAA+B,GACnE,MAAM,GAAG,SAAS,CA8BpB"}
@@ -2,8 +2,9 @@ import crypto from "node:crypto";
2
2
  import fs from "node:fs";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
- import { spawn } from "node:child_process";
6
- import { resetCodexModelCacheForTests, resolveCodexModel, } from "./codex-cli-model.js";
5
+ import { spawn, spawnSync } from "node:child_process";
6
+ import { findCodexModelRejection } from "../diagnostics/codex-preflight.js";
7
+ import { markCodexModelRefused, resetCodexModelCacheForTests, resolveCodexModel, } from "./codex-cli-model.js";
7
8
  const SCHEMA_CACHE = new Map();
8
9
  let codexVersionPromise = null;
9
10
  let isolatedCodexHomePath = null;
@@ -30,9 +31,10 @@ const CODEX_MODEL_PROBE_SCHEMA = {
30
31
  };
31
32
  /**
32
33
  * Does this model actually run under our isolated CODEX_HOME? A tiny real
33
- * `codex exec` — true on a clean structured response, false on any failure
34
- * (unsupported model, auth, timeout). Injected into resolveCodexModel so the
35
- * fallback is verified rather than guessed.
34
+ * `codex exec` — true on a clean structured response, false when Codex refuses
35
+ * the model. Any other failure (auth, network, timeout) throws: it is not about
36
+ * the model, so trying the next one would only hide it. Injected into
37
+ * resolveCodexModel so the pick is verified rather than guessed.
36
38
  */
37
39
  async function probeCodexModel(model) {
38
40
  try {
@@ -44,9 +46,31 @@ async function probeCodexModel(model) {
44
46
  });
45
47
  return true;
46
48
  }
47
- catch {
48
- return false;
49
+ catch (error) {
50
+ if (error instanceof CodexModelRejectedError) {
51
+ return false;
52
+ }
53
+ throw error;
54
+ }
55
+ }
56
+ /**
57
+ * The models this account can use, from `codex debug models`. Signed in, Codex
58
+ * refreshes the list from OpenAI (well under a second; no model call, no
59
+ * content), so a retired model is already gone from it. Injected into
60
+ * resolveCodexModel.
61
+ */
62
+ async function listCodexCatalog() {
63
+ const { stdout } = await runCodexCommand(["debug", "models"], {
64
+ cwd: ensureRuntimeTempDir(),
65
+ timeoutMs: 30_000,
66
+ });
67
+ const models = JSON.parse(stdout).models;
68
+ if (!Array.isArray(models)) {
69
+ return [];
49
70
  }
71
+ return models.filter((model) => typeof model === "object" &&
72
+ model !== null &&
73
+ typeof model.slug === "string");
50
74
  }
51
75
  /**
52
76
  * `codex exec` options `runCodexCliJson` depends on. A `codex` whose
@@ -140,6 +164,22 @@ export class CodexCliTimeoutError extends Error {
140
164
  this.signal = signal;
141
165
  }
142
166
  }
167
+ /**
168
+ * Thrown when Codex exits refusing the pinned model — retired, or not on the
169
+ * account's plan ("The 'gpt-5.5' model is not supported when using Codex with
170
+ * a ChatGPT account."). Found in the FULL output before it is shortened, and
171
+ * named first in the message, so the recorded error always says it.
172
+ */
173
+ export class CodexModelRejectedError extends Error {
174
+ model;
175
+ constructor(model, reason, exitCode) {
176
+ super(`Codex CLI failed (exit ${exitCode}) — Codex rejected the model "${model}": ${reason}`);
177
+ this.name = "CodexModelRejectedError";
178
+ this.model = model;
179
+ }
180
+ }
181
+ /** At most this many model switches inside one call — see runCodexCliJson. */
182
+ const CODEX_MODEL_SWITCH_LIMIT = 3;
143
183
  function delay(ms) {
144
184
  return new Promise((resolve) => setTimeout(resolve, ms));
145
185
  }
@@ -151,12 +191,40 @@ export async function runCodexCliJson(options) {
151
191
  // uses `codex exec --help` only — no content, no model call, no auth — and is
152
192
  // cached process-wide on success. Mirrors the Claude runner's pre-send probe.
153
193
  await ensureCodexExecCompatible(cwd);
154
- const schemaPath = ensureSchemaFile(options.schema);
155
- const timeoutMs = options.timeoutMs ?? 120_000;
194
+ const exec = {
195
+ prompt: options.prompt,
196
+ cwd,
197
+ schemaPath: ensureSchemaFile(options.schema),
198
+ timeoutMs: options.timeoutMs ?? 120_000,
199
+ };
200
+ // An explicit model (the probe) is run as asked — never swapped.
201
+ if (options.model !== undefined) {
202
+ return runCodexExec(exec, options.model);
203
+ }
156
204
  // Pin an explicit model on every run. Never inherit codex's implicit
157
205
  // default — that default changes between releases and silently broke every
158
206
  // preflight when 0.125.0 moved it to a ChatGPT-plan-rejected model.
159
- const model = options.model ?? (await resolveCodexModel(probeCodexModel));
207
+ let model = await resolveCodexModel(probeCodexModel, listCodexCatalog);
208
+ // When Codex refuses the model (OpenAI retired it, or the plan lost it),
209
+ // record the refusal, pick another model and run again, instead of failing
210
+ // every capture until someone edits config.json. Bounded: the configured,
211
+ // source and persisted models are tried unprobed, so each can be refused once
212
+ // before resolution reaches the probed catalog.
213
+ for (let switches = 0;; switches++) {
214
+ try {
215
+ return await runCodexExec(exec, model);
216
+ }
217
+ catch (error) {
218
+ if (!(error instanceof CodexModelRejectedError) ||
219
+ switches >= CODEX_MODEL_SWITCH_LIMIT) {
220
+ throw error;
221
+ }
222
+ markCodexModelRefused(model);
223
+ model = await resolveCodexModel(probeCodexModel, listCodexCatalog);
224
+ }
225
+ }
226
+ }
227
+ async function runCodexExec(exec, model) {
160
228
  // One bounded retry, and ONLY for timeout/termination (the old "exit null").
161
229
  // Triage/preflight calls that get SIGTERM'd are overwhelmingly transient
162
230
  // (cold start, brief contention), so a single retry recovers them inside the
@@ -184,13 +252,13 @@ export async function runCodexCliJson(options) {
184
252
  "--model",
185
253
  model,
186
254
  "--output-schema",
187
- schemaPath,
255
+ exec.schemaPath,
188
256
  "--output-last-message",
189
257
  outputPath,
190
258
  ], {
191
- cwd,
192
- timeoutMs,
193
- stdinText: options.prompt,
259
+ cwd: exec.cwd,
260
+ timeoutMs: exec.timeoutMs,
261
+ stdinText: exec.prompt,
194
262
  });
195
263
  const raw = fs.existsSync(outputPath)
196
264
  ? fs.readFileSync(outputPath, "utf-8").trim()
@@ -201,7 +269,7 @@ export async function runCodexCliJson(options) {
201
269
  try {
202
270
  return {
203
271
  output: JSON.parse(raw),
204
- cliTag: await resolveCodexCliTag(cwd),
272
+ cliTag: await resolveCodexCliTag(exec.cwd),
205
273
  model,
206
274
  };
207
275
  }
@@ -241,6 +309,7 @@ export function resetCodexCliRunnerCacheForTests() {
241
309
  codexVersionPromise = null;
242
310
  codexLaunchSpec = null;
243
311
  codexExecCompatible = false;
312
+ wrapperKeepsCodexHomeCache.clear();
244
313
  resetCodexModelCacheForTests();
245
314
  cleanupRuntimeTempArtifacts();
246
315
  }
@@ -358,6 +427,19 @@ async function runCodexCommandOnce(args, options) {
358
427
  return;
359
428
  }
360
429
  if (code !== 0) {
430
+ // Look for a model refusal in the FULL output, before it is shortened:
431
+ // a burst of reconnect errors can push it out of the summary. Only a
432
+ // Codex ERROR line naming the pinned model counts, and not one that is
433
+ // part of the prompt Codex echoes back (a triaged conversation can
434
+ // quote an old refusal).
435
+ const model = pinnedModelArg(args);
436
+ const rejection = model
437
+ ? findCodexModelRejection(`${stderr}\n${stdout}`, model, options.stdinText ?? "")
438
+ : null;
439
+ if (model && rejection) {
440
+ reject(new CodexModelRejectedError(model, rejection, code));
441
+ return;
442
+ }
361
443
  reject(new Error(`Codex CLI failed (exit ${code})${summary
362
444
  ? ` — ${summary}`
363
445
  : stdinError
@@ -397,6 +479,11 @@ export function summarizeCodexOutput(stderr, stdout) {
397
479
  ? combined
398
480
  : `…${combined.slice(-CODEX_OUTPUT_SUMMARY_MAX)}`;
399
481
  }
482
+ /** The value after `--model` in a codex argv, if any. */
483
+ function pinnedModelArg(args) {
484
+ const index = args.indexOf("--model");
485
+ return index >= 0 ? args[index + 1] : undefined;
486
+ }
400
487
  function isIgnorableStdinError(error) {
401
488
  return ("code" in error &&
402
489
  (error.code === "EPIPE" ||
@@ -470,20 +557,94 @@ function resolveCodexLaunchSpec() {
470
557
  : { command: stableLaunchPath, prefixArgs: [] };
471
558
  return codexLaunchSpec;
472
559
  }
473
- export function resolveCodexExecutableForTests(name, pathEnv = process.env["PATH"], fallbackDirs = CODEX_EXECUTABLE_FALLBACK_DIRS) {
560
+ export function resolveCodexExecutableForTests(name, pathEnv = process.env["PATH"], fallbackDirs = CODEX_EXECUTABLE_FALLBACK_DIRS, keepsCodexHome = wrapperKeepsCodexHome) {
474
561
  const searchDirs = [
475
562
  ...(pathEnv ? pathEnv.split(path.delimiter) : []),
476
563
  ...fallbackDirs,
477
564
  ];
478
- for (const dir of searchDirs) {
479
- if (!dir)
480
- continue;
481
- const candidate = path.join(dir, name);
482
- if (fs.existsSync(candidate)) {
565
+ const candidates = searchDirs
566
+ .filter((dir) => dir.length > 0)
567
+ .map((dir) => path.join(dir, name))
568
+ .filter((candidate) => fs.existsSync(candidate));
569
+ const hasRealBinary = candidates.some((candidate) => !isShellScriptWrapper(candidate));
570
+ for (const candidate of candidates) {
571
+ // A shell-script wrapper (account routing, proxy settings, a version
572
+ // manager) is used as before, unless it replaces the CODEX_HOME we set and
573
+ // a real binary is there to use instead. A wrapper that replaces it makes
574
+ // triage run with the user's MCP servers and hooks (their noise buried
575
+ // the real error on 2026-10-14) and saves every triage call in the user's
576
+ // Codex history, where the next capture picks it up as a conversation.
577
+ if (!isShellScriptWrapper(candidate) ||
578
+ !hasRealBinary ||
579
+ keepsCodexHome(candidate)) {
483
580
  return candidate;
484
581
  }
485
582
  }
486
- return undefined;
583
+ return candidates[0];
584
+ }
585
+ const wrapperKeepsCodexHomeCache = new Map();
586
+ /**
587
+ * Does this wrapper leave our CODEX_HOME alone? Run `login status` with an
588
+ * empty CODEX_HOME: Codex itself, or a wrapper that passes it through, answers
589
+ * "Not logged in"; a wrapper that swaps in the user's own home answers "Logged
590
+ * in using …". Reads a file, no network, a few milliseconds. When the answer is
591
+ * unclear the wrapper is kept, as before this check existed. Cached per path.
592
+ */
593
+ function wrapperKeepsCodexHome(wrapper) {
594
+ const cached = wrapperKeepsCodexHomeCache.get(wrapper);
595
+ if (cached !== undefined)
596
+ return cached;
597
+ let keeps = true;
598
+ let emptyHome;
599
+ try {
600
+ emptyHome = fs.mkdtempSync(path.join(ensureRuntimeTempDir(), "codex-home-check-"));
601
+ const result = spawnSync(wrapper, ["login", "status"], {
602
+ env: { ...process.env, CODEX_HOME: emptyHome },
603
+ encoding: "utf-8",
604
+ timeout: 10_000,
605
+ });
606
+ if (!result.error) {
607
+ keeps = !/logged in using/i.test(`${result.stdout ?? ""}\n${result.stderr ?? ""}`);
608
+ }
609
+ }
610
+ catch {
611
+ // Keep the wrapper.
612
+ }
613
+ finally {
614
+ if (emptyHome)
615
+ fs.rmSync(emptyHome, { recursive: true, force: true });
616
+ }
617
+ wrapperKeepsCodexHomeCache.set(wrapper, keeps);
618
+ return keeps;
619
+ }
620
+ /**
621
+ * A `codex` that is a shell script (`#!/bin/sh`, `#!/usr/bin/env bash`, …) is a
622
+ * wrapper around Codex, not Codex. A node `.js` entry point is not a shell
623
+ * script.
624
+ */
625
+ function isShellScriptWrapper(file) {
626
+ let fd;
627
+ try {
628
+ fd = fs.openSync(file, "r");
629
+ const head = Buffer.alloc(128);
630
+ const bytesRead = fs.readSync(fd, head, 0, head.length, 0);
631
+ const firstLine = head.subarray(0, bytesRead).toString("utf-8").split("\n")[0] ?? "";
632
+ if (!firstLine.startsWith("#!"))
633
+ return false;
634
+ // `#!/bin/sh` → sh; `#!/usr/bin/env -S bash -e` → bash; `#!/usr/bin/env node` → node.
635
+ const [command = "", ...rest] = firstLine.slice(2).trim().split(/\s+/);
636
+ const interpreter = path.basename(command) === "env"
637
+ ? (rest.find((arg) => !arg.startsWith("-")) ?? "")
638
+ : path.basename(command);
639
+ return /^(sh|bash|zsh|dash|ksh)$/.test(path.basename(interpreter));
640
+ }
641
+ catch {
642
+ return false;
643
+ }
644
+ finally {
645
+ if (fd !== undefined)
646
+ fs.closeSync(fd);
647
+ }
487
648
  }
488
649
  /**
489
650
  * Path to a private CODEX_HOME holding ONLY a copy of the operator's