@openclaw/codex 2026.7.1-beta.5 → 2026.7.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.
@@ -1,6 +1,6 @@
1
1
  import { r as isJsonObject } from "./protocol-2POPqAY4.js";
2
2
  import { n as canUseCodexModelBackedApprovalsReviewerForModel } from "./config-CYEDnLJ2.js";
3
- import { f as summarizeCodexAccountRateLimits, l as hasCodexRateLimitSnapshots, m as summarizeCodexRateLimits } from "./provider-cc_62eQE.js";
3
+ import { f as summarizeCodexAccountRateLimits, l as hasCodexRateLimitSnapshots, m as summarizeCodexRateLimits } from "./provider-zjPfx5Fs.js";
4
4
  //#region extensions/codex/src/command-formatters.ts
5
5
  /** Formats the combined `/codex status` probe result. */
6
6
  function formatCodexStatus(probes) {
@@ -2,15 +2,15 @@ import { r as isJsonObject } from "./protocol-2POPqAY4.js";
2
2
  import { o as isCodexFastServiceTier } from "./config-CYEDnLJ2.js";
3
3
  import { n as assertCodexThreadResumeResponse } from "./protocol-validators-dZQ-UTOa.js";
4
4
  import { t as listAllCodexAppServerModels } from "./models-DDmO1zwd.js";
5
- import { p as summarizeCodexAccountUsage } from "./provider-cc_62eQE.js";
5
+ import { p as summarizeCodexAccountUsage } from "./provider-zjPfx5Fs.js";
6
6
  import { y as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-4ICy3U6d.js";
7
- import { a as reclaimCurrentCodexSessionGeneration, i as normalizeCodexAppServerBindingModelProvider, n as bindingStoreKey, o as sessionBindingIdentity } from "./session-binding-Dc03iwRF.js";
8
- import { r as CODEX_CONTROL_METHODS } from "./plugin-app-cache-key-o-AHbdaf.js";
9
- import { a as formatCodexDisplayText, c as formatList, d as formatThreads, f as readString$1, i as formatAccount, l as formatModels, o as formatCodexStatus, r as buildHelp, s as formatComputerUseStatus, u as formatSkills } from "./app-server-policy-BUk0GLMy.js";
7
+ import { a as normalizeCodexAppServerBindingModelProvider, n as bindingStoreKey, o as reclaimCurrentCodexSessionGeneration, s as sessionBindingIdentity } from "./session-binding-C1ZXdP-x.js";
8
+ import { r as CODEX_CONTROL_METHODS } from "./plugin-app-cache-key-BrhVdeEf.js";
9
+ import { a as formatCodexDisplayText, c as formatList, d as formatThreads, f as readString$1, i as formatAccount, l as formatModels, o as formatCodexStatus, r as buildHelp, s as formatComputerUseStatus, u as formatSkills } from "./app-server-policy-C968Kgin.js";
10
10
  import { n as resolveCodexNativeExecutionBlock, r as resolveCodexNativeSandboxBlock } from "./sandbox-guard-DA2TQfZW.js";
11
- import { S as canMutateCodexHost, _ as setCodexConversationPermissions, d as formatPermissionsMode, f as parseCodexFastModeArg, g as setCodexConversationModel, h as setCodexConversationFastMode, i as safeCodexControlRequest, m as readCodexConversationActiveTurn, n as readCodexStatusProbes, p as parseCodexPermissionsModeArg, r as requestOptions, s as formatCodexCliSessions, t as codexControlRequest, v as steerCodexConversationTurn, x as CODEX_NATIVE_EXECUTION_AUTH_ERROR, y as stopCodexConversationTurn } from "./command-rpc-BjgEPh19.js";
11
+ import { S as canMutateCodexHost, _ as setCodexConversationPermissions, d as formatPermissionsMode, f as parseCodexFastModeArg, g as setCodexConversationModel, h as setCodexConversationFastMode, i as safeCodexControlRequest, m as readCodexConversationActiveTurn, n as readCodexStatusProbes, p as parseCodexPermissionsModeArg, r as requestOptions, s as formatCodexCliSessions, t as codexControlRequest, v as steerCodexConversationTurn, x as CODEX_NATIVE_EXECUTION_AUTH_ERROR, y as stopCodexConversationTurn } from "./command-rpc-eLM_mtC7.js";
12
12
  import { i as readCodexConversationBindingData, n as createCodexCliNodeConversationBindingData, o as resolveCodexDefaultWorkspaceDir, r as createCodexConversationBindingData } from "./conversation-binding-data-BHRpYbX3.js";
13
- import { n as installCodexComputerUse, r as readCodexComputerUseStatus } from "./computer-use-DDeySrnb.js";
13
+ import { n as installCodexComputerUse, r as readCodexComputerUseStatus } from "./computer-use-Bmaz333N.js";
14
14
  import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
15
15
  import crypto from "node:crypto";
16
16
  import { ensureAuthProfileStore, findNormalizedProviderValue, resolveAgentDir, resolveAuthProfileEligibility, resolveAuthProfileOrder, resolveDefaultAgentDir, resolveProfileUnusableUntilForDisplay, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
@@ -1,10 +1,10 @@
1
1
  import { d as resolveCodexAppServerRuntimeOptions, m as resolveCodexModelBackedReviewerPolicyContext, o as isCodexFastServiceTier } from "./config-CYEDnLJ2.js";
2
2
  import { n as listCodexAppServerModels } from "./models-DDmO1zwd.js";
3
- import { d as resolveCodexAppServerRequestModelSelection, p as resolveCodexBindingModelProviderFallback } from "./thread-lifecycle-BskXnNP-.js";
3
+ import { f as resolveCodexAppServerRequestModelSelection, m as resolveCodexBindingModelProviderFallback } from "./thread-lifecycle-qWE88Dn2.js";
4
4
  import { a as getLeasedSharedCodexAppServerClient, o as releaseLeasedSharedCodexAppServerClient } from "./shared-client-4ICy3U6d.js";
5
- import { i as normalizeCodexAppServerBindingModelProvider, n as bindingStoreKey, r as isCodexAppServerNativeAuthProfile } from "./session-binding-Dc03iwRF.js";
6
- import { i as describeControlFailure, r as CODEX_CONTROL_METHODS } from "./plugin-app-cache-key-o-AHbdaf.js";
7
- import { a as formatCodexDisplayText } from "./app-server-policy-BUk0GLMy.js";
5
+ import { a as normalizeCodexAppServerBindingModelProvider, i as isCodexAppServerNativeAuthProfile, n as bindingStoreKey } from "./session-binding-C1ZXdP-x.js";
6
+ import { i as describeControlFailure, r as CODEX_CONTROL_METHODS } from "./plugin-app-cache-key-BrhVdeEf.js";
7
+ import { a as formatCodexDisplayText } from "./app-server-policy-C968Kgin.js";
8
8
  import { t as requestCodexAppServerJson } from "./request-BcJyl8KL.js";
9
9
  import fs from "node:fs/promises";
10
10
  import path from "node:path";
@@ -2,7 +2,7 @@ import { r as isJsonObject } from "./protocol-2POPqAY4.js";
2
2
  import { _ as readCodexNotificationItem } from "./attempt-notifications-BGsEIIDI.js";
3
3
  import { d as resolveCodexAppServerRuntimeOptions } from "./config-CYEDnLJ2.js";
4
4
  import { a as getLeasedSharedCodexAppServerClient, o as releaseLeasedSharedCodexAppServerClient, u as CodexAppServerRpcError } from "./shared-client-4ICy3U6d.js";
5
- import { o as sessionBindingIdentity, t as CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS } from "./session-binding-Dc03iwRF.js";
5
+ import { s as sessionBindingIdentity, t as CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS } from "./session-binding-C1ZXdP-x.js";
6
6
  import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-DA2TQfZW.js";
7
7
  import { n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-Bo7KB3ks.js";
8
8
  import { embeddedAgentLog, resolveCompactionTimeoutMs } from "openclaw/plugin-sdk/agent-harness-runtime";
@@ -1,5 +1,5 @@
1
1
  import { d as resolveCodexAppServerRuntimeOptions, p as resolveCodexComputerUseConfig } from "./config-CYEDnLJ2.js";
2
- import { i as describeControlFailure } from "./plugin-app-cache-key-o-AHbdaf.js";
2
+ import { i as describeControlFailure } from "./plugin-app-cache-key-BrhVdeEf.js";
3
3
  import { t as requestCodexAppServerJson } from "./request-BcJyl8KL.js";
4
4
  import { existsSync } from "node:fs";
5
5
  //#region extensions/codex/src/app-server/computer-use.ts
@@ -88,20 +88,58 @@ async function collectLegacyBindingSources(params, options = {}) {
88
88
  surfaces
89
89
  };
90
90
  }
91
+ async function readLegacySessionIndex(storePath) {
92
+ let contents;
93
+ try {
94
+ contents = await fs.readFile(storePath, "utf8");
95
+ } catch (error) {
96
+ const code = error.code;
97
+ return code === "ENOENT" ? { entries: [] } : { failure: `session index ${storePath} could not be read${code ? ` (${code})` : ""}` };
98
+ }
99
+ let raw;
100
+ try {
101
+ raw = JSON.parse(contents);
102
+ } catch {
103
+ return { failure: `session index ${storePath} could not be read (invalid JSON)` };
104
+ }
105
+ if (!isRecord(raw)) return { failure: `session index ${storePath} has invalid entries` };
106
+ let normalizedEntries;
107
+ try {
108
+ normalizedEntries = listSessionEntries({
109
+ storePath,
110
+ hydrateSkillPromptRefs: false
111
+ });
112
+ } catch {
113
+ return { failure: `session index ${storePath} could not be normalized` };
114
+ }
115
+ const normalizedByKey = new Map(normalizedEntries.map(({ sessionKey, entry }) => [sessionKey, entry]));
116
+ const entries = [];
117
+ for (const [sessionKey, value] of Object.entries(raw)) {
118
+ if (!isRecord(value)) return { failure: `session index ${storePath} has invalid entries` };
119
+ if (value.sessionId === void 0) continue;
120
+ const rawSessionId = typeof value.sessionId === "string" ? value.sessionId.trim() : "";
121
+ const sessionId = normalizedByKey.get(sessionKey)?.sessionId?.trim() ?? "";
122
+ const sessionFile = value.sessionFile;
123
+ const lifecycleRevision = value.lifecycleRevision;
124
+ const agentHarnessId = value.agentHarnessId;
125
+ if (!sessionId || sessionId !== rawSessionId || sessionFile !== void 0 && typeof sessionFile !== "string" || lifecycleRevision !== void 0 && typeof lifecycleRevision !== "string" || agentHarnessId !== void 0 && typeof agentHarnessId !== "string") return { failure: `session index ${storePath} has invalid entries` };
126
+ entries.push({
127
+ sessionKey,
128
+ entry: {
129
+ sessionId,
130
+ ...typeof sessionFile === "string" ? { sessionFile } : {},
131
+ ...typeof lifecycleRevision === "string" ? { lifecycleRevision } : {},
132
+ ...typeof agentHarnessId === "string" ? { agentHarnessId } : {}
133
+ }
134
+ });
135
+ }
136
+ return { entries };
137
+ }
91
138
  async function* iterateIndexedSidecars(surface, params) {
92
139
  for (const storePath of surface.storePaths) {
93
- let entries;
94
- try {
95
- entries = listSessionEntries({
96
- storePath,
97
- hydrateSkillPromptRefs: false
98
- });
99
- } catch {
100
- continue;
101
- }
102
- for (const { sessionKey, entry } of entries) {
103
- const sessionId = entry.sessionId?.trim();
104
- if (!sessionId) continue;
140
+ const index = await readLegacySessionIndex(storePath);
141
+ if ("failure" in index) continue;
142
+ for (const { sessionKey, entry } of index.entries) {
105
143
  const agentId = resolveLegacyBindingOwnerAgentId({
106
144
  sessionKey,
107
145
  config: params.config,
@@ -109,7 +147,7 @@ async function* iterateIndexedSidecars(surface, params) {
109
147
  });
110
148
  let transcriptPath;
111
149
  try {
112
- transcriptPath = resolveSessionFilePath(sessionId, entry, {
150
+ transcriptPath = resolveSessionFilePath(entry.sessionId, entry, {
113
151
  sessionsDir: path.dirname(storePath),
114
152
  agentId
115
153
  });
@@ -149,55 +187,57 @@ async function collectBindingOwners(sources, surfaces, params) {
149
187
  for (const agentId of surface.agentIds) agents.add(agentId);
150
188
  storeAgentIds.set(storePath, agents);
151
189
  }
190
+ const failures = [];
152
191
  for (const storePath of storePaths) {
153
- let entries;
154
- try {
155
- entries = listSessionEntries({
156
- storePath,
157
- hydrateSkillPromptRefs: false
158
- });
159
- } catch {
192
+ const canonicalStorePath = await canonicalizePath(storePath);
193
+ const index = await readLegacySessionIndex(storePath);
194
+ if ("failure" in index) {
195
+ failures.push(index.failure);
160
196
  continue;
161
197
  }
162
198
  const sessionsDir = path.dirname(storePath);
163
- for (const { sessionKey, entry } of entries) {
164
- const sessionId = entry.sessionId?.trim();
165
- if (!sessionId) continue;
199
+ for (const { sessionKey, entry } of index.entries) {
200
+ const sessionId = entry.sessionId;
166
201
  const agentId = resolveLegacyBindingOwnerAgentId({
167
202
  sessionKey,
168
203
  config: params.config,
169
204
  storeAgentIds: storeAgentIds.get(storePath)
170
205
  });
171
- let transcriptPath;
172
- let legacyTranscriptPath;
206
+ let effectiveTranscriptPath;
173
207
  try {
174
- legacyTranscriptPath = resolveLegacySessionFileLocator(sessionsDir, entry, sessionId);
175
- transcriptPath = await canonicalizePath(resolveSessionFilePath(sessionId, entry, {
208
+ effectiveTranscriptPath = resolveSessionFilePath(sessionId, entry, {
176
209
  sessionsDir,
177
210
  agentId
178
- }));
211
+ });
179
212
  } catch {
213
+ failures.push(`session index ${storePath} has an invalid locator for ${sessionKey}`);
180
214
  continue;
181
215
  }
216
+ const transcriptPath = await canonicalizePath(effectiveTranscriptPath);
182
217
  if (!sourcePaths.has(transcriptPath)) continue;
183
218
  const owner = {
184
219
  agentId,
185
220
  sessionId,
186
221
  sessionKey,
187
222
  storePath,
188
- transcriptPath: legacyTranscriptPath,
223
+ transcriptPath: effectiveTranscriptPath,
224
+ ...entry.lifecycleRevision ? { lifecycleRevision: entry.lifecycleRevision } : {},
189
225
  ...entry.agentHarnessId?.trim() ? { agentHarnessId: entry.agentHarnessId.trim() } : {}
190
226
  };
191
227
  const candidates = owners.get(transcriptPath) ?? /* @__PURE__ */ new Map();
192
- candidates.set(`${agentId}\0${sessionId}\0${sessionKey}\0${storePath}`, owner);
228
+ const ownerKey = `${agentId}\0${sessionId}\0${sessionKey}\0${canonicalStorePath}`;
229
+ const configuredStorePath = resolveStorePath(params.config.session?.store, {
230
+ agentId,
231
+ env: params.env
232
+ });
233
+ if (!candidates.has(ownerKey) || storePath === configuredStorePath) candidates.set(ownerKey, owner);
193
234
  owners.set(transcriptPath, candidates);
194
235
  }
195
236
  }
196
- return new Map([...owners].map(([key, values]) => [key, [...values.values()]]));
197
- }
198
- function resolveLegacySessionFileLocator(sessionsDir, entry, sessionId) {
199
- const sessionFile = entry.sessionFile?.trim();
200
- return path.resolve(sessionsDir, sessionFile || `${sessionId}.jsonl`);
237
+ return {
238
+ owners: new Map([...owners].map(([key, values]) => [key, [...values.values()]])),
239
+ failures
240
+ };
201
241
  }
202
242
  function resolveLegacyBindingOwnerAgentId(params) {
203
243
  if (params.sessionKey.trim().toLowerCase().startsWith("agent:")) return resolveSessionAgentIds({
@@ -224,18 +264,19 @@ function copyBindingForSession(stored, sessionId) {
224
264
  ...stored.retired ? { retired: true } : {}
225
265
  };
226
266
  }
227
- async function migrateSource(source, owner, params, store) {
267
+ async function migrateSource(source, candidates, params, store) {
228
268
  let importedKeys = 0;
229
269
  const retain = (reason) => ({
230
270
  archived: false,
231
271
  importedKeys,
232
272
  warning: `Left Codex binding sidecar in place because ${reason}: ${source.sidecarPath}`
233
273
  });
274
+ const owner = candidates.length === 1 ? candidates[0] : void 0;
234
275
  try {
235
276
  return await withFileLock(source.sidecarPath, LEGACY_BINDING_LOCK_OPTIONS, async () => {
236
277
  const [contents, stat] = await Promise.all([fs.readFile(source.sidecarPath, "utf8"), fs.stat(source.sidecarPath)]);
237
278
  const raw = JSON.parse(contents);
238
- const [{ bindingStoreKey, createStoredCodexAppServerBinding, readCodexAppServerThreadBinding }, { legacyCodexConversationBindingId }] = await Promise.all([import("./session-binding-Dc03iwRF.js").then((n) => n.s), import("./conversation-binding-data-BHRpYbX3.js").then((n) => n.t)]);
279
+ const [{ bindingStoreKey, createStoredCodexAppServerBinding, normalizeStoredCodexAppServerBindingFingerprints, readStoredCodexAppServerBinding }, { legacyCodexConversationBindingId }] = await Promise.all([import("./session-binding-C1ZXdP-x.js").then((n) => n.c), import("./conversation-binding-data-BHRpYbX3.js").then((n) => n.t)]);
239
280
  const agentId = owner?.agentId ?? (source.agentIds.size === 1 ? [...source.agentIds][0] : void 0);
240
281
  const baseStored = createStoredCodexAppServerBinding(raw, {
241
282
  now: stat.mtime.toISOString(),
@@ -245,6 +286,7 @@ async function migrateSource(source, owner, params, store) {
245
286
  }
246
287
  });
247
288
  if (!baseStored) return retain("its binding is invalid");
289
+ if (candidates.length > 1) return retain(`${candidates.length} matching session owners make ownership ambiguous`);
248
290
  if (owner?.agentHarnessId && owner.agentHarnessId !== CODEX_AGENT_HARNESS_ID) return retain(`its session is owned by agent harness ${owner.agentHarnessId}`);
249
291
  const sourceSessionFile = typeof raw.sessionFile === "string" && raw.sessionFile.trim() ? raw.sessionFile : source.transcriptPath;
250
292
  const ownerSessionFile = typeof raw.sessionFile === "string" && raw.sessionFile.trim() ? raw.sessionFile : owner?.transcriptPath;
@@ -252,67 +294,137 @@ async function migrateSource(source, owner, params, store) {
252
294
  kind: "conversation",
253
295
  bindingId: legacyCodexConversationBindingId(sessionFile)
254
296
  }));
297
+ const normalizeStoredRow = async (key, current) => {
298
+ const parsed = readStoredCodexAppServerBinding(current);
299
+ if (!parsed) return { warning: `canonical plugin state is invalid at ${key}` };
300
+ const normalized = normalizeStoredCodexAppServerBindingFingerprints(parsed);
301
+ if (!normalized) return { warning: `canonical plugin state is invalid at ${key}` };
302
+ if (isDeepStrictEqual(parsed, normalized)) return { value: parsed };
303
+ if (parsed.lease && parsed.lease.expiresAt > Date.now()) return { warning: `canonical plugin state is leased at ${key}` };
304
+ const update = store.update;
305
+ if (!update) return { warning: `canonical plugin state could not be normalized at ${key}` };
306
+ await update(key, (candidate) => {
307
+ const candidateParsed = readStoredCodexAppServerBinding(candidate);
308
+ if (!candidateParsed || !isDeepStrictEqual(candidateParsed, parsed)) return;
309
+ return normalized;
310
+ });
311
+ const persisted = readStoredCodexAppServerBinding(await store.lookup(key));
312
+ if (!persisted || !isDeepStrictEqual(persisted, normalized)) return { warning: `canonical plugin state changed at ${key}` };
313
+ importedKeys++;
314
+ return { value: normalized };
315
+ };
255
316
  let currentConversation;
256
- for (const key of conversationKeys) currentConversation ??= await store.lookup(key);
317
+ for (const key of conversationKeys) {
318
+ const current = await store.lookup(key);
319
+ if (current === void 0) continue;
320
+ const result = await normalizeStoredRow(key, current);
321
+ if (result.warning || !result.value) return retain(result.warning ?? `canonical plugin state is invalid at ${key}`);
322
+ currentConversation ??= result.value;
323
+ }
257
324
  const stored = currentConversation ?? baseStored;
258
- if (stored.state !== "active" && stored.state !== "cleared") return retain(`canonical plugin state changed at ${conversationKeys[0]}`);
259
325
  const sessionKey = owner ? bindingStoreKey({
260
326
  kind: "session",
261
327
  agentId: owner.agentId,
262
328
  sessionId: owner.sessionId,
263
329
  sessionKey: owner.sessionKey
264
330
  }) : void 0;
265
- const entries = [...conversationKeys.map((key) => ({
331
+ const conversationEntries = conversationKeys.map((key) => ({
266
332
  key,
267
333
  value: stored
268
- })), ...owner && sessionKey ? [{
334
+ }));
335
+ const sessionEntry = owner && sessionKey ? {
269
336
  key: sessionKey,
270
337
  value: copyBindingForSession(stored, owner.sessionId)
271
- }] : []];
272
- const hasExpected = (value, expected) => expected.state === "cleared" ? value?.state === "cleared" && value.sessionId === expected.sessionId && value.retired === expected.retired : value?.state === "active" && value.sessionId === expected.sessionId && isDeepStrictEqual(readCodexAppServerThreadBinding(value.binding), expected.binding);
338
+ } : void 0;
339
+ const entries = [...conversationEntries, ...sessionEntry ? [sessionEntry] : []];
340
+ const hasExpected = (value, target) => {
341
+ const parsed = readStoredCodexAppServerBinding(value);
342
+ if (!parsed) return false;
343
+ return target.state === "cleared" ? parsed.state === "cleared" && parsed.sessionId === target.sessionId && parsed.retired === target.retired : parsed.state === "active" && parsed.sessionId === target.sessionId && isDeepStrictEqual(parsed.binding, target.binding);
344
+ };
273
345
  for (const entry of entries) {
274
346
  const current = await store.lookup(entry.key);
275
- if (current !== void 0 && !hasExpected(current, entry.value)) return retain(`canonical plugin state changed at ${entry.key}`);
347
+ if (current === void 0) continue;
348
+ const result = await normalizeStoredRow(entry.key, current);
349
+ if (result.warning || !result.value) return retain(result.warning ?? `canonical plugin state is invalid at ${entry.key}`);
350
+ if (!hasExpected(result.value, entry.value)) return retain(`canonical plugin state changed at ${entry.key}`);
276
351
  }
277
352
  for (const entry of entries) {
278
353
  if (await store.registerIfAbsent(entry.key, entry.value)) importedKeys++;
279
354
  if (!hasExpected(await store.lookup(entry.key), entry.value)) return retain(`canonical plugin state changed at ${entry.key}`);
280
355
  }
281
- if (!owner) return {
282
- archived: false,
283
- importedKeys,
284
- warning: `Left Codex binding sidecar in place after importing its conversation binding because its session owner could not be resolved: ${source.sidecarPath}`
285
- };
286
- const ownershipWarning = await recordSessionOwner(owner);
287
- if (ownershipWarning) return retain(ownershipWarning);
288
- for (const entry of entries) if (!hasExpected(await store.lookup(entry.key), entry.value)) return retain(`canonical plugin state changed at ${entry.key}`);
289
- const archivePath = `${source.sidecarPath}.migrated`;
290
- if (await pathExists(archivePath)) return retain(`its archive already exists at ${archivePath}`);
291
- await fs.rename(source.sidecarPath, archivePath);
356
+ if (owner) {
357
+ const ownershipWarning = await recordSessionOwner(owner);
358
+ if (ownershipWarning) {
359
+ if (sessionEntry?.value.state === "active") {
360
+ const update = store.update;
361
+ if (!update) return retain(`${ownershipWarning}; its stale session binding could not be retired`);
362
+ await update(sessionEntry.key, (current) => {
363
+ const parsed = readStoredCodexAppServerBinding(current);
364
+ if (parsed?.lease && parsed.lease.expiresAt > Date.now()) return;
365
+ if (!hasExpected(current, sessionEntry.value)) return;
366
+ return {
367
+ version: 1,
368
+ state: "cleared",
369
+ sessionId: owner.sessionId,
370
+ retired: true
371
+ };
372
+ });
373
+ if (hasExpected(await store.lookup(sessionEntry.key), sessionEntry.value)) return retain(`${ownershipWarning}; its stale session binding could not be retired`);
374
+ }
375
+ return retain(ownershipWarning);
376
+ }
377
+ for (const entry of entries) if (!hasExpected(await store.lookup(entry.key), entry.value)) return retain(`canonical plugin state changed at ${entry.key}`);
378
+ }
379
+ await archiveBindingSidecar(source.sidecarPath);
292
380
  return {
293
381
  archived: true,
294
382
  importedKeys
295
383
  };
296
384
  });
297
385
  } catch (error) {
386
+ if (error.code === "ENOENT" && !await pathExists(source.sidecarPath)) return {
387
+ archived: true,
388
+ importedKeys
389
+ };
298
390
  return retain(`migration or archiving failed: ${String(error)}`);
299
391
  }
300
392
  }
301
393
  async function recordSessionOwner(owner) {
394
+ let observedForeignHarness;
302
395
  const updated = await updateSessionStoreEntry({
303
396
  storePath: owner.storePath,
304
397
  sessionKey: owner.sessionKey,
305
398
  skipMaintenance: true,
306
399
  requireWriteSuccess: true,
307
400
  update: (entry) => {
308
- if (entry.sessionId.trim() !== owner.sessionId) return null;
309
- return entry.agentHarnessId?.trim() ? null : { agentHarnessId: CODEX_AGENT_HARNESS_ID };
401
+ const transcriptPath = resolveOwnerTranscriptPath(owner, entry);
402
+ if (entry.sessionId.trim() !== owner.sessionId || transcriptPath !== owner.transcriptPath || entry.lifecycleRevision !== owner.lifecycleRevision) return null;
403
+ const harnessId = typeof entry.agentHarnessId === "string" ? entry.agentHarnessId.trim() : void 0;
404
+ if (entry.agentHarnessId !== void 0 && harnessId === void 0) return null;
405
+ if (harnessId && harnessId !== CODEX_AGENT_HARNESS_ID) {
406
+ observedForeignHarness = harnessId;
407
+ return null;
408
+ }
409
+ return { agentHarnessId: CODEX_AGENT_HARNESS_ID };
310
410
  }
311
411
  });
312
- if (!updated || updated.sessionId.trim() !== owner.sessionId) return "its session owner changed before Codex ownership could be recorded";
412
+ if (!updated) return observedForeignHarness ? `its session is owned by agent harness ${observedForeignHarness}` : "its session owner changed before Codex ownership could be recorded";
413
+ const transcriptPath = resolveOwnerTranscriptPath(owner, updated);
414
+ if (updated.sessionId.trim() !== owner.sessionId || transcriptPath !== owner.transcriptPath || updated.lifecycleRevision !== owner.lifecycleRevision) return "its session owner changed before Codex ownership could be recorded";
313
415
  const harnessId = updated.agentHarnessId?.trim();
314
416
  return harnessId === CODEX_AGENT_HARNESS_ID ? void 0 : harnessId ? `its session is owned by agent harness ${harnessId}` : "Codex harness ownership could not be recorded on its session";
315
417
  }
418
+ function resolveOwnerTranscriptPath(owner, entry) {
419
+ try {
420
+ return resolveSessionFilePath(entry.sessionId, entry, {
421
+ sessionsDir: path.dirname(owner.storePath),
422
+ agentId: owner.agentId
423
+ });
424
+ } catch {
425
+ return;
426
+ }
427
+ }
316
428
  async function readDirectoryEntries(directory) {
317
429
  try {
318
430
  return await fs.readdir(directory, { withFileTypes: true });
@@ -333,6 +445,9 @@ async function isRegularFile(filePath) {
333
445
  return false;
334
446
  }
335
447
  }
448
+ function isRecord(value) {
449
+ return value !== null && typeof value === "object" && !Array.isArray(value);
450
+ }
336
451
  function isPathWithin(root, candidate) {
337
452
  const relative = path.relative(root, candidate);
338
453
  return relative === "" || relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
@@ -352,6 +467,25 @@ async function pathExists(filePath) {
352
467
  return false;
353
468
  }
354
469
  }
470
+ async function firstFreeArchivePath(sourcePath) {
471
+ for (let index = 2;; index++) {
472
+ const candidate = `${sourcePath}.migrated.${index}`;
473
+ if (!await pathExists(candidate)) return candidate;
474
+ }
475
+ }
476
+ async function archiveBindingSidecar(sourcePath) {
477
+ const archivePath = `${sourcePath}.migrated`;
478
+ if (await pathExists(archivePath)) {
479
+ const [sourceBytes, archiveBytes] = await Promise.all([fs.readFile(sourcePath), fs.readFile(archivePath)]);
480
+ if (sourceBytes.equals(archiveBytes)) {
481
+ await fs.rm(sourcePath, { force: true });
482
+ return;
483
+ }
484
+ await fs.rename(sourcePath, await firstFreeArchivePath(sourcePath));
485
+ return;
486
+ }
487
+ await fs.rename(sourcePath, archivePath);
488
+ }
355
489
  const stateMigrations = [{
356
490
  id: "codex-app-server-sidecars-to-plugin-state",
357
491
  label: "Codex app-server thread bindings",
@@ -367,7 +501,14 @@ const stateMigrations = [{
367
501
  changes,
368
502
  warnings
369
503
  };
370
- const owners = await collectBindingOwners(sources, surfaces, params);
504
+ const ownerCollection = await collectBindingOwners(sources, surfaces, params);
505
+ if (ownerCollection.failures.length > 0) {
506
+ warnings.push(`Left ${sources.length} Codex binding sidecar(s) in place because session ownership is indeterminate: ${ownerCollection.failures.join("; ")}`);
507
+ return {
508
+ changes,
509
+ warnings
510
+ };
511
+ }
371
512
  const store = params.context.openPluginStateKeyedStore({
372
513
  namespace: CODEX_APP_SERVER_BINDING_NAMESPACE,
373
514
  maxEntries: CODEX_APP_SERVER_BINDING_MAX_ENTRIES,
@@ -376,8 +517,7 @@ const stateMigrations = [{
376
517
  let migrated = 0;
377
518
  let partialImports = 0;
378
519
  for (const source of sources) {
379
- const candidates = owners.get(await canonicalizePath(source.transcriptPath)) ?? [];
380
- const result = await migrateSource(source, candidates.length === 1 ? candidates[0] : void 0, params, store);
520
+ const result = await migrateSource(source, ownerCollection.owners.get(await canonicalizePath(source.transcriptPath)) ?? [], params, store);
381
521
  if (result.warning) warnings.push(result.warning);
382
522
  if (result.archived) migrated++;
383
523
  else partialImports += result.importedKeys;
package/dist/harness.js CHANGED
@@ -32,7 +32,7 @@ function createCodexAppServerAgentHarness(options) {
32
32
  };
33
33
  },
34
34
  runAttempt: async (params) => {
35
- const { runCodexAppServerAttempt } = await import("./run-attempt-8SPLiDlT.js");
35
+ const { runCodexAppServerAttempt } = await import("./run-attempt-FUyOjGCV.js");
36
36
  return runCodexAppServerAttempt(params, {
37
37
  bindingStore: options.bindingStore,
38
38
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
@@ -40,7 +40,7 @@ function createCodexAppServerAgentHarness(options) {
40
40
  });
41
41
  },
42
42
  runSideQuestion: async (params) => {
43
- const { runCodexAppServerSideQuestion } = await import("./side-question-DkjXvYv7.js");
43
+ const { runCodexAppServerSideQuestion } = await import("./side-question-N4OaDer2.js");
44
44
  return runCodexAppServerSideQuestion(params, {
45
45
  bindingStore: options.bindingStore,
46
46
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
@@ -48,14 +48,14 @@ function createCodexAppServerAgentHarness(options) {
48
48
  });
49
49
  },
50
50
  compact: async (params) => {
51
- const { maybeCompactCodexAppServerSession } = await import("./compact-CZzbcygx.js");
51
+ const { maybeCompactCodexAppServerSession } = await import("./compact-4mVBriKT.js");
52
52
  return maybeCompactCodexAppServerSession(params, {
53
53
  bindingStore: options.bindingStore,
54
54
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig
55
55
  });
56
56
  },
57
57
  compactAfterContextEngine: async (params) => {
58
- const { maybeCompactCodexAppServerSession } = await import("./compact-CZzbcygx.js");
58
+ const { maybeCompactCodexAppServerSession } = await import("./compact-4mVBriKT.js");
59
59
  return maybeCompactCodexAppServerSession(params, {
60
60
  bindingStore: options.bindingStore,
61
61
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
@@ -64,7 +64,7 @@ function createCodexAppServerAgentHarness(options) {
64
64
  },
65
65
  reset: async (params) => {
66
66
  if (params.sessionId) {
67
- const { reclaimCurrentCodexSessionGeneration, sessionBindingIdentity } = await import("./session-binding-Dc03iwRF.js").then((n) => n.s);
67
+ const { reclaimCurrentCodexSessionGeneration, sessionBindingIdentity } = await import("./session-binding-C1ZXdP-x.js").then((n) => n.c);
68
68
  const identity = sessionBindingIdentity({
69
69
  agentId: params.agentId,
70
70
  sessionId: params.sessionId,
package/dist/index.js CHANGED
@@ -2,16 +2,16 @@ import { createCodexAppServerAgentHarness } from "./harness.js";
2
2
  import { r as isJsonObject, t as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS } from "./protocol-2POPqAY4.js";
3
3
  import { d as resolveCodexAppServerRuntimeOptions, g as resolveOpenClawExecPolicyForCodexAppServer, i as codexSandboxPolicyForTurn, n as canUseCodexModelBackedApprovalsReviewerForModel, t as CODEX_PLUGINS_MARKETPLACE_NAME, u as readCodexPluginConfig } from "./config-CYEDnLJ2.js";
4
4
  import { r as assertCodexThreadStartResponse } from "./protocol-validators-dZQ-UTOa.js";
5
- import { K as defaultCodexAppInventoryCache, U as ensureCodexPluginActivation, W as pluginReadParams, d as resolveCodexAppServerRequestModelSelection, t as CODEX_NATIVE_PERSONALITY_NONE } from "./thread-lifecycle-BskXnNP-.js";
6
- import { t as buildCodexProvider } from "./provider-cc_62eQE.js";
5
+ import { G as pluginReadParams, W as ensureCodexPluginActivation, f as resolveCodexAppServerRequestModelSelection, q as defaultCodexAppInventoryCache, t as CODEX_NATIVE_PERSONALITY_NONE } from "./thread-lifecycle-qWE88Dn2.js";
6
+ import { t as buildCodexProvider } from "./provider-zjPfx5Fs.js";
7
7
  import { _ as resolveCodexAppServerAuthAccountCacheKey, a as getLeasedSharedCodexAppServerClient, b as resolveCodexAppServerFallbackApiKeyCacheKey, o as releaseLeasedSharedCodexAppServerClient, r as clearSharedCodexAppServerClientIfCurrentAndWait, y as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-4ICy3U6d.js";
8
8
  import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./session-binding-meta-B7aEMU7g.js";
9
- import { i as normalizeCodexAppServerBindingModelProvider, o as sessionBindingIdentity, r as isCodexAppServerNativeAuthProfile } from "./session-binding-Dc03iwRF.js";
10
- import { t as buildCodexMediaUnderstandingProvider } from "./media-understanding-provider-DgqRvU2_.js";
11
- import { i as describeControlFailure, n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./plugin-app-cache-key-o-AHbdaf.js";
12
- import { a as formatCodexDisplayText, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-BUk0GLMy.js";
9
+ import { a as normalizeCodexAppServerBindingModelProvider, i as isCodexAppServerNativeAuthProfile, s as sessionBindingIdentity } from "./session-binding-C1ZXdP-x.js";
10
+ import { t as buildCodexMediaUnderstandingProvider } from "./media-understanding-provider-BHOu9-Gg.js";
11
+ import { i as describeControlFailure, n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./plugin-app-cache-key-BrhVdeEf.js";
12
+ import { a as formatCodexDisplayText, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-C968Kgin.js";
13
13
  import { n as resolveCodexNativeExecutionBlock, r as resolveCodexNativeSandboxBlock } from "./sandbox-guard-DA2TQfZW.js";
14
- import { S as canMutateCodexHost, a as createCodexCliSessionNodeHostCommands, b as trackCodexConversationActiveTurn, c as listCodexCliSessionsOnNode, l as resolveCodexCliSessionForBindingOnNode, o as createCodexCliSessionNodeInvokePolicies, t as codexControlRequest, u as resumeCodexCliSessionOnNode, x as CODEX_NATIVE_EXECUTION_AUTH_ERROR } from "./command-rpc-BjgEPh19.js";
14
+ import { S as canMutateCodexHost, a as createCodexCliSessionNodeHostCommands, b as trackCodexConversationActiveTurn, c as listCodexCliSessionsOnNode, l as resolveCodexCliSessionForBindingOnNode, o as createCodexCliSessionNodeInvokePolicies, t as codexControlRequest, u as resumeCodexCliSessionOnNode, x as CODEX_NATIVE_EXECUTION_AUTH_ERROR } from "./command-rpc-eLM_mtC7.js";
15
15
  import { a as readCodexConversationBindingDataRecord, i as readCodexConversationBindingData } from "./conversation-binding-data-BHRpYbX3.js";
16
16
  import { n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-Bo7KB3ks.js";
17
17
  import { t as requestCodexAppServerJson } from "./request-BcJyl8KL.js";
@@ -43,7 +43,7 @@ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
43
43
  /** Defers schema compilation and auth loading until the first binding operation. */
44
44
  function createLazyCodexAppServerBindingStore(state) {
45
45
  let resolved;
46
- const store = () => resolved ??= import("./session-binding-Dc03iwRF.js").then((n) => n.s).then(({ createCodexAppServerBindingStore }) => createCodexAppServerBindingStore(state));
46
+ const store = () => resolved ??= import("./session-binding-C1ZXdP-x.js").then((n) => n.c).then(({ createCodexAppServerBindingStore }) => createCodexAppServerBindingStore(state));
47
47
  return {
48
48
  read: async (identity) => (await store()).read(identity),
49
49
  mutate: async (identity, mutation) => (await store()).mutate(identity, mutation),
@@ -86,7 +86,7 @@ async function handleCodexCommand(ctx, options) {
86
86
  }
87
87
  }
88
88
  async function loadDefaultCodexSubcommandHandler() {
89
- const { handleCodexSubcommand } = await import("./command-handlers-UVniG5Hl.js");
89
+ const { handleCodexSubcommand } = await import("./command-handlers-Dv-pzAmg.js");
90
90
  return handleCodexSubcommand;
91
91
  }
92
92
  //#endregion
@@ -914,7 +914,7 @@ async function readJsonObject(filePath) {
914
914
  //#endregion
915
915
  //#region extensions/codex/src/migration/auth.ts
916
916
  const OPENAI_PROVIDER_ID = "openai";
917
- const OPENAI_CODEX_DEFAULT_MODEL = "openai/gpt-5.5";
917
+ const OPENAI_CODEX_DEFAULT_MODEL = "openai/gpt-5.6-sol";
918
918
  const CODEX_IMPORT_DISPLAY_NAME = "Codex import";
919
919
  const CODEX_REASON_AUTH_NOT_SELECTED = "auth credential migration not selected";
920
920
  const CODEX_REASON_AUTH_PROFILE_EXISTS = "auth profile exists";
@@ -2583,7 +2583,7 @@ function createCodexThreadsTool(options) {
2583
2583
  }
2584
2584
  //#endregion
2585
2585
  //#region extensions/codex/src/web-search-provider.ts
2586
- const loadCodexWebSearchRuntime = createLazyRuntimeModule(() => import("./web-search-provider.runtime-B5F42P7x.js"));
2586
+ const loadCodexWebSearchRuntime = createLazyRuntimeModule(() => import("./web-search-provider.runtime-BSlriav6.js"));
2587
2587
  const CodexWebSearchSchema = {
2588
2588
  type: "object",
2589
2589
  properties: { query: {
@@ -2726,7 +2726,7 @@ var codex_default = definePluginEntry({
2726
2726
  if (!previousSessionId || !sessionId || previousSessionId === sessionId) return;
2727
2727
  const config = resolveCurrentConfig();
2728
2728
  const sessionKey = ctx.sessionKey?.trim();
2729
- const { sessionBindingIdentity } = await import("./session-binding-Dc03iwRF.js").then((n) => n.s);
2729
+ const { sessionBindingIdentity } = await import("./session-binding-C1ZXdP-x.js").then((n) => n.c);
2730
2730
  const identity = sessionBindingIdentity({
2731
2731
  sessionId,
2732
2732
  ...sessionKey ? { sessionKey } : {},
@@ -2740,7 +2740,7 @@ var codex_default = definePluginEntry({
2740
2740
  if (!event.reason || !ENDED_SESSION_REASONS.has(event.reason)) return;
2741
2741
  const sessionKey = event.sessionKey ?? ctx.sessionKey;
2742
2742
  const config = resolveCurrentConfig();
2743
- const { sessionBindingIdentity } = await import("./session-binding-Dc03iwRF.js").then((n) => n.s);
2743
+ const { sessionBindingIdentity } = await import("./session-binding-C1ZXdP-x.js").then((n) => n.c);
2744
2744
  await bindingStore.retireSessionGeneration(sessionBindingIdentity({
2745
2745
  sessionId: event.sessionId,
2746
2746
  ...sessionKey ? { sessionKey } : {},
@@ -4,7 +4,7 @@ import { _ as readCodexNotificationItem } from "./attempt-notifications-BGsEIIDI
4
4
  import { d as resolveCodexAppServerRuntimeOptions } from "./config-CYEDnLJ2.js";
5
5
  import { i as assertCodexTurnStartResponse, l as readCodexTurnCompletedNotification, o as readCodexErrorNotification, r as assertCodexThreadStartResponse } from "./protocol-validators-dZQ-UTOa.js";
6
6
  import { i as readModelListResult } from "./models-DDmO1zwd.js";
7
- import { V as mergeCodexThreadConfigs, r as buildCodexRuntimeThreadConfig } from "./thread-lifecycle-BskXnNP-.js";
7
+ import { H as mergeCodexThreadConfigs, r as buildCodexRuntimeThreadConfig } from "./thread-lifecycle-qWE88Dn2.js";
8
8
  import { validateJsonSchemaValue } from "openclaw/plugin-sdk/json-schema-runtime";
9
9
  import fs from "node:fs/promises";
10
10
  import path from "node:path";
@@ -1,2 +1,2 @@
1
- import { t as buildCodexMediaUnderstandingProvider } from "./media-understanding-provider-DgqRvU2_.js";
1
+ import { t as buildCodexMediaUnderstandingProvider } from "./media-understanding-provider-BHOu9-Gg.js";
2
2
  export { buildCodexMediaUnderstandingProvider };
@@ -1,4 +1,4 @@
1
- import { G as buildCodexAppInventoryCacheKey } from "./thread-lifecycle-BskXnNP-.js";
1
+ import { K as buildCodexAppInventoryCacheKey } from "./thread-lifecycle-qWE88Dn2.js";
2
2
  import { u as CodexAppServerRpcError, x as resolveCodexAppServerHomeDir } from "./shared-client-4ICy3U6d.js";
3
3
  import { createRequire } from "node:module";
4
4
  import { createHash } from "node:crypto";