@bitkyc08/opencodex 2.53.0-preview.20260913 → 2.54.0-preview.20260914
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/gui/dist/assets/{index-D7ynYo2K.js → index-B4VYfZcY.js} +2 -2
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapters/devin.ts +39 -7
- package/src/cli/capabilities.ts +4 -2
- package/src/cli/catalog.ts +39 -10
- package/src/cli/dispatch.ts +19 -64
- package/src/cli/doctor.ts +1 -1
- package/src/cli/internal-command.ts +44 -0
- package/src/cli/registry.ts +9 -7
- package/src/cli/restart-scope.ts +184 -0
- package/src/codex/app-server-processes.ts +20 -5
- package/src/codex/app-server-restart-service.ts +29 -0
- package/src/codex/catalog/provider-fetch.ts +13 -5
- package/src/codex/catalog/sync.ts +12 -3
- package/src/codex/desktop-app/darwin.ts +268 -0
- package/src/codex/desktop-app/handoff.ts +303 -0
- package/src/codex/desktop-app/linux.ts +388 -0
- package/src/codex/desktop-app/lock.ts +226 -0
- package/src/codex/desktop-app/types.ts +141 -0
- package/src/codex/desktop-app/windows.ts +239 -0
- package/src/codex/desktop-app-restart.ts +264 -279
- package/src/codex/inject.ts +83 -21
- package/src/codex/sync.ts +16 -22
- package/src/generated/compatibility-version.json +58 -22
- package/src/lib/codex-restart-contract.ts +31 -0
- package/src/providers/registry.ts +13 -12
- package/src/server/responses/core.ts +62 -4
- package/src/server/responses/encrypted-payload.ts +161 -0
- package/src/server/responses.ts +1 -1
- package/src/types/provider.ts +6 -5
- package/src/web-search/index.ts +14 -67
- package/src/web-search/passthrough-bridge.ts +256 -32
- package/src/web-search/sidecar-providers.ts +76 -0
package/src/codex/inject.ts
CHANGED
|
@@ -895,7 +895,13 @@ export function chooseCatalogPathForInjection(
|
|
|
895
895
|
export interface CodexInjectResult {
|
|
896
896
|
success: boolean;
|
|
897
897
|
message: string;
|
|
898
|
-
/**
|
|
898
|
+
/**
|
|
899
|
+
* Structured read-only history preflight refusal; never parsed from display text.
|
|
900
|
+
*
|
|
901
|
+
* On the apply direction this reports that the conversation-history relabel unit stood
|
|
902
|
+
* down while the config was still written, so a caller must not read it as a failure.
|
|
903
|
+
* The restore and remove directions still refuse outright and say so in `message`.
|
|
904
|
+
*/
|
|
899
905
|
historyPreflightFailureReason?: string;
|
|
900
906
|
status?: "skipped";
|
|
901
907
|
/** `hub-gated` is the hub-role gate (#4236), distinct from the user's own OFF switch. */
|
|
@@ -903,6 +909,12 @@ export interface CodexInjectResult {
|
|
|
903
909
|
nativeSubagentDefaultsWarning?: string;
|
|
904
910
|
}
|
|
905
911
|
|
|
912
|
+
/**
|
|
913
|
+
* The one history preflight reason that is permanent rather than operational: Codex owns
|
|
914
|
+
* paginated rollout ordinals, so no retry makes the legacy relabel protocol available again.
|
|
915
|
+
*/
|
|
916
|
+
const HISTORY_RELABEL_STANDS_DOWN = "history_paginated_requires_native_writer";
|
|
917
|
+
|
|
906
918
|
class CodexHistoryPreflightRefusal extends Error {}
|
|
907
919
|
class CodexRestoreRefusal extends Error {
|
|
908
920
|
constructor(readonly config: CodexRestoreConfigResult) {
|
|
@@ -929,7 +941,7 @@ export async function injectCodexConfig(
|
|
|
929
941
|
): Promise<CodexInjectResult> {
|
|
930
942
|
try { return await injectCodexConfigImpl(port, config, options); }
|
|
931
943
|
catch (error) {
|
|
932
|
-
if (error instanceof CodexHistoryPreflightRefusal) return { success: false, message: `Codex config injection refused: ${error.message}. Existing configuration and history were preserved.` };
|
|
944
|
+
if (error instanceof CodexHistoryPreflightRefusal) return { success: false, historyPreflightFailureReason: error.message, message: `Codex config injection refused: ${error.message}. Existing configuration and history were preserved.` };
|
|
933
945
|
throw error;
|
|
934
946
|
}
|
|
935
947
|
}
|
|
@@ -1055,7 +1067,10 @@ async function injectCodexConfigImpl(
|
|
|
1055
1067
|
journaledInjectedOpenaiBaseUrl({ readOnly: !!options.beforeClientWrite }),
|
|
1056
1068
|
journaledInjectedRealtimeWsBaseUrl({ readOnly: !!options.beforeClientWrite }),
|
|
1057
1069
|
);
|
|
1058
|
-
|
|
1070
|
+
// Whether this home already published the provider id that its thread rows may reference.
|
|
1071
|
+
// Design B strips the table below; it may only stay stripped if those rows can be relabeled.
|
|
1072
|
+
const hadOcxProviderTableOnDisk = hasOcxProviderTable(content);
|
|
1073
|
+
if (hadOcxProviderTableOnDisk) {
|
|
1059
1074
|
content = removeOcxSection(content);
|
|
1060
1075
|
}
|
|
1061
1076
|
content = removeProfileSection(content);
|
|
@@ -1190,16 +1205,56 @@ async function injectCodexConfigImpl(
|
|
|
1190
1205
|
return "history_injection_preflight_unavailable";
|
|
1191
1206
|
}
|
|
1192
1207
|
};
|
|
1193
|
-
|
|
1194
|
-
|
|
1208
|
+
/*
|
|
1209
|
+
* ONE refusal stands the relabel unit down instead of vetoing the config transition, and
|
|
1210
|
+
* only because it is permanent. Codex allocates paginated rollout ordinals in its own
|
|
1211
|
+
* writer, so `assertLegacyHistoryRecord` refuses every rollout on a current install and no
|
|
1212
|
+
* amount of retrying changes that. While it vetoed the write, `model_catalog_json` never
|
|
1213
|
+
* reached config.toml, so the app and the CLI both fell back to their built-in model list
|
|
1214
|
+
* while `ocx sync` still reported success.
|
|
1215
|
+
*
|
|
1216
|
+
* Every other reason — an unreadable state database, a rollout whose identity changed, a
|
|
1217
|
+
* preflight that could not run — describes a store that may well be relabelable on the next
|
|
1218
|
+
* attempt. Treating those as a stand-down would record the transition as converged and
|
|
1219
|
+
* suppress the relabel permanently, so they keep the hard refusal and the rollback.
|
|
1220
|
+
*/
|
|
1221
|
+
/*
|
|
1222
|
+
* Re-observed inside the artifact transaction. A store that migrates to paginated history
|
|
1223
|
+
* mid-write retires the relabel unit, because the config half writes no history and rolling
|
|
1224
|
+
* it back is what left every paginated home with no OpenCodex models. Any other reason is
|
|
1225
|
+
* still treated as a failed transition so compensation can restore the pre-images.
|
|
1226
|
+
*/
|
|
1227
|
+
const observeHistoryRefusalOrThrow = (known: string | null): string | null => {
|
|
1228
|
+
if (known) return known;
|
|
1229
|
+
const observed = historyPreflight();
|
|
1230
|
+
if (observed && observed !== HISTORY_RELABEL_STANDS_DOWN) throw new CodexHistoryPreflightRefusal(observed);
|
|
1231
|
+
return observed;
|
|
1232
|
+
};
|
|
1233
|
+
const observedHistoryRefusal = historyPreflight();
|
|
1234
|
+
if (observedHistoryRefusal && observedHistoryRefusal !== HISTORY_RELABEL_STANDS_DOWN) {
|
|
1195
1235
|
return {
|
|
1196
1236
|
success: false,
|
|
1197
|
-
historyPreflightFailureReason:
|
|
1198
|
-
message: `Codex config injection refused: ${
|
|
1237
|
+
historyPreflightFailureReason: observedHistoryRefusal,
|
|
1238
|
+
message: `Codex config injection refused: ${observedHistoryRefusal}. `
|
|
1199
1239
|
+ "Existing provider definitions and conversation files were preserved. "
|
|
1200
1240
|
+ "Paginated history requires native-writer coordination; do not run legacy recovery or retry this transition blindly.",
|
|
1201
1241
|
};
|
|
1202
1242
|
}
|
|
1243
|
+
let historyRelabelRefusal = observedHistoryRefusal;
|
|
1244
|
+
|
|
1245
|
+
/*
|
|
1246
|
+
* Rows this home may have tagged `opencodex` resolve only through a provider table. Design B
|
|
1247
|
+
* normally retires that table because the relabel migrates those rows back to `openai` in
|
|
1248
|
+
* the same pass; with the relabel stood down, stripping it anyway would leave every such
|
|
1249
|
+
* conversation pointing at a provider id that no longer exists. Keep what was already
|
|
1250
|
+
* published, and keep it BEFORE the witness so the lock admits the bytes actually written.
|
|
1251
|
+
*/
|
|
1252
|
+
if (historyRelabelRefusal && hadOcxProviderTableOnDisk && !providerTableMode) {
|
|
1253
|
+
content = applyEol(
|
|
1254
|
+
content.trimEnd() + "\n" + buildProviderTableBlockForTarget(routingTarget, websocketsEnabled(config ?? {})),
|
|
1255
|
+
eol,
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1203
1258
|
|
|
1204
1259
|
/*
|
|
1205
1260
|
* The witness, built from the FINAL bytes. Everything it hashes is either the
|
|
@@ -1286,14 +1341,14 @@ async function injectCodexConfigImpl(
|
|
|
1286
1341
|
if (options.validateOnly) {
|
|
1287
1342
|
return {
|
|
1288
1343
|
success: true,
|
|
1344
|
+
...(historyRelabelRefusal ? { historyPreflightFailureReason: historyRelabelRefusal } : {}),
|
|
1289
1345
|
message: "Codex config injection preflight passed; no files were changed.",
|
|
1290
1346
|
};
|
|
1291
1347
|
}
|
|
1292
1348
|
|
|
1293
1349
|
const applyNativeArtifacts = (): void => {
|
|
1294
1350
|
beforeHistoryArtifactCommitForTests?.(eligibility.kind);
|
|
1295
|
-
|
|
1296
|
-
if (historyError) throw new CodexHistoryPreflightRefusal(historyError);
|
|
1351
|
+
historyRelabelRefusal = observeHistoryRefusalOrThrow(historyRelabelRefusal);
|
|
1297
1352
|
const preImages = captureCodexPreImages();
|
|
1298
1353
|
try {
|
|
1299
1354
|
historyArtifactStageForTests?.("after-preflight");
|
|
@@ -1329,9 +1384,7 @@ async function injectCodexConfigImpl(
|
|
|
1329
1384
|
});
|
|
1330
1385
|
historyArtifactStageForTests?.("after-artifacts");
|
|
1331
1386
|
// Detect migration throughout the artifact transaction, not just at entry.
|
|
1332
|
-
|
|
1333
|
-
const finalHistoryError = historyPreflight();
|
|
1334
|
-
if (finalHistoryError) throw new CodexHistoryPreflightRefusal(finalHistoryError);
|
|
1387
|
+
historyRelabelRefusal = observeHistoryRefusalOrThrow(historyRelabelRefusal);
|
|
1335
1388
|
} catch (error) {
|
|
1336
1389
|
const compensated = restoreCodexPreImages(preImages);
|
|
1337
1390
|
if (!compensated.complete) throw new CodexPartialWriteError(compensated.unrestored);
|
|
@@ -1487,15 +1540,19 @@ async function injectCodexConfigImpl(
|
|
|
1487
1540
|
// serialized one of them and an opposite-direction process could overtake
|
|
1488
1541
|
// through the other two. The operation is derived from admitted intent here and
|
|
1489
1542
|
// handed down fixed; the Worker never takes a direction from its caller.
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1543
|
+
// A stood-down relabel unit spawns no Worker: the preflight it would run first has
|
|
1544
|
+
// already refused, and the config half is committed either way.
|
|
1545
|
+
const historyOutcome: CodexHistoryJobOutcome = historyRelabelRefusal
|
|
1546
|
+
? { kind: "skipped" }
|
|
1547
|
+
: await runCodexHistoryJob({
|
|
1548
|
+
...resolveCodexHistoryJobTarget(),
|
|
1549
|
+
expectedDesiredEnabled: true,
|
|
1550
|
+
operation: deriveCodexHistoryOperation({
|
|
1551
|
+
direction: "apply",
|
|
1552
|
+
resumeHistory: config?.syncResumeHistory !== false && !keepRootOverrideAlongsideTable,
|
|
1553
|
+
legacyMode: providerTableMode,
|
|
1554
|
+
}),
|
|
1555
|
+
});
|
|
1499
1556
|
// A blocked or failed unit is reported, not silently counted as zero work:
|
|
1500
1557
|
// `failed` is what makes the caller's message say so.
|
|
1501
1558
|
const history: { rows: number; files: number; failed?: true } =
|
|
@@ -1528,6 +1585,8 @@ async function injectCodexConfigImpl(
|
|
|
1528
1585
|
? (keptUserBaseUrl
|
|
1529
1586
|
? ` Codex resume history: left unchanged; threads already tagged openai follow your configured root openai_base_url.\n`
|
|
1530
1587
|
: ` Codex resume history: left unchanged; existing threads keep reaching the proxy through the retained openai_base_url override.\n`)
|
|
1588
|
+
: historyRelabelRefusal
|
|
1589
|
+
? ` ⚠️ Codex resume history: left to Codex's native writer (${historyRelabelRefusal}); existing threads keep the provider they are tagged with. Routing and the model catalog were still installed, so new threads reach the proxy.\n`
|
|
1531
1590
|
: config?.syncResumeHistory === false
|
|
1532
1591
|
? ` Codex resume history: left unchanged (syncResumeHistory=false).\n`
|
|
1533
1592
|
: history.failed
|
|
@@ -1548,6 +1607,7 @@ async function injectCodexConfigImpl(
|
|
|
1548
1607
|
return {
|
|
1549
1608
|
success: true,
|
|
1550
1609
|
...(nativeSubagentDefaultsWarning ? { nativeSubagentDefaultsWarning } : {}),
|
|
1610
|
+
...(historyRelabelRefusal ? { historyPreflightFailureReason: historyRelabelRefusal } : {}),
|
|
1551
1611
|
message:
|
|
1552
1612
|
`Injected opencodex as default provider into Codex config (client-side compaction mode; ChatGPT auth remains required).\n` +
|
|
1553
1613
|
` Your root openai_base_url was left exactly as you set it, so opencodex did not add its own.\n` +
|
|
@@ -1566,6 +1626,7 @@ async function injectCodexConfigImpl(
|
|
|
1566
1626
|
...(nativeSubagentDefaultsWarning
|
|
1567
1627
|
? { nativeSubagentDefaultsWarning }
|
|
1568
1628
|
: {}),
|
|
1629
|
+
...(historyRelabelRefusal ? { historyPreflightFailureReason: historyRelabelRefusal } : {}),
|
|
1569
1630
|
message:
|
|
1570
1631
|
`⚠️ Codex routing NOT injected: your config already sets a root openai_base_url, and opencodex never overwrites a user-owned override.\n` +
|
|
1571
1632
|
catalogMessage +
|
|
@@ -1585,6 +1646,7 @@ async function injectCodexConfigImpl(
|
|
|
1585
1646
|
return {
|
|
1586
1647
|
success: true,
|
|
1587
1648
|
...(nativeSubagentDefaultsWarning ? { nativeSubagentDefaultsWarning } : {}),
|
|
1649
|
+
...(historyRelabelRefusal ? { historyPreflightFailureReason: historyRelabelRefusal } : {}),
|
|
1588
1650
|
message:
|
|
1589
1651
|
headline +
|
|
1590
1652
|
catalogMessage +
|
package/src/codex/sync.ts
CHANGED
|
@@ -19,7 +19,7 @@ export interface CodexSyncResult {
|
|
|
19
19
|
/**
|
|
20
20
|
* `skipped` is policy truth, never evidence that Codex was written.
|
|
21
21
|
* `catalog-only` means an explicit sync refreshed the catalog/cache while
|
|
22
|
-
* config/history injection was skipped (OFF, externally owned
|
|
22
|
+
* config/history injection was skipped (integration OFF, or externally owned).
|
|
23
23
|
*/
|
|
24
24
|
status: "applied" | "skipped" | "catalog-only" | "refused";
|
|
25
25
|
ok: boolean;
|
|
@@ -51,8 +51,9 @@ export interface CodexSyncOptions {
|
|
|
51
51
|
* Explicit `ocx sync` is also the refresh path for side profiles that consume
|
|
52
52
|
* the OpenCodex catalog without injection. When set, the sync still refreshes
|
|
53
53
|
* the catalog and models cache even if the Codex integration toggle is OFF or
|
|
54
|
-
* an external `model_provider` owns config.toml
|
|
55
|
-
*
|
|
54
|
+
* an external `model_provider` owns config.toml. Config/history injection is
|
|
55
|
+
* skipped in those two cases. A paginated-history refusal is NOT one of them:
|
|
56
|
+
* the injector writes config and stands only its relabel unit down.
|
|
56
57
|
*/
|
|
57
58
|
catalogEvenWhenNotInjected?: boolean;
|
|
58
59
|
}
|
|
@@ -209,25 +210,12 @@ export async function syncModelsToCodex(
|
|
|
209
210
|
// working catalog/cache into the partial result of an otherwise unnecessary refresh.
|
|
210
211
|
const preflight = await deps.injectCodexConfig(p, config, { validateOnly: true });
|
|
211
212
|
if (!preflight.success) {
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const refreshed = await refreshCatalogForSync(config, deps, undefined, log);
|
|
219
|
-
const ok = refreshed.refreshOutcome === "committed" && refreshed.catalogExists;
|
|
220
|
-
const message = ok
|
|
221
|
-
? "Model catalog synchronized; Codex config and conversation history left unchanged because paginated history requires its native writer."
|
|
222
|
-
: "Model catalog refresh did not complete; Codex config and conversation history were left unchanged.";
|
|
223
|
-
reportCodexHomeTarget(log, deps.collectCodexHomeDiagnostic ?? collectOrcaCodexHomeDiagnostic);
|
|
224
|
-
return {
|
|
225
|
-
...refreshed,
|
|
226
|
-
status: "catalog-only",
|
|
227
|
-
ok,
|
|
228
|
-
message,
|
|
229
|
-
};
|
|
230
|
-
}
|
|
213
|
+
// A paginated-history refusal used to be downgraded here to a `catalog-only` success.
|
|
214
|
+
// That is what made the model picker regression silent: the catalog file was rewritten
|
|
215
|
+
// and reported synchronized while config.toml kept no provider table and no catalog
|
|
216
|
+
// path, so Codex offered only its native models. The injector now writes config and
|
|
217
|
+
// stands the relabel unit down instead, so nothing reaches this branch for that reason
|
|
218
|
+
// and a surviving refusal is a real config/integrity failure again.
|
|
231
219
|
log?.error(preflight.message);
|
|
232
220
|
reportCodexHomeTarget(log, deps.collectCodexHomeDiagnostic ?? collectOrcaCodexHomeDiagnostic);
|
|
233
221
|
return {
|
|
@@ -300,6 +288,12 @@ export async function syncModelsToCodex(
|
|
|
300
288
|
}
|
|
301
289
|
if (result.success) log?.log(result.message);
|
|
302
290
|
else log?.error(result.message);
|
|
291
|
+
// The config was written; only the relabel unit stood down. Carry that as a warning so a
|
|
292
|
+
// caller reading the structured result sees it without parsing the display message.
|
|
293
|
+
if (result.success && result.historyPreflightFailureReason) {
|
|
294
|
+
const historyWarning = `Codex conversation-history relabel left to Codex's native writer: ${result.historyPreflightFailureReason}.`;
|
|
295
|
+
warning = warning ? `${warning} ${historyWarning}` : historyWarning;
|
|
296
|
+
}
|
|
303
297
|
reportCodexHomeTarget(log, deps.collectCodexHomeDiagnostic ?? collectOrcaCodexHomeDiagnostic);
|
|
304
298
|
const projectConfigWarnings = printProjectCodexConfigWarnings(log, { cwd: process.cwd() });
|
|
305
299
|
return {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"path": "package.json",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "a640f2216bdb5ae42aee20beb16d273e59e4b359f9953f1b6185fed066db5d78"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"path": "scripts/model-metadata.source.json",
|
|
@@ -266,7 +266,7 @@
|
|
|
266
266
|
},
|
|
267
267
|
{
|
|
268
268
|
"path": "src/adapters/devin.ts",
|
|
269
|
-
"sha256": "
|
|
269
|
+
"sha256": "15a82837e1d54e5de20b9ed37cb4f450534d907ecdaa08d29632787f7a38cd7c"
|
|
270
270
|
},
|
|
271
271
|
{
|
|
272
272
|
"path": "src/adapters/devin/cloud-direct/auth.ts",
|
|
@@ -698,7 +698,7 @@
|
|
|
698
698
|
},
|
|
699
699
|
{
|
|
700
700
|
"path": "src/cli/capabilities.ts",
|
|
701
|
-
"sha256": "
|
|
701
|
+
"sha256": "eb069b79507e91300e449987d5adfae9e5637a5f70141f204e6f1e6c7ea38526"
|
|
702
702
|
},
|
|
703
703
|
{
|
|
704
704
|
"path": "src/cli/catalog-prewarm.ts",
|
|
@@ -706,7 +706,7 @@
|
|
|
706
706
|
},
|
|
707
707
|
{
|
|
708
708
|
"path": "src/cli/catalog.ts",
|
|
709
|
-
"sha256": "
|
|
709
|
+
"sha256": "3ba859e525b04202b97abf62590c041984053db84510eb981a4910e7bcc3b43a"
|
|
710
710
|
},
|
|
711
711
|
{
|
|
712
712
|
"path": "src/cli/claude-agent-startup-sync.ts",
|
|
@@ -754,11 +754,11 @@
|
|
|
754
754
|
},
|
|
755
755
|
{
|
|
756
756
|
"path": "src/cli/dispatch.ts",
|
|
757
|
-
"sha256": "
|
|
757
|
+
"sha256": "3c52a4d65ac960dfbe25c89fa82fc770d171cda0f53f3a3e469823c6207e4f4b"
|
|
758
758
|
},
|
|
759
759
|
{
|
|
760
760
|
"path": "src/cli/doctor.ts",
|
|
761
|
-
"sha256": "
|
|
761
|
+
"sha256": "57e91bb3223ff95bde1c57b80a2674dbce8a4d403919a63a319ae4e2f96355bd"
|
|
762
762
|
},
|
|
763
763
|
{
|
|
764
764
|
"path": "src/cli/effort.ts",
|
|
@@ -808,6 +808,10 @@
|
|
|
808
808
|
"path": "src/cli/interactive-confirm.ts",
|
|
809
809
|
"sha256": "9fdc081a5f8e7a8c74612371e044f34054151a20b9692c0fd81a2bb41e86f9e5"
|
|
810
810
|
},
|
|
811
|
+
{
|
|
812
|
+
"path": "src/cli/internal-command.ts",
|
|
813
|
+
"sha256": "b8a181fb5276380bf322fe38d7fd0202a0e976491f3148bc357b485282132b57"
|
|
814
|
+
},
|
|
811
815
|
{
|
|
812
816
|
"path": "src/cli/lab.ts",
|
|
813
817
|
"sha256": "1a9b3f10824fabd4c4bdb192a9a2dcaafd3f3aea6b840f46330e2202906aeda9"
|
|
@@ -858,12 +862,16 @@
|
|
|
858
862
|
},
|
|
859
863
|
{
|
|
860
864
|
"path": "src/cli/registry.ts",
|
|
861
|
-
"sha256": "
|
|
865
|
+
"sha256": "c4c80108b8746765f4e0a1d741d4605984788161bf5562ef4459201dc137b016"
|
|
862
866
|
},
|
|
863
867
|
{
|
|
864
868
|
"path": "src/cli/remote-workspace.ts",
|
|
865
869
|
"sha256": "1f3d9a38a6c8ade4b567f6d7b010e9d6e71691fabd9f393fdedfdf6958e93339"
|
|
866
870
|
},
|
|
871
|
+
{
|
|
872
|
+
"path": "src/cli/restart-scope.ts",
|
|
873
|
+
"sha256": "3d0dcc412b9695b4cb83d7da06dcd38cba2b8bb1ed56e6c6d8977f752341699f"
|
|
874
|
+
},
|
|
867
875
|
{
|
|
868
876
|
"path": "src/cli/root.ts",
|
|
869
877
|
"sha256": "19c8d84e3d829d07a9ac8e3115e0cd1a3f3fd7d04416aa8a4754a057104b1ee2"
|
|
@@ -1074,11 +1082,11 @@
|
|
|
1074
1082
|
},
|
|
1075
1083
|
{
|
|
1076
1084
|
"path": "src/codex/app-server-processes.ts",
|
|
1077
|
-
"sha256": "
|
|
1085
|
+
"sha256": "9e0d8d1ae92bbcb6cf82d16ebde3a06021e527a48100a78819a06ca0fe94478f"
|
|
1078
1086
|
},
|
|
1079
1087
|
{
|
|
1080
1088
|
"path": "src/codex/app-server-restart-service.ts",
|
|
1081
|
-
"sha256": "
|
|
1089
|
+
"sha256": "6217a77e951e1155cce05f1a662bf12d7cf558677082b5ee94805907e69f6579"
|
|
1082
1090
|
},
|
|
1083
1091
|
{
|
|
1084
1092
|
"path": "src/codex/auth-api.ts",
|
|
@@ -1150,7 +1158,7 @@
|
|
|
1150
1158
|
},
|
|
1151
1159
|
{
|
|
1152
1160
|
"path": "src/codex/catalog/provider-fetch.ts",
|
|
1153
|
-
"sha256": "
|
|
1161
|
+
"sha256": "7e5b6be0ec07b69c74ccd4e47b9a340cf9b8503e4c84d7a73f229d2224342907"
|
|
1154
1162
|
},
|
|
1155
1163
|
{
|
|
1156
1164
|
"path": "src/codex/catalog/remote.ts",
|
|
@@ -1162,7 +1170,7 @@
|
|
|
1162
1170
|
},
|
|
1163
1171
|
{
|
|
1164
1172
|
"path": "src/codex/catalog/sync.ts",
|
|
1165
|
-
"sha256": "
|
|
1173
|
+
"sha256": "d337c2270cd82ba94ea963127b59613a9e3086722b7625f848b5f6c5380c9007"
|
|
1166
1174
|
},
|
|
1167
1175
|
{
|
|
1168
1176
|
"path": "src/codex/cli-install-provenance.ts",
|
|
@@ -1210,7 +1218,31 @@
|
|
|
1210
1218
|
},
|
|
1211
1219
|
{
|
|
1212
1220
|
"path": "src/codex/desktop-app-restart.ts",
|
|
1213
|
-
"sha256": "
|
|
1221
|
+
"sha256": "33fd530a45237e78f8829b49634d30b5e72e73c518a026b55d70c777f2f10ffc"
|
|
1222
|
+
},
|
|
1223
|
+
{
|
|
1224
|
+
"path": "src/codex/desktop-app/darwin.ts",
|
|
1225
|
+
"sha256": "535068797d57187eab4d3a004c13438d41fcb3300876eb7750d199d8e2e7b860"
|
|
1226
|
+
},
|
|
1227
|
+
{
|
|
1228
|
+
"path": "src/codex/desktop-app/handoff.ts",
|
|
1229
|
+
"sha256": "644c823f83223b12ba73aeb835ead89c3e8189a61f626a2db2353e87ff003748"
|
|
1230
|
+
},
|
|
1231
|
+
{
|
|
1232
|
+
"path": "src/codex/desktop-app/linux.ts",
|
|
1233
|
+
"sha256": "88038f9b068acf9a549aeebe8c590c798671a56c2d2ebbdc6fade0ba07440e5e"
|
|
1234
|
+
},
|
|
1235
|
+
{
|
|
1236
|
+
"path": "src/codex/desktop-app/lock.ts",
|
|
1237
|
+
"sha256": "c4e6fec7461b96a6397c7a06a3e8ae2741f7e9c3b13d1db36473e18b160d482d"
|
|
1238
|
+
},
|
|
1239
|
+
{
|
|
1240
|
+
"path": "src/codex/desktop-app/types.ts",
|
|
1241
|
+
"sha256": "7e42332e52ea3a3957b59df658785b37f87672f0445b03f73d9773f581dd5646"
|
|
1242
|
+
},
|
|
1243
|
+
{
|
|
1244
|
+
"path": "src/codex/desktop-app/windows.ts",
|
|
1245
|
+
"sha256": "8d5c2a333027d115456d61509e521402c178fa60b78e4a209efb0549a5d80b3a"
|
|
1214
1246
|
},
|
|
1215
1247
|
{
|
|
1216
1248
|
"path": "src/codex/exec-invocation.ts",
|
|
@@ -1266,7 +1298,7 @@
|
|
|
1266
1298
|
},
|
|
1267
1299
|
{
|
|
1268
1300
|
"path": "src/codex/inject.ts",
|
|
1269
|
-
"sha256": "
|
|
1301
|
+
"sha256": "8f7807baf60620b30d87c86eb4d03bc6769376dfb147baa97e2d5a682746af14"
|
|
1270
1302
|
},
|
|
1271
1303
|
{
|
|
1272
1304
|
"path": "src/codex/injected-marker.ts",
|
|
@@ -1574,7 +1606,7 @@
|
|
|
1574
1606
|
},
|
|
1575
1607
|
{
|
|
1576
1608
|
"path": "src/codex/sync.ts",
|
|
1577
|
-
"sha256": "
|
|
1609
|
+
"sha256": "4fac2a4db6165eda61d759765319329b49a2aa5a8ee14527dcf65d43c9c4fdc6"
|
|
1578
1610
|
},
|
|
1579
1611
|
{
|
|
1580
1612
|
"path": "src/codex/transition-state.ts",
|
|
@@ -2414,7 +2446,7 @@
|
|
|
2414
2446
|
},
|
|
2415
2447
|
{
|
|
2416
2448
|
"path": "src/lib/codex-restart-contract.ts",
|
|
2417
|
-
"sha256": "
|
|
2449
|
+
"sha256": "f2738e9d2fd79c80430aaa1e6f77161f448ccfd81ab39cbb0bc6cdd6ed7d66fd"
|
|
2418
2450
|
},
|
|
2419
2451
|
{
|
|
2420
2452
|
"path": "src/lib/config-ownership.ts",
|
|
@@ -3078,7 +3110,7 @@
|
|
|
3078
3110
|
},
|
|
3079
3111
|
{
|
|
3080
3112
|
"path": "src/providers/registry.ts",
|
|
3081
|
-
"sha256": "
|
|
3113
|
+
"sha256": "db391a42721d43cd168dafe464bb1d3bb22cb6a935fe8679c58188a0b7fa9359"
|
|
3082
3114
|
},
|
|
3083
3115
|
{
|
|
3084
3116
|
"path": "src/providers/request-pacing.ts",
|
|
@@ -3890,7 +3922,7 @@
|
|
|
3890
3922
|
},
|
|
3891
3923
|
{
|
|
3892
3924
|
"path": "src/server/responses.ts",
|
|
3893
|
-
"sha256": "
|
|
3925
|
+
"sha256": "35b3f0b37c659a523c63738ffc0367e38fd68f5d974a402b3fd35f039b9a3e87"
|
|
3894
3926
|
},
|
|
3895
3927
|
{
|
|
3896
3928
|
"path": "src/server/responses/agent-task-recovery-cache.ts",
|
|
@@ -3954,7 +3986,7 @@
|
|
|
3954
3986
|
},
|
|
3955
3987
|
{
|
|
3956
3988
|
"path": "src/server/responses/core.ts",
|
|
3957
|
-
"sha256": "
|
|
3989
|
+
"sha256": "dd6612bc2d46dbdc42f41c76bcd341216c4e66a9408fd2485cbb15631781875c"
|
|
3958
3990
|
},
|
|
3959
3991
|
{
|
|
3960
3992
|
"path": "src/server/responses/empty-completion-guard.ts",
|
|
@@ -3962,7 +3994,7 @@
|
|
|
3962
3994
|
},
|
|
3963
3995
|
{
|
|
3964
3996
|
"path": "src/server/responses/encrypted-payload.ts",
|
|
3965
|
-
"sha256": "
|
|
3997
|
+
"sha256": "90cb251bcdd11bbe0e8b63e0d4f59608db329afd23932b301763017f427ba0a2"
|
|
3966
3998
|
},
|
|
3967
3999
|
{
|
|
3968
4000
|
"path": "src/server/responses/fetch-helpers.ts",
|
|
@@ -4254,7 +4286,7 @@
|
|
|
4254
4286
|
},
|
|
4255
4287
|
{
|
|
4256
4288
|
"path": "src/types/provider.ts",
|
|
4257
|
-
"sha256": "
|
|
4289
|
+
"sha256": "be9b34e6587de2341a6a82fca69cead2017ecd3675736ebc6c2e46f70e84e221"
|
|
4258
4290
|
},
|
|
4259
4291
|
{
|
|
4260
4292
|
"path": "src/types/request.ts",
|
|
@@ -4490,7 +4522,7 @@
|
|
|
4490
4522
|
},
|
|
4491
4523
|
{
|
|
4492
4524
|
"path": "src/web-search/index.ts",
|
|
4493
|
-
"sha256": "
|
|
4525
|
+
"sha256": "dcc1d3fef00b97249b3905c34a6f4f7c5319f90db0a670275e95e58c408024dd"
|
|
4494
4526
|
},
|
|
4495
4527
|
{
|
|
4496
4528
|
"path": "src/web-search/loop.ts",
|
|
@@ -4506,12 +4538,16 @@
|
|
|
4506
4538
|
},
|
|
4507
4539
|
{
|
|
4508
4540
|
"path": "src/web-search/passthrough-bridge.ts",
|
|
4509
|
-
"sha256": "
|
|
4541
|
+
"sha256": "82f2c355d6c5b8c4b557a5187aa71fc5b77396c1fe902bc50b79d62c03e9ab71"
|
|
4510
4542
|
},
|
|
4511
4543
|
{
|
|
4512
4544
|
"path": "src/web-search/progress-stream.ts",
|
|
4513
4545
|
"sha256": "0b743935e725b7bdfaf285ba973bb3fcc0faaca6225c8ba3113ce504af328126"
|
|
4514
4546
|
},
|
|
4547
|
+
{
|
|
4548
|
+
"path": "src/web-search/sidecar-providers.ts",
|
|
4549
|
+
"sha256": "ffbc26760250ec95779d0130d18df4d0b3ce45cfbc7a1c12b7f00ba8f1be90a3"
|
|
4550
|
+
},
|
|
4515
4551
|
{
|
|
4516
4552
|
"path": "src/web-search/sources.ts",
|
|
4517
4553
|
"sha256": "1b4d77d514dde268edbc3354192fe9c6edb623f977753506ef89aa77b61d6571"
|
|
@@ -32,6 +32,19 @@ export interface CodexAppServerStateResponse {
|
|
|
32
32
|
runningCount: number;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* The desktop half of a restart. Scalar-only for the same reason as the rest of this
|
|
37
|
+
* contract: pid lists and a closed-vocabulary reason, never a command line or an OS
|
|
38
|
+
* error message, both of which routinely embed a path or a username.
|
|
39
|
+
*/
|
|
40
|
+
export interface CodexDesktopRestartSummary {
|
|
41
|
+
attempted: boolean;
|
|
42
|
+
stopped: number[];
|
|
43
|
+
surviving: number[];
|
|
44
|
+
relaunch: "started" | "skipped";
|
|
45
|
+
reason?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
/** POST response. All four arrays are pid lists — never command lines. */
|
|
36
49
|
export interface CodexRestartResponse {
|
|
37
50
|
success: boolean;
|
|
@@ -44,6 +57,12 @@ export interface CodexRestartResponse {
|
|
|
44
57
|
surviving: number[];
|
|
45
58
|
failed: number[];
|
|
46
59
|
code: CodexRestartCode;
|
|
60
|
+
/**
|
|
61
|
+
* Absent on a proxy older than this change, which is why it is optional rather than
|
|
62
|
+
* required: this guard is a version-skew check the GUI runs, and a dashboard talking
|
|
63
|
+
* to an older proxy has to keep working.
|
|
64
|
+
*/
|
|
65
|
+
desktopApp?: CodexDesktopRestartSummary;
|
|
47
66
|
}
|
|
48
67
|
|
|
49
68
|
const APP_SERVER_STATES: readonly string[] = ["fresh", "stale", "not_running", "unknown"];
|
|
@@ -103,6 +122,18 @@ export function isCodexRestartResponse(value: unknown): value is CodexRestartRes
|
|
|
103
122
|
if ((code === "nothing_running" || code === "enumeration_unavailable") && stopped.length > 0) {
|
|
104
123
|
return false;
|
|
105
124
|
}
|
|
125
|
+
if ("desktopApp" in view && view.desktopApp !== undefined) {
|
|
126
|
+
const desktop = view.desktopApp;
|
|
127
|
+
if (typeof desktop !== "object" || desktop === null) return false;
|
|
128
|
+
const d = desktop as Record<string, unknown>;
|
|
129
|
+
if (typeof d.attempted !== "boolean") return false;
|
|
130
|
+
if (!isPidList(d.stopped) || !isPidList(d.surviving)) return false;
|
|
131
|
+
if (d.relaunch !== "started" && d.relaunch !== "skipped") return false;
|
|
132
|
+
if (d.reason !== undefined && typeof d.reason !== "string") return false;
|
|
133
|
+
// A started relaunch cannot have left anything behind: the ladder refuses to
|
|
134
|
+
// relaunch beside a survivor precisely so a second shell never appears.
|
|
135
|
+
if (d.relaunch === "started" && (d.surviving as number[]).length > 0) return false;
|
|
136
|
+
}
|
|
106
137
|
return true;
|
|
107
138
|
}
|
|
108
139
|
|
|
@@ -683,10 +683,9 @@ const DEEPSEEK_V4_LEGACY_MODELS = ["deepseek-v4-flash"];
|
|
|
683
683
|
const DEEPSEEK_NATIVE_THINKING_MODELS = ["deepseek-flash", "deepseek-v4-flash"];
|
|
684
684
|
const DEEPSEEK_GATEWAY_THINKING_MODELS = ["deepseek-v4.1-flash", "deepseek-v4-flash"];
|
|
685
685
|
/*
|
|
686
|
-
* DeepSeek's
|
|
687
|
-
*
|
|
688
|
-
*
|
|
689
|
-
* at which point this id retires the same way deepseek-chat/reasoner did.
|
|
686
|
+
* DeepSeek's legacy vision preview id (released 2026-08-21). First-party probes
|
|
687
|
+
* in #4436 resolve it to image-capable `deepseek-flash`; retain the existing
|
|
688
|
+
* declarations because gateway support is specific to each served identifier.
|
|
690
689
|
*/
|
|
691
690
|
const DEEPSEEK_VISION_PREVIEW_MODEL = "deepseek-v4-flash-vision-exp";
|
|
692
691
|
/**
|
|
@@ -2165,9 +2164,8 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
2165
2164
|
// the list only as compatibility aliases so existing saved configs and requests
|
|
2166
2165
|
// keep validating and routing (they previously mapped to v4-flash; devlog
|
|
2167
2166
|
// _fin/260710_provider_hardening/002_research_cn.md). The current offerings are
|
|
2168
|
-
//
|
|
2169
|
-
//
|
|
2170
|
-
// expected to merge into deepseek-v4-flash later; see DEEPSEEK_VISION_PREVIEW_MODEL.
|
|
2167
|
+
// V4.1-Flash — defaultModel and the model-specific wiring below use its live id.
|
|
2168
|
+
// Keep the legacy vision-preview alias; see DEEPSEEK_VISION_PREVIEW_MODEL.
|
|
2171
2169
|
models: ["deepseek-chat", "deepseek-reasoner", ...DEEPSEEK_NATIVE_THINKING_MODELS, DEEPSEEK_VISION_PREVIEW_MODEL],
|
|
2172
2170
|
// V4.1-Flash is the current first-party offering; `deepseek-v4-flash` now routes there
|
|
2173
2171
|
// as a compatibility alias, so a new install should ask for the live id by name.
|
|
@@ -2175,7 +2173,10 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
2175
2173
|
// Official DeepSeek Codex setup (codex-deepseek-setup.sh) advertises 1,048,576
|
|
2176
2174
|
// for both V4 models; the older 1,000,000 figure was a rounded approximation.
|
|
2177
2175
|
modelContextWindows: { "deepseek-flash": 1_048_576, "deepseek-v4-flash": 1_048_576, [DEEPSEEK_VISION_PREVIEW_MODEL]: 1_048_576 },
|
|
2178
|
-
modelInputModalities: {
|
|
2176
|
+
modelInputModalities: {
|
|
2177
|
+
"deepseek-flash": ["text", "image"],
|
|
2178
|
+
[DEEPSEEK_VISION_PREVIEW_MODEL]: ["text", "image"],
|
|
2179
|
+
},
|
|
2179
2180
|
// DeepSeek documents both V4 models as native Responses API models adapted for Codex
|
|
2180
2181
|
// (model table marks Responses API ✓ for flash and pro; the /responses reference lists
|
|
2181
2182
|
// both ids as accepted `model` values — verified 2026-08-13 with the V4 Pro GA,
|
|
@@ -2245,10 +2246,10 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
|
2245
2246
|
modelReasoningEffortMap: Object.fromEntries(DEEPSEEK_NATIVE_THINKING_MODELS.map(id => [id, deepseekReasoningMapFor(id)])),
|
|
2246
2247
|
modelSupportsReasoningSummaries: Object.fromEntries(DEEPSEEK_NATIVE_THINKING_MODELS.map(id => [id, true])),
|
|
2247
2248
|
preserveReasoningContentModels: DEEPSEEK_NATIVE_THINKING_MODELS,
|
|
2248
|
-
//
|
|
2249
|
-
//
|
|
2250
|
-
//
|
|
2251
|
-
noVisionModels: ["deepseek-chat", "deepseek-reasoner",
|
|
2249
|
+
// #4436: first-party deepseek-flash accepts native images on Chat and Responses.
|
|
2250
|
+
// Keep unprobed compatibility aliases on the #88 sidecar path. This must be fixed
|
|
2251
|
+
// here: router enrichment unions this list with saved config, so config cannot remove it.
|
|
2252
|
+
noVisionModels: ["deepseek-chat", "deepseek-reasoner", "deepseek-v4-flash"],
|
|
2252
2253
|
},
|
|
2253
2254
|
// llama-3.3-70b was deprecated by Cerebras on 2026-02-16. Evidence: devlog/_plan/260710_provider_hardening/003_research_aggregators.md.
|
|
2254
2255
|
{ id: "cerebras", label: "Cerebras", baseUrl: "https://api.cerebras.ai/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://cloud.cerebras.ai/platform/apikeys", defaultModel: "gpt-oss-120b" },
|