@openclaw/codex 2026.8.1-beta.3 → 2026.8.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 (69) hide show
  1. package/dist/api.js +5 -6
  2. package/dist/{attempt-client-cleanup-URjUlCHg.js → attempt-client-cleanup-CpVfwctT.js} +47 -5
  3. package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
  4. package/dist/{binding-connection-DAvZwp96.js → binding-connection-CF7BmrDk.js} +2 -2
  5. package/dist/{bounded-turn-4BjrZEwW.js → bounded-turn-DRC3hcjm.js} +16 -20
  6. package/dist/{capabilities-CH3K57v4.js → capabilities-D6m_TdVy.js} +1 -1
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-D0nZ3qtd.js → command-formatters--UToCokS.js} +4 -3
  9. package/dist/{command-handlers-DC86lgT4.js → command-handlers-CLFx2Ypa.js} +114 -79
  10. package/dist/{compact-COqgBRny.js → compact-5xqW1oCh.js} +13 -12
  11. package/dist/{config-CpNeo5AE.js → config-CcYL77O6.js} +350 -288
  12. package/dist/{conversation-binding-data-CW2GuupV.js → conversation-binding-data-BiodpIzq.js} +2 -1
  13. package/dist/doctor-contract-api.js +121 -16
  14. package/dist/{dynamic-tools-fJZhl4CE.js → dynamic-tools-BmeXjwNZ.js} +243 -1002
  15. package/dist/{effective-mcp-catalog-4YKn51aG.js → effective-mcp-catalog-XXQKgK1U.js} +2 -2
  16. package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
  17. package/dist/{event-projector-usage-CLwNEJqW.js → event-projector-usage-B2r5vhWH.js} +9 -14
  18. package/dist/{harness-DoKQcF8n.js → harness-BgeB7LnD.js} +42 -52
  19. package/dist/harness.js +1 -1
  20. package/dist/index.js +308 -306
  21. package/dist/{isolated-completion-DPMtlH9r.js → isolated-completion-CxTus3vZ.js} +4 -4
  22. package/dist/launch-args-sXOAg0SX.js +84 -0
  23. package/dist/{managed-binary-By4FZC6i.js → managed-binary-ZkGodW19.js} +43 -7
  24. package/dist/media-understanding-provider.js +1 -1
  25. package/dist/model-catalog-DULBcniB.js +101 -0
  26. package/dist/{models-CZw1wClT.js → models-DaWfETQk.js} +27 -29
  27. package/dist/{native-subagent-monitor-GGq3RnOo.js → native-subagent-monitor-vXYUZH37.js} +226 -129
  28. package/dist/{node-exec-server.runtime-Bsu1LdFZ.js → node-exec-server.runtime-DirKVZ5h.js} +9 -6
  29. package/dist/{plugin-approval-roundtrip-C75Yiiwc.js → plugin-approval-roundtrip-CCWQGlAI.js} +2 -1
  30. package/dist/{plugin-marketplace-discovery-CSWDkMrP.js → plugin-marketplace-discovery-BXjIFEiw.js} +38 -46
  31. package/dist/{plugin-metadata-cache-BXH5NF-4.js → plugin-metadata-cache-DQQm4gWT.js} +163 -136
  32. package/dist/{protocol-validators-VAVyEnDp.js → protocol-validators-Bg5rpNxk.js} +148 -5
  33. package/dist/{rate-limits-BI1dMHDG.js → rate-limits-BqHEHXQJ.js} +3 -2
  34. package/dist/{sandbox-guard-C1qEeZ5C.js → request-BWxweEdK.js} +183 -2
  35. package/dist/{run-attempt-BV3HzuCf.js → run-attempt-BVLE4Gbi.js} +706 -517
  36. package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-D9pYp4zL.js} +3 -3
  37. package/dist/{session-binding-BTrLf9Qm.js → session-binding-D0zinCP1.js} +195 -122
  38. package/dist/{session-catalog-ezP_UcRM.js → session-catalog-eMhVm0Ql.js} +448 -313
  39. package/dist/session-catalog-home-id-Dt2GiG5o.js +112 -0
  40. package/dist/{session-cli-B1hKvfkI.js → session-cli-B2lyjJA0.js} +1 -1
  41. package/dist/session-history-C5J1AKzG.js +87 -0
  42. package/dist/session-permission-policy-ScnAyG90.js +160 -0
  43. package/dist/session-retirement-CtUtUTr9.js +90 -0
  44. package/dist/{session-upstream-marker-D_2npHlA.js → session-upstream-marker-gqrYIRHk.js} +2 -3
  45. package/dist/settled-turn-context-Bk3IUwod.js +290 -0
  46. package/dist/settled-turn-finalizer-BXLN9PfJ.js +104 -0
  47. package/dist/{shared-client-Dw-rzii0.js → shared-client-B1tT5U6r.js} +1738 -806
  48. package/dist/{side-question-DbXkJZzg.js → side-question-CZ-mCw-t.js} +76 -43
  49. package/dist/{thread-lifecycle-DKdrnTMX.js → thread-lifecycle-CGGKP720.js} +991 -455
  50. package/dist/{thread-ownership-i2NBwDUL.js → thread-ownership-RkaoZCmQ.js} +18 -8
  51. package/dist/{plugin-app-cache-key-DMNQ8Zi8.js → thread-resume-BFt1-ZDa.js} +55 -8
  52. package/dist/{transcript-mirror-BU0_LKAL.js → transcript-mirror-1ep4XjzF.js} +124 -18
  53. package/dist/transport-stdio-NT_Dpd9V.js +724 -0
  54. package/dist/{upstream-prompt-provenance-CFmsKwr9.js → upstream-prompt-provenance-LphB8slG.js} +8 -4
  55. package/dist/{upstream-session-fork-BDVJCLAD.js → upstream-session-fork-Dc8BFExw.js} +76 -90
  56. package/dist/{usage-9dKJCgcy.js → usage-DUhd58gI.js} +3 -3
  57. package/dist/{web-search-provider.runtime-DCdx4DGu.js → web-search-provider.runtime-BEmlE7ov.js} +3 -3
  58. package/openclaw.plugin.json +19 -1
  59. package/package.json +8 -8
  60. package/dist/app-server-policy-bg5QPSVP.js +0 -25
  61. package/dist/command-rpc-xUIIonsO.js +0 -90
  62. package/dist/incognito-session-ET_ufDH-.js +0 -2
  63. package/dist/model-catalog-CmGoqVKB.js +0 -48
  64. package/dist/request-DSK0W6YI.js +0 -157
  65. package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
  66. package/dist/session-retirement-CE4iMiLh.js +0 -36
  67. package/dist/settled-turn-finalizer-Dx1onIqg.js +0 -328
  68. package/dist/thread-resume-CdJk2Ehf.js +0 -30
  69. package/dist/transport-stdio-DhoGy33Z.js +0 -99
package/dist/index.js CHANGED
@@ -1,30 +1,27 @@
1
1
  import { registerCodexCliMetadata } from "./cli-metadata.js";
2
- import { n as createCodexAppServerNativeCompaction, t as createCodexAppServerAgentHarness } from "./harness-DoKQcF8n.js";
3
- import { A as resolveOpenClawExecPolicyForCodexAppServer, _ as CODEX_PLUGINS_MARKETPLACE_NAME, b as canUseCodexModelBackedApprovalsReviewerForModel, c as assertCodexAppServerConnectionSecurity, h as readCodexPluginConfig, i as resolveCodexAppServerRuntimeOptions, n as codexSandboxPolicyForTurn, s as resolveCodexSupervisionAppServerRuntimeOptions, t as codexAppServerStartOptionsKey } from "./config-CpNeo5AE.js";
4
- import { G as isCodexAppServerClientRuntimeLive, J as releaseCodexAppServerLiveThread, K as isCodexAppServerLiveThreadClaimed, L as isUnsupportedCodexAppServerVersionError, N as isCodexAppServerIndeterminateRequestCancellationError, U as consumeCodexAppServerLiveThread, a as getLeasedSharedCodexAppServerClient, c as releaseCodexAppServerClientLease, d as retainSharedCodexAppServerClientByInstanceId, et as resolveCodexAppServerAuthAccountCacheKey, h as withLeasedCodexAppServerClientStartSelectionRetry, l as releaseLeasedSharedCodexAppServerClient, nt as resolveCodexAppServerAuthProfileIdForAgent, r as clearSharedCodexAppServerClientIfCurrentAndWait, rt as resolveCodexAppServerFallbackApiKeyCacheKey, st as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS, ut as isJsonObject } from "./shared-client-Dw-rzii0.js";
2
+ import { n as createCodexAppServerNativeCompaction, t as createCodexAppServerAgentHarness } from "./harness-BgeB7LnD.js";
3
+ import { D as resolveOpenClawExecPolicyForCodexAppServer, T as readCodexPluginConfig, c as assertCodexAppServerConnectionSecurity, i as resolveCodexAppServerRuntimeOptions, j as CODEX_PLUGINS_MARKETPLACE_NAME, n as codexSandboxPolicyForTurn, p as canUseCodexModelBackedApprovalsReviewerForModel, s as resolveCodexSupervisionAppServerRuntimeOptions, t as codexAppServerStartOptionsKey, v as readCodexRequirementsToml } from "./config-CcYL77O6.js";
4
+ import { C as withLeasedCodexAppServerClientStartSelectionRetry, Ft as resolveCodexAppServerFallbackApiKeyCacheKey, Ht as isJsonObject, J as isCodexAppServerOverloadError, K as isCodexAppServerIndeterminateRequestCancellationError, Nt as resolveCodexAppServerAuthProfileIdForAgent, St as releaseCodexAppServerLiveThread, Z as isUnsupportedCodexAppServerVersionError, _ as retainSharedCodexAppServerClientByInstanceId, b as retireSharedCodexAppServerClientsBeforeDesktopGeneration, bt as isCodexAppServerLiveThreadClaimed, c as getLeasedSharedCodexAppServerClient, gt as consumeCodexAppServerLiveThread, h as releaseLeasedSharedCodexAppServerClient, jt as resolveCodexAppServerAuthAccountCacheKey, k as createCodexDesktopGenerationService, m as releaseCodexAppServerClientLease, o as clearSharedCodexAppServerClientIfCurrentAndWait, vt as hasCodexAppServerLiveThread, yt as isCodexAppServerClientRuntimeLive, zt as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS } from "./shared-client-B1tT5U6r.js";
5
+ import { i as setManagedCodexPluginRoot } from "./managed-binary-ZkGodW19.js";
5
6
  import { n as CODEX_APP_SERVER_BINDING_NAMESPACE, t as CODEX_APP_SERVER_BINDING_MAX_ENTRIES } from "./session-binding-meta-B7aEMU7g.js";
6
- import { d as sessionBindingIdentity, n as assertCodexBindingMayBeReplaced, o as isCodexAppServerNativeAuthProfile, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-BTrLf9Qm.js";
7
- import { i as setManagedCodexPluginRoot } from "./managed-binary-By4FZC6i.js";
8
- import { a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, h as isCodexNotificationForTurn, o as interruptCodexTurnAndWaitBestEffort, p as getCodexAppServerTurnRouter, u as retireUnsafeCodexTurnClientBestEffort } from "./attempt-client-cleanup-URjUlCHg.js";
9
- import { s as isAssistantCommentaryCompletionNotification } from "./event-projector-usage-CLwNEJqW.js";
10
- import { a as assertCodexThreadStartResponse } from "./protocol-validators-VAVyEnDp.js";
11
- import { o as defaultCodexAppInventoryCache, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-DMNQ8Zi8.js";
12
- import { $ as ensureCodexPluginActivation, C as CODEX_MANAGED_THREAD_NAMESPACE, S as CODEX_MANAGED_THREAD_MAX_ENTRIES, Y as buildDisabledAppsConfigPatch, Z as mergeCodexThreadConfigs, _ as resolveCodexAppServerRequestModelSelection, h as CODEX_NATIVE_PERSONALITY_NONE, m as buildCodexProjectDocThreadConfig, rt as pluginReadParams, tt as isOpenAiCuratedMarketplace, w as createCodexManagedThreadStore } from "./thread-lifecycle-DKdrnTMX.js";
13
- import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
14
- import { t as resumeCodexAppServerThread } from "./thread-resume-CdJk2Ehf.js";
15
- import { d as projectBoundedCodexVisibleSessionHistory } from "./transcript-mirror-BU0_LKAL.js";
7
+ import { d as sessionBindingIdentity, n as assertCodexBindingMayBeReplaced, o as isCodexAppServerNativeAuthProfile, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-D0zinCP1.js";
8
+ import { o as createCodexAppServerProcessReaperService } from "./transport-stdio-NT_Dpd9V.js";
9
+ import { r as assertCodexThreadAcceptsDirectInput, s as assertCodexThreadStartResponse, t as CodexThreadDirectInputError } from "./protocol-validators-Bg5rpNxk.js";
10
+ import { a as closeCodexStartupClientBestEffort, c as isCodexAppServerUnsafeSubscriptionError, f as unsubscribeCodexThreadBestEffort, g as isCodexNotificationForTurn, m as getCodexAppServerTurnRouter, o as interruptCodexTurnAndWaitBestEffort, u as retireUnsafeCodexTurnClientBestEffort } from "./attempt-client-cleanup-CpVfwctT.js";
11
+ import { s as isAssistantCommentaryCompletionNotification } from "./event-projector-usage-B2r5vhWH.js";
12
+ import { i as buildCodexPluginAppCacheKey, s as defaultCodexAppInventoryCache, t as resumeCodexAppServerThread } from "./thread-resume-BFt1-ZDa.js";
13
+ import { C as buildCodexProjectDocThreadConfig, E as resolveCodexAppServerRequestModelSelection, M as CODEX_MANAGED_THREAD_NAMESPACE, N as createCodexManagedThreadStore, ct as ensureCodexPluginActivation, ft as pluginReadParams, it as buildDisabledAppsConfigPatch, j as CODEX_MANAGED_THREAD_MAX_ENTRIES, ot as mergeCodexThreadConfigs, ut as isOpenAiCuratedMarketplace, w as CODEX_NATIVE_PERSONALITY_NONE } from "./thread-lifecycle-CGGKP720.js";
14
+ import { a as rollbackCodexAppServerBindingSubscription, c as withExclusiveCodexAppServerThread, i as retireCodexConversationThreadBinding, l as isIncognitoSessionKey, n as releaseCodexAppServerBindingSubscription, r as retainCodexAppServerBindingSubscription, s as withCodexConversationThreadActivity, t as isSameCodexAppServerThreadOwner } from "./thread-ownership-RkaoZCmQ.js";
15
+ import { c as resolveCodexNativeSandboxBlock, i as requestCodexAppServerJson, o as withCodexAppServerJsonClient, s as resolveCodexNativeExecutionBlock } from "./request-BWxweEdK.js";
16
+ import { p as projectBoundedCodexVisibleSessionHistory } from "./transcript-mirror-1ep4XjzF.js";
16
17
  import { buildCodexMediaUnderstandingProvider } from "./media-understanding-provider.js";
17
- import { n as describeControlFailure, t as CODEX_CONTROL_METHODS } from "./capabilities-CH3K57v4.js";
18
- import { r as formatCodexDisplayText } from "./command-formatters-D0nZ3qtd.js";
19
- import { t as resolveCodexAppServerForModelProvider } from "./app-server-policy-bg5QPSVP.js";
20
- import { n as resolveCodexNativeExecutionBlock, r as resolveCodexNativeSandboxBlock } from "./sandbox-guard-C1qEeZ5C.js";
21
- import { a as rollbackCodexAppServerBindingSubscription, i as retireCodexConversationThreadBinding, n as releaseCodexAppServerBindingSubscription, o as withCodexConversationThreadActivity, r as retainCodexAppServerBindingSubscription, s as withExclusiveCodexAppServerThread, t as isSameCodexAppServerThreadOwner } from "./thread-ownership-i2NBwDUL.js";
22
- import { f as trackCodexConversationActiveTurn, h as canMutateCodexHost, m as CODEX_NATIVE_EXECUTION_AUTH_ERROR, t as discoverCodexMarketplacePlugins } from "./plugin-marketplace-discovery-CSWDkMrP.js";
23
- import { a as readCodexConversationBindingDataRecord, i as readCodexConversationBindingData, o as resolveCodexDefaultWorkspaceDir, r as createCodexConversationBindingData } from "./conversation-binding-data-CW2GuupV.js";
24
- import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-DAvZwp96.js";
25
- import { c as createCodexCliSessionNodeInvokePolicies, d as resolveCodexCliSessionForBindingOnNode, f as resumeCodexCliSessionOnNode, i as createCodexSessionCatalogNodeHostCommands, n as createCodexSessionCatalogNodeInvokePolicies, o as assertCodexArchiveDescendantsUnowned, r as createCodexSessionCatalogControl, s as createCodexCliSessionNodeHostCommands, t as codexSessionCatalogRuntime, u as listCodexCliSessionsOnNode } from "./session-catalog-ezP_UcRM.js";
26
- import { i as withCodexAppServerJsonClient, r as requestCodexAppServerJson } from "./request-DSK0W6YI.js";
27
- import { t as codexControlRequest } from "./command-rpc-xUIIonsO.js";
18
+ import { n as describeControlFailure, t as CODEX_CONTROL_METHODS } from "./capabilities-D6m_TdVy.js";
19
+ import { r as formatCodexDisplayText } from "./command-formatters--UToCokS.js";
20
+ import { a as resolveCodexAppServerForModelProvider, i as resolveCodexSessionPermissionCwd, n as applyCodexSessionPermissionPolicy, t as CODEX_SESSION_PERMISSION_EXEC_MODES } from "./session-permission-policy-ScnAyG90.js";
21
+ import { f as trackCodexConversationActiveTurn, g as canMutateCodexHost, h as CODEX_NATIVE_EXECUTION_AUTH_ERROR, t as discoverCodexMarketplacePlugins } from "./plugin-marketplace-discovery-BXjIFEiw.js";
22
+ import { a as readCodexConversationBindingDataRecord, i as readCodexConversationBindingData, o as resolveCodexDefaultWorkspaceDir, r as createCodexConversationBindingData } from "./conversation-binding-data-BiodpIzq.js";
23
+ import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-CF7BmrDk.js";
24
+ import { d as createCodexCliSessionNodeHostCommands, f as createCodexCliSessionNodeInvokePolicies, g as resumeCodexCliSessionOnNode, h as resolveCodexCliSessionForBindingOnNode, i as createCodexSessionCatalogNodeHostCommands, m as listCodexCliSessionsOnNode, n as createCodexSessionCatalogNodeInvokePolicies, o as assertCodexArchiveDescendantsUnowned, r as createCodexSessionCatalogControl, s as codexControlRequest, t as codexSessionCatalogRuntime } from "./session-catalog-eMhVm0Ql.js";
28
25
  import { t as createCodexWebSearchProviderBase } from "./web-search-provider.shared-BrZmlqyR.js";
29
26
  import { mutateConfigFile } from "openclaw/plugin-sdk/config-mutation";
30
27
  import { normalizePluginsConfig, resolveEffectiveEnableState, resolveLivePluginConfigObject, resolvePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
@@ -37,18 +34,17 @@ import { embeddedAgentLog, formatErrorMessage, resolveActiveEmbeddedRunSessionId
37
34
  import os from "node:os";
38
35
  import { loadAuthProfileStoreWithoutExternalProfiles, resolveAgentConfig, resolveAgentWorkspaceDir, resolveDefaultAgentDir, resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
39
36
  import { applyAuthProfileConfig, buildApiKeyCredential, buildOauthProviderAuthResult, buildOpenAICodexCredentialExtra, readCodexCliCredentialsCached, resolveOpenAICodexAuthIdentity, resolveOpenAICodexImportProfileName, updateAuthProfileStoreWithLock } from "openclaw/plugin-sdk/provider-auth";
40
- import { resolveSessionAgentIds as resolveSessionAgentIds$2, tryResolveDefaultAgentId } from "openclaw/plugin-sdk/agent-scope-runtime";
41
- import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
42
37
  import { extractErrorCode, pathExists } from "openclaw/plugin-sdk/security-runtime";
38
+ import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
39
+ import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
43
40
  import { getSessionEntry, resolveStorePath, resolveTranscriptSessionKeyBySessionId } from "openclaw/plugin-sdk/session-store-runtime";
44
41
  import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
45
42
  import { fileURLToPath } from "node:url";
46
43
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
47
- import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
48
44
  import { canonicalPathFromExistingAncestor, isPathInside } from "openclaw/plugin-sdk/file-access-runtime";
45
+ import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
49
46
  import { readVisibleSessionTranscriptMessageEntries } from "openclaw/plugin-sdk/session-transcript-runtime";
50
47
  import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-binding-runtime";
51
- import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
52
48
  import { ModelSelectionLockedError, isModelSelectionLocked } from "openclaw/plugin-sdk/model-session-runtime";
53
49
  import { MIGRATION_REASON_TARGET_EXISTS, applyMigrationManualItem, createMigrationItem, createMigrationManualItem, hasMigrationConfigPatchConflict, markMigrationItemConflict, markMigrationItemError, markMigrationItemSkipped, mergeMigrationConfigValue, readMigrationConfigPath, resolveMigrationConfigRuntime, summarizeMigrationItems, writeMigrationConfigPath } from "openclaw/plugin-sdk/migration";
54
50
  import { archiveMigrationItem, copyMemoryMigrationFileItem, copyMigrationFileItem, withCachedMigrationConfigRuntime, writeMigrationReport } from "openclaw/plugin-sdk/migration-runtime";
@@ -185,17 +181,18 @@ function waitForReconnect(delayMs, signal) {
185
181
  /** Defers schema compilation and auth loading until the first binding operation. */
186
182
  function createLazyCodexAppServerBindingStore(state, managedThreadState) {
187
183
  let resolved;
188
- const store = () => resolved ??= import("./session-binding-BTrLf9Qm.js").then((n) => n.f).then(({ createCodexAppServerBindingStore }) => createCodexAppServerBindingStore(state));
184
+ const store = () => resolved ??= import("./session-binding-D0zinCP1.js").then((n) => n.f).then(({ createCodexAppServerBindingStore }) => createCodexAppServerBindingStore(state));
189
185
  const managedThreads = managedThreadState ? createCodexManagedThreadStore(managedThreadState) : void 0;
190
186
  return {
191
187
  ...managedThreads ? { managedThreads } : {},
192
188
  read: async (identity) => (await store()).read(identity),
193
189
  hasOtherThreadOwner: async (threadId, currentIdentity) => (await store()).hasOtherThreadOwner(threadId, currentIdentity),
194
- mutate: async (identity, mutation) => (await store()).mutate(identity, mutation),
190
+ mutate: async (identity, mutation, assertCurrent) => (await store()).mutate(identity, mutation, assertCurrent),
195
191
  prepareSessionGenerationReclaim: async (identity) => (await store()).prepareSessionGenerationReclaim(identity),
196
192
  adoptSessionGeneration: async (identity, previousSessionId) => (await store()).adoptSessionGeneration(identity, previousSessionId),
197
193
  resetSessionGeneration: async (identity) => (await store()).resetSessionGeneration(identity),
198
194
  retireSessionGeneration: async (identity) => (await store()).retireSessionGeneration(identity),
195
+ withSessionDeletion: async (identity, assertCurrent, run) => (await store()).withSessionDeletion(identity, assertCurrent, run),
199
196
  withThreadArchiveFence: async (run) => (await store()).withThreadArchiveFence(run),
200
197
  withLease: async (identity, run) => (await store()).withLease(identity, run)
201
198
  };
@@ -215,7 +212,7 @@ async function handleCodexCommand(ctx, options) {
215
212
  }
216
213
  }
217
214
  async function loadDefaultCodexSubcommandHandler() {
218
- const { handleCodexSubcommand } = await import("./command-handlers-DC86lgT4.js");
215
+ const { handleCodexSubcommand } = await import("./command-handlers-CLFx2Ypa.js");
219
216
  return handleCodexSubcommand;
220
217
  }
221
218
  //#endregion
@@ -397,7 +394,7 @@ function isImageMedia(media) {
397
394
  return IMAGE_EXTENSIONS.has(path.extname(candidate.split(/[?#]/, 1)[0] ?? "").toLowerCase());
398
395
  }
399
396
  function normalizeFileUrl(value) {
400
- if (!value.startsWith("file://")) return value;
397
+ if (!/^file:\/\//iu.test(value)) return value;
401
398
  try {
402
399
  return fileURLToPath(value);
403
400
  } catch {
@@ -406,36 +403,83 @@ function normalizeFileUrl(value) {
406
403
  }
407
404
  function readLocalMediaPath(value) {
408
405
  if (!value) return;
409
- if (value.startsWith("file://")) return value;
406
+ if (/^file:\/\//iu.test(value)) return value;
410
407
  if (value.startsWith("//")) return;
411
408
  if (path.isAbsolute(value) || path.win32.isAbsolute(value)) return value;
412
409
  return /^[a-z][a-z0-9+.-]*:/i.test(value) ? void 0 : value;
413
410
  }
414
411
  //#endregion
415
412
  //#region extensions/codex/src/conversation-binding.ts
416
- const DEFAULT_BOUND_TURN_TIMEOUT_MS = 20 * 6e4;
413
+ const DEFAULT_BOUND_TURN_TIMEOUT_MS = 12e5;
417
414
  const NATIVE_CONVERSATION_INTERACTIVE_APPROVALS_UNAVAILABLE = "OpenClaw native Codex conversation binding cannot route interactive approvals yet; use the Codex harness or explicit /acp spawn codex for that workflow.";
418
415
  async function resolveConversationAppServerRuntime(params) {
419
- const execPolicy = resolveConversationExecPolicy({
416
+ const source = params.source;
417
+ const agentId = source?.agentId ?? params.agentId ?? (params.config ? resolveSessionAgentIdsStrict({
418
+ sessionKey: params.sessionKey,
419
+ config: params.config
420
+ }).sessionAgentId : void 0);
421
+ const storePath = agentId && (source || params.sessionKey) ? resolveStorePath(params.config?.session?.store, { agentId }) : void 0;
422
+ const sessionKey = source ? source.sessionKey ?? (storePath ? resolveTranscriptSessionKeyBySessionId({
423
+ agentId: source.agentId,
424
+ sessionId: source.sessionId,
425
+ storePath
426
+ }) : void 0) : params.sessionKey;
427
+ const storedEntry = sessionKey && storePath ? getSessionEntry({
428
+ agentId,
429
+ storePath,
430
+ sessionKey,
431
+ readConsistency: "latest"
432
+ }) : void 0;
433
+ const entry = !source || storedEntry?.sessionId === source.sessionId ? storedEntry : void 0;
434
+ if (source && !entry) throw new Error("Codex conversation source session is missing or no longer current; rebind this conversation before retrying.");
435
+ const permissionMode = entry?.permissionMode;
436
+ const sessionRoot = permissionMode ? entry?.sessionRoot : void 0;
437
+ const agentWorkspaceDir = params.config && agentId ? resolveAgentWorkspaceDir(params.config, agentId) : resolveCodexDefaultWorkspaceDir(params.pluginConfig);
438
+ const execPolicy = resolveOpenClawExecPolicyForCodexAppServer({
420
439
  config: params.config,
421
- agentId: params.agentId,
422
- sessionKey: params.sessionKey
440
+ agentId,
441
+ permissionMode,
442
+ execOverrides: permissionMode ? { mode: CODEX_SESSION_PERMISSION_EXEC_MODES[permissionMode] } : void 0,
443
+ approvals: permissionMode === "full" ? void 0 : loadExecApprovals()
423
444
  });
424
445
  const sandboxForPolicy = execPolicy.touched && execPolicy.security === "full" && execPolicy.ask !== "off" ? await resolveSandboxContext({
425
446
  config: params.config,
426
- sessionKey: params.sessionKey,
427
- workspaceDir: params.workspaceDir
447
+ sessionKey,
448
+ workspaceDir: agentWorkspaceDir
428
449
  }) : void 0;
429
- return {
450
+ const configuredRuntime = resolveCodexAppServerRuntimeOptions({
451
+ pluginConfig: params.pluginConfig,
430
452
  execPolicy,
431
- runtime: resolveCodexAppServerRuntimeOptions({
432
- pluginConfig: params.pluginConfig,
433
- execPolicy,
434
- modelProvider: params.modelProvider,
435
- model: params.model,
436
- config: params.config,
437
- agentDir: params.agentDir,
438
- openClawSandboxActive: Boolean(sandboxForPolicy?.enabled)
453
+ modelProvider: params.modelProvider,
454
+ model: params.model,
455
+ config: params.config,
456
+ agentDir: params.agentDir,
457
+ openClawSandboxActive: Boolean(sandboxForPolicy?.enabled)
458
+ });
459
+ const canUseAutoReview = canUseCodexModelBackedApprovalsReviewerForModel({
460
+ modelProvider: params.modelProvider,
461
+ model: params.model,
462
+ config: params.config,
463
+ env: process.env,
464
+ agentDir: params.agentDir
465
+ });
466
+ return {
467
+ runtime: applyCodexSessionPermissionPolicy({
468
+ appServer: configuredRuntime,
469
+ permissionMode,
470
+ sessionRoot,
471
+ defaultRoot: agentWorkspaceDir,
472
+ pluginConfig: readCodexPluginConfig(params.pluginConfig),
473
+ canUseAutoReview,
474
+ requirementsToml: readCodexRequirementsToml({}),
475
+ execMode: execPolicy.mode
476
+ }),
477
+ workspaceDir: resolveCodexSessionPermissionCwd({
478
+ permissionMode,
479
+ sessionRoot,
480
+ defaultRoot: agentWorkspaceDir,
481
+ requestedCwd: params.workspaceDir,
482
+ fallbackCwd: params.workspaceDir
439
483
  })
440
484
  };
441
485
  }
@@ -465,42 +509,27 @@ async function startCodexConversationThread(params) {
465
509
  authProfileId: params.authProfileId ?? existingBinding?.authProfileId,
466
510
  ...agentLookup
467
511
  });
468
- const incognito = isIncognitoSessionKey(params.sessionKey);
469
- if (params.threadId?.trim()) await attachExistingThread({
512
+ const bindingParams = {
470
513
  pluginConfig: params.pluginConfig,
471
514
  bindingStore: params.bindingStore,
472
515
  identity,
473
- threadId: params.threadId.trim(),
474
516
  workspaceDir,
475
517
  ...agentDir ? { agentDir } : {},
476
518
  model: params.model,
477
519
  modelProvider: params.modelProvider,
478
520
  authProfileId,
479
- approvalPolicy: params.approvalPolicy,
480
- sandbox: params.sandbox,
481
521
  serviceTier: params.serviceTier,
482
522
  config: params.config,
483
523
  sessionKey: params.sessionKey,
484
- incognito,
485
- agentId: params.agentId
486
- });
487
- else await createThread({
488
- pluginConfig: params.pluginConfig,
489
- bindingStore: params.bindingStore,
490
- identity,
491
- workspaceDir,
492
- ...agentDir ? { agentDir } : {},
493
- model: params.model,
494
- modelProvider: params.modelProvider,
495
- authProfileId,
496
- approvalPolicy: params.approvalPolicy,
497
- sandbox: params.sandbox,
498
- serviceTier: params.serviceTier,
499
- config: params.config,
500
- sessionKey: params.sessionKey,
501
- incognito,
524
+ incognito: isIncognitoSessionKey(params.sessionKey),
502
525
  agentId: params.agentId
526
+ };
527
+ const threadId = params.threadId?.trim();
528
+ if (threadId) await attachExistingThread({
529
+ ...bindingParams,
530
+ threadId
503
531
  });
532
+ else await bindThread(bindingParams);
504
533
  const storedBinding = await params.bindingStore.read(identity);
505
534
  if (!storedBinding) throw new Error("Codex session binding disappeared while starting its conversation thread.");
506
535
  return createCodexConversationBindingData({
@@ -639,11 +668,12 @@ async function resolveThreadBindingRuntime(params) {
639
668
  modelProvider: params.modelProvider,
640
669
  ...agentLookup
641
670
  });
642
- const { execPolicy, runtime } = await resolveConversationAppServerRuntime({
671
+ const { runtime, workspaceDir } = await resolveConversationAppServerRuntime({
643
672
  pluginConfig: params.pluginConfig,
644
673
  config: params.config,
645
674
  agentId: params.agentId,
646
675
  sessionKey: params.sessionKey,
676
+ source: params.source,
647
677
  workspaceDir: params.workspaceDir,
648
678
  modelProvider: reviewerModelProvider,
649
679
  model: params.model,
@@ -657,43 +687,32 @@ async function resolveThreadBindingRuntime(params) {
657
687
  env: process.env,
658
688
  agentDir: params.agentDir
659
689
  });
660
- assertNativeConversationApprovalPolicySupported({
661
- execPolicy,
662
- approvalPolicy: execPolicy?.touched ? modelScopedRuntime.approvalPolicy : params.approvalPolicy ?? modelScopedRuntime.approvalPolicy,
663
- approvalsReviewer: modelScopedRuntime.approvalsReviewer,
664
- modelBackedApprovalsReviewerUnavailable: !canUseCodexModelBackedApprovalsReviewerForModel({
665
- modelProvider: reviewerModelProvider,
666
- model: params.model,
667
- config: params.config,
668
- env: process.env,
669
- agentDir: params.agentDir
670
- })
671
- });
690
+ assertNativeConversationApprovalPolicySupported(modelScopedRuntime);
672
691
  const clientOptions = {
673
692
  startOptions: runtime.start,
674
693
  timeoutMs: runtime.requestTimeoutMs,
675
694
  authProfileId: params.authProfileId,
676
695
  ...agentLookup
677
696
  };
678
- const client = await getLeasedSharedCodexAppServerClient(clientOptions);
679
697
  return {
680
- execPolicy,
681
698
  runtime: modelScopedRuntime,
699
+ workspaceDir,
682
700
  agentLookup,
683
701
  model: modelSelection?.model,
684
702
  modelProvider: modelSelection?.modelProvider ?? modelProvider,
685
- client,
686
- clientLease: { client },
687
703
  clientOptions
688
704
  };
689
705
  }
690
- function buildThreadRequestRuntimeOptions(params, resolved) {
691
- const serviceTier = params.serviceTier ?? resolved.runtime.serviceTier;
692
- const sandbox = resolved.execPolicy?.touched ? resolved.runtime.sandbox : params.sandbox ?? resolved.runtime.sandbox;
706
+ function buildConversationThreadRequest(resolved, serviceTier) {
693
707
  return {
694
- approvalPolicy: resolved.execPolicy?.touched ? resolved.runtime.approvalPolicy : params.approvalPolicy ?? resolved.runtime.approvalPolicy,
708
+ cwd: resolved.workspaceDir,
709
+ ...resolved.model ? { model: resolved.model } : {},
710
+ ...resolved.modelProvider ? { modelProvider: resolved.modelProvider } : {},
711
+ personality: CODEX_NATIVE_PERSONALITY_NONE,
712
+ approvalPolicy: resolved.runtime.approvalPolicy,
695
713
  approvalsReviewer: resolved.runtime.approvalsReviewer,
696
- ...codexConversationSandboxOrPermissions(resolved.runtime, sandbox),
714
+ ...resolved.runtime.sessionRoot ? { runtimeWorkspaceRoots: [resolved.runtime.sessionRoot] } : {},
715
+ ...codexConversationSandboxOrPermissions(resolved.runtime, resolved.runtime.sandbox),
697
716
  ...serviceTier ? { serviceTier } : {}
698
717
  };
699
718
  }
@@ -706,47 +725,34 @@ function codexConversationSandboxOrPermissions(runtime, sandbox) {
706
725
  config
707
726
  };
708
727
  }
709
- async function requestNewConversationBindingThread(params, resolved) {
710
- return await withLeasedCodexAppServerClientStartSelectionRetry({
711
- lease: resolved.clientLease,
712
- options: resolved.clientOptions,
713
- run: async (client, requestOptions) => await client.request("thread/start", {
714
- cwd: params.workspaceDir,
715
- ...resolved.model ? { model: resolved.model } : {},
716
- ...resolved.modelProvider ? { modelProvider: resolved.modelProvider } : {},
717
- personality: CODEX_NATIVE_PERSONALITY_NONE,
718
- ...buildThreadRequestRuntimeOptions(params, resolved),
719
- developerInstructions: CODEX_CONVERSATION_THREAD_DEVELOPER_INSTRUCTIONS,
720
- experimentalRawEvents: true,
721
- ...params.incognito ? { ephemeral: true } : {}
722
- }, requestOptions),
723
- onClientChange: (client) => {
724
- resolved.client = client;
725
- }
726
- });
727
- }
728
- async function writeThreadBindingFromResponse(params, resolved, response) {
729
- const current = await params.bindingStore.read(params.identity);
730
- assertCodexBindingMayBeReplaced(current, "storing a conversation-bound Codex thread");
731
- const runtimeApprovalPolicy = typeof resolved.runtime.approvalPolicy === "string" ? resolved.runtime.approvalPolicy : void 0;
732
- const trackSubscription = !params.incognito && isCodexAppServerClientRuntimeLive(resolved.client);
733
- const sameOwner = isSameCodexAppServerThreadOwner(current, {
734
- threadId: response.thread.id,
735
- clientId: resolved.client.getInstanceId()
736
- });
728
+ async function writeThreadBindingFromResponse(params, resolved, client, response, requestOptions) {
737
729
  let retained = false;
730
+ let sameOwner = false;
738
731
  try {
732
+ const current = await params.bindingStore.read(params.identity);
733
+ assertCodexBindingMayBeReplaced(current, "storing a conversation-bound Codex thread");
734
+ const trackSubscription = !params.incognito && isCodexAppServerClientRuntimeLive(client);
735
+ sameOwner = isSameCodexAppServerThreadOwner(current, {
736
+ threadId: response.thread.id,
737
+ clientId: client.getInstanceId()
738
+ });
739
+ requestOptions();
740
+ assertCodexThreadAcceptsDirectInput(response.thread);
739
741
  if (trackSubscription) {
740
- retained = await retainCodexAppServerBindingSubscription(resolved.client, response.thread.id);
742
+ retained = await retainCodexAppServerBindingSubscription(client, response.thread.id);
741
743
  if (!retained) throw new Error("Codex conversation thread lost its native subscription owner.");
742
744
  }
743
- if (current && !sameOwner) await releaseCodexAppServerBindingSubscription(current);
745
+ if (current && !sameOwner) {
746
+ const { assertCurrent } = requestOptions();
747
+ await releaseCodexAppServerBindingSubscription(current, { assertCurrent });
748
+ }
749
+ requestOptions();
744
750
  if (!await params.bindingStore.mutate(params.identity, {
745
751
  kind: "set",
746
752
  binding: {
747
753
  threadId: response.thread.id,
748
- clientId: resolved.client.getInstanceId(),
749
- cwd: params.workspaceDir,
754
+ clientId: client.getInstanceId(),
755
+ cwd: resolved.workspaceDir,
750
756
  authProfileId: params.authProfileId,
751
757
  model: response.model ?? resolved.model ?? params.model,
752
758
  modelProvider: normalizeCodexAppServerBindingModelProvider({
@@ -754,15 +760,13 @@ async function writeThreadBindingFromResponse(params, resolved, response) {
754
760
  modelProvider: response.modelProvider ?? resolved.modelProvider ?? params.modelProvider,
755
761
  ...resolved.agentLookup
756
762
  }),
757
- approvalPolicy: resolved.execPolicy?.touched ? runtimeApprovalPolicy : params.approvalPolicy ?? runtimeApprovalPolicy,
758
- sandbox: resolved.execPolicy?.touched ? resolved.runtime.sandbox : params.sandbox ?? resolved.runtime.sandbox,
759
763
  serviceTier: params.serviceTier ?? resolved.runtime.serviceTier ?? void 0,
760
764
  networkProxyProfileName: resolved.runtime.networkProxy?.profileName,
761
765
  networkProxyConfigFingerprint: resolved.runtime.networkProxy?.configFingerprint
762
766
  }
763
- })) throw new Error("Codex conversation binding changed while storing its thread.");
767
+ }, requestOptions)) throw new Error("Codex conversation binding changed while storing its thread.");
764
768
  } catch (error) {
765
- if (trackSubscription && !sameOwner) await rollbackCodexAppServerBindingSubscription(resolved.client, response.thread.id, retained);
769
+ if (retained && !sameOwner || !hasCodexAppServerLiveThread(client, response.thread.id)) await rollbackCodexAppServerBindingSubscription(client, response.thread.id, retained);
766
770
  throw error;
767
771
  }
768
772
  }
@@ -771,44 +775,51 @@ async function attachExistingThread(params) {
771
775
  bindingStore: params.bindingStore,
772
776
  identity: params.identity,
773
777
  threadId: params.threadId,
774
- run: async () => {
775
- assertCodexBindingMayBeReplaced(await params.bindingStore.read(params.identity), "attaching a conversation-bound Codex thread");
776
- const resolved = await resolveThreadBindingRuntime(params);
777
- try {
778
- const response = resolved.runtime.networkProxy ? await requestNewConversationBindingThread(params, resolved) : await withLeasedCodexAppServerClientStartSelectionRetry({
779
- lease: resolved.clientLease,
780
- options: resolved.clientOptions,
781
- run: async (client, requestOptions) => {
782
- if (isCodexAppServerLiveThreadClaimed(client, params.threadId)) throw new Error(`Codex thread ${params.threadId} has an active run; stop it before binding its conversation.`);
783
- await releaseCodexAppServerLiveThread(client, params.threadId);
784
- if (isCodexAppServerLiveThreadClaimed(client, params.threadId)) throw new Error(`Codex thread ${params.threadId} has an active run; stop it before binding its conversation.`);
785
- return await client.request(CODEX_CONTROL_METHODS.resumeThread, {
786
- threadId: params.threadId,
787
- ...resolved.model ? { model: resolved.model } : {},
788
- ...resolved.modelProvider ? { modelProvider: resolved.modelProvider } : {},
789
- personality: CODEX_NATIVE_PERSONALITY_NONE,
790
- ...buildThreadRequestRuntimeOptions(params, resolved)
791
- }, requestOptions);
792
- },
793
- onClientChange: (client) => {
794
- resolved.client = client;
795
- }
796
- });
797
- if (!resolved.runtime.networkProxy && response.thread.id !== params.threadId) throw new Error(`Codex conversation resume returned ${response.thread.id} for ${params.threadId}.`);
798
- await writeThreadBindingFromResponse(params, resolved, response);
799
- } finally {
800
- releaseCodexAppServerClientLease(resolved.clientLease);
801
- }
802
- }
778
+ run: () => bindThread(params, params.threadId)
803
779
  });
804
780
  }
805
- async function createThread(params) {
806
- assertCodexBindingMayBeReplaced(await params.bindingStore.read(params.identity), "creating a conversation-bound Codex thread");
781
+ async function bindThread(params, threadId) {
782
+ const current = await params.bindingStore.read(params.identity);
783
+ assertCodexBindingMayBeReplaced(current, "binding a conversation-bound Codex thread");
807
784
  const resolved = await resolveThreadBindingRuntime(params);
785
+ const clientLease = { client: await getLeasedSharedCodexAppServerClient(resolved.clientOptions) };
808
786
  try {
809
- await writeThreadBindingFromResponse(params, resolved, await requestNewConversationBindingThread(params, resolved));
787
+ await withLeasedCodexAppServerClientStartSelectionRetry({
788
+ lease: clientLease,
789
+ options: resolved.clientOptions,
790
+ run: async (client, requestOptions) => {
791
+ const request = buildConversationThreadRequest(resolved, params.serviceTier ?? resolved.runtime.serviceTier);
792
+ let response;
793
+ if (threadId && !resolved.runtime.networkProxy) {
794
+ if (isCodexAppServerLiveThreadClaimed(client, threadId)) throw new Error(`Codex thread ${threadId} has an active run; stop it before binding its conversation.`);
795
+ const { thread } = await client.request("thread/read", {
796
+ threadId,
797
+ includeTurns: false
798
+ }, requestOptions());
799
+ assertCodexThreadAcceptsDirectInput(thread);
800
+ const { assertCurrent } = requestOptions();
801
+ await releaseCodexAppServerLiveThread(client, threadId, assertCurrent);
802
+ if (isCodexAppServerLiveThreadClaimed(client, threadId)) throw new Error(`Codex thread ${threadId} has an active run; stop it before binding its conversation.`);
803
+ response = await resumeCodexAppServerThread({
804
+ client,
805
+ abandonClient: () => closeCodexStartupClientBestEffort(client),
806
+ request: {
807
+ ...request,
808
+ threadId
809
+ },
810
+ requestResume: (resumeRequest) => client.request("thread/resume", resumeRequest, requestOptions())
811
+ });
812
+ } else response = await client.request("thread/start", {
813
+ ...request,
814
+ developerInstructions: CODEX_CONVERSATION_THREAD_DEVELOPER_INSTRUCTIONS,
815
+ experimentalRawEvents: true,
816
+ ...params.incognito ? { ephemeral: true } : {}
817
+ }, requestOptions());
818
+ await writeThreadBindingFromResponse(params, resolved, client, response, requestOptions);
819
+ }
820
+ });
810
821
  } finally {
811
- releaseCodexAppServerClientLease(resolved.clientLease);
822
+ releaseCodexAppServerClientLease(clientLease);
812
823
  }
813
824
  }
814
825
  async function runBoundTurn(params) {
@@ -821,18 +832,19 @@ async function runBoundTurn(params) {
821
832
  if (!binding?.threadId) throw new Error("bound Codex conversation has no thread binding");
822
833
  assertCodexBindingMayBeReplaced(binding, "running a conversation-bound Codex thread");
823
834
  let threadId = binding.threadId;
824
- const workspaceDir = binding.cwd || params.data.workspaceDir;
835
+ const requestedWorkspaceDir = binding.cwd || params.data.workspaceDir;
825
836
  const reviewerModelProvider = resolveModelBackedReviewerPolicyProvider({
826
837
  authProfileId: binding.authProfileId,
827
838
  modelProvider: binding.modelProvider,
828
839
  ...agentLookup
829
840
  });
830
- const { execPolicy, runtime } = await resolveConversationAppServerRuntime({
841
+ const { runtime, workspaceDir } = await resolveConversationAppServerRuntime({
831
842
  pluginConfig: params.pluginConfig,
832
843
  config: params.config,
833
- agentId: params.data.agentId,
834
- sessionKey: params.sessionKey,
835
- workspaceDir,
844
+ agentId: params.data.source?.agentId ?? params.data.agentId,
845
+ sessionKey: params.data.legacyBinding ? params.sessionKey : params.data.source?.sessionKey,
846
+ source: params.data.source,
847
+ workspaceDir: requestedWorkspaceDir,
836
848
  modelProvider: reviewerModelProvider,
837
849
  model: binding.model,
838
850
  agentDir: params.data.agentDir
@@ -845,33 +857,26 @@ async function runBoundTurn(params) {
845
857
  env: process.env,
846
858
  agentDir: params.data.agentDir
847
859
  });
848
- const modelBackedApprovalsReviewerUnavailable = !canUseCodexModelBackedApprovalsReviewerForModel({
849
- modelProvider: reviewerModelProvider,
850
- model: binding.model,
851
- config: params.config,
852
- env: process.env,
853
- agentDir: params.data.agentDir
854
- });
855
- const useModelScopedPolicy = execPolicy?.touched === true || modelBackedApprovalsReviewerUnavailable;
856
- const approvalPolicy = useModelScopedPolicy ? modelScopedRuntime.approvalPolicy : binding.approvalPolicy ?? modelScopedRuntime.approvalPolicy;
857
- const sandbox = useModelScopedPolicy ? modelScopedRuntime.sandbox : binding.sandbox ?? modelScopedRuntime.sandbox;
860
+ const sessionRoot = modelScopedRuntime.sessionRoot;
861
+ const approvalPolicy = modelScopedRuntime.approvalPolicy;
862
+ const sandbox = modelScopedRuntime.sandbox;
858
863
  const permissionProfile = modelScopedRuntime.networkProxy?.profileName;
859
864
  const networkProxyConfigFingerprint = modelScopedRuntime.networkProxy?.configFingerprint;
860
865
  const networkProxyBindingChanged = binding.networkProxyProfileName !== permissionProfile || binding.networkProxyConfigFingerprint !== networkProxyConfigFingerprint;
861
866
  const serviceTier = binding.serviceTier ?? runtime.serviceTier;
862
867
  let useStickyNetworkProfile = permissionProfile !== void 0 && binding.networkProxyProfileName === permissionProfile && binding.networkProxyConfigFingerprint === networkProxyConfigFingerprint;
863
- assertNativeConversationApprovalPolicySupported({
864
- execPolicy,
865
- approvalPolicy,
866
- approvalsReviewer: modelScopedRuntime.approvalsReviewer,
867
- modelBackedApprovalsReviewerUnavailable
868
- });
868
+ assertNativeConversationApprovalPolicySupported(modelScopedRuntime);
869
869
  const modelSelection = binding.model ? resolveCodexAppServerRequestModelSelection({
870
870
  model: binding.model,
871
871
  modelProvider: binding.modelProvider,
872
872
  authProfileId: binding.authProfileId,
873
873
  ...agentLookup
874
874
  }) : void 0;
875
+ const threadRequestRuntime = {
876
+ runtime: modelScopedRuntime,
877
+ workspaceDir,
878
+ ...modelSelection
879
+ };
875
880
  const clientOptions = {
876
881
  startOptions: runtime.start,
877
882
  timeoutMs: runtime.requestTimeoutMs,
@@ -882,12 +887,20 @@ async function runBoundTurn(params) {
882
887
  const clientLease = { client };
883
888
  let activeTurnId;
884
889
  let activeTurnCleanup = () => void 0;
885
- let retiredUnsafeClient;
890
+ let isolatedSubscriptionClient;
886
891
  let turnRoute;
887
892
  let liveThreadOwnership;
888
893
  let ownsNativeSubscription = false;
889
894
  let turnSucceeded = false;
895
+ const assertResumeInputAllowed = async () => {
896
+ const { thread } = await client.request("thread/read", {
897
+ threadId,
898
+ includeTurns: false
899
+ }, { timeoutMs: runtime.requestTimeoutMs });
900
+ assertCodexThreadAcceptsDirectInput(thread);
901
+ };
890
902
  try {
903
+ if (!networkProxyBindingChanged && binding.clientId !== client.getInstanceId()) await assertResumeInputAllowed();
891
904
  if (!params.incognito && isCodexAppServerClientRuntimeLive(client)) {
892
905
  const ownership = await consumeCodexAppServerLiveThread(client, threadId);
893
906
  if (ownership) {
@@ -904,24 +917,18 @@ async function runBoundTurn(params) {
904
917
  lease: clientLease,
905
918
  options: clientOptions,
906
919
  run: async (requestClient, requestOptions) => await requestClient.request("thread/start", {
907
- cwd: workspaceDir,
908
- ...modelSelection?.model ? { model: modelSelection.model } : {},
909
- ...modelSelection?.modelProvider ? { modelProvider: modelSelection.modelProvider } : {},
910
- personality: CODEX_NATIVE_PERSONALITY_NONE,
911
- approvalPolicy,
912
- approvalsReviewer: modelScopedRuntime.approvalsReviewer,
913
- ...codexConversationSandboxOrPermissions(modelScopedRuntime, sandbox),
914
- ...serviceTier ? { serviceTier } : {},
920
+ ...buildConversationThreadRequest(threadRequestRuntime, serviceTier),
915
921
  developerInstructions: CODEX_CONVERSATION_THREAD_DEVELOPER_INSTRUCTIONS,
916
922
  experimentalRawEvents: true,
917
923
  ...params.incognito ? { ephemeral: true } : {}
918
- }, requestOptions),
924
+ }, requestOptions()),
919
925
  onClientChange: (nextClient) => {
920
926
  client = nextClient;
921
927
  }
922
928
  }));
923
929
  threadId = response.thread.id;
924
930
  ownsNativeSubscription = true;
931
+ assertCodexThreadAcceptsDirectInput(response.thread);
925
932
  if (liveThreadOwnership && (liveThreadOwnership.threadId !== threadId || liveThreadOwnership.client !== client)) {
926
933
  const previousOwnership = liveThreadOwnership;
927
934
  try {
@@ -946,8 +953,6 @@ async function runBoundTurn(params) {
946
953
  modelProvider: response.modelProvider ?? modelSelection?.modelProvider ?? binding.modelProvider,
947
954
  ...agentLookup
948
955
  }),
949
- approvalPolicy: typeof approvalPolicy === "string" ? approvalPolicy : void 0,
950
- sandbox,
951
956
  serviceTier: serviceTier ?? void 0,
952
957
  networkProxyProfileName: modelScopedRuntime.networkProxy?.profileName,
953
958
  networkProxyConfigFingerprint: modelScopedRuntime.networkProxy?.configFingerprint,
@@ -958,26 +963,24 @@ async function runBoundTurn(params) {
958
963
  })) throw new Error("Codex conversation binding changed while rotating its thread.");
959
964
  useStickyNetworkProfile = modelScopedRuntime.networkProxy !== void 0;
960
965
  } else if (binding.clientId !== client.getInstanceId() || isCodexAppServerClientRuntimeLive(client) && !params.incognito && !liveThreadOwnership) {
966
+ if (binding.clientId === client.getInstanceId()) await assertResumeInputAllowed();
961
967
  const response = await withLeasedCodexAppServerClientStartSelectionRetry({
962
968
  lease: clientLease,
963
969
  options: clientOptions,
964
970
  run: async (requestClient, requestOptions) => await resumeCodexAppServerThread({
965
971
  client: requestClient,
972
+ onSubscriptionReleased: () => {
973
+ isolatedSubscriptionClient = requestClient;
974
+ },
966
975
  abandonClient: async () => {
967
- retiredUnsafeClient = requestClient;
968
976
  await closeCodexStartupClientBestEffort(requestClient);
977
+ isolatedSubscriptionClient = requestClient;
969
978
  },
970
979
  request: {
971
980
  threadId,
972
- ...modelSelection?.model ? { model: modelSelection.model } : {},
973
- ...modelSelection?.modelProvider ? { modelProvider: modelSelection.modelProvider } : {},
974
- personality: CODEX_NATIVE_PERSONALITY_NONE,
975
- approvalPolicy,
976
- approvalsReviewer: modelScopedRuntime.approvalsReviewer,
977
- ...codexConversationSandboxOrPermissions(modelScopedRuntime, sandbox),
978
- ...serviceTier ? { serviceTier } : {}
981
+ ...buildConversationThreadRequest(threadRequestRuntime, serviceTier)
979
982
  },
980
- ...requestOptions
983
+ requestResume: (request) => requestClient.request("thread/resume", request, requestOptions())
981
984
  }),
982
985
  onClientChange: (nextClient) => {
983
986
  client = nextClient;
@@ -985,6 +988,7 @@ async function runBoundTurn(params) {
985
988
  });
986
989
  threadId = response.thread.id;
987
990
  ownsNativeSubscription = true;
991
+ assertCodexThreadAcceptsDirectInput(response.thread);
988
992
  if (!isSameCodexAppServerThreadOwner(binding, {
989
993
  threadId,
990
994
  clientId: client.getInstanceId()
@@ -1017,9 +1021,10 @@ async function runBoundTurn(params) {
1017
1021
  event: params.event
1018
1022
  }),
1019
1023
  cwd: workspaceDir,
1024
+ ...sessionRoot ? { runtimeWorkspaceRoots: [sessionRoot] } : {},
1020
1025
  approvalPolicy,
1021
1026
  approvalsReviewer: modelScopedRuntime.approvalsReviewer,
1022
- ...useStickyNetworkProfile ? {} : { sandboxPolicy: codexSandboxPolicyForTurn(sandbox, workspaceDir) },
1027
+ ...useStickyNetworkProfile ? {} : { sandboxPolicy: codexSandboxPolicyForTurn(sandbox, sessionRoot ?? workspaceDir) },
1023
1028
  ...modelSelection?.model ? { model: modelSelection.model } : {},
1024
1029
  personality: CODEX_NATIVE_PERSONALITY_NONE,
1025
1030
  ...serviceTier ? { serviceTier } : {}
@@ -1036,20 +1041,30 @@ async function runBoundTurn(params) {
1036
1041
  turnSucceeded = true;
1037
1042
  return { reply: { text: replyText || "Codex completed without a text reply." } };
1038
1043
  } catch (error) {
1044
+ if (isCodexAppServerOverloadError(error) && error.method === "thread/resume") throw error;
1045
+ if (error instanceof CodexThreadDirectInputError) {
1046
+ if (params.incognito && ownsNativeSubscription) {
1047
+ if (!await unsubscribeCodexThreadBestEffort(client, {
1048
+ threadId,
1049
+ timeoutMs: 5e3
1050
+ })) await retireUnsafeCodexTurnClientBestEffort(client, "parent-owned thread unsubscribe");
1051
+ }
1052
+ throw error;
1053
+ }
1039
1054
  if (error instanceof CodexConversationTurnTimeoutError && activeTurnId || turnRoute && isCodexAppServerIndeterminateRequestCancellationError(error)) {
1040
1055
  if (!await interruptCodexTurnAndWaitBestEffort(client, {
1041
1056
  threadId,
1042
1057
  turnId: activeTurnId ?? ""
1043
1058
  })) {
1044
- retiredUnsafeClient = client;
1045
1059
  await retireUnsafeCodexTurnClientBestEffort(client, "turn interrupt");
1060
+ isolatedSubscriptionClient = client;
1046
1061
  }
1047
1062
  }
1048
1063
  if (params.incognito) {
1049
1064
  if (await params.bindingStore.mutate(identity, {
1050
1065
  kind: "clear",
1051
1066
  threadId
1052
- }) && retiredUnsafeClient !== client) {
1067
+ }) && isolatedSubscriptionClient !== client) {
1053
1068
  if (!await unsubscribeCodexThreadBestEffort(client, {
1054
1069
  threadId,
1055
1070
  timeoutMs: 5e3
@@ -1061,7 +1076,7 @@ async function runBoundTurn(params) {
1061
1076
  activeTurnCleanup();
1062
1077
  turnRoute?.release();
1063
1078
  try {
1064
- if (ownsNativeSubscription && retiredUnsafeClient !== client && !params.incognito && isCodexAppServerClientRuntimeLive(client)) {
1079
+ if (ownsNativeSubscription && isolatedSubscriptionClient !== client && !params.incognito && isCodexAppServerClientRuntimeLive(client)) {
1065
1080
  const currentLiveThreadOwnership = liveThreadOwnership?.client === client && liveThreadOwnership.threadId === threadId ? liveThreadOwnership.ownership : void 0;
1066
1081
  let retained = false;
1067
1082
  if (turnSucceeded) retained = await params.bindingStore.withLease(identity, async () => {
@@ -1087,8 +1102,8 @@ async function runBoundTurn(params) {
1087
1102
  }
1088
1103
  }
1089
1104
  }
1090
- function assertNativeConversationApprovalPolicySupported(params) {
1091
- if (params.approvalPolicy !== "never" && (params.execPolicy?.touched === true || params.modelBackedApprovalsReviewerUnavailable && params.approvalsReviewer === "user")) throw new Error(NATIVE_CONVERSATION_INTERACTIVE_APPROVALS_UNAVAILABLE);
1105
+ function assertNativeConversationApprovalPolicySupported(runtime) {
1106
+ if (runtime.approvalPolicy !== "never" && runtime.approvalsReviewer === "user") throw new Error(NATIVE_CONVERSATION_INTERACTIVE_APPROVALS_UNAVAILABLE);
1092
1107
  }
1093
1108
  async function runBoundTurnWithMissingThreadRecovery(params) {
1094
1109
  await prepareConversationBinding(params);
@@ -1116,11 +1131,6 @@ async function prepareConversationBinding(params, options = {}) {
1116
1131
  assertCodexBindingMayBeReplaced(current, "initializing a conversation-bound Codex thread");
1117
1132
  assertCodexBindingMayBeReplaced(sourceBinding, "transferring a session into a conversation-bound Codex thread");
1118
1133
  const inherited = current ?? sourceBinding;
1119
- const execPolicy = resolveConversationExecPolicy({
1120
- config: params.config,
1121
- agentId: params.data.agentId,
1122
- sessionKey: params.sessionKey
1123
- });
1124
1134
  const agentLookup = buildAgentLookup({
1125
1135
  agentDir: params.data.agentDir,
1126
1136
  config: params.config
@@ -1134,20 +1144,19 @@ async function prepareConversationBinding(params, options = {}) {
1134
1144
  model: requested?.model ?? inherited?.model,
1135
1145
  modelProvider: requested?.modelProvider ?? inherited?.modelProvider,
1136
1146
  authProfileId: requested?.authProfileId ?? inherited?.authProfileId,
1137
- approvalPolicy: execPolicy.touched ? void 0 : inherited?.approvalPolicy,
1138
- sandbox: execPolicy.touched ? void 0 : inherited?.sandbox,
1139
1147
  serviceTier: inherited?.serviceTier,
1140
1148
  config: params.config,
1141
- sessionKey: params.sessionKey,
1149
+ sessionKey: params.data.legacyBinding ? params.sessionKey : params.data.source?.sessionKey,
1150
+ source: params.data.source,
1142
1151
  incognito: params.incognito,
1143
- agentId: params.data.agentId
1152
+ agentId: params.data.source?.agentId ?? params.data.agentId
1144
1153
  };
1145
1154
  const threadId = requested?.threadId;
1146
1155
  if (threadId && !options.forceNew) await attachExistingThread({
1147
1156
  ...bindingParams,
1148
1157
  threadId
1149
1158
  });
1150
- else await createThread(bindingParams);
1159
+ else await bindThread(bindingParams);
1151
1160
  const stored = await params.bindingStore.read(identity);
1152
1161
  if (!stored) throw new Error("Codex conversation binding disappeared while initializing its thread.");
1153
1162
  if (sourceIdentity && params.data.source && !current?.conversationSourceTransferComplete) await params.bindingStore.withLease(sourceIdentity, async () => {
@@ -1187,12 +1196,13 @@ async function projectConversationSourceHistory(source, target, config) {
1187
1196
  storePath
1188
1197
  });
1189
1198
  if (!sessionKey) return;
1190
- const history = projectBoundedCodexVisibleSessionHistory(await readVisibleSessionTranscriptMessageEntries({
1199
+ const entries = await readVisibleSessionTranscriptMessageEntries({
1191
1200
  agentId: source.agentId,
1192
1201
  sessionId: source.sessionId,
1193
1202
  sessionKey,
1194
1203
  storePath
1195
- }));
1204
+ });
1205
+ const history = projectBoundedCodexVisibleSessionHistory(entries);
1196
1206
  if (history.length === 0) return;
1197
1207
  const clientLease = retainSharedCodexAppServerClientByInstanceId(target.clientId);
1198
1208
  if (!clientLease) throw new Error("Codex conversation source history lost its bound client owner.");
@@ -1205,66 +1215,8 @@ async function projectConversationSourceHistory(source, target, config) {
1205
1215
  clientLease.release();
1206
1216
  }
1207
1217
  }
1208
- function resolveConversationExecPolicy(params) {
1209
- const agentId = params.agentId ?? (params.config ? resolveSessionAgentIds$2({
1210
- sessionKey: params.sessionKey,
1211
- config: params.config
1212
- }).sessionAgentId : void 0);
1213
- return resolveOpenClawExecPolicyForCodexAppServer({
1214
- config: params.config,
1215
- agentId,
1216
- execOverrides: readSessionExecOverrides({
1217
- config: params.config,
1218
- agentId,
1219
- sessionKey: params.sessionKey
1220
- }),
1221
- approvals: loadExecApprovals()
1222
- });
1223
- }
1224
- function readSessionExecOverrides(params) {
1225
- const sessionKey = params.sessionKey?.trim();
1226
- if (!params.config || !sessionKey) return;
1227
- if (!canReadSessionExecOverrides({
1228
- config: params.config,
1229
- agentId: params.agentId,
1230
- sessionKey
1231
- })) return;
1232
- const entry = getSessionEntry({
1233
- storePath: resolveStorePath(params.config.session?.store, { agentId: params.agentId }),
1234
- sessionKey,
1235
- readConsistency: "latest"
1236
- });
1237
- if (!entry?.execSecurity && !entry?.execAsk) return;
1238
- return {
1239
- security: entry.execSecurity,
1240
- ask: entry.execAsk
1241
- };
1242
- }
1243
- function canReadSessionExecOverrides(params) {
1244
- const agentId = normalizeAgentIdOrDefault(params.agentId);
1245
- if (!agentId) return true;
1246
- const sessionAgentId = parseAgentIdFromSessionKey(params.sessionKey);
1247
- if (!sessionAgentId) return isDefaultAgentSessionKeyForAgent({
1248
- config: params.config,
1249
- agentId
1250
- });
1251
- return sessionAgentId === agentId;
1252
- }
1253
- function parseAgentIdFromSessionKey(sessionKey) {
1254
- const raw = sessionKey?.trim();
1255
- if (!raw) return;
1256
- const parts = raw.toLowerCase().split(":").filter(Boolean);
1257
- if (parts.length < 3 || parts[0] !== "agent" || !parts[2]) return;
1258
- return normalizeAgentIdOrDefault(parts[1]);
1259
- }
1260
- function isDefaultAgentSessionKeyForAgent(params) {
1261
- return normalizeAgentId(params.agentId) === tryResolveDefaultAgentId(params.config);
1262
- }
1263
- function normalizeAgentIdOrDefault(value) {
1264
- const normalized = normalizeAgentId(value);
1265
- return normalized === "main" && !(value ?? "").trim() ? void 0 : normalized;
1266
- }
1267
1218
  function isCodexThreadNotFoundError(error) {
1219
+ if (isCodexAppServerOverloadError(error) || isCodexAppServerUnsafeSubscriptionError(error)) return false;
1268
1220
  const message = formatErrorMessage(error);
1269
1221
  return /\bthread not found:/iu.test(message) || /\bbound Codex conversation has no thread binding\b/u.test(message);
1270
1222
  }
@@ -1435,7 +1387,8 @@ async function buildCodexOAuthCredential(source) {
1435
1387
  } : null;
1436
1388
  }
1437
1389
  async function buildCodexApiKeyCredential(source) {
1438
- const key = normalizeOptionalString((await readJsonObject(source.authPath)).OPENAI_API_KEY);
1390
+ const raw = await readJsonObject(source.authPath);
1391
+ const key = normalizeOptionalString(raw.OPENAI_API_KEY);
1439
1392
  if (!key) return null;
1440
1393
  return {
1441
1394
  kind: "api_key",
@@ -2743,7 +2696,8 @@ async function requestTargetCodexAppServerJson(params) {
2743
2696
  });
2744
2697
  if (hasOpenAiCuratedMarketplace(lastResponse)) return lastResponse;
2745
2698
  if (Date.now() >= discoveryDeadline) return lastResponse;
2746
- await sleep(Math.min(TARGET_CODEX_MARKETPLACE_DISCOVERY_POLL_MS, discoveryDeadline - Date.now()));
2699
+ const waitMs = Math.min(TARGET_CODEX_MARKETPLACE_DISCOVERY_POLL_MS, discoveryDeadline - Date.now());
2700
+ await sleep(waitMs);
2747
2701
  } while (Date.now() < discoveryDeadline);
2748
2702
  return lastResponse;
2749
2703
  }
@@ -3298,7 +3252,8 @@ function createCodexNodeExecServerCommand() {
3298
3252
  } catch {
3299
3253
  throw new Error("Codex node exec-server requires a valid workspace request.");
3300
3254
  }
3301
- const placement = parseCodexNodePlacementWorkspace(request);
3255
+ if (!isRecord(request) || Object.keys(request).length !== 2 || request.authorization !== "human-approved" && request.authorization !== "session-full") throw new Error("Codex node exec-server requires an authorized managed placement workspace launch.");
3256
+ const placement = parseCodexNodePlacementWorkspace(request.placement);
3302
3257
  if (!context?.acquireManagedWorkspace || context.sessionKey !== placement.sessionKey || io.signal.aborted) throw new Error("Codex node exec-server requires active managed placement authority.");
3303
3258
  const workspace = context.acquireManagedWorkspace({
3304
3259
  workspaceDir: placement.cwd,
@@ -3310,11 +3265,14 @@ function createCodexNodeExecServerCommand() {
3310
3265
  const frames = io.frames;
3311
3266
  let unsubscribe;
3312
3267
  try {
3313
- const { runCodexNodeExecServer } = await import("./node-exec-server.runtime-Bsu1LdFZ.js");
3268
+ if (!context.prepareExecAuthorization) throw new Error("Codex node execution requires node-local exec policy support; update the node.");
3269
+ const assertExecAuthorized = context.prepareExecAuthorization(request.authorization);
3270
+ const { runCodexNodeExecServer } = await import("./node-exec-server.runtime-DirKVZ5h.js");
3314
3271
  return await runCodexNodeExecServer({
3315
3272
  workspaceDir: workspace.workspaceDir,
3316
3273
  io,
3317
3274
  activeProcesses,
3275
+ assertExecAuthorized,
3318
3276
  onFrameReceiver: (receiver) => {
3319
3277
  unsubscribe = frames.onMessage(receiver);
3320
3278
  }
@@ -3329,7 +3287,7 @@ function createCodexNodeExecServerCommand() {
3329
3287
  }
3330
3288
  };
3331
3289
  }
3332
- /** Keeps paired-device exec-server launch behind explicit arming and one-time approval. */
3290
+ /** Keeps node launch behind command opt-in and a live Full owner or human decision. */
3333
3291
  function createCodexNodeExecServerInvokePolicy() {
3334
3292
  return {
3335
3293
  commands: [CODEX_NODE_EXEC_SERVER_COMMAND],
@@ -3339,10 +3297,10 @@ function createCodexNodeExecServerInvokePolicy() {
3339
3297
  family: CODEX_NODE_EXEC_SERVER_CAPABILITY
3340
3298
  }),
3341
3299
  handle: async (context) => {
3342
- if (!context.approvals || context.risk?.level !== "high") return {
3300
+ if (context.risk?.level !== "high") return {
3343
3301
  ok: false,
3344
3302
  code: "CODEX_NODE_EXEC_APPROVAL_REQUIRED",
3345
- message: "Codex paired-device execution requires an available approval reviewer."
3303
+ message: "Codex node execution requires an available approval reviewer."
3346
3304
  };
3347
3305
  let placement;
3348
3306
  try {
@@ -3351,21 +3309,60 @@ function createCodexNodeExecServerInvokePolicy() {
3351
3309
  return {
3352
3310
  ok: false,
3353
3311
  code: "CODEX_NODE_EXEC_WORKSPACE_INVALID",
3354
- message: "Codex paired-device execution requires an exact managed placement workspace."
3312
+ message: "Codex node execution requires an exact managed placement workspace."
3355
3313
  };
3356
3314
  }
3357
- const deviceName = context.node?.displayName ?? context.nodeId;
3358
- if ((await context.approvals.request({
3359
- title: "Run Codex execution on paired device",
3360
- description: `${deviceName}: ${placement.cwd}; allows arbitrary processes and filesystem access across the paired-device account, not only this workspace.`,
3361
- severity: "critical",
3362
- allowedDecisions: ["allow-once"]
3363
- })).decision !== "allow-once") return {
3315
+ const workspace = {
3316
+ workspaceDir: placement.cwd,
3317
+ environmentId: placement.environmentId,
3318
+ sessionId: placement.sessionId,
3319
+ ownerEpoch: placement.ownerEpoch,
3320
+ sessionKey: placement.sessionKey
3321
+ };
3322
+ const fullLaunch = await context.invokeNodeWithSessionFull?.({
3323
+ workspace,
3324
+ createParams: () => ({
3325
+ placement,
3326
+ authorization: "session-full"
3327
+ })
3328
+ });
3329
+ if (fullLaunch) return fullLaunch;
3330
+ if (!context.approvals) return {
3364
3331
  ok: false,
3365
- code: "CODEX_NODE_EXEC_APPROVAL_DENIED",
3366
- message: "Codex paired-device execution requires one-time approval."
3332
+ code: "CODEX_NODE_EXEC_APPROVAL_REQUIRED",
3333
+ message: "Codex node execution requires an available approval reviewer."
3367
3334
  };
3368
- return await context.invokeNode({ params: placement });
3335
+ const nodeName = context.node?.displayName ?? context.nodeId;
3336
+ const approval = await context.approvals.request({
3337
+ title: "Run Codex execution on node",
3338
+ description: `Allows arbitrary processes and filesystem access across the node account, not only this workspace. ${nodeName}: ${placement.cwd}`,
3339
+ severity: "critical",
3340
+ allowedDecisions: ["allow-once"]
3341
+ });
3342
+ if (approval.decision !== "allow-once") {
3343
+ if (approval.decision === "deny") return {
3344
+ ok: false,
3345
+ code: "CODEX_NODE_EXEC_APPROVAL_DENIED",
3346
+ message: "Codex node execution was denied. Retry the action and choose Allow once to continue."
3347
+ };
3348
+ if (approval.decision === "allow-always") return {
3349
+ ok: false,
3350
+ code: "CODEX_NODE_EXEC_APPROVAL_INVALID",
3351
+ message: "Codex node execution cannot use permanent approval. Retry the action and choose Allow once."
3352
+ };
3353
+ return {
3354
+ ok: false,
3355
+ code: "CODEX_NODE_EXEC_APPROVAL_EXPIRED",
3356
+ message: "Codex node execution approval expired before a decision. Retry the action and approve the new request."
3357
+ };
3358
+ }
3359
+ return await context.invokeNode({
3360
+ workspace,
3361
+ params: {
3362
+ placement,
3363
+ authorization: "human-approved"
3364
+ }
3365
+ });
3369
3366
  }
3370
3367
  };
3371
3368
  }
@@ -4151,7 +4148,7 @@ function createCodexSupervisionTools(options) {
4151
4148
  }
4152
4149
  //#endregion
4153
4150
  //#region extensions/codex/src/web-search-provider.ts
4154
- const loadCodexWebSearchRuntime = createLazyRuntimeModule(() => import("./web-search-provider.runtime-DCdx4DGu.js"));
4151
+ const loadCodexWebSearchRuntime = createLazyRuntimeModule(() => import("./web-search-provider.runtime-BEmlE7ov.js"));
4155
4152
  const CodexWebSearchSchema = {
4156
4153
  type: "object",
4157
4154
  properties: { query: {
@@ -4187,8 +4184,7 @@ const ENDED_SESSION_REASONS = /* @__PURE__ */ new Set([
4187
4184
  "new",
4188
4185
  "reset",
4189
4186
  "idle",
4190
- "daily",
4191
- "deleted"
4187
+ "daily"
4192
4188
  ]);
4193
4189
  var codex_default = definePluginEntry({
4194
4190
  id: "codex",
@@ -4211,7 +4207,10 @@ var codex_default = definePluginEntry({
4211
4207
  return livePluginConfig;
4212
4208
  };
4213
4209
  const resolveCurrentPluginConfig = () => resolvePluginConfig(resolveCurrentConfig);
4214
- if (readCodexPluginConfig(resolveCurrentPluginConfig()).appServer?.transport === "websocket") api.registerService(createCodexAppServerConnectionHealthService({
4210
+ const appServerConfig = readCodexPluginConfig(resolveCurrentPluginConfig()).appServer;
4211
+ api.registerService(createCodexDesktopGenerationService({ onGenerationChange: retireSharedCodexAppServerClientsBeforeDesktopGeneration }));
4212
+ api.registerService(createCodexAppServerProcessReaperService());
4213
+ if (appServerConfig?.transport === "websocket") api.registerService(createCodexAppServerConnectionHealthService({
4215
4214
  getPluginConfig: resolveCurrentPluginConfig,
4216
4215
  getRuntimeConfig: resolveCurrentConfig
4217
4216
  }));
@@ -4223,9 +4222,10 @@ var codex_default = definePluginEntry({
4223
4222
  overflowPolicy: "reject-new"
4224
4223
  });
4225
4224
  const lazyBindingStateStore = {
4226
- delete: (key) => openBindingStateStore().delete(key),
4225
+ deleteIf: (key, predicate) => openBindingStateStore().deleteIf(key, predicate),
4227
4226
  entries: () => openBindingStateStore().entries(),
4228
4227
  lookup: (key) => openBindingStateStore().lookup(key),
4228
+ registerIfAbsent: (key, value, options) => openBindingStateStore().registerIfAbsent(key, value, options),
4229
4229
  get update() {
4230
4230
  const store = openBindingStateStore();
4231
4231
  return store.update?.bind(store);
@@ -4238,10 +4238,12 @@ var codex_default = definePluginEntry({
4238
4238
  });
4239
4239
  const bindingStore = createLazyCodexAppServerBindingStore(lazyBindingStateStore, {
4240
4240
  entries: () => openManagedThreadStateStore().entries(),
4241
+ lookup: (key) => openManagedThreadStateStore().lookup(key),
4241
4242
  registerIfAbsent: (key, value) => openManagedThreadStateStore().registerIfAbsent(key, value)
4242
4243
  });
4243
4244
  registerCodexCliMetadata(api);
4244
4245
  const sessionCatalogControlFactory = createCodexSessionCatalogControl({
4246
+ managedThreads: bindingStore.managedThreads,
4245
4247
  config: api.config,
4246
4248
  getPluginConfig: resolveCurrentPluginConfig,
4247
4249
  getRuntimeConfig: resolveCurrentConfig
@@ -4381,7 +4383,7 @@ var codex_default = definePluginEntry({
4381
4383
  if (!previousSessionId || !sessionId || previousSessionId === sessionId) return;
4382
4384
  const config = resolveCurrentConfig();
4383
4385
  const sessionKey = ctx.sessionKey?.trim();
4384
- const { sessionBindingIdentity } = await import("./session-binding-BTrLf9Qm.js").then((n) => n.f);
4386
+ const { sessionBindingIdentity } = await import("./session-binding-D0zinCP1.js").then((n) => n.f);
4385
4387
  const identity = sessionBindingIdentity({
4386
4388
  sessionId,
4387
4389
  ...sessionKey ? { sessionKey } : {},
@@ -4399,7 +4401,7 @@ var codex_default = definePluginEntry({
4399
4401
  if (endedSessionKey && nextSessionKey && nextSessionKey !== endedSessionKey) return;
4400
4402
  if (event.nextSessionId?.trim() === event.sessionId.trim()) return;
4401
4403
  const config = resolveCurrentConfig();
4402
- const [{ sessionBindingIdentity }, { retireCodexAppServerSessionGeneration }] = await Promise.all([import("./session-binding-BTrLf9Qm.js").then((n) => n.f), import("./session-retirement-CE4iMiLh.js")]);
4404
+ const [{ sessionBindingIdentity }, { retireCodexAppServerSessionGeneration }] = await Promise.all([import("./session-binding-D0zinCP1.js").then((n) => n.f), import("./session-retirement-CtUtUTr9.js")]);
4403
4405
  await retireCodexAppServerSessionGeneration({
4404
4406
  bindingStore,
4405
4407
  identity: sessionBindingIdentity({