@openclaw/codex 2026.9.1-beta.1 → 2026.9.2
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/dist/api.js +8 -9
- package/dist/{attempt-client-cleanup-bfsmcQ6m.js → attempt-client-cleanup-Bp1ZOnk2.js} +105 -75
- package/dist/attempt-context-CSazkWns.js +634 -0
- package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
- package/dist/{bounded-turn-B7iBUcuP.js → bounded-turn-DxGJRYbY.js} +53 -57
- package/dist/{capabilities-BRMh0aIq.js → capabilities-B1mgvpP8.js} +2 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-DEsIufkt.js → command-formatters-DSbGMXA0.js} +5 -4
- package/dist/{command-handlers-D_-1_qRp.js → command-handlers-DOJvGv6-.js} +243 -148
- package/dist/{compact-BglNFZrQ.js → compact-Y_xBqrHN.js} +109 -65
- package/dist/{config-giW8X0QA.js → config-CyapYSji.js} +328 -374
- package/dist/config-utils-C57JiJrU.js +69 -0
- package/dist/{context-compaction-activity-BOeJf7yo.js → context-compaction-activity-CMla5FPJ.js} +4 -1
- package/dist/{conversation-binding-data-CW2GuupV.js → conversation-binding-data-BiodpIzq.js} +2 -1
- package/dist/doctor-contract-api.js +144 -14
- package/dist/{dynamic-tools-Dnlfa--w.js → dynamic-tools-BwpvTxaX.js} +1119 -1135
- package/dist/{effective-mcp-catalog-CTeGrnfO.js → effective-mcp-catalog-CY9Jn4bA.js} +4 -3
- package/dist/{event-projector-assistant-message-C5-Ds8mA.js → event-projector-assistant-message-B9kp6iGC.js} +15 -6
- package/dist/event-projector-usage-ZqEVbAEY.js +212 -0
- package/dist/{harness-Csz0F-DK.js → harness-Czh2Sdoc.js} +65 -52
- package/dist/harness.js +1 -1
- package/dist/{image-payload-sanitizer-CnfoUPCE.js → image-payload-sanitizer-tupAr-2o.js} +29 -15
- package/dist/index.js +495 -457
- package/dist/{isolated-completion-Cv6FqygM.js → isolated-completion-CRh-51AK.js} +9 -21
- package/dist/{managed-binary-DFYK4DWq.js → managed-binary-DcpnJF9x.js} +117 -80
- package/dist/media-understanding-provider.js +1 -1
- package/dist/model-catalog-DT5vo6qo.js +101 -0
- package/dist/{models-TS3HBU-q.js → models-CcrgSMQR.js} +26 -29
- package/dist/{native-subagent-monitor-4Mfq2HDs.js → native-subagent-monitor-B3bvQGcg.js} +63 -122
- package/dist/{node-exec-server.runtime-BpWqJO1V.js → node-exec-server.runtime-nfbUOtUB.js} +10 -7
- package/dist/{plugin-approval-roundtrip-bUm777tR.js → plugin-approval-roundtrip-aQVdyL5g.js} +30 -3
- package/dist/{plugin-marketplace-discovery-B9DvaAG-.js → plugin-marketplace-discovery-B7gHXJ3d.js} +44 -30
- package/dist/{plugin-metadata-cache-CTCT3w5L.js → plugin-metadata-cache-BwCLTY_U.js} +6 -6
- package/dist/provider-capabilities-BpG9Ltc5.js +101 -0
- package/dist/{rate-limits-C5_D8Gmb.js → rate-limits-Fx_l4eNa.js} +3 -2
- package/dist/{sandbox-guard-kuWTn9C5.js → request-C8H22rPi.js} +195 -2
- package/dist/{run-attempt-DYc0QCBF.js → run-attempt-BzthFQSM.js} +1616 -2634
- package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-Bh_gf6-t.js} +22 -15
- package/dist/{session-binding-Bcynfd-_.js → session-binding-4Ki04sW-.js} +282 -399
- package/dist/session-binding-record-CyaXZvTe.js +270 -0
- package/dist/{session-catalog-DaLKVtpH.js → session-catalog-B47uwekb.js} +812 -504
- package/dist/{session-cli-DMc4oS2w.js → session-cli-BjLhpmS1.js} +1 -1
- package/dist/session-history-DWmMqiqW.js +93 -0
- package/dist/session-history-read-LHldwvyh.js +36 -0
- package/dist/session-history-worker-runtime.js +48 -0
- package/dist/session-history.worker-zZVcx0ME.js +267 -0
- package/dist/session-history.worker.js +2 -0
- package/dist/session-initialization-BCFVnLL4.js +75 -0
- package/dist/{session-permission-policy-BrNH1bjy.js → session-permission-policy-BaueHmSj.js} +2 -2
- package/dist/session-retirement-DNdmYdFc.js +97 -0
- package/dist/{session-upstream-marker-BIkusb95.js → session-upstream-marker-DReTpGz6.js} +20 -4
- package/dist/settled-turn-context-BOM3Y1pl.js +45 -0
- package/dist/settled-turn-finalizer-BI-b1sry.js +115 -0
- package/dist/{shared-client-DKz23hHY.js → shared-client-CKhX2kFt.js} +3659 -847
- package/dist/{side-question-DjA_jsNe.js → side-question-B6DWAw1A.js} +168 -81
- package/dist/{thread-lifecycle-L7oEkTlq.js → thread-lifecycle-DPK30jad.js} +2412 -2145
- package/dist/{thread-ownership-DZeuKH1j.js → thread-ownership-CbucAmmp.js} +27 -16
- package/dist/thread-policy-CTalhWFy.js +105 -0
- package/dist/{plugin-app-cache-key-C1CAdfcP.js → thread-resume-BLgqkUc1.js} +61 -9
- package/dist/{transcript-mirror-DsCMWBca.js → transcript-mirror-_njEB84z.js} +114 -110
- package/dist/transcript-mirror-attestation-Byl34PC-.js +76 -0
- package/dist/transport-stdio-CzTngV0j.js +728 -0
- package/dist/{upstream-prompt-provenance-CFmsKwr9.js → upstream-prompt-provenance-LphB8slG.js} +8 -4
- package/dist/upstream-session-fork-1fwbNKzQ.js +886 -0
- package/dist/{usage-ROIaW3wo.js → usage-i9fv5-4m.js} +3 -3
- package/dist/{web-search-provider.runtime-ClaNPV7N.js → web-search-provider.runtime-DKQn67A7.js} +3 -3
- package/openclaw.plugin.json +1 -30
- package/package.json +6 -6
- package/dist/binding-connection-BMvPX73o.js +0 -45
- package/dist/command-rpc-CCeCkf_v.js +0 -90
- package/dist/event-projector-usage-Bk1I90Bg.js +0 -328
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/model-catalog-i9rNBthX.js +0 -48
- package/dist/protocol-validators-VeJxxJ0U.js +0 -2421
- package/dist/request-DXXGHko0.js +0 -157
- package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
- package/dist/session-retirement-CcNC3YSY.js +0 -36
- package/dist/settled-turn-finalizer-Dc3ApjU4.js +0 -328
- package/dist/thread-resume-BE9qNEW0.js +0 -30
- package/dist/transport-stdio-DhoGy33Z.js +0 -99
- package/dist/upstream-session-fork-DlaHxSLC.js +0 -326
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
|
-
import {
|
|
2
|
+
import { g as CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN } from "./config-utils-C57JiJrU.js";
|
|
3
|
+
import { a as readCodexBindingTimestamp, c as readStoredCodexAppServerBinding, d as validateBindingForWrite, i as readCodexBindingSessionEntry, l as sessionBindingIdentity, n as ownsStoredSessionGeneration, o as readCodexSessionOwnershipBinding, r as readCodexAppServerThreadBinding, s as readCurrentCodexAppServerBinding, t as bindingStoreKey, u as stripUndefinedBinding } from "./session-binding-record-CyaXZvTe.js";
|
|
3
4
|
import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./session-binding-meta-B7aEMU7g.js";
|
|
4
5
|
import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
|
-
import { AgentHarnessSessionSupersededError, embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
6
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { AgentHarnessPreflightError, AgentHarnessSessionSupersededError, embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
8
|
+
import { isDeepStrictEqual } from "node:util";
|
|
9
|
+
import { ensureAuthProfileStore, resolveDefaultAgentDir, resolveProviderIdForAuth } from "openclaw/plugin-sdk/agent-runtime";
|
|
9
10
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
|
-
import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
11
11
|
//#region extensions/codex/src/app-server/session-binding.ts
|
|
12
12
|
/** SQLite-backed Codex app-server thread bindings. */
|
|
13
13
|
var session_binding_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -28,8 +28,10 @@ var session_binding_exports = /* @__PURE__ */ __exportAll({
|
|
|
28
28
|
readStoredCodexAppServerBinding: () => readStoredCodexAppServerBinding,
|
|
29
29
|
reclaimCurrentCodexSessionGeneration: () => reclaimCurrentCodexSessionGeneration,
|
|
30
30
|
resolveCodexRunSessionBindingAuthority: () => resolveCodexRunSessionBindingAuthority,
|
|
31
|
+
resolveCodexSessionBinding: () => resolveCodexSessionBinding,
|
|
31
32
|
scopeCodexRunBindingStore: () => scopeCodexRunBindingStore,
|
|
32
|
-
sessionBindingIdentity: () => sessionBindingIdentity
|
|
33
|
+
sessionBindingIdentity: () => sessionBindingIdentity,
|
|
34
|
+
validateBindingForWrite: () => validateBindingForWrite
|
|
33
35
|
});
|
|
34
36
|
const CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER = "openai";
|
|
35
37
|
const PUBLIC_OPENAI_MODEL_PROVIDER = "openai";
|
|
@@ -40,220 +42,52 @@ const BINDING_LEASE_STALE_MS = 65e3;
|
|
|
40
42
|
const BINDING_LEASE_WAIT_MS = 7e4;
|
|
41
43
|
const BINDING_LEASE_RENEW_INTERVAL_MS = Math.floor(BINDING_LEASE_STALE_MS / 3);
|
|
42
44
|
const PHYSICAL_SESSION_RETIRE_TTL_MS = BINDING_LEASE_WAIT_MS;
|
|
43
|
-
/** Resolves the same agent scope OpenClaw uses for transcript/session ownership. */
|
|
44
|
-
function sessionBindingIdentity(params) {
|
|
45
|
-
const { sessionAgentId } = resolveSessionAgentIds$1(params);
|
|
46
|
-
const sessionKey = params.sessionKey?.trim();
|
|
47
|
-
return {
|
|
48
|
-
kind: "session",
|
|
49
|
-
agentId: sessionAgentId,
|
|
50
|
-
sessionId: params.sessionId,
|
|
51
|
-
...sessionKey ? { sessionKey } : {}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
45
|
/** Decides whether a run may share the durable stable-key binding owner. */
|
|
55
46
|
function resolveCodexRunSessionBindingAuthority(params) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
47
|
+
return captureCodexSessionGenerationAuthority(params)[0];
|
|
48
|
+
}
|
|
49
|
+
function captureCodexSessionGenerationAuthority(params, assertCallerCurrent = () => {}) {
|
|
50
|
+
const readEntry = () => {
|
|
51
|
+
try {
|
|
52
|
+
return readCodexBindingSessionEntry(params);
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const entry = readEntry();
|
|
58
|
+
const current = entry?.sessionId === params.identity.sessionId;
|
|
59
|
+
const authority = entry === void 0 ? "ephemeral" : current ? "current" : "superseded";
|
|
60
|
+
const previousSessionId = current ? entry.previousSessionId : void 0;
|
|
61
|
+
const assertHostCurrent = () => {
|
|
62
|
+
if (authority === "ephemeral") return;
|
|
63
|
+
const latest = readEntry();
|
|
64
|
+
if (authority !== "current" || !latest || latest.sessionId !== params.identity.sessionId || latest.previousSessionId !== previousSessionId) throw createCodexSessionGenerationSupersededError(params.identity.sessionId);
|
|
65
|
+
};
|
|
66
|
+
const assertCurrent = () => {
|
|
67
|
+
assertCallerCurrent();
|
|
68
|
+
assertHostCurrent();
|
|
69
|
+
};
|
|
70
|
+
return [
|
|
71
|
+
authority,
|
|
72
|
+
previousSessionId,
|
|
73
|
+
assertHostCurrent,
|
|
74
|
+
assertCurrent
|
|
75
|
+
];
|
|
72
76
|
}
|
|
73
77
|
/** Builds the terminal coordination error used when a newer OpenClaw session owns the binding. */
|
|
74
78
|
function createCodexSessionGenerationSupersededError(sessionId) {
|
|
75
79
|
return new AgentHarnessSessionSupersededError(`Codex session generation is no longer current: ${sessionId}`);
|
|
76
80
|
}
|
|
77
|
-
const optionalStringSchema = z.string().optional().catch(void 0);
|
|
78
|
-
const optionalBooleanSchema = z.boolean().optional().catch(void 0);
|
|
79
|
-
const optionalNonBlankStringSchema = z.string().refine((value) => Boolean(value.trim())).optional().catch(void 0);
|
|
80
|
-
const optionalTimestampSchema = z.string().refine((value) => Number.isFinite(Date.parse(value))).optional().catch(void 0);
|
|
81
|
-
const pendingSupervisionBranchSchema = z.object({
|
|
82
|
-
sourceThreadId: z.string().trim().min(1),
|
|
83
|
-
connectionFingerprint: z.string().trim().min(1).optional(),
|
|
84
|
-
lastTurnId: z.string().trim().min(1).optional(),
|
|
85
|
-
cleanupThreadIds: z.array(z.string().trim().min(1)).max(2).optional()
|
|
86
|
-
}).strict().superRefine((pending, context) => {
|
|
87
|
-
const cleanupThreadIds = pending.cleanupThreadIds ?? [];
|
|
88
|
-
if (new Set(cleanupThreadIds).size !== cleanupThreadIds.length) context.addIssue({
|
|
89
|
-
code: "custom",
|
|
90
|
-
message: "pending supervision cleanup thread ids must be unique"
|
|
91
|
-
});
|
|
92
|
-
if (cleanupThreadIds.includes(pending.sourceThreadId)) context.addIssue({
|
|
93
|
-
code: "custom",
|
|
94
|
-
message: "pending supervision cleanup cannot target its source"
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
const contextEngineProjectionSchema = z.object({
|
|
98
|
-
schemaVersion: z.literal(1),
|
|
99
|
-
mode: z.literal("thread_bootstrap"),
|
|
100
|
-
epoch: z.string().refine((value) => Boolean(value.trim())),
|
|
101
|
-
fingerprint: optionalStringSchema
|
|
102
|
-
}).strict();
|
|
103
|
-
const contextEngineSchema = z.object({
|
|
104
|
-
schemaVersion: z.literal(1),
|
|
105
|
-
engineId: z.string(),
|
|
106
|
-
policyFingerprint: z.string(),
|
|
107
|
-
projection: contextEngineProjectionSchema.optional().catch(void 0)
|
|
108
|
-
}).strict();
|
|
109
|
-
const destructiveApprovalModeSchema = z.enum([
|
|
110
|
-
"allow",
|
|
111
|
-
"deny",
|
|
112
|
-
"auto",
|
|
113
|
-
"ask"
|
|
114
|
-
]).optional().catch(void 0);
|
|
115
|
-
const accountAppPolicyEntrySchema = z.object({
|
|
116
|
-
source: z.literal("account"),
|
|
117
|
-
appName: z.string(),
|
|
118
|
-
allowDestructiveActions: z.boolean(),
|
|
119
|
-
allowOpenWorld: z.boolean().optional(),
|
|
120
|
-
destructiveApprovalMode: destructiveApprovalModeSchema,
|
|
121
|
-
mcpServerNames: z.array(z.string())
|
|
122
|
-
}).strict();
|
|
123
|
-
const pluginAppPolicyEntrySchema = z.object({
|
|
124
|
-
source: z.literal("plugin").optional(),
|
|
125
|
-
configKey: z.string(),
|
|
126
|
-
marketplaceName: z.string().regex(CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN),
|
|
127
|
-
pluginName: z.string(),
|
|
128
|
-
allowDestructiveActions: z.boolean(),
|
|
129
|
-
allowOpenWorld: z.boolean().optional(),
|
|
130
|
-
destructiveApprovalMode: destructiveApprovalModeSchema,
|
|
131
|
-
mcpServerNames: z.array(z.string())
|
|
132
|
-
}).strict();
|
|
133
|
-
const pluginAppPolicyContextSchema = z.object({
|
|
134
|
-
fingerprint: z.string(),
|
|
135
|
-
apps: z.record(z.string(), z.union([accountAppPolicyEntrySchema, pluginAppPolicyEntrySchema])),
|
|
136
|
-
pluginAppIds: z.record(z.string(), z.array(z.string())).default({})
|
|
137
|
-
}).strict();
|
|
138
|
-
const threadBindingSchema = z.object({
|
|
139
|
-
threadId: z.string().refine((value) => Boolean(value.trim())),
|
|
140
|
-
clientId: optionalStringSchema,
|
|
141
|
-
cwd: z.string(),
|
|
142
|
-
rolloutPath: optionalNonBlankStringSchema,
|
|
143
|
-
connectionScope: z.literal("supervision").optional(),
|
|
144
|
-
supervisionSourceThreadId: z.string().trim().min(1).optional(),
|
|
145
|
-
authProfileId: optionalStringSchema,
|
|
146
|
-
agentWorkspaceDeveloperInstructions: optionalNonBlankStringSchema,
|
|
147
|
-
model: optionalStringSchema,
|
|
148
|
-
preserveNativeModel: z.literal(true).optional().catch(void 0),
|
|
149
|
-
pendingSupervisionBranch: pendingSupervisionBranchSchema.optional(),
|
|
150
|
-
modelProvider: z.string().transform((value) => value.trim()).pipe(z.string().min(1)).optional().catch(void 0),
|
|
151
|
-
approvalPolicy: z.preprocess((value) => value === "on-failure" ? "on-request" : value, z.enum([
|
|
152
|
-
"never",
|
|
153
|
-
"on-request",
|
|
154
|
-
"untrusted"
|
|
155
|
-
]).optional()).catch(void 0),
|
|
156
|
-
sandbox: z.enum([
|
|
157
|
-
"read-only",
|
|
158
|
-
"workspace-write",
|
|
159
|
-
"danger-full-access"
|
|
160
|
-
]).optional().catch(void 0),
|
|
161
|
-
serviceTier: z.preprocess(normalizeCodexServiceTier, z.custom((value) => typeof value === "string").optional()).optional().catch(void 0),
|
|
162
|
-
networkProxyProfileName: optionalStringSchema,
|
|
163
|
-
networkProxyConfigFingerprint: optionalStringSchema,
|
|
164
|
-
dynamicToolsFingerprint: optionalStringSchema,
|
|
165
|
-
dynamicToolsContainDeferred: optionalBooleanSchema,
|
|
166
|
-
webSearchThreadConfigFingerprint: optionalStringSchema,
|
|
167
|
-
nativeSkillIsolationFingerprint: optionalStringSchema,
|
|
168
|
-
userMcpServersFingerprint: optionalStringSchema,
|
|
169
|
-
mcpServersFingerprint: optionalStringSchema,
|
|
170
|
-
configuredMcpOwnershipVersion: z.literal(1).optional().catch(void 0),
|
|
171
|
-
ringZeroConfigFingerprint: optionalStringSchema,
|
|
172
|
-
ringZeroClientInstanceId: optionalStringSchema,
|
|
173
|
-
/** Durable fact preventing a later unrestricted turn from widening this thread. */
|
|
174
|
-
nativeToolPolicyRestricted: z.literal(true).optional().catch(void 0),
|
|
175
|
-
nativeHookRelayGeneration: optionalNonBlankStringSchema,
|
|
176
|
-
appServerRuntimeFingerprint: optionalStringSchema,
|
|
177
|
-
pluginAppsFingerprint: optionalStringSchema,
|
|
178
|
-
pluginAppsInputFingerprint: optionalStringSchema,
|
|
179
|
-
pluginAppPolicyContext: pluginAppPolicyContextSchema.optional().catch(void 0),
|
|
180
|
-
contextEngine: contextEngineSchema.optional().catch(void 0),
|
|
181
|
-
environmentSelectionFingerprint: optionalStringSchema,
|
|
182
|
-
conversationStartId: optionalStringSchema,
|
|
183
|
-
conversationSourceTransferComplete: z.literal(true).optional().catch(void 0),
|
|
184
|
-
historyCoveredThrough: optionalTimestampSchema,
|
|
185
|
-
continuityCalibration: z.object({
|
|
186
|
-
promptChars: z.number().int().positive(),
|
|
187
|
-
inputTokens: z.number().int().positive()
|
|
188
|
-
}).optional().catch(void 0)
|
|
189
|
-
}).superRefine((binding, context) => {
|
|
190
|
-
if (binding.connectionScope === "supervision") {
|
|
191
|
-
if (!binding.supervisionSourceThreadId) context.addIssue({
|
|
192
|
-
code: "custom",
|
|
193
|
-
message: "supervision connection ownership requires its native source thread id"
|
|
194
|
-
});
|
|
195
|
-
if (binding.preserveNativeModel !== true) context.addIssue({
|
|
196
|
-
code: "custom",
|
|
197
|
-
message: "supervision connection ownership requires native model ownership"
|
|
198
|
-
});
|
|
199
|
-
if (binding.conversationSourceTransferComplete !== true) context.addIssue({
|
|
200
|
-
code: "custom",
|
|
201
|
-
message: "supervision connection ownership requires a completed source transfer"
|
|
202
|
-
});
|
|
203
|
-
if (!binding.pendingSupervisionBranch && (!binding.model?.trim() || !binding.modelProvider)) context.addIssue({
|
|
204
|
-
code: "custom",
|
|
205
|
-
message: "materialized supervision bindings require a native model and provider"
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
if (binding.supervisionSourceThreadId && binding.connectionScope !== "supervision") context.addIssue({
|
|
209
|
-
code: "custom",
|
|
210
|
-
message: "a supervision source thread id requires supervision connection ownership"
|
|
211
|
-
});
|
|
212
|
-
if (!binding.pendingSupervisionBranch) return;
|
|
213
|
-
if (binding.threadId !== binding.pendingSupervisionBranch.sourceThreadId) context.addIssue({
|
|
214
|
-
code: "custom",
|
|
215
|
-
message: "pending supervision source must match the provisional thread binding"
|
|
216
|
-
});
|
|
217
|
-
if (binding.supervisionSourceThreadId !== binding.pendingSupervisionBranch.sourceThreadId) context.addIssue({
|
|
218
|
-
code: "custom",
|
|
219
|
-
message: "pending supervision source must match its durable source identity"
|
|
220
|
-
});
|
|
221
|
-
if (binding.preserveNativeModel !== true) context.addIssue({
|
|
222
|
-
code: "custom",
|
|
223
|
-
message: "pending supervision bindings must defer model selection to Codex App Server"
|
|
224
|
-
});
|
|
225
|
-
if (binding.connectionScope !== "supervision") context.addIssue({
|
|
226
|
-
code: "custom",
|
|
227
|
-
message: "pending supervision bindings require supervision connection ownership"
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
81
|
var CodexSupervisionBindingReplacementError = class extends Error {
|
|
231
82
|
constructor(threadId, operation) {
|
|
232
83
|
super(`Refusing to replace supervised Codex thread ${threadId} while ${operation}; its native user-home connection and model ownership must be preserved`);
|
|
233
84
|
this.name = "CodexSupervisionBindingReplacementError";
|
|
234
85
|
}
|
|
235
86
|
};
|
|
236
|
-
function assertCodexBindingMayBeReplaced(binding, operation) {
|
|
87
|
+
function assertCodexBindingMayBeReplaced(binding, operation, expected) {
|
|
88
|
+
if (expected) throw new AgentHarnessPreflightError(`Codex native model ownership prevents ${operation}. Continue or compact the original session in its native runtime, or create a new chat with a concrete model; the original binding was preserved.`);
|
|
237
89
|
if (binding?.connectionScope === "supervision") throw new CodexSupervisionBindingReplacementError(binding.threadId, operation);
|
|
238
90
|
}
|
|
239
|
-
const bindingLeaseSchema = z.object({
|
|
240
|
-
token: z.string().refine((value) => Boolean(value.trim())),
|
|
241
|
-
expiresAt: z.number().finite()
|
|
242
|
-
});
|
|
243
|
-
const storedSessionIdSchema = z.string().transform((value) => value.trim()).pipe(z.string().min(1)).optional().catch(void 0);
|
|
244
|
-
const storedBindingSchema = z.discriminatedUnion("state", [z.object({
|
|
245
|
-
version: z.literal(1),
|
|
246
|
-
state: z.literal("active"),
|
|
247
|
-
binding: threadBindingSchema,
|
|
248
|
-
sessionId: storedSessionIdSchema,
|
|
249
|
-
lease: bindingLeaseSchema.optional().catch(void 0)
|
|
250
|
-
}), z.object({
|
|
251
|
-
version: z.literal(1),
|
|
252
|
-
state: z.literal("cleared"),
|
|
253
|
-
sessionId: storedSessionIdSchema,
|
|
254
|
-
lease: bindingLeaseSchema.optional().catch(void 0),
|
|
255
|
-
retired: z.literal(true).optional().catch(void 0)
|
|
256
|
-
})]);
|
|
257
91
|
function hashCodexAppServerBindingFingerprint(canonical) {
|
|
258
92
|
return `sha256:${createHash("sha256").update(canonical).digest("hex")}`;
|
|
259
93
|
}
|
|
@@ -288,7 +122,7 @@ function createStoredCodexAppServerBinding(value, options = {}) {
|
|
|
288
122
|
const record = normalizeLegacyBindingFingerprints(rawRecord);
|
|
289
123
|
if (record.schemaVersion !== 1 && record.schemaVersion !== 2) return;
|
|
290
124
|
const pluginAppPolicyContext = readPluginAppPolicyContext(record.pluginAppPolicyContext, record.schemaVersion);
|
|
291
|
-
const historyCoveredThrough =
|
|
125
|
+
const historyCoveredThrough = readCodexBindingTimestamp(record.historyCoveredThrough) ?? readCodexBindingTimestamp(record.updatedAt) ?? readCodexBindingTimestamp(record.createdAt) ?? readCodexBindingTimestamp(options.now) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
292
126
|
const authProfileId = typeof record.authProfileId === "string" ? record.authProfileId : void 0;
|
|
293
127
|
const binding = readCodexAppServerThreadBinding({
|
|
294
128
|
...record,
|
|
@@ -318,37 +152,72 @@ function scopeCodexRunBindingStore(params) {
|
|
|
318
152
|
...params.bindingStore,
|
|
319
153
|
read: (identity) => params.bindingStore.read(mapIdentity(identity)),
|
|
320
154
|
hasOtherThreadOwner: (threadId, identity) => params.bindingStore.hasOtherThreadOwner(threadId, identity ? mapIdentity(identity) : void 0),
|
|
321
|
-
mutate: (identity, mutation) => params.bindingStore.mutate(mapIdentity(identity), mutation),
|
|
155
|
+
mutate: (identity, mutation, assertCurrent) => params.bindingStore.mutate(mapIdentity(identity), mutation, assertCurrent),
|
|
322
156
|
prepareSessionGenerationReclaim: (identity) => params.bindingStore.prepareSessionGenerationReclaim(mapSessionIdentity(identity)),
|
|
323
|
-
adoptSessionGeneration: (identity, expectedPreviousSessionId) => params.bindingStore.adoptSessionGeneration(mapSessionIdentity(identity), expectedPreviousSessionId),
|
|
157
|
+
adoptSessionGeneration: (identity, expectedPreviousSessionId, assertCurrent) => params.bindingStore.adoptSessionGeneration(mapSessionIdentity(identity), expectedPreviousSessionId, assertCurrent),
|
|
324
158
|
resetSessionGeneration: (identity) => params.bindingStore.resetSessionGeneration(mapSessionIdentity(identity)),
|
|
325
159
|
retireSessionGeneration: (identity) => params.bindingStore.retireSessionGeneration(mapSessionIdentity(identity)),
|
|
160
|
+
withSessionDeletion: (identity, assertCurrent, run) => params.bindingStore.withSessionDeletion(mapSessionIdentity(identity), assertCurrent, run),
|
|
326
161
|
withThreadArchiveFence: (run) => params.bindingStore.withThreadArchiveFence(run),
|
|
327
162
|
withLease: (identity, run) => params.bindingStore.withLease(mapIdentity(identity), run)
|
|
328
163
|
};
|
|
329
164
|
}
|
|
330
|
-
|
|
331
|
-
async function reclaimCurrentCodexSessionGeneration(params) {
|
|
332
|
-
const sessionKey = params.identity.sessionKey?.trim();
|
|
333
|
-
if (!sessionKey) return true;
|
|
165
|
+
async function reclaimPreparedCodexSessionGeneration(params, authority, assertCurrent = authority[3]) {
|
|
334
166
|
const plan = await params.bindingStore.prepareSessionGenerationReclaim(params.identity);
|
|
167
|
+
assertCurrent();
|
|
335
168
|
if (plan.kind === "resolved") return plan.result;
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
sessionKey,
|
|
343
|
-
storePath
|
|
344
|
-
})?.sessionId !== params.identity.sessionId) return false;
|
|
345
|
-
} catch {
|
|
346
|
-
return false;
|
|
169
|
+
const [state, previousSessionId, assertHostCurrent] = authority;
|
|
170
|
+
if (state !== "current") return false;
|
|
171
|
+
params.onHostGenerationVerified?.(assertHostCurrent);
|
|
172
|
+
if (previousSessionId === plan.expectedPreviousSessionId) {
|
|
173
|
+
const adopted = await params.bindingStore.adoptSessionGeneration(params.identity, previousSessionId, assertCurrent);
|
|
174
|
+
if (adopted !== "absent") return adopted !== "conflict";
|
|
347
175
|
}
|
|
348
|
-
|
|
176
|
+
if (params.reclaimStale === false) return false;
|
|
177
|
+
return params.bindingStore.mutate(params.identity, {
|
|
349
178
|
kind: "reclaim-generation",
|
|
350
179
|
expectedPreviousSessionId: plan.expectedPreviousSessionId
|
|
351
|
-
});
|
|
180
|
+
}, assertCurrent);
|
|
181
|
+
}
|
|
182
|
+
/** Lets the authoritative OpenClaw session generation claim a stale stable binding row. */
|
|
183
|
+
async function reclaimCurrentCodexSessionGeneration(params) {
|
|
184
|
+
params.assertCurrent?.();
|
|
185
|
+
if (!params.identity.sessionKey?.trim()) return true;
|
|
186
|
+
const authority = captureCodexSessionGenerationAuthority(params, params.assertCurrent);
|
|
187
|
+
if (authority[0] === "superseded") return false;
|
|
188
|
+
return reclaimPreparedCodexSessionGeneration(params, authority);
|
|
189
|
+
}
|
|
190
|
+
/** Resolve continuity before selecting native queues, catalogs, or connections. */
|
|
191
|
+
async function resolveCodexSessionBinding(params) {
|
|
192
|
+
let assertCurrent = params.assertCurrent ?? (() => {});
|
|
193
|
+
const assertAdmissionCurrent = () => {
|
|
194
|
+
assertCurrent();
|
|
195
|
+
params.signal?.throwIfAborted();
|
|
196
|
+
};
|
|
197
|
+
assertAdmissionCurrent();
|
|
198
|
+
params.assertBinding?.(readCodexSessionOwnershipBinding(params));
|
|
199
|
+
const identity = params.identity;
|
|
200
|
+
const authority = identity.kind === "session" && identity.sessionKey?.trim() ? captureCodexSessionGenerationAuthority({
|
|
201
|
+
...params,
|
|
202
|
+
identity
|
|
203
|
+
}, assertCurrent) : void 0;
|
|
204
|
+
assertCurrent = authority?.[3] ?? assertCurrent;
|
|
205
|
+
assertAdmissionCurrent();
|
|
206
|
+
let binding = params.bindingStore.read(identity);
|
|
207
|
+
if (!binding && authority && identity.kind === "session") {
|
|
208
|
+
if (!await reclaimPreparedCodexSessionGeneration({
|
|
209
|
+
...params,
|
|
210
|
+
identity,
|
|
211
|
+
reclaimStale: params.reclaimStale === true
|
|
212
|
+
}, authority, assertAdmissionCurrent) && params.reclaimStale) throw createCodexSessionGenerationSupersededError(identity.sessionId);
|
|
213
|
+
binding = params.bindingStore.read(identity);
|
|
214
|
+
}
|
|
215
|
+
assertAdmissionCurrent();
|
|
216
|
+
params.assertBinding?.(binding);
|
|
217
|
+
return {
|
|
218
|
+
binding,
|
|
219
|
+
assertCurrent
|
|
220
|
+
};
|
|
352
221
|
}
|
|
353
222
|
/** Creates the single binding facade owned by the Codex plugin runtime. */
|
|
354
223
|
function createCodexAppServerBindingStore(state) {
|
|
@@ -382,9 +251,10 @@ function createCodexAppServerBindingStore(state) {
|
|
|
382
251
|
}
|
|
383
252
|
};
|
|
384
253
|
const renewLease = (key, owner) => {
|
|
385
|
-
if (owner.failure) return;
|
|
254
|
+
if (owner.failure || owner.phase !== "held") return;
|
|
386
255
|
try {
|
|
387
256
|
let renewed = false;
|
|
257
|
+
owner.assertCurrent?.();
|
|
388
258
|
const stored = update(key, (raw) => {
|
|
389
259
|
const current = readStoredCodexAppServerBinding(raw);
|
|
390
260
|
if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
@@ -405,15 +275,18 @@ function createCodexAppServerBindingStore(state) {
|
|
|
405
275
|
owner.failure = bindingLeaseLostError(key, error);
|
|
406
276
|
}
|
|
407
277
|
};
|
|
408
|
-
const transactKey = async (key, apply, ttlMs) => {
|
|
278
|
+
const transactKey = async (key, apply, ttlMs, assertCurrent) => {
|
|
409
279
|
const deadline = Date.now() + BINDING_LEASE_WAIT_MS;
|
|
410
280
|
while (true) {
|
|
411
281
|
let busy = false;
|
|
412
282
|
let leaseLost = false;
|
|
413
283
|
let result;
|
|
414
284
|
const ownedLease = leaseContext.getStore()?.get(key);
|
|
285
|
+
if (ownedLease && ownedLease.phase !== "held") throw bindingLeaseLostError(key);
|
|
415
286
|
if (ownedLease?.failure) throw ownedLease.failure;
|
|
416
287
|
const ownedToken = ownedLease?.token;
|
|
288
|
+
assertCurrent?.();
|
|
289
|
+
ownedLease?.assertCurrent?.();
|
|
417
290
|
update(key, (raw) => {
|
|
418
291
|
const current = readStoredCodexAppServerBinding(raw);
|
|
419
292
|
if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
@@ -441,14 +314,117 @@ function createCodexAppServerBindingStore(state) {
|
|
|
441
314
|
await sleep(BINDING_LEASE_RETRY_INTERVAL_MS);
|
|
442
315
|
}
|
|
443
316
|
};
|
|
444
|
-
|
|
445
|
-
|
|
317
|
+
const withBindingLease = async (identity, run, options = {}) => {
|
|
318
|
+
options.assertCurrent?.();
|
|
319
|
+
const key = bindingStoreKey(identity);
|
|
320
|
+
const owned = leaseContext.getStore();
|
|
321
|
+
const existingOwner = owned?.get(key);
|
|
322
|
+
if (existingOwner) {
|
|
323
|
+
if (existingOwner.phase !== "held") throw bindingLeaseLostError(key);
|
|
324
|
+
const failureBeforeRun = existingOwner.failure;
|
|
325
|
+
if (failureBeforeRun) throw failureBeforeRun;
|
|
326
|
+
const result = await run();
|
|
327
|
+
options.assertCurrent?.();
|
|
328
|
+
const failureAfterRun = existingOwner.failure;
|
|
329
|
+
if (failureAfterRun) throw failureAfterRun;
|
|
330
|
+
return result;
|
|
331
|
+
}
|
|
332
|
+
const token = randomUUID();
|
|
333
|
+
const acquired = await transactKey(key, (current) => {
|
|
334
|
+
if (current?.state === "cleared" && current.retired === true && ownsStoredSessionGeneration(identity, current) && !options.allowRetired) return { result: false };
|
|
335
|
+
const lease = {
|
|
336
|
+
token,
|
|
337
|
+
expiresAt: Date.now() + BINDING_LEASE_STALE_MS
|
|
338
|
+
};
|
|
339
|
+
if (current?.state === "active") return {
|
|
340
|
+
result: true,
|
|
341
|
+
next: {
|
|
342
|
+
...current,
|
|
343
|
+
...preservedSessionGeneration(identity, current),
|
|
344
|
+
lease
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
if (current?.state === "cleared" && current.retired === true) return {
|
|
348
|
+
result: true,
|
|
349
|
+
next: {
|
|
350
|
+
...current,
|
|
351
|
+
lease
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
return {
|
|
355
|
+
result: true,
|
|
356
|
+
next: {
|
|
357
|
+
version: 1,
|
|
358
|
+
state: "cleared",
|
|
359
|
+
...preservedSessionGeneration(identity, current),
|
|
360
|
+
lease
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
}, void 0, options.assertCurrent);
|
|
364
|
+
options.assertCurrent?.();
|
|
365
|
+
if (!acquired) throw new Error(`Codex binding generation was retired: ${key}`);
|
|
366
|
+
const owner = {
|
|
367
|
+
token,
|
|
368
|
+
phase: "held",
|
|
369
|
+
assertCurrent: options.assertCurrent
|
|
370
|
+
};
|
|
371
|
+
const nested = new Map(owned);
|
|
372
|
+
nested.set(key, owner);
|
|
373
|
+
const heartbeat = setInterval(() => renewLease(key, owner), BINDING_LEASE_RENEW_INTERVAL_MS);
|
|
374
|
+
heartbeat.unref();
|
|
375
|
+
try {
|
|
376
|
+
const result = await leaseContext.run(nested, run);
|
|
377
|
+
options.assertCurrent?.();
|
|
378
|
+
if (owner.failure) throw owner.failure;
|
|
379
|
+
return result;
|
|
380
|
+
} finally {
|
|
381
|
+
clearInterval(heartbeat);
|
|
382
|
+
owner.phase = "closed";
|
|
383
|
+
options.assertCurrent?.();
|
|
384
|
+
try {
|
|
385
|
+
const current = readStoredCodexAppServerBinding(state.lookup(key));
|
|
386
|
+
if (current?.lease?.token === token) {
|
|
387
|
+
const ttlMs = current.state === "active" || current.retired === true && !key.startsWith("session:") ? void 0 : current.retired === true ? PHYSICAL_SESSION_RETIRE_TTL_MS : 1;
|
|
388
|
+
options.assertCurrent?.();
|
|
389
|
+
update(key, (raw) => {
|
|
390
|
+
const stored = readStoredCodexAppServerBinding(raw);
|
|
391
|
+
if (stored?.lease?.token !== token) return;
|
|
392
|
+
const { lease: _lease, ...released } = stored;
|
|
393
|
+
return released;
|
|
394
|
+
}, ttlMs === void 0 ? void 0 : { ttlMs });
|
|
395
|
+
}
|
|
396
|
+
} catch (error) {
|
|
397
|
+
options.assertCurrent?.();
|
|
398
|
+
embeddedAgentLog.warn("failed to release codex app-server binding lease", {
|
|
399
|
+
key,
|
|
400
|
+
error
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
const transitionSessionGeneration = async (identity, mode) => {
|
|
406
|
+
return await runBindingMutation(async () => {
|
|
446
407
|
const key = bindingStoreKey(identity);
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
408
|
+
const ttlMs = mode === "reset" ? leaseContext.getStore()?.has(key) ? void 0 : 1 : identity.sessionKey?.trim() ? void 0 : PHYSICAL_SESSION_RETIRE_TTL_MS;
|
|
409
|
+
return await transactKey(key, (current, leaseToken) => {
|
|
410
|
+
if (!current) return { result: "absent" };
|
|
411
|
+
if (!ownsStoredSessionGeneration(identity, current)) return { result: "conflict" };
|
|
412
|
+
if (current.state === "cleared" && current.retired === true) return { result: mode === "retire" ? "applied" : "conflict" };
|
|
413
|
+
return {
|
|
414
|
+
result: "applied",
|
|
415
|
+
next: {
|
|
416
|
+
version: 1,
|
|
417
|
+
state: "cleared",
|
|
418
|
+
...mode === "retire" ? { retired: true } : {},
|
|
419
|
+
...storedSessionGeneration(identity, current),
|
|
420
|
+
...current.lease && current.lease.token === leaseToken ? { lease: current.lease } : {}
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
}, ttlMs);
|
|
424
|
+
});
|
|
425
|
+
};
|
|
426
|
+
return {
|
|
427
|
+
read: (identity) => readCurrentCodexAppServerBinding(state, identity),
|
|
452
428
|
async hasOtherThreadOwner(threadId, currentIdentity) {
|
|
453
429
|
const currentKey = currentIdentity ? bindingStoreKey(currentIdentity) : void 0;
|
|
454
430
|
return state.entries().some(({ key, value }) => {
|
|
@@ -485,7 +461,7 @@ function createCodexAppServerBindingStore(state) {
|
|
|
485
461
|
expectedPreviousSessionId: currentSessionId
|
|
486
462
|
};
|
|
487
463
|
},
|
|
488
|
-
async mutate(identity, mutation) {
|
|
464
|
+
async mutate(identity, mutation, assertCurrent) {
|
|
489
465
|
return await runBindingMutation(async () => {
|
|
490
466
|
const key = bindingStoreKey(identity);
|
|
491
467
|
const retainLegacyClear = mutation.kind === "clear" && key.startsWith("conversation:legacy-");
|
|
@@ -523,9 +499,8 @@ function createCodexAppServerBindingStore(state) {
|
|
|
523
499
|
const active = ownsGeneration ? storedActive : void 0;
|
|
524
500
|
const retiredGeneration = current?.state === "cleared" && current.retired === true && ownsGeneration;
|
|
525
501
|
const preservesSupervisionOwner = mutation.kind === "set" && active?.binding.connectionScope === "supervision" && isSameSupervisionOwner(active.binding, mutation.binding);
|
|
526
|
-
const clearsPendingSupervisionOwner = mutation.kind === "clear" && active?.binding.connectionScope === "supervision" && matchesPendingSupervisionClear(active.binding, mutation.threadId, mutation.expectedPendingSupervisionBranch);
|
|
527
502
|
const replacesExpectedOrdinaryOwner = mutation.kind === "replace-thread" && active?.binding.threadId === mutation.expectedThreadId && active.binding.connectionScope !== "supervision" && mutation.binding.connectionScope !== "supervision" && mutation.binding.threadId !== mutation.expectedThreadId;
|
|
528
|
-
if (mutation.kind === "set" && (mutation.if?.kind === "absent" && storedActive || current !== void 0 && !ownsGeneration || retiredGeneration || active?.binding.connectionScope === "supervision" && !preservesSupervisionOwner) || mutation.kind === "patch" && active?.binding.threadId !== mutation.threadId || mutation.kind === "replace-thread" && !replacesExpectedOrdinaryOwner || (mutation.kind === "patch-pending-supervision-branch" || mutation.kind === "commit-pending-supervision-branch") && !matchesPendingSupervisionBranch(active?.binding, mutation.expected) || mutation.kind === "clear" && (mutation.threadId !== void 0 && active?.binding.threadId !== mutation.threadId ||
|
|
503
|
+
if (mutation.kind === "set" && (mutation.if?.kind === "absent" && storedActive || current !== void 0 && !ownsGeneration || retiredGeneration || active?.binding.connectionScope === "supervision" && !preservesSupervisionOwner) || mutation.kind === "patch" && active?.binding.threadId !== mutation.threadId || mutation.kind === "replace-thread" && !replacesExpectedOrdinaryOwner || (mutation.kind === "patch-pending-supervision-branch" || mutation.kind === "commit-pending-supervision-branch") && !matchesPendingSupervisionBranch(active?.binding, mutation.expected) || mutation.kind === "clear" && (!ownsGeneration || mutation.threadId !== void 0 && active?.binding.threadId !== mutation.threadId || active?.binding.connectionScope === "supervision")) return { result: false };
|
|
529
504
|
if (mutation.kind === "clear" && retiredGeneration) return { result: true };
|
|
530
505
|
if (mutation.kind === "clear") return {
|
|
531
506
|
result: true,
|
|
@@ -563,10 +538,10 @@ function createCodexAppServerBindingStore(state) {
|
|
|
563
538
|
...ownedLease
|
|
564
539
|
}
|
|
565
540
|
};
|
|
566
|
-
}, mutation.kind === "clear" && !retainLegacyClear && !leaseContext.getStore()?.has(key) ? 1 : void 0);
|
|
541
|
+
}, mutation.kind === "clear" && !retainLegacyClear && !leaseContext.getStore()?.has(key) ? 1 : void 0, assertCurrent);
|
|
567
542
|
});
|
|
568
543
|
},
|
|
569
|
-
async adoptSessionGeneration(identity, expectedPreviousSessionId) {
|
|
544
|
+
async adoptSessionGeneration(identity, expectedPreviousSessionId, assertCurrent) {
|
|
570
545
|
return await runBindingMutation(async () => {
|
|
571
546
|
const key = bindingStoreKey(identity);
|
|
572
547
|
const expectedSessionId = expectedPreviousSessionId.trim();
|
|
@@ -583,48 +558,11 @@ function createCodexAppServerBindingStore(state) {
|
|
|
583
558
|
sessionId: targetSessionId
|
|
584
559
|
}
|
|
585
560
|
};
|
|
586
|
-
});
|
|
587
|
-
});
|
|
588
|
-
},
|
|
589
|
-
async resetSessionGeneration(identity) {
|
|
590
|
-
return await runBindingMutation(async () => {
|
|
591
|
-
const key = bindingStoreKey(identity);
|
|
592
|
-
return await transactKey(key, (current, leaseToken) => {
|
|
593
|
-
if (!current) return { result: "absent" };
|
|
594
|
-
if (!ownsStoredSessionGeneration(identity, current)) return { result: "conflict" };
|
|
595
|
-
if (current.state === "cleared" && current.retired === true) return { result: "conflict" };
|
|
596
|
-
return {
|
|
597
|
-
result: "applied",
|
|
598
|
-
next: {
|
|
599
|
-
version: 1,
|
|
600
|
-
state: "cleared",
|
|
601
|
-
...storedSessionGeneration(identity, current),
|
|
602
|
-
...current.lease && current.lease.token === leaseToken ? { lease: current.lease } : {}
|
|
603
|
-
}
|
|
604
|
-
};
|
|
605
|
-
}, leaseContext.getStore()?.has(key) ? void 0 : 1);
|
|
606
|
-
});
|
|
607
|
-
},
|
|
608
|
-
async retireSessionGeneration(identity) {
|
|
609
|
-
return await runBindingMutation(async () => {
|
|
610
|
-
const key = bindingStoreKey(identity);
|
|
611
|
-
return await transactKey(key, (current, leaseToken) => {
|
|
612
|
-
if (!current) return { result: "absent" };
|
|
613
|
-
if (!ownsStoredSessionGeneration(identity, current)) return { result: "conflict" };
|
|
614
|
-
if (current.state === "cleared" && current.retired === true) return { result: "applied" };
|
|
615
|
-
return {
|
|
616
|
-
result: "applied",
|
|
617
|
-
next: {
|
|
618
|
-
version: 1,
|
|
619
|
-
state: "cleared",
|
|
620
|
-
retired: true,
|
|
621
|
-
...storedSessionGeneration(identity, current),
|
|
622
|
-
...current.lease && current.lease.token === leaseToken ? { lease: current.lease } : {}
|
|
623
|
-
}
|
|
624
|
-
};
|
|
625
|
-
}, identity.sessionKey?.trim() ? void 0 : PHYSICAL_SESSION_RETIRE_TTL_MS);
|
|
561
|
+
}, void 0, assertCurrent);
|
|
626
562
|
});
|
|
627
563
|
},
|
|
564
|
+
resetSessionGeneration: (identity) => transitionSessionGeneration(identity, "reset"),
|
|
565
|
+
retireSessionGeneration: (identity) => transitionSessionGeneration(identity, "retire"),
|
|
628
566
|
async withThreadArchiveFence(run) {
|
|
629
567
|
pendingArchives += 1;
|
|
630
568
|
const operation = archiveTail.then(async () => {
|
|
@@ -638,79 +576,74 @@ function createCodexAppServerBindingStore(state) {
|
|
|
638
576
|
pendingArchives -= 1;
|
|
639
577
|
}
|
|
640
578
|
},
|
|
641
|
-
async
|
|
579
|
+
async withSessionDeletion(identity, assertCurrent, run) {
|
|
642
580
|
const key = bindingStoreKey(identity);
|
|
643
|
-
const
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
if (
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
};
|
|
660
|
-
if (current?.state === "active") return {
|
|
661
|
-
result: true,
|
|
662
|
-
next: {
|
|
663
|
-
...current,
|
|
664
|
-
...preservedSessionGeneration(identity, current),
|
|
665
|
-
lease
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
if (current?.state === "cleared" && current.retired === true) return {
|
|
669
|
-
result: true,
|
|
670
|
-
next: {
|
|
671
|
-
...current,
|
|
672
|
-
lease
|
|
673
|
-
}
|
|
674
|
-
};
|
|
675
|
-
return {
|
|
676
|
-
result: true,
|
|
677
|
-
next: {
|
|
678
|
-
version: 1,
|
|
679
|
-
state: "cleared",
|
|
680
|
-
...preservedSessionGeneration(identity, current),
|
|
681
|
-
lease
|
|
581
|
+
const deleteIf = state.deleteIf?.bind(state);
|
|
582
|
+
if (!deleteIf) throw new Error("Codex session deletion requires conditional plugin-state deletion");
|
|
583
|
+
return await runBindingMutation(async () => {
|
|
584
|
+
assertCurrent();
|
|
585
|
+
if (state.lookup(key) === void 0) {
|
|
586
|
+
let active = true;
|
|
587
|
+
try {
|
|
588
|
+
return await run(void 0, {
|
|
589
|
+
commit() {
|
|
590
|
+
assertCurrent();
|
|
591
|
+
if (!active || state.lookup(key) !== void 0) throw new Error("Codex binding changed before session deletion");
|
|
592
|
+
},
|
|
593
|
+
rollback() {}
|
|
594
|
+
});
|
|
595
|
+
} finally {
|
|
596
|
+
active = false;
|
|
682
597
|
}
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
clearInterval(heartbeat);
|
|
696
|
-
try {
|
|
697
|
-
const removeOwnedLease = (raw, matches) => {
|
|
698
|
-
const current = readStoredCodexAppServerBinding(raw);
|
|
699
|
-
if (!current || !matches(current) || current.lease?.token !== token) return;
|
|
700
|
-
const { lease: _lease, ...released } = current;
|
|
701
|
-
return released;
|
|
598
|
+
}
|
|
599
|
+
return await withBindingLease(identity, async () => {
|
|
600
|
+
const owner = leaseContext.getStore().get(key);
|
|
601
|
+
const expected = state.lookup(key);
|
|
602
|
+
const stored = readStoredCodexAppServerBinding(expected);
|
|
603
|
+
if (!stored || !ownsStoredSessionGeneration(identity, stored)) throw new Error("Codex binding generation changed before session deletion");
|
|
604
|
+
const { lease: _lease, ...expectedValue } = stored;
|
|
605
|
+
let deleted;
|
|
606
|
+
let active = true;
|
|
607
|
+
const assertActive = () => {
|
|
608
|
+
assertCurrent();
|
|
609
|
+
if (!active || owner.phase === "closed" || owner.failure) throw owner.failure ?? bindingLeaseLostError(key);
|
|
702
610
|
};
|
|
703
|
-
|
|
704
|
-
|
|
611
|
+
try {
|
|
612
|
+
return await run(stored.state === "active" ? stored.binding : void 0, {
|
|
613
|
+
commit() {
|
|
614
|
+
assertActive();
|
|
615
|
+
if (deleted) return;
|
|
616
|
+
const current = state.lookup(key);
|
|
617
|
+
const { lease, ...value } = readStoredCodexAppServerBinding(current) ?? {};
|
|
618
|
+
if (!current || lease?.token !== owner.token || lease.expiresAt <= Date.now() || !isDeepStrictEqual(value, expectedValue) || !deleteIf(key, (raw) => isDeepStrictEqual(raw, current))) throw new Error("Codex binding changed before session deletion");
|
|
619
|
+
deleted = current;
|
|
620
|
+
owner.phase = "deleted";
|
|
621
|
+
},
|
|
622
|
+
rollback() {
|
|
623
|
+
assertActive();
|
|
624
|
+
if (!deleted) return;
|
|
625
|
+
const restored = {
|
|
626
|
+
...deleted,
|
|
627
|
+
lease: {
|
|
628
|
+
token: owner.token,
|
|
629
|
+
expiresAt: Date.now() + BINDING_LEASE_STALE_MS
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
if (!state.registerIfAbsent(key, restored)) throw new Error("Codex binding changed before session deletion rollback");
|
|
633
|
+
deleted = void 0;
|
|
634
|
+
owner.phase = "held";
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
} finally {
|
|
638
|
+
active = false;
|
|
705
639
|
}
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
}
|
|
640
|
+
}, {
|
|
641
|
+
allowRetired: true,
|
|
642
|
+
assertCurrent
|
|
643
|
+
});
|
|
644
|
+
});
|
|
645
|
+
},
|
|
646
|
+
withLease: withBindingLease
|
|
714
647
|
};
|
|
715
648
|
}
|
|
716
649
|
function matchesPendingSupervisionBranch(binding, expected) {
|
|
@@ -724,31 +657,6 @@ function matchesPendingSupervisionBranch(binding, expected) {
|
|
|
724
657
|
function isSameSupervisionOwner(current, replacement) {
|
|
725
658
|
return replacement.connectionScope === "supervision" && replacement.threadId === current.threadId && replacement.supervisionSourceThreadId === current.supervisionSourceThreadId;
|
|
726
659
|
}
|
|
727
|
-
function matchesPendingSupervisionClear(binding, threadId, expected) {
|
|
728
|
-
if (!expected) return false;
|
|
729
|
-
const sourceThreadId = expected.sourceThreadId;
|
|
730
|
-
return threadId === sourceThreadId && binding.supervisionSourceThreadId === sourceThreadId && matchesPendingSupervisionBranch(binding, expected);
|
|
731
|
-
}
|
|
732
|
-
/** Stable plugin-state key for one current binding owner. */
|
|
733
|
-
function bindingStoreKey(identity) {
|
|
734
|
-
if (identity.kind === "session") {
|
|
735
|
-
const rawAgentId = identity.agentId.trim();
|
|
736
|
-
const sessionId = identity.sessionId.trim();
|
|
737
|
-
if (!rawAgentId) throw new Error("Codex app-server binding requires an agent id");
|
|
738
|
-
if (!sessionId) throw new Error("Codex app-server binding requires a session id");
|
|
739
|
-
const agentId = resolveSessionAgentIds$1({ agentId: rawAgentId }).sessionAgentId;
|
|
740
|
-
const sessionKey = identity.sessionKey?.trim();
|
|
741
|
-
if (sessionKey) return `session-key:${agentId}:${createHash("sha256").update(sessionKey).digest("base64url")}`;
|
|
742
|
-
return `session:${agentId}:${sessionId}`;
|
|
743
|
-
}
|
|
744
|
-
const bindingId = identity.bindingId.trim();
|
|
745
|
-
if (!bindingId) throw new Error("Codex app-server conversation binding requires a binding id");
|
|
746
|
-
return `conversation:${bindingId}`;
|
|
747
|
-
}
|
|
748
|
-
function readStoredCodexAppServerBinding(value) {
|
|
749
|
-
const result = storedBindingSchema.safeParse(value);
|
|
750
|
-
return result.success ? stripUndefinedValue(result.data) : void 0;
|
|
751
|
-
}
|
|
752
660
|
function storedSessionGeneration(identity, current) {
|
|
753
661
|
if (identity.kind === "session") return { sessionId: identity.sessionId };
|
|
754
662
|
return current?.sessionId ? { sessionId: current.sessionId } : {};
|
|
@@ -757,31 +665,6 @@ function preservedSessionGeneration(identity, current) {
|
|
|
757
665
|
if (current?.sessionId) return { sessionId: current.sessionId };
|
|
758
666
|
return storedSessionGeneration(identity, current);
|
|
759
667
|
}
|
|
760
|
-
function ownsStoredSessionGeneration(identity, current) {
|
|
761
|
-
return identity.kind !== "session" || !current?.sessionId || current.sessionId === identity.sessionId;
|
|
762
|
-
}
|
|
763
|
-
function validateBindingForWrite(binding) {
|
|
764
|
-
const validated = readCodexAppServerThreadBinding(binding);
|
|
765
|
-
if (!validated) throw new Error("Invalid Codex app-server thread binding");
|
|
766
|
-
return stripUndefinedBinding(validated);
|
|
767
|
-
}
|
|
768
|
-
/** Parses stored or shipped sidecar data into the current domain value. */
|
|
769
|
-
function readCodexAppServerThreadBinding(value) {
|
|
770
|
-
const result = threadBindingSchema.safeParse(value);
|
|
771
|
-
if (!result.success) return;
|
|
772
|
-
return result.data;
|
|
773
|
-
}
|
|
774
|
-
function stripUndefinedBinding(binding) {
|
|
775
|
-
return stripUndefinedValue(binding);
|
|
776
|
-
}
|
|
777
|
-
function stripUndefinedValue(value) {
|
|
778
|
-
if (Array.isArray(value)) return value.map(stripUndefinedValue);
|
|
779
|
-
if (!value || typeof value !== "object") return value;
|
|
780
|
-
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0).map(([key, entry]) => [key, stripUndefinedValue(entry)]));
|
|
781
|
-
}
|
|
782
|
-
function readTimestamp(value) {
|
|
783
|
-
return optionalTimestampSchema.parse(value);
|
|
784
|
-
}
|
|
785
668
|
function readPluginAppPolicyContext(value, bindingSchemaVersion) {
|
|
786
669
|
const record = asOptionalRecord(value);
|
|
787
670
|
if (!record || typeof record.fingerprint !== "string") return;
|
|
@@ -871,4 +754,4 @@ function normalizeCodexAppServerBindingModelProvider(params) {
|
|
|
871
754
|
return modelProvider;
|
|
872
755
|
}
|
|
873
756
|
//#endregion
|
|
874
|
-
export {
|
|
757
|
+
export { isCodexAppServerNativeAuthProfile as a, resolveCodexRunSessionBindingAuthority as c, session_binding_exports as d, hashCodexAppServerBindingFingerprint as i, resolveCodexSessionBinding as l, assertCodexBindingMayBeReplaced as n, normalizeCodexAppServerBindingModelProvider as o, createCodexSessionGenerationSupersededError as r, reclaimCurrentCodexSessionGeneration as s, CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS as t, scopeCodexRunBindingStore as u };
|