@openclaw/codex 2026.7.2-beta.5 → 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 (59) hide show
  1. package/README.md +2 -0
  2. package/dist/{app-server-policy-BmDgseo_.js → app-server-policy-zcBDc1JU.js} +1 -1
  3. package/dist/attempt-client-cleanup-DMLXUfa8.js +735 -0
  4. package/dist/binding-connection-I5Bo-AsX.js +33 -0
  5. package/dist/{bounded-turn-FEbUXoYT.js → bounded-turn-qgZmzy_4.js} +71 -63
  6. package/dist/{capabilities-BHRSI6Cn.js → capabilities-CybGI1oz.js} +8 -2
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-ico4ZFnk.js → command-formatters-B1AEz8ZA.js} +18 -18
  9. package/dist/{command-handlers-CRmnwI2N.js → command-handlers-Db8pu_ds.js} +484 -95
  10. package/dist/{compact-dEN49UH6.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-LIt9ojep.js → dynamic-tools-BVdyWkUD.js} +2984 -1221
  14. package/dist/effective-mcp-catalog-DIIhAtOZ.js +119 -0
  15. package/dist/{event-projector-assistant-message-DTgnPPVF.js → event-projector-assistant-message-BwxV4d6N.js} +11 -23
  16. package/dist/{attempt-notifications-CMR2_fmR.js → event-projector-usage-e5huIQWu.js} +113 -29
  17. package/dist/harness.js +83 -13
  18. package/dist/image-payload-sanitizer-CnfoUPCE.js +65 -0
  19. package/dist/index.js +703 -329
  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-BA01NEez.js → models-BFlpn1Ex.js} +12 -17
  24. package/dist/native-subagent-monitor-DyTGmTUx.js +3111 -0
  25. package/dist/{plugin-app-cache-key-DSXX-rXO.js → plugin-app-cache-key-C3H2CVp6.js} +135 -42
  26. package/dist/plugin-marketplace-discovery-CzrGJdCR.js +385 -0
  27. package/dist/{computer-use-BjGylO-E.js → plugin-metadata-cache-CNJPj4_b.js} +211 -113
  28. package/dist/protocol-validators-B4F7L8Rf.js +2346 -0
  29. package/dist/{rate-limits-S_PXs0ul.js → rate-limits-DZXmOL8-.js} +17 -35
  30. package/dist/{request-CXpPennK.js → request-BRl5_UfX.js} +4 -4
  31. package/dist/{run-attempt-C5GTPJOE.js → run-attempt-P8BdxC1I.js} +1996 -5728
  32. package/dist/{runtime-artifact-C2ITXdhM.js → runtime-artifact-BVSPdd6g.js} +91 -40
  33. package/dist/{sandbox-guard-D1Wky__S.js → sandbox-guard-Cmwc9eIk.js} +10 -13
  34. package/dist/{session-binding-DlVQ-Pxs.js → session-binding-DPxIvMgE.js} +305 -271
  35. package/dist/{session-catalog-CP2oCcEb.js → session-catalog-xwNi_SDM.js} +418 -144
  36. package/dist/{session-cli-CqZ0Fp2a.js → session-cli-7hgXZDV7.js} +1 -1
  37. package/dist/session-retirement-DoMMJFKm.js +36 -0
  38. package/dist/{session-upstream-marker-QE-m5QFG.js → session-upstream-marker-CrIFX06J.js} +1 -1
  39. package/dist/{settled-turn-finalizer-CA_2QXIE.js → settled-turn-finalizer-BRWBO4MO.js} +36 -15
  40. package/dist/{shared-client-BVKE40c-.js → shared-client-kIBbGjk4.js} +721 -240
  41. package/dist/{side-question-CO12sHxo.js → side-question-9HAL26l9.js} +102 -53
  42. package/dist/{thread-lifecycle-DRg_FdzC.js → thread-lifecycle-Bu1BTDXr.js} +1355 -660
  43. package/dist/thread-ownership-6kOQHlyC.js +92 -0
  44. package/dist/thread-resume-CPrJNQVM.js +30 -0
  45. package/dist/{transcript-mirror-uKA-A4tB.js → transcript-mirror-B9gGgnJS.js} +202 -182
  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-_Vrz4WJr.js → upstream-session-fork-CE-_LdnP.js} +5 -5
  49. package/dist/{usage-UpVbdX5G.js → usage-CHlV0e-o.js} +3 -3
  50. package/dist/{web-search-provider.runtime-CaQMYDbp.js → web-search-provider.runtime-DRw2Vl42.js} +8 -9
  51. package/openclaw.plugin.json +18 -3
  52. package/package.json +6 -7
  53. package/dist/attempt-client-cleanup-Ia52yRWc.js +0 -127
  54. package/dist/conversation-control-DE7d9DOj.js +0 -287
  55. package/dist/event-projector-usage-tvgb1NCX.js +0 -69
  56. package/dist/notification-correlation-Bj_Ak_jI.js +0 -67
  57. package/dist/protocol-validators-Dm4eXZmt.js +0 -6337
  58. package/dist/realtime-voice-api-BPcA1uN9.js +0 -494
  59. package/dist/realtime-voice-api.js +0 -2
@@ -0,0 +1,33 @@
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";
3
+ //#region extensions/codex/src/app-server/binding-connection.ts
4
+ /** Requires the native model pair after a supervised pending branch has materialized. */
5
+ function requireCodexSupervisionModelSelection(binding) {
6
+ const model = binding.model?.trim();
7
+ const modelProvider = binding.modelProvider?.trim();
8
+ if (binding.connectionScope !== "supervision" || !model || !modelProvider) throw new Error("Codex supervised binding is missing its native model and provider; refusing request selection");
9
+ return {
10
+ model,
11
+ modelProvider
12
+ };
13
+ }
14
+ /** Resolves connection and auth ownership exclusively from the private thread binding. */
15
+ function resolveCodexBindingAppServerConnection(params) {
16
+ const { binding, authProfileId, ...runtimeParams } = params;
17
+ const usesSupervisionConnection = binding?.connectionScope === "supervision";
18
+ if (usesSupervisionConnection && readCodexPluginConfig(runtimeParams.pluginConfig).supervision?.enabled !== true) throw new Error("Codex supervision is disabled; refusing to open a native user-home supervised session");
19
+ const appServer = (usesSupervisionConnection ? resolveCodexSupervisionAppServerRuntimeOptions : resolveCodexAppServerRuntimeOptions)(runtimeParams);
20
+ if (usesSupervisionConnection) {
21
+ const persistedFingerprint = binding.pendingSupervisionBranch?.connectionFingerprint ?? binding.appServerRuntimeFingerprint;
22
+ const currentFingerprint = buildCodexAppServerConnectionFingerprint(appServer, runtimeParams.agentDir);
23
+ if (!persistedFingerprint || persistedFingerprint !== currentFingerprint) throw new Error("Codex supervision connection changed; refusing to operate on its bound native thread");
24
+ }
25
+ return {
26
+ appServer,
27
+ usesSupervisionConnection,
28
+ requestAuthProfileId: usesSupervisionConnection ? void 0 : authProfileId,
29
+ clientAuthProfileId: usesSupervisionConnection ? null : authProfileId
30
+ };
31
+ }
32
+ //#endregion
33
+ export { resolveCodexBindingAppServerConnection as n, requireCodexSupervisionModelSelection as t };
@@ -1,24 +1,22 @@
1
- import { V as isJsonObject, s as isCodexAppServerStartSelectionChangedError } from "./shared-client-BVKE40c-.js";
2
- import { p as resolveCodexAppServerRuntimeOptions } from "./session-binding-DlVQ-Pxs.js";
3
- import { o as interruptCodexTurnAndWaitBestEffort, t as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS } from "./attempt-client-cleanup-Ia52yRWc.js";
4
- import { _ as readCodexNotificationItem, h as isRetryableErrorNotification } from "./attempt-notifications-CMR2_fmR.js";
5
- import { G as mergeCodexThreadConfigs, d as buildCodexRingZeroThreadConfigPatch, f as buildCodexRuntimeThreadConfig, l as assertCodexRingZeroHasNoManagedHooks, p as readCodexInheritedMcpServerNames, u as attestCodexRingZeroThreadHasNoMcpServers } from "./thread-lifecycle-DRg_FdzC.js";
6
- import { t as normalizeCodexResponseTokenUsage } from "./event-projector-usage-tvgb1NCX.js";
7
- import { a as assertCodexTurnStartResponse, i as assertCodexThreadStartResponse, s as readCodexErrorNotification, u as readCodexTurnCompletedNotification } from "./protocol-validators-Dm4eXZmt.js";
8
- import { r as readModelListResult } from "./models-BA01NEez.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";
9
9
  import fs from "node:fs/promises";
10
10
  import path from "node:path";
11
+ import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
11
12
  import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
12
13
  import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
13
14
  //#region extensions/codex/src/app-server/bounded-turn.ts
14
- const CODEX_PRIVATE_STDIO_ARGS = [
15
- "app-server",
16
- "--listen",
17
- "stdio://"
18
- ];
19
15
  const CODEX_APP_SERVER_ARGS_ENV_KEY = "OPENCLAW_CODEX_APP_SERVER_ARGS";
20
16
  const CODEX_BOUNDED_THREAD_CONFIG = {
17
+ "agents.enabled": false,
21
18
  "features.multi_agent": false,
19
+ "features.multi_agent_v2": false,
22
20
  "features.apps": false,
23
21
  "features.plugins": false,
24
22
  "features.image_generation": false,
@@ -33,6 +31,13 @@ const CODEX_SETTLED_FINALIZER_THREAD_CONFIG = {
33
31
  "skills.include_instructions": false,
34
32
  include_environment_context: false
35
33
  };
34
+ var CodexBoundedTurnTimeoutError = class extends Error {
35
+ constructor(taskLabel, timeoutMs) {
36
+ const bound = timeoutMs % 1e3 === 0 ? `${timeoutMs / 1e3}s` : `${timeoutMs}ms`;
37
+ super(`codex app-server ${taskLabel} turn timed out after ${bound}`);
38
+ this.name = "TimeoutError";
39
+ }
40
+ };
36
41
  async function runBoundedCodexAppServerTurn(params) {
37
42
  const appServer = resolveCodexAppServerRuntimeOptions({
38
43
  pluginConfig: params.options.pluginConfig,
@@ -55,23 +60,31 @@ async function runBoundedCodexAppServerTurn(params) {
55
60
  }
56
61
  async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace, selectionAttempt = 0, timing) {
57
62
  const totalTimeoutMs = timing?.timeoutMs ?? resolveTimerTimeoutMs(params.timeoutMs, 100, 100);
63
+ const timeoutError = new CodexBoundedTurnTimeoutError(params.taskLabel, totalTimeoutMs);
58
64
  const deadline = timing?.deadline ?? Date.now() + totalTimeoutMs;
59
65
  const timeoutMs = deadline - Date.now();
60
- if (timeoutMs <= 0) throw new Error(`${params.taskLabel} timed out`);
66
+ if (timeoutMs <= 0) throw timeoutError;
61
67
  const agentDir = params.agentDir?.trim() || void 0;
62
- 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;
63
73
  const ownsClient = !params.options.clientFactory;
74
+ const authSelection = params.preparedAuth ? { preparedAuth: params.preparedAuth } : { authProfileId: params.profile };
64
75
  const client = params.options.clientFactory ? await params.options.clientFactory({
65
76
  startOptions,
66
- authProfileId: params.profile,
77
+ ...authSelection,
78
+ authRequirement: params.authRequirement,
67
79
  agentDir,
68
80
  config: params.config,
69
81
  timeoutMs,
70
82
  ...params.signal ? { abandonSignal: params.signal } : {}
71
- }) : await import("./shared-client-BVKE40c-.js").then((n) => n.p).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
83
+ }) : await import("./shared-client-kIBbGjk4.js").then((n) => n.m).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
72
84
  startOptions,
73
85
  timeoutMs,
74
- authProfileId: params.profile,
86
+ ...authSelection,
87
+ authRequirement: params.authRequirement,
75
88
  agentDir,
76
89
  authProfileStore: params.authProfileStore,
77
90
  config: params.config,
@@ -97,8 +110,8 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
97
110
  if (params.signal?.aborted) abortFromCaller();
98
111
  else params.signal?.addEventListener("abort", abortFromCaller, { once: true });
99
112
  const remainingRunMs = deadline - Date.now();
100
- if (remainingRunMs <= 0) abortRun("timeout");
101
- const timeout = setTimeout(() => abortRun("timeout"), Math.max(1, remainingRunMs));
113
+ if (remainingRunMs <= 0) abortRun(timeoutError);
114
+ const timeout = setTimeout(() => abortRun(timeoutError), Math.max(1, remainingRunMs));
102
115
  timeout.unref?.();
103
116
  let retrySelection = false;
104
117
  try {
@@ -110,17 +123,18 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
110
123
  signal: abortController.signal
111
124
  });
112
125
  const inheritedMcpServerNames = params.requireNoExternalCapabilities ? await readCodexInheritedMcpServerNames(client, workspace.cwd, abortController.signal) : [];
113
- 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 });
114
128
  const thread = assertCodexThreadStartResponse(await client.request("thread/start", {
115
129
  model,
116
- modelProvider: "openai",
130
+ ...params.modelProvider ? { modelProvider: params.modelProvider } : {},
117
131
  cwd: workspace.cwd,
118
132
  approvalPolicy: "on-request",
119
133
  sandbox: "read-only",
120
134
  serviceName: "OpenClaw",
121
135
  ...params.requireNoExternalCapabilities ? { baseInstructions: "" } : {},
122
136
  developerInstructions: params.developerInstructions,
123
- config: buildCodexRuntimeThreadConfig(resolveBoundedThreadConfig(params, workspace, inheritedMcpServerNames), { nativeCodeModeEnabled: false }),
137
+ config: threadConfig,
124
138
  environments: [],
125
139
  dynamicTools: [],
126
140
  experimentalRawEvents: true,
@@ -131,7 +145,7 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
131
145
  }));
132
146
  activeThreadId = thread.thread.id;
133
147
  if (abortController.signal.aborted) requestInterrupt();
134
- if (params.requireNoExternalCapabilities) await attestCodexRingZeroThreadHasNoMcpServers(client, thread.thread.id, abortController.signal);
148
+ if (params.requireNoExternalCapabilities) await attestCodexRestrictedToolSurfaceMcpServersDisabled(client, thread.thread.id, threadConfig, abortController.signal);
135
149
  if (params.historyItems?.length) await client.request("thread/inject_items", {
136
150
  threadId: thread.thread.id,
137
151
  items: params.historyItems
@@ -139,14 +153,13 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
139
153
  timeoutMs,
140
154
  signal: abortController.signal
141
155
  });
142
- const collector = createCodexBoundedTurnCollector(thread.thread.id, params.taskLabel);
156
+ const collector = createCodexBoundedTurnCollector(thread.thread.id, params.taskLabel, params.allowEmptyText === true);
143
157
  const cleanup = client.addNotificationHandler(collector.handleNotification);
144
158
  const requestCleanup = client.addRequestHandler(createCodexBoundedApprovalHandler(params.taskLabel));
145
159
  try {
146
160
  const turn = assertCodexTurnStartResponse(await client.request("turn/start", {
147
161
  threadId: thread.thread.id,
148
162
  input: params.input,
149
- cwd: workspace.cwd,
150
163
  approvalPolicy: "on-request",
151
164
  model,
152
165
  effort: "low"
@@ -158,23 +171,25 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
158
171
  if (abortController.signal.aborted) requestInterrupt();
159
172
  return {
160
173
  ...await collector.collect(turn.turn, {
161
- timeoutMs,
162
- signal: abortController.signal
174
+ signal: abortController.signal,
175
+ timeoutError
163
176
  }),
164
177
  model
165
178
  };
166
179
  } finally {
180
+ await interruptPromise;
167
181
  requestCleanup();
168
182
  cleanup();
169
183
  }
170
184
  } catch (error) {
185
+ if (abortController.signal.aborted) throw resolveCodexBoundedTurnAbortError(abortController.signal, params.taskLabel, timeoutError);
171
186
  if (ownsClient && isCodexAppServerStartSelectionChangedError(error) && selectionAttempt === 0) retrySelection = true;
172
187
  else throw error;
173
188
  } finally {
174
189
  clearTimeout(timeout);
175
190
  params.signal?.removeEventListener("abort", abortFromCaller);
176
191
  await interruptPromise;
177
- if (ownsClient) client.close();
192
+ if (ownsClient) await closeCodexStartupClientBestEffort(client);
178
193
  }
179
194
  if (retrySelection) return await runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace, selectionAttempt + 1, {
180
195
  deadline,
@@ -189,6 +204,10 @@ function resolveBoundedThreadConfig(params, workspace, inheritedMcpServerNames)
189
204
  return mergeCodexThreadConfigs(privateConfig, CODEX_SETTLED_FINALIZER_THREAD_CONFIG, buildCodexRingZeroThreadConfigPatch({ toolsAllow: ["openclaw"] }, true, inheritedMcpServerNames)) ?? privateConfig;
190
205
  }
191
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
+ });
192
211
  const privateEnv = Object.fromEntries(Object.entries(start.env ?? {}).filter(([name]) => name.trim().toUpperCase() !== CODEX_APP_SERVER_ARGS_ENV_KEY));
193
212
  const clearEnv = (start.clearEnv ?? []).filter((name) => {
194
213
  const normalized = name.trim().toUpperCase();
@@ -196,7 +215,12 @@ function buildPrivateCodexAppServerStartOptions(start, codexHome) {
196
215
  });
197
216
  return {
198
217
  ...start,
199
- args: [...CODEX_PRIVATE_STDIO_ARGS],
218
+ args: [
219
+ "app-server",
220
+ ...providerArgs,
221
+ "--listen",
222
+ "stdio://"
223
+ ],
200
224
  env: {
201
225
  ...privateEnv,
202
226
  CODEX_HOME: codexHome
@@ -243,7 +267,7 @@ async function resolveCodexBoundedTurnModel(params) {
243
267
  if (params.requiredModalities.includes("text") && !match.inputModalities.includes("text")) throw new Error(`Codex app-server model does not support text: ${model}`);
244
268
  return model;
245
269
  }
246
- function createCodexBoundedTurnCollector(threadId, taskLabel) {
270
+ function createCodexBoundedTurnCollector(threadId, taskLabel, allowEmptyText) {
247
271
  let turnId;
248
272
  let completedTurn;
249
273
  let promptError;
@@ -252,10 +276,7 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
252
276
  const completedItems = /* @__PURE__ */ new Map();
253
277
  const assistantTextByItem = /* @__PURE__ */ new Map();
254
278
  const assistantItemOrder = [];
255
- let resolveCompletion;
256
- const completion = new Promise((resolve) => {
257
- resolveCompletion = resolve;
258
- });
279
+ const { promise: completion, resolve: resolveCompletion } = createDeferred();
259
280
  const rememberAssistantText = (itemId, text) => {
260
281
  if (!text) return;
261
282
  if (!assistantTextByItem.has(itemId)) assistantItemOrder.push(itemId);
@@ -263,12 +284,12 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
263
284
  };
264
285
  const handleNotification = (notification) => {
265
286
  const params = isJsonObject(notification.params) ? notification.params : void 0;
266
- if (!params || readString(params, "threadId") !== threadId) return;
287
+ if (!params || readStringField(params, "threadId") !== threadId) return;
267
288
  if (!turnId) {
268
289
  pending.push(notification);
269
290
  return;
270
291
  }
271
- if (readNotificationTurnId(params) !== turnId) return;
292
+ if (readCodexNotificationTurnId(params) !== turnId) return;
272
293
  if (notification.method === "item/completed") {
273
294
  const item = readCodexNotificationItem(notification.params);
274
295
  if (item) {
@@ -278,8 +299,8 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
278
299
  return;
279
300
  }
280
301
  if (notification.method === "item/agentMessage/delta") {
281
- const itemId = readString(params, "itemId") ?? readString(params, "id") ?? "assistant";
282
- const delta = readString(params, "delta") ?? "";
302
+ const itemId = readStringField(params, "itemId") ?? readStringField(params, "id") ?? "assistant";
303
+ const delta = readStringField(params, "delta") ?? "";
283
304
  rememberAssistantText(itemId, `${assistantTextByItem.get(itemId) ?? ""}${delta}`);
284
305
  return;
285
306
  }
@@ -290,26 +311,26 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
290
311
  }
291
312
  if (notification.method === "turn/completed") {
292
313
  completedTurn = readCodexTurnCompletedNotification(notification.params)?.turn ?? completedTurn;
293
- resolveCompletion?.();
314
+ resolveCompletion();
294
315
  return;
295
316
  }
296
317
  if (notification.method === "error") {
297
318
  if (isRetryableErrorNotification(notification.params)) return;
298
319
  promptError = readCodexErrorNotification(notification.params)?.error.message ?? `codex app-server ${taskLabel} turn failed`;
299
- resolveCompletion?.();
320
+ resolveCompletion();
300
321
  }
301
322
  };
302
323
  return {
303
324
  handleNotification,
304
325
  async collect(startedTurn, options) {
305
326
  turnId = startedTurn.id;
306
- if (isTerminalTurn(startedTurn)) completedTurn = startedTurn;
327
+ if (isTerminalTurnStatus(startedTurn.status)) completedTurn = startedTurn;
307
328
  for (const notification of pending.splice(0)) handleNotification(notification);
308
329
  if (!completedTurn && !promptError) await waitForTurnCompletion({
309
330
  completion,
310
- timeoutMs: options.timeoutMs,
311
331
  signal: options.signal,
312
- taskLabel
332
+ taskLabel,
333
+ timeoutError: options.timeoutError
313
334
  });
314
335
  if (promptError) throw new Error(promptError);
315
336
  if (completedTurn?.status === "failed") throw new Error(completedTurn.error?.message ?? `codex app-server ${taskLabel} turn failed`);
@@ -318,7 +339,7 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
318
339
  const itemText = collectAssistantTextFromItems(items);
319
340
  const deltaText = assistantItemOrder.map((itemId) => assistantTextByItem.get(itemId)?.trim()).filter((text) => Boolean(text)).join("\n\n").trim();
320
341
  const text = (itemText || deltaText).trim();
321
- 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.`);
322
343
  return {
323
344
  text,
324
345
  items,
@@ -333,36 +354,23 @@ function collectCompletedItems(turnItems, notificationItems) {
333
354
  return [...items.values()];
334
355
  }
335
356
  async function waitForTurnCompletion(params) {
336
- if (params.signal.aborted) throw new Error(`codex app-server ${params.taskLabel} turn aborted`);
337
- let timeout;
357
+ if (params.signal.aborted) throw resolveCodexBoundedTurnAbortError(params.signal, params.taskLabel, params.timeoutError);
338
358
  let cleanupAbort;
339
359
  try {
340
360
  await Promise.race([params.completion, new Promise((_, reject) => {
341
- timeout = setTimeout(() => reject(/* @__PURE__ */ new Error(`codex app-server ${params.taskLabel} turn timed out`)), params.timeoutMs);
342
- timeout.unref?.();
343
- const abortListener = () => reject(/* @__PURE__ */ new Error(`codex app-server ${params.taskLabel} turn aborted`));
361
+ const abortListener = () => reject(resolveCodexBoundedTurnAbortError(params.signal, params.taskLabel, params.timeoutError));
344
362
  params.signal.addEventListener("abort", abortListener, { once: true });
345
363
  cleanupAbort = () => params.signal.removeEventListener("abort", abortListener);
346
364
  })]);
347
365
  } finally {
348
- if (timeout) clearTimeout(timeout);
349
366
  cleanupAbort?.();
350
367
  }
351
368
  }
369
+ function resolveCodexBoundedTurnAbortError(signal, taskLabel, timeoutError) {
370
+ return signal.reason === timeoutError ? timeoutError : /* @__PURE__ */ new Error(`codex app-server ${taskLabel} turn aborted`);
371
+ }
352
372
  function collectAssistantTextFromItems(items) {
353
373
  return (items ?? []).filter((item) => item.type === "agentMessage").map((item) => item.text.trim()).filter(Boolean).join("\n\n").trim();
354
374
  }
355
- function readNotificationTurnId(record) {
356
- const direct = readString(record, "turnId");
357
- if (direct) return direct;
358
- return isJsonObject(record.turn) ? readString(record.turn, "id") : void 0;
359
- }
360
- function readString(record, key) {
361
- const value = record[key];
362
- return typeof value === "string" ? value : void 0;
363
- }
364
- function isTerminalTurn(turn) {
365
- return turn.status === "completed" || turn.status === "interrupted" || turn.status === "failed";
366
- }
367
375
  //#endregion
368
376
  export { runBoundedCodexAppServerTurn as t };
@@ -1,4 +1,4 @@
1
- import { _ as CodexAppServerRpcError } from "./shared-client-BVKE40c-.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 { _ as CodexAppServerRpcError } from "./shared-client-BVKE40c-.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-CqZ0Fp2a.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 { V as isJsonObject } from "./shared-client-BVKE40c-.js";
2
- import { c as summarizeCodexRateLimits, o as summarizeCodexAccountRateLimits, r as hasCodexRateLimitSnapshots } from "./rate-limits-S_PXs0ul.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 };