@yansigit/opencodex 2.31.2 → 2.32.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/bin/ocx.mjs +99 -70
- package/gui/dist/assets/index-BG43zwVe.js +102 -0
- package/gui/dist/assets/index-CiSI-jrP.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/anthropic.ts +6 -8
- package/src/adapters/base.ts +2 -0
- package/src/adapters/command-code-project-context.ts +377 -0
- package/src/adapters/command-code.ts +7 -4
- package/src/adapters/cursor/live-models.ts +8 -0
- package/src/adapters/cursor/live-transport.ts +21 -0
- package/src/adapters/cursor/native-exec-bridge.ts +141 -0
- package/src/adapters/cursor/native-exec-desktop.ts +16 -0
- package/src/adapters/cursor/tool-definitions.ts +1 -1
- package/src/adapters/google-http.ts +12 -2
- package/src/adapters/google-wire-compiler.ts +83 -2
- package/src/adapters/google.ts +62 -21
- package/src/adapters/kiro.ts +0 -3
- package/src/adapters/openai-responses.ts +3 -0
- package/src/adapters/tool-catalog-nudge.ts +1 -1
- package/src/adapters/xai-web-search.ts +7 -2
- package/src/bridge.ts +21 -15
- package/src/cli/dispatch.ts +50 -2
- package/src/cli/doctor.ts +24 -11
- package/src/cli/help.ts +4 -3
- package/src/cli/index.ts +11 -4
- package/src/cli/models.ts +13 -3
- package/src/cli/observe.ts +20 -5
- package/src/cli/provider.ts +2 -1
- package/src/cli/registry.ts +7 -5
- package/src/cli/status.ts +2 -1
- package/src/cli/system-restart-client.ts +1 -1
- package/src/cli/usage-report.ts +134 -0
- package/src/codex/app-server-processes.ts +3 -1
- package/src/codex/catalog/aggregation.ts +13 -1
- package/src/codex/catalog/effort.ts +24 -9
- package/src/codex/catalog/model-metadata.ts +566 -0
- package/src/codex/catalog/parsing.ts +33 -0
- package/src/codex/catalog/provider-fetch.ts +123 -32
- package/src/codex/catalog/sync.ts +5 -4
- package/src/codex/desktop-app-restart.ts +342 -0
- package/src/codex/history-job.ts +32 -3
- package/src/codex/history-manifest.ts +112 -0
- package/src/codex/history-migration-guardian.ts +5 -5
- package/src/codex/history-provider.ts +825 -247
- package/src/codex/history-worker.ts +8 -5
- package/src/codex/inject.ts +49 -21
- package/src/codex/injected-marker.ts +1 -1
- package/src/codex/internal/history-writer.ts +4 -3
- package/src/codex/native-profile-startup.ts +157 -27
- package/src/codex/native-residue.ts +26 -33
- package/src/combos/failover.ts +27 -0
- package/src/compatibility/index.ts +26 -0
- package/src/compatibility/manifest.ts +253 -0
- package/src/compatibility/openai-responses.ts +81 -0
- package/src/config/atomic-write.ts +219 -0
- package/src/config/paths.ts +40 -0
- package/src/config/process-state.ts +308 -0
- package/src/config/provider-validation.ts +177 -0
- package/src/config.ts +77 -812
- package/src/generated/compatibility-version.json +162 -94
- package/src/images/plan.ts +5 -4
- package/src/integrations/ownership-policy.ts +141 -0
- package/src/integrations/ownership.ts +10 -0
- package/src/integrations/state.ts +44 -5
- package/src/integrations/writer.ts +6 -0
- package/src/lab/subject/behavior-fingerprint.ts +1 -1
- package/src/lib/bounded-body.ts +14 -2
- package/src/lib/process-control.ts +2 -1
- package/src/lib/state-store-registrations.ts +2 -0
- package/src/lib/tool-argument-integers.ts +56 -5
- package/src/oauth/health.ts +1 -1
- package/src/oauth/index.ts +3 -0
- package/src/providers/registry.ts +1 -1
- package/src/reasoning-effort.ts +19 -2
- package/src/responses/apply-patch-envelope.ts +63 -0
- package/src/responses/custom-tool-compat.ts +132 -38
- package/src/responses/parser.ts +3 -2
- package/src/responses/reasoning-replay-cache.ts +81 -3
- package/src/routing/compatibility/behavior.ts +3 -0
- package/src/server/auth-cors.ts +9 -7
- package/src/server/index.ts +102 -21
- package/src/server/local-management-read-client.ts +1 -1
- package/src/server/local-provider-reload-client.ts +1 -1
- package/src/server/management/agent-settings-routes.ts +1 -1
- package/src/server/management/config-routes.ts +4 -1
- package/src/server/management/context.ts +1 -1
- package/src/server/management/logs-usage-routes.ts +27 -6
- package/src/server/management/model-routes.ts +8 -4
- package/src/server/management/native-integration-routes.ts +2 -1
- package/src/server/management/provider-capability-config.ts +1 -1
- package/src/server/management/system-restart.ts +1 -1
- package/src/server/port-reclaim.ts +1 -1
- package/src/server/proxy-liveness.ts +2 -1
- package/src/server/request-log-conversation.ts +30 -0
- package/src/server/responses/codex-auth-error.ts +55 -0
- package/src/server/responses/combo-stream-preflight.ts +171 -0
- package/src/server/responses/compact.ts +6 -21
- package/src/server/responses/core.ts +242 -101
- package/src/server/responses/fetch-helpers.ts +2 -97
- package/src/server/responses-custom-tool-repair.ts +41 -5
- package/src/server/responses-undeclared-tool-guard.ts +156 -15
- package/src/service.ts +8 -4
- package/src/types/provider.ts +7 -0
- package/src/types/request.ts +12 -1
- package/src/types/tools.ts +87 -11
- package/src/types.ts +1 -1
- package/src/update/index.ts +5 -4
- package/src/update/job.ts +3 -1
- package/src/update/transactional-install.mjs +8 -1
- package/src/usage/log.ts +16 -8
- package/src/usage/summary.ts +201 -8
- package/src/vision/describe.ts +18 -13
- package/src/web-search/executor.ts +10 -3
- package/src/web-search/gemini-executor.ts +35 -13
- package/src/web-search/index.ts +85 -1
- package/gui/dist/assets/index-BAMgarF9.js +0 -102
- package/gui/dist/assets/index-CGoDO3uO.css +0 -1
package/src/codex/history-job.ts
CHANGED
|
@@ -109,7 +109,8 @@ export type CodexHistoryJobOutcome =
|
|
|
109
109
|
| { readonly kind: "skipped" }
|
|
110
110
|
| { readonly kind: "blocked"; readonly reason: "busy" | "database" | "unsafe-path" | "desired_disabled" | "desired_enabled" }
|
|
111
111
|
| { readonly kind: "failed"; readonly reason: "worker-error" | "worker-died" | "timeout";
|
|
112
|
-
readonly message: string; readonly historyFailureReason?: CodexHistoryFailureReason
|
|
112
|
+
readonly message: string; readonly historyFailureReason?: CodexHistoryFailureReason;
|
|
113
|
+
readonly rows?: number; readonly files?: number };
|
|
113
114
|
|
|
114
115
|
/**
|
|
115
116
|
* Derive the durable history operation from admitted intent.
|
|
@@ -174,7 +175,14 @@ function isPlausibleWorkerResult(
|
|
|
174
175
|
|| message.reason === "desired_disabled" || message.reason === "desired_enabled";
|
|
175
176
|
case "error":
|
|
176
177
|
return typeof message.message === "string"
|
|
177
|
-
&& (message.
|
|
178
|
+
&& (message.rows === undefined || (Number.isSafeInteger(message.rows) && Number(message.rows) >= 0))
|
|
179
|
+
&& (message.files === undefined || (Number.isSafeInteger(message.files) && Number(message.files) >= 0))
|
|
180
|
+
&& ((message.rows === undefined && message.files === undefined)
|
|
181
|
+
|| (message.rows !== undefined && message.files !== undefined))
|
|
182
|
+
&& (message.reason === undefined
|
|
183
|
+
|| message.reason === "busy"
|
|
184
|
+
|| message.reason === "permission"
|
|
185
|
+
|| message.reason === "integrity");
|
|
178
186
|
default:
|
|
179
187
|
return false;
|
|
180
188
|
}
|
|
@@ -224,6 +232,7 @@ export function describeHistoryJobFailure(
|
|
|
224
232
|
: surface === "recover-legacy"
|
|
225
233
|
? "the Codex history DB is locked (Codex app/IDE open?). Close it and rerun this command."
|
|
226
234
|
: "the Codex app appears to be holding the history database. Close Codex and run `ocx restore` again.";
|
|
235
|
+
const busyStateText = "Codex history state is busy (database, backup manifest, or rollout file); this is not enough evidence to blame the Codex app. It is retried automatically while the proxy runs; run 'ocx doctor' before forcing another attempt.";
|
|
227
236
|
if (outcome.kind === "blocked") {
|
|
228
237
|
if (outcome.reason === "busy") return busyText;
|
|
229
238
|
switch (outcome.reason) {
|
|
@@ -237,10 +246,22 @@ export function describeHistoryJobFailure(
|
|
|
237
246
|
return "Codex integration is enabled, so the history operation was skipped.";
|
|
238
247
|
}
|
|
239
248
|
}
|
|
240
|
-
|
|
249
|
+
const partiallyChanged = (outcome.rows ?? 0) > 0 || (outcome.files ?? 0) > 0;
|
|
250
|
+
if (partiallyChanged && outcome.historyFailureReason === "busy") {
|
|
251
|
+
return "Codex history metadata changed but did not converge because manifest finalization remained busy; the manifest was retained for review and safe retry. Run 'ocx doctor'.";
|
|
252
|
+
}
|
|
253
|
+
if (partiallyChanged && outcome.historyFailureReason === "permission") {
|
|
254
|
+
return "Codex history metadata changed but did not converge because permission was denied while finalizing the manifest; the manifest was retained for review and safe retry. Run 'ocx doctor'.";
|
|
255
|
+
}
|
|
256
|
+
if (outcome.historyFailureReason === "busy") return busyStateText;
|
|
241
257
|
if (outcome.historyFailureReason === "permission") {
|
|
242
258
|
return "permission was denied while writing Codex history; this is not a Codex app lock. Run 'ocx doctor'.";
|
|
243
259
|
}
|
|
260
|
+
if (outcome.historyFailureReason === "integrity") {
|
|
261
|
+
return partiallyChanged
|
|
262
|
+
? "the history backup or its restore target changed after a partial restore; the manifest was retained for review and safe retry. Run 'ocx doctor'."
|
|
263
|
+
: "the history backup or its restore target failed integrity checks; no unverified provider metadata was applied. Run 'ocx doctor'.";
|
|
264
|
+
}
|
|
244
265
|
switch (outcome.reason) {
|
|
245
266
|
case "worker-error":
|
|
246
267
|
return `the history worker failed (${outcome.message}). Run 'ocx doctor'.`;
|
|
@@ -277,6 +298,9 @@ function classifyWorkerResult(result: HistoryWorkerResult): CodexHistoryJobOutco
|
|
|
277
298
|
reason: "worker-error",
|
|
278
299
|
message: redactWorkerMessage(result.message),
|
|
279
300
|
...(result.reason ? { historyFailureReason: result.reason } : {}),
|
|
301
|
+
...(result.rows !== undefined && result.files !== undefined
|
|
302
|
+
? { rows: result.rows, files: result.files }
|
|
303
|
+
: {}),
|
|
280
304
|
};
|
|
281
305
|
}
|
|
282
306
|
return result.outcome === "skipped"
|
|
@@ -284,6 +308,11 @@ function classifyWorkerResult(result: HistoryWorkerResult): CodexHistoryJobOutco
|
|
|
284
308
|
: { kind: "converged", rows: result.rows, files: result.files, ...(result.proof ? { proof: result.proof } : {}) };
|
|
285
309
|
}
|
|
286
310
|
|
|
311
|
+
/** Test seam for the parent-side Worker result classification contract. */
|
|
312
|
+
export function classifyWorkerResultForTests(result: HistoryWorkerResult): CodexHistoryJobOutcome {
|
|
313
|
+
return classifyWorkerResult(result);
|
|
314
|
+
}
|
|
315
|
+
|
|
287
316
|
/**
|
|
288
317
|
* Run one history unit in a Worker and join it before returning.
|
|
289
318
|
*
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { isAbsolute, resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
/** Sources whose native OpenAI provenance can be restored exactly. */
|
|
5
|
+
export const CODEX_HISTORY_RESUMABLE_SOURCES = ["cli", "vscode"] as const;
|
|
6
|
+
|
|
7
|
+
export interface CodexHistoryBackupEntry {
|
|
8
|
+
id: string;
|
|
9
|
+
rolloutPath: string;
|
|
10
|
+
modelProvider: string;
|
|
11
|
+
source: string;
|
|
12
|
+
hasUserEvent: 0 | 1;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface CodexHistoryBackupManifest {
|
|
16
|
+
version: 1;
|
|
17
|
+
stateDbPath: string;
|
|
18
|
+
entries: Record<string, CodexHistoryBackupEntry>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type CodexHistoryManifestValidation =
|
|
22
|
+
| { readonly ok: true; readonly manifest: CodexHistoryBackupManifest }
|
|
23
|
+
| { readonly ok: false; readonly reason: "foreign-database" }
|
|
24
|
+
| {
|
|
25
|
+
readonly ok: false;
|
|
26
|
+
readonly reason: "schema";
|
|
27
|
+
readonly scope: "manifest" | "entry-shape" | "entry-provenance";
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function codexHistoryPathIdentity(path: string): string {
|
|
31
|
+
const canonical = resolve(path);
|
|
32
|
+
return process.platform === "win32" ? canonical.toLowerCase() : canonical;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Canonical identity used by both backup naming and manifest ownership checks.
|
|
37
|
+
* Windows paths are case-insensitive for this contract; other platforms keep
|
|
38
|
+
* the resolved path's case.
|
|
39
|
+
*/
|
|
40
|
+
export function codexHistoryStateDbIdentity(path: string): string {
|
|
41
|
+
return codexHistoryPathIdentity(path);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Stable, non-secret file-name component for one state database. */
|
|
45
|
+
export function codexHistoryBackupId(stateDbPath: string): string {
|
|
46
|
+
return createHash("sha256")
|
|
47
|
+
.update(codexHistoryStateDbIdentity(stateDbPath))
|
|
48
|
+
.digest("hex")
|
|
49
|
+
.slice(0, 16);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Platform-aware identity comparison shared by database and rollout checks. */
|
|
53
|
+
export function sameCodexHistoryPath(left: string, right: string): boolean {
|
|
54
|
+
return codexHistoryPathIdentity(left) === codexHistoryPathIdentity(right);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
58
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function hasAllowedProvenance(entry: Record<string, unknown>): boolean {
|
|
62
|
+
return (entry.modelProvider === "openai"
|
|
63
|
+
&& CODEX_HISTORY_RESUMABLE_SOURCES.includes(
|
|
64
|
+
entry.source as (typeof CODEX_HISTORY_RESUMABLE_SOURCES)[number],
|
|
65
|
+
))
|
|
66
|
+
|| (entry.modelProvider === "opencodex" && entry.source === "exec");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Validate only the versioned data contract and database ownership identity.
|
|
71
|
+
* Filesystem type checks, reads, fingerprints, rollout inspection, SQLite, and
|
|
72
|
+
* mutation deliberately remain with the callers.
|
|
73
|
+
*/
|
|
74
|
+
export function validateCodexHistoryBackupManifest(
|
|
75
|
+
raw: unknown,
|
|
76
|
+
expectedStateDbPath: string,
|
|
77
|
+
): CodexHistoryManifestValidation {
|
|
78
|
+
if (!isRecord(raw)
|
|
79
|
+
|| raw.version !== 1
|
|
80
|
+
|| typeof raw.stateDbPath !== "string"
|
|
81
|
+
|| !raw.stateDbPath.trim()
|
|
82
|
+
|| !isAbsolute(raw.stateDbPath)
|
|
83
|
+
|| !isRecord(raw.entries)) {
|
|
84
|
+
return { ok: false, reason: "schema", scope: "manifest" };
|
|
85
|
+
}
|
|
86
|
+
if (!sameCodexHistoryPath(raw.stateDbPath, expectedStateDbPath)) {
|
|
87
|
+
return { ok: false, reason: "foreign-database" };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
for (const [id, value] of Object.entries(raw.entries)) {
|
|
91
|
+
if (!isRecord(value)) {
|
|
92
|
+
return { ok: false, reason: "schema", scope: "entry-shape" };
|
|
93
|
+
}
|
|
94
|
+
if (!id
|
|
95
|
+
|| value.id !== id
|
|
96
|
+
|| typeof value.rolloutPath !== "string"
|
|
97
|
+
|| !value.rolloutPath.trim()
|
|
98
|
+
|| !isAbsolute(value.rolloutPath)
|
|
99
|
+
|| typeof value.modelProvider !== "string"
|
|
100
|
+
|| !value.modelProvider.trim()
|
|
101
|
+
|| typeof value.source !== "string"
|
|
102
|
+
|| !value.source.trim()
|
|
103
|
+
|| typeof value.hasUserEvent !== "number"
|
|
104
|
+
|| !Number.isSafeInteger(value.hasUserEvent)
|
|
105
|
+
|| (value.hasUserEvent !== 0 && value.hasUserEvent !== 1)
|
|
106
|
+
|| !hasAllowedProvenance(value)) {
|
|
107
|
+
return { ok: false, reason: "schema", scope: "entry-provenance" };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return { ok: true, manifest: raw as unknown as CodexHistoryBackupManifest };
|
|
112
|
+
}
|
|
@@ -2,11 +2,11 @@ import { migrateHistoryToOpenai } from "./history-provider";
|
|
|
2
2
|
import { resolveCodexHistoryJobTarget, runCodexHistoryJob } from "./history-job";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Daemon-side retry for the one-time Design-B history
|
|
5
|
+
* Daemon-side retry for the one-time Design-B history metadata restoration.
|
|
6
6
|
*
|
|
7
7
|
* Most upgrades run `ocx start` while the Codex app still holds `state_5.sqlite`,
|
|
8
|
-
* so the inject-time
|
|
9
|
-
*
|
|
8
|
+
* so the inject-time restore can fail on the FIRST start while manifest-backed original
|
|
9
|
+
* metadata is still pending. Instead
|
|
10
10
|
* of asking the user to close the app and rerun start, this guardian keeps retrying
|
|
11
11
|
* in the background until the migration lands.
|
|
12
12
|
*
|
|
@@ -77,7 +77,7 @@ export function startHistoryMigrationGuardian(deps: HistoryMigrationGuardianDeps
|
|
|
77
77
|
if (!result.failed) {
|
|
78
78
|
const moved = result.rows + ((result as { ejectedRows?: number }).ejectedRows ?? 0);
|
|
79
79
|
if (moved > 0) {
|
|
80
|
-
log.log(`🩹 history-migration: ${moved}
|
|
80
|
+
log.log(`🩹 history-migration: restored original provider metadata for ${moved} manifest-backed thread(s).`);
|
|
81
81
|
}
|
|
82
82
|
// Zero mutations are authoritative only when the worker verified the
|
|
83
83
|
// exact DB/manifest state while H was held.
|
|
@@ -92,7 +92,7 @@ export function startHistoryMigrationGuardian(deps: HistoryMigrationGuardianDeps
|
|
|
92
92
|
}
|
|
93
93
|
if (ticks >= maxTicks) {
|
|
94
94
|
stopped = true;
|
|
95
|
-
log.log("⚠️ history-migration: Could not verify that
|
|
95
|
+
log.log("⚠️ history-migration: Could not verify that backed-up provider metadata was restored; the history database may be busy, unavailable, or not yet ready. Run 'ocx sync' (or check 'ocx doctor').");
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
98
|
schedule();
|