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

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 (68) hide show
  1. package/README.md +2 -0
  2. package/dist/api.js +147 -0
  3. package/dist/app-server-policy-bg5QPSVP.js +25 -0
  4. package/dist/attempt-client-cleanup-URjUlCHg.js +735 -0
  5. package/dist/binding-connection-DAvZwp96.js +45 -0
  6. package/dist/{bounded-turn-D2ZAgZVz.js → bounded-turn-4BjrZEwW.js} +63 -56
  7. package/dist/{capabilities-BFDTVYr4.js → capabilities-CH3K57v4.js} +8 -2
  8. package/dist/cli-metadata.js +1 -1
  9. package/dist/{command-formatters-C336eRVS.js → command-formatters-D0nZ3qtd.js} +18 -18
  10. package/dist/{command-handlers-DAHUSry9.js → command-handlers-DC86lgT4.js} +507 -101
  11. package/dist/command-rpc-xUIIonsO.js +90 -0
  12. package/dist/{compact-D_uvHurS.js → compact-COqgBRny.js} +234 -214
  13. package/dist/{session-binding-BXpo9ymA.js → config-CpNeo5AE.js} +284 -1163
  14. package/dist/context-compaction-activity-BOeJf7yo.js +58 -0
  15. package/dist/{conversation-binding-data-BHRpYbX3.js → conversation-binding-data-CW2GuupV.js} +6 -10
  16. package/dist/doctor-contract-api.js +48 -50
  17. package/dist/{dynamic-tools-D2gYkSBO.js → dynamic-tools-fJZhl4CE.js} +3442 -1433
  18. package/dist/{effective-mcp-catalog-Bbd98Inw.js → effective-mcp-catalog-4YKn51aG.js} +20 -15
  19. package/dist/elicitation-input-DMkeki8d.js +71 -0
  20. package/dist/{event-projector-assistant-message-DTgnPPVF.js → event-projector-assistant-message-BwxV4d6N.js} +11 -23
  21. package/dist/{attempt-notifications-AP-a-Q5k.js → event-projector-usage-CLwNEJqW.js} +113 -29
  22. package/dist/harness-DoKQcF8n.js +258 -0
  23. package/dist/harness.js +2 -160
  24. package/dist/image-payload-sanitizer-CnfoUPCE.js +65 -0
  25. package/dist/index.js +730 -256
  26. package/dist/isolated-completion-DPMtlH9r.js +75 -0
  27. package/dist/local-runtime-attribution-B_2mnqhb.js +19 -0
  28. package/dist/managed-binary-By4FZC6i.js +212 -0
  29. package/dist/media-understanding-provider.js +5 -5
  30. package/dist/model-catalog-CmGoqVKB.js +48 -0
  31. package/dist/{models-BBMKU4jA.js → models-CZw1wClT.js} +12 -17
  32. package/dist/native-subagent-monitor-GGq3RnOo.js +3225 -0
  33. package/dist/node-exec-server.runtime-Bsu1LdFZ.js +192 -0
  34. package/dist/{plugin-app-cache-key-DztPafOA.js → plugin-app-cache-key-DMNQ8Zi8.js} +18 -6
  35. package/dist/plugin-approval-roundtrip-C75Yiiwc.js +95 -0
  36. package/dist/plugin-marketplace-discovery-CSWDkMrP.js +399 -0
  37. package/dist/{computer-use-CYEc8U3w.js → plugin-metadata-cache-BXH5NF-4.js} +109 -6
  38. package/dist/protocol-validators-VAVyEnDp.js +2399 -0
  39. package/dist/{rate-limits-CU-gVCCS.js → rate-limits-BI1dMHDG.js} +17 -35
  40. package/dist/{request-qKh331yu.js → request-DSK0W6YI.js} +3 -3
  41. package/dist/{run-attempt-CY9WlDLc.js → run-attempt-BV3HzuCf.js} +3416 -7194
  42. package/dist/{runtime-artifact-CmtG_t1L.js → runtime-artifact-BvyT1uyd.js} +11 -29
  43. package/dist/{sandbox-guard-NuhpXmPB.js → sandbox-guard-C1qEeZ5C.js} +29 -30
  44. package/dist/session-binding-BTrLf9Qm.js +874 -0
  45. package/dist/{session-catalog-DyOgR4WH.js → session-catalog-ezP_UcRM.js} +1584 -1289
  46. package/dist/session-catalog-home-id-BNwAJ9D7.js +18 -0
  47. package/dist/{session-cli-2PZaFLRh.js → session-cli-B1hKvfkI.js} +20 -7
  48. package/dist/session-retirement-CE4iMiLh.js +36 -0
  49. package/dist/{session-upstream-marker-B6U7tLw5.js → session-upstream-marker-D_2npHlA.js} +1 -1
  50. package/dist/{settled-turn-finalizer-CXY2Z9dT.js → settled-turn-finalizer-Dx1onIqg.js} +40 -28
  51. package/dist/{shared-client-DTbvH-XV.js → shared-client-Dw-rzii0.js} +1315 -469
  52. package/dist/{side-question-_ulBk1AL.js → side-question-DbXkJZzg.js} +140 -69
  53. package/dist/{thread-lifecycle-DF53ogiA.js → thread-lifecycle-DKdrnTMX.js} +927 -768
  54. package/dist/thread-ownership-i2NBwDUL.js +92 -0
  55. package/dist/thread-resume-CdJk2Ehf.js +30 -0
  56. package/dist/transcript-mirror-BU0_LKAL.js +588 -0
  57. package/dist/{transport-stdio-DXgGZ7Ib.js → transport-stdio-DhoGy33Z.js} +13 -2
  58. package/dist/upstream-prompt-provenance-CFmsKwr9.js +39 -0
  59. package/dist/{upstream-session-fork-Dy4Xvuoj.js → upstream-session-fork-BDVJCLAD.js} +14 -8
  60. package/dist/{usage-CQ6GhD5-.js → usage-9dKJCgcy.js} +3 -3
  61. package/dist/{web-search-provider.runtime-CCFhg2z5.js → web-search-provider.runtime-DCdx4DGu.js} +8 -9
  62. package/openclaw.plugin.json +49 -4
  63. package/package.json +6 -5
  64. package/dist/app-server-policy-BSaO2JIT.js +0 -49
  65. package/dist/conversation-control-xsIeXbo4.js +0 -287
  66. package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
  67. package/dist/notification-correlation-CU6_AnOb.js +0 -67
  68. package/dist/transcript-mirror-DzsdNCf5.js +0 -6924
@@ -0,0 +1,45 @@
1
+ import { h as readCodexPluginConfig, i as resolveCodexAppServerRuntimeOptions, s as resolveCodexSupervisionAppServerRuntimeOptions } from "./config-CpNeo5AE.js";
2
+ import { a as resolveCodexCatalogConnectionHome, t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-DMNQ8Zi8.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
+ let appServer = (usesSupervisionConnection ? resolveCodexSupervisionAppServerRuntimeOptions : resolveCodexAppServerRuntimeOptions)(runtimeParams);
20
+ if (usesSupervisionConnection) {
21
+ const persistedFingerprint = binding.pendingSupervisionBranch?.connectionFingerprint ?? binding.appServerRuntimeFingerprint;
22
+ const catalogHome = persistedFingerprint ? resolveCodexCatalogConnectionHome(persistedFingerprint, runtimeParams.agentDir) : void 0;
23
+ if (catalogHome) appServer = {
24
+ ...appServer,
25
+ start: {
26
+ ...appServer.start,
27
+ homeScope: "user",
28
+ env: {
29
+ ...appServer.start.env,
30
+ CODEX_HOME: catalogHome
31
+ }
32
+ }
33
+ };
34
+ const currentFingerprint = buildCodexAppServerConnectionFingerprint(appServer, runtimeParams.agentDir);
35
+ if (!persistedFingerprint || persistedFingerprint !== currentFingerprint) throw new Error("Codex supervision connection changed; refusing to operate on its bound native thread");
36
+ }
37
+ return {
38
+ appServer,
39
+ usesSupervisionConnection,
40
+ requestAuthProfileId: usesSupervisionConnection ? void 0 : authProfileId,
41
+ clientAuthProfileId: usesSupervisionConnection ? null : authProfileId
42
+ };
43
+ }
44
+ //#endregion
45
+ 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 { i as resolveCodexAppServerRuntimeOptions } from "./config-CpNeo5AE.js";
2
+ import { V as createCodexElicitationResponse, s as isCodexAppServerStartSelectionChangedError, ut as isJsonObject } from "./shared-client-Dw-rzii0.js";
3
+ import { _ as readCodexNotificationTurnId, a as closeCodexStartupClientBestEffort, o as interruptCodexTurnAndWaitBestEffort, t as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS } from "./attempt-client-cleanup-URjUlCHg.js";
4
+ import { b as isTerminalTurnStatus, n as normalizeCodexResponseTokenUsage, x as readCodexNotificationItem, y as isRetryableErrorNotification } from "./event-projector-usage-CLwNEJqW.js";
5
+ import { a as assertCodexThreadStartResponse, c as readCodexErrorNotification, o as assertCodexTurnStartResponse, u as readCodexTurnCompletedNotification } from "./protocol-validators-VAVyEnDp.js";
6
+ import { r as readModelListResult } from "./models-CZw1wClT.js";
7
+ import { Z as mergeCodexThreadConfigs, c as buildCodexRingZeroThreadConfigPatch, l as buildCodexRuntimeThreadConfig, o as assertCodexManagedRequirementsDoNotOverrideToolPolicy, s as attestCodexRestrictedToolSurfaceMcpServersDisabled, u as readCodexInheritedMcpServerNames } from "./thread-lifecycle-DKdrnTMX.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-Dw-rzii0.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,
@@ -109,7 +115,7 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
109
115
  timeout.unref?.();
110
116
  let retrySelection = false;
111
117
  try {
112
- const model = await resolveCodexBoundedTurnModel({
118
+ const modelSelection = await resolveCodexBoundedTurnModel({
113
119
  client,
114
120
  selection: params.model,
115
121
  requiredModalities: params.requiredModalities,
@@ -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 assertCodexManagedRequirementsDoNotOverrideToolPolicy(client, { restrictedToolSurface: true }, abortController.signal);
127
+ const threadConfig = buildCodexRuntimeThreadConfig(resolveBoundedThreadConfig(params, workspace, inheritedMcpServerNames), { nativeCodeModeEnabled: false });
121
128
  const thread = assertCodexThreadStartResponse(await client.request("thread/start", {
122
- model,
123
- modelProvider: "openai",
129
+ model: modelSelection.runtimeModelId,
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,16 +153,15 @@ 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
- model,
164
+ model: modelSelection.runtimeModelId,
159
165
  effort: "low"
160
166
  }, {
161
167
  timeoutMs,
@@ -168,9 +174,10 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
168
174
  signal: abortController.signal,
169
175
  timeoutError
170
176
  }),
171
- model
177
+ model: modelSelection.catalogId
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
@@ -226,7 +242,7 @@ function createCodexBoundedApprovalHandler(taskLabel) {
226
242
  decision: "decline",
227
243
  reason: `OpenClaw Codex ${taskLabel} does not grant native approvals.`
228
244
  };
229
- if (request.method === "mcpServer/elicitation/request") return { action: "decline" };
245
+ if (request.method === "mcpServer/elicitation/request") return createCodexElicitationResponse("decline", null, { message: `OpenClaw Codex ${taskLabel} does not support interactive input.` });
230
246
  };
231
247
  }
232
248
  async function resolveCodexBoundedTurnModel(params) {
@@ -242,16 +258,22 @@ async function resolveCodexBoundedTurnModel(params) {
242
258
  const supported = listed.filter((entry) => params.requiredModalities.every((modality) => entry.inputModalities.includes(modality)));
243
259
  const selected = supported.find((entry) => entry.isDefault) ?? supported[0];
244
260
  if (!selected) throw new Error(`Codex app-server has no model supporting ${params.requiredModalities.join(" and ")} input.`);
245
- return selected.model;
261
+ return {
262
+ catalogId: selected.id,
263
+ runtimeModelId: selected.model
264
+ };
246
265
  }
247
266
  const model = params.selection.id;
248
267
  const match = listed.find((entry) => entry.model === model || entry.id === model);
249
268
  if (!match) throw new Error(`Codex app-server model not found: ${model}`);
250
269
  if (params.requiredModalities.includes("image") && !match.inputModalities.includes("image")) throw new Error(`Codex app-server model does not support images: ${model}`);
251
270
  if (params.requiredModalities.includes("text") && !match.inputModalities.includes("text")) throw new Error(`Codex app-server model does not support text: ${model}`);
252
- return model;
271
+ return {
272
+ catalogId: match.id,
273
+ runtimeModelId: match.model
274
+ };
253
275
  }
254
- function createCodexBoundedTurnCollector(threadId, taskLabel) {
276
+ function createCodexBoundedTurnCollector(threadId, taskLabel, allowEmptyText) {
255
277
  let turnId;
256
278
  let completedTurn;
257
279
  let promptError;
@@ -260,10 +282,7 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
260
282
  const completedItems = /* @__PURE__ */ new Map();
261
283
  const assistantTextByItem = /* @__PURE__ */ new Map();
262
284
  const assistantItemOrder = [];
263
- let resolveCompletion;
264
- const completion = new Promise((resolve) => {
265
- resolveCompletion = resolve;
266
- });
285
+ const { promise: completion, resolve: resolveCompletion } = createDeferred();
267
286
  const rememberAssistantText = (itemId, text) => {
268
287
  if (!text) return;
269
288
  if (!assistantTextByItem.has(itemId)) assistantItemOrder.push(itemId);
@@ -271,12 +290,12 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
271
290
  };
272
291
  const handleNotification = (notification) => {
273
292
  const params = isJsonObject(notification.params) ? notification.params : void 0;
274
- if (!params || readString(params, "threadId") !== threadId) return;
293
+ if (!params || readStringField(params, "threadId") !== threadId) return;
275
294
  if (!turnId) {
276
295
  pending.push(notification);
277
296
  return;
278
297
  }
279
- if (readNotificationTurnId(params) !== turnId) return;
298
+ if (readCodexNotificationTurnId(params) !== turnId) return;
280
299
  if (notification.method === "item/completed") {
281
300
  const item = readCodexNotificationItem(notification.params);
282
301
  if (item) {
@@ -286,8 +305,8 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
286
305
  return;
287
306
  }
288
307
  if (notification.method === "item/agentMessage/delta") {
289
- const itemId = readString(params, "itemId") ?? readString(params, "id") ?? "assistant";
290
- const delta = readString(params, "delta") ?? "";
308
+ const itemId = readStringField(params, "itemId") ?? readStringField(params, "id") ?? "assistant";
309
+ const delta = readStringField(params, "delta") ?? "";
291
310
  rememberAssistantText(itemId, `${assistantTextByItem.get(itemId) ?? ""}${delta}`);
292
311
  return;
293
312
  }
@@ -298,20 +317,20 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
298
317
  }
299
318
  if (notification.method === "turn/completed") {
300
319
  completedTurn = readCodexTurnCompletedNotification(notification.params)?.turn ?? completedTurn;
301
- resolveCompletion?.();
320
+ resolveCompletion();
302
321
  return;
303
322
  }
304
323
  if (notification.method === "error") {
305
324
  if (isRetryableErrorNotification(notification.params)) return;
306
325
  promptError = readCodexErrorNotification(notification.params)?.error.message ?? `codex app-server ${taskLabel} turn failed`;
307
- resolveCompletion?.();
326
+ resolveCompletion();
308
327
  }
309
328
  };
310
329
  return {
311
330
  handleNotification,
312
331
  async collect(startedTurn, options) {
313
332
  turnId = startedTurn.id;
314
- if (isTerminalTurn(startedTurn)) completedTurn = startedTurn;
333
+ if (isTerminalTurnStatus(startedTurn.status)) completedTurn = startedTurn;
315
334
  for (const notification of pending.splice(0)) handleNotification(notification);
316
335
  if (!completedTurn && !promptError) await waitForTurnCompletion({
317
336
  completion,
@@ -326,7 +345,7 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
326
345
  const itemText = collectAssistantTextFromItems(items);
327
346
  const deltaText = assistantItemOrder.map((itemId) => assistantTextByItem.get(itemId)?.trim()).filter((text) => Boolean(text)).join("\n\n").trim();
328
347
  const text = (itemText || deltaText).trim();
329
- if (!text) throw new Error(`Codex app-server ${taskLabel} turn returned no text.`);
348
+ if (!text && !allowEmptyText) throw new Error(`Codex app-server ${taskLabel} turn returned no text.`);
330
349
  return {
331
350
  text,
332
351
  items,
@@ -359,17 +378,5 @@ function resolveCodexBoundedTurnAbortError(signal, taskLabel, timeoutError) {
359
378
  function collectAssistantTextFromItems(items) {
360
379
  return (items ?? []).filter((item) => item.type === "agentMessage").map((item) => item.text.trim()).filter(Boolean).join("\n\n").trim();
361
380
  }
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
381
  //#endregion
375
382
  export { runBoundedCodexAppServerTurn as t };
@@ -1,4 +1,4 @@
1
- import { v as CodexAppServerRpcError } from "./shared-client-DTbvH-XV.js";
1
+ import { B as CodexAppServerRpcError } from "./shared-client-Dw-rzii0.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-B1hKvfkI.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 { ut as isJsonObject } from "./shared-client-Dw-rzii0.js";
2
+ import { c as summarizeCodexRateLimits, o as summarizeCodexAccountRateLimits, r as hasCodexRateLimitSnapshots } from "./rate-limits-BI1dMHDG.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 };