@openclaw/codex 2026.8.1-beta.3 → 2026.8.1
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 +4 -5
- package/dist/{attempt-client-cleanup-URjUlCHg.js → attempt-client-cleanup-CVPvp9dL.js} +47 -5
- package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
- package/dist/{binding-connection-DAvZwp96.js → binding-connection-CCQFs8lf.js} +2 -2
- package/dist/{bounded-turn-4BjrZEwW.js → bounded-turn-rq5tiSXk.js} +13 -18
- package/dist/{capabilities-CH3K57v4.js → capabilities-CGm_94eL.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-D0nZ3qtd.js → command-formatters-C54Yg3eA.js} +2 -2
- package/dist/{command-handlers-DC86lgT4.js → command-handlers-BvOAHTrA.js} +89 -62
- package/dist/{compact-COqgBRny.js → compact-Hd7SAc0N.js} +8 -9
- package/dist/{config-CpNeo5AE.js → config-Cxw3Cl3k.js} +346 -286
- package/dist/doctor-contract-api.js +115 -14
- package/dist/{dynamic-tools-fJZhl4CE.js → dynamic-tools-BFoUcRdx.js} +147 -903
- package/dist/{effective-mcp-catalog-4YKn51aG.js → effective-mcp-catalog-BTJHnDSx.js} +2 -2
- package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
- package/dist/{event-projector-usage-CLwNEJqW.js → event-projector-usage-D3PHFFXh.js} +3 -3
- package/dist/{harness-DoKQcF8n.js → harness-DVfUQBlQ.js} +42 -52
- package/dist/harness.js +1 -1
- package/dist/index.js +278 -295
- package/dist/{isolated-completion-DPMtlH9r.js → isolated-completion-Cbbx_5Ed.js} +4 -4
- package/dist/launch-args-sXOAg0SX.js +84 -0
- package/dist/{managed-binary-By4FZC6i.js → managed-binary-ZkGodW19.js} +43 -7
- package/dist/media-understanding-provider.js +1 -1
- package/dist/model-catalog-o6Cgjoss.js +101 -0
- package/dist/{models-CZw1wClT.js → models-DgFWSuxA.js} +25 -28
- package/dist/{native-subagent-monitor-GGq3RnOo.js → native-subagent-monitor-CwFyoylz.js} +207 -30
- package/dist/{node-exec-server.runtime-Bsu1LdFZ.js → node-exec-server.runtime-DXrqpw1c.js} +8 -5
- package/dist/{plugin-approval-roundtrip-C75Yiiwc.js → plugin-approval-roundtrip-D80UZiJ_.js} +1 -1
- package/dist/{plugin-marketplace-discovery-CSWDkMrP.js → plugin-marketplace-discovery-mdmScYOj.js} +30 -39
- package/dist/{plugin-metadata-cache-BXH5NF-4.js → plugin-metadata-cache-CulOABwu.js} +162 -135
- package/dist/{protocol-validators-VAVyEnDp.js → protocol-validators-Bg5rpNxk.js} +148 -5
- package/dist/{rate-limits-BI1dMHDG.js → rate-limits-hFtzt2Up.js} +1 -1
- package/dist/{sandbox-guard-C1qEeZ5C.js → request-CCm4LaED.js} +183 -2
- package/dist/{run-attempt-BV3HzuCf.js → run-attempt-BwNQDH2u.js} +599 -361
- package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-DeBvleJw.js} +1 -1
- package/dist/{session-binding-BTrLf9Qm.js → session-binding-q2WSTVmC.js} +195 -122
- package/dist/{session-catalog-ezP_UcRM.js → session-catalog-C2Tae4rI.js} +229 -122
- package/dist/session-catalog-home-id-DAKUrm3C.js +112 -0
- package/dist/{session-cli-B1hKvfkI.js → session-cli-BuDjm5Ou.js} +1 -1
- package/dist/session-permission-policy-gLm40Vtq.js +160 -0
- package/dist/session-retirement-CdkI0bvb.js +90 -0
- package/dist/{session-upstream-marker-D_2npHlA.js → session-upstream-marker-Bcy33kam.js} +2 -3
- package/dist/{settled-turn-finalizer-Dx1onIqg.js → settled-turn-finalizer-B8JJcxCi.js} +7 -6
- package/dist/{shared-client-Dw-rzii0.js → shared-client-kNkljY-R.js} +1720 -786
- package/dist/{side-question-DbXkJZzg.js → side-question-GwD73tX6.js} +69 -39
- package/dist/{thread-lifecycle-DKdrnTMX.js → thread-lifecycle-Ss-uwnC4.js} +852 -359
- package/dist/{thread-ownership-i2NBwDUL.js → thread-ownership-CeYBqg_4.js} +18 -8
- package/dist/{plugin-app-cache-key-DMNQ8Zi8.js → thread-resume-DF54hagX.js} +52 -6
- package/dist/{transcript-mirror-BU0_LKAL.js → transcript-mirror-CkEQIna-.js} +112 -13
- package/dist/transport-stdio-C7-s9TLG.js +708 -0
- package/dist/{upstream-session-fork-BDVJCLAD.js → upstream-session-fork-BACGlOFa.js} +78 -86
- package/dist/{usage-9dKJCgcy.js → usage-C2l8Mils.js} +3 -3
- package/dist/{web-search-provider.runtime-DCdx4DGu.js → web-search-provider.runtime-B2XgRdFv.js} +3 -3
- package/openclaw.plugin.json +19 -1
- package/package.json +8 -8
- package/dist/app-server-policy-bg5QPSVP.js +0 -25
- package/dist/command-rpc-xUIIonsO.js +0 -90
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/model-catalog-CmGoqVKB.js +0 -48
- package/dist/request-DSK0W6YI.js +0 -157
- package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
- package/dist/session-retirement-CE4iMiLh.js +0 -36
- package/dist/thread-resume-CdJk2Ehf.js +0 -30
- package/dist/transport-stdio-DhoGy33Z.js +0 -99
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as resolveCodexAppServerSpawnEnv } from "./transport-stdio-
|
|
1
|
+
import { n as resolveCodexAppServerSpawnEnv } from "./transport-stdio-C7-s9TLG.js";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
|
-
import {
|
|
2
|
+
import { A as normalizeCodexServiceTier, N as CODEX_PLUGIN_MARKETPLACE_NAME_PATTERN } from "./config-Cxw3Cl3k.js";
|
|
3
3
|
import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./session-binding-meta-B7aEMU7g.js";
|
|
4
4
|
import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
5
5
|
import { AgentHarnessSessionSupersededError, embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
6
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
7
|
-
import {
|
|
7
|
+
import { isDeepStrictEqual } from "node:util";
|
|
8
|
+
import { ensureAuthProfileStore, resolveDefaultAgentDir, resolveProviderIdForAuth } from "openclaw/plugin-sdk/agent-runtime";
|
|
9
|
+
import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
8
10
|
import { z } from "zod";
|
|
9
11
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
12
|
import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
@@ -42,7 +44,7 @@ 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
45
|
/** Resolves the same agent scope OpenClaw uses for transcript/session ownership. */
|
|
44
46
|
function sessionBindingIdentity(params) {
|
|
45
|
-
const { sessionAgentId } =
|
|
47
|
+
const { sessionAgentId } = resolveSessionAgentIdsStrict(params);
|
|
46
48
|
const sessionKey = params.sessionKey?.trim();
|
|
47
49
|
return {
|
|
48
50
|
kind: "session",
|
|
@@ -147,6 +149,7 @@ const threadBindingSchema = z.object({
|
|
|
147
149
|
model: optionalStringSchema,
|
|
148
150
|
preserveNativeModel: z.literal(true).optional().catch(void 0),
|
|
149
151
|
pendingSupervisionBranch: pendingSupervisionBranchSchema.optional(),
|
|
152
|
+
pendingResumeConfiguration: z.literal(true).optional(),
|
|
150
153
|
modelProvider: z.string().transform((value) => value.trim()).pipe(z.string().min(1)).optional().catch(void 0),
|
|
151
154
|
approvalPolicy: z.preprocess((value) => value === "on-failure" ? "on-request" : value, z.enum([
|
|
152
155
|
"never",
|
|
@@ -318,11 +321,12 @@ function scopeCodexRunBindingStore(params) {
|
|
|
318
321
|
...params.bindingStore,
|
|
319
322
|
read: (identity) => params.bindingStore.read(mapIdentity(identity)),
|
|
320
323
|
hasOtherThreadOwner: (threadId, identity) => params.bindingStore.hasOtherThreadOwner(threadId, identity ? mapIdentity(identity) : void 0),
|
|
321
|
-
mutate: (identity, mutation) => params.bindingStore.mutate(mapIdentity(identity), mutation),
|
|
324
|
+
mutate: (identity, mutation, assertCurrent) => params.bindingStore.mutate(mapIdentity(identity), mutation, assertCurrent),
|
|
322
325
|
prepareSessionGenerationReclaim: (identity) => params.bindingStore.prepareSessionGenerationReclaim(mapSessionIdentity(identity)),
|
|
323
326
|
adoptSessionGeneration: (identity, expectedPreviousSessionId) => params.bindingStore.adoptSessionGeneration(mapSessionIdentity(identity), expectedPreviousSessionId),
|
|
324
327
|
resetSessionGeneration: (identity) => params.bindingStore.resetSessionGeneration(mapSessionIdentity(identity)),
|
|
325
328
|
retireSessionGeneration: (identity) => params.bindingStore.retireSessionGeneration(mapSessionIdentity(identity)),
|
|
329
|
+
withSessionDeletion: (identity, assertCurrent, run) => params.bindingStore.withSessionDeletion(mapSessionIdentity(identity), assertCurrent, run),
|
|
326
330
|
withThreadArchiveFence: (run) => params.bindingStore.withThreadArchiveFence(run),
|
|
327
331
|
withLease: (identity, run) => params.bindingStore.withLease(mapIdentity(identity), run)
|
|
328
332
|
};
|
|
@@ -382,9 +386,10 @@ function createCodexAppServerBindingStore(state) {
|
|
|
382
386
|
}
|
|
383
387
|
};
|
|
384
388
|
const renewLease = (key, owner) => {
|
|
385
|
-
if (owner.failure) return;
|
|
389
|
+
if (owner.failure || owner.phase !== "held") return;
|
|
386
390
|
try {
|
|
387
391
|
let renewed = false;
|
|
392
|
+
owner.assertCurrent?.();
|
|
388
393
|
const stored = update(key, (raw) => {
|
|
389
394
|
const current = readStoredCodexAppServerBinding(raw);
|
|
390
395
|
if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
@@ -405,15 +410,18 @@ function createCodexAppServerBindingStore(state) {
|
|
|
405
410
|
owner.failure = bindingLeaseLostError(key, error);
|
|
406
411
|
}
|
|
407
412
|
};
|
|
408
|
-
const transactKey = async (key, apply, ttlMs) => {
|
|
413
|
+
const transactKey = async (key, apply, ttlMs, assertCurrent) => {
|
|
409
414
|
const deadline = Date.now() + BINDING_LEASE_WAIT_MS;
|
|
410
415
|
while (true) {
|
|
411
416
|
let busy = false;
|
|
412
417
|
let leaseLost = false;
|
|
413
418
|
let result;
|
|
414
419
|
const ownedLease = leaseContext.getStore()?.get(key);
|
|
420
|
+
if (ownedLease && ownedLease.phase !== "held") throw bindingLeaseLostError(key);
|
|
415
421
|
if (ownedLease?.failure) throw ownedLease.failure;
|
|
416
422
|
const ownedToken = ownedLease?.token;
|
|
423
|
+
assertCurrent?.();
|
|
424
|
+
ownedLease?.assertCurrent?.();
|
|
417
425
|
update(key, (raw) => {
|
|
418
426
|
const current = readStoredCodexAppServerBinding(raw);
|
|
419
427
|
if (raw !== void 0 && !current) throw new Error(`Invalid Codex app-server binding row: ${key}`);
|
|
@@ -441,6 +449,115 @@ function createCodexAppServerBindingStore(state) {
|
|
|
441
449
|
await sleep(BINDING_LEASE_RETRY_INTERVAL_MS);
|
|
442
450
|
}
|
|
443
451
|
};
|
|
452
|
+
const withBindingLease = async (identity, run, options = {}) => {
|
|
453
|
+
options.assertCurrent?.();
|
|
454
|
+
const key = bindingStoreKey(identity);
|
|
455
|
+
const owned = leaseContext.getStore();
|
|
456
|
+
const existingOwner = owned?.get(key);
|
|
457
|
+
if (existingOwner) {
|
|
458
|
+
if (existingOwner.phase !== "held") throw bindingLeaseLostError(key);
|
|
459
|
+
const failureBeforeRun = existingOwner.failure;
|
|
460
|
+
if (failureBeforeRun) throw failureBeforeRun;
|
|
461
|
+
const result = await run();
|
|
462
|
+
options.assertCurrent?.();
|
|
463
|
+
const failureAfterRun = existingOwner.failure;
|
|
464
|
+
if (failureAfterRun) throw failureAfterRun;
|
|
465
|
+
return result;
|
|
466
|
+
}
|
|
467
|
+
const token = randomUUID();
|
|
468
|
+
const acquired = await transactKey(key, (current) => {
|
|
469
|
+
if (current?.state === "cleared" && current.retired === true && ownsStoredSessionGeneration(identity, current) && !options.allowRetired) return { result: false };
|
|
470
|
+
const lease = {
|
|
471
|
+
token,
|
|
472
|
+
expiresAt: Date.now() + BINDING_LEASE_STALE_MS
|
|
473
|
+
};
|
|
474
|
+
if (current?.state === "active") return {
|
|
475
|
+
result: true,
|
|
476
|
+
next: {
|
|
477
|
+
...current,
|
|
478
|
+
...preservedSessionGeneration(identity, current),
|
|
479
|
+
lease
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
if (current?.state === "cleared" && current.retired === true) return {
|
|
483
|
+
result: true,
|
|
484
|
+
next: {
|
|
485
|
+
...current,
|
|
486
|
+
lease
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
return {
|
|
490
|
+
result: true,
|
|
491
|
+
next: {
|
|
492
|
+
version: 1,
|
|
493
|
+
state: "cleared",
|
|
494
|
+
...preservedSessionGeneration(identity, current),
|
|
495
|
+
lease
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
}, void 0, options.assertCurrent);
|
|
499
|
+
options.assertCurrent?.();
|
|
500
|
+
if (!acquired) throw new Error(`Codex binding generation was retired: ${key}`);
|
|
501
|
+
const owner = {
|
|
502
|
+
token,
|
|
503
|
+
phase: "held",
|
|
504
|
+
assertCurrent: options.assertCurrent
|
|
505
|
+
};
|
|
506
|
+
const nested = new Map(owned);
|
|
507
|
+
nested.set(key, owner);
|
|
508
|
+
const heartbeat = setInterval(() => renewLease(key, owner), BINDING_LEASE_RENEW_INTERVAL_MS);
|
|
509
|
+
heartbeat.unref();
|
|
510
|
+
try {
|
|
511
|
+
const result = await leaseContext.run(nested, run);
|
|
512
|
+
options.assertCurrent?.();
|
|
513
|
+
if (owner.failure) throw owner.failure;
|
|
514
|
+
return result;
|
|
515
|
+
} finally {
|
|
516
|
+
clearInterval(heartbeat);
|
|
517
|
+
owner.phase = "closed";
|
|
518
|
+
options.assertCurrent?.();
|
|
519
|
+
try {
|
|
520
|
+
const current = readStoredCodexAppServerBinding(state.lookup(key));
|
|
521
|
+
if (current?.lease?.token === token) {
|
|
522
|
+
const ttlMs = current.state === "active" || current.retired === true && !key.startsWith("session:") ? void 0 : current.retired === true ? PHYSICAL_SESSION_RETIRE_TTL_MS : 1;
|
|
523
|
+
options.assertCurrent?.();
|
|
524
|
+
update(key, (raw) => {
|
|
525
|
+
const stored = readStoredCodexAppServerBinding(raw);
|
|
526
|
+
if (stored?.lease?.token !== token) return;
|
|
527
|
+
const { lease: _lease, ...released } = stored;
|
|
528
|
+
return released;
|
|
529
|
+
}, ttlMs === void 0 ? void 0 : { ttlMs });
|
|
530
|
+
}
|
|
531
|
+
} catch (error) {
|
|
532
|
+
options.assertCurrent?.();
|
|
533
|
+
embeddedAgentLog.warn("failed to release codex app-server binding lease", {
|
|
534
|
+
key,
|
|
535
|
+
error
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
const transitionSessionGeneration = async (identity, mode) => {
|
|
541
|
+
return await runBindingMutation(async () => {
|
|
542
|
+
const key = bindingStoreKey(identity);
|
|
543
|
+
const ttlMs = mode === "reset" ? leaseContext.getStore()?.has(key) ? void 0 : 1 : identity.sessionKey?.trim() ? void 0 : PHYSICAL_SESSION_RETIRE_TTL_MS;
|
|
544
|
+
return await transactKey(key, (current, leaseToken) => {
|
|
545
|
+
if (!current) return { result: "absent" };
|
|
546
|
+
if (!ownsStoredSessionGeneration(identity, current)) return { result: "conflict" };
|
|
547
|
+
if (current.state === "cleared" && current.retired === true) return { result: mode === "retire" ? "applied" : "conflict" };
|
|
548
|
+
return {
|
|
549
|
+
result: "applied",
|
|
550
|
+
next: {
|
|
551
|
+
version: 1,
|
|
552
|
+
state: "cleared",
|
|
553
|
+
...mode === "retire" ? { retired: true } : {},
|
|
554
|
+
...storedSessionGeneration(identity, current),
|
|
555
|
+
...current.lease && current.lease.token === leaseToken ? { lease: current.lease } : {}
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
}, ttlMs);
|
|
559
|
+
});
|
|
560
|
+
};
|
|
444
561
|
return {
|
|
445
562
|
async read(identity) {
|
|
446
563
|
const key = bindingStoreKey(identity);
|
|
@@ -485,7 +602,7 @@ function createCodexAppServerBindingStore(state) {
|
|
|
485
602
|
expectedPreviousSessionId: currentSessionId
|
|
486
603
|
};
|
|
487
604
|
},
|
|
488
|
-
async mutate(identity, mutation) {
|
|
605
|
+
async mutate(identity, mutation, assertCurrent) {
|
|
489
606
|
return await runBindingMutation(async () => {
|
|
490
607
|
const key = bindingStoreKey(identity);
|
|
491
608
|
const retainLegacyClear = mutation.kind === "clear" && key.startsWith("conversation:legacy-");
|
|
@@ -523,9 +640,9 @@ function createCodexAppServerBindingStore(state) {
|
|
|
523
640
|
const active = ownsGeneration ? storedActive : void 0;
|
|
524
641
|
const retiredGeneration = current?.state === "cleared" && current.retired === true && ownsGeneration;
|
|
525
642
|
const preservesSupervisionOwner = mutation.kind === "set" && active?.binding.connectionScope === "supervision" && isSameSupervisionOwner(active.binding, mutation.binding);
|
|
526
|
-
const clearsPendingSupervisionOwner = mutation.kind === "clear" &&
|
|
643
|
+
const clearsPendingSupervisionOwner = mutation.kind === "clear" && matchesPendingSupervisionClear(active?.binding, mutation.threadId, mutation.expectedPendingSupervisionBranch);
|
|
527
644
|
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 ||
|
|
645
|
+
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.expectedPendingSupervisionBranch ? !clearsPendingSupervisionOwner : mutation.threadId !== void 0 && active?.binding.threadId !== mutation.threadId || active?.binding.connectionScope === "supervision"))) return { result: false };
|
|
529
646
|
if (mutation.kind === "clear" && retiredGeneration) return { result: true };
|
|
530
647
|
if (mutation.kind === "clear") return {
|
|
531
648
|
result: true,
|
|
@@ -563,7 +680,7 @@ function createCodexAppServerBindingStore(state) {
|
|
|
563
680
|
...ownedLease
|
|
564
681
|
}
|
|
565
682
|
};
|
|
566
|
-
}, mutation.kind === "clear" && !retainLegacyClear && !leaseContext.getStore()?.has(key) ? 1 : void 0);
|
|
683
|
+
}, mutation.kind === "clear" && !retainLegacyClear && !leaseContext.getStore()?.has(key) ? 1 : void 0, assertCurrent);
|
|
567
684
|
});
|
|
568
685
|
},
|
|
569
686
|
async adoptSessionGeneration(identity, expectedPreviousSessionId) {
|
|
@@ -586,45 +703,8 @@ function createCodexAppServerBindingStore(state) {
|
|
|
586
703
|
});
|
|
587
704
|
});
|
|
588
705
|
},
|
|
589
|
-
|
|
590
|
-
|
|
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);
|
|
626
|
-
});
|
|
627
|
-
},
|
|
706
|
+
resetSessionGeneration: (identity) => transitionSessionGeneration(identity, "reset"),
|
|
707
|
+
retireSessionGeneration: (identity) => transitionSessionGeneration(identity, "retire"),
|
|
628
708
|
async withThreadArchiveFence(run) {
|
|
629
709
|
pendingArchives += 1;
|
|
630
710
|
const operation = archiveTail.then(async () => {
|
|
@@ -638,79 +718,73 @@ function createCodexAppServerBindingStore(state) {
|
|
|
638
718
|
pendingArchives -= 1;
|
|
639
719
|
}
|
|
640
720
|
},
|
|
641
|
-
async
|
|
721
|
+
async withSessionDeletion(identity, assertCurrent, run) {
|
|
642
722
|
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
|
|
723
|
+
const deleteIf = state.deleteIf?.bind(state);
|
|
724
|
+
if (!deleteIf) throw new Error("Codex session deletion requires conditional plugin-state deletion");
|
|
725
|
+
return await runBindingMutation(async () => {
|
|
726
|
+
assertCurrent();
|
|
727
|
+
if (state.lookup(key) === void 0) {
|
|
728
|
+
let active = true;
|
|
729
|
+
try {
|
|
730
|
+
return await run(void 0, {
|
|
731
|
+
commit() {
|
|
732
|
+
assertCurrent();
|
|
733
|
+
if (!active || state.lookup(key) !== void 0) throw new Error("Codex binding changed before session deletion");
|
|
734
|
+
},
|
|
735
|
+
rollback() {}
|
|
736
|
+
});
|
|
737
|
+
} finally {
|
|
738
|
+
active = false;
|
|
682
739
|
}
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
} finally {
|
|
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;
|
|
740
|
+
}
|
|
741
|
+
return await withBindingLease(identity, async () => {
|
|
742
|
+
const owner = leaseContext.getStore().get(key);
|
|
743
|
+
const stored = readStoredCodexAppServerBinding(state.lookup(key));
|
|
744
|
+
if (!stored || !ownsStoredSessionGeneration(identity, stored)) throw new Error("Codex binding generation changed before session deletion");
|
|
745
|
+
const { lease: _lease, ...expectedValue } = stored;
|
|
746
|
+
let deleted;
|
|
747
|
+
let active = true;
|
|
748
|
+
const assertActive = () => {
|
|
749
|
+
assertCurrent();
|
|
750
|
+
if (!active || owner.phase === "closed" || owner.failure) throw owner.failure ?? bindingLeaseLostError(key);
|
|
702
751
|
};
|
|
703
|
-
|
|
704
|
-
|
|
752
|
+
try {
|
|
753
|
+
return await run(stored.state === "active" ? stored.binding : void 0, {
|
|
754
|
+
commit() {
|
|
755
|
+
assertActive();
|
|
756
|
+
if (deleted) return;
|
|
757
|
+
const current = state.lookup(key);
|
|
758
|
+
const { lease, ...value } = readStoredCodexAppServerBinding(current) ?? {};
|
|
759
|
+
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");
|
|
760
|
+
deleted = current;
|
|
761
|
+
owner.phase = "deleted";
|
|
762
|
+
},
|
|
763
|
+
rollback() {
|
|
764
|
+
assertActive();
|
|
765
|
+
if (!deleted) return;
|
|
766
|
+
const restored = {
|
|
767
|
+
...deleted,
|
|
768
|
+
lease: {
|
|
769
|
+
token: owner.token,
|
|
770
|
+
expiresAt: Date.now() + BINDING_LEASE_STALE_MS
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
if (!state.registerIfAbsent(key, restored)) throw new Error("Codex binding changed before session deletion rollback");
|
|
774
|
+
deleted = void 0;
|
|
775
|
+
owner.phase = "held";
|
|
776
|
+
}
|
|
777
|
+
});
|
|
778
|
+
} finally {
|
|
779
|
+
active = false;
|
|
705
780
|
}
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
}
|
|
781
|
+
}, {
|
|
782
|
+
allowRetired: true,
|
|
783
|
+
assertCurrent
|
|
784
|
+
});
|
|
785
|
+
});
|
|
786
|
+
},
|
|
787
|
+
withLease: withBindingLease
|
|
714
788
|
};
|
|
715
789
|
}
|
|
716
790
|
function matchesPendingSupervisionBranch(binding, expected) {
|
|
@@ -725,9 +799,8 @@ function isSameSupervisionOwner(current, replacement) {
|
|
|
725
799
|
return replacement.connectionScope === "supervision" && replacement.threadId === current.threadId && replacement.supervisionSourceThreadId === current.supervisionSourceThreadId;
|
|
726
800
|
}
|
|
727
801
|
function matchesPendingSupervisionClear(binding, threadId, expected) {
|
|
728
|
-
if (!expected) return false;
|
|
729
|
-
|
|
730
|
-
return threadId === sourceThreadId && binding.supervisionSourceThreadId === sourceThreadId && matchesPendingSupervisionBranch(binding, expected);
|
|
802
|
+
if (!expected || threadId !== expected.sourceThreadId) return false;
|
|
803
|
+
return !binding || binding.connectionScope === "supervision" && binding.supervisionSourceThreadId === expected.sourceThreadId && matchesPendingSupervisionBranch(binding, expected);
|
|
731
804
|
}
|
|
732
805
|
/** Stable plugin-state key for one current binding owner. */
|
|
733
806
|
function bindingStoreKey(identity) {
|
|
@@ -736,7 +809,7 @@ function bindingStoreKey(identity) {
|
|
|
736
809
|
const sessionId = identity.sessionId.trim();
|
|
737
810
|
if (!rawAgentId) throw new Error("Codex app-server binding requires an agent id");
|
|
738
811
|
if (!sessionId) throw new Error("Codex app-server binding requires a session id");
|
|
739
|
-
const agentId =
|
|
812
|
+
const agentId = resolveSessionAgentIdsStrict({ agentId: rawAgentId }).sessionAgentId;
|
|
740
813
|
const sessionKey = identity.sessionKey?.trim();
|
|
741
814
|
if (sessionKey) return `session-key:${agentId}:${createHash("sha256").update(sessionKey).digest("base64url")}`;
|
|
742
815
|
return `session:${agentId}:${sessionId}`;
|