@openclaw/codex 2026.7.2-beta.7 → 2026.8.1-beta.2

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 (55) hide show
  1. package/README.md +2 -0
  2. package/dist/{app-server-policy-BSaO2JIT.js → app-server-policy-zcBDc1JU.js} +1 -1
  3. package/dist/attempt-client-cleanup-DMLXUfa8.js +735 -0
  4. package/dist/{notification-correlation-CU6_AnOb.js → binding-connection-I5Bo-AsX.js} +3 -37
  5. package/dist/{bounded-turn-D2ZAgZVz.js → bounded-turn-qgZmzy_4.js} +50 -49
  6. package/dist/{capabilities-BFDTVYr4.js → capabilities-CybGI1oz.js} +8 -2
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-C336eRVS.js → command-formatters-B1AEz8ZA.js} +18 -18
  9. package/dist/{command-handlers-DAHUSry9.js → command-handlers-Db8pu_ds.js} +484 -95
  10. package/dist/{compact-D_uvHurS.js → compact-LspQaGfl.js} +213 -199
  11. package/dist/{conversation-binding-data-BHRpYbX3.js → conversation-binding-data-CW2GuupV.js} +6 -10
  12. package/dist/doctor-contract-api.js +40 -43
  13. package/dist/{dynamic-tools-D2gYkSBO.js → dynamic-tools-BVdyWkUD.js} +2597 -1221
  14. package/dist/{effective-mcp-catalog-Bbd98Inw.js → effective-mcp-catalog-DIIhAtOZ.js} +20 -15
  15. package/dist/{event-projector-assistant-message-DTgnPPVF.js → event-projector-assistant-message-BwxV4d6N.js} +11 -23
  16. package/dist/{attempt-notifications-AP-a-Q5k.js → event-projector-usage-e5huIQWu.js} +113 -29
  17. package/dist/harness.js +80 -14
  18. package/dist/image-payload-sanitizer-CnfoUPCE.js +65 -0
  19. package/dist/index.js +591 -240
  20. package/dist/isolated-completion-C58NbL40.js +75 -0
  21. package/dist/local-runtime-attribution-B_2mnqhb.js +19 -0
  22. package/dist/media-understanding-provider.js +5 -5
  23. package/dist/{models-BBMKU4jA.js → models-BFlpn1Ex.js} +12 -17
  24. package/dist/native-subagent-monitor-DyTGmTUx.js +3111 -0
  25. package/dist/{plugin-app-cache-key-DztPafOA.js → plugin-app-cache-key-C3H2CVp6.js} +5 -5
  26. package/dist/plugin-marketplace-discovery-CzrGJdCR.js +385 -0
  27. package/dist/{computer-use-CYEc8U3w.js → plugin-metadata-cache-CNJPj4_b.js} +105 -5
  28. package/dist/protocol-validators-B4F7L8Rf.js +2346 -0
  29. package/dist/{rate-limits-CU-gVCCS.js → rate-limits-DZXmOL8-.js} +17 -35
  30. package/dist/{request-qKh331yu.js → request-BRl5_UfX.js} +3 -3
  31. package/dist/{run-attempt-CY9WlDLc.js → run-attempt-P8BdxC1I.js} +4837 -9047
  32. package/dist/{runtime-artifact-CmtG_t1L.js → runtime-artifact-BVSPdd6g.js} +8 -23
  33. package/dist/{sandbox-guard-NuhpXmPB.js → sandbox-guard-Cmwc9eIk.js} +6 -13
  34. package/dist/{session-binding-BXpo9ymA.js → session-binding-DPxIvMgE.js} +246 -265
  35. package/dist/{session-catalog-DyOgR4WH.js → session-catalog-xwNi_SDM.js} +159 -109
  36. package/dist/{session-cli-2PZaFLRh.js → session-cli-7hgXZDV7.js} +1 -1
  37. package/dist/session-retirement-DoMMJFKm.js +36 -0
  38. package/dist/{session-upstream-marker-B6U7tLw5.js → session-upstream-marker-CrIFX06J.js} +1 -1
  39. package/dist/{settled-turn-finalizer-CXY2Z9dT.js → settled-turn-finalizer-BRWBO4MO.js} +21 -13
  40. package/dist/{shared-client-DTbvH-XV.js → shared-client-kIBbGjk4.js} +587 -223
  41. package/dist/{side-question-_ulBk1AL.js → side-question-9HAL26l9.js} +101 -52
  42. package/dist/{thread-lifecycle-DF53ogiA.js → thread-lifecycle-Bu1BTDXr.js} +694 -753
  43. package/dist/thread-ownership-6kOQHlyC.js +92 -0
  44. package/dist/thread-resume-CPrJNQVM.js +30 -0
  45. package/dist/transcript-mirror-B9gGgnJS.js +570 -0
  46. package/dist/{transport-stdio-DXgGZ7Ib.js → transport-stdio-DIImwDVS.js} +11 -0
  47. package/dist/upstream-prompt-provenance-ClRBije0.js +41 -0
  48. package/dist/{upstream-session-fork-Dy4Xvuoj.js → upstream-session-fork-CE-_LdnP.js} +5 -5
  49. package/dist/{usage-CQ6GhD5-.js → usage-CHlV0e-o.js} +3 -3
  50. package/dist/{web-search-provider.runtime-CCFhg2z5.js → web-search-provider.runtime-DRw2Vl42.js} +8 -9
  51. package/openclaw.plugin.json +18 -3
  52. package/package.json +5 -5
  53. package/dist/conversation-control-xsIeXbo4.js +0 -287
  54. package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
  55. package/dist/transcript-mirror-DzsdNCf5.js +0 -6924
@@ -1,6 +1,5 @@
1
- import { W as isJsonObject } from "./shared-client-DTbvH-XV.js";
2
- import { O as readCodexPluginConfig, g as resolveCodexAppServerRuntimeOptions, y as resolveCodexSupervisionAppServerRuntimeOptions } from "./session-binding-BXpo9ymA.js";
3
- import { t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-DztPafOA.js";
1
+ import { T as readCodexPluginConfig, g as resolveCodexAppServerRuntimeOptions, y as resolveCodexSupervisionAppServerRuntimeOptions } from "./session-binding-DPxIvMgE.js";
2
+ import { t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-C3H2CVp6.js";
4
3
  //#region extensions/codex/src/app-server/binding-connection.ts
5
4
  /** Requires the native model pair after a supervised pending branch has materialized. */
6
5
  function requireCodexSupervisionModelSelection(binding) {
@@ -31,37 +30,4 @@ function resolveCodexBindingAppServerConnection(params) {
31
30
  };
32
31
  }
33
32
  //#endregion
34
- //#region extensions/codex/src/app-server/notification-correlation.ts
35
- /**
36
- * Correlates Codex app-server notifications with the active thread/turn so
37
- * projectors can ignore global or stale events without losing diagnostics.
38
- */
39
- /** Returns true when a notification payload belongs to the exact active thread and turn. */
40
- function isCodexNotificationForTurn(value, threadId, turnId) {
41
- if (!isJsonObject(value)) return false;
42
- return readCodexNotificationThreadId(value) === threadId && readCodexNotificationTurnId(value) === turnId;
43
- }
44
- /**
45
- * Reads a thread id from canonical top-level or nested thread payloads.
46
- * The generated v2 schemas require top-level `threadId` on turn/item-scoped
47
- * notifications and define `Turn` without one, so `turn.threadId` is not a
48
- * wire shape and is deliberately not read here.
49
- */
50
- function readCodexNotificationThreadId(record) {
51
- const thread = isJsonObject(record.thread) ? record.thread : void 0;
52
- return readString(record, "threadId") ?? (thread ? readString(thread, "id") : void 0);
53
- }
54
- /** Reads a turn id from either top-level notification params or nested turn payloads. */
55
- function readCodexNotificationTurnId(record) {
56
- return readNestedTurnId(record) ?? readString(record, "turnId");
57
- }
58
- function readNestedTurnId(record) {
59
- const turn = record.turn;
60
- return isJsonObject(turn) ? readString(turn, "id") : void 0;
61
- }
62
- function readString(record, key) {
63
- const value = record[key];
64
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
65
- }
66
- //#endregion
67
- export { resolveCodexBindingAppServerConnection as a, requireCodexSupervisionModelSelection as i, readCodexNotificationThreadId as n, readCodexNotificationTurnId as r, isCodexNotificationForTurn as t };
33
+ export { resolveCodexBindingAppServerConnection as n, requireCodexSupervisionModelSelection as t };
@@ -1,23 +1,22 @@
1
- import { W as isJsonObject, s as isCodexAppServerStartSelectionChangedError } from "./shared-client-DTbvH-XV.js";
2
- import { g as resolveCodexAppServerRuntimeOptions } from "./session-binding-BXpo9ymA.js";
3
- import { G as mergeCodexThreadConfigs, d as attestCodexRingZeroThreadHasNoMcpServers, f as buildCodexRingZeroThreadConfigPatch, m as readCodexInheritedMcpServerNames, mt as interruptCodexTurnAndWaitBestEffort, p as buildCodexRuntimeThreadConfig, u as assertCodexRingZeroHasNoManagedHooks, ut as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS } from "./thread-lifecycle-DF53ogiA.js";
4
- import { _ as readCodexNotificationItem, h as isRetryableErrorNotification } from "./attempt-notifications-AP-a-Q5k.js";
5
- import { n as normalizeCodexResponseTokenUsage } from "./event-projector-usage-Xp4AlR2k.js";
6
- import { C as readCodexTurnCompletedNotification, _ as assertCodexThreadStartResponse, b as readCodexErrorNotification, v as assertCodexTurnStartResponse } from "./transcript-mirror-DzsdNCf5.js";
7
- import { r as readModelListResult } from "./models-BBMKU4jA.js";
1
+ import { g as resolveCodexAppServerRuntimeOptions } from "./session-binding-DPxIvMgE.js";
2
+ import { ct as isJsonObject, s as isCodexAppServerStartSelectionChangedError } from "./shared-client-kIBbGjk4.js";
3
+ import { _ as readCodexNotificationTurnId, a as closeCodexStartupClientBestEffort, o as interruptCodexTurnAndWaitBestEffort, t as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS } from "./attempt-client-cleanup-DMLXUfa8.js";
4
+ import { b as isTerminalTurnStatus, n as normalizeCodexResponseTokenUsage, x as readCodexNotificationItem, y as isRetryableErrorNotification } from "./event-projector-usage-e5huIQWu.js";
5
+ import { a as assertCodexThreadStartResponse, c as readCodexErrorNotification, o as assertCodexTurnStartResponse, u as readCodexTurnCompletedNotification } from "./protocol-validators-B4F7L8Rf.js";
6
+ import { r as readModelListResult } from "./models-BFlpn1Ex.js";
7
+ import { W as mergeCodexThreadConfigs, c as buildCodexRingZeroThreadConfigPatch, l as buildCodexRuntimeThreadConfig, o as assertCodexRestrictedToolSurfaceHasNoManagedHooks, s as attestCodexRestrictedToolSurfaceMcpServersDisabled, u as readCodexInheritedMcpServerNames } from "./thread-lifecycle-Bu1BTDXr.js";
8
+ import { readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
8
9
  import fs from "node:fs/promises";
9
10
  import path from "node:path";
11
+ import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
10
12
  import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
11
13
  import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
12
14
  //#region extensions/codex/src/app-server/bounded-turn.ts
13
- const CODEX_PRIVATE_STDIO_ARGS = [
14
- "app-server",
15
- "--listen",
16
- "stdio://"
17
- ];
18
15
  const CODEX_APP_SERVER_ARGS_ENV_KEY = "OPENCLAW_CODEX_APP_SERVER_ARGS";
19
16
  const CODEX_BOUNDED_THREAD_CONFIG = {
17
+ "agents.enabled": false,
20
18
  "features.multi_agent": false,
19
+ "features.multi_agent_v2": false,
21
20
  "features.apps": false,
22
21
  "features.plugins": false,
23
22
  "features.image_generation": false,
@@ -66,19 +65,26 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
66
65
  const timeoutMs = deadline - Date.now();
67
66
  if (timeoutMs <= 0) throw timeoutError;
68
67
  const agentDir = params.agentDir?.trim() || void 0;
69
- const startOptions = workspace.codexHome ? buildPrivateCodexAppServerStartOptions(appServer.start, workspace.codexHome) : appServer.start;
68
+ const isolatedStartOptions = workspace.codexHome ? buildPrivateCodexAppServerStartOptions(appServer.start, workspace.codexHome) : appServer.start;
69
+ const startOptions = workspace.codexHome && params.preparedAuth ? {
70
+ ...isolatedStartOptions,
71
+ homeScope: "agent"
72
+ } : isolatedStartOptions;
70
73
  const ownsClient = !params.options.clientFactory;
74
+ const authSelection = params.preparedAuth ? { preparedAuth: params.preparedAuth } : { authProfileId: params.profile };
71
75
  const client = params.options.clientFactory ? await params.options.clientFactory({
72
76
  startOptions,
73
- authProfileId: params.profile,
77
+ ...authSelection,
78
+ authRequirement: params.authRequirement,
74
79
  agentDir,
75
80
  config: params.config,
76
81
  timeoutMs,
77
82
  ...params.signal ? { abandonSignal: params.signal } : {}
78
- }) : await import("./shared-client-DTbvH-XV.js").then((n) => n.m).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
83
+ }) : await import("./shared-client-kIBbGjk4.js").then((n) => n.m).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
79
84
  startOptions,
80
85
  timeoutMs,
81
- authProfileId: params.profile,
86
+ ...authSelection,
87
+ authRequirement: params.authRequirement,
82
88
  agentDir,
83
89
  authProfileStore: params.authProfileStore,
84
90
  config: params.config,
@@ -117,17 +123,18 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
117
123
  signal: abortController.signal
118
124
  });
119
125
  const inheritedMcpServerNames = params.requireNoExternalCapabilities ? await readCodexInheritedMcpServerNames(client, workspace.cwd, abortController.signal) : [];
120
- if (params.requireNoExternalCapabilities) await assertCodexRingZeroHasNoManagedHooks(client, abortController.signal);
126
+ if (params.requireNoExternalCapabilities) await assertCodexRestrictedToolSurfaceHasNoManagedHooks(client, abortController.signal);
127
+ const threadConfig = buildCodexRuntimeThreadConfig(resolveBoundedThreadConfig(params, workspace, inheritedMcpServerNames), { nativeCodeModeEnabled: false });
121
128
  const thread = assertCodexThreadStartResponse(await client.request("thread/start", {
122
129
  model,
123
- modelProvider: "openai",
130
+ ...params.modelProvider ? { modelProvider: params.modelProvider } : {},
124
131
  cwd: workspace.cwd,
125
132
  approvalPolicy: "on-request",
126
133
  sandbox: "read-only",
127
134
  serviceName: "OpenClaw",
128
135
  ...params.requireNoExternalCapabilities ? { baseInstructions: "" } : {},
129
136
  developerInstructions: params.developerInstructions,
130
- config: buildCodexRuntimeThreadConfig(resolveBoundedThreadConfig(params, workspace, inheritedMcpServerNames), { nativeCodeModeEnabled: false }),
137
+ config: threadConfig,
131
138
  environments: [],
132
139
  dynamicTools: [],
133
140
  experimentalRawEvents: true,
@@ -138,7 +145,7 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
138
145
  }));
139
146
  activeThreadId = thread.thread.id;
140
147
  if (abortController.signal.aborted) requestInterrupt();
141
- if (params.requireNoExternalCapabilities) await attestCodexRingZeroThreadHasNoMcpServers(client, thread.thread.id, abortController.signal);
148
+ if (params.requireNoExternalCapabilities) await attestCodexRestrictedToolSurfaceMcpServersDisabled(client, thread.thread.id, threadConfig, abortController.signal);
142
149
  if (params.historyItems?.length) await client.request("thread/inject_items", {
143
150
  threadId: thread.thread.id,
144
151
  items: params.historyItems
@@ -146,14 +153,13 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
146
153
  timeoutMs,
147
154
  signal: abortController.signal
148
155
  });
149
- const collector = createCodexBoundedTurnCollector(thread.thread.id, params.taskLabel);
156
+ const collector = createCodexBoundedTurnCollector(thread.thread.id, params.taskLabel, params.allowEmptyText === true);
150
157
  const cleanup = client.addNotificationHandler(collector.handleNotification);
151
158
  const requestCleanup = client.addRequestHandler(createCodexBoundedApprovalHandler(params.taskLabel));
152
159
  try {
153
160
  const turn = assertCodexTurnStartResponse(await client.request("turn/start", {
154
161
  threadId: thread.thread.id,
155
162
  input: params.input,
156
- cwd: workspace.cwd,
157
163
  approvalPolicy: "on-request",
158
164
  model,
159
165
  effort: "low"
@@ -171,6 +177,7 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
171
177
  model
172
178
  };
173
179
  } finally {
180
+ await interruptPromise;
174
181
  requestCleanup();
175
182
  cleanup();
176
183
  }
@@ -182,7 +189,7 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
182
189
  clearTimeout(timeout);
183
190
  params.signal?.removeEventListener("abort", abortFromCaller);
184
191
  await interruptPromise;
185
- if (ownsClient) client.close();
192
+ if (ownsClient) await closeCodexStartupClientBestEffort(client);
186
193
  }
187
194
  if (retrySelection) return await runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace, selectionAttempt + 1, {
188
195
  deadline,
@@ -197,6 +204,10 @@ function resolveBoundedThreadConfig(params, workspace, inheritedMcpServerNames)
197
204
  return mergeCodexThreadConfigs(privateConfig, CODEX_SETTLED_FINALIZER_THREAD_CONFIG, buildCodexRingZeroThreadConfigPatch({ toolsAllow: ["openclaw"] }, true, inheritedMcpServerNames)) ?? privateConfig;
198
205
  }
199
206
  function buildPrivateCodexAppServerStartOptions(start, codexHome) {
207
+ const providerArgs = start.args.flatMap((arg, index) => {
208
+ const override = arg === "-c" || arg === "--config" ? start.args[index + 1] : arg.startsWith("--config=") ? arg.slice(9) : void 0;
209
+ return override && /^\s*(?:openai_base_url|model_catalog_json)\s*=/u.test(override) ? ["-c", override] : [];
210
+ });
200
211
  const privateEnv = Object.fromEntries(Object.entries(start.env ?? {}).filter(([name]) => name.trim().toUpperCase() !== CODEX_APP_SERVER_ARGS_ENV_KEY));
201
212
  const clearEnv = (start.clearEnv ?? []).filter((name) => {
202
213
  const normalized = name.trim().toUpperCase();
@@ -204,7 +215,12 @@ function buildPrivateCodexAppServerStartOptions(start, codexHome) {
204
215
  });
205
216
  return {
206
217
  ...start,
207
- args: [...CODEX_PRIVATE_STDIO_ARGS],
218
+ args: [
219
+ "app-server",
220
+ ...providerArgs,
221
+ "--listen",
222
+ "stdio://"
223
+ ],
208
224
  env: {
209
225
  ...privateEnv,
210
226
  CODEX_HOME: codexHome
@@ -251,7 +267,7 @@ async function resolveCodexBoundedTurnModel(params) {
251
267
  if (params.requiredModalities.includes("text") && !match.inputModalities.includes("text")) throw new Error(`Codex app-server model does not support text: ${model}`);
252
268
  return model;
253
269
  }
254
- function createCodexBoundedTurnCollector(threadId, taskLabel) {
270
+ function createCodexBoundedTurnCollector(threadId, taskLabel, allowEmptyText) {
255
271
  let turnId;
256
272
  let completedTurn;
257
273
  let promptError;
@@ -260,10 +276,7 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
260
276
  const completedItems = /* @__PURE__ */ new Map();
261
277
  const assistantTextByItem = /* @__PURE__ */ new Map();
262
278
  const assistantItemOrder = [];
263
- let resolveCompletion;
264
- const completion = new Promise((resolve) => {
265
- resolveCompletion = resolve;
266
- });
279
+ const { promise: completion, resolve: resolveCompletion } = createDeferred();
267
280
  const rememberAssistantText = (itemId, text) => {
268
281
  if (!text) return;
269
282
  if (!assistantTextByItem.has(itemId)) assistantItemOrder.push(itemId);
@@ -271,12 +284,12 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
271
284
  };
272
285
  const handleNotification = (notification) => {
273
286
  const params = isJsonObject(notification.params) ? notification.params : void 0;
274
- if (!params || readString(params, "threadId") !== threadId) return;
287
+ if (!params || readStringField(params, "threadId") !== threadId) return;
275
288
  if (!turnId) {
276
289
  pending.push(notification);
277
290
  return;
278
291
  }
279
- if (readNotificationTurnId(params) !== turnId) return;
292
+ if (readCodexNotificationTurnId(params) !== turnId) return;
280
293
  if (notification.method === "item/completed") {
281
294
  const item = readCodexNotificationItem(notification.params);
282
295
  if (item) {
@@ -286,8 +299,8 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
286
299
  return;
287
300
  }
288
301
  if (notification.method === "item/agentMessage/delta") {
289
- const itemId = readString(params, "itemId") ?? readString(params, "id") ?? "assistant";
290
- const delta = readString(params, "delta") ?? "";
302
+ const itemId = readStringField(params, "itemId") ?? readStringField(params, "id") ?? "assistant";
303
+ const delta = readStringField(params, "delta") ?? "";
291
304
  rememberAssistantText(itemId, `${assistantTextByItem.get(itemId) ?? ""}${delta}`);
292
305
  return;
293
306
  }
@@ -298,20 +311,20 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
298
311
  }
299
312
  if (notification.method === "turn/completed") {
300
313
  completedTurn = readCodexTurnCompletedNotification(notification.params)?.turn ?? completedTurn;
301
- resolveCompletion?.();
314
+ resolveCompletion();
302
315
  return;
303
316
  }
304
317
  if (notification.method === "error") {
305
318
  if (isRetryableErrorNotification(notification.params)) return;
306
319
  promptError = readCodexErrorNotification(notification.params)?.error.message ?? `codex app-server ${taskLabel} turn failed`;
307
- resolveCompletion?.();
320
+ resolveCompletion();
308
321
  }
309
322
  };
310
323
  return {
311
324
  handleNotification,
312
325
  async collect(startedTurn, options) {
313
326
  turnId = startedTurn.id;
314
- if (isTerminalTurn(startedTurn)) completedTurn = startedTurn;
327
+ if (isTerminalTurnStatus(startedTurn.status)) completedTurn = startedTurn;
315
328
  for (const notification of pending.splice(0)) handleNotification(notification);
316
329
  if (!completedTurn && !promptError) await waitForTurnCompletion({
317
330
  completion,
@@ -326,7 +339,7 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
326
339
  const itemText = collectAssistantTextFromItems(items);
327
340
  const deltaText = assistantItemOrder.map((itemId) => assistantTextByItem.get(itemId)?.trim()).filter((text) => Boolean(text)).join("\n\n").trim();
328
341
  const text = (itemText || deltaText).trim();
329
- if (!text) throw new Error(`Codex app-server ${taskLabel} turn returned no text.`);
342
+ if (!text && !allowEmptyText) throw new Error(`Codex app-server ${taskLabel} turn returned no text.`);
330
343
  return {
331
344
  text,
332
345
  items,
@@ -359,17 +372,5 @@ function resolveCodexBoundedTurnAbortError(signal, taskLabel, timeoutError) {
359
372
  function collectAssistantTextFromItems(items) {
360
373
  return (items ?? []).filter((item) => item.type === "agentMessage").map((item) => item.text.trim()).filter(Boolean).join("\n\n").trim();
361
374
  }
362
- function readNotificationTurnId(record) {
363
- const direct = readString(record, "turnId");
364
- if (direct) return direct;
365
- return isJsonObject(record.turn) ? readString(record.turn, "id") : void 0;
366
- }
367
- function readString(record, key) {
368
- const value = record[key];
369
- return typeof value === "string" ? value : void 0;
370
- }
371
- function isTerminalTurn(turn) {
372
- return turn.status === "completed" || turn.status === "interrupted" || turn.status === "failed";
373
- }
374
375
  //#endregion
375
376
  export { runBoundedCodexAppServerTurn as t };
@@ -1,4 +1,4 @@
1
- import { v as CodexAppServerRpcError } from "./shared-client-DTbvH-XV.js";
1
+ import { z as CodexAppServerRpcError } from "./shared-client-kIBbGjk4.js";
2
2
  //#region extensions/codex/src/app-server/capabilities.ts
3
3
  /**
4
4
  * Capability helpers for optional Codex app-server control-plane methods.
@@ -6,10 +6,14 @@ import { v as CodexAppServerRpcError } from "./shared-client-DTbvH-XV.js";
6
6
  /** Known app-server methods used by OpenClaw control surfaces. */
7
7
  const CODEX_CONTROL_METHODS = {
8
8
  account: "account/read",
9
- compact: "thread/compact/start",
9
+ installedApps: "app/installed",
10
+ listApps: "app/list",
11
+ readApps: "app/read",
10
12
  feedback: "feedback/upload",
11
13
  forkThread: "thread/fork",
14
+ listHooks: "hooks/list",
12
15
  listMcpServers: "mcpServerStatus/list",
16
+ listPlugins: "plugin/list",
13
17
  listSkills: "skills/list",
14
18
  listThreads: "thread/list",
15
19
  listThreadTurns: "thread/turns/list",
@@ -19,6 +23,8 @@ const CODEX_CONTROL_METHODS = {
19
23
  renameThread: "thread/name/set",
20
24
  resumeThread: "thread/resume",
21
25
  review: "review/start",
26
+ installPlugin: "plugin/install",
27
+ reloadMcpServers: "config/mcpServer/reload",
22
28
  unarchiveThread: "thread/unarchive",
23
29
  getThreadGoal: "thread/goal/get",
24
30
  setThreadGoal: "thread/goal/set",
@@ -2,7 +2,7 @@ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
2
2
  //#region extensions/codex/cli-metadata.ts
3
3
  function registerCodexCliMetadata(api) {
4
4
  api.registerCli(async ({ program }) => {
5
- const { registerCodexSessionCli } = await import("./session-cli-2PZaFLRh.js");
5
+ const { registerCodexSessionCli } = await import("./session-cli-7hgXZDV7.js");
6
6
  registerCodexSessionCli(program);
7
7
  }, { descriptors: [{
8
8
  name: "codex",
@@ -1,6 +1,11 @@
1
- import { W as isJsonObject } from "./shared-client-DTbvH-XV.js";
2
- import { c as summarizeCodexRateLimits, o as summarizeCodexAccountRateLimits, r as hasCodexRateLimitSnapshots } from "./rate-limits-CU-gVCCS.js";
1
+ import { ct as isJsonObject } from "./shared-client-kIBbGjk4.js";
2
+ import { c as summarizeCodexRateLimits, o as summarizeCodexAccountRateLimits, r as hasCodexRateLimitSnapshots } from "./rate-limits-DZXmOL8-.js";
3
+ import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
4
  //#region extensions/codex/src/command-formatters.ts
5
+ /**
6
+ * Formats Codex command responses for safe chat display, including status,
7
+ * lists, account summaries, and user-facing help text.
8
+ */
4
9
  /** Formats the combined `/codex status` probe result. */
5
10
  function formatCodexStatus(probes) {
6
11
  const lines = [`Codex app-server: ${probes.models.ok || probes.account.ok || probes.limits.ok || probes.mcps.ok || probes.skills.ok ? "connected" : "unavailable"}`];
@@ -25,12 +30,12 @@ function formatThreads(response) {
25
30
  if (threads.length === 0) return "No Codex threads returned.";
26
31
  return ["Codex threads:", ...threads.slice(0, 10).map((thread) => {
27
32
  const record = isJsonObject(thread) ? thread : {};
28
- const id = readString(record, "threadId") ?? readString(record, "id") ?? "<unknown>";
29
- const title = readString(record, "title") ?? readString(record, "name") ?? readString(record, "summary");
33
+ const id = normalizeOptionalString(record.threadId) ?? normalizeOptionalString(record.id) ?? "<unknown>";
34
+ const title = normalizeOptionalString(record.title) ?? normalizeOptionalString(record.name) ?? normalizeOptionalString(record.summary);
30
35
  const details = [
31
- readString(record, "model"),
32
- readString(record, "cwd"),
33
- readString(record, "updatedAt") ?? readString(record, "lastUpdatedAt")
36
+ normalizeOptionalString(record.model),
37
+ normalizeOptionalString(record.cwd),
38
+ normalizeOptionalString(record.updatedAt) ?? normalizeOptionalString(record.lastUpdatedAt)
34
39
  ].filter((value) => Boolean(value));
35
40
  return `- ${formatCodexDisplayText(id)}${title ? ` - ${formatCodexDisplayText(title)}` : ""}${details.length > 0 ? ` (${details.map(formatCodexDisplayText).join(", ")})` : ""}\n Resume: ${formatCodexResumeHint(id)}`;
36
41
  })].join("\n");
@@ -85,7 +90,7 @@ function formatList(response, label) {
85
90
  if (entries.length === 0) return `${label}: none returned.`;
86
91
  return [`${label}:`, ...entries.slice(0, 25).map((entry) => {
87
92
  const record = isJsonObject(entry) ? entry : {};
88
- return `- ${formatCodexDisplayText(readString(record, "name") ?? readString(record, "id") ?? JSON.stringify(entry))}`;
93
+ return `- ${formatCodexDisplayText(normalizeOptionalString(record.name) ?? normalizeOptionalString(record.id) ?? JSON.stringify(entry))}`;
89
94
  })].join("\n");
90
95
  }
91
96
  /** Formats Codex skills grouped by scope, omitting disabled entries. */
@@ -113,7 +118,7 @@ function formatSkills(response) {
113
118
  return lines.join("\n");
114
119
  }
115
120
  function formatCodexSkillEntry(entry) {
116
- return `\`${formatCodexDisplayText(readString(isJsonObject(entry) ? entry : {}, "name") ?? "<unknown>")}\``;
121
+ return `\`${formatCodexDisplayText(normalizeOptionalString((isJsonObject(entry) ? entry : {}).name) ?? "<unknown>")}\``;
117
122
  }
118
123
  const CODEX_RESUME_SAFE_THREAD_ID_PATTERN = /^[A-Za-z0-9._:-]+$/;
119
124
  function formatCodexResumeHint(threadId) {
@@ -200,8 +205,8 @@ function buildHelp() {
200
205
  function summarizeAccount(value) {
201
206
  if (!isJsonObject(value)) return "unavailable";
202
207
  const account = isJsonObject(value.account) ? value.account : value;
203
- if (readString(account, "type") === "amazonBedrock") return "Amazon Bedrock";
204
- return readString(account, "email") ?? readString(account, "accountEmail") ?? readString(account, "planType") ?? readString(account, "id") ?? "available";
208
+ if (normalizeOptionalString(account.type) === "amazonBedrock") return "Amazon Bedrock";
209
+ return normalizeOptionalString(account.email) ?? normalizeOptionalString(account.accountEmail) ?? normalizeOptionalString(account.planType) ?? normalizeOptionalString(account.id) ?? "available";
205
210
  }
206
211
  function summarizeArrayLike(value) {
207
212
  const entries = extractArray(value);
@@ -249,7 +254,7 @@ function summarizeRateLimits(value) {
249
254
  }
250
255
  function isMeaningfulRateLimitSnapshot(value) {
251
256
  if (!isJsonObject(value)) return false;
252
- if (readString(value, "rateLimitReachedType") ?? readString(value, "rate_limit_reached_type")) return true;
257
+ if (normalizeOptionalString(value.rateLimitReachedType) ?? normalizeOptionalString(value.rate_limit_reached_type)) return true;
253
258
  return ["primary", "secondary"].some((key) => {
254
259
  const window = value[key];
255
260
  return isJsonObject(window) && Object.values(window).some((entry) => entry != null);
@@ -272,10 +277,5 @@ function extractArray(value) {
272
277
  }
273
278
  return [];
274
279
  }
275
- /** Reads and trims a non-empty string field from a JSON object. */
276
- function readString(record, key) {
277
- const value = record[key];
278
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
279
- }
280
280
  //#endregion
281
- export { formatComputerUseStatus as a, formatSkills as c, formatCodexStatus as i, formatThreads as l, formatAccount as n, formatList as o, formatCodexDisplayText as r, formatModels as s, buildHelp as t, readString as u };
281
+ export { formatComputerUseStatus as a, formatSkills as c, formatCodexStatus as i, formatThreads as l, formatAccount as n, formatList as o, formatCodexDisplayText as r, formatModels as s, buildHelp as t };