@openclaw/codex 2026.6.2-beta.1 → 2026.6.5-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 (28) hide show
  1. package/dist/{client-factory-BS9nYX8K.js → client-factory-Bt49r45B.js} +2 -1
  2. package/dist/{client-BFxKzFnH.js → client-kMCtlApt.js} +42 -0
  3. package/dist/{command-handlers-BaBMyAFy.js → command-handlers-DMn2M7W7.js} +9 -9
  4. package/dist/{compact-CVPc2Rag.js → compact-CwnPeYnM.js} +11 -4
  5. package/dist/{computer-use-Dhz6SrFx.js → computer-use-ClweWaMz.js} +11 -1
  6. package/dist/{conversation-binding-CMaXGYAc.js → conversation-binding-CzpvaBs1.js} +7 -7
  7. package/dist/doctor-contract-api.js +5 -0
  8. package/dist/harness.js +9 -5
  9. package/dist/index.js +8 -6
  10. package/dist/media-understanding-provider.js +13 -5
  11. package/dist/{models-D8i1zWEu.js → models-DXorTaja.js} +9 -2
  12. package/dist/{native-hook-relay-CBp3nIGk.js → native-hook-relay-DZ3Oon0b.js} +61 -3
  13. package/dist/{notification-correlation-Bg-AlEEy.js → notification-correlation-o8quHmTK.js} +30 -1
  14. package/dist/prompt-overlay.js +7 -0
  15. package/dist/{protocol-validators-DIt7cXIp.js → protocol-validators-CIpP8IJ2.js} +13 -0
  16. package/dist/provider-catalog.js +8 -0
  17. package/dist/provider-discovery.js +1 -0
  18. package/dist/provider.js +16 -1
  19. package/dist/{rate-limit-cache-N66I-Rd7.js → rate-limit-cache-C7qmZ0Jh.js} +2 -0
  20. package/dist/{request-nYrsFNU2.js → request-D64BfplD.js} +16 -4
  21. package/dist/{run-attempt-Wo9uasL_.js → run-attempt-CWfXFq9Q.js} +383 -27
  22. package/dist/{sandbox-guard-DMCJlzmz.js → sandbox-guard-C-Yv9uwY.js} +5 -0
  23. package/dist/{session-binding-D8DxeEbf.js → session-binding-BgTv_YGm.js} +11 -0
  24. package/dist/{shared-client-B31-oqN-.js → shared-client-xytpSKD0.js} +31 -2
  25. package/dist/{side-question-DbYSPUnj.js → side-question-BEpALo9c.js} +9 -9
  26. package/dist/{thread-lifecycle-BOYYMjx6.js → thread-lifecycle-BJsazZ8j.js} +50 -6
  27. package/npm-shrinkwrap.json +2 -2
  28. package/package.json +4 -4
@@ -1,16 +1,16 @@
1
1
  import { c as readCodexPluginConfig, d as resolveCodexPluginsPolicy, f as resolveOpenClawExecPolicyForCodexAppServer, i as isCodexAppServerApprovalPolicyAllowedByRequirements, l as resolveCodexAppServerRuntimeOptions, m as withMcpElicitationsApprovalPolicy, o as isCodexSandboxExecServerEnabled, p as shouldAutoApproveCodexAppServerApprovals, u as resolveCodexComputerUseConfig } from "./config-BT6SLiE6.js";
2
- import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-DIt7cXIp.js";
3
- import { a as isCodexAppServerConnectionClosedError, i as isCodexAppServerApprovalRequest, l as isJsonObject, r as compareCodexAppServerVersions, s as MIN_CODEX_SANDBOX_EXEC_SERVER_APP_SERVER_VERSION } from "./client-BFxKzFnH.js";
4
- import { A as projectContextEngineAssemblyForCodex, C as sanitizeCodexHistoryImagePayloads, D as normalizeCodexDynamicToolName$1, E as isForcedPrivateQaCodexRuntime, M as resolveCodexContextEngineProjectionReserveTokens, T as filterCodexDynamicTools, _ as shouldBuildCodexPluginThreadConfig, a as buildDeveloperInstructions, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as mergeCodexThreadConfigs, h as buildCodexPluginThreadConfigInputFingerprint, i as buildContextEngineBinding, j as resolveCodexContextEngineProjectionMaxChars, k as resolveCodexDynamicToolsLoadingForModel, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfig, n as areCodexDynamicToolFingerprintsCompatible, o as buildTurnCollaborationMode, p as isCodexAppServerProfilerEnabled, s as buildTurnStartParams, x as defaultCodexAppInventoryCache } from "./thread-lifecycle-BOYYMjx6.js";
5
- import { a as readCodexAppServerBinding, n as clearCodexAppServerBindingForThread, s as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-D8DxeEbf.js";
6
- import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-nYrsFNU2.js";
7
- import { _ as shouldRefreshCodexRateLimitsForUsageLimitMessage, g as resolveCodexUsageLimitResetAtMs, h as formatCodexUsageLimitErrorMessage, i as readCodexNotificationTurnId, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-Bg-AlEEy.js";
8
- import { d as resolveCodexAppServerAuthAccountCacheKey, f as resolveCodexAppServerAuthProfileId, h as resolveCodexAppServerHomeDir, m as resolveCodexAppServerFallbackApiKeyCacheKey, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as releaseLeasedSharedCodexAppServerClient, p as resolveCodexAppServerAuthProfileIdForAgent, s as retireSharedCodexAppServerClientIfCurrent, t as clearSharedCodexAppServerClientIfCurrent, u as refreshCodexAppServerAuthTokens } from "./shared-client-B31-oqN-.js";
9
- import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-DMCJlzmz.js";
10
- import { t as defaultLeasedCodexAppServerClientFactory } from "./client-factory-BS9nYX8K.js";
11
- import { S as withCodexStartupTimeout, _ as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, a as createCodexNativeHookRelay, b as resolveCodexTurnCompletionIdleTimeoutMs, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, h as handleCodexAppServerApprovalRequest, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, n as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, o as resolveCodexNativeHookRelayEvents, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, s as resolveCodexNativeHookRelayTtlMs, u as createCodexDynamicToolBridge, v as resolveCodexStartupTimeoutMs, x as resolveCodexTurnTerminalIdleTimeoutMs, y as resolveCodexTurnAssistantCompletionIdleTimeoutMs } from "./native-hook-relay-CBp3nIGk.js";
12
- import { t as ensureCodexComputerUse } from "./computer-use-Dhz6SrFx.js";
13
- import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-N66I-Rd7.js";
2
+ import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-CIpP8IJ2.js";
3
+ import { a as isCodexAppServerConnectionClosedError, i as isCodexAppServerApprovalRequest, l as isJsonObject, r as compareCodexAppServerVersions, s as MIN_CODEX_SANDBOX_EXEC_SERVER_APP_SERVER_VERSION } from "./client-kMCtlApt.js";
4
+ import { A as projectContextEngineAssemblyForCodex, C as sanitizeCodexHistoryImagePayloads, D as normalizeCodexDynamicToolName$1, E as isForcedPrivateQaCodexRuntime, M as resolveCodexContextEngineProjectionReserveTokens, T as filterCodexDynamicTools, _ as shouldBuildCodexPluginThreadConfig, a as buildDeveloperInstructions, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as mergeCodexThreadConfigs, h as buildCodexPluginThreadConfigInputFingerprint, i as buildContextEngineBinding, j as resolveCodexContextEngineProjectionMaxChars, k as resolveCodexDynamicToolsLoadingForModel, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfig, n as areCodexDynamicToolFingerprintsCompatible, o as buildTurnCollaborationMode, p as isCodexAppServerProfilerEnabled, s as buildTurnStartParams, x as defaultCodexAppInventoryCache } from "./thread-lifecycle-BJsazZ8j.js";
5
+ import { a as readCodexAppServerBinding, n as clearCodexAppServerBindingForThread, s as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-BgTv_YGm.js";
6
+ import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-D64BfplD.js";
7
+ import { _ as shouldRefreshCodexRateLimitsForUsageLimitMessage, g as resolveCodexUsageLimitResetAtMs, h as formatCodexUsageLimitErrorMessage, i as readCodexNotificationTurnId, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-o8quHmTK.js";
8
+ import { d as resolveCodexAppServerAuthAccountCacheKey, f as resolveCodexAppServerAuthProfileId, h as resolveCodexAppServerHomeDir, m as resolveCodexAppServerFallbackApiKeyCacheKey, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as releaseLeasedSharedCodexAppServerClient, p as resolveCodexAppServerAuthProfileIdForAgent, s as retireSharedCodexAppServerClientIfCurrent, t as clearSharedCodexAppServerClientIfCurrent, u as refreshCodexAppServerAuthTokens } from "./shared-client-xytpSKD0.js";
9
+ import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-C-Yv9uwY.js";
10
+ import { t as defaultLeasedCodexAppServerClientFactory } from "./client-factory-Bt49r45B.js";
11
+ import { S as withCodexStartupTimeout, _ as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, a as createCodexNativeHookRelay, b as resolveCodexTurnCompletionIdleTimeoutMs, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, h as handleCodexAppServerApprovalRequest, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, n as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, o as resolveCodexNativeHookRelayEvents, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, s as resolveCodexNativeHookRelayTtlMs, u as createCodexDynamicToolBridge, v as resolveCodexStartupTimeoutMs, x as resolveCodexTurnTerminalIdleTimeoutMs, y as resolveCodexTurnAssistantCompletionIdleTimeoutMs } from "./native-hook-relay-DZ3Oon0b.js";
12
+ import { t as ensureCodexComputerUse } from "./computer-use-ClweWaMz.js";
13
+ import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-C7qmZ0Jh.js";
14
14
  import { asDateTimestampMs, parseStrictNonNegativeInteger, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
15
15
  import { createHash, randomUUID } from "node:crypto";
16
16
  import fsSync from "node:fs";
@@ -33,6 +33,10 @@ import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generat
33
33
  import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
34
34
  import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
35
35
  //#region extensions/codex/src/app-server/app-server-policy.ts
36
+ /**
37
+ * Promotes implicit `never` approval policy to `untrusted` only when runtime
38
+ * requirements allow OpenClaw to handle tool approvals.
39
+ */
36
40
  function resolveCodexAppServerForOpenClawToolPolicy(params) {
37
41
  if (!params.shouldPromote || !params.canUseUntrustedApprovalPolicy || params.appServer.approvalPolicy !== "never") return params.appServer;
38
42
  const explicitMode = params.execPolicy?.mode === "full" || params.pluginConfig.appServer?.mode !== void 0 || isCodexAppServerPolicyMode(params.env.OPENCLAW_CODEX_APP_SERVER_MODE);
@@ -51,8 +55,14 @@ function isCodexAppServerApprovalPolicy(value) {
51
55
  }
52
56
  //#endregion
53
57
  //#region extensions/codex/src/app-server/attempt-client-cleanup.ts
58
+ /**
59
+ * Best-effort cleanup helpers for timed-out or aborted Codex app-server turns.
60
+ */
61
+ /** Timeout for best-effort app-server turn interruption during cleanup. */
54
62
  const CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS = 5e3;
63
+ /** Timeout for best-effort thread unsubscribe during cleanup. */
55
64
  const CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS = 5e3;
65
+ /** Sends a turn interrupt without blocking abort cleanup on app-server errors. */
56
66
  function interruptCodexTurnBestEffort(client, params) {
57
67
  const requestOptions = params.timeoutMs && Number.isFinite(params.timeoutMs) && params.timeoutMs > 0 ? { timeoutMs: params.timeoutMs } : void 0;
58
68
  const requestParams = {
@@ -68,6 +78,7 @@ function interruptCodexTurnBestEffort(client, params) {
68
78
  embeddedAgentLog.debug("codex app-server turn interrupt failed during abort", { error });
69
79
  }
70
80
  }
81
+ /** Unsubscribes from a thread while swallowing cleanup-only failures. */
71
82
  async function unsubscribeCodexThreadBestEffort(client, params) {
72
83
  try {
73
84
  await client.request("thread/unsubscribe", { threadId: params.threadId }, { timeoutMs: params.timeoutMs });
@@ -78,6 +89,10 @@ async function unsubscribeCodexThreadBestEffort(client, params) {
78
89
  });
79
90
  }
80
91
  }
92
+ /**
93
+ * Retires the shared client after a timed-out turn so later runs do not reuse a
94
+ * potentially wedged app-server connection.
95
+ */
81
96
  async function retireCodexAppServerClientAfterTimedOutTurn(client, params) {
82
97
  const retiredSharedClient = retireSharedCodexAppServerClientIfCurrent(client);
83
98
  const detachedSharedClient = Boolean(retiredSharedClient);
@@ -115,9 +130,14 @@ async function retireCodexAppServerClientAfterTimedOutTurn(client, params) {
115
130
  }
116
131
  //#endregion
117
132
  //#region extensions/codex/src/app-server/session-history.ts
133
+ /**
134
+ * Reads OpenClaw session history for Codex transcript mirroring and sanitizes
135
+ * image payloads before replaying messages into the app-server projector.
136
+ */
118
137
  function isMissingFileError(error) {
119
138
  return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
120
139
  }
140
+ /** Returns sanitized session-context messages for a Codex mirrored session file. */
121
141
  async function readCodexMirroredSessionHistoryMessages(sessionFile) {
122
142
  try {
123
143
  const entries = parseSessionEntries(await fs.readFile(sessionFile, "utf-8"));
@@ -132,6 +152,10 @@ async function readCodexMirroredSessionHistoryMessages(sessionFile) {
132
152
  }
133
153
  //#endregion
134
154
  //#region extensions/codex/src/app-server/attempt-context.ts
155
+ /**
156
+ * Builds Codex app-server prompt context, workspace bootstrap injections,
157
+ * system-prompt reports, and context-engine projection decisions.
158
+ */
135
159
  const CODEX_NATIVE_PROJECT_DOC_BASENAMES = new Set(["agents.md"]);
136
160
  const CODEX_INHERITED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = new Set(["tools.md"]);
137
161
  const CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = new Set([
@@ -152,11 +176,13 @@ const CODEX_BOOTSTRAP_CONTEXT_ORDER = new Map([
152
176
  ["memory.md", 60],
153
177
  ["heartbeat.md", 70]
154
178
  ]);
179
+ /** Reads mirrored Codex session history for harness hooks. */
155
180
  async function readMirroredSessionHistoryMessages(sessionFile) {
156
181
  const messages = await readCodexMirroredSessionHistoryMessages(sessionFile);
157
182
  if (!messages) embeddedAgentLog.warn("failed to read mirrored session history for codex harness hooks", { sessionFile });
158
183
  return messages;
159
184
  }
185
+ /** Reads a valid thread-bootstrap projection request from context-engine output. */
160
186
  function readContextEngineThreadBootstrapProjection(projection) {
161
187
  if (projection?.mode !== "thread_bootstrap") return;
162
188
  const epoch = projection.epoch?.trim();
@@ -171,6 +197,10 @@ function readContextEngineThreadBootstrapProjection(projection) {
171
197
  ...fingerprint ? { fingerprint } : {}
172
198
  };
173
199
  }
200
+ /**
201
+ * Decides whether an existing Codex thread can reuse its context-engine
202
+ * bootstrap projection or must be reprojected.
203
+ */
174
204
  function resolveContextEngineBootstrapProjectionDecision(params) {
175
205
  const bindingProjection = params.startupBinding?.contextEngine?.projection;
176
206
  if (!params.startupBinding?.threadId || !bindingProjection) return {
@@ -196,6 +226,10 @@ function resolveContextEngineBootstrapProjectionDecision(params) {
196
226
  reason: "matching-thread-bootstrap-binding"
197
227
  };
198
228
  }
229
+ /**
230
+ * Loads workspace bootstrap files and partitions them into Codex-native prompt,
231
+ * developer-instruction, heartbeat, and memory-tool contexts.
232
+ */
199
233
  async function buildCodexWorkspaceBootstrapContext(params) {
200
234
  try {
201
235
  const memoryToolsAvailable = params.memoryToolNames.length > 0 && canRouteCodexWorkspaceMemoryThroughTools({
@@ -269,6 +303,10 @@ async function buildCodexWorkspaceBootstrapContext(params) {
269
303
  };
270
304
  }
271
305
  }
306
+ /**
307
+ * Builds the prompt-size, bootstrap-file, skill, and tool-schema accounting
308
+ * report for a Codex run.
309
+ */
272
310
  function buildCodexSystemPromptReport(params) {
273
311
  const toolEntries = params.tools.map(buildCodexToolReportEntry);
274
312
  const schemaChars = toolEntries.reduce((sum, tool) => sum + tool.schemaChars, 0);
@@ -427,6 +465,9 @@ function readPositiveNumber(value) {
427
465
  function readNonEmptyString$1(value) {
428
466
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
429
467
  }
468
+ /**
469
+ * Builds OpenClaw-provided workspace prompt context for the current Codex turn.
470
+ */
430
471
  function buildCodexOpenClawPromptContext(params) {
431
472
  if (!shouldInjectCodexOpenClawPromptContext(params.params)) return;
432
473
  const sections = [params.workspacePromptContext?.trim() ? [
@@ -445,6 +486,7 @@ function buildCodexOpenClawPromptContext(params) {
445
486
  function shouldInjectCodexOpenClawPromptContext(params) {
446
487
  return !(params.bootstrapContextMode === "lightweight" && params.bootstrapContextRunKind === "cron");
447
488
  }
489
+ /** Renders loaded OpenClaw skill prompts as Codex collaboration instructions. */
448
490
  function renderCodexSkillsCollaborationInstructions(params) {
449
491
  if (!shouldInjectCodexOpenClawPromptContext(params.attempt)) return;
450
492
  return params.skillsPrompt?.trim() ? [
@@ -453,6 +495,10 @@ function renderCodexSkillsCollaborationInstructions(params) {
453
495
  params.skillsPrompt.trim()
454
496
  ].join("\n") : void 0;
455
497
  }
498
+ /**
499
+ * Prepends OpenClaw context while preserving leading delivery metadata as
500
+ * routing guidance instead of user request text.
501
+ */
456
502
  function prependCodexOpenClawPromptContext(prompt, context, options = {}) {
457
503
  const { deliveryHint, prompt: promptWithoutDeliveryHint } = splitLeadingCodexDeliveryHint(prompt);
458
504
  if (!context?.trim() && (!deliveryHint || options.preservePromptWithoutContext)) return prompt;
@@ -567,6 +613,10 @@ function selectCodexWorkspaceMemoryReferenceFiles(params) {
567
613
  }) && !file.missing && (file.content ?? "").trim().length > 0;
568
614
  }).toSorted(compareCodexBootstrapFiles);
569
615
  }
616
+ /**
617
+ * Renders a memory-file reference that points Codex at memory tools instead of
618
+ * embedding MEMORY.md contents.
619
+ */
570
620
  function renderCodexWorkspaceMemoryReference(params) {
571
621
  if (params.files.length === 0) return;
572
622
  const lines = [
@@ -578,6 +628,7 @@ function renderCodexWorkspaceMemoryReference(params) {
578
628
  for (const file of params.files) lines.push(`- ${file.path}`);
579
629
  return lines.join("\n").trim();
580
630
  }
631
+ /** Lists available memory tool names understood by Codex workspace memory routing. */
581
632
  function getCodexWorkspaceMemoryToolNames(tools) {
582
633
  const availableToolNames = new Set(tools.map((tool) => normalizeCodexDynamicToolName(tool.name)));
583
634
  return Array.from(CODEX_MEMORY_TOOL_NAMES).filter((name) => availableToolNames.has(name));
@@ -616,6 +667,10 @@ function isCodexWorkspaceRootMemoryPath(params) {
616
667
  function isSameCodexWorkspacePath(left, right) {
617
668
  return path.resolve(left) === path.resolve(right);
618
669
  }
670
+ /**
671
+ * Remaps bootstrap file paths from the resolved workspace to the effective Codex
672
+ * workspace while preserving platform path separators.
673
+ */
619
674
  function remapCodexContextFilePath(params) {
620
675
  const relativePath = path.relative(params.sourceWorkspaceDir, params.file.path);
621
676
  if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath) || params.sourceWorkspaceDir === params.targetWorkspaceDir) return params.file;
@@ -657,9 +712,15 @@ function isNonEmptyString$2(value) {
657
712
  }
658
713
  //#endregion
659
714
  //#region extensions/codex/src/app-server/attempt-diagnostics.ts
715
+ /**
716
+ * Diagnostic helpers for Codex app-server model calls and plugin-thread config
717
+ * eligibility.
718
+ */
719
+ /** Reads a tool schema field in either app-server or OpenClaw naming. */
660
720
  function readCodexDiagnosticToolParameters(tool) {
661
721
  return tool.inputSchema ?? tool.parameters;
662
722
  }
723
+ /** Builds compact diagnostic tool definitions for trusted private telemetry. */
663
724
  function buildCodexDiagnosticToolDefinitions(tools) {
664
725
  return tools.map((tool) => ({
665
726
  name: tool.name,
@@ -667,6 +728,7 @@ function buildCodexDiagnosticToolDefinitions(tools) {
667
728
  parameters: readCodexDiagnosticToolParameters(tool)
668
729
  }));
669
730
  }
731
+ /** Returns the serialized UTF-8 byte length for a JSON-compatible value. */
670
732
  function utf8JsonByteLength(value) {
671
733
  try {
672
734
  return Buffer.byteLength(JSON.stringify(value), "utf8");
@@ -674,6 +736,7 @@ function utf8JsonByteLength(value) {
674
736
  return;
675
737
  }
676
738
  }
739
+ /** Builds a short namespaced fingerprint for sensitive log values. */
677
740
  function fingerprintCodexLogValue(namespace, value) {
678
741
  const hash = createHash("sha256");
679
742
  hash.update(namespace);
@@ -681,6 +744,10 @@ function fingerprintCodexLogValue(namespace, value) {
681
744
  hash.update(value);
682
745
  return `sha256:${hash.digest("hex").slice(0, 16)}`;
683
746
  }
747
+ /**
748
+ * Builds redacted diagnostics explaining whether plugin thread config was
749
+ * eligible for a Codex app-server attempt.
750
+ */
684
751
  function buildCodexPluginThreadConfigEligibilityLogData(params) {
685
752
  return {
686
753
  sessionId: params.sessionId,
@@ -696,6 +763,10 @@ function buildCodexPluginThreadConfigEligibilityLogData(params) {
696
763
  appServerCommandSource: params.appServer.start.commandSource
697
764
  };
698
765
  }
766
+ /**
767
+ * Creates lifecycle emitters for trusted model-call diagnostics with optional
768
+ * private payload capture.
769
+ */
699
770
  function createCodexModelCallDiagnosticEmitter(params) {
700
771
  const now = params.now ?? (() => Date.now());
701
772
  const toolDefinitions = params.capture.toolDefinitions ? buildCodexDiagnosticToolDefinitions(params.tools) : void 0;
@@ -756,6 +827,7 @@ function createCodexModelCallDiagnosticEmitter(params) {
756
827
  }
757
828
  };
758
829
  }
830
+ /** Classifies model-call failures into timeout/abort buckets for diagnostics. */
759
831
  function classifyCodexModelCallFailureKind(params) {
760
832
  if (params.timedOut || params.turnCompletionIdleTimedOut) return "timeout";
761
833
  const errorMessage = params.error ? params.formatError(params.error).toLowerCase() : "";
@@ -765,10 +837,14 @@ function classifyCodexModelCallFailureKind(params) {
765
837
  }
766
838
  //#endregion
767
839
  //#region extensions/codex/src/app-server/attempt-notifications.ts
840
+ /**
841
+ * Predicates and readers for Codex app-server notification envelopes.
842
+ */
768
843
  const CODEX_TURN_ABORT_MARKER_START = "<turn_aborted>";
769
844
  const CODEX_TURN_ABORT_MARKER_END = "</turn_aborted>";
770
845
  const CODEX_INTERRUPTED_USER_GUIDANCE = "The user interrupted the previous turn on purpose. Any running unified exec processes may still be running in the background. If any tools/commands were aborted, they may have partially executed.";
771
846
  const CODEX_INTERRUPTED_DEVELOPER_GUIDANCE = "The previous turn was interrupted on purpose. Any running unified exec processes may still be running in the background. If any tools/commands were aborted, they may have partially executed.";
847
+ /** Builds compact activity metadata for watchdog and diagnostic updates. */
772
848
  function describeNotificationActivity(notification) {
773
849
  if (!isJsonObject(notification.params)) return { lastNotificationMethod: notification.method };
774
850
  if (notification.method !== "rawResponseItem/completed") return { lastNotificationMethod: notification.method };
@@ -782,6 +858,7 @@ function describeNotificationActivity(notification) {
782
858
  lastAssistantTextPreview: readRawAssistantTextPreview(item)
783
859
  };
784
860
  }
861
+ /** Tracks active app-server item ids from item start/completion notifications. */
785
862
  function updateActiveTurnItemIds(notification, activeItemIds) {
786
863
  if (notification.method !== "item/started" && notification.method !== "item/completed") return;
787
864
  const itemId = readNotificationItemId(notification);
@@ -798,36 +875,43 @@ function isCompletedAssistantNotification(notification) {
798
875
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
799
876
  return Boolean(item && readString$6(item, "type") === "agentMessage" && readString$6(item, "phase") !== "commentary");
800
877
  }
878
+ /** Returns true for completed app-server reasoning items. */
801
879
  function isReasoningItemCompletionNotification(notification) {
802
880
  if (!isJsonObject(notification.params) || notification.method !== "item/completed") return false;
803
881
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
804
882
  return item ? readString$6(item, "type") === "reasoning" : false;
805
883
  }
884
+ /** Returns true for completed assistant commentary items. */
806
885
  function isAssistantCommentaryCompletionNotification(notification) {
807
886
  if (!isJsonObject(notification.params) || notification.method !== "item/completed") return false;
808
887
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
809
888
  return Boolean(item && readString$6(item, "type") === "agentMessage" && readString$6(item, "phase") === "commentary");
810
889
  }
890
+ /** Returns true for completed raw response reasoning items. */
811
891
  function isRawReasoningCompletionNotification(notification) {
812
892
  if (!isJsonObject(notification.params) || notification.method !== "rawResponseItem/completed") return false;
813
893
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
814
894
  return item ? readString$6(item, "type") === "reasoning" : false;
815
895
  }
896
+ /** Returns true when assistant completion can release the short idle watch. */
816
897
  function isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff) {
817
898
  if (isCompletedAssistantNotification(notification)) return true;
818
899
  return !turnCrossedToolHandoff && isRawAssistantCompletionNotification(notification);
819
900
  }
901
+ /** Returns true when a notification proves assistant output is still active. */
820
902
  function shouldDisarmAssistantCompletionIdleWatch(notification) {
821
903
  if (!isJsonObject(notification.params)) return false;
822
904
  if (notification.method === "item/started") return true;
823
905
  if (notification.method === "item/agentMessage/delta") return true;
824
906
  return false;
825
907
  }
908
+ /** Reads an item id from supported notification envelope shapes. */
826
909
  function readNotificationItemId(notification) {
827
910
  if (!isJsonObject(notification.params)) return;
828
911
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
829
912
  return (item ? readString$6(item, "id") : void 0) ?? readString$6(notification.params, "itemId") ?? readString$6(notification.params, "id");
830
913
  }
914
+ /** Detects completion for an OpenClaw dynamic tool result still awaited by Codex. */
831
915
  function isPendingOpenClawDynamicToolCompletionNotification(notification, pendingOpenClawDynamicToolCompletionIds) {
832
916
  if (notification.method !== "item/completed" || !isJsonObject(notification.params)) return false;
833
917
  const itemId = readNotificationItemId(notification);
@@ -836,11 +920,13 @@ function isPendingOpenClawDynamicToolCompletionNotification(notification, pendin
836
920
  const itemType = item ? readString$6(item, "type") : void 0;
837
921
  return itemType === void 0 || itemType === "dynamicToolCall";
838
922
  }
923
+ /** Returns true for raw response tool-output completion notifications. */
839
924
  function isRawToolOutputCompletionNotification(notification) {
840
925
  if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
841
926
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
842
927
  return item ? readString$6(item, "type") === "custom_tool_call_output" : false;
843
928
  }
929
+ /** Returns true for progress on Codex-native tool item types. */
844
930
  function isNativeToolProgressNotification(notification) {
845
931
  if (notification.method !== "item/started" && notification.method !== "item/completed" && notification.method !== "item/updated") return false;
846
932
  if (!isJsonObject(notification.params)) return false;
@@ -853,17 +939,21 @@ function isNativeToolProgressNotification(notification) {
853
939
  default: return false;
854
940
  }
855
941
  }
942
+ /** Returns true for raw native response stream delta events. */
856
943
  function isNativeResponseStreamDeltaNotification(notification) {
857
944
  return notification.method.startsWith("response.") && notification.method.endsWith(".delta");
858
945
  }
946
+ /** Returns true for file-change patch update notifications. */
859
947
  function isFileChangePatchUpdatedNotification(notification) {
860
948
  return notification.method === "item/fileChange/patchUpdated" && isJsonObject(notification.params);
861
949
  }
950
+ /** Returns true for raw assistant message progress with readable text. */
862
951
  function isRawAssistantProgressNotification(notification) {
863
952
  if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
864
953
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
865
954
  return Boolean(item && readString$6(item, "type") === "message" && readString$6(item, "role") === "assistant" && readRawAssistantTextPreview(item));
866
955
  }
956
+ /** Returns true for raw assistant completion outside commentary phase. */
867
957
  function isRawAssistantCompletionNotification(notification) {
868
958
  if (!isRawAssistantProgressNotification(notification) || !isJsonObject(notification.params)) return false;
869
959
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
@@ -879,34 +969,45 @@ function readRawAssistantTextPreview(item) {
879
969
  if (!text) return;
880
970
  return text.length > 240 ? `${text.slice(0, 237)}...` : text;
881
971
  }
972
+ /** Returns true when notification params correlate to a specific thread/turn. */
882
973
  function isTurnNotification(value, threadId, turnId) {
883
974
  return isCodexNotificationForTurn(value, threadId, turnId);
884
975
  }
976
+ /** Returns true when a correlated notification belongs to another active run. */
885
977
  function isCodexNotificationOutsideActiveRun(correlation) {
886
978
  if (!Boolean(correlation.threadId || correlation.nestedTurnThreadId)) return false;
887
979
  if (!correlation.matchesActiveThread) return true;
888
980
  return Boolean(correlation.turnId || correlation.nestedTurnId) && correlation.matchesActiveTurn === false;
889
981
  }
982
+ /** Checks request params that must contain the current thread and turn ids. */
890
983
  function isCurrentThreadTurnRequestParams(value, threadId, turnId) {
891
984
  if (!isJsonObject(value)) return false;
892
985
  return readString$6(value, "threadId") === threadId && readString$6(value, "turnId") === turnId;
893
986
  }
987
+ /** Checks approval request params, accepting `conversationId` as thread id. */
894
988
  function isCurrentApprovalTurnRequestParams(value, threadId, turnId) {
895
989
  if (!isJsonObject(value)) return false;
896
990
  return (readString$6(value, "threadId") ?? readString$6(value, "conversationId")) === threadId && readString$6(value, "turnId") === turnId;
897
991
  }
992
+ /** Checks request params where `turnId` may be omitted or null for the thread. */
898
993
  function isCurrentThreadOptionalTurnRequestParams(value, threadId, turnId) {
899
994
  if (!isJsonObject(value) || readString$6(value, "threadId") !== threadId) return false;
900
995
  const requestTurnId = value.turnId;
901
996
  return requestTurnId === null || requestTurnId === void 0 || requestTurnId === turnId;
902
997
  }
998
+ /** Returns true for app-server error notifications that will retry. */
903
999
  function isRetryableErrorNotification(value) {
904
1000
  if (!isJsonObject(value)) return false;
905
1001
  return readBoolean$1(value, "willRetry") === true || readBoolean$1(value, "will_retry") === true;
906
1002
  }
1003
+ /** Returns true for terminal app-server thread status strings. */
907
1004
  function isTerminalTurnStatus(status) {
908
1005
  return status === "completed" || status === "interrupted" || status === "failed";
909
1006
  }
1007
+ /**
1008
+ * Detects Codex's synthetic interrupted-turn marker while ignoring the current
1009
+ * user prompt echoed through raw response events.
1010
+ */
910
1011
  function isCodexTurnAbortMarkerNotification(notification, options = {}) {
911
1012
  if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
912
1013
  const item = notification.params.item;
@@ -940,11 +1041,13 @@ function readString$6(record, key) {
940
1041
  function readBoolean$1(record, key) {
941
1042
  return asBoolean(record[key]);
942
1043
  }
1044
+ /** Reads a typed Codex item from notification params when id/type are present. */
943
1045
  function readCodexNotificationItem(params) {
944
1046
  if (!isJsonObject(params) || !isJsonObject(params.item)) return;
945
1047
  const item = params.item;
946
1048
  return typeof item.id === "string" && typeof item.type === "string" ? item : void 0;
947
1049
  }
1050
+ /** Maps Codex item types to the tool name shown in execution progress. */
948
1051
  function codexExecutionToolName(item) {
949
1052
  if (item.type === "dynamicToolCall" && typeof item.tool === "string") return item.tool;
950
1053
  if (item.type === "mcpToolCall" && typeof item.tool === "string") {
@@ -960,6 +1063,10 @@ function isNonEmptyString$1(value) {
960
1063
  }
961
1064
  //#endregion
962
1065
  //#region extensions/codex/src/app-server/attempt-notification-state.ts
1066
+ /**
1067
+ * State machine for Codex app-server turn notifications and idle-watch updates.
1068
+ */
1069
+ /** Emits coarse execution phases exactly once from app-server notifications. */
963
1070
  function reportCodexExecutionNotification(params) {
964
1071
  const { notification } = params;
965
1072
  if (notification.method === "turn/started") {
@@ -980,10 +1087,15 @@ function reportCodexExecutionNotification(params) {
980
1087
  itemId: item.id
981
1088
  });
982
1089
  }
1090
+ /** Returns true when a notification ends the current app-server turn. */
983
1091
  function isTerminalCodexTurnNotificationForTurn(params) {
984
1092
  if (!isTurnNotification(params.notification.params, params.threadId, params.turnId)) return false;
985
1093
  return params.notification.method === "turn/completed" || isCodexTurnAbortMarkerNotification(params.notification, { currentPromptTexts: params.currentPromptTexts });
986
1094
  }
1095
+ /**
1096
+ * Applies one notification to active item tracking, idle watches, and terminal
1097
+ * turn state.
1098
+ */
987
1099
  function applyCodexTurnNotificationState(params) {
988
1100
  const { notification, turnWatches } = params;
989
1101
  const isCurrentTurnNotification = isTurnNotification(notification.params, params.threadId, params.turnId);
@@ -1058,30 +1170,34 @@ function applyCodexTurnNotificationState(params) {
1058
1170
  //#region extensions/codex/src/app-server/attempt-results.ts
1059
1171
  const CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_USER_MESSAGE = "Codex stopped before confirming the turn was complete. The response may be incomplete; retry if needed.";
1060
1172
  const CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_SIDE_EFFECT_USER_MESSAGE = "Codex stopped before confirming the turn was complete. Some work may already have been performed; verify the current state before retrying.";
1173
+ /** Joins terminal assistant text blocks into the final attempt answer. */
1061
1174
  function collectTerminalAssistantText(result) {
1062
1175
  return result.assistantTexts.join("\n\n").trim();
1063
1176
  }
1064
- function hasCodexAppServerPotentialSideEffectEvidence(result) {
1065
- return result.replayMetadata.hadPotentialSideEffects;
1066
- }
1177
+ /**
1178
+ * Builds the user-facing timeout outcome when Codex stops without a terminal
1179
+ * turn event.
1180
+ */
1067
1181
  function buildCodexAppServerPromptTimeoutOutcome(params) {
1068
- const completionIdleTimeoutHadPotentialSideEffects = hasCodexAppServerPotentialSideEffectEvidence(params.result);
1182
+ if (!params.turnCompletionIdleTimedOut) return;
1183
+ if (params.turnWatchTimeoutKind !== void 0 && params.turnWatchTimeoutKind !== "completion") return;
1069
1184
  const replayBlockedReason = resolveCodexAppServerReplayBlockedReason(params.result);
1070
- if (!params.turnCompletionIdleTimedOut || params.result.itemLifecycle.completedCount === 0 && !completionIdleTimeoutHadPotentialSideEffects && replayBlockedReason === void 0) return;
1071
1185
  return {
1072
- message: completionIdleTimeoutHadPotentialSideEffects ? CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_SIDE_EFFECT_USER_MESSAGE : CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_USER_MESSAGE,
1073
- ...completionIdleTimeoutHadPotentialSideEffects ? {
1186
+ message: replayBlockedReason === "tool_activity" || replayBlockedReason === "potential_side_effect" || replayBlockedReason === "active_item" ? CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_SIDE_EFFECT_USER_MESSAGE : CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_USER_MESSAGE,
1187
+ ...replayBlockedReason ? {
1074
1188
  replayInvalid: true,
1075
1189
  livenessState: "abandoned"
1076
1190
  } : {}
1077
1191
  };
1078
1192
  }
1193
+ /** Explains why an incomplete app-server turn cannot be safely replayed. */
1079
1194
  function resolveCodexAppServerReplayBlockedReason(result) {
1080
1195
  if (result.replayMetadata.hadPotentialSideEffects) return "potential_side_effect";
1081
1196
  if (result.assistantTexts.some((text) => text.trim().length > 0)) return "assistant_output";
1082
1197
  if (result.toolMetas.length > 0 || result.clientToolCalls || result.lastToolError || result.didSendDeterministicApprovalPrompt) return "tool_activity";
1083
1198
  if (result.itemLifecycle.startedCount > 0 || result.itemLifecycle.activeCount > 0) return "active_item";
1084
1199
  }
1200
+ /** Builds an attempt result for failures before the app-server turn starts. */
1085
1201
  function buildCodexTurnStartFailureResult(params) {
1086
1202
  return {
1087
1203
  aborted: false,
@@ -1115,6 +1231,7 @@ function buildCodexTurnStartFailureResult(params) {
1115
1231
  systemPromptReport: params.systemPromptReport
1116
1232
  };
1117
1233
  }
1234
+ /** Detects app-server errors caused by invalid image payload data. */
1118
1235
  function isInvalidCodexImagePayloadError(message) {
1119
1236
  if (typeof message !== "string" || !message.trim()) return false;
1120
1237
  const normalizedMessage = message.replace(/[_-]+/gu, " ");
@@ -1122,6 +1239,11 @@ function isInvalidCodexImagePayloadError(message) {
1122
1239
  }
1123
1240
  //#endregion
1124
1241
  //#region extensions/codex/src/app-server/dynamic-tool-build.ts
1242
+ /**
1243
+ * Builds the Codex app-server dynamic tool list for one turn, including
1244
+ * OpenClaw-owned tools, Codex native-tool fallback rules, sandbox shell shims,
1245
+ * and provider allowlist normalization.
1246
+ */
1125
1247
  const CODEX_NATIVE_SANDBOX_TOOL_REQUIREMENTS = [
1126
1248
  "exec",
1127
1249
  "process",
@@ -1131,12 +1253,14 @@ const CODEX_NATIVE_SANDBOX_TOOL_REQUIREMENTS = [
1131
1253
  "apply_patch"
1132
1254
  ];
1133
1255
  const CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW = new Set(["read", "write"]);
1256
+ /** Splits sandbox and run session keys so tool calls can bind to both scopes when needed. */
1134
1257
  function resolveOpenClawCodingToolsSessionKeys(params, sandboxSessionKey) {
1135
1258
  return {
1136
1259
  sessionKey: sandboxSessionKey,
1137
1260
  runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0
1138
1261
  };
1139
1262
  }
1263
+ /** Resolves the channel id that hook events should target for this Codex app-server turn. */
1140
1264
  function resolveCodexAppServerHookChannelId(params, sandboxSessionKey) {
1141
1265
  return buildAgentHookContextChannelFields({
1142
1266
  sessionKey: sandboxSessionKey,
@@ -1148,6 +1272,7 @@ function resolveCodexAppServerHookChannelId(params, sandboxSessionKey) {
1148
1272
  }
1149
1273
  const CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS = 1e3;
1150
1274
  const CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS = 500;
1275
+ /** Creates cheap optional timing instrumentation for the dynamic-tool hot path. */
1151
1276
  function createCodexDynamicToolBuildStageTracker(options = {}) {
1152
1277
  if (!options.enabled) return {
1153
1278
  mark() {},
@@ -1180,12 +1305,15 @@ function createCodexDynamicToolBuildStageTracker(options = {}) {
1180
1305
  }
1181
1306
  };
1182
1307
  }
1308
+ /** Returns true when dynamic-tool construction is slow enough to warrant a warning log. */
1183
1309
  function shouldWarnCodexDynamicToolBuildStageSummary(summary) {
1184
1310
  return summary.totalMs >= CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS || summary.stages.some((stage) => stage.durationMs >= CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS);
1185
1311
  }
1312
+ /** Formats per-stage timings into the compact form used by Codex app-server logs. */
1186
1313
  function formatCodexDynamicToolBuildStageSummary(summary) {
1187
1314
  return summary.stages.length > 0 ? summary.stages.map((stage) => `${stage.name}:${stage.durationMs}ms@${stage.elapsedMs}ms`).join(",") : "none";
1188
1315
  }
1316
+ /** Builds, filters, and normalizes Codex-compatible runtime tools for a single turn. */
1189
1317
  async function buildDynamicTools(input) {
1190
1318
  const { params } = input;
1191
1319
  if (params.disableTools || !supportsModelTools(params.model)) return [];
@@ -1323,6 +1451,7 @@ async function buildDynamicTools(input) {
1323
1451
  }
1324
1452
  return normalizedTools;
1325
1453
  }
1454
+ /** Preserves delivery-critical tools when a narrow allowlist would otherwise hide them. */
1326
1455
  function includeForcedCodexDynamicToolAllow(toolsAllow, params) {
1327
1456
  if (toolsAllow === void 0 || hasWildcardCodexToolsAllow(toolsAllow)) return toolsAllow;
1328
1457
  const forcedToolNames = shouldForceMessageTool(params) ? ["message"] : [];
@@ -1332,6 +1461,7 @@ function includeForcedCodexDynamicToolAllow(toolsAllow, params) {
1332
1461
  const missingToolNames = forcedToolNames.filter((toolName) => !normalized.has(normalizeCodexDynamicToolName$1(toolName)));
1333
1462
  return missingToolNames.length === 0 ? toolsAllow : [...toolsAllow, ...missingToolNames];
1334
1463
  }
1464
+ /** Decides whether Codex native code mode can own shell/file tools for this turn. */
1335
1465
  function shouldEnableCodexAppServerNativeToolSurface(params, sandbox, options = {}) {
1336
1466
  if (isCodexMemoryFlushRun(params)) return false;
1337
1467
  if (isCodexNativeExecutionBlockedByNodeExecHost(params, {
@@ -1343,6 +1473,7 @@ function shouldEnableCodexAppServerNativeToolSurface(params, sandbox, options =
1343
1473
  if (toolsAllow === void 0) return canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
1344
1474
  return hasWildcardCodexToolsAllow(toolsAllow) && canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
1345
1475
  }
1476
+ /** Returns true when OpenClaw policy requires the Node-owned exec/process tools instead. */
1346
1477
  function isCodexNativeExecutionBlockedByNodeExecHost(params, options = {}) {
1347
1478
  return !resolveCodexNativeExecutionPolicy({
1348
1479
  config: params.config,
@@ -1371,15 +1502,19 @@ function isCodexMemoryFlushRun(params) {
1371
1502
  function filterCodexMemoryFlushDynamicTools(tools) {
1372
1503
  return tools.filter((tool) => CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW.has(normalizeCodexDynamicToolName$1(tool.name)));
1373
1504
  }
1505
+ /** Requires a Codex sandbox environment only when native tools must run inside OpenClaw sandboxing. */
1374
1506
  function shouldRequireCodexSandboxExecServerEnvironment(params) {
1375
1507
  return Boolean(params.sandbox?.enabled && params.nativeToolSurfaceEnabled && params.sandboxExecServerEnabled);
1376
1508
  }
1509
+ /** Selects the sandbox exec-server environment passed through the Codex app-server protocol. */
1377
1510
  function resolveCodexSandboxEnvironmentSelection(environment, nativeToolSurfaceEnabled) {
1378
1511
  return environment && nativeToolSurfaceEnabled ? [environment] : void 0;
1379
1512
  }
1513
+ /** Chooses the cwd visible to Codex native execution after sandbox exec-server setup. */
1380
1514
  function resolveCodexAppServerExecutionCwd(params) {
1381
1515
  return params.environment && params.nativeToolSurfaceEnabled ? params.environment.cwd : params.effectiveCwd;
1382
1516
  }
1517
+ /** Converts OpenClaw sandbox networking into Codex's external-sandbox policy shape. */
1383
1518
  function resolveCodexExternalSandboxPolicyForOpenClawSandbox(sandbox) {
1384
1519
  return {
1385
1520
  type: "externalSandbox",
@@ -1391,6 +1526,7 @@ function codexNetworkAccessForOpenClawSandbox(sandbox) {
1391
1526
  const network = sandbox?.docker?.network?.trim().toLowerCase();
1392
1527
  return Boolean(network && network !== "none");
1393
1528
  }
1529
+ /** Returns a Codex config copy with app-server Codex plugin loading disabled for thread tools. */
1394
1530
  function disableCodexPluginThreadConfig(pluginConfig) {
1395
1531
  const config = readCodexPluginConfig(pluginConfig);
1396
1532
  return {
@@ -1401,6 +1537,7 @@ function disableCodexPluginThreadConfig(pluginConfig) {
1401
1537
  }
1402
1538
  };
1403
1539
  }
1540
+ /** Adds sandbox_exec/process aliases when native Code Mode cannot directly honor the sandbox. */
1404
1541
  function addSandboxShellDynamicToolsIfAvailable(filteredTools, allTools, input) {
1405
1542
  if (!shouldExposeSandboxExecDynamicTool(input) || isSandboxShellDynamicToolExcluded(input.pluginConfig)) return filteredTools;
1406
1543
  const execTool = allTools.find((tool) => normalizeCodexDynamicToolName$1(tool.name) === "exec");
@@ -1471,6 +1608,7 @@ function addNodeShellDynamicToolsIfNeeded(filteredTools, allTools, input) {
1471
1608
  }
1472
1609
  return next;
1473
1610
  }
1611
+ /** Applies a normalized tool allowlist while preserving sandbox shell aliases for exec/process. */
1474
1612
  function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
1475
1613
  if (!toolsAllow) return tools;
1476
1614
  if (toolsAllow.length === 0) return [];
@@ -1481,46 +1619,57 @@ function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
1481
1619
  return allowSet.has(normalized) || normalized === "sandbox_exec" && allowSet.has("exec") || normalized === "sandbox_process" && (allowSet.has("exec") || allowSet.has("process"));
1482
1620
  });
1483
1621
  }
1622
+ /** Detects the wildcard allowlist marker after Codex tool-name normalization. */
1484
1623
  function hasWildcardCodexToolsAllow(toolsAllow) {
1485
1624
  return toolsAllow.some((name) => normalizeCodexDynamicToolName$1(name) === "*");
1486
1625
  }
1626
+ /** Forces message delivery through the message tool when the source channel requires it. */
1487
1627
  function shouldForceMessageTool(params) {
1488
1628
  return params.disableMessageTool !== true && params.sourceReplyDeliveryMode === "message_tool_only";
1489
1629
  }
1490
1630
  //#endregion
1491
1631
  //#region extensions/codex/src/app-server/sandbox-exec-server/json-rpc.ts
1632
+ /** JSON-RPC error code used when a sandbox exec-server method is unknown. */
1492
1633
  const JSON_RPC_NOT_FOUND = -32004;
1634
+ /** Protocol-level error carrying the JSON-RPC error code to send to the client. */
1493
1635
  var JsonRpcProtocolError = class extends Error {
1494
1636
  constructor(code, message) {
1495
1637
  super(message);
1496
1638
  this.code = code;
1497
1639
  }
1498
1640
  };
1641
+ /** Parses raw WebSocket data into a JSON-RPC request object. */
1499
1642
  function parseRequest(data) {
1500
1643
  const text = (Array.isArray(data) ? Buffer.concat(data) : Buffer.isBuffer(data) ? data : Buffer.from(data)).toString("utf8");
1501
1644
  return requireObject(JSON.parse(text), "JSON-RPC request");
1502
1645
  }
1646
+ /** Validates that a JSON value is a non-array object. */
1503
1647
  function requireObject(value, label) {
1504
1648
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object.`);
1505
1649
  return value;
1506
1650
  }
1651
+ /** Validates a non-empty string JSON-RPC parameter. */
1507
1652
  function requireString(value, label) {
1508
1653
  if (typeof value !== "string" || !value) throw new Error(`${label} must be a non-empty string.`);
1509
1654
  return value;
1510
1655
  }
1656
+ /** Validates a base64 payload parameter as a string; decoding happens at call sites. */
1511
1657
  function requireBase64String(value, label) {
1512
1658
  if (typeof value !== "string") throw new Error(`${label} must be a string.`);
1513
1659
  return value;
1514
1660
  }
1661
+ /** Validates a finite numeric JSON-RPC parameter. */
1515
1662
  function requireNumber(value, label) {
1516
1663
  if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`${label} must be a finite number.`);
1517
1664
  return value;
1518
1665
  }
1666
+ /** Validates a non-empty string-array JSON-RPC parameter. */
1519
1667
  function requireStringArray(value, label) {
1520
1668
  if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) throw new Error(`${label} must be a string array.`);
1521
1669
  if (value.length === 0) throw new Error(`${label} must not be empty.`);
1522
1670
  return value;
1523
1671
  }
1672
+ /** Reads HTTP headers from JSON-RPC params, defaulting to an empty header list. */
1524
1673
  function readHttpHeaders(value) {
1525
1674
  if (!Array.isArray(value)) return [];
1526
1675
  return value.map((entry, index) => {
@@ -1531,6 +1680,7 @@ function readHttpHeaders(value) {
1531
1680
  };
1532
1681
  });
1533
1682
  }
1683
+ /** Sends a JSON-RPC success response over the WebSocket. */
1534
1684
  function sendResult(socket, id, result) {
1535
1685
  socket.send(JSON.stringify({
1536
1686
  jsonrpc: "2.0",
@@ -1538,6 +1688,7 @@ function sendResult(socket, id, result) {
1538
1688
  result: result === void 0 ? {} : result
1539
1689
  }));
1540
1690
  }
1691
+ /** Sends a JSON-RPC error response over the WebSocket. */
1541
1692
  function sendError(socket, id, code, message) {
1542
1693
  socket.send(JSON.stringify({
1543
1694
  jsonrpc: "2.0",
@@ -1550,9 +1701,15 @@ function sendError(socket, id, code, message) {
1550
1701
  }
1551
1702
  //#endregion
1552
1703
  //#region extensions/codex/src/app-server/sandbox-exec-server/fs-policy.ts
1704
+ /**
1705
+ * Resolves Codex filesystem sandbox policy payloads into OpenClaw path/glob
1706
+ * checks for sandbox exec-server filesystem operations.
1707
+ */
1708
+ /** Resolves request-local sandbox policy and asserts each requested path has the needed access. */
1553
1709
  function assertFsSandboxAccess(execServer, record, requests) {
1554
1710
  assertResolvedFsSandboxAccess(resolveFsSandboxPolicy(execServer, record), requests);
1555
1711
  }
1712
+ /** Parses a Codex managed filesystem sandbox context into normalized access entries. */
1556
1713
  function resolveFsSandboxPolicy(execServer, record) {
1557
1714
  if (record.sandbox === void 0 || record.sandbox === null) return;
1558
1715
  const sandbox = requireObject(record.sandbox, "fs sandbox context");
@@ -1633,6 +1790,7 @@ function resolveFsSpecialPath(value, cwd) {
1633
1790
  if (kind === "slash_tmp" || kind === "tmpdir") return "/tmp";
1634
1791
  throw new Error(`Unsupported Codex fs sandbox special path: ${kind}`);
1635
1792
  }
1793
+ /** Asserts access against an already resolved filesystem sandbox policy. */
1636
1794
  function assertResolvedFsSandboxAccess(policy, requests) {
1637
1795
  if (!policy?.unrestricted && policy) for (const request of requests) {
1638
1796
  const access = resolveFsAccess(policy, request.path);
@@ -1655,6 +1813,7 @@ function resolveFsAccess(policy, rawPath) {
1655
1813
  }
1656
1814
  return selected?.access ?? "none";
1657
1815
  }
1816
+ /** Rejects recursive writes/removes that would cross protected read-only descendants. */
1658
1817
  function assertNoReadOnlyDescendant(policy, rawPath, operation) {
1659
1818
  if (!policy || policy.unrestricted) return;
1660
1819
  const target = normalizeSandboxAbsolutePath(rawPath, "fs path");
@@ -1669,11 +1828,13 @@ function assertNoReadOnlyDescendant(policy, rawPath, operation) {
1669
1828
  throw new Error(`Codex fs sandbox denied recursive ${operation} of ${rawPath} because ${protectedPath} is not writable.`);
1670
1829
  }
1671
1830
  }
1831
+ /** Normalizes and validates an absolute POSIX path inside the sandbox namespace. */
1672
1832
  function normalizeSandboxAbsolutePath(rawPath, label) {
1673
1833
  if (!rawPath || rawPath.includes("\0") || !rawPath.startsWith("/")) throw new Error(`${label} must be an absolute sandbox path.`);
1674
1834
  const normalized = posix.normalize(rawPath);
1675
1835
  return normalized === "//" ? "/" : normalized;
1676
1836
  }
1837
+ /** Returns true when target is root itself or a descendant of root. */
1677
1838
  function pathContains(root, target) {
1678
1839
  return root === "/" || target === root || target.startsWith(`${root}/`);
1679
1840
  }
@@ -1751,17 +1912,20 @@ function sandboxGlobLiteralPrefix(pattern) {
1751
1912
  if (slash <= 0) return "/";
1752
1913
  return normalizeSandboxAbsolutePath(prefix.slice(0, slash), "fs sandbox glob prefix");
1753
1914
  }
1915
+ /** Safely joins a single directory entry name onto a sandbox parent path. */
1754
1916
  function joinSandboxChildPath(parent, child) {
1755
1917
  if (!child || child === "." || child === ".." || child.includes("/") || child.includes("\0")) throw new Error(`Invalid sandbox directory entry name: ${child}`);
1756
1918
  return parent.endsWith("/") ? `${parent}${child}` : `${parent}/${child}`;
1757
1919
  }
1758
1920
  //#endregion
1759
1921
  //#region extensions/codex/src/app-server/sandbox-exec-server/runtime.ts
1922
+ /** Returns the configured sandbox backend or fails the current JSON-RPC request. */
1760
1923
  function requireBackend(execServer) {
1761
1924
  const backend = execServer.sandbox.backend;
1762
1925
  if (!backend) throw new Error("OpenClaw sandbox backend is unavailable.");
1763
1926
  return backend;
1764
1927
  }
1928
+ /** Returns the configured filesystem bridge or fails the current JSON-RPC request. */
1765
1929
  function requireFsBridge(execServer) {
1766
1930
  const fsBridge = execServer.sandbox.fsBridge;
1767
1931
  if (!fsBridge) throw new Error("Sandbox filesystem bridge is unavailable.");
@@ -1769,7 +1933,12 @@ function requireFsBridge(execServer) {
1769
1933
  }
1770
1934
  //#endregion
1771
1935
  //#region extensions/codex/src/app-server/sandbox-exec-server/filesystem.ts
1936
+ /**
1937
+ * Implements filesystem JSON-RPC handlers for the Codex sandbox exec-server
1938
+ * with OpenClaw sandbox policy checks before every bridge operation.
1939
+ */
1772
1940
  const CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES = 512 * 1024 * 1024;
1941
+ /** Reads a sandbox file as base64 after read-policy and size checks. */
1773
1942
  async function readFile(execServer, params) {
1774
1943
  const record = requireObject(params, "fs/readFile params");
1775
1944
  const filePath = requireString(record.path, "path");
@@ -1783,6 +1952,7 @@ async function readFile(execServer, params) {
1783
1952
  if (stat.type === "file" && stat.size > CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES) throw new Error(`file is too large to read through Codex sandbox exec-server: ${stat.size} bytes`);
1784
1953
  return { dataBase64: (await fsBridge.readFile({ filePath })).toString("base64") };
1785
1954
  }
1955
+ /** Writes base64 data to an existing sandbox directory after write-policy checks. */
1786
1956
  async function writeFile(execServer, params) {
1787
1957
  const record = requireObject(params, "fs/writeFile params");
1788
1958
  const filePath = requireString(record.path, "path");
@@ -1798,6 +1968,7 @@ async function writeFile(execServer, params) {
1798
1968
  mkdir: false
1799
1969
  });
1800
1970
  }
1971
+ /** Creates a sandbox directory, respecting recursive and parent-directory semantics. */
1801
1972
  async function createDirectory(execServer, params) {
1802
1973
  const record = requireObject(params, "fs/createDirectory params");
1803
1974
  const filePath = requireString(record.path, "path");
@@ -1812,6 +1983,7 @@ async function createDirectory(execServer, params) {
1812
1983
  }
1813
1984
  await fsBridge.mkdirp({ filePath });
1814
1985
  }
1986
+ /** Returns normalized metadata for a sandbox path. */
1815
1987
  async function getMetadata(execServer, params) {
1816
1988
  const record = requireObject(params, "fs/getMetadata params");
1817
1989
  const filePath = requireString(record.path, "path");
@@ -1823,6 +1995,7 @@ async function getMetadata(execServer, params) {
1823
1995
  if (!stat) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, "file not found");
1824
1996
  return metadataResponse(stat);
1825
1997
  }
1998
+ /** Lists sandbox directory entries visible under the resolved filesystem policy. */
1826
1999
  async function readDirectory(execServer, params) {
1827
2000
  const record = requireObject(params, "fs/readDirectory params");
1828
2001
  return { entries: await listDirectoryEntries(execServer, requireString(record.path, "path"), resolveFsSandboxPolicy(execServer, record)) };
@@ -1854,6 +2027,7 @@ async function listDirectoryEntries(execServer, filePath, fsSandboxPolicy) {
1854
2027
  };
1855
2028
  });
1856
2029
  }
2030
+ /** Removes a sandbox path after rejecting writes outside policy or under read-only descendants. */
1857
2031
  async function removePath(execServer, params) {
1858
2032
  const record = requireObject(params, "fs/remove params");
1859
2033
  const filePath = requireString(record.path, "path");
@@ -1869,6 +2043,7 @@ async function removePath(execServer, params) {
1869
2043
  force: record.force !== false
1870
2044
  });
1871
2045
  }
2046
+ /** Copies sandbox files or recursive directories while enforcing source and destination policy. */
1872
2047
  async function copyPath(execServer, params) {
1873
2048
  const record = requireObject(params, "fs/copy params");
1874
2049
  const sourcePath = requireString(record.sourcePath ?? record.source, "sourcePath");
@@ -1933,7 +2108,13 @@ function metadataResponse(stat) {
1933
2108
  }
1934
2109
  //#endregion
1935
2110
  //#region extensions/codex/src/app-server/sandbox-exec-server/http.ts
2111
+ /**
2112
+ * Implements sandboxed HTTP requests for Codex native tools by routing network
2113
+ * access through the active OpenClaw sandbox backend.
2114
+ */
2115
+ /** Maximum JSON-line size accepted from the streaming HTTP helper process. */
1936
2116
  const SANDBOX_HTTP_STREAM_LINE_MAX_CHARS = 256 * 1024;
2117
+ /** Handles one sandbox HTTP JSON-RPC request, optionally streaming response body deltas. */
1937
2118
  async function httpRequest(execServer, socket, params) {
1938
2119
  const record = requireObject(params, "http/request params");
1939
2120
  const requestId = requireString(record.requestId, "requestId");
@@ -2182,9 +2363,14 @@ function sendHttpBodyDelta(socket, params) {
2182
2363
  }
2183
2364
  //#endregion
2184
2365
  //#region extensions/codex/src/app-server/sandbox-exec-server/processes.ts
2366
+ /**
2367
+ * Manages subprocess lifecycle, streaming output buffers, stdin writes, and
2368
+ * termination for Codex sandbox exec-server process RPCs.
2369
+ */
2185
2370
  const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
2186
2371
  const RETAINED_PROCESS_OUTPUT_BYTES = 1024 * 1024;
2187
2372
  const CLOSED_PROCESS_EVICTION_MS = 6e4;
2373
+ /** Starts a sandbox-backed process and registers it in the connection-local process table. */
2188
2374
  async function startProcess(execServer, processes, socket, params) {
2189
2375
  const record = requireObject(params, "process/start params");
2190
2376
  const processId = requireString(record.processId, "processId");
@@ -2365,6 +2551,7 @@ function limitProcessChunks(chunks, maxBytes) {
2365
2551
  }
2366
2552
  return retained;
2367
2553
  }
2554
+ /** Reads buffered process output, optionally waiting for new output or process close. */
2368
2555
  async function readProcess(processes, params) {
2369
2556
  const record = requireObject(params, "process/read params");
2370
2557
  const managed = requireProcess(processes, requireString(record.processId, "processId"));
@@ -2382,6 +2569,7 @@ async function readProcess(processes, params) {
2382
2569
  failure: managed.failure
2383
2570
  };
2384
2571
  }
2572
+ /** Writes base64 stdin data to a running process when stdin is still open. */
2385
2573
  function writeProcess(processes, params) {
2386
2574
  const record = requireObject(params, "process/write params");
2387
2575
  const processId = requireString(record.processId, "processId");
@@ -2392,6 +2580,7 @@ function writeProcess(processes, params) {
2392
2580
  managed.child.stdin.write(chunk);
2393
2581
  return { status: "accepted" };
2394
2582
  }
2583
+ /** Requests process termination and reports whether it was running at call time. */
2395
2584
  function terminateProcess(processes, params) {
2396
2585
  const processId = requireString(requireObject(params, "process/terminate params").processId, "processId");
2397
2586
  const managed = processes.get(processId);
@@ -2471,7 +2660,12 @@ function readStringList(value) {
2471
2660
  }
2472
2661
  //#endregion
2473
2662
  //#region extensions/codex/src/app-server/sandbox-exec-server.ts
2663
+ /**
2664
+ * Hosts the local OpenClaw sandbox exec-server that Codex app-server native
2665
+ * execution can register as an external environment.
2666
+ */
2474
2667
  const SANDBOX_EXEC_SERVERS = /* @__PURE__ */ new Map();
2668
+ /** Starts or reuses a sandbox exec-server and registers it with Codex app-server. */
2475
2669
  async function ensureCodexSandboxExecServerEnvironment(params) {
2476
2670
  if (!params.sandbox?.enabled || !params.sandbox.backend) return;
2477
2671
  if (!canExposeLocalExecServerToAppServer(params.appServerStartOptions)) throw new Error("OpenClaw Codex exec-server uses a local loopback URL and cannot be registered with a remote Codex app-server.");
@@ -2498,6 +2692,7 @@ async function ensureCodexSandboxExecServerEnvironment(params) {
2498
2692
  cwd: params.sandbox.containerWorkdir
2499
2693
  };
2500
2694
  }
2695
+ /** Releases the sandbox exec-server lease associated with a sandbox runtime. */
2501
2696
  async function releaseCodexSandboxExecServerEnvironment(sandbox) {
2502
2697
  if (!sandbox?.enabled) return;
2503
2698
  const server = await SANDBOX_EXEC_SERVERS.get(sandbox.runtimeId)?.catch(() => void 0);
@@ -2659,7 +2854,16 @@ async function dispatchRequest(execServer, processes, socket, request) {
2659
2854
  }
2660
2855
  //#endregion
2661
2856
  //#region extensions/codex/src/app-server/attempt-startup.ts
2857
+ /**
2858
+ * Startup orchestration for Codex app-server attempts, including shared-client
2859
+ * leasing, plugin thread config, sandbox execution environment, and thread
2860
+ * lifecycle binding.
2861
+ */
2662
2862
  const CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS = 3;
2863
+ /**
2864
+ * Starts or resumes the Codex app-server thread and returns the resources the
2865
+ * run loop must later release.
2866
+ */
2663
2867
  async function startCodexAttemptThread(params) {
2664
2868
  let pluginAppServer = params.appServer;
2665
2869
  let releaseSharedClientLease;
@@ -2984,7 +3188,15 @@ function shouldClearSharedClientAfterStartupFailure(params) {
2984
3188
  }
2985
3189
  //#endregion
2986
3190
  //#region extensions/codex/src/app-server/attempt-steering.ts
3191
+ /**
3192
+ * Debounced steering queue for forwarding user text to an active Codex
3193
+ * app-server turn.
3194
+ */
2987
3195
  const CODEX_STEER_ALL_DEBOUNCE_MS = 500;
3196
+ /**
3197
+ * Creates a queue that batches steer text while still serializing app-server
3198
+ * `turn/steer` requests.
3199
+ */
2988
3200
  function createCodexSteeringQueue(params) {
2989
3201
  let batchedTexts = [];
2990
3202
  let batchTimer;
@@ -3055,9 +3267,11 @@ function createCodexSteeringQueue(params) {
3055
3267
  }
3056
3268
  };
3057
3269
  }
3270
+ /** Normalizes steer debounce milliseconds, preserving explicit zero. */
3058
3271
  function normalizeCodexSteerDebounceMs(value) {
3059
3272
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : CODEX_STEER_ALL_DEBOUNCE_MS;
3060
3273
  }
3274
+ /** Converts plain text into the Codex app-server user-input shape. */
3061
3275
  function toCodexTextInput(text) {
3062
3276
  return {
3063
3277
  type: "text",
@@ -3067,6 +3281,14 @@ function toCodexTextInput(text) {
3067
3281
  }
3068
3282
  //#endregion
3069
3283
  //#region extensions/codex/src/app-server/attempt-turn-watches.ts
3284
+ /**
3285
+ * Idle-watch controller for Codex app-server turn progress, completion, and
3286
+ * terminal-event gaps.
3287
+ */
3288
+ /**
3289
+ * Creates a controller that arms/disarms timers as Codex app-server
3290
+ * notifications and tool handoffs progress.
3291
+ */
3070
3292
  function createCodexAttemptTurnWatchController(params) {
3071
3293
  let completionIdleTimer;
3072
3294
  let completionIdleWatchArmed = false;
@@ -3258,12 +3480,21 @@ function createCodexAttemptTurnWatchController(params) {
3258
3480
  scheduleCompletionIdleWatch();
3259
3481
  return;
3260
3482
  }
3483
+ const details = {
3484
+ ...completionLastActivityDetails,
3485
+ activeAppServerTurnRequests: params.getActiveAppServerTurnRequests(),
3486
+ activeTurnItemCount: params.getActiveTurnItemCount(),
3487
+ terminalTurnNotificationQueued: params.isTerminalTurnNotificationQueued(),
3488
+ completionIdleWatchArmed,
3489
+ assistantCompletionIdleWatchArmed,
3490
+ terminalIdleWatchArmed
3491
+ };
3261
3492
  const timeout = {
3262
3493
  kind: "completion",
3263
3494
  idleMs,
3264
3495
  timeoutMs,
3265
3496
  lastActivityReason: completionLastActivityReason,
3266
- details: completionLastActivityDetails
3497
+ details
3267
3498
  };
3268
3499
  params.onTimeout(timeout);
3269
3500
  params.onMarkTimedOut();
@@ -3385,8 +3616,10 @@ function createCodexAttemptTurnWatchController(params) {
3385
3616
  clearAllTimers
3386
3617
  };
3387
3618
  }
3619
+ /** Hard cap for per-call Codex dynamic tool timeout overrides. */
3388
3620
  const CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 6e5;
3389
3621
  const CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS = 12e4;
3622
+ /** Timeout for message-delivery dynamic tool calls. */
3390
3623
  const CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS = 12e4;
3391
3624
  const LOG_FIELD_MAX_LENGTH = 160;
3392
3625
  function normalizeLogField(value) {
@@ -3436,6 +3669,10 @@ function formatDynamicToolTimeoutDetails(params) {
3436
3669
  }
3437
3670
  };
3438
3671
  }
3672
+ /**
3673
+ * Runs a dynamic tool call with run-abort and per-call timeout handling,
3674
+ * returning a Codex protocol response instead of throwing.
3675
+ */
3439
3676
  async function handleDynamicToolCallWithTimeout(params) {
3440
3677
  if (params.signal.aborted) return failedDynamicToolResponse("OpenClaw dynamic tool call aborted before execution.");
3441
3678
  const controller = new AbortController();
@@ -3505,12 +3742,14 @@ function failedDynamicToolResponse(message, options) {
3505
3742
  });
3506
3743
  return response;
3507
3744
  }
3745
+ /** Strips OpenClaw-only metadata before sending a dynamic tool response to Codex. */
3508
3746
  function toCodexDynamicToolProtocolResponse(response) {
3509
3747
  return {
3510
3748
  contentItems: response.contentItems,
3511
3749
  success: response.success
3512
3750
  };
3513
3751
  }
3752
+ /** Adds async-started progress details when a tool result continues out of band. */
3514
3753
  function toCodexDynamicToolProgressResponse(response, protocolResponse) {
3515
3754
  if (response.asyncStarted !== true) return protocolResponse;
3516
3755
  return {
@@ -3521,21 +3760,26 @@ function toCodexDynamicToolProgressResponse(response, protocolResponse) {
3521
3760
  }
3522
3761
  };
3523
3762
  }
3763
+ /** Decides whether a terminal dynamic tool response can release the Codex turn. */
3524
3764
  function shouldReleaseTurnAfterTerminalDynamicTool(state) {
3525
3765
  return !state.completed && !state.aborted && state.responseSuccess && !state.currentTurnHadNonTerminalDynamicToolResult && state.activeAppServerTurnRequests === 0 && state.activeTurnItemIdsCount === 0 && state.pendingOpenClawDynamicToolCompletionIdsCount === 0;
3526
3766
  }
3767
+ /** Returns true when a non-async result should block terminal-release shortcuts. */
3527
3768
  function shouldBlockTerminalReleaseForNonTerminalDynamicToolResult(response) {
3528
3769
  return response.asyncStarted !== true;
3529
3770
  }
3771
+ /** Resolves whether terminal diagnostic state should release, wait, or stay idle. */
3530
3772
  function resolveTerminalDynamicToolBatchAction(state) {
3531
3773
  if (state.activeAppServerTurnRequests > 0 || state.activeTurnItemIdsCount > 0 || state.pendingOpenClawDynamicToolCompletionIdsCount > 0) return "wait";
3532
3774
  if (state.currentTurnHadNonTerminalDynamicToolResult) return "clear-nonterminal-batch";
3533
3775
  if (state.hasPendingTerminalDynamicToolRelease) return "release-pending-terminal";
3534
3776
  return "idle";
3535
3777
  }
3778
+ /** Returns true for diagnostic events that terminate a dynamic tool call. */
3536
3779
  function isDynamicToolTerminalDiagnosticEvent(event) {
3537
3780
  return event.type === "tool.execution.completed" || event.type === "tool.execution.error" || event.type === "tool.execution.blocked";
3538
3781
  }
3782
+ /** Matches terminal diagnostics to a specific dynamic tool call id/name. */
3539
3783
  function isMatchingDynamicToolTerminalDiagnostic(params) {
3540
3784
  if (params.event.toolCallId !== params.call.callId || params.event.toolName !== params.call.tool) return false;
3541
3785
  if (params.runId !== void 0) return params.event.runId === params.runId;
@@ -3543,6 +3787,7 @@ function isMatchingDynamicToolTerminalDiagnostic(params) {
3543
3787
  if (params.sessionKey !== void 0) return params.event.sessionKey === params.sessionKey;
3544
3788
  return params.event.runId === void 0 && params.event.sessionId === void 0 && params.event.sessionKey === void 0;
3545
3789
  }
3790
+ /** Checks pending diagnostics for a terminal event matching a tool call. */
3546
3791
  function hasPendingDynamicToolTerminalDiagnostic(params) {
3547
3792
  return hasPendingInternalDiagnosticEvent((event) => {
3548
3793
  if (!isDynamicToolTerminalDiagnosticEvent(event)) return false;
@@ -3555,6 +3800,7 @@ function hasPendingDynamicToolTerminalDiagnostic(params) {
3555
3800
  });
3556
3801
  });
3557
3802
  }
3803
+ /** Resolves per-tool timeout, applying media/message defaults and hard caps. */
3558
3804
  function resolveDynamicToolCallTimeoutMs(params) {
3559
3805
  return clampDynamicToolTimeoutMs(readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? 9e4);
3560
3806
  }
@@ -3589,6 +3835,7 @@ const OPENAI_CODEX_RESPONSES_API = "openai-chatgpt-responses";
3589
3835
  function normalizeRuntimeId(value) {
3590
3836
  return value?.trim().toLowerCase() ?? "";
3591
3837
  }
3838
+ /** Maps local Codex runtime plans onto the provider/api pair exposed to event projection. */
3592
3839
  function resolveCodexLocalRuntimeAttribution(params) {
3593
3840
  const authProfileProvider = normalizeRuntimeId(params.runtimePlan?.auth?.authProfileProviderForAuth);
3594
3841
  if (normalizeRuntimeId(params.runtimePlan?.observability.harnessId) === "codex" && authProfileProvider !== OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.provider) === OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.api) === OPENAI_RESPONSES_API) return {
@@ -3602,9 +3849,15 @@ function resolveCodexLocalRuntimeAttribution(params) {
3602
3849
  }
3603
3850
  //#endregion
3604
3851
  //#region extensions/codex/src/app-server/tool-progress-normalization.ts
3852
+ /**
3853
+ * Normalizes and sanitizes Codex dynamic-tool progress payloads before they are
3854
+ * emitted into OpenClaw events or logs.
3855
+ */
3856
+ /** Maps OpenClaw tool-progress config to the mode used by Codex progress metadata. */
3605
3857
  function resolveCodexToolProgressDetailMode(value) {
3606
3858
  return value === "raw" ? "raw" : "explain";
3607
3859
  }
3860
+ /** Recursively redacts sensitive strings and handles circular values in event payloads. */
3608
3861
  function sanitizeCodexAgentEventValue(value, seen = /* @__PURE__ */ new WeakSet()) {
3609
3862
  if (typeof value === "string") return redactToolPayloadText(value);
3610
3863
  if (Array.isArray(value)) {
@@ -3621,16 +3874,20 @@ function sanitizeCodexAgentEventValue(value, seen = /* @__PURE__ */ new WeakSet(
3621
3874
  }
3622
3875
  return value;
3623
3876
  }
3877
+ /** Sanitizes a record-shaped Codex agent event payload. */
3624
3878
  function sanitizeCodexAgentEventRecord(value) {
3625
3879
  return sanitizeCodexAgentEventValue(value);
3626
3880
  }
3881
+ /** Sanitizes dynamic-tool arguments before diagnostic/event emission. */
3627
3882
  function sanitizeCodexToolArguments(value) {
3628
3883
  if (!isJsonObject(value)) return;
3629
3884
  return sanitizeCodexAgentEventRecord(value);
3630
3885
  }
3886
+ /** Sanitizes a Codex dynamic-tool response before diagnostic/event emission. */
3631
3887
  function sanitizeCodexToolResponse(response) {
3632
3888
  return sanitizeCodexAgentEventRecord(response);
3633
3889
  }
3890
+ /** Infers compact human-readable tool metadata from Codex dynamic-tool arguments. */
3634
3891
  function inferCodexDynamicToolMeta(call, detailMode) {
3635
3892
  return inferToolMetaFromArgs(call.tool, call.arguments, { detailMode });
3636
3893
  }
@@ -3994,6 +4251,10 @@ var CodexAppServerEventProjector = class {
3994
4251
  getCompletedTurnStatus() {
3995
4252
  return this.completedTurn?.status;
3996
4253
  }
4254
+ hasCompletedTerminalAssistantText() {
4255
+ const finalItem = this.resolveFinalAssistantTextItem();
4256
+ return finalItem !== void 0 && this.completedItemIds.has(finalItem.itemId);
4257
+ }
3997
4258
  async handleNotification(notification) {
3998
4259
  const params = isJsonObject(notification.params) ? notification.params : void 0;
3999
4260
  if (!params) return;
@@ -5023,12 +5284,18 @@ var CodexAppServerEventProjector = class {
5023
5284
  return finalText ? [finalText] : [];
5024
5285
  }
5025
5286
  resolveFinalAssistantText() {
5287
+ return this.resolveFinalAssistantTextItem()?.text;
5288
+ }
5289
+ resolveFinalAssistantTextItem() {
5026
5290
  for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
5027
5291
  const itemId = this.assistantItemOrder[i];
5028
5292
  if (!itemId) continue;
5029
5293
  const text = this.assistantTextByItem.get(itemId)?.trim();
5030
5294
  if (this.assistantPhaseByItem.get(itemId) === "commentary") continue;
5031
- if (text && !this.toolProgressTexts.has(text)) return text;
5295
+ if (text && !this.toolProgressTexts.has(text)) return {
5296
+ itemId,
5297
+ text
5298
+ };
5032
5299
  }
5033
5300
  }
5034
5301
  rememberAssistantItem(itemId) {
@@ -5546,6 +5813,7 @@ function readTurn(value) {
5546
5813
  //#region extensions/codex/src/app-server/native-subagent-notification.ts
5547
5814
  const CODEX_SUBAGENT_NOTIFICATION_START = "<subagent_notification>";
5548
5815
  const CODEX_SUBAGENT_NOTIFICATION_END = "</subagent_notification>";
5816
+ /** Extracts trusted subagent completion payloads from a Codex server notification. */
5549
5817
  function extractCodexNativeSubagentCompletions(notification) {
5550
5818
  const params = isJsonObject(notification.params) ? notification.params : void 0;
5551
5819
  if (!params) return [];
@@ -5556,6 +5824,7 @@ function extractCodexNativeSubagentCompletions(notification) {
5556
5824
  const author = readTrustedInterAgentCommunicationAuthor(item);
5557
5825
  return extractCodexNativeSubagentCompletionsFromText(text).filter((completion) => completion.agentPath === author);
5558
5826
  }
5827
+ /** Parses one or more tagged subagent completion payloads from commentary text. */
5559
5828
  function extractCodexNativeSubagentCompletionsFromText(text) {
5560
5829
  const completions = [];
5561
5830
  let cursor = 0;
@@ -5656,11 +5925,19 @@ function normalizeStatusKey(value) {
5656
5925
  }
5657
5926
  //#endregion
5658
5927
  //#region extensions/codex/src/app-server/native-subagent-task-ids.ts
5928
+ /**
5929
+ * Shared identifiers for representing Codex native subagents as OpenClaw task
5930
+ * runtime rows.
5931
+ */
5932
+ /** Task runtime namespace for Codex native subagent task rows. */
5659
5933
  const CODEX_NATIVE_SUBAGENT_RUNTIME = "subagent";
5934
+ /** Task kind used to distinguish native Codex subagents from other subagent runtimes. */
5660
5935
  const CODEX_NATIVE_SUBAGENT_TASK_KIND = "codex-native";
5936
+ /** Run id prefix for task rows keyed by Codex child thread ids. */
5661
5937
  const CODEX_NATIVE_SUBAGENT_RUN_ID_PREFIX = "codex-thread:";
5662
5938
  //#endregion
5663
5939
  //#region extensions/codex/src/app-server/native-subagent-task-mirror.ts
5940
+ /** Projects Codex thread and collab-agent notifications into task lifecycle updates. */
5664
5941
  var CodexNativeSubagentTaskMirror = class {
5665
5942
  constructor(params, runtime) {
5666
5943
  this.params = params;
@@ -5875,9 +6152,11 @@ var CodexNativeSubagentTaskMirror = class {
5875
6152
  });
5876
6153
  }
5877
6154
  };
6155
+ /** Converts a Codex child thread id into the OpenClaw task-runtime run id. */
5878
6156
  function codexNativeSubagentRunId(threadId) {
5879
6157
  return `${CODEX_NATIVE_SUBAGENT_RUN_ID_PREFIX}${threadId.trim()}`;
5880
6158
  }
6159
+ /** Reads a subagent thread-spawn source only when it belongs to the expected parent thread. */
5881
6160
  function readSubagentThreadSpawnSource(source, parentThreadId) {
5882
6161
  if (!source || typeof source !== "object" || !("subAgent" in source)) return;
5883
6162
  const subAgent = source.subAgent;
@@ -5970,6 +6249,10 @@ function trimOptional(value) {
5970
6249
  }
5971
6250
  //#endregion
5972
6251
  //#region extensions/codex/src/app-server/native-subagent-monitor.ts
6252
+ /**
6253
+ * Monitors Codex native subagent threads and mirrors their lifecycle/completion
6254
+ * into OpenClaw task runtime records for parent sessions.
6255
+ */
5973
6256
  const DEFAULT_TRANSCRIPT_POLL_DELAYS_MS = [
5974
6257
  2e3,
5975
6258
  5e3,
@@ -5995,6 +6278,7 @@ const defaultRuntime = {
5995
6278
  deliverAgentHarnessTaskCompletion
5996
6279
  };
5997
6280
  const monitors = /* @__PURE__ */ new WeakMap();
6281
+ /** Registers or updates the monitor bound to a Codex app-server client. */
5998
6282
  function registerCodexNativeSubagentMonitor(params) {
5999
6283
  let monitor = monitors.get(params.client);
6000
6284
  if (!monitor) {
@@ -6008,6 +6292,7 @@ function registerCodexNativeSubagentMonitor(params) {
6008
6292
  agentId: params.agentId
6009
6293
  });
6010
6294
  }
6295
+ /** Tracks native subagent thread notifications, transcript completions, and task delivery. */
6011
6296
  var CodexNativeSubagentMonitor = class {
6012
6297
  constructor(client, runtime = defaultRuntime, options = {}) {
6013
6298
  this.runtime = runtime;
@@ -6805,6 +7090,7 @@ function minFiniteNumber(values) {
6805
7090
  function hasContextEngineThreadBootstrapProjection(binding) {
6806
7091
  return binding.contextEngine?.projection?.mode === "thread_bootstrap";
6807
7092
  }
7093
+ /** Clears and drops a binding when the native Codex thread is too large to resume safely. */
6808
7094
  async function rotateOversizedCodexAppServerStartupBinding(params) {
6809
7095
  const binding = params.binding;
6810
7096
  if (!binding?.threadId) return binding;
@@ -6871,6 +7157,10 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
6871
7157
  }
6872
7158
  //#endregion
6873
7159
  //#region extensions/codex/src/app-server/trajectory.ts
7160
+ /**
7161
+ * Records optional Codex runtime trajectory sidecars with bounded, redacted
7162
+ * context and completion events.
7163
+ */
6874
7164
  const SENSITIVE_FIELD_RE = /(?:authorization|cookie|credential|key|password|passwd|secret|token)/iu;
6875
7165
  const PRIVATE_PAYLOAD_FIELD_RE = /(?:image|screenshot|attachment|fileData|dataUri)/iu;
6876
7166
  const AUTHORIZATION_VALUE_RE = /\b(Bearer|Basic)\s+[A-Za-z0-9+/._~=-]{8,}/giu;
@@ -6878,6 +7168,7 @@ const JWT_VALUE_RE = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]
6878
7168
  const COOKIE_PAIR_RE = /\b([A-Za-z][A-Za-z0-9_.-]{1,64})=([A-Za-z0-9+/._~%=-]{16,})(?=;|\s|$)/gu;
6879
7169
  const TRAJECTORY_RUNTIME_FILE_MAX_BYTES = 50 * 1024 * 1024;
6880
7170
  const TRAJECTORY_RUNTIME_EVENT_MAX_BYTES = 256 * 1024;
7171
+ /** Resolves secure create/truncate flags for trajectory pointer files. */
6881
7172
  function resolveCodexTrajectoryPointerFlags(constants = fsSync.constants) {
6882
7173
  const noFollow = constants.O_NOFOLLOW;
6883
7174
  return constants.O_CREAT | constants.O_TRUNC | constants.O_WRONLY | (typeof noFollow === "number" ? noFollow : 0);
@@ -6932,6 +7223,7 @@ function writeTrajectoryPointerBestEffort(params) {
6932
7223
  }
6933
7224
  } catch {}
6934
7225
  }
7226
+ /** Creates a trajectory recorder when trajectory capture is enabled for the environment. */
6935
7227
  function createCodexTrajectoryRecorder(params) {
6936
7228
  const env = params.env ?? process.env;
6937
7229
  if (!parseTrajectoryEnabled(env)) return null;
@@ -6981,6 +7273,7 @@ function createCodexTrajectoryRecorder(params) {
6981
7273
  }
6982
7274
  };
6983
7275
  }
7276
+ /** Records compiled prompt/tool context at the start of a Codex runtime attempt. */
6984
7277
  function recordCodexTrajectoryContext(recorder, params) {
6985
7278
  if (!recorder) return;
6986
7279
  recorder.recordEvent("context.compiled", {
@@ -6990,6 +7283,7 @@ function recordCodexTrajectoryContext(recorder, params) {
6990
7283
  tools: toTrajectoryToolDefinitions(params.tools)
6991
7284
  });
6992
7285
  }
7286
+ /** Records final Codex model completion metadata and assistant snapshots. */
6993
7287
  function recordCodexTrajectoryCompletion(recorder, params) {
6994
7288
  if (!recorder) return;
6995
7289
  recorder.recordEvent("model.completed", {
@@ -7059,6 +7353,7 @@ function sanitizeValue(value, depth = 0, key = "") {
7059
7353
  function redactSensitiveString(value) {
7060
7354
  return value.replace(AUTHORIZATION_VALUE_RE, "$1 <redacted>").replace(JWT_VALUE_RE, "<redacted-jwt>").replace(COOKIE_PAIR_RE, "$1=<redacted>");
7061
7355
  }
7356
+ /** Converts arbitrary prompt errors into trajectory-safe text. */
7062
7357
  function normalizeCodexTrajectoryError(value) {
7063
7358
  if (!value) return null;
7064
7359
  if (value instanceof Error) return value.message;
@@ -7071,7 +7366,12 @@ function normalizeCodexTrajectoryError(value) {
7071
7366
  }
7072
7367
  //#endregion
7073
7368
  //#region extensions/codex/src/app-server/usage-limit-error.ts
7369
+ /**
7370
+ * Enriches Codex usage-limit failures with current rate-limit information and
7371
+ * marks blocked auth profiles when Codex exposes a reset time.
7372
+ */
7074
7373
  const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
7374
+ /** Marks a Codex auth profile blocked until the reset time advertised by rate limits. */
7075
7375
  async function markCodexAuthProfileBlockedFromRateLimits(params) {
7076
7376
  const authProfileId = params.authProfileId?.trim();
7077
7377
  if (!authProfileId || !params.params.authProfileStore) return;
@@ -7094,6 +7394,7 @@ async function markCodexAuthProfileBlockedFromRateLimits(params) {
7094
7394
  });
7095
7395
  }
7096
7396
  }
7397
+ /** Formats a turn-start usage-limit error, refreshing rate limits when needed. */
7097
7398
  async function formatCodexTurnStartUsageLimitError(params) {
7098
7399
  return refreshCodexUsageLimitError({
7099
7400
  client: params.client,
@@ -7102,6 +7403,7 @@ async function formatCodexTurnStartUsageLimitError(params) {
7102
7403
  signal: params.signal
7103
7404
  });
7104
7405
  }
7406
+ /** Refreshes a generic prompt usage-limit message into a reset-aware message. */
7105
7407
  async function refreshCodexUsageLimitPromptError(params) {
7106
7408
  if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(params.message)) return;
7107
7409
  return (await refreshCodexUsageLimitError({
@@ -7211,6 +7513,11 @@ function readString$1(record, key) {
7211
7513
  }
7212
7514
  //#endregion
7213
7515
  //#region extensions/codex/src/app-server/user-input-bridge.ts
7516
+ /**
7517
+ * Bridges Codex item/tool user-input requests to OpenClaw messaging prompts and
7518
+ * turns replies into app-server answer payloads.
7519
+ */
7520
+ /** Creates a per-turn bridge for pending Codex user-input requests. */
7214
7521
  function createCodexUserInputBridge(params) {
7215
7522
  let pending;
7216
7523
  const resolvePending = (value) => {
@@ -8051,6 +8358,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
8051
8358
  let timedOut = false;
8052
8359
  let turnCompletionIdleTimedOut = false;
8053
8360
  let turnWatchTimeoutKind;
8361
+ let turnWatchTimeoutIdleMs;
8362
+ let turnWatchTimeoutMs;
8363
+ let turnWatchTimeoutLastActivityReason;
8364
+ let turnWatchTimeoutDetails;
8054
8365
  let turnCompletionIdleTimeoutMessage;
8055
8366
  let clientClosedPromptError;
8056
8367
  let clientClosedAbort = false;
@@ -8111,6 +8422,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
8111
8422
  timedOut = true;
8112
8423
  turnCompletionIdleTimedOut = true;
8113
8424
  turnWatchTimeoutKind = timeout.kind;
8425
+ turnWatchTimeoutIdleMs = timeout.idleMs;
8426
+ turnWatchTimeoutMs = timeout.timeoutMs;
8427
+ turnWatchTimeoutLastActivityReason = timeout.lastActivityReason;
8428
+ turnWatchTimeoutDetails = timeout.details;
8114
8429
  turnCompletionIdleTimeoutMessage = "codex app-server turn idle timed out waiting for turn/completed";
8115
8430
  },
8116
8431
  onMarkTimedOut: () => projectorRef.current?.markTimedOut(),
@@ -8905,7 +9220,9 @@ async function runCodexAppServerAttempt(params, options = {}) {
8905
9220
  await notificationQueue;
8906
9221
  const result = activeProjector.buildResult(toolBridge.telemetry, { yieldDetected });
8907
9222
  const finalAborted = result.aborted || runAbortController.signal.aborted && !clientClosedAbort;
8908
- let finalPromptError = clientClosedPromptError ?? (turnCompletionIdleTimedOut ? turnCompletionIdleTimeoutMessage : timedOut ? "codex app-server attempt timed out" : result.promptError);
9223
+ const canUseCompletedAssistantTextAfterClientClose = activeProjector.hasCompletedTerminalAssistantText() && activeAppServerTurnRequests === 0 && activeTurnItemIds.size === 0 && pendingOpenClawDynamicToolCompletionIds.size === 0;
9224
+ const clientClosedPromptErrorForFinal = clientClosedPromptError && canUseCompletedAssistantTextAfterClientClose ? void 0 : clientClosedPromptError;
9225
+ let finalPromptError = clientClosedPromptErrorForFinal ?? (turnCompletionIdleTimedOut ? turnCompletionIdleTimeoutMessage : timedOut ? "codex app-server attempt timed out" : result.promptError);
8909
9226
  const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
8910
9227
  if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(activeSessionFile, {
8911
9228
  phase: "turn_completed",
@@ -8934,13 +9251,20 @@ async function runCodexAppServerAttempt(params, options = {}) {
8934
9251
  signal: runAbortController.signal
8935
9252
  });
8936
9253
  if (refreshedUsageLimitPromptError) finalPromptError = refreshedUsageLimitPromptError;
8937
- const finalPromptErrorSource = timedOut || clientClosedPromptError ? "prompt" : result.promptErrorSource;
8938
- const codexAppServerFailureKind = clientClosedPromptError ? "client_closed_before_turn_completed" : turnCompletionIdleTimedOut ? "turn_completion_idle_timeout" : void 0;
9254
+ const finalPromptErrorSource = timedOut || clientClosedPromptErrorForFinal ? "prompt" : result.promptErrorSource;
9255
+ const codexAppServerFailureKind = clientClosedPromptErrorForFinal ? "client_closed_before_turn_completed" : turnCompletionIdleTimedOut ? "turn_completion_idle_timeout" : void 0;
8939
9256
  const codexAppServerReplayBlockedReason = codexAppServerFailureKind ? resolveCodexAppServerReplayBlockedReason(result) : void 0;
8940
9257
  const promptTimeoutOutcome = buildCodexAppServerPromptTimeoutOutcome({
8941
9258
  result,
8942
- turnCompletionIdleTimedOut
9259
+ turnCompletionIdleTimedOut,
9260
+ turnWatchTimeoutKind
8943
9261
  });
9262
+ const codexAppServerFailureDiagnostics = codexAppServerFailureKind === "turn_completion_idle_timeout" && turnWatchTimeoutKind === "completion" ? buildCodexAppServerTimeoutDiagnostics({
9263
+ idleMs: turnWatchTimeoutIdleMs,
9264
+ timeoutMs: turnWatchTimeoutMs,
9265
+ lastActivityReason: turnWatchTimeoutLastActivityReason,
9266
+ details: turnWatchTimeoutDetails
9267
+ }) : void 0;
8944
9268
  const modelCallFailureKind = classifyCodexModelCallFailureKind({
8945
9269
  error: finalPromptError,
8946
9270
  timedOut,
@@ -9020,7 +9344,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
9020
9344
  }),
9021
9345
  runMaintenance: runHarnessContextEngineMaintenance,
9022
9346
  config: params.config,
9023
- warn: (message) => embeddedAgentLog.warn(message)
9347
+ warn: (message) => embeddedAgentLog.warn(message),
9348
+ isHeartbeat: params.bootstrapContextRunKind === "heartbeat"
9024
9349
  });
9025
9350
  }
9026
9351
  runAgentHarnessLlmOutputHook({
@@ -9070,7 +9395,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
9070
9395
  threadId: thread.threadId,
9071
9396
  turnId: activeTurnId,
9072
9397
  replaySafe: codexAppServerReplayBlockedReason === void 0,
9073
- ...codexAppServerReplayBlockedReason ? { replayBlockedReason: codexAppServerReplayBlockedReason } : {}
9398
+ ...codexAppServerReplayBlockedReason ? { replayBlockedReason: codexAppServerReplayBlockedReason } : {},
9399
+ ...codexAppServerFailureDiagnostics ? { diagnostics: codexAppServerFailureDiagnostics } : {}
9074
9400
  } } : {},
9075
9401
  ...promptTimeoutOutcome ? { promptTimeoutOutcome } : {},
9076
9402
  systemPromptReport
@@ -9179,6 +9505,36 @@ function waitForCodexNotificationDispatchTurn() {
9179
9505
  setImmediate(resolve);
9180
9506
  });
9181
9507
  }
9508
+ function buildCodexAppServerTimeoutDiagnostics(params) {
9509
+ const readString = (key) => {
9510
+ const value = params.details?.[key];
9511
+ return typeof value === "string" && value.trim() ? value : void 0;
9512
+ };
9513
+ const readNumber = (key) => {
9514
+ const value = params.details?.[key];
9515
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
9516
+ };
9517
+ const readBoolean = (key) => {
9518
+ const value = params.details?.[key];
9519
+ return typeof value === "boolean" ? value : void 0;
9520
+ };
9521
+ return {
9522
+ ...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
9523
+ ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
9524
+ ...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
9525
+ ...readString("lastNotificationMethod") ? { lastNotificationMethod: readString("lastNotificationMethod") } : {},
9526
+ ...readString("lastNotificationItemId") ? { lastNotificationItemId: readString("lastNotificationItemId") } : {},
9527
+ ...readString("lastNotificationItemType") ? { lastNotificationItemType: readString("lastNotificationItemType") } : {},
9528
+ ...readString("lastNotificationItemRole") ? { lastNotificationItemRole: readString("lastNotificationItemRole") } : {},
9529
+ ...readString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readString("lastAssistantTextPreview") } : {},
9530
+ ...readNumber("activeAppServerTurnRequests") !== void 0 ? { activeAppServerTurnRequests: readNumber("activeAppServerTurnRequests") } : {},
9531
+ ...readNumber("activeTurnItemCount") !== void 0 ? { activeTurnItemCount: readNumber("activeTurnItemCount") } : {},
9532
+ ...readBoolean("terminalTurnNotificationQueued") !== void 0 ? { terminalTurnNotificationQueued: readBoolean("terminalTurnNotificationQueued") } : {},
9533
+ ...readBoolean("completionIdleWatchArmed") !== void 0 ? { completionIdleWatchArmed: readBoolean("completionIdleWatchArmed") } : {},
9534
+ ...readBoolean("assistantCompletionIdleWatchArmed") !== void 0 ? { assistantCompletionIdleWatchArmed: readBoolean("assistantCompletionIdleWatchArmed") } : {},
9535
+ ...readBoolean("terminalIdleWatchArmed") !== void 0 ? { terminalIdleWatchArmed: readBoolean("terminalIdleWatchArmed") } : {}
9536
+ };
9537
+ }
9182
9538
  function handleApprovalRequest(params) {
9183
9539
  return handleCodexAppServerApprovalRequest({
9184
9540
  method: params.method,