@openclaw/codex 2026.7.1-beta.2 → 2026.7.1-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/{app-server-policy-B7hqD3Xj.js → app-server-policy-BUk0GLMy.js} +5 -5
  2. package/dist/{attempt-notifications-tqyQ_Tdn.js → attempt-notifications-BGsEIIDI.js} +5 -40
  3. package/dist/{command-handlers-C9K-KRU-.js → command-handlers-UVniG5Hl.js} +267 -232
  4. package/dist/command-rpc-BjgEPh19.js +784 -0
  5. package/dist/compact-CZzbcygx.js +603 -0
  6. package/dist/{computer-use-CpurU-G9.js → computer-use-DDeySrnb.js} +3 -3
  7. package/dist/{config-C_whBx3M.js → config-CYEDnLJ2.js} +36 -15
  8. package/dist/conversation-binding-data-BHRpYbX3.js +121 -0
  9. package/dist/doctor-contract-api.js +439 -22
  10. package/dist/harness.js +29 -10
  11. package/dist/index.js +1117 -19
  12. package/dist/{media-understanding-provider-BOeoBhEw.js → media-understanding-provider-DgqRvU2_.js} +13 -8
  13. package/dist/media-understanding-provider.js +1 -1
  14. package/dist/{models-DpzY1xpp.js → models-DDmO1zwd.js} +2 -2
  15. package/dist/notification-correlation-Bo7KB3ks.js +35 -0
  16. package/dist/{plugin-app-cache-key-BrZUG9jj.js → plugin-app-cache-key-o-AHbdaf.js} +8 -4
  17. package/dist/{protocol-dh-ETiNd.js → protocol-2POPqAY4.js} +2 -1
  18. package/dist/{protocol-validators-CJiWigAJ.js → protocol-validators-dZQ-UTOa.js} +116 -59
  19. package/dist/{provider-capabilities-wqedK49Z.js → provider-capabilities-gTCwjfmh.js} +2916 -114
  20. package/dist/{provider-nmtMDcGH.js → provider-cc_62eQE.js} +19 -10
  21. package/dist/provider.js +2 -2
  22. package/dist/{request-BQuSQF29.js → request-BcJyl8KL.js} +2 -2
  23. package/dist/{run-attempt-DikbXia_.js → run-attempt-8SPLiDlT.js} +907 -3002
  24. package/dist/{sandbox-guard-pTY2COoC.js → sandbox-guard-DA2TQfZW.js} +3 -3
  25. package/dist/session-binding-Dc03iwRF.js +595 -0
  26. package/dist/session-binding-meta-B7aEMU7g.js +6 -0
  27. package/dist/{shared-client-rR6TDJA3.js → shared-client-4ICy3U6d.js} +892 -103
  28. package/dist/{side-question-Ca9wqmd0.js → side-question-DkjXvYv7.js} +132 -140
  29. package/dist/{thread-lifecycle-D6R40plk.js → thread-lifecycle-BskXnNP-.js} +609 -444
  30. package/dist/{web-search-provider.runtime-B6eZEFmd.js → web-search-provider.runtime-B5F42P7x.js} +3 -3
  31. package/npm-shrinkwrap.json +34 -34
  32. package/openclaw.plugin.json +20 -0
  33. package/package.json +9 -6
  34. package/dist/client-IcTBKEqA.js +0 -732
  35. package/dist/client-factory-DfFu9JH_.js +0 -15
  36. package/dist/compact-CILptrPS.js +0 -278
  37. package/dist/conversation-binding-DOJtUxOy.js +0 -1570
  38. package/dist/rate-limit-cache-C7qmZ0Jh.js +0 -26
  39. package/dist/session-binding-Cm0Gg7Z1.js +0 -339
@@ -130,7 +130,7 @@ function readRuntimeSessionEntryBestEffort(params) {
130
130
  }
131
131
  //#endregion
132
132
  //#region extensions/codex/src/app-server/sandbox-guard.ts
133
- const DIRECT_METHOD_POLICIES = new Map([
133
+ const DIRECT_METHOD_POLICIES = /* @__PURE__ */ new Map([
134
134
  ["account/rateLimits/read", "allowed-control-plane"],
135
135
  ["account/read", "allowed-control-plane"],
136
136
  ["app/list", "allowed-control-plane"],
@@ -153,7 +153,7 @@ const DIRECT_METHOD_POLICIES = new Map([
153
153
  ["thread/inject_items", "allowed-control-plane"],
154
154
  ["thread/list", "allowed-control-plane"],
155
155
  ["thread/metadata/update", "allowed-control-plane"],
156
- ["thread/name/update", "allowed-control-plane"],
156
+ ["thread/name/set", "allowed-control-plane"],
157
157
  ["thread/read", "allowed-control-plane"],
158
158
  ["thread/rollback", "allowed-control-plane"],
159
159
  ["thread/start", "requires-openclaw-environment"],
@@ -184,7 +184,7 @@ const BLOCKED_DIRECT_METHOD_PREFIXES = [
184
184
  "fs/",
185
185
  "windowsSandbox/"
186
186
  ];
187
- const NODE_EXEC_BLOCKED_CONTROL_PLANE_METHODS = new Set(["config/mcpServer/reload"]);
187
+ const NODE_EXEC_BLOCKED_CONTROL_PLANE_METHODS = /* @__PURE__ */ new Set(["config/mcpServer/reload"]);
188
188
  /** Returns a block message when a direct app-server method would bypass OpenClaw execution policy. */
189
189
  function resolveCodexAppServerDirectSandboxBypassBlock(params) {
190
190
  const policy = resolveDirectMethodPolicy(params.method);
@@ -0,0 +1,595 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
+ import { l as normalizeCodexServiceTier, t as CODEX_PLUGINS_MARKETPLACE_NAME } from "./config-CYEDnLJ2.js";
3
+ import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./session-binding-meta-B7aEMU7g.js";
4
+ import { createHash, randomUUID } from "node:crypto";
5
+ import { ensureAuthProfileStore, resolveDefaultAgentDir, resolveProviderIdForAuth, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
6
+ import { z } from "zod";
7
+ import { embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-runtime";
8
+ import { AsyncLocalStorage } from "node:async_hooks";
9
+ import { loadSessionStore, resolveSessionStoreEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
10
+ //#region extensions/codex/src/app-server/session-binding.ts
11
+ /** SQLite-backed Codex app-server thread bindings. */
12
+ var session_binding_exports = /* @__PURE__ */ __exportAll({
13
+ CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS: () => CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS,
14
+ CODEX_APP_SERVER_BINDING_MAX_ENTRIES: () => CODEX_APP_SERVER_BINDING_MAX_ENTRIES,
15
+ CODEX_APP_SERVER_BINDING_NAMESPACE: () => CODEX_APP_SERVER_BINDING_NAMESPACE,
16
+ bindingStoreKey: () => bindingStoreKey,
17
+ createCodexAppServerBindingStore: () => createCodexAppServerBindingStore,
18
+ createStoredCodexAppServerBinding: () => createStoredCodexAppServerBinding,
19
+ isCodexAppServerNativeAuthProfile: () => isCodexAppServerNativeAuthProfile,
20
+ normalizeCodexAppServerBindingModelProvider: () => normalizeCodexAppServerBindingModelProvider,
21
+ readCodexAppServerThreadBinding: () => readCodexAppServerThreadBinding,
22
+ reclaimCurrentCodexSessionGeneration: () => reclaimCurrentCodexSessionGeneration,
23
+ resolveCodexAppServerBindingModelProvider: () => resolveCodexAppServerBindingModelProvider,
24
+ sessionBindingIdentity: () => sessionBindingIdentity
25
+ });
26
+ const CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER = "openai";
27
+ const PUBLIC_OPENAI_MODEL_PROVIDER = "openai";
28
+ const BINDING_LEASE_RETRY_INTERVAL_MS = 1e3;
29
+ const CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS = 6e4;
30
+ const BINDING_LEASE_STALE_MS = 65e3;
31
+ const BINDING_LEASE_WAIT_MS = 7e4;
32
+ const BINDING_LEASE_RENEW_INTERVAL_MS = Math.floor(BINDING_LEASE_STALE_MS / 3);
33
+ const PHYSICAL_SESSION_RETIRE_TTL_MS = BINDING_LEASE_WAIT_MS;
34
+ /** Resolves the same agent scope OpenClaw uses for transcript/session ownership. */
35
+ function sessionBindingIdentity(params) {
36
+ const { sessionAgentId } = resolveSessionAgentIds(params);
37
+ const sessionKey = params.sessionKey?.trim();
38
+ return {
39
+ kind: "session",
40
+ agentId: sessionAgentId,
41
+ sessionId: params.sessionId,
42
+ ...sessionKey ? { sessionKey } : {}
43
+ };
44
+ }
45
+ const optionalStringSchema = z.string().optional().catch(void 0);
46
+ const optionalBooleanSchema = z.boolean().optional().catch(void 0);
47
+ const optionalNonBlankStringSchema = z.string().refine((value) => Boolean(value.trim())).optional().catch(void 0);
48
+ const optionalTimestampSchema = z.string().refine((value) => Number.isFinite(Date.parse(value))).optional().catch(void 0);
49
+ const contextEngineProjectionSchema = z.object({
50
+ schemaVersion: z.literal(1),
51
+ mode: z.literal("thread_bootstrap"),
52
+ epoch: z.string().refine((value) => Boolean(value.trim())),
53
+ fingerprint: optionalStringSchema
54
+ }).strict();
55
+ const contextEngineSchema = z.object({
56
+ schemaVersion: z.literal(1),
57
+ engineId: z.string(),
58
+ policyFingerprint: z.string(),
59
+ projection: contextEngineProjectionSchema.optional().catch(void 0)
60
+ }).strict();
61
+ const destructiveApprovalModeSchema = z.enum([
62
+ "allow",
63
+ "deny",
64
+ "auto",
65
+ "ask"
66
+ ]).optional().catch(void 0);
67
+ const accountAppPolicyEntrySchema = z.object({
68
+ source: z.literal("account"),
69
+ appName: z.string(),
70
+ allowDestructiveActions: z.boolean(),
71
+ destructiveApprovalMode: destructiveApprovalModeSchema,
72
+ mcpServerNames: z.array(z.string())
73
+ }).strict();
74
+ const pluginAppPolicyEntrySchema = z.object({
75
+ source: z.literal("plugin").optional(),
76
+ configKey: z.string(),
77
+ marketplaceName: z.literal(CODEX_PLUGINS_MARKETPLACE_NAME),
78
+ pluginName: z.string(),
79
+ allowDestructiveActions: z.boolean(),
80
+ destructiveApprovalMode: destructiveApprovalModeSchema,
81
+ mcpServerNames: z.array(z.string())
82
+ }).strict();
83
+ const pluginAppPolicyContextSchema = z.object({
84
+ fingerprint: z.string(),
85
+ apps: z.record(z.string(), z.union([accountAppPolicyEntrySchema, pluginAppPolicyEntrySchema])),
86
+ pluginAppIds: z.record(z.string(), z.array(z.string())).default({})
87
+ }).strict();
88
+ const threadBindingSchema = z.object({
89
+ threadId: z.string().refine((value) => Boolean(value.trim())),
90
+ cwd: z.string(),
91
+ authProfileId: optionalStringSchema,
92
+ model: optionalStringSchema,
93
+ modelProvider: z.string().transform((value) => value.trim()).pipe(z.string().min(1)).optional().catch(void 0),
94
+ approvalPolicy: z.preprocess((value) => value === "on-failure" ? "on-request" : value, z.enum([
95
+ "never",
96
+ "on-request",
97
+ "untrusted"
98
+ ]).optional()).catch(void 0),
99
+ sandbox: z.enum([
100
+ "read-only",
101
+ "workspace-write",
102
+ "danger-full-access"
103
+ ]).optional().catch(void 0),
104
+ serviceTier: z.preprocess(normalizeCodexServiceTier, z.custom((value) => typeof value === "string").optional()).optional().catch(void 0),
105
+ networkProxyProfileName: optionalStringSchema,
106
+ networkProxyConfigFingerprint: optionalStringSchema,
107
+ dynamicToolsFingerprint: optionalStringSchema,
108
+ dynamicToolsContainDeferred: optionalBooleanSchema,
109
+ webSearchThreadConfigFingerprint: optionalStringSchema,
110
+ userMcpServersFingerprint: optionalStringSchema,
111
+ mcpServersFingerprint: optionalStringSchema,
112
+ nativeHookRelayGeneration: optionalNonBlankStringSchema,
113
+ appServerRuntimeFingerprint: optionalStringSchema,
114
+ pluginAppsFingerprint: optionalStringSchema,
115
+ pluginAppsInputFingerprint: optionalStringSchema,
116
+ pluginAppPolicyContext: pluginAppPolicyContextSchema.optional().catch(void 0),
117
+ contextEngine: contextEngineSchema.optional().catch(void 0),
118
+ environmentSelectionFingerprint: optionalStringSchema,
119
+ conversationStartId: optionalStringSchema,
120
+ conversationSourceTransferComplete: z.literal(true).optional().catch(void 0),
121
+ historyCoveredThrough: optionalTimestampSchema
122
+ });
123
+ const bindingLeaseSchema = z.object({
124
+ token: z.string().refine((value) => Boolean(value.trim())),
125
+ expiresAt: z.number().finite()
126
+ });
127
+ const storedSessionIdSchema = z.string().transform((value) => value.trim()).pipe(z.string().min(1)).optional().catch(void 0);
128
+ const storedBindingSchema = z.discriminatedUnion("state", [z.object({
129
+ version: z.literal(1),
130
+ state: z.literal("active"),
131
+ binding: threadBindingSchema,
132
+ sessionId: storedSessionIdSchema,
133
+ lease: bindingLeaseSchema.optional().catch(void 0)
134
+ }), z.object({
135
+ version: z.literal(1),
136
+ state: z.literal("cleared"),
137
+ sessionId: storedSessionIdSchema,
138
+ lease: bindingLeaseSchema.optional().catch(void 0),
139
+ retired: z.literal(true).optional().catch(void 0)
140
+ })]);
141
+ /** Encodes a migrated sidecar binding as one canonical plugin-state row. */
142
+ function createStoredCodexAppServerBinding(value, options = {}) {
143
+ const record = asRecord(value);
144
+ if (!record) return;
145
+ if (record.schemaVersion !== 1 && record.schemaVersion !== 2) return;
146
+ const pluginAppPolicyContext = readPluginAppPolicyContext(record.pluginAppPolicyContext, record.schemaVersion);
147
+ const historyCoveredThrough = readTimestamp(record.historyCoveredThrough) ?? readTimestamp(record.updatedAt) ?? readTimestamp(record.createdAt) ?? readTimestamp(options.now) ?? (/* @__PURE__ */ new Date()).toISOString();
148
+ const authProfileId = typeof record.authProfileId === "string" ? record.authProfileId : void 0;
149
+ const binding = readCodexAppServerThreadBinding({
150
+ ...record,
151
+ modelProvider: normalizeCodexAppServerBindingModelProvider({
152
+ ...options.lookup,
153
+ authProfileId,
154
+ modelProvider: typeof record.modelProvider === "string" ? record.modelProvider : void 0
155
+ }),
156
+ cwd: typeof record.cwd === "string" ? record.cwd : "",
157
+ pluginAppPolicyContext,
158
+ historyCoveredThrough
159
+ });
160
+ return binding ? {
161
+ version: 1,
162
+ state: "active",
163
+ binding: stripUndefinedBinding(binding)
164
+ } : void 0;
165
+ }
166
+ function bindingLeaseLostError(key, cause) {
167
+ return new Error(`Lost Codex binding lease: ${key}`, cause === void 0 ? void 0 : { cause });
168
+ }
169
+ /** Lets the authoritative OpenClaw session generation claim a stale stable binding row. */
170
+ async function reclaimCurrentCodexSessionGeneration(params) {
171
+ const sessionKey = params.identity.sessionKey?.trim();
172
+ if (!sessionKey) return true;
173
+ const plan = await params.bindingStore.prepareSessionGenerationReclaim(params.identity);
174
+ if (plan.kind === "resolved") return plan.result;
175
+ try {
176
+ if (resolveSessionStoreEntry({
177
+ store: loadSessionStore(resolveStorePath(params.config?.session?.store, { agentId: params.identity.agentId }), {
178
+ skipCache: true,
179
+ hydrateSkillPromptRefs: false
180
+ }),
181
+ sessionKey
182
+ }).existing?.sessionId !== params.identity.sessionId) return false;
183
+ } catch {
184
+ return false;
185
+ }
186
+ return await params.bindingStore.mutate(params.identity, {
187
+ kind: "reclaim-generation",
188
+ expectedPreviousSessionId: plan.expectedPreviousSessionId
189
+ });
190
+ }
191
+ /** Creates the single binding facade owned by the Codex plugin runtime. */
192
+ function createCodexAppServerBindingStore(state) {
193
+ const update = state.update?.bind(state);
194
+ if (!update) throw new Error("Codex app-server bindings require atomic plugin-state updates");
195
+ const leaseContext = new AsyncLocalStorage();
196
+ const renewLease = (key, owner) => {
197
+ if (owner.failure) return;
198
+ try {
199
+ let renewed = false;
200
+ const stored = update(key, (raw) => {
201
+ const current = readStoredBinding(raw);
202
+ if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
203
+ const lease = current?.lease;
204
+ const now = Date.now();
205
+ if (!lease || lease.token !== owner.token || lease.expiresAt <= now) return;
206
+ renewed = true;
207
+ return {
208
+ ...current,
209
+ lease: {
210
+ token: owner.token,
211
+ expiresAt: now + BINDING_LEASE_STALE_MS
212
+ }
213
+ };
214
+ });
215
+ if (!renewed || !stored) owner.failure = bindingLeaseLostError(key);
216
+ } catch (error) {
217
+ owner.failure = bindingLeaseLostError(key, error);
218
+ }
219
+ };
220
+ const transactKey = async (key, apply, ttlMs) => {
221
+ const deadline = Date.now() + BINDING_LEASE_WAIT_MS;
222
+ while (true) {
223
+ let busy = false;
224
+ let leaseLost = false;
225
+ let result;
226
+ const ownedLease = leaseContext.getStore()?.get(key);
227
+ if (ownedLease?.failure) throw ownedLease.failure;
228
+ const ownedToken = ownedLease?.token;
229
+ update(key, (raw) => {
230
+ const current = readStoredBinding(raw);
231
+ if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
232
+ const activeLease = current?.lease;
233
+ const now = Date.now();
234
+ if (ownedToken && (!activeLease || activeLease.token !== ownedToken || activeLease.expiresAt <= now)) {
235
+ leaseLost = true;
236
+ return;
237
+ }
238
+ if (activeLease && activeLease.token !== ownedToken && activeLease.expiresAt > now) {
239
+ busy = true;
240
+ return;
241
+ }
242
+ const applied = apply(current, ownedToken);
243
+ result = applied.result;
244
+ return applied.next;
245
+ }, ttlMs == null ? void 0 : { ttlMs });
246
+ if (leaseLost) {
247
+ const failure = bindingLeaseLostError(key);
248
+ if (ownedLease) ownedLease.failure = failure;
249
+ throw failure;
250
+ }
251
+ if (!busy) return result;
252
+ if (Date.now() >= deadline) throw new Error(`Timed out waiting for Codex binding lease: ${key}`);
253
+ await sleep(BINDING_LEASE_RETRY_INTERVAL_MS);
254
+ }
255
+ };
256
+ return {
257
+ async read(identity) {
258
+ const key = bindingStoreKey(identity);
259
+ const raw = state.lookup(key);
260
+ const stored = readStoredBinding(raw);
261
+ if (raw !== void 0 && !stored) throw new Error(`Invalid Codex app-server binding row: ${key}`);
262
+ return stored?.state === "active" && ownsStoredSessionGeneration(identity, stored) ? stored.binding : void 0;
263
+ },
264
+ async prepareSessionGenerationReclaim(identity) {
265
+ const key = bindingStoreKey(identity);
266
+ const raw = state.lookup(key);
267
+ const current = readStoredBinding(raw);
268
+ if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
269
+ if (!current) return {
270
+ kind: "resolved",
271
+ result: true
272
+ };
273
+ const currentSessionId = current.sessionId;
274
+ if (!currentSessionId || currentSessionId === identity.sessionId) return {
275
+ kind: "resolved",
276
+ result: current.state !== "cleared" || current.retired !== true
277
+ };
278
+ return {
279
+ kind: "verify",
280
+ expectedPreviousSessionId: currentSessionId
281
+ };
282
+ },
283
+ async mutate(identity, mutation) {
284
+ const key = bindingStoreKey(identity);
285
+ const retainLegacyClear = mutation.kind === "clear" && key.startsWith("conversation:legacy-");
286
+ return await transactKey(key, (current, leaseToken) => {
287
+ const ownsGeneration = ownsStoredSessionGeneration(identity, current);
288
+ const ownedLease = current?.lease && current.lease.token === leaseToken ? { lease: current.lease } : {};
289
+ if (mutation.kind === "reclaim-generation") {
290
+ if (identity.kind !== "session" || !identity.sessionKey?.trim()) return { result: false };
291
+ if (!current) return { result: true };
292
+ if (ownsGeneration) return { result: current.state !== "cleared" || current.retired !== true };
293
+ if (current.sessionId !== mutation.expectedPreviousSessionId) return { result: false };
294
+ return {
295
+ result: true,
296
+ next: {
297
+ version: 1,
298
+ state: "cleared",
299
+ sessionId: identity.sessionId,
300
+ ...ownedLease
301
+ }
302
+ };
303
+ }
304
+ const storedActive = current?.state === "active" ? current : void 0;
305
+ const active = ownsGeneration ? storedActive : void 0;
306
+ const retiredGeneration = current?.state === "cleared" && current.retired === true && ownsGeneration;
307
+ if (mutation.kind === "set" && (mutation.if?.kind === "absent" && storedActive || current !== void 0 && !ownsGeneration || retiredGeneration) || mutation.kind === "patch" && active?.binding.threadId !== mutation.threadId || mutation.kind === "clear" && (mutation.threadId !== void 0 && active?.binding.threadId !== mutation.threadId || !ownsGeneration)) return { result: false };
308
+ if (mutation.kind === "clear" && retiredGeneration) return { result: true };
309
+ if (mutation.kind === "clear") return {
310
+ result: true,
311
+ next: {
312
+ version: 1,
313
+ state: "cleared",
314
+ ...storedSessionGeneration(identity, current),
315
+ ...ownedLease
316
+ }
317
+ };
318
+ let binding;
319
+ if (mutation.kind === "set") binding = validateBindingForWrite(mutation.binding);
320
+ else binding = validateBindingForWrite({
321
+ ...active.binding,
322
+ ...mutation.patch,
323
+ threadId: mutation.threadId
324
+ });
325
+ return {
326
+ result: true,
327
+ next: {
328
+ version: 1,
329
+ state: "active",
330
+ binding,
331
+ ...storedSessionGeneration(identity, current),
332
+ ...ownedLease
333
+ }
334
+ };
335
+ }, mutation.kind === "clear" && !retainLegacyClear && !leaseContext.getStore()?.has(key) ? 1 : void 0);
336
+ },
337
+ async adoptSessionGeneration(identity, expectedPreviousSessionId) {
338
+ const key = bindingStoreKey(identity);
339
+ const expectedSessionId = expectedPreviousSessionId.trim();
340
+ const targetSessionId = identity.sessionId.trim();
341
+ if (!expectedSessionId) throw new Error("Codex session generation adoption requires the previous session id");
342
+ return await transactKey(key, (current) => {
343
+ if (current?.state !== "active") return { result: "absent" };
344
+ if (current.sessionId === targetSessionId) return { result: "current" };
345
+ if (current.sessionId !== expectedSessionId) return { result: "conflict" };
346
+ return {
347
+ result: "adopted",
348
+ next: {
349
+ ...current,
350
+ sessionId: targetSessionId
351
+ }
352
+ };
353
+ });
354
+ },
355
+ async retireSessionGeneration(identity) {
356
+ const key = bindingStoreKey(identity);
357
+ return await transactKey(key, (current, leaseToken) => {
358
+ if (!current) return { result: "absent" };
359
+ if (!ownsStoredSessionGeneration(identity, current)) return { result: "conflict" };
360
+ if (current.state === "cleared" && current.retired === true) return { result: "applied" };
361
+ return {
362
+ result: "applied",
363
+ next: {
364
+ version: 1,
365
+ state: "cleared",
366
+ retired: true,
367
+ ...storedSessionGeneration(identity, current),
368
+ ...current.lease && current.lease.token === leaseToken ? { lease: current.lease } : {}
369
+ }
370
+ };
371
+ }, identity.sessionKey?.trim() ? void 0 : PHYSICAL_SESSION_RETIRE_TTL_MS);
372
+ },
373
+ async withLease(identity, run) {
374
+ const key = bindingStoreKey(identity);
375
+ const owned = leaseContext.getStore();
376
+ const existingOwner = owned?.get(key);
377
+ if (existingOwner) {
378
+ const failureBeforeRun = existingOwner.failure;
379
+ if (failureBeforeRun) throw failureBeforeRun;
380
+ const result = await run();
381
+ const failureAfterRun = existingOwner.failure;
382
+ if (failureAfterRun) throw failureAfterRun;
383
+ return result;
384
+ }
385
+ const token = randomUUID();
386
+ if (!await transactKey(key, (current) => {
387
+ if (current?.state === "cleared" && current.retired === true && ownsStoredSessionGeneration(identity, current)) return { result: false };
388
+ const lease = {
389
+ token,
390
+ expiresAt: Date.now() + BINDING_LEASE_STALE_MS
391
+ };
392
+ if (current?.state === "active") return {
393
+ result: true,
394
+ next: {
395
+ ...current,
396
+ ...preservedSessionGeneration(identity, current),
397
+ lease
398
+ }
399
+ };
400
+ if (current?.state === "cleared" && current.retired === true) return {
401
+ result: true,
402
+ next: {
403
+ ...current,
404
+ lease
405
+ }
406
+ };
407
+ return {
408
+ result: true,
409
+ next: {
410
+ version: 1,
411
+ state: "cleared",
412
+ ...preservedSessionGeneration(identity, current),
413
+ lease
414
+ }
415
+ };
416
+ })) throw new Error(`Codex binding generation was retired: ${key}`);
417
+ const owner = { token };
418
+ const nested = new Map(owned);
419
+ nested.set(key, owner);
420
+ const heartbeat = setInterval(() => renewLease(key, owner), BINDING_LEASE_RENEW_INTERVAL_MS);
421
+ heartbeat.unref();
422
+ try {
423
+ const result = await leaseContext.run(nested, run);
424
+ if (owner.failure) throw owner.failure;
425
+ return result;
426
+ } finally {
427
+ clearInterval(heartbeat);
428
+ try {
429
+ const removeOwnedLease = (raw, matches) => {
430
+ const current = readStoredBinding(raw);
431
+ if (!current || !matches(current) || current.lease?.token !== token) return;
432
+ const { lease: _lease, ...released } = current;
433
+ return released;
434
+ };
435
+ if (!update(key, (raw) => removeOwnedLease(raw, (current) => current.state === "active"))) {
436
+ if (!update(key, (raw) => removeOwnedLease(raw, (current) => current.state === "cleared" && current.retired === true), key.startsWith("session:") ? { ttlMs: PHYSICAL_SESSION_RETIRE_TTL_MS } : void 0)) update(key, (raw) => removeOwnedLease(raw, (current) => current.state === "cleared"), { ttlMs: 1 });
437
+ }
438
+ } catch (error) {
439
+ embeddedAgentLog.warn("failed to release codex app-server binding lease", {
440
+ key,
441
+ error
442
+ });
443
+ }
444
+ }
445
+ }
446
+ };
447
+ }
448
+ /** Stable plugin-state key for one current binding owner. */
449
+ function bindingStoreKey(identity) {
450
+ if (identity.kind === "session") {
451
+ const rawAgentId = identity.agentId.trim();
452
+ const sessionId = identity.sessionId.trim();
453
+ if (!rawAgentId) throw new Error("Codex app-server binding requires an agent id");
454
+ if (!sessionId) throw new Error("Codex app-server binding requires a session id");
455
+ const agentId = resolveSessionAgentIds({ agentId: rawAgentId }).sessionAgentId;
456
+ const sessionKey = identity.sessionKey?.trim();
457
+ if (sessionKey) return `session-key:${agentId}:${createHash("sha256").update(sessionKey).digest("base64url")}`;
458
+ return `session:${agentId}:${sessionId}`;
459
+ }
460
+ const bindingId = identity.bindingId.trim();
461
+ if (!bindingId) throw new Error("Codex app-server conversation binding requires a binding id");
462
+ return `conversation:${bindingId}`;
463
+ }
464
+ function readStoredBinding(value) {
465
+ const result = storedBindingSchema.safeParse(value);
466
+ return result.success ? stripUndefinedValue(result.data) : void 0;
467
+ }
468
+ function storedSessionGeneration(identity, current) {
469
+ if (identity.kind === "session") return { sessionId: identity.sessionId };
470
+ return current?.sessionId ? { sessionId: current.sessionId } : {};
471
+ }
472
+ function preservedSessionGeneration(identity, current) {
473
+ if (current?.sessionId) return { sessionId: current.sessionId };
474
+ return storedSessionGeneration(identity, current);
475
+ }
476
+ function ownsStoredSessionGeneration(identity, current) {
477
+ return identity.kind !== "session" || !current?.sessionId || current.sessionId === identity.sessionId;
478
+ }
479
+ function validateBindingForWrite(binding) {
480
+ const validated = readCodexAppServerThreadBinding(binding);
481
+ if (!validated) throw new Error("Invalid Codex app-server thread binding");
482
+ return stripUndefinedBinding(validated);
483
+ }
484
+ /** Parses stored or shipped sidecar data into the current domain value. */
485
+ function readCodexAppServerThreadBinding(value) {
486
+ const result = threadBindingSchema.safeParse(value);
487
+ if (!result.success) return;
488
+ return result.data;
489
+ }
490
+ function stripUndefinedBinding(binding) {
491
+ return stripUndefinedValue(binding);
492
+ }
493
+ function stripUndefinedValue(value) {
494
+ if (Array.isArray(value)) return value.map(stripUndefinedValue);
495
+ if (!value || typeof value !== "object") return value;
496
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0).map(([key, entry]) => [key, stripUndefinedValue(entry)]));
497
+ }
498
+ function asRecord(value) {
499
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
500
+ }
501
+ function readTimestamp(value) {
502
+ return optionalTimestampSchema.parse(value);
503
+ }
504
+ function readPluginAppPolicyContext(value, bindingSchemaVersion) {
505
+ const record = asRecord(value);
506
+ if (!record || typeof record.fingerprint !== "string") return;
507
+ const apps = asRecord(record.apps);
508
+ if (!apps) return;
509
+ const parsedApps = {};
510
+ for (const [appId, rawEntry] of Object.entries(apps)) {
511
+ const entry = asRecord(rawEntry);
512
+ if (!entry) return;
513
+ const destructiveApprovalMode = readDestructiveApprovalMode(entry.destructiveApprovalMode, bindingSchemaVersion);
514
+ const mcpServerNamesValid = Array.isArray(entry.mcpServerNames) && entry.mcpServerNames.every((serverName) => typeof serverName === "string");
515
+ if (entry.source === "account") {
516
+ if ("appId" in entry || typeof entry.appName !== "string" || typeof entry.allowDestructiveActions !== "boolean" || destructiveApprovalMode === "invalid" || !mcpServerNamesValid) return;
517
+ parsedApps[appId] = {
518
+ source: "account",
519
+ appName: entry.appName,
520
+ allowDestructiveActions: entry.allowDestructiveActions,
521
+ ...destructiveApprovalMode ? { destructiveApprovalMode } : {},
522
+ mcpServerNames: entry.mcpServerNames
523
+ };
524
+ continue;
525
+ }
526
+ if ("appId" in entry || entry.source !== void 0 && entry.source !== "plugin" || typeof entry.configKey !== "string" || entry.marketplaceName !== "openai-curated" || typeof entry.pluginName !== "string" || typeof entry.allowDestructiveActions !== "boolean" || destructiveApprovalMode === "invalid" || !mcpServerNamesValid) return;
527
+ parsedApps[appId] = {
528
+ configKey: entry.configKey,
529
+ marketplaceName: entry.marketplaceName,
530
+ pluginName: entry.pluginName,
531
+ allowDestructiveActions: entry.allowDestructiveActions,
532
+ ...destructiveApprovalMode ? { destructiveApprovalMode } : {},
533
+ mcpServerNames: entry.mcpServerNames
534
+ };
535
+ }
536
+ const parsedPluginAppIds = {};
537
+ if (record.pluginAppIds !== void 0 && (!record.pluginAppIds || typeof record.pluginAppIds !== "object" || Array.isArray(record.pluginAppIds))) return;
538
+ if (record.pluginAppIds && typeof record.pluginAppIds === "object") for (const [configKey, appIds] of Object.entries(record.pluginAppIds)) {
539
+ if (!Array.isArray(appIds) || appIds.some((appId) => typeof appId !== "string")) return;
540
+ parsedPluginAppIds[configKey] = appIds;
541
+ }
542
+ return {
543
+ fingerprint: record.fingerprint,
544
+ apps: parsedApps,
545
+ pluginAppIds: parsedPluginAppIds
546
+ };
547
+ }
548
+ function readDestructiveApprovalMode(value, bindingSchemaVersion) {
549
+ if (value === void 0) return;
550
+ if (value === "allow" || value === "deny") return value;
551
+ if (value === "auto") return bindingSchemaVersion === 1 ? "allow" : "auto";
552
+ if (value === "ask" && bindingSchemaVersion === 2) return "ask";
553
+ if (value === "on-request" && bindingSchemaVersion === 1) return "auto";
554
+ return "invalid";
555
+ }
556
+ function sleep(ms) {
557
+ return new Promise((resolve) => {
558
+ setTimeout(resolve, ms);
559
+ });
560
+ }
561
+ /** Returns true when an auth profile uses native Codex/OpenAI app-server auth. */
562
+ function isCodexAppServerNativeAuthProfile(lookup) {
563
+ const authProfileId = lookup.authProfileId?.trim();
564
+ if (!authProfileId) return false;
565
+ try {
566
+ const credential = (lookup.authProfileStore ?? ensureAuthProfileStore(lookup.agentDir?.trim() || resolveDefaultAgentDir(lookup.config ?? {}), {
567
+ allowKeychainPrompt: false,
568
+ config: lookup.config,
569
+ externalCliProviderIds: [CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER],
570
+ externalCliProfileIds: [authProfileId]
571
+ })).profiles[authProfileId];
572
+ if (!credential || credential.type === "api_key") return false;
573
+ const provider = credential.provider?.trim();
574
+ return Boolean(provider && resolveProviderIdForAuth(provider, { config: lookup.config }) === CODEX_APP_SERVER_NATIVE_AUTH_PROVIDER);
575
+ } catch (error) {
576
+ embeddedAgentLog.debug("failed to resolve codex app-server auth profile provider", {
577
+ authProfileId,
578
+ error
579
+ });
580
+ return false;
581
+ }
582
+ }
583
+ /** Hides redundant OpenAI provider attribution for native Codex auth bindings. */
584
+ function normalizeCodexAppServerBindingModelProvider(params) {
585
+ const modelProvider = params.modelProvider?.trim();
586
+ if (!modelProvider) return;
587
+ if (isCodexAppServerNativeAuthProfile(params) && modelProvider.toLowerCase() === PUBLIC_OPENAI_MODEL_PROVIDER) return;
588
+ return modelProvider;
589
+ }
590
+ /** Restores the sole provider intentionally omitted from canonical binding rows. */
591
+ function resolveCodexAppServerBindingModelProvider(params) {
592
+ return params.modelProvider?.trim() || (isCodexAppServerNativeAuthProfile(params) ? PUBLIC_OPENAI_MODEL_PROVIDER : void 0);
593
+ }
594
+ //#endregion
595
+ export { reclaimCurrentCodexSessionGeneration as a, normalizeCodexAppServerBindingModelProvider as i, bindingStoreKey as n, sessionBindingIdentity as o, isCodexAppServerNativeAuthProfile as r, session_binding_exports as s, CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS as t };
@@ -0,0 +1,6 @@
1
+ //#region extensions/codex/src/app-server/session-binding-meta.ts
2
+ /** Process-stable plugin-state metadata for Codex app-server bindings. */
3
+ const CODEX_APP_SERVER_BINDING_NAMESPACE = "app-server-thread-bindings";
4
+ const CODEX_APP_SERVER_BINDING_MAX_ENTRIES = 5e4;
5
+ //#endregion
6
+ export { CODEX_APP_SERVER_BINDING_NAMESPACE as n, CODEX_APP_SERVER_BINDING_MAX_ENTRIES as t };