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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/{app-server-policy-B7hqD3Xj.js → app-server-policy-BUk0GLMy.js} +5 -5
  2. package/dist/{attempt-notifications-tqyQ_Tdn.js → attempt-notifications-BGsEIIDI.js} +5 -40
  3. package/dist/{command-handlers-C9K-KRU-.js → command-handlers-UVniG5Hl.js} +267 -232
  4. package/dist/command-rpc-BjgEPh19.js +784 -0
  5. package/dist/compact-CZzbcygx.js +603 -0
  6. package/dist/{computer-use-CpurU-G9.js → computer-use-DDeySrnb.js} +3 -3
  7. package/dist/{config-C_whBx3M.js → config-CYEDnLJ2.js} +36 -15
  8. package/dist/conversation-binding-data-BHRpYbX3.js +121 -0
  9. package/dist/doctor-contract-api.js +439 -22
  10. package/dist/harness.js +29 -10
  11. package/dist/index.js +1117 -19
  12. package/dist/{media-understanding-provider-BOeoBhEw.js → media-understanding-provider-DgqRvU2_.js} +13 -8
  13. package/dist/media-understanding-provider.js +1 -1
  14. package/dist/{models-DpzY1xpp.js → models-DDmO1zwd.js} +2 -2
  15. package/dist/notification-correlation-Bo7KB3ks.js +35 -0
  16. package/dist/{plugin-app-cache-key-BrZUG9jj.js → plugin-app-cache-key-o-AHbdaf.js} +8 -4
  17. package/dist/{protocol-dh-ETiNd.js → protocol-2POPqAY4.js} +2 -1
  18. package/dist/{protocol-validators-CJiWigAJ.js → protocol-validators-dZQ-UTOa.js} +116 -59
  19. package/dist/{provider-capabilities-wqedK49Z.js → provider-capabilities-gTCwjfmh.js} +2916 -114
  20. package/dist/{provider-nmtMDcGH.js → provider-cc_62eQE.js} +19 -10
  21. package/dist/provider.js +2 -2
  22. package/dist/{request-BQuSQF29.js → request-BcJyl8KL.js} +2 -2
  23. package/dist/{run-attempt-DikbXia_.js → run-attempt-8SPLiDlT.js} +907 -3002
  24. package/dist/{sandbox-guard-pTY2COoC.js → sandbox-guard-DA2TQfZW.js} +3 -3
  25. package/dist/session-binding-Dc03iwRF.js +595 -0
  26. package/dist/session-binding-meta-B7aEMU7g.js +6 -0
  27. package/dist/{shared-client-rR6TDJA3.js → shared-client-4ICy3U6d.js} +892 -103
  28. package/dist/{side-question-Ca9wqmd0.js → side-question-DkjXvYv7.js} +132 -140
  29. package/dist/{thread-lifecycle-D6R40plk.js → thread-lifecycle-BskXnNP-.js} +609 -444
  30. package/dist/{web-search-provider.runtime-B6eZEFmd.js → web-search-provider.runtime-B5F42P7x.js} +3 -3
  31. package/npm-shrinkwrap.json +34 -34
  32. package/openclaw.plugin.json +20 -0
  33. package/package.json +9 -6
  34. package/dist/client-IcTBKEqA.js +0 -732
  35. package/dist/client-factory-DfFu9JH_.js +0 -15
  36. package/dist/compact-CILptrPS.js +0 -278
  37. package/dist/conversation-binding-DOJtUxOy.js +0 -1570
  38. package/dist/rate-limit-cache-C7qmZ0Jh.js +0 -26
  39. package/dist/session-binding-Cm0Gg7Z1.js +0 -339
@@ -1,3 +1,396 @@
1
+ import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./session-binding-meta-B7aEMU7g.js";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { listAgentIds, resolveAgentDir, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
5
+ import { isDeepStrictEqual } from "node:util";
6
+ import { listSessionEntries, resolveSessionFilePath, resolveStorePath, updateSessionStoreEntry } from "openclaw/plugin-sdk/session-store-runtime";
7
+ import { withFileLock } from "openclaw/plugin-sdk/file-lock";
8
+ //#region extensions/codex/src/migration/session-binding-sidecars.ts
9
+ const LEGACY_BINDING_SUFFIX = ".codex-app-server.json";
10
+ const CODEX_AGENT_HARNESS_ID = "codex";
11
+ const MAX_SESSION_DIRECTORY_DEPTH = 16;
12
+ const LEGACY_BINDING_LOCK_OPTIONS = {
13
+ retries: {
14
+ retries: 75,
15
+ factor: 1,
16
+ minTimeout: 1e3,
17
+ maxTimeout: 1e3
18
+ },
19
+ stale: 12e4
20
+ };
21
+ async function collectSessionSurfaces(params) {
22
+ const surfaces = /* @__PURE__ */ new Map();
23
+ const stateRoot = await canonicalizePath(params.stateDir);
24
+ const add = async (root, storePath, agentId, scan) => {
25
+ const canonicalRoot = await canonicalizePath(root);
26
+ const surface = surfaces.get(canonicalRoot) ?? {
27
+ root: canonicalRoot,
28
+ scan: false,
29
+ storePaths: /* @__PURE__ */ new Set(),
30
+ agentIds: /* @__PURE__ */ new Set()
31
+ };
32
+ surface.scan ||= scan;
33
+ surface.storePaths.add(path.resolve(storePath));
34
+ surface.agentIds.add(agentId);
35
+ surfaces.set(canonicalRoot, surface);
36
+ };
37
+ const agentIds = new Set(listAgentIds(params.config));
38
+ const agentsDir = path.join(params.stateDir, "agents");
39
+ for (const entry of await readDirectoryEntries(agentsDir)) {
40
+ if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
41
+ const agentId = resolveSessionAgentIds({
42
+ agentId: entry.name,
43
+ config: params.config
44
+ }).sessionAgentId;
45
+ agentIds.add(agentId);
46
+ const root = path.join(agentsDir, entry.name, "sessions");
47
+ await add(root, path.join(root, "sessions.json"), agentId, true);
48
+ }
49
+ for (const agentId of agentIds) {
50
+ const storePath = resolveStorePath(params.config.session?.store, {
51
+ agentId,
52
+ env: params.env
53
+ });
54
+ const root = path.dirname(storePath);
55
+ await add(root, storePath, agentId, isPathWithin(stateRoot, await canonicalizePath(root)));
56
+ }
57
+ const legacyRoot = path.join(params.stateDir, "sessions");
58
+ const defaultAgentId = resolveSessionAgentIds({ config: params.config }).defaultAgentId;
59
+ await add(legacyRoot, path.join(legacyRoot, "sessions.json"), defaultAgentId, true);
60
+ return [...surfaces.values()].toSorted((a, b) => a.root.localeCompare(b.root));
61
+ }
62
+ async function collectLegacyBindingSources(params, options = {}) {
63
+ const surfaces = await collectSessionSurfaces(params);
64
+ const sources = /* @__PURE__ */ new Map();
65
+ const addSource = async (sidecarPath, surface) => {
66
+ const canonicalSidecar = await canonicalizePath(sidecarPath);
67
+ const source = sources.get(canonicalSidecar) ?? {
68
+ sidecarPath: canonicalSidecar,
69
+ transcriptPath: sidecarPath.slice(0, -22),
70
+ agentIds: /* @__PURE__ */ new Set()
71
+ };
72
+ for (const agentId of surface.agentIds) source.agentIds.add(agentId);
73
+ sources.set(canonicalSidecar, source);
74
+ return source;
75
+ };
76
+ for (const surface of surfaces) {
77
+ const sidecars = surface.scan ? walkSidecars(surface.root) : iterateIndexedSidecars(surface, params);
78
+ for await (const sidecarPath of sidecars) {
79
+ const source = await addSource(sidecarPath, surface);
80
+ if (options.firstOnly) return {
81
+ sources: [source],
82
+ surfaces
83
+ };
84
+ }
85
+ }
86
+ return {
87
+ sources: [...sources.values()].toSorted((a, b) => a.sidecarPath.localeCompare(b.sidecarPath)),
88
+ surfaces
89
+ };
90
+ }
91
+ async function* iterateIndexedSidecars(surface, params) {
92
+ 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;
105
+ const agentId = resolveLegacyBindingOwnerAgentId({
106
+ sessionKey,
107
+ config: params.config,
108
+ storeAgentIds: surface.agentIds
109
+ });
110
+ let transcriptPath;
111
+ try {
112
+ transcriptPath = resolveSessionFilePath(sessionId, entry, {
113
+ sessionsDir: path.dirname(storePath),
114
+ agentId
115
+ });
116
+ } catch {
117
+ continue;
118
+ }
119
+ const sidecarPath = `${transcriptPath}${LEGACY_BINDING_SUFFIX}`;
120
+ if (await isRegularFile(sidecarPath)) yield sidecarPath;
121
+ }
122
+ }
123
+ }
124
+ async function* walkSidecars(root) {
125
+ const pending = [{
126
+ directory: root,
127
+ depth: 0
128
+ }];
129
+ while (pending.length > 0) {
130
+ const current = pending.pop();
131
+ for (const entry of (await readDirectoryEntries(current.directory)).toSorted((a, b) => a.name.localeCompare(b.name))) {
132
+ if (entry.isSymbolicLink()) continue;
133
+ const entryPath = path.join(current.directory, entry.name);
134
+ if (entry.isFile() && entry.name.endsWith(LEGACY_BINDING_SUFFIX)) yield entryPath;
135
+ else if (entry.isDirectory() && current.depth < MAX_SESSION_DIRECTORY_DEPTH) pending.push({
136
+ directory: entryPath,
137
+ depth: current.depth + 1
138
+ });
139
+ }
140
+ }
141
+ }
142
+ async function collectBindingOwners(sources, surfaces, params) {
143
+ const sourcePaths = new Set(await Promise.all(sources.map((source) => canonicalizePath(source.transcriptPath))));
144
+ const owners = /* @__PURE__ */ new Map();
145
+ const storePaths = new Set(surfaces.flatMap((surface) => [...surface.storePaths]));
146
+ const storeAgentIds = /* @__PURE__ */ new Map();
147
+ for (const surface of surfaces) for (const storePath of surface.storePaths) {
148
+ const agents = storeAgentIds.get(storePath) ?? /* @__PURE__ */ new Set();
149
+ for (const agentId of surface.agentIds) agents.add(agentId);
150
+ storeAgentIds.set(storePath, agents);
151
+ }
152
+ for (const storePath of storePaths) {
153
+ let entries;
154
+ try {
155
+ entries = listSessionEntries({
156
+ storePath,
157
+ hydrateSkillPromptRefs: false
158
+ });
159
+ } catch {
160
+ continue;
161
+ }
162
+ const sessionsDir = path.dirname(storePath);
163
+ for (const { sessionKey, entry } of entries) {
164
+ const sessionId = entry.sessionId?.trim();
165
+ if (!sessionId) continue;
166
+ const agentId = resolveLegacyBindingOwnerAgentId({
167
+ sessionKey,
168
+ config: params.config,
169
+ storeAgentIds: storeAgentIds.get(storePath)
170
+ });
171
+ let transcriptPath;
172
+ let legacyTranscriptPath;
173
+ try {
174
+ legacyTranscriptPath = resolveLegacySessionFileLocator(sessionsDir, entry, sessionId);
175
+ transcriptPath = await canonicalizePath(resolveSessionFilePath(sessionId, entry, {
176
+ sessionsDir,
177
+ agentId
178
+ }));
179
+ } catch {
180
+ continue;
181
+ }
182
+ if (!sourcePaths.has(transcriptPath)) continue;
183
+ const owner = {
184
+ agentId,
185
+ sessionId,
186
+ sessionKey,
187
+ storePath,
188
+ transcriptPath: legacyTranscriptPath,
189
+ ...entry.agentHarnessId?.trim() ? { agentHarnessId: entry.agentHarnessId.trim() } : {}
190
+ };
191
+ const candidates = owners.get(transcriptPath) ?? /* @__PURE__ */ new Map();
192
+ candidates.set(`${agentId}\0${sessionId}\0${sessionKey}\0${storePath}`, owner);
193
+ owners.set(transcriptPath, candidates);
194
+ }
195
+ }
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`);
201
+ }
202
+ function resolveLegacyBindingOwnerAgentId(params) {
203
+ if (params.sessionKey.trim().toLowerCase().startsWith("agent:")) return resolveSessionAgentIds({
204
+ sessionKey: params.sessionKey,
205
+ config: params.config
206
+ }).sessionAgentId;
207
+ const storeAgentId = params.storeAgentIds?.size === 1 ? [...params.storeAgentIds][0] : void 0;
208
+ return resolveSessionAgentIds({
209
+ sessionKey: params.sessionKey,
210
+ config: params.config,
211
+ ...storeAgentId ? { agentId: storeAgentId } : {}
212
+ }).sessionAgentId;
213
+ }
214
+ function copyBindingForSession(stored, sessionId) {
215
+ return stored.state === "active" ? {
216
+ version: 1,
217
+ state: "active",
218
+ binding: stored.binding,
219
+ sessionId
220
+ } : {
221
+ version: 1,
222
+ state: "cleared",
223
+ sessionId,
224
+ ...stored.retired ? { retired: true } : {}
225
+ };
226
+ }
227
+ async function migrateSource(source, owner, params, store) {
228
+ let importedKeys = 0;
229
+ const retain = (reason) => ({
230
+ archived: false,
231
+ importedKeys,
232
+ warning: `Left Codex binding sidecar in place because ${reason}: ${source.sidecarPath}`
233
+ });
234
+ try {
235
+ return await withFileLock(source.sidecarPath, LEGACY_BINDING_LOCK_OPTIONS, async () => {
236
+ const [contents, stat] = await Promise.all([fs.readFile(source.sidecarPath, "utf8"), fs.stat(source.sidecarPath)]);
237
+ 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)]);
239
+ const agentId = owner?.agentId ?? (source.agentIds.size === 1 ? [...source.agentIds][0] : void 0);
240
+ const baseStored = createStoredCodexAppServerBinding(raw, {
241
+ now: stat.mtime.toISOString(),
242
+ lookup: {
243
+ config: params.config,
244
+ ...agentId ? { agentDir: resolveAgentDir(params.config, agentId, params.env) } : {}
245
+ }
246
+ });
247
+ if (!baseStored) return retain("its binding is invalid");
248
+ if (owner?.agentHarnessId && owner.agentHarnessId !== CODEX_AGENT_HARNESS_ID) return retain(`its session is owned by agent harness ${owner.agentHarnessId}`);
249
+ const sourceSessionFile = typeof raw.sessionFile === "string" && raw.sessionFile.trim() ? raw.sessionFile : source.transcriptPath;
250
+ const ownerSessionFile = typeof raw.sessionFile === "string" && raw.sessionFile.trim() ? raw.sessionFile : owner?.transcriptPath;
251
+ const conversationKeys = [sourceSessionFile, ...ownerSessionFile && ownerSessionFile !== sourceSessionFile ? [ownerSessionFile] : []].map((sessionFile) => bindingStoreKey({
252
+ kind: "conversation",
253
+ bindingId: legacyCodexConversationBindingId(sessionFile)
254
+ }));
255
+ let currentConversation;
256
+ for (const key of conversationKeys) currentConversation ??= await store.lookup(key);
257
+ const stored = currentConversation ?? baseStored;
258
+ if (stored.state !== "active" && stored.state !== "cleared") return retain(`canonical plugin state changed at ${conversationKeys[0]}`);
259
+ const sessionKey = owner ? bindingStoreKey({
260
+ kind: "session",
261
+ agentId: owner.agentId,
262
+ sessionId: owner.sessionId,
263
+ sessionKey: owner.sessionKey
264
+ }) : void 0;
265
+ const entries = [...conversationKeys.map((key) => ({
266
+ key,
267
+ value: stored
268
+ })), ...owner && sessionKey ? [{
269
+ key: sessionKey,
270
+ 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);
273
+ for (const entry of entries) {
274
+ 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}`);
276
+ }
277
+ for (const entry of entries) {
278
+ if (await store.registerIfAbsent(entry.key, entry.value)) importedKeys++;
279
+ if (!hasExpected(await store.lookup(entry.key), entry.value)) return retain(`canonical plugin state changed at ${entry.key}`);
280
+ }
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);
292
+ return {
293
+ archived: true,
294
+ importedKeys
295
+ };
296
+ });
297
+ } catch (error) {
298
+ return retain(`migration or archiving failed: ${String(error)}`);
299
+ }
300
+ }
301
+ async function recordSessionOwner(owner) {
302
+ const updated = await updateSessionStoreEntry({
303
+ storePath: owner.storePath,
304
+ sessionKey: owner.sessionKey,
305
+ skipMaintenance: true,
306
+ requireWriteSuccess: true,
307
+ update: (entry) => {
308
+ if (entry.sessionId.trim() !== owner.sessionId) return null;
309
+ return entry.agentHarnessId?.trim() ? null : { agentHarnessId: CODEX_AGENT_HARNESS_ID };
310
+ }
311
+ });
312
+ if (!updated || updated.sessionId.trim() !== owner.sessionId) return "its session owner changed before Codex ownership could be recorded";
313
+ const harnessId = updated.agentHarnessId?.trim();
314
+ 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
+ }
316
+ async function readDirectoryEntries(directory) {
317
+ try {
318
+ return await fs.readdir(directory, { withFileTypes: true });
319
+ } catch (error) {
320
+ if ([
321
+ "EACCES",
322
+ "ENOENT",
323
+ "ENOTDIR",
324
+ "EPERM"
325
+ ].includes(error.code ?? "")) return [];
326
+ throw error;
327
+ }
328
+ }
329
+ async function isRegularFile(filePath) {
330
+ try {
331
+ return (await fs.stat(filePath)).isFile();
332
+ } catch {
333
+ return false;
334
+ }
335
+ }
336
+ function isPathWithin(root, candidate) {
337
+ const relative = path.relative(root, candidate);
338
+ return relative === "" || relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
339
+ }
340
+ async function canonicalizePath(filePath) {
341
+ try {
342
+ return await fs.realpath(filePath);
343
+ } catch {
344
+ return path.resolve(filePath);
345
+ }
346
+ }
347
+ async function pathExists(filePath) {
348
+ try {
349
+ await fs.access(filePath);
350
+ return true;
351
+ } catch {
352
+ return false;
353
+ }
354
+ }
355
+ const stateMigrations = [{
356
+ id: "codex-app-server-sidecars-to-plugin-state",
357
+ label: "Codex app-server thread bindings",
358
+ async detectLegacyState(params) {
359
+ const { sources } = await collectLegacyBindingSources(params, { firstOnly: true });
360
+ return sources.length > 0 ? { preview: [`- Codex app-server bindings: legacy sidecar -> plugin state (${CODEX_APP_SERVER_BINDING_NAMESPACE})`] } : null;
361
+ },
362
+ async migrateLegacyState(params) {
363
+ const changes = [];
364
+ const warnings = [];
365
+ const { sources, surfaces } = await collectLegacyBindingSources(params);
366
+ if (sources.length === 0) return {
367
+ changes,
368
+ warnings
369
+ };
370
+ const owners = await collectBindingOwners(sources, surfaces, params);
371
+ const store = params.context.openPluginStateKeyedStore({
372
+ namespace: CODEX_APP_SERVER_BINDING_NAMESPACE,
373
+ maxEntries: CODEX_APP_SERVER_BINDING_MAX_ENTRIES,
374
+ overflowPolicy: "reject-new"
375
+ });
376
+ let migrated = 0;
377
+ let partialImports = 0;
378
+ 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);
381
+ if (result.warning) warnings.push(result.warning);
382
+ if (result.archived) migrated++;
383
+ else partialImports += result.importedKeys;
384
+ }
385
+ if (migrated > 0) changes.push(`Migrated ${migrated} Codex app-server binding sidecar(s) to plugin state and archived the legacy sources`);
386
+ if (partialImports > 0) changes.push(`Migrated ${partialImports} safe Codex app-server binding row(s) to plugin state; retained legacy sidecars needing review`);
387
+ return {
388
+ changes,
389
+ warnings
390
+ };
391
+ }
392
+ }];
393
+ //#endregion
1
394
  //#region extensions/codex/doctor-contract-api.ts
2
395
  function asRecord(value) {
3
396
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -12,36 +405,55 @@ function hasLegacyPluginDestructivePolicy(value) {
12
405
  const plugins = asRecord(codexPlugins.plugins);
13
406
  return Object.values(plugins ?? {}).some((plugin) => asRecord(plugin)?.allow_destructive_actions === "on-request");
14
407
  }
408
+ function hasRetiredOnFailureApprovalPolicy(value) {
409
+ return asRecord(value)?.approvalPolicy === "on-failure";
410
+ }
15
411
  /** Legacy Codex config keys that doctor should report or repair. */
16
- const legacyConfigRules = [{
17
- path: [
18
- "plugins",
19
- "entries",
20
- "codex",
21
- "config"
22
- ],
23
- message: "plugins.entries.codex.config.codexDynamicToolsProfile is retired; Codex app-server always keeps Codex-native workspace tools native. Run \"openclaw doctor --fix\".",
24
- match: hasRetiredDynamicToolsProfile
25
- }, {
26
- path: [
27
- "plugins",
28
- "entries",
29
- "codex",
30
- "config",
31
- "codexPlugins"
32
- ],
33
- message: "plugins.entries.codex.config.codexPlugins.allow_destructive_actions=\"on-request\" was renamed to \"auto\". Run \"openclaw doctor --fix\".",
34
- match: hasLegacyPluginDestructivePolicy
35
- }];
412
+ const legacyConfigRules = [
413
+ {
414
+ path: [
415
+ "plugins",
416
+ "entries",
417
+ "codex",
418
+ "config"
419
+ ],
420
+ message: "plugins.entries.codex.config.codexDynamicToolsProfile is retired; Codex app-server always keeps Codex-native workspace tools native. Run \"openclaw doctor --fix\".",
421
+ match: hasRetiredDynamicToolsProfile
422
+ },
423
+ {
424
+ path: [
425
+ "plugins",
426
+ "entries",
427
+ "codex",
428
+ "config",
429
+ "codexPlugins"
430
+ ],
431
+ message: "plugins.entries.codex.config.codexPlugins.allow_destructive_actions=\"on-request\" was renamed to \"auto\". Run \"openclaw doctor --fix\".",
432
+ match: hasLegacyPluginDestructivePolicy
433
+ },
434
+ {
435
+ path: [
436
+ "plugins",
437
+ "entries",
438
+ "codex",
439
+ "config",
440
+ "appServer"
441
+ ],
442
+ message: "plugins.entries.codex.config.appServer.approvalPolicy=\"on-failure\" was retired by Codex 0.143; use \"on-request\". Run \"openclaw doctor --fix\".",
443
+ match: hasRetiredOnFailureApprovalPolicy
444
+ }
445
+ ];
36
446
  /**
37
447
  * Removes retired Codex plugin config keys while preserving unrelated config.
38
448
  */
39
449
  function normalizeCompatibilityConfig({ cfg }) {
40
450
  const rawPluginConfig = asRecord(asRecord(cfg.plugins?.entries?.codex)?.config);
41
451
  const rawCodexPlugins = asRecord(rawPluginConfig?.codexPlugins);
452
+ const rawAppServer = asRecord(rawPluginConfig?.appServer);
42
453
  const shouldRemoveDynamicToolsProfile = rawPluginConfig !== null && hasRetiredDynamicToolsProfile(rawPluginConfig);
43
454
  const shouldRewriteDestructivePolicy = hasLegacyPluginDestructivePolicy(rawCodexPlugins);
44
- if (!rawPluginConfig || !shouldRemoveDynamicToolsProfile && !shouldRewriteDestructivePolicy) return {
455
+ const shouldRewriteApprovalPolicy = hasRetiredOnFailureApprovalPolicy(rawAppServer);
456
+ if (!rawPluginConfig || !shouldRemoveDynamicToolsProfile && !shouldRewriteDestructivePolicy && !shouldRewriteApprovalPolicy) return {
45
457
  config: cfg,
46
458
  changes: []
47
459
  };
@@ -66,6 +478,11 @@ function normalizeCompatibilityConfig({ cfg }) {
66
478
  }
67
479
  changes.push("Renamed plugins.entries.codex.config.codexPlugins allow_destructive_actions=\"on-request\" values to \"auto\".");
68
480
  }
481
+ if (shouldRewriteApprovalPolicy) {
482
+ const nextAppServer = asRecord(nextPluginConfig.appServer);
483
+ if (nextAppServer?.approvalPolicy === "on-failure") nextAppServer.approvalPolicy = "on-request";
484
+ changes.push("Renamed plugins.entries.codex.config.appServer.approvalPolicy=\"on-failure\" to \"on-request\".");
485
+ }
69
486
  return {
70
487
  config: nextConfig,
71
488
  changes
@@ -89,4 +506,4 @@ const sessionRouteStateOwners = [{
89
506
  ]
90
507
  }];
91
508
  //#endregion
92
- export { legacyConfigRules, normalizeCompatibilityConfig, sessionRouteStateOwners };
509
+ export { legacyConfigRules, normalizeCompatibilityConfig, sessionRouteStateOwners, stateMigrations };
package/dist/harness.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region extensions/codex/harness.ts
2
- const DEFAULT_CODEX_HARNESS_PROVIDER_IDS = new Set(["codex", "openai"]);
2
+ const DEFAULT_CODEX_HARNESS_PROVIDER_IDS = /* @__PURE__ */ new Set(["codex", "openai"]);
3
3
  const CODEX_APP_SERVER_CONTEXT_ENGINE_HOST_CAPABILITIES = [
4
4
  "bootstrap",
5
5
  "assemble-before-prompt",
@@ -32,38 +32,57 @@ function createCodexAppServerAgentHarness(options) {
32
32
  };
33
33
  },
34
34
  runAttempt: async (params) => {
35
- const { runCodexAppServerAttempt } = await import("./run-attempt-DikbXia_.js");
35
+ const { runCodexAppServerAttempt } = await import("./run-attempt-8SPLiDlT.js");
36
36
  return runCodexAppServerAttempt(params, {
37
+ bindingStore: options.bindingStore,
37
38
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
38
39
  nativeHookRelay: { enabled: true }
39
40
  });
40
41
  },
41
42
  runSideQuestion: async (params) => {
42
- const { runCodexAppServerSideQuestion } = await import("./side-question-Ca9wqmd0.js");
43
+ const { runCodexAppServerSideQuestion } = await import("./side-question-DkjXvYv7.js");
43
44
  return runCodexAppServerSideQuestion(params, {
45
+ bindingStore: options.bindingStore,
44
46
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
45
47
  nativeHookRelay: { enabled: true }
46
48
  });
47
49
  },
48
50
  compact: async (params) => {
49
- const { maybeCompactCodexAppServerSession } = await import("./compact-CILptrPS.js");
50
- return maybeCompactCodexAppServerSession(params, { pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig });
51
+ const { maybeCompactCodexAppServerSession } = await import("./compact-CZzbcygx.js");
52
+ return maybeCompactCodexAppServerSession(params, {
53
+ bindingStore: options.bindingStore,
54
+ pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig
55
+ });
51
56
  },
52
57
  compactAfterContextEngine: async (params) => {
53
- const { maybeCompactCodexAppServerSession } = await import("./compact-CILptrPS.js");
58
+ const { maybeCompactCodexAppServerSession } = await import("./compact-CZzbcygx.js");
54
59
  return maybeCompactCodexAppServerSession(params, {
60
+ bindingStore: options.bindingStore,
55
61
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
56
62
  allowNonManualNativeRequest: true
57
63
  });
58
64
  },
59
65
  reset: async (params) => {
60
- if (params.sessionFile) {
61
- const { clearCodexAppServerBinding } = await import("./session-binding-Cm0Gg7Z1.js").then((n) => n.s);
62
- await clearCodexAppServerBinding(params.sessionFile);
66
+ if (params.sessionId) {
67
+ const { reclaimCurrentCodexSessionGeneration, sessionBindingIdentity } = await import("./session-binding-Dc03iwRF.js").then((n) => n.s);
68
+ const identity = sessionBindingIdentity({
69
+ agentId: params.agentId,
70
+ sessionId: params.sessionId,
71
+ sessionKey: params.sessionKey
72
+ });
73
+ let retired = await options.bindingStore.retireSessionGeneration(identity);
74
+ if (retired === "conflict") {
75
+ if (await reclaimCurrentCodexSessionGeneration({
76
+ bindingStore: options.bindingStore,
77
+ identity,
78
+ config: options.resolveConfig?.()
79
+ })) retired = await options.bindingStore.retireSessionGeneration(identity);
80
+ }
81
+ if (retired === "conflict") throw new Error(`Codex binding generation changed before session ${params.sessionId} could reset`);
63
82
  }
64
83
  },
65
84
  dispose: async () => {
66
- const { clearSharedCodexAppServerClientAndWait } = await import("./shared-client-rR6TDJA3.js").then((n) => n.c);
85
+ const { clearSharedCodexAppServerClientAndWait } = await import("./shared-client-4ICy3U6d.js").then((n) => n.c);
67
86
  await clearSharedCodexAppServerClientAndWait();
68
87
  }
69
88
  };