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.
- package/README.md +1 -1
- package/dist/src/cli/commands/onboard.js +2 -2
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/status.js +1 -1
- package/dist/src/cli/commands/status.js.map +1 -1
- package/dist/src/cli/commands/update.d.ts +1 -1
- package/dist/src/cli/commands/update.d.ts.map +1 -1
- package/dist/src/cli/commands/update.js +23 -20
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/cli/status/friend-header.d.ts.map +1 -1
- package/dist/src/cli/status/friend-header.js +20 -1
- package/dist/src/cli/status/friend-header.js.map +1 -1
- package/dist/src/diagnostics/codex-preflight.d.ts +10 -0
- package/dist/src/diagnostics/codex-preflight.d.ts.map +1 -1
- package/dist/src/diagnostics/codex-preflight.js +30 -1
- package/dist/src/diagnostics/codex-preflight.js.map +1 -1
- package/dist/src/diagnostics/doctor.js +1 -1
- package/dist/src/diagnostics/doctor.js.map +1 -1
- package/dist/src/observability/version-check.d.ts +7 -3
- package/dist/src/observability/version-check.d.ts.map +1 -1
- package/dist/src/observability/version-check.js +5 -5
- package/dist/src/observability/version-check.js.map +1 -1
- package/dist/src/providers/codex-cli-model.d.ts +65 -16
- package/dist/src/providers/codex-cli-model.d.ts.map +1 -1
- package/dist/src/providers/codex-cli-model.js +187 -43
- package/dist/src/providers/codex-cli-model.js.map +1 -1
- package/dist/src/providers/codex-cli-runner.d.ts +11 -1
- package/dist/src/providers/codex-cli-runner.d.ts.map +1 -1
- package/dist/src/providers/codex-cli-runner.js +183 -22
- package/dist/src/providers/codex-cli-runner.js.map +1 -1
- package/dist/src/retrieval/context-pack.d.ts.map +1 -1
- package/dist/src/retrieval/context-pack.js +16 -6
- package/dist/src/retrieval/context-pack.js.map +1 -1
- package/dist/src/server/routes/friend-status.d.ts +7 -0
- package/dist/src/server/routes/friend-status.d.ts.map +1 -1
- package/dist/src/server/routes/friend-status.js +7 -3
- package/dist/src/server/routes/friend-status.js.map +1 -1
- 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
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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
|
-
|
|
24
|
-
|
|
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
|
|
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 →
|
|
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`
|
|
71
|
-
* runner (rather than imported) to avoid
|
|
72
|
-
* a
|
|
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
|
-
|
|
80
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
let catalog = [];
|
|
83
|
+
try {
|
|
84
|
+
catalog = await listModels();
|
|
85
85
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
90
|
+
const candidates = orderCodexModelCandidates(catalog, (model) => isRefused(model, now)).slice(0, MAX_CATALOG_PROBES);
|
|
91
91
|
const tried = [];
|
|
92
|
-
for (const candidate of
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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":"
|
|
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 {
|
|
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
|
|
34
|
-
*
|
|
35
|
-
*
|
|
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
|
-
|
|
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
|
|
155
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
|
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
|