@openclaw/codex 2026.9.2 → 2026.9.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.
- package/README.md +2 -0
- package/dist/api.js +29 -26
- package/dist/apply-CvT8tW5i.js +356 -0
- package/dist/{attempt-client-cleanup-Bp1ZOnk2.js → attempt-client-cleanup-DKHzbwt5.js} +38 -214
- package/dist/{attempt-context-CSazkWns.js → attempt-context-D44yeDII.js} +9 -7
- package/dist/{event-projector-usage-ZqEVbAEY.js → attempt-notifications-C9XufG6l.js} +3 -106
- package/dist/{auth-binding-Ds_QVm-X.js → auth-binding-CWlKVccJ.js} +2 -2
- package/dist/auth-cache-key-7orQae_j.js +498 -0
- package/dist/auth-profile-CwzO4_RG.js +43 -0
- package/dist/auth-profile-selection-DFu9e167.js +45 -0
- package/dist/binding-connection-D3udKbIE.js +60 -0
- package/dist/{bounded-turn-DxGJRYbY.js → bounded-turn-C_Hneydj.js} +28 -125
- package/dist/build-state-BCmg9-5p.js +19 -0
- package/dist/{capabilities-B1mgvpP8.js → capabilities-8vx68WLH.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/client-B57KWPQx.js +4005 -0
- package/dist/command-dispatch-BpduNGVf.js +21 -0
- package/dist/{command-formatters-DSbGMXA0.js → command-formatters-lxlkNZgU.js} +4 -3
- package/dist/{command-handlers-DOJvGv6-.js → command-handlers-tiL9iWj7.js} +788 -135
- package/dist/command-rpc-CR5EOEZX.js +233 -0
- package/dist/{compact-Y_xBqrHN.js → compact-B_H3AOd7.js} +19 -14
- package/dist/config-oIORaQ5T.js +106 -0
- package/dist/{config-CyapYSji.js → config-options-CXMq1T-C.js} +205 -593
- package/dist/config-runtime-D0zGNIHu.js +11 -0
- package/dist/{config-utils-C57JiJrU.js → config-utils-DujwEnhg.js} +2 -4
- package/dist/conversation-binding-DsB4-O7U.js +900 -0
- package/dist/{plugin-marketplace-discovery-B7gHXJ3d.js → conversation-control-CtUu1b3m.js} +11 -143
- package/dist/doctor-contract-api.js +5 -5
- package/dist/{dynamic-tools-BwpvTxaX.js → dynamic-tools-CmN5RAip.js} +133 -76
- package/dist/{effective-mcp-catalog-CY9Jn4bA.js → effective-mcp-catalog-Bd73bqA8.js} +3 -3
- package/dist/{elicitation-input-DMkeki8d.js → elicitation-input-DPoK8F7w.js} +8 -22
- package/dist/ephemeral-turn-D78_VmzO.js +101 -0
- package/dist/{event-projector-assistant-message-B9kp6iGC.js → event-projector-assistant-message-BmBM4qBV.js} +12 -25
- package/dist/event-projector-items-5VhsECCO.js +200 -0
- package/dist/event-projector-usage-BfXmpOec.js +102 -0
- package/dist/{harness-Czh2Sdoc.js → harness-C7rRa7bm.js} +48 -24
- package/dist/harness.js +1 -1
- package/dist/history-rejection-B4nOXNXF.js +13 -0
- package/dist/incognito-session-uhrBF6wJ.js +15 -0
- package/dist/index.js +406 -2915
- package/dist/inference-context-Dr_mzvk4.js +94 -0
- package/dist/inference-proxy-HGXKUIre.js +311 -0
- package/dist/{isolated-completion-CRh-51AK.js → isolated-completion-DWVb5U2J.js} +7 -4
- package/dist/launch-args-RXQwn8zV.js +90 -0
- package/dist/{managed-binary-DcpnJF9x.js → managed-binary-D22rNEcR.js} +13 -103
- package/dist/managed-thread-store-D1t5jh3G.js +66 -0
- package/dist/media-understanding-provider.js +4 -1
- package/dist/migration-provider-api.js +2 -0
- package/dist/{model-catalog-DT5vo6qo.js → model-catalog-Dq2n8f_p.js} +6 -5
- package/dist/{models-CcrgSMQR.js → models-PCKOim-h.js} +3 -3
- package/dist/native-execution-policy-umd0tgh4.js +128 -0
- package/dist/native-subagent-history-DjtPloaU.js +140 -0
- package/dist/native-subagent-history-owner-Pcp7JuVF.js +34 -0
- package/dist/{native-subagent-monitor-B3bvQGcg.js → native-subagent-monitor-fQ7eIXEf.js} +115 -460
- package/dist/native-subagent-task-ids-BzTdT0Uw.js +387 -0
- package/dist/node-cli-sessions-DKaOmVUh.js +527 -0
- package/dist/{node-exec-server.runtime-nfbUOtUB.js → node-exec-server.runtime-Cl2vapEi.js} +55 -24
- package/dist/plan-7uG-Fp36.js +947 -0
- package/dist/plugin-activation-BYQculil.js +138 -0
- package/dist/{thread-resume-BLgqkUc1.js → plugin-app-cache-key-d0eKxy7b.js} +4 -52
- package/dist/{plugin-approval-roundtrip-aQVdyL5g.js → plugin-approval-roundtrip-Bz3FT8W5.js} +1 -1
- package/dist/plugin-inventory-oL4Na1ZG.js +328 -0
- package/dist/plugin-marketplace-discovery-P-Vndfqq.js +137 -0
- package/dist/{plugin-metadata-cache-BwCLTY_U.js → plugin-metadata-cache-ClPJpRio.js} +17 -9
- package/dist/protocol-5bh1G-H7.js +275 -0
- package/dist/provider-MQ8PVkuE.js +50 -0
- package/dist/{provider-capabilities-BpG9Ltc5.js → provider-capabilities-BvCUL69A.js} +2 -2
- package/dist/{rate-limits-Fx_l4eNa.js → rate-limits-CBMmWBr9.js} +1 -1
- package/dist/request-B7hEkBGq.js +212 -0
- package/dist/rpc-error-ttN_QjEm.js +30 -0
- package/dist/{run-attempt-BzthFQSM.js → run-attempt-CvsAAGa0.js} +664 -377
- package/dist/{runtime-artifact-Bh_gf6-t.js → runtime-artifact-BJ0rXBZ_.js} +27 -27
- package/dist/sandbox-guard-BxgyoM8M.js +166 -0
- package/dist/{session-binding-4Ki04sW-.js → session-binding-CI8UuilT.js} +30 -48
- package/dist/{session-binding-record-CyaXZvTe.js → session-binding-record-Bcvslnhf.js} +12 -26
- package/dist/session-catalog-adoption-tcZi1IfX.js +251 -0
- package/dist/session-catalog-archive-CwKg8Xz2.js +56 -0
- package/dist/session-catalog-ct-AH01I.js +1477 -0
- package/dist/session-catalog-home-id-CwhLdC03.js +18 -0
- package/dist/session-catalog-node-adoption-B1tgDW-m.js +182 -0
- package/dist/session-catalog-node-continue-Ci-DXyJP.js +238 -0
- package/dist/session-catalog-provenance-D-dIfRAH.js +96 -0
- package/dist/{session-cli-BjLhpmS1.js → session-cli-DNN_jhGc.js} +3 -2
- package/dist/{session-history-DWmMqiqW.js → session-history-Cz-tOOYj.js} +6 -3
- package/dist/{session-upstream-marker-DReTpGz6.js → session-history-import-DwyijFI6.js} +5 -50
- package/dist/{session-history-read-LHldwvyh.js → session-history-read-cxPUxyVV.js} +21 -7
- package/dist/session-history-worker-runtime.js +18 -6
- package/dist/session-history.worker-BeK1YOyT.js +378 -0
- package/dist/session-history.worker.js +1 -1
- package/dist/{session-initialization-BCFVnLL4.js → session-initialization-Ct0_Hzmg.js} +2 -2
- package/dist/{session-permission-policy-BaueHmSj.js → session-permission-policy-BBmXA8Eg.js} +4 -7
- package/dist/{session-retirement-DNdmYdFc.js → session-retirement-B2YfbAAT.js} +6 -5
- package/dist/session-upstream-marker-D15C9NHp.js +46 -0
- package/dist/{settled-turn-context-BOM3Y1pl.js → settled-turn-context-Du6gdUDd.js} +9 -9
- package/dist/{settled-turn-finalizer-BI-b1sry.js → settled-turn-finalizer-Dn91stmc.js} +8 -7
- package/dist/shared-client-CscigXXL.js +3109 -0
- package/dist/{side-question-B6DWAw1A.js → side-question-BGMJQf4U.js} +65 -170
- package/dist/source-CElXU0Oy.js +518 -0
- package/dist/thread-archive-guard-DfpBr-Sz.js +53 -0
- package/dist/thread-history-page-D0JIp48V.js +361 -0
- package/dist/{thread-lifecycle-DPK30jad.js → thread-lifecycle-DXl1-I6b.js} +187 -639
- package/dist/{thread-ownership-CbucAmmp.js → thread-ownership-BsDRTsyp.js} +13 -15
- package/dist/thread-policy-BuEQfE0g.js +54 -0
- package/dist/thread-resume-DsDOZpFg.js +52 -0
- package/dist/timeout-BVw8aaM1.js +33 -0
- package/dist/transcript-history-projection-v17wXgdK.js +238 -0
- package/dist/{transcript-mirror-_njEB84z.js → transcript-mirror-C5CKgNy6.js} +50 -260
- package/dist/{transcript-mirror-attestation-Byl34PC-.js → transcript-mirror-attestation-DibE0krH.js} +17 -4
- package/dist/{transport-stdio-CzTngV0j.js → transport-stdio-BGjHoYLr.js} +73 -43
- package/dist/{upstream-session-fork-1fwbNKzQ.js → upstream-session-fork-BZerMte_.js} +27 -19
- package/dist/{usage-i9fv5-4m.js → usage-tCk-mg_x.js} +4 -3
- package/dist/version-omm6IPI3.js +12 -0
- package/dist/{web-search-provider.runtime-DKQn67A7.js → web-search-provider.runtime-B7bGbGWq.js} +3 -3
- package/openclaw.plugin.json +23 -1
- package/package.json +4 -4
- package/dist/request-C8H22rPi.js +0 -475
- package/dist/session-catalog-B47uwekb.js +0 -3272
- package/dist/session-history.worker-zZVcx0ME.js +0 -267
- package/dist/shared-client-CKhX2kFt.js +0 -7505
- package/dist/thread-policy-CTalhWFy.js +0 -105
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
//#region extensions/codex/src/session-catalog-home-id.ts
|
|
5
|
+
function canonicalCodexCatalogHome(value) {
|
|
6
|
+
const resolved = path.resolve(value);
|
|
7
|
+
try {
|
|
8
|
+
return fs.realpathSync.native(resolved);
|
|
9
|
+
} catch {
|
|
10
|
+
return resolved;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** One canonical identity for catalog discovery and durable ownership rows. */
|
|
14
|
+
function codexCatalogHomeId(codexHome) {
|
|
15
|
+
return createHash("sha256").update("openclaw:codex-session-catalog-home:v1\0").update(canonicalCodexCatalogHome(codexHome)).digest("hex");
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { codexCatalogHomeId as n, canonicalCodexCatalogHome as t };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { c as CatalogParamsError } from "./thread-history-page-D0JIp48V.js";
|
|
2
|
+
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
|
+
import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
|
|
4
|
+
import { resolveStorePath } from "openclaw/plugin-sdk/session-store-paths";
|
|
5
|
+
import { listSessionCatalogEntries, sessionCatalogAdoptedSessionKey, sessionCatalogAdoptedSourceKey } from "openclaw/plugin-sdk/session-catalog";
|
|
6
|
+
//#region extensions/codex/src/session-catalog-node-adoption.ts
|
|
7
|
+
const CODEX_NODE_SESSION_KEY_PREFIX = "harness:codex:node-session:";
|
|
8
|
+
const continueOperations = /* @__PURE__ */ new Map();
|
|
9
|
+
const sessionActionTails = /* @__PURE__ */ new Map();
|
|
10
|
+
async function runSessionActionExclusive(threadId, run) {
|
|
11
|
+
const operation = (sessionActionTails.get(threadId) ?? Promise.resolve()).then(run);
|
|
12
|
+
const tail = operation.then(() => void 0, () => void 0);
|
|
13
|
+
sessionActionTails.set(threadId, tail);
|
|
14
|
+
try {
|
|
15
|
+
return await operation;
|
|
16
|
+
} finally {
|
|
17
|
+
if (sessionActionTails.get(threadId) === tail) sessionActionTails.delete(threadId);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function adoptionSessionKeyRest(sessionKey) {
|
|
21
|
+
const trimmed = sessionKey.trim();
|
|
22
|
+
return parseAgentSessionKey(trimmed)?.rest ?? trimmed;
|
|
23
|
+
}
|
|
24
|
+
function nodeAdoptionSessionKey(hostId, threadId) {
|
|
25
|
+
const source = JSON.stringify([hostId, threadId]);
|
|
26
|
+
return sessionCatalogAdoptedSessionKey(CODEX_NODE_SESSION_KEY_PREFIX, source);
|
|
27
|
+
}
|
|
28
|
+
function readNodeSessionMarker(entry) {
|
|
29
|
+
const codex = isRecord(entry.pluginExtensions?.codex) ? entry.pluginExtensions.codex : void 0;
|
|
30
|
+
const marker = codex && isRecord(codex.sessionCatalog) ? codex.sessionCatalog : void 0;
|
|
31
|
+
if (!marker || typeof marker.sourceHostId !== "string" || !marker.sourceHostId.startsWith("node:") || typeof marker.sourceThreadId !== "string" || !marker.sourceThreadId.trim() || typeof marker.nodeId !== "string" || !marker.nodeId.trim()) return;
|
|
32
|
+
return {
|
|
33
|
+
sourceHostId: marker.sourceHostId,
|
|
34
|
+
sourceThreadId: marker.sourceThreadId,
|
|
35
|
+
nodeId: marker.nodeId,
|
|
36
|
+
...marker.initializing === true ? { initializing: true } : {}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function listNodeAdoptedSessionEntries(params) {
|
|
40
|
+
const adopted = /* @__PURE__ */ new Map();
|
|
41
|
+
for (const { agentId, entry, sessionKey } of listSessionCatalogEntries({
|
|
42
|
+
...params.agentId ? { agentId: params.agentId } : {},
|
|
43
|
+
config: params.config ?? {},
|
|
44
|
+
runtime: params.runtime,
|
|
45
|
+
sessionEntries: params.sessionEntries
|
|
46
|
+
})) {
|
|
47
|
+
const marker = readNodeSessionMarker(entry);
|
|
48
|
+
const sessionId = entry.sessionId?.trim();
|
|
49
|
+
if (!marker || marker.initializing === true && params.includeInitializing !== true || entry.initializationPending === true || entry.agentHarnessId !== "codex" || entry.modelSelectionLocked !== true || !sessionId || adoptionSessionKeyRest(sessionKey) !== nodeAdoptionSessionKey(marker.sourceHostId, marker.sourceThreadId) || marker.sourceHostId !== `node:${marker.nodeId}`) continue;
|
|
50
|
+
const sourceKey = sessionCatalogAdoptedSourceKey(marker.sourceHostId, marker.sourceThreadId);
|
|
51
|
+
if (adopted.has(sourceKey)) throw new Error(`multiple OpenClaw sessions adopt Codex thread ${marker.sourceThreadId} on ${marker.sourceHostId}`);
|
|
52
|
+
adopted.set(sourceKey, {
|
|
53
|
+
key: sessionKey,
|
|
54
|
+
sessionId,
|
|
55
|
+
agentId,
|
|
56
|
+
...marker.initializing === true ? { initializing: true } : {}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return adopted;
|
|
60
|
+
}
|
|
61
|
+
function findNodeAdoptedSessionEntry(params) {
|
|
62
|
+
return listNodeAdoptedSessionEntries(params).get(sessionCatalogAdoptedSourceKey(params.hostId, params.threadId));
|
|
63
|
+
}
|
|
64
|
+
function nodeSessionMarker(params) {
|
|
65
|
+
return {
|
|
66
|
+
sourceHostId: params.hostId,
|
|
67
|
+
sourceThreadId: params.threadId,
|
|
68
|
+
nodeId: params.nodeId,
|
|
69
|
+
...params.initializing === true ? { initializing: true } : {}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async function finalizeNodeAdoptedSession(params) {
|
|
73
|
+
const changedError = () => new CatalogParamsError("Codex OpenClaw session changed before it could be bound. Retry.");
|
|
74
|
+
let finalized;
|
|
75
|
+
try {
|
|
76
|
+
finalized = await params.api.runtime.agent.session.patchSessionEntry({
|
|
77
|
+
sessionKey: params.adopted.key,
|
|
78
|
+
readConsistency: "latest",
|
|
79
|
+
preserveActivity: true,
|
|
80
|
+
update: (entry) => {
|
|
81
|
+
const current = readNodeSessionMarker(entry);
|
|
82
|
+
if (entry.sessionId?.trim() !== params.adopted.sessionId || entry.initializationPending === true || entry.agentHarnessId !== "codex" || entry.modelSelectionLocked !== true || !current || current.sourceHostId !== params.marker.sourceHostId || current.sourceThreadId !== params.marker.sourceThreadId || current.nodeId !== params.marker.nodeId) throw changedError();
|
|
83
|
+
if (current.initializing !== true) return {
|
|
84
|
+
archivedAt: void 0,
|
|
85
|
+
archivedBy: void 0,
|
|
86
|
+
archiveReason: void 0
|
|
87
|
+
};
|
|
88
|
+
const codex = isRecord(entry.pluginExtensions?.codex) ? entry.pluginExtensions.codex : {};
|
|
89
|
+
return {
|
|
90
|
+
archivedAt: void 0,
|
|
91
|
+
archivedBy: void 0,
|
|
92
|
+
archiveReason: void 0,
|
|
93
|
+
pluginExtensions: {
|
|
94
|
+
...entry.pluginExtensions,
|
|
95
|
+
codex: {
|
|
96
|
+
...codex,
|
|
97
|
+
sessionCatalog: params.marker
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
} catch (error) {
|
|
104
|
+
const currentEntry = params.api.runtime.agent.session.getSessionEntry({
|
|
105
|
+
sessionKey: params.adopted.key,
|
|
106
|
+
readConsistency: "latest"
|
|
107
|
+
});
|
|
108
|
+
const current = currentEntry ? readNodeSessionMarker(currentEntry) : void 0;
|
|
109
|
+
if (currentEntry?.sessionId?.trim() === params.adopted.sessionId && current?.initializing !== true && current?.sourceHostId === params.marker.sourceHostId && current.sourceThreadId === params.marker.sourceThreadId && current.nodeId === params.marker.nodeId) return;
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
if (!finalized) throw changedError();
|
|
113
|
+
}
|
|
114
|
+
async function createOrReuseNodeAdoptedSession(params) {
|
|
115
|
+
const existing = findNodeAdoptedSessionEntry({
|
|
116
|
+
agentId: params.agentId,
|
|
117
|
+
config: params.config,
|
|
118
|
+
runtime: params.api.runtime,
|
|
119
|
+
hostId: params.hostId,
|
|
120
|
+
threadId: params.record.threadId,
|
|
121
|
+
includeInitializing: true
|
|
122
|
+
});
|
|
123
|
+
if (existing) return existing;
|
|
124
|
+
const initializingMarker = {
|
|
125
|
+
...nodeSessionMarker({
|
|
126
|
+
hostId: params.hostId,
|
|
127
|
+
threadId: params.record.threadId,
|
|
128
|
+
nodeId: params.nodeId
|
|
129
|
+
}),
|
|
130
|
+
initializing: true
|
|
131
|
+
};
|
|
132
|
+
try {
|
|
133
|
+
const created = await params.api.runtime.agent.session.createSessionEntry({
|
|
134
|
+
cfg: params.config,
|
|
135
|
+
key: nodeAdoptionSessionKey(params.hostId, params.record.threadId),
|
|
136
|
+
agentId: params.agentId,
|
|
137
|
+
recoverMatchingInitialEntry: true,
|
|
138
|
+
displayName: params.record.name ?? void 0,
|
|
139
|
+
...params.record.cwd?.trim() ? { spawnedCwd: params.record.cwd.trim() } : {},
|
|
140
|
+
initialEntry: {
|
|
141
|
+
agentHarnessId: "codex",
|
|
142
|
+
modelSelectionLocked: true,
|
|
143
|
+
pluginExtensions: { codex: { sessionCatalog: initializingMarker } }
|
|
144
|
+
},
|
|
145
|
+
afterCreate: async (entry) => {
|
|
146
|
+
const storePath = resolveStorePath(params.config.session?.store, { agentId: entry.agentId });
|
|
147
|
+
const { importCodexThreadHistoryToTranscript } = await import("./transcript-mirror-C5CKgNy6.js").then((n) => n.a);
|
|
148
|
+
await importCodexThreadHistoryToTranscript({
|
|
149
|
+
thread: params.history.thread,
|
|
150
|
+
throughTurnId: params.history.throughTurnId,
|
|
151
|
+
storePath,
|
|
152
|
+
sessionId: entry.sessionId,
|
|
153
|
+
sessionKey: entry.key,
|
|
154
|
+
agentId: entry.agentId,
|
|
155
|
+
...params.record.cwd?.trim() ? { cwd: params.record.cwd.trim() } : {},
|
|
156
|
+
modelProvider: params.record.modelProvider,
|
|
157
|
+
config: params.config
|
|
158
|
+
});
|
|
159
|
+
return { pluginExtensions: { codex: { sessionCatalog: initializingMarker } } };
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
return {
|
|
163
|
+
key: created.key,
|
|
164
|
+
sessionId: created.sessionId,
|
|
165
|
+
agentId: created.agentId,
|
|
166
|
+
initializing: true
|
|
167
|
+
};
|
|
168
|
+
} catch (error) {
|
|
169
|
+
const raced = findNodeAdoptedSessionEntry({
|
|
170
|
+
agentId: params.agentId,
|
|
171
|
+
config: params.config,
|
|
172
|
+
runtime: params.api.runtime,
|
|
173
|
+
hostId: params.hostId,
|
|
174
|
+
threadId: params.record.threadId,
|
|
175
|
+
includeInitializing: true
|
|
176
|
+
});
|
|
177
|
+
if (raced) return raced;
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//#endregion
|
|
182
|
+
export { adoptionSessionKeyRest, continueOperations, createOrReuseNodeAdoptedSession, finalizeNodeAdoptedSession, findNodeAdoptedSessionEntry, listNodeAdoptedSessionEntries, nodeSessionMarker, runSessionActionExclusive };
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { n as createCodexCliNodeConversationBindingData } from "./conversation-binding-data-BiodpIzq.js";
|
|
2
|
+
import { t as CODEX_CLI_SESSION_RESUME_COMMAND } from "./node-cli-sessions-DKaOmVUh.js";
|
|
3
|
+
import { a as lookupNodeCodexCatalogRecord } from "./session-catalog-ct-AH01I.js";
|
|
4
|
+
import { D as unwrapNodeInvokePayload, _ as parseCatalogPage, a as CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND, c as CatalogParamsError, d as NODE_INVOKE_TIMEOUT_MS, f as boundedCatalogString, h as isInteractiveThreadSource, i as CODEX_APP_SERVER_THREADS_LIST_COMMAND, m as filterCatalogPageByTitle, p as catalogError, y as parseTranscriptPage } from "./thread-history-page-D0JIp48V.js";
|
|
5
|
+
import { t as codexLastTerminalTurnId } from "./session-upstream-marker-D15C9NHp.js";
|
|
6
|
+
import { n as withTimeout } from "./timeout-BVw8aaM1.js";
|
|
7
|
+
import { createOrReuseNodeAdoptedSession, finalizeNodeAdoptedSession, findNodeAdoptedSessionEntry, nodeSessionMarker, runSessionActionExclusive } from "./session-catalog-node-adoption-B1tgDW-m.js";
|
|
8
|
+
import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
9
|
+
import { createSessionCatalogAdoptionCoordinator, publishSessionCatalogHost, sessionCatalogAdoptedSourceKey } from "openclaw/plugin-sdk/session-catalog";
|
|
10
|
+
//#region extensions/codex/src/session-catalog-node-continue.ts
|
|
11
|
+
const CODEX_NODE_CONTINUE_COMMANDS = [
|
|
12
|
+
CODEX_APP_SERVER_THREADS_LIST_COMMAND,
|
|
13
|
+
CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND,
|
|
14
|
+
CODEX_CLI_SESSION_RESUME_COMMAND
|
|
15
|
+
];
|
|
16
|
+
const NODE_CATALOG_LIST_RESPONSE_TIMEOUT_MS = 8e3;
|
|
17
|
+
const continueNodeAdoption = createSessionCatalogAdoptionCoordinator();
|
|
18
|
+
function nodeLabel(node) {
|
|
19
|
+
return node.displayName?.trim() || node.remoteIp?.trim() || node.nodeId;
|
|
20
|
+
}
|
|
21
|
+
function compareNodeLabels(left, right) {
|
|
22
|
+
const leftLabel = nodeLabel(left);
|
|
23
|
+
const rightLabel = nodeLabel(right);
|
|
24
|
+
if (leftLabel < rightLabel) return -1;
|
|
25
|
+
if (leftLabel > rightLabel) return 1;
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
function canContinueCodexOnNode(node) {
|
|
29
|
+
return node.connected === true && CODEX_NODE_CONTINUE_COMMANDS.every((command) => node.commands?.includes(command) === true && node.invocableCommands?.includes(command) === true);
|
|
30
|
+
}
|
|
31
|
+
async function listPairedNode(params) {
|
|
32
|
+
const hostId = `node:${params.node.nodeId}`;
|
|
33
|
+
const common = {
|
|
34
|
+
hostId,
|
|
35
|
+
label: nodeLabel(params.node),
|
|
36
|
+
kind: "node",
|
|
37
|
+
nodeId: params.node.nodeId,
|
|
38
|
+
canContinueCodex: canContinueCodexOnNode(params.node),
|
|
39
|
+
...params.terminalCapabilities
|
|
40
|
+
};
|
|
41
|
+
if (params.node.connected !== true) {
|
|
42
|
+
const host = {
|
|
43
|
+
...common,
|
|
44
|
+
connected: false,
|
|
45
|
+
sessions: [],
|
|
46
|
+
error: {
|
|
47
|
+
code: "NODE_OFFLINE",
|
|
48
|
+
message: "Paired node is offline"
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
params.onHost?.(host);
|
|
52
|
+
return host;
|
|
53
|
+
}
|
|
54
|
+
if (!params.node.commands?.includes("codex.appServer.threads.list.v1")) {
|
|
55
|
+
const host = {
|
|
56
|
+
...common,
|
|
57
|
+
connected: true,
|
|
58
|
+
sessions: []
|
|
59
|
+
};
|
|
60
|
+
params.onHost?.(host);
|
|
61
|
+
return host;
|
|
62
|
+
}
|
|
63
|
+
const eventualHost = Promise.resolve().then(async () => {
|
|
64
|
+
const raw = await params.runtime.nodes.invoke({
|
|
65
|
+
nodeId: params.node.nodeId,
|
|
66
|
+
command: CODEX_APP_SERVER_THREADS_LIST_COMMAND,
|
|
67
|
+
params: {
|
|
68
|
+
agentId: params.agentId,
|
|
69
|
+
cursor: params.query.cursors?.[hostId],
|
|
70
|
+
limit: params.query.limitPerHost,
|
|
71
|
+
searchTerm: params.query.search
|
|
72
|
+
},
|
|
73
|
+
timeoutMs: NODE_INVOKE_TIMEOUT_MS,
|
|
74
|
+
scopes: ["operator.write"],
|
|
75
|
+
signal: params.signal
|
|
76
|
+
});
|
|
77
|
+
const page = filterCatalogPageByTitle(parseCatalogPage(unwrapNodeInvokePayload(raw)), params.query.search);
|
|
78
|
+
return {
|
|
79
|
+
...common,
|
|
80
|
+
connected: true,
|
|
81
|
+
...page,
|
|
82
|
+
sessions: page.sessions.map((session) => {
|
|
83
|
+
const adopted = params.adoptedSessions.get(sessionCatalogAdoptedSourceKey(hostId, session.threadId));
|
|
84
|
+
return adopted ? Object.assign({}, session, { sessionKey: adopted.key }) : session;
|
|
85
|
+
})
|
|
86
|
+
};
|
|
87
|
+
}).catch((error) => ({
|
|
88
|
+
...common,
|
|
89
|
+
connected: true,
|
|
90
|
+
sessions: [],
|
|
91
|
+
error: catalogError("NODE_INVOKE_FAILED", error)
|
|
92
|
+
}));
|
|
93
|
+
publishSessionCatalogHost(params, eventualHost);
|
|
94
|
+
try {
|
|
95
|
+
return await withTimeout(eventualHost, NODE_CATALOG_LIST_RESPONSE_TIMEOUT_MS, "paired node Codex session catalog timed out");
|
|
96
|
+
} catch (error) {
|
|
97
|
+
return {
|
|
98
|
+
...common,
|
|
99
|
+
connected: true,
|
|
100
|
+
sessions: [],
|
|
101
|
+
error: catalogError("NODE_INVOKE_FAILED", error)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async function requireNodeForCodexContinue(params) {
|
|
106
|
+
const nodeId = params.hostId.slice(5).trim();
|
|
107
|
+
if (!nodeId || params.hostId !== `node:${nodeId}`) throw new CatalogParamsError("Codex session catalog hostId is invalid");
|
|
108
|
+
const node = (await params.runtime.nodes.list()).nodes.find((candidate) => candidate.nodeId === nodeId);
|
|
109
|
+
if (!node || !canContinueCodexOnNode(node)) throw new CatalogParamsError("paired node does not permit Codex session continuation");
|
|
110
|
+
return {
|
|
111
|
+
node,
|
|
112
|
+
nodeId
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function requireContinuableNodeRecord(record) {
|
|
116
|
+
if (record.archived) throw new CatalogParamsError("Codex session is archived on the paired node");
|
|
117
|
+
if (!isInteractiveThreadSource(record.source)) throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
|
|
118
|
+
if (record.status === "idle" || record.status === "notLoaded") return;
|
|
119
|
+
if (record.status === "active") throw new CatalogParamsError("Codex session is active on the paired node; wait for it to finish before continuing");
|
|
120
|
+
throw new CatalogParamsError("Codex session cannot be continued in its current state");
|
|
121
|
+
}
|
|
122
|
+
async function readNodeCodexHistory(params) {
|
|
123
|
+
const raw = await params.runtime.nodes.invoke({
|
|
124
|
+
nodeId: params.nodeId,
|
|
125
|
+
command: CODEX_APP_SERVER_THREAD_TURNS_LIST_COMMAND,
|
|
126
|
+
params: {
|
|
127
|
+
agentId: params.agentId,
|
|
128
|
+
threadId: params.record.threadId,
|
|
129
|
+
limit: 50
|
|
130
|
+
},
|
|
131
|
+
timeoutMs: NODE_INVOKE_TIMEOUT_MS,
|
|
132
|
+
scopes: ["operator.write"]
|
|
133
|
+
});
|
|
134
|
+
const page = parseTranscriptPage(unwrapNodeInvokePayload(raw));
|
|
135
|
+
const thread = {
|
|
136
|
+
id: params.record.threadId,
|
|
137
|
+
createdAt: params.record.createdAt ?? 0,
|
|
138
|
+
modelProvider: params.record.modelProvider ?? "openai",
|
|
139
|
+
projectId: null,
|
|
140
|
+
turns: page.data.toReversed()
|
|
141
|
+
};
|
|
142
|
+
return {
|
|
143
|
+
thread,
|
|
144
|
+
throughTurnId: codexLastTerminalTurnId(thread, (value) => boundedCatalogString(value, 256)) ?? null
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async function continueNodeCodexSessionInner(params) {
|
|
148
|
+
const { nodeId } = await requireNodeForCodexContinue({
|
|
149
|
+
runtime: params.api.runtime,
|
|
150
|
+
hostId: params.hostId
|
|
151
|
+
});
|
|
152
|
+
const lookup = await lookupNodeCodexCatalogRecord({
|
|
153
|
+
agentId: params.agentId,
|
|
154
|
+
runtime: params.api.runtime,
|
|
155
|
+
nodeId,
|
|
156
|
+
threadId: params.threadId
|
|
157
|
+
});
|
|
158
|
+
if (lookup.kind !== "found") throw new CatalogParamsError(lookup.kind === "cursor-cycle" ? "Codex session eligibility could not be verified" : "Codex session is unavailable on the paired node");
|
|
159
|
+
const record = lookup.record;
|
|
160
|
+
requireContinuableNodeRecord(record);
|
|
161
|
+
const existing = findNodeAdoptedSessionEntry({
|
|
162
|
+
agentId: params.agentId,
|
|
163
|
+
config: params.config,
|
|
164
|
+
runtime: params.api.runtime,
|
|
165
|
+
hostId: params.hostId,
|
|
166
|
+
threadId: params.threadId,
|
|
167
|
+
includeInitializing: true
|
|
168
|
+
});
|
|
169
|
+
let adopted;
|
|
170
|
+
let disposition;
|
|
171
|
+
if (existing) {
|
|
172
|
+
adopted = existing;
|
|
173
|
+
disposition = "existing";
|
|
174
|
+
} else {
|
|
175
|
+
const history = await readNodeCodexHistory({
|
|
176
|
+
agentId: params.agentId,
|
|
177
|
+
runtime: params.api.runtime,
|
|
178
|
+
nodeId,
|
|
179
|
+
record
|
|
180
|
+
});
|
|
181
|
+
adopted = await createOrReuseNodeAdoptedSession({
|
|
182
|
+
agentId: params.agentId,
|
|
183
|
+
api: params.api,
|
|
184
|
+
config: params.config,
|
|
185
|
+
hostId: params.hostId,
|
|
186
|
+
nodeId,
|
|
187
|
+
record,
|
|
188
|
+
history
|
|
189
|
+
});
|
|
190
|
+
disposition = "forked";
|
|
191
|
+
}
|
|
192
|
+
const marker = nodeSessionMarker({
|
|
193
|
+
hostId: params.hostId,
|
|
194
|
+
threadId: params.threadId,
|
|
195
|
+
nodeId
|
|
196
|
+
});
|
|
197
|
+
return {
|
|
198
|
+
sessionKey: adopted.key,
|
|
199
|
+
disposition,
|
|
200
|
+
conversationBinding: {
|
|
201
|
+
summary: "Continue this Codex session on its paired node.",
|
|
202
|
+
detachHint: "Start a new chat to leave the paired-node Codex session.",
|
|
203
|
+
data: createCodexCliNodeConversationBindingData({
|
|
204
|
+
nodeId,
|
|
205
|
+
sessionId: params.threadId,
|
|
206
|
+
agentId: adopted.agentId,
|
|
207
|
+
cwd: record.cwd
|
|
208
|
+
})
|
|
209
|
+
},
|
|
210
|
+
afterConversationBound: async () => await finalizeNodeAdoptedSession({
|
|
211
|
+
api: params.api,
|
|
212
|
+
adopted,
|
|
213
|
+
marker
|
|
214
|
+
})
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
async function continueNodeCodexSession(params) {
|
|
218
|
+
if (params.clientScopes?.includes("operator.admin") !== true) throw new CatalogParamsError("continuing a paired-node Codex session requires operator.admin");
|
|
219
|
+
const nodeId = params.hostId.slice(5).trim();
|
|
220
|
+
if (!nodeId || params.hostId !== `node:${nodeId}`) throw new CatalogParamsError("Codex session catalog hostId is invalid");
|
|
221
|
+
const agentId = resolveSessionAgentIdsStrict({
|
|
222
|
+
config: params.config,
|
|
223
|
+
agentId: params.agentId
|
|
224
|
+
}).sessionAgentId;
|
|
225
|
+
const sourceKey = sessionCatalogAdoptedSourceKey(`node:${nodeId}`, params.threadId);
|
|
226
|
+
const operationKey = sessionCatalogAdoptedSourceKey(agentId, sourceKey);
|
|
227
|
+
return await continueNodeAdoption({
|
|
228
|
+
sourceKey: operationKey,
|
|
229
|
+
findExisting: () => void 0,
|
|
230
|
+
create: () => runSessionActionExclusive(sourceKey, async () => continueNodeCodexSessionInner({
|
|
231
|
+
...params,
|
|
232
|
+
agentId
|
|
233
|
+
})),
|
|
234
|
+
complete: async (continued) => continued
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
//#endregion
|
|
238
|
+
export { compareNodeLabels, continueNodeCodexSession, listPairedNode, nodeLabel };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { o as isJsonObject } from "./protocol-5bh1G-H7.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createZstdDecompress } from "node:zlib";
|
|
4
|
+
import { root } from "openclaw/plugin-sdk/file-access-runtime";
|
|
5
|
+
//#region extensions/codex/src/session-catalog-provenance.ts
|
|
6
|
+
const MAX_SESSION_META_BYTES = 1048576;
|
|
7
|
+
const SESSION_META_READ_CHUNK_BYTES = 65536;
|
|
8
|
+
const MAX_PROVENANCE_CACHE_ENTRIES = 2e4;
|
|
9
|
+
const provenanceByPath = /* @__PURE__ */ new Map();
|
|
10
|
+
function cacheProvenance(key, value) {
|
|
11
|
+
provenanceByPath.delete(key);
|
|
12
|
+
provenanceByPath.set(key, value);
|
|
13
|
+
while (provenanceByPath.size > MAX_PROVENANCE_CACHE_ENTRIES) {
|
|
14
|
+
const oldest = provenanceByPath.keys().next().value;
|
|
15
|
+
if (oldest === void 0) break;
|
|
16
|
+
provenanceByPath.delete(oldest);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Undefined means the metadata line is not durable enough to cache yet. */
|
|
20
|
+
async function readCodexSessionMeta(sessionsRoot, rolloutPath, threadId) {
|
|
21
|
+
let safeRoot;
|
|
22
|
+
try {
|
|
23
|
+
safeRoot = await root(sessionsRoot, {
|
|
24
|
+
hardlinks: "reject",
|
|
25
|
+
maxBytes: Number.MAX_SAFE_INTEGER,
|
|
26
|
+
symlinks: "reject"
|
|
27
|
+
});
|
|
28
|
+
} catch {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const candidates = rolloutPath.endsWith(".zst") ? [rolloutPath, rolloutPath.slice(0, -4)] : [rolloutPath, `${rolloutPath}.zst`];
|
|
32
|
+
for (const candidate of candidates) {
|
|
33
|
+
let opened;
|
|
34
|
+
try {
|
|
35
|
+
opened = await safeRoot.open(path.relative(sessionsRoot, candidate));
|
|
36
|
+
} catch {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const input = opened.handle.createReadStream({
|
|
40
|
+
autoClose: false,
|
|
41
|
+
highWaterMark: SESSION_META_READ_CHUNK_BYTES
|
|
42
|
+
});
|
|
43
|
+
const reader = candidate.endsWith(".zst") ? input.pipe(createZstdDecompress()) : input;
|
|
44
|
+
try {
|
|
45
|
+
const chunks = [];
|
|
46
|
+
let bytesReadTotal = 0;
|
|
47
|
+
let line;
|
|
48
|
+
for await (const value of reader) {
|
|
49
|
+
const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
50
|
+
const remaining = MAX_SESSION_META_BYTES - bytesReadTotal;
|
|
51
|
+
if (remaining <= 0) break;
|
|
52
|
+
const bounded = chunk.subarray(0, remaining);
|
|
53
|
+
bytesReadTotal += bounded.length;
|
|
54
|
+
const newline = bounded.indexOf(10);
|
|
55
|
+
chunks.push(newline >= 0 ? bounded.subarray(0, newline) : bounded);
|
|
56
|
+
if (newline >= 0) {
|
|
57
|
+
line = Buffer.concat(chunks).toString("utf8");
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!line) continue;
|
|
62
|
+
let parsed;
|
|
63
|
+
try {
|
|
64
|
+
parsed = JSON.parse(line);
|
|
65
|
+
} catch {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (!isJsonObject(parsed) || parsed.type !== "session_meta" || !isJsonObject(parsed.payload)) return null;
|
|
69
|
+
const payload = parsed.payload;
|
|
70
|
+
return payload.id === threadId ? payload : null;
|
|
71
|
+
} catch {
|
|
72
|
+
continue;
|
|
73
|
+
} finally {
|
|
74
|
+
reader.destroy();
|
|
75
|
+
input.destroy();
|
|
76
|
+
await opened.handle.close().catch(() => void 0);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Codex 0.147 reports OpenClaw app-server rollouts as `vscode`, so the rollout's
|
|
82
|
+
* immutable session metadata is the authoritative historical provenance.
|
|
83
|
+
*/
|
|
84
|
+
async function isOpenClawManagedCodexThread(thread, localSessionsRoot) {
|
|
85
|
+
const rolloutPath = typeof thread.path === "string" ? thread.path.trim() : "";
|
|
86
|
+
if (!localSessionsRoot || !rolloutPath) return false;
|
|
87
|
+
const cacheKey = `${localSessionsRoot}\0${rolloutPath}`;
|
|
88
|
+
const cached = provenanceByPath.get(cacheKey);
|
|
89
|
+
if (cached !== void 0) return cached;
|
|
90
|
+
const metadata = await readCodexSessionMeta(localSessionsRoot, rolloutPath, thread.id);
|
|
91
|
+
const managed = metadata === void 0 ? void 0 : metadata?.originator === "openclaw";
|
|
92
|
+
if (managed !== void 0) cacheProvenance(cacheKey, managed);
|
|
93
|
+
return managed ?? false;
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
export { readCodexSessionMeta as n, isOpenClawManagedCodexThread as t };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import "./session-catalog-
|
|
1
|
+
import "./session-catalog-ct-AH01I.js";
|
|
2
|
+
import "./thread-history-page-D0JIp48V.js";
|
|
2
3
|
import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
3
4
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
4
|
-
import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
|
|
5
5
|
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
6
|
+
import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
|
|
6
7
|
import { addGatewayClientOptions, callGatewayFromCli } from "openclaw/plugin-sdk/gateway-runtime";
|
|
7
8
|
//#region extensions/codex/src/session-cli.ts
|
|
8
9
|
const CODEX_SESSION_CATALOG_CLI_TIMEOUT_MS = 75e3;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as readCodexNativeHistory, t as consumeCodexHistory } from "./session-history-read-
|
|
2
|
-
import { getSessionEntry, parseSqliteSessionFileMarker, resolveTranscriptSessionKeyBySessionId } from "openclaw/plugin-sdk/session-store-runtime";
|
|
1
|
+
import { n as readCodexNativeHistory, t as consumeCodexHistory } from "./session-history-read-cxPUxyVV.js";
|
|
3
2
|
import { SessionManager } from "openclaw/plugin-sdk/agent-sessions";
|
|
3
|
+
import { getSessionEntry, parseSqliteSessionFileMarker, resolveTranscriptSessionKeyBySessionId } from "openclaw/plugin-sdk/session-store-runtime";
|
|
4
4
|
//#region extensions/codex/src/app-server/session-history.ts
|
|
5
5
|
function resolveCodexHistoryTarget(target, admission) {
|
|
6
6
|
if (target.sessionTarget) {
|
|
@@ -64,7 +64,10 @@ async function readCodexMirroredSessionHistoryMessages(target, admission, view =
|
|
|
64
64
|
signal
|
|
65
65
|
});
|
|
66
66
|
result = consumeCodexHistory(loaded.buildSessionContext().messages, loaded.getHeader(), target.sessionId, read, "codex mirrored model context");
|
|
67
|
-
} else
|
|
67
|
+
} else {
|
|
68
|
+
const history = await readCodexNativeHistory(resolved, target.sessionId, read, admission);
|
|
69
|
+
result = history.status === "ok" ? history.value : void 0;
|
|
70
|
+
}
|
|
68
71
|
}
|
|
69
72
|
signal?.throwIfAborted();
|
|
70
73
|
return result;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { l as sessionBindingIdentity } from "./session-binding-record-
|
|
2
|
-
import "./session-binding-
|
|
3
|
-
import { r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-
|
|
4
|
-
import { n as prepareCodexSessionInitialization } from "./session-initialization-
|
|
1
|
+
import { l as sessionBindingIdentity } from "./session-binding-record-Bcvslnhf.js";
|
|
2
|
+
import "./session-binding-CI8UuilT.js";
|
|
3
|
+
import { r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-C5CKgNy6.js";
|
|
4
|
+
import { n as prepareCodexSessionInitialization } from "./session-initialization-Ct0_Hzmg.js";
|
|
5
5
|
import { resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
6
6
|
//#region extensions/codex/src/app-server/session-history-import.ts
|
|
7
7
|
/** Creates a session whose transcript is derived from one verified Codex thread snapshot. */
|
|
@@ -50,49 +50,4 @@ async function createImportedCodexSession(params) {
|
|
|
50
50
|
}) : await params.runtime.agent.session.createSessionEntry(createParams);
|
|
51
51
|
}
|
|
52
52
|
//#endregion
|
|
53
|
-
|
|
54
|
-
function lastIdentifiableTurn(thread, normalizeTurnId) {
|
|
55
|
-
for (let index = (thread.turns?.length ?? 0) - 1; index >= 0; index -= 1) {
|
|
56
|
-
const turn = thread.turns?.[index];
|
|
57
|
-
const turnId = normalizeTurnId(turn?.id);
|
|
58
|
-
if (turn && turnId) return {
|
|
59
|
-
...turn,
|
|
60
|
-
id: turnId
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
function codexUpstreamBaseline(thread, normalizeTurnId) {
|
|
65
|
-
const turn = lastIdentifiableTurn(thread, normalizeTurnId);
|
|
66
|
-
return {
|
|
67
|
-
turnId: turn?.id ?? null,
|
|
68
|
-
userMessageCount: turn?.items.filter((item) => item.type === "userMessage").length ?? 0
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function codexLastTerminalTurnId(thread, normalizeTurnId) {
|
|
72
|
-
for (let index = (thread.turns?.length ?? 0) - 1; index >= 0; index -= 1) {
|
|
73
|
-
const turn = thread.turns?.[index];
|
|
74
|
-
const turnId = normalizeTurnId(turn?.id);
|
|
75
|
-
if (!turn || !turnId) continue;
|
|
76
|
-
if (turn.status === "completed" || turn.status === "interrupted" || turn.status === "failed") return turnId;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/** Build the upstream link seed for a continued Codex session, if a baseline exists. */
|
|
80
|
-
function codexUpstreamContinueResult(sessionKey, threadId, baseline) {
|
|
81
|
-
if (!baseline) return { sessionKey };
|
|
82
|
-
return {
|
|
83
|
-
sessionKey,
|
|
84
|
-
upstream: {
|
|
85
|
-
kind: "codex-app-server",
|
|
86
|
-
ref: {
|
|
87
|
-
connectionFingerprint: baseline.connectionFingerprint,
|
|
88
|
-
threadId
|
|
89
|
-
},
|
|
90
|
-
marker: {
|
|
91
|
-
turnId: baseline.turnId,
|
|
92
|
-
userMessageCount: baseline.userMessageCount
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
//#endregion
|
|
98
|
-
export { createImportedCodexSession as i, codexUpstreamBaseline as n, codexUpstreamContinueResult as r, codexLastTerminalTurnId as t };
|
|
53
|
+
export { createImportedCodexSession };
|