farming-code 2.2.29 → 2.2.32

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 (385) hide show
  1. package/README.md +25 -66
  2. package/README.zh_cn.md +15 -66
  3. package/THIRD_PARTY_NOTICES.md +7 -0
  4. package/backend/acp/{client-services.js → client-services.cjs} +132 -134
  5. package/backend/acp/packaged-claude-acp.cjs +37 -0
  6. package/backend/acp/packaged-codex-acp.cjs +37 -0
  7. package/backend/acp/patch-decisions.cjs +182 -0
  8. package/backend/acp/permission-security.cjs +131 -0
  9. package/backend/{acp-checkpoint-store.js → acp-checkpoint-store.cjs} +90 -59
  10. package/backend/{acp-runtime.js → acp-runtime.cjs} +1219 -1125
  11. package/backend/acp-session-state.cjs +622 -0
  12. package/backend/acp-transcript.cjs +525 -0
  13. package/backend/agent-env.cjs +257 -0
  14. package/backend/agent-extension-discovery.cjs +452 -0
  15. package/backend/agent-extension-inventory.cjs +116 -0
  16. package/backend/agent-json-stream.cjs +283 -0
  17. package/backend/agent-lifecycle-journal.cjs +185 -0
  18. package/backend/{agent-manager.js → agent-manager.cjs} +3116 -4275
  19. package/backend/agent-order-transaction.cjs +85 -0
  20. package/backend/agent-order.cjs +159 -0
  21. package/backend/agent-provider-session.cjs +98 -0
  22. package/backend/agent-runtime-binding.cjs +179 -0
  23. package/backend/agent-session-history.cjs +1022 -0
  24. package/backend/agent-session-inventory.cjs +291 -0
  25. package/backend/async-cache.cjs +104 -0
  26. package/backend/atomic-json-store.cjs +67 -0
  27. package/backend/auth.cjs +261 -0
  28. package/backend/authoritative-inventory-cache.cjs +383 -0
  29. package/backend/business-health.cjs +68 -0
  30. package/backend/chat-runtime.cjs +50 -0
  31. package/backend/claude-settings.cjs +132 -0
  32. package/backend/cli-agents.cjs +435 -0
  33. package/backend/codex-context-window.cjs +196 -0
  34. package/backend/codex-models.cjs +228 -0
  35. package/backend/codex-session-archive.cjs +82 -0
  36. package/backend/codex-session-history.cjs +590 -0
  37. package/backend/{codex-terminal-profile.js → codex-terminal-profile.cjs} +149 -155
  38. package/backend/codex-transcript-sanitizer.cjs +130 -0
  39. package/backend/codex-transcript.cjs +2107 -0
  40. package/backend/command-runner-child.cjs +105 -0
  41. package/backend/config-manager.cjs +1263 -0
  42. package/backend/control-api.cjs +439 -0
  43. package/backend/data/LICENSE.cua +21 -0
  44. package/backend/executable-discovery.cjs +204 -0
  45. package/backend/farming-agent-bootstrap.cjs +81 -0
  46. package/backend/farming-agent-bootstrap.zh_cn.md +6 -2
  47. package/backend/{farming-app-cli.js → farming-app-cli.cjs} +441 -493
  48. package/backend/farming-cli.cjs +414 -0
  49. package/backend/farming-net-pass.cjs +319 -0
  50. package/backend/farming-net-registry.cjs +123 -0
  51. package/backend/farming-net-server.cjs +309 -0
  52. package/backend/farming-session-store.cjs +651 -0
  53. package/backend/git-worktree-info.cjs +181 -0
  54. package/backend/haiku-token.cjs +828 -0
  55. package/backend/index-html.cjs +96 -0
  56. package/backend/input-parts.cjs +68 -0
  57. package/backend/input-routing.cjs +40 -0
  58. package/backend/{local-session-engine.js → local-session-engine.cjs} +276 -282
  59. package/backend/main-agent-skills.cjs +309 -0
  60. package/backend/main-page-session.cjs +132 -0
  61. package/backend/native-pty-controller-generation.cjs +139 -0
  62. package/backend/{native-pty-host-client.js → native-pty-host-client.cjs} +338 -346
  63. package/backend/native-pty-host-identity.cjs +125 -0
  64. package/backend/native-pty-host-path.cjs +68 -0
  65. package/backend/{native-pty-host.js → native-pty-host.cjs} +480 -569
  66. package/backend/native-session-engine.cjs +296 -0
  67. package/backend/network.cjs +57 -0
  68. package/backend/npm-update-helper.cjs +399 -0
  69. package/backend/packaged-node-pty.cjs +120 -0
  70. package/backend/preview-session-manager.cjs +89 -0
  71. package/backend/provider-adapters.cjs +492 -0
  72. package/backend/provider-home-configuration.cjs +211 -0
  73. package/backend/provider-session-id.cjs +79 -0
  74. package/backend/provider-session-service.cjs +333 -0
  75. package/backend/qr-share-tickets.cjs +119 -0
  76. package/backend/resource-broadcast-protocol.cjs +50 -0
  77. package/backend/review-diff-router.cjs +202 -0
  78. package/backend/review-diff-service.cjs +1267 -0
  79. package/backend/review-session-router.cjs +93 -0
  80. package/backend/review-session-service.cjs +470 -0
  81. package/backend/review-session-store.cjs +161 -0
  82. package/backend/review-state-router.cjs +132 -0
  83. package/backend/review-state-store.cjs +299 -0
  84. package/backend/run-history-store.cjs +97 -0
  85. package/backend/runtime-dependency-manager.cjs +893 -0
  86. package/backend/runtime-executable-invocation.cjs +37 -0
  87. package/backend/runtime-observation.cjs +96 -0
  88. package/backend/server-process-identity.cjs +70 -0
  89. package/backend/server.cjs +3356 -0
  90. package/backend/session-engine-bridge.cjs +144 -0
  91. package/backend/session-engine-router.cjs +105 -0
  92. package/backend/session-engine.cjs +64 -0
  93. package/backend/session-stream-protocol.cjs +181 -0
  94. package/backend/shell-busy-integration.cjs +442 -0
  95. package/backend/slash-command-discovery.cjs +423 -0
  96. package/backend/storage-layout.cjs +263 -0
  97. package/backend/system-monitor.cjs +96 -0
  98. package/backend/terminal-attach-checkpoint.cjs +73 -0
  99. package/backend/terminal-exit-quiescence.cjs +57 -0
  100. package/backend/{terminal-reducer-flow-control.js → terminal-reducer-flow-control.cjs} +45 -22
  101. package/backend/terminal-runtime-cleanup.cjs +99 -0
  102. package/backend/{terminal-screen-state.js → terminal-screen-state.cjs} +100 -108
  103. package/backend/{terminal-screen-worker-pool.js → terminal-screen-worker-pool.cjs} +89 -79
  104. package/backend/{terminal-screen-worker-thread.js → terminal-screen-worker-thread.cjs} +64 -65
  105. package/backend/terminal-screen-worker.cjs +352 -0
  106. package/backend/terminal-state-serialization.cjs +147 -0
  107. package/backend/{terminal-status.js → terminal-status.cjs} +137 -187
  108. package/backend/theme-manager.cjs +185 -0
  109. package/backend/update-service.cjs +675 -0
  110. package/backend/usage-forecast.cjs +95 -0
  111. package/backend/{usage-history-client.js → usage-history-client.cjs} +144 -94
  112. package/backend/usage-history-smoke.cjs +85 -0
  113. package/backend/usage-history-worker.cjs +60 -0
  114. package/backend/{usage-monitor.js → usage-monitor.cjs} +363 -390
  115. package/backend/workspace-directory.cjs +239 -0
  116. package/backend/workspace-discovery.cjs +271 -0
  117. package/backend/{workspace-file-router.js → workspace-file-router.cjs} +213 -282
  118. package/backend/{workspace-file-service.js → workspace-file-service.cjs} +1139 -1318
  119. package/backend/workspace-root-registry.cjs +192 -0
  120. package/bin/farming +1 -1
  121. package/config/farming.deploy.env.example +1 -1
  122. package/config/farming.install.env.example +1 -1
  123. package/dist/acp/codex-acp-1.1.4.mjs +405 -8
  124. package/dist/assets/App-BCkdpWB6.css +1 -0
  125. package/dist/assets/App-CRjKpaGp.js +697 -0
  126. package/dist/assets/CodeSelect-Ci8sKZPU.js +1 -0
  127. package/dist/assets/CodeSelect-T2eNzrOc.css +1 -0
  128. package/dist/assets/{FileEditorMarkdownPreview-Cs9cLv8a.js → FileEditorMarkdownPreview-V06QHlAg.js} +55 -55
  129. package/dist/assets/FileEditorPane-BX-Wjg9U.js +2 -0
  130. package/dist/assets/IconGlyphs-YhV7tqd4.js +1 -0
  131. package/dist/assets/ProjectFilesSection-BDT2_r0o.js +12 -0
  132. package/dist/assets/ReviewPage-BqAs5sG1.js +3 -0
  133. package/dist/assets/code-dark-B7eM_9G9.css +1 -0
  134. package/dist/assets/{cssMode-Bdg5RpcJ.js → cssMode-ADdAlxTO.js} +1 -1
  135. package/dist/assets/{editor.api2-D74ufkbr.js → editor.api2-BFLAr0YF.js} +162 -162
  136. package/dist/assets/file-icons-BpeqWkIB.js +1 -0
  137. package/dist/assets/{freemarker2-DfMDJfnE.js → freemarker2-C90q5jrp.js} +1 -1
  138. package/dist/assets/{handlebars-BEdPtzMT.js → handlebars-BwUQcEDq.js} +1 -1
  139. package/dist/assets/{html-B1fPb1QD.js → html-1s3uPKfh.js} +1 -1
  140. package/dist/assets/{htmlMode-CY2ZjHxH.js → htmlMode-xtKD99de.js} +1 -1
  141. package/dist/assets/{index-CQNaZc3l.js → index-C8MchCem.js} +3 -3
  142. package/dist/assets/{javascript-BV2OsWA0.js → javascript-Ph7ijyny.js} +1 -1
  143. package/dist/assets/{jsonMode-zd07aeuX.js → jsonMode-D-jGAnFH.js} +1 -1
  144. package/dist/assets/linkComputer-CbGyI_qx.js +1 -0
  145. package/dist/assets/{liquid-BParI24X.js → liquid-0IamE_cI.js} +1 -1
  146. package/dist/assets/{lspLanguageFeatures-BzredkoV.js → lspLanguageFeatures-BxnQunWF.js} +1 -1
  147. package/dist/assets/main-CLKXa6hf.css +1 -0
  148. package/dist/assets/{mdx-vGzUJN98.js → mdx-DdNmfivn.js} +1 -1
  149. package/dist/assets/{monaco.contribution-BmaeBQEc.js → monaco.contribution-B43jsUs1.js} +2 -2
  150. package/dist/assets/{python-CUwdLgsI.js → python-IAt4X5TS.js} +1 -1
  151. package/dist/assets/{razor-BScebUxU.js → razor-DRkFYW0S.js} +1 -1
  152. package/dist/assets/review-C8-oPKXk.css +1 -0
  153. package/dist/assets/{tsMode-DzUAibXK.js → tsMode-_d_4U2gf.js} +1 -1
  154. package/dist/assets/{typescript-D9EOeM7N.js → typescript-C7zcMq9l.js} +1 -1
  155. package/dist/assets/{workers-DAiomYZM.js → workers-D0nOyJzf.js} +1 -1
  156. package/dist/assets/workspace-editor-model-DND_Y-Bj.js +1 -0
  157. package/dist/assets/workspace-editor-monaco-BPWhgcIB.js +4 -0
  158. package/dist/assets/workspace-editor-monaco-N641qPjX.js +1 -0
  159. package/dist/assets/workspace-view-state-k1bTlJ_Z.js +13 -0
  160. package/dist/assets/{xml-wWl1dhkQ.js → xml-BR-HvxT8.js} +1 -1
  161. package/dist/assets/{yaml-Dc2WDaOZ.js → yaml-YtFQwh4q.js} +1 -1
  162. package/dist/index.html +2 -1
  163. package/extensions/browser/backend/agent-browser-runtime.cjs +1040 -0
  164. package/extensions/browser/backend/agent-capability.cjs +85 -0
  165. package/extensions/browser/backend/browser-mcp-server.cjs +655 -0
  166. package/extensions/browser/backend/browser-resource-manager.cjs +1486 -0
  167. package/extensions/browser/backend/browser-resource-store.cjs +228 -0
  168. package/extensions/browser/backend/browser-router.cjs +203 -0
  169. package/extensions/browser/backend/executable-discovery.cjs +248 -0
  170. package/extensions/browser/backend/farming-browser-client.cjs +116 -0
  171. package/extensions/browser/backend/index.cjs +32 -0
  172. package/extensions/browser/backend/managed-chromium-installer.cjs +833 -0
  173. package/extensions/browser/bin/farming-browser +16 -7
  174. package/extensions/computer/backend/agent-capability.cjs +72 -0
  175. package/extensions/computer/backend/computer-constants.cjs +59 -0
  176. package/extensions/computer/backend/computer-mcp-server.cjs +182 -0
  177. package/extensions/computer/backend/computer-resource-manager.cjs +1219 -0
  178. package/extensions/computer/backend/computer-resource-store.cjs +190 -0
  179. package/extensions/computer/backend/computer-router.cjs +257 -0
  180. package/extensions/computer/backend/cua-tools.json +3067 -0
  181. package/extensions/computer/backend/farming-computer-client.cjs +84 -0
  182. package/extensions/computer/backend/index.cjs +35 -0
  183. package/extensions/computer/backend/isolated-browser-provider.cjs +157 -0
  184. package/extensions/computer/bin/farming-computer +131 -0
  185. package/frontend/farming-net/app.js +255 -262
  186. package/frontend/ghostty-loader.js +24 -20
  187. package/frontend/reading-anchor.js +210 -193
  188. package/frontend/runtime-paths.js +24 -26
  189. package/frontend/session-bridge.js +90 -111
  190. package/frontend/session-modal-bridge.js +184 -302
  191. package/frontend/skin-bridge.js +20 -23
  192. package/frontend/skins/crt/app.js +7686 -7901
  193. package/frontend/skins/crt/effects.js +7 -6
  194. package/frontend/skins/crt/index.html +6 -6
  195. package/frontend/skins/crt/styles/markdown.css +4 -4
  196. package/frontend/terminal-bridge.js +174 -181
  197. package/frontend/terminal-replay.js +320 -345
  198. package/frontend/theme-loader.js +55 -71
  199. package/index.html +1 -0
  200. package/package.json +64 -37
  201. package/shared/backend-connection-status.js +38 -69
  202. package/shared/browser-protocol.js +235 -110
  203. package/shared/websocket-liveness.js +40 -0
  204. package/backend/acp/packaged-claude-acp.js +0 -13
  205. package/backend/acp/packaged-codex-acp.js +0 -13
  206. package/backend/acp/patch-decisions.js +0 -153
  207. package/backend/acp/permission-security.js +0 -108
  208. package/backend/acp-session-state.js +0 -644
  209. package/backend/acp-transcript.js +0 -512
  210. package/backend/agent-env.js +0 -250
  211. package/backend/agent-json-stream.js +0 -268
  212. package/backend/agent-lifecycle-journal.js +0 -133
  213. package/backend/agent-memory-report.js +0 -583
  214. package/backend/agent-order.js +0 -166
  215. package/backend/agent-provider-session.js +0 -76
  216. package/backend/agent-runtime-binding.js +0 -174
  217. package/backend/agent-session-history.js +0 -953
  218. package/backend/async-cache.js +0 -94
  219. package/backend/atomic-json-store.js +0 -37
  220. package/backend/auth.js +0 -251
  221. package/backend/bundle-update-helper.js +0 -113
  222. package/backend/chat-runtime.js +0 -28
  223. package/backend/claude-settings.js +0 -121
  224. package/backend/cli-agents.js +0 -486
  225. package/backend/codex-context-window.js +0 -189
  226. package/backend/codex-models.js +0 -226
  227. package/backend/codex-rollout-follower.js +0 -326
  228. package/backend/codex-session-archive.js +0 -65
  229. package/backend/codex-session-history.js +0 -647
  230. package/backend/codex-transcript-sanitizer.js +0 -115
  231. package/backend/codex-transcript.js +0 -2564
  232. package/backend/command-runner-child.js +0 -67
  233. package/backend/config-manager.js +0 -1133
  234. package/backend/control-api.js +0 -455
  235. package/backend/executable-discovery.js +0 -216
  236. package/backend/farming-agent-bootstrap.js +0 -49
  237. package/backend/farming-cli.js +0 -457
  238. package/backend/farming-net-pass.js +0 -285
  239. package/backend/farming-net-registry.js +0 -112
  240. package/backend/farming-net-server.js +0 -298
  241. package/backend/farming-session-store.js +0 -677
  242. package/backend/git-worktree-info.js +0 -181
  243. package/backend/haiku-token.js +0 -772
  244. package/backend/index-html.js +0 -62
  245. package/backend/input-parts.js +0 -54
  246. package/backend/input-routing.js +0 -24
  247. package/backend/json-cli-runtime.js +0 -275
  248. package/backend/main-agent-skills.js +0 -305
  249. package/backend/main-page-session.js +0 -122
  250. package/backend/native-pty-controller-generation.js +0 -106
  251. package/backend/native-pty-host-identity.js +0 -86
  252. package/backend/native-pty-host-path.js +0 -42
  253. package/backend/native-session-engine.js +0 -268
  254. package/backend/network.js +0 -23
  255. package/backend/npm-update-helper.js +0 -374
  256. package/backend/packaged-node-pty.js +0 -99
  257. package/backend/preview-session-manager.js +0 -68
  258. package/backend/provider-adapters.js +0 -399
  259. package/backend/provider-session-id.js +0 -47
  260. package/backend/provider-session-service.js +0 -345
  261. package/backend/qr-share-tickets.js +0 -100
  262. package/backend/review-diff-router.js +0 -180
  263. package/backend/review-diff-service.js +0 -1270
  264. package/backend/review-session-router.js +0 -74
  265. package/backend/review-session-service.js +0 -446
  266. package/backend/review-session-store.js +0 -151
  267. package/backend/review-state-router.js +0 -116
  268. package/backend/review-state-store.js +0 -286
  269. package/backend/run-history-store.js +0 -67
  270. package/backend/runtime-dependency-manager.js +0 -759
  271. package/backend/runtime-executable-invocation.js +0 -20
  272. package/backend/runtime-observation.js +0 -81
  273. package/backend/server-process-identity.js +0 -47
  274. package/backend/server.js +0 -3267
  275. package/backend/session-engine-bridge.js +0 -129
  276. package/backend/session-engine-router.js +0 -66
  277. package/backend/session-engine.js +0 -39
  278. package/backend/session-stream-protocol.js +0 -185
  279. package/backend/shell-busy-integration.js +0 -472
  280. package/backend/slash-command-discovery.js +0 -433
  281. package/backend/storage-layout.js +0 -190
  282. package/backend/system-monitor.js +0 -77
  283. package/backend/terminal-attach-checkpoint.js +0 -74
  284. package/backend/terminal-exit-quiescence.js +0 -39
  285. package/backend/terminal-runtime-cleanup.js +0 -80
  286. package/backend/terminal-screen-worker.js +0 -337
  287. package/backend/terminal-state-serialization.js +0 -127
  288. package/backend/theme-manager.js +0 -163
  289. package/backend/update-service.js +0 -1545
  290. package/backend/usage-forecast.js +0 -86
  291. package/backend/usage-history-scanner.ts +0 -2718
  292. package/backend/usage-history-smoke.js +0 -64
  293. package/backend/usage-history-worker.js +0 -34
  294. package/backend/workspace-directory.js +0 -232
  295. package/backend/workspace-discovery.js +0 -311
  296. package/backend/workspace-root-registry.js +0 -166
  297. package/dist/assets/App-BKNUILuL.css +0 -1
  298. package/dist/assets/App-Ex2oVVXO.js +0 -693
  299. package/dist/assets/FileEditorPane-CNtuGjQ3.js +0 -2
  300. package/dist/assets/IconGlyphs-BClgag6E.js +0 -1
  301. package/dist/assets/ProjectFilesSection-Cf2BEcAN.js +0 -12
  302. package/dist/assets/ReviewPage-BRuxFaH5.js +0 -3
  303. package/dist/assets/code-dark-BEZTQwYZ.css +0 -1
  304. package/dist/assets/file-icons-BOlcJ0ZF.js +0 -1
  305. package/dist/assets/main-DK9Sy7-c.css +0 -1
  306. package/dist/assets/review-BcnwQtJv.css +0 -1
  307. package/dist/assets/workspace-editor-model-CSGCl21x.js +0 -1
  308. package/dist/assets/workspace-editor-monaco-CJNwbpCy.js +0 -4
  309. package/dist/assets/workspace-editor-monaco-CO9w8YV0.js +0 -1
  310. package/dist/assets/workspace-view-state-BjKPYp0E.js +0 -7
  311. package/extensions/browser/backend/agent-browser-runtime.js +0 -1041
  312. package/extensions/browser/backend/agent-capability.js +0 -55
  313. package/extensions/browser/backend/browser-mcp-server.js +0 -621
  314. package/extensions/browser/backend/browser-resource-manager.js +0 -1309
  315. package/extensions/browser/backend/browser-resource-store.js +0 -190
  316. package/extensions/browser/backend/browser-router.js +0 -133
  317. package/extensions/browser/backend/executable-discovery.js +0 -224
  318. package/extensions/browser/backend/farming-browser-client.js +0 -83
  319. package/extensions/browser/backend/index.js +0 -7
  320. package/extensions/browser/frontend/BrowserSidebarPortals.tsx +0 -360
  321. package/extensions/browser/frontend/BrowserViewer.tsx +0 -500
  322. package/extensions/browser/frontend/browser-resource-state.ts +0 -60
  323. package/extensions/browser/frontend/browser.css +0 -567
  324. package/extensions/browser/frontend/types.ts +0 -31
  325. package/extensions/browser/frontend/useBrowserResources.ts +0 -158
  326. package/frontend/vendor/ghostty-web/index.d.ts +0 -1842
  327. package/shared/backend-connection-status.d.ts +0 -37
  328. package/shared/browser-protocol.d.ts +0 -5
  329. /package/dist/assets/{api-w2x5QfxB.js → api-ByCV9MEr.js} +0 -0
  330. /package/dist/assets/{core-vPkV8P_m.js → core-Czwdx12k.js} +0 -0
  331. /package/dist/assets/{fsharp-DNZNZyEE.js → fsharp-BjPpkoJe.js} +0 -0
  332. /package/dist/assets/{go-_kPJjNc_.js → go-BkIDmSUP.js} +0 -0
  333. /package/dist/assets/{graphql-4HCNVt5g.js → graphql-CCJTpqi1.js} +0 -0
  334. /package/dist/assets/{hcl-C87ymY0o.js → hcl-s4z8lUFg.js} +0 -0
  335. /package/dist/assets/{ini-BYrrGNTc.js → ini-CyUW1I7Z.js} +0 -0
  336. /package/dist/assets/{java-B211rJbk.js → java-CFCcGRiM.js} +0 -0
  337. /package/dist/assets/{julia-DVPsRtBm.js → julia-DQyH_EYb.js} +0 -0
  338. /package/dist/assets/{kotlin-BYyNerjp.js → kotlin-B8hA5O51.js} +0 -0
  339. /package/dist/assets/{less-EC9UblGE.js → less-DaVdaas0.js} +0 -0
  340. /package/dist/assets/{lexon-B1yuUdqW.js → lexon-DLBhPd3y.js} +0 -0
  341. /package/dist/assets/{lua-Bo6GFzxT.js → lua-gB1c_cif.js} +0 -0
  342. /package/dist/assets/{m3-C-Y9cBVI.js → m3-C2T3z3gB.js} +0 -0
  343. /package/dist/assets/{markdown-BHu-wLbe.js → markdown-CKq-Euj1.js} +0 -0
  344. /package/dist/assets/{mips-Dkds26rX.js → mips-Bcs5qIDX.js} +0 -0
  345. /package/dist/assets/{msdax-PU4g-8_g.js → msdax-CBP48FHF.js} +0 -0
  346. /package/dist/assets/{mysql-fPpuGpS7.js → mysql-c7tiPcFj.js} +0 -0
  347. /package/dist/assets/{objective-c-Wy1e5JUf.js → objective-c-D4BZkeEV.js} +0 -0
  348. /package/dist/assets/{pascal-BIXwvrqU.js → pascal-CJDZg0MN.js} +0 -0
  349. /package/dist/assets/{pascaligo-DwR0AtL_.js → pascaligo-Bygi8Ynl.js} +0 -0
  350. /package/dist/assets/{perl-CGHAl8my.js → perl-aS8bkf7E.js} +0 -0
  351. /package/dist/assets/{pgsql-B91M73E2.js → pgsql-CzNAYFYl.js} +0 -0
  352. /package/dist/assets/{php-C70ttrCx.js → php-DOtoEFTT.js} +0 -0
  353. /package/dist/assets/{pla-BNrXaRh0.js → pla-DugRnao1.js} +0 -0
  354. /package/dist/assets/{postiats-Dv2IAZR9.js → postiats-DsXwusKh.js} +0 -0
  355. /package/dist/assets/{powerquery-CkY5Wq7J.js → powerquery-DL3o72oD.js} +0 -0
  356. /package/dist/assets/{powershell-uGIYLU3C.js → powershell-C1qHekys.js} +0 -0
  357. /package/dist/assets/{protobuf-CavfmJu-.js → protobuf-DHgsc-cH.js} +0 -0
  358. /package/dist/assets/{pug-Drqnyitx.js → pug-FZXlE_Iu.js} +0 -0
  359. /package/dist/assets/{qrcode-7uGsTEmi.js → qrcode-DJDTdjL7.js} +0 -0
  360. /package/dist/assets/{qsharp-C7yF-Dti.js → qsharp-bLyhI3DT.js} +0 -0
  361. /package/dist/assets/{r-HXLGP0_-.js → r-DjFGXbAa.js} +0 -0
  362. /package/dist/assets/{redis-C4y6mf2p.js → redis-DSoZ_V6u.js} +0 -0
  363. /package/dist/assets/{redshift-DdQrFPrv.js → redshift-CzkdCsrg.js} +0 -0
  364. /package/dist/assets/{restructuredtext-CBrf2PNj.js → restructuredtext-B_XPrGCQ.js} +0 -0
  365. /package/dist/assets/{ruby-CVtMoX2B.js → ruby-Cry2RneJ.js} +0 -0
  366. /package/dist/assets/{rust-Ckq4sbMP.js → rust-CWzdbFq1.js} +0 -0
  367. /package/dist/assets/{sb-er66OpE3.js → sb-DmofU59h.js} +0 -0
  368. /package/dist/assets/{scala-BdWZz-hH.js → scala-BUC2l-vN.js} +0 -0
  369. /package/dist/assets/{scheme-kTV_s2kP.js → scheme-CNIB_72f.js} +0 -0
  370. /package/dist/assets/{scss-Bymy2VJQ.js → scss-DcL4-NbX.js} +0 -0
  371. /package/dist/assets/{shell-bwEP1LQ1.js → shell-CgAGvSSA.js} +0 -0
  372. /package/dist/assets/{solidity-DCddeBgL.js → solidity-DSkt6O_P.js} +0 -0
  373. /package/dist/assets/{sophia-BMN3AQig.js → sophia--5ytcjDN.js} +0 -0
  374. /package/dist/assets/{sparql-CSXOLjzi.js → sparql-C1Srr7cD.js} +0 -0
  375. /package/dist/assets/{sql-COg8ewmK.js → sql-2k_O5fj7.js} +0 -0
  376. /package/dist/assets/{st-CIaZtBS_.js → st-DCCCPqfz.js} +0 -0
  377. /package/dist/assets/{swift-DXiOhUHu.js → swift-Dd8mAfOt.js} +0 -0
  378. /package/dist/assets/{systemverilog-BTDE6Dr2.js → systemverilog-B0-aZYXu.js} +0 -0
  379. /package/dist/assets/{tcl-B0zy9NvV.js → tcl-CZAZwPVX.js} +0 -0
  380. /package/dist/assets/{twig-D594l4Z1.js → twig-D-Ag0tdS.js} +0 -0
  381. /package/dist/assets/{typespec-XKVjaPqo.js → typespec-B7kTFp0Z.js} +0 -0
  382. /package/dist/assets/{useWorkspaceMenuKeyboard-Bpy_s69Z.js → useWorkspaceMenuKeyboard-uYZpDxhU.js} +0 -0
  383. /package/dist/assets/{vb-B2wYoKRV.js → vb-20w1JPum.js} +0 -0
  384. /package/dist/assets/{wgsl-D0Yf2LbK.js → wgsl-CLJfqFt0.js} +0 -0
  385. /package/dist/assets/{workspace-working-copy-C3FSR3N6.js → workspace-working-copy-Cfz07cOd.js} +0 -0
@@ -1,82 +1,125 @@
1
- const EventEmitter = require('events');
2
- const crypto = require('crypto');
3
- const fs = require('fs');
4
- const path = require('path');
5
- const { execFile, spawn } = require('child_process');
6
- const { Readable, Writable } = require('stream');
7
- const { createRequire } = require('module');
8
- const { promisify } = require('util');
9
- const packageJson = require('../package.json');
10
- const { AcpCheckpointStore } = require('./acp-checkpoint-store');
11
- const { AcpSessionState } = require('./acp-session-state');
12
- const { readCodexHistoryImageData } = require('./codex-transcript');
13
- const { AcpClientFileSystem, AcpClientTerminalManager } = require('./acp/client-services');
14
- const { PACKAGED_CODEX_ACP_ARG } = require('./acp/packaged-codex-acp');
15
- const { PACKAGED_CLAUDE_ACP_ARG } = require('./acp/packaged-claude-acp');
16
- const { permissionSecurityWarnings } = require('./acp/permission-security');
17
- const { patchBlock, rejectPatch } = require('./acp/patch-decisions');
18
- const { getProviderAdapter, listProviderAdapters } = require('./provider-adapters');
19
- const { isSafeProviderSessionId } = require('./provider-session-id');
20
-
1
+ // Generated by scripts/build-backend-runtime.ts. Do not edit.
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+ var acp_runtime_exports = {};
31
+ __export(acp_runtime_exports, {
32
+ ADAPTER_VERSIONS: () => ADAPTER_VERSIONS,
33
+ AcpRuntime: () => AcpRuntime,
34
+ CODEX_STEER_METHOD: () => CODEX_STEER_METHOD,
35
+ acpErrorKind: () => acpErrorKind,
36
+ acpSessionRequestOptions: () => acpSessionRequestOptions,
37
+ autoPermissionResponse: () => autoPermissionResponse,
38
+ codexAcpEnvironment: () => codexAcpEnvironment,
39
+ deleteProviderSessionIdentity: () => deleteProviderSessionIdentity,
40
+ describeAcpProcessGroup: () => describeAcpProcessGroup,
41
+ isCodexSteerUnavailableError: () => isCodexSteerUnavailableError,
42
+ promptContentForCapabilities: () => promptContentForCapabilities,
43
+ resolveAcpLaunch: () => resolveAcpLaunch,
44
+ stopPersistedAcpProcessGroup: () => stopPersistedAcpProcessGroup,
45
+ supportsCodexSteer: () => supportsCodexSteer
46
+ });
47
+ module.exports = __toCommonJS(acp_runtime_exports);
48
+ var import_events = require("events");
49
+ var import_acp_checkpoint_store = require("./acp-checkpoint-store.cjs");
50
+ var import_acp_session_state = require("./acp-session-state.cjs");
51
+ var import_client_services = require("./acp/client-services.cjs");
52
+ var import_packaged_codex_acp = require("./acp/packaged-codex-acp.cjs");
53
+ var import_packaged_claude_acp = require("./acp/packaged-claude-acp.cjs");
54
+ var import_permission_security = require("./acp/permission-security.cjs");
55
+ var import_patch_decisions = require("./acp/patch-decisions.cjs");
56
+ var import_provider_adapters = require("./provider-adapters.cjs");
57
+ var import_provider_session_id = require("./provider-session-id.cjs");
58
+ const crypto = require("crypto");
59
+ const fs = require("fs");
60
+ const path = require("path");
61
+ const { execFile, spawn } = require("child_process");
62
+ const { Readable, Writable } = require("stream");
63
+ const { createRequire } = require("module");
64
+ const { promisify } = require("util");
65
+ const packageJson = require("../package.json");
66
+ function asErrorLike(error) {
67
+ return error && typeof error === "object" ? error : {};
68
+ }
21
69
  const ADAPTER_VERSIONS = Object.freeze(Object.fromEntries(
22
- listProviderAdapters().filter(adapter => adapter.acp).map(adapter => [adapter.id, adapter.acp.version]),
70
+ (0, import_provider_adapters.listProviderAdapters)().filter((adapter) => adapter.acp).map((adapter) => [adapter.id, adapter.acp.version])
23
71
  ));
24
-
25
- const DEFAULT_INITIALIZE_TIMEOUT_MS = 15_000;
26
- const DEFAULT_SESSION_SETUP_TIMEOUT_MS = 120_000;
27
- const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
28
- const DEFAULT_CANCEL_TIMEOUT_MS = 15_000;
72
+ const DEFAULT_INITIALIZE_TIMEOUT_MS = 15e3;
73
+ const DEFAULT_SESSION_SETUP_TIMEOUT_MS = 12e4;
74
+ const DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
75
+ const DEFAULT_CANCEL_TIMEOUT_MS = 15e3;
29
76
  const DEFAULT_HISTORY_REPLAY_MIN_WAIT_MS = 350;
30
77
  const DEFAULT_HISTORY_REPLAY_QUIET_MS = 150;
31
- const DEFAULT_HISTORY_REPLAY_MAX_WAIT_MS = 5_000;
32
- const IDENTITY_ADAPTER_GRACEFUL_EXIT_MS = 3_000;
33
- const IDENTITY_ADAPTER_TERMINATE_MS = 1_000;
34
- const IDENTITY_ADAPTER_KILL_MS = 1_000;
35
- const CODEX_SET_SESSION_MODEL_METHOD = 'session/set_model';
36
- const CODEX_STEER_METHOD = '_codex/session/steer';
37
- const CODEX_ACP_PACKAGE = '@agentclientprotocol/codex-acp';
38
- const CODEX_ACP_VERSION = '1.1.4';
39
- const CODEX_ACP_SHA256 = 'e36876cc2250737c719644e6c69ab054a3f8b58071fad45c44407013082942ff';
40
- const CLAUDE_ACP_PACKAGE = '@agentclientprotocol/claude-agent-acp';
41
- const CLAUDE_ACP_VERSION = '0.59.0';
42
- const CLAUDE_ACP_SHA256 = 'a6aa515dd02382617bf46d9eac47b8a1022c6835bcf7a8d61e2c63939be2e49c';
78
+ const DEFAULT_HISTORY_REPLAY_MAX_WAIT_MS = 5e3;
79
+ const IDENTITY_ADAPTER_GRACEFUL_EXIT_MS = 3e3;
80
+ const IDENTITY_ADAPTER_TERMINATE_MS = 1e3;
81
+ const IDENTITY_ADAPTER_KILL_MS = 1e3;
82
+ const CODEX_SET_SESSION_MODEL_METHOD = "session/set_model";
83
+ const CODEX_STEER_METHOD = "_codex/session/steer";
84
+ const CODEX_ACP_PACKAGE = "@agentclientprotocol/codex-acp";
85
+ const CODEX_ACP_VERSION = "1.1.4";
86
+ const CODEX_ACP_SHA256 = "7d9647ad2af49d47311a785bf5abd2d317d7c7438ae9d4eacfe785ba37191718";
87
+ const CLAUDE_ACP_PACKAGE = "@agentclientprotocol/claude-agent-acp";
88
+ const CLAUDE_ACP_VERSION = "0.59.0";
89
+ const CLAUDE_ACP_SHA256 = "a6aa515dd02382617bf46d9eac47b8a1022c6835bcf7a8d61e2c63939be2e49c";
43
90
  const CODEX_ACP_VENDOR_ENTRY = path.join(
44
91
  __dirname,
45
- '..',
46
- 'dist',
47
- 'acp',
48
- `codex-acp-${CODEX_ACP_VERSION}.mjs`,
92
+ "..",
93
+ "dist",
94
+ "acp",
95
+ `codex-acp-${CODEX_ACP_VERSION}.mjs`
49
96
  );
50
97
  const CLAUDE_ACP_VENDOR_ENTRY = path.join(
51
98
  __dirname,
52
- '..',
53
- 'dist',
54
- 'acp',
55
- `claude-agent-acp-${CLAUDE_ACP_VERSION}.mjs`,
99
+ "..",
100
+ "dist",
101
+ "acp",
102
+ `claude-agent-acp-${CLAUDE_ACP_VERSION}.mjs`
56
103
  );
57
104
  const execFileAsync = promisify(execFile);
58
-
59
105
  let sdkPromise;
60
106
  const runtimeRequire = createRequire(__filename);
61
107
  function loadAcpSdk() {
62
- if (!sdkPromise) sdkPromise = import('@agentclientprotocol/sdk');
108
+ if (!sdkPromise) sdkPromise = import("@agentclientprotocol/sdk");
63
109
  return sdkPromise;
64
110
  }
65
-
66
111
  function fileSha256(filePath) {
67
- return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
112
+ return crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex");
68
113
  }
69
-
70
114
  function verifiedCodexAcpEntry(entry) {
71
115
  const actualSha256 = fileSha256(entry);
72
116
  if (actualSha256 !== CODEX_ACP_SHA256) {
73
117
  throw new Error(
74
- `Codex ACP runtime failed integrity verification: expected ${CODEX_ACP_SHA256}, found ${actualSha256}`,
118
+ `Codex ACP runtime failed integrity verification: expected ${CODEX_ACP_SHA256}, found ${actualSha256}`
75
119
  );
76
120
  }
77
121
  return entry;
78
122
  }
79
-
80
123
  function adapterEntry(packageName) {
81
124
  if (packageName === CODEX_ACP_PACKAGE && fs.existsSync(CODEX_ACP_VENDOR_ENTRY)) {
82
125
  return verifiedCodexAcpEntry(CODEX_ACP_VENDOR_ENTRY);
@@ -85,42 +128,40 @@ function adapterEntry(packageName) {
85
128
  const actualSha256 = fileSha256(CLAUDE_ACP_VENDOR_ENTRY);
86
129
  if (actualSha256 !== CLAUDE_ACP_SHA256) {
87
130
  throw new Error(
88
- `Claude ACP runtime failed integrity verification: expected ${CLAUDE_ACP_SHA256}, found ${actualSha256}`,
131
+ `Claude ACP runtime failed integrity verification: expected ${CLAUDE_ACP_SHA256}, found ${actualSha256}`
89
132
  );
90
133
  }
91
134
  return CLAUDE_ACP_VENDOR_ENTRY;
92
135
  }
93
136
  let sdkDirectory;
94
137
  try {
95
- sdkDirectory = path.dirname(runtimeRequire.resolve('@agentclientprotocol/sdk'));
138
+ sdkDirectory = path.dirname(runtimeRequire.resolve("@agentclientprotocol/sdk"));
96
139
  } catch {
97
- throw new Error('ACP runtime packages are unavailable in this installation. Use the npm or app-bundle distribution.');
140
+ throw new Error("ACP runtime packages are unavailable in this installation. Use the npm or app-bundle distribution.");
98
141
  }
99
- const entry = path.resolve(sdkDirectory, '..', '..', packageName.split('/').pop(), 'dist', 'index.js');
142
+ const entry = path.resolve(sdkDirectory, "..", "..", packageName.split("/").pop(), "dist", "index.js");
100
143
  if (!fs.existsSync(entry)) throw new Error(`ACP adapter is not installed: ${packageName}`);
101
144
  if (packageName === CODEX_ACP_PACKAGE) return verifiedCodexAcpEntry(entry);
102
145
  return entry;
103
146
  }
104
-
105
- function nodeAdapterLaunch(entry, env = process.env, packagedArg = '') {
106
- const runtimeEnv = env && typeof env === 'object' ? env : process.env;
147
+ function nodeAdapterLaunch(entry, env = process.env, packagedArg = "") {
148
+ const runtimeEnv = env && typeof env === "object" ? env : process.env;
107
149
  if (process.pkg && packagedArg) {
108
150
  return { command: process.execPath, args: [packagedArg] };
109
151
  }
110
152
  const nodeBin = runtimeEnv.FARMING_NODE_BIN || process.execPath;
111
- const ldPath = runtimeEnv.FARMING_NODE_LD || '';
112
- const libraryPath = runtimeEnv.FARMING_NODE_LIBRARY_PATH || '';
153
+ const ldPath = runtimeEnv.FARMING_NODE_LD || "";
154
+ const libraryPath = runtimeEnv.FARMING_NODE_LIBRARY_PATH || "";
113
155
  if (ldPath && libraryPath) {
114
156
  return {
115
157
  command: ldPath,
116
- args: ['--library-path', libraryPath, nodeBin, entry],
158
+ args: ["--library-path", libraryPath, nodeBin, entry]
117
159
  };
118
160
  }
119
161
  return { command: nodeBin, args: [entry] };
120
162
  }
121
-
122
163
  function resolveAcpLaunch(provider, options = {}) {
123
- const adapter = getProviderAdapter(provider);
164
+ const adapter = (0, import_provider_adapters.getProviderAdapter)(provider);
124
165
  if (!adapter?.acp) throw new Error(`Unsupported ACP provider: ${provider}`);
125
166
  if (adapter.acp.launch) {
126
167
  return { ...adapter.acp.launch(options), version: adapter.acp.version };
@@ -129,25 +170,22 @@ function resolveAcpLaunch(provider, options = {}) {
129
170
  const launch = nodeAdapterLaunch(
130
171
  adapterEntry(adapter.acp.packageName),
131
172
  options.runtimeEnv || process.env,
132
- adapter.acp.packageName === CODEX_ACP_PACKAGE
133
- ? PACKAGED_CODEX_ACP_ARG
134
- : adapter.acp.packageName === CLAUDE_ACP_PACKAGE
135
- ? PACKAGED_CLAUDE_ACP_ARG
136
- : '',
173
+ adapter.acp.packageName === CODEX_ACP_PACKAGE ? import_packaged_codex_acp.PACKAGED_CODEX_ACP_ARG : adapter.acp.packageName === CLAUDE_ACP_PACKAGE ? import_packaged_claude_acp.PACKAGED_CLAUDE_ACP_ARG : ""
137
174
  );
138
175
  return { ...launch, version: adapter.acp.version };
139
176
  }
140
177
  throw new Error(`Unsupported ACP provider: ${provider}`);
141
178
  }
142
-
143
179
  function codexAcpEnvironment(options = {}) {
144
- return getProviderAdapter('codex').prepareAcpEnvironment(options);
180
+ const adapter = (0, import_provider_adapters.getProviderAdapter)("codex");
181
+ if (!adapter?.prepareAcpEnvironment) {
182
+ throw new Error("Codex ACP environment adapter is unavailable");
183
+ }
184
+ return adapter.prepareAcpEnvironment(options);
145
185
  }
146
-
147
186
  function selectedPermission(option) {
148
- return { outcome: { outcome: 'selected', optionId: option.optionId } };
187
+ return { outcome: { outcome: "selected", optionId: option.optionId } };
149
188
  }
150
-
151
189
  function withTimeout(promise, timeoutMs, label) {
152
190
  let timer;
153
191
  const timeout = new Promise((_, reject) => {
@@ -156,70 +194,144 @@ function withTimeout(promise, timeoutMs, label) {
156
194
  });
157
195
  return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
158
196
  }
159
-
160
197
  function acpErrorMessage(error) {
161
- const message = error && error.message ? error.message : String(error || 'ACP request failed');
162
- const details = error?.data?.details;
163
- return typeof details === 'string' && details && details !== message
164
- ? `${message}: ${details}`
165
- : message;
198
+ const failure = asErrorLike(error);
199
+ const message = failure.message || String(error || "ACP request failed");
200
+ const details = failure.data?.details;
201
+ return typeof details === "string" && details && details !== message ? `${message}: ${details}` : message;
166
202
  }
167
-
168
203
  function acpErrorKind(error) {
169
- const message = (error && error.message ? error.message : String(error || '')).toLowerCase();
170
- const code = String(error?.code || error?.data?.code || '').toLowerCase();
204
+ const failure = asErrorLike(error);
205
+ const message = (failure.message || String(error || "")).toLowerCase();
206
+ const code = String(failure.code || failure.data?.code || "").toLowerCase();
171
207
  const text = `${code} ${message}`;
172
- if (/\b(401|unauthorized|authentication|authenticate|login|sign[ -]?in|invalid api key)\b/.test(text)) return 'authentication';
173
- if (/\b(402|payment|billing|credit|insufficient quota)\b/.test(text)) return 'payment';
174
- if (/context (?:window|length|limit)|too many tokens|max(?:imum)? tokens/.test(text)) return 'context';
175
- if (/\b(model_not_found|unknown model|model unavailable|unsupported model)\b/.test(text)) return 'model';
176
- if (/\b(429|rate[ -]?limit|too many requests)\b/.test(text)) return 'rate-limit';
177
- if (/\b(econn|enet|ehost|socket|network|connection|timed? out|timeout|dns)\b/.test(text)) return 'network';
178
- if (/\b(protocol|json-rpc|parse error|invalid request|method not found)\b/.test(text)) return 'protocol';
179
- return 'unknown';
208
+ if (/\b(401|unauthorized|authentication|authenticate|login|sign[ -]?in|invalid api key)\b/.test(text)) return "authentication";
209
+ if (/\b(402|payment|billing|credit|insufficient quota)\b/.test(text)) return "payment";
210
+ if (/context (?:window|length|limit)|too many tokens|max(?:imum)? tokens/.test(text)) return "context";
211
+ if (/\b(model_not_found|unknown model|model unavailable|unsupported model)\b/.test(text)) return "model";
212
+ if (/\b(429|rate[ -]?limit|too many requests)\b/.test(text)) return "rate-limit";
213
+ if (/\b(econn|enet|ehost|socket|network|connection|timed? out|timeout|dns)\b/.test(text)) return "network";
214
+ if (/\b(protocol|json-rpc|parse error|invalid request|method not found)\b/.test(text)) return "protocol";
215
+ return "unknown";
180
216
  }
181
-
182
217
  function autoPermissionResponse(request, approvalMode) {
183
218
  const options = Array.isArray(request?.options) ? request.options : [];
184
- if (approvalMode === 'full') {
185
- const option = options.find(item => item.kind === 'allow_always')
186
- || options.find(item => item.kind === 'allow_once');
187
- return option ? selectedPermission(option) : { outcome: { outcome: 'cancelled' } };
219
+ if (approvalMode === "full") {
220
+ const option = options.find((item) => item.kind === "allow_always") || options.find((item) => item.kind === "allow_once");
221
+ return option ? selectedPermission(option) : { outcome: { outcome: "cancelled" } };
188
222
  }
189
- if (approvalMode === 'ask') {
190
- const option = options.find(item => item.kind === 'reject_once')
191
- || options.find(item => item.kind === 'reject_always');
192
- return option ? selectedPermission(option) : { outcome: { outcome: 'cancelled' } };
223
+ if (approvalMode === "ask") {
224
+ const option = options.find((item) => item.kind === "reject_once") || options.find((item) => item.kind === "reject_always");
225
+ return option ? selectedPermission(option) : { outcome: { outcome: "cancelled" } };
193
226
  }
194
227
  return null;
195
228
  }
196
-
229
+ const FARMING_BROWSER_SERVER_NAME = "farming-browser";
230
+ const FARMING_BROWSER_RESOURCE_TOOLS = /* @__PURE__ */ new Set([
231
+ "browser_list",
232
+ "browser_stop"
233
+ ]);
234
+ function recordValue(value) {
235
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
236
+ }
237
+ function browserApprovalSessionState(binding, request) {
238
+ const requestSessionId = String(request.sessionId || "");
239
+ if (!requestSessionId || requestSessionId === binding.sessionId) return binding.sessionState || null;
240
+ return binding.subagentStates.get(requestSessionId) || null;
241
+ }
242
+ function farmingBrowserApprovalTarget(binding, request) {
243
+ const toolCall = recordValue(request.toolCall);
244
+ const toolCallId = String(request.toolCallId || toolCall.toolCallId || "");
245
+ const sessionState = browserApprovalSessionState(binding, request);
246
+ const entry = toolCallId ? sessionState?.toolEntries?.get(toolCallId) || sessionState?.entries?.find((candidate) => candidate.id === toolCallId) : null;
247
+ const rawInput = recordValue(entry?.rawInput || toolCall.rawInput);
248
+ if (rawInput.server !== FARMING_BROWSER_SERVER_NAME) return null;
249
+ const tool = String(rawInput.tool || "");
250
+ if (!tool.startsWith("browser_")) return null;
251
+ return {
252
+ tool,
253
+ arguments: recordValue(rawInput.arguments)
254
+ };
255
+ }
256
+ function browserSiteScope(value) {
257
+ const text = String(value || "").trim();
258
+ if (!text || text === "about:blank") {
259
+ return { requiresApproval: false, scopeKey: "", site: "" };
260
+ }
261
+ try {
262
+ const url = new URL(/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(text) ? text : `https://${text}`);
263
+ if (!["http:", "https:"].includes(url.protocol) || !url.host) {
264
+ return { requiresApproval: true, scopeKey: "", site: "" };
265
+ }
266
+ return {
267
+ requiresApproval: true,
268
+ scopeKey: `site:${url.origin.toLowerCase()}`,
269
+ site: url.host.toLowerCase()
270
+ };
271
+ } catch {
272
+ return { requiresApproval: true, scopeKey: "", site: "" };
273
+ }
274
+ }
275
+ function defaultBrowserPermissionDecision(target) {
276
+ if (FARMING_BROWSER_RESOURCE_TOOLS.has(target.tool)) {
277
+ return { requiresApproval: false, scopeKey: "", site: "" };
278
+ }
279
+ if (target.tool === "browser_open" || target.tool === "browser_navigate") {
280
+ return browserSiteScope(target.arguments.url);
281
+ }
282
+ const browserId = String(target.arguments.browserId || "");
283
+ return {
284
+ requiresApproval: true,
285
+ scopeKey: browserId ? `browser:${browserId}` : "",
286
+ site: ""
287
+ };
288
+ }
289
+ function shouldAutoApproveFarmingBrowser(binding, decision) {
290
+ const scopeKey = String(decision.scopeKey || "");
291
+ if (decision.requiresApproval !== true) {
292
+ return { approve: true, scopeKey };
293
+ }
294
+ return {
295
+ approve: Boolean(scopeKey && binding.farmingBrowserApprovedSites.has(scopeKey)),
296
+ scopeKey
297
+ };
298
+ }
299
+ function automaticBrowserPermissionResponse(request) {
300
+ const options = Array.isArray(request.options) ? request.options : [];
301
+ const option = options.find((item) => item.kind === "allow_once") || options.find((item) => item.kind === "allow_always");
302
+ return option ? selectedPermission(option) : { outcome: { outcome: "cancelled" } };
303
+ }
304
+ function automaticBrowserElicitationResponse(request) {
305
+ const properties = recordValue(recordValue(request.requestedSchema).properties);
306
+ return {
307
+ action: "accept",
308
+ content: Object.prototype.hasOwnProperty.call(properties, "persist") ? { persist: "once" } : {}
309
+ };
310
+ }
197
311
  function validateElicitationContent(request, content) {
198
- if (request?.mode !== 'form') return undefined;
199
- const value = content && typeof content === 'object' && !Array.isArray(content) ? content : {};
200
- const schema = request.requestedSchema && typeof request.requestedSchema === 'object'
201
- ? request.requestedSchema
202
- : {};
203
- const properties = schema.properties && typeof schema.properties === 'object' ? schema.properties : {};
312
+ if (request?.mode !== "form") return void 0;
313
+ const value = content && typeof content === "object" && !Array.isArray(content) ? content : {};
314
+ const schema = request.requestedSchema && typeof request.requestedSchema === "object" ? request.requestedSchema : {};
315
+ const properties = schema.properties && typeof schema.properties === "object" ? schema.properties : {};
204
316
  for (const name of Array.isArray(schema.required) ? schema.required : []) {
205
317
  if (!Object.prototype.hasOwnProperty.call(value, name)) throw new Error(`ACP input is required: ${name}`);
206
318
  }
207
319
  for (const [name, fieldValue] of Object.entries(value)) {
208
320
  const property = properties[name];
209
- if (!property || typeof property !== 'object') throw new Error(`Unknown ACP input field: ${name}`);
210
- if (property.type === 'string' && typeof fieldValue !== 'string') throw new Error(`ACP input must be text: ${name}`);
211
- if (property.type === 'number' && (typeof fieldValue !== 'number' || !Number.isFinite(fieldValue))) {
321
+ if (!property || typeof property !== "object") throw new Error(`Unknown ACP input field: ${name}`);
322
+ if (property.type === "string" && typeof fieldValue !== "string") throw new Error(`ACP input must be text: ${name}`);
323
+ if (property.type === "number" && (typeof fieldValue !== "number" || !Number.isFinite(fieldValue))) {
212
324
  throw new Error(`ACP input must be a number: ${name}`);
213
325
  }
214
- if (property.type === 'integer' && !Number.isInteger(fieldValue)) throw new Error(`ACP input must be an integer: ${name}`);
215
- if (property.type === 'boolean' && typeof fieldValue !== 'boolean') throw new Error(`ACP input must be true or false: ${name}`);
216
- if (property.type === 'array' && (!Array.isArray(fieldValue) || fieldValue.some(item => typeof item !== 'string'))) {
326
+ if (property.type === "integer" && !Number.isInteger(fieldValue)) throw new Error(`ACP input must be an integer: ${name}`);
327
+ if (property.type === "boolean" && typeof fieldValue !== "boolean") throw new Error(`ACP input must be true or false: ${name}`);
328
+ if (property.type === "array" && (!Array.isArray(fieldValue) || fieldValue.some((item) => typeof item !== "string"))) {
217
329
  throw new Error(`ACP input must be a text selection: ${name}`);
218
330
  }
219
- if (typeof fieldValue === 'string') {
220
- if (Number.isFinite(property.minLength) && fieldValue.length < property.minLength) throw new Error(`ACP input is too short: ${name}`);
221
- if (Number.isFinite(property.maxLength) && fieldValue.length > property.maxLength) throw new Error(`ACP input is too long: ${name}`);
222
- if (typeof property.pattern === 'string') {
331
+ if (typeof fieldValue === "string") {
332
+ if (typeof property.minLength === "number" && Number.isFinite(property.minLength) && fieldValue.length < property.minLength) throw new Error(`ACP input is too short: ${name}`);
333
+ if (typeof property.maxLength === "number" && Number.isFinite(property.maxLength) && fieldValue.length > property.maxLength) throw new Error(`ACP input is too long: ${name}`);
334
+ if (typeof property.pattern === "string") {
223
335
  let pattern;
224
336
  try {
225
337
  pattern = new RegExp(property.pattern);
@@ -228,179 +340,161 @@ function validateElicitationContent(request, content) {
228
340
  }
229
341
  if (!pattern.test(fieldValue)) throw new Error(`ACP input has an invalid format: ${name}`);
230
342
  }
231
- const allowed = Array.isArray(property.enum)
232
- ? property.enum
233
- : Array.isArray(property.oneOf)
234
- ? property.oneOf.map(option => option?.const)
235
- : null;
343
+ const allowed = Array.isArray(property.enum) ? property.enum : Array.isArray(property.oneOf) ? property.oneOf.map((option) => option?.const) : null;
236
344
  if (allowed && !allowed.includes(fieldValue)) throw new Error(`ACP input is not an allowed choice: ${name}`);
237
345
  }
238
- if (typeof fieldValue === 'number') {
239
- if (Number.isFinite(property.minimum) && fieldValue < property.minimum) throw new Error(`ACP input is below the minimum: ${name}`);
240
- if (Number.isFinite(property.maximum) && fieldValue > property.maximum) throw new Error(`ACP input is above the maximum: ${name}`);
346
+ if (typeof fieldValue === "number") {
347
+ if (typeof property.minimum === "number" && Number.isFinite(property.minimum) && fieldValue < property.minimum) throw new Error(`ACP input is below the minimum: ${name}`);
348
+ if (typeof property.maximum === "number" && Number.isFinite(property.maximum) && fieldValue > property.maximum) throw new Error(`ACP input is above the maximum: ${name}`);
241
349
  }
242
350
  if (Array.isArray(fieldValue)) {
243
- if (Number.isFinite(property.minItems) && fieldValue.length < property.minItems) throw new Error(`ACP input needs more selections: ${name}`);
244
- if (Number.isFinite(property.maxItems) && fieldValue.length > property.maxItems) throw new Error(`ACP input has too many selections: ${name}`);
245
- const allowedItems = Array.isArray(property.items?.enum)
246
- ? property.items.enum
247
- : Array.isArray(property.items?.anyOf)
248
- ? property.items.anyOf.map(option => option?.const)
249
- : null;
250
- if (allowedItems && fieldValue.some(item => !allowedItems.includes(item))) {
351
+ if (typeof property.minItems === "number" && Number.isFinite(property.minItems) && fieldValue.length < property.minItems) throw new Error(`ACP input needs more selections: ${name}`);
352
+ if (typeof property.maxItems === "number" && Number.isFinite(property.maxItems) && fieldValue.length > property.maxItems) throw new Error(`ACP input has too many selections: ${name}`);
353
+ const allowedItems = Array.isArray(property.items?.enum) ? property.items.enum : Array.isArray(property.items?.anyOf) ? property.items.anyOf.map((option) => option?.const) : null;
354
+ if (allowedItems && fieldValue.some((item) => !allowedItems.includes(item))) {
251
355
  throw new Error(`ACP input contains an unknown selection: ${name}`);
252
356
  }
253
357
  }
254
358
  }
255
359
  return JSON.parse(JSON.stringify(value));
256
360
  }
257
-
258
- function interactiveRuntimeState(binding, fallback = '') {
259
- if (binding.pendingPermissions.size > 0) return 'waiting-for-permission';
260
- if (binding.pendingElicitations.size > 0) return 'waiting-for-input';
261
- if (binding.activeTurn?.phase === 'running') return 'working';
262
- if (binding.activeTurn?.phase === 'cancelling') return 'interrupting';
263
- if (['connecting', 'idle', 'error'].includes(String(fallback || ''))) return fallback;
264
- return binding.sessionId ? 'idle' : 'connecting';
361
+ function interactiveRuntimeState(binding, fallback = "") {
362
+ if (binding.pendingPermissions.size > 0) return "waiting-for-permission";
363
+ if (binding.pendingElicitations.size > 0) return "waiting-for-input";
364
+ if (binding.activeTurn?.phase === "running") return "working";
365
+ if (binding.activeTurn?.phase === "cancelling") return "interrupting";
366
+ if (["connecting", "idle", "error"].includes(String(fallback || ""))) return fallback;
367
+ return binding.sessionId ? "idle" : "connecting";
265
368
  }
266
-
267
369
  function clone(value) {
268
370
  return value == null ? value : JSON.parse(JSON.stringify(value));
269
371
  }
270
-
271
372
  function acpSessionRequestOptions(options = {}, cwd = process.cwd()) {
272
373
  const root = path.resolve(cwd || process.cwd());
273
- const additionalDirectories = Array.isArray(options.additionalDirectories)
274
- ? [...new Set(options.additionalDirectories
275
- .filter(directory => typeof directory === 'string' && directory.trim())
276
- .map(directory => path.resolve(root, directory)))]
277
- : [];
278
- const mcpServers = Array.isArray(options.mcpServers)
279
- ? clone(options.mcpServers.filter(server => server && typeof server === 'object' && !Array.isArray(server)))
280
- : [];
374
+ const additionalDirectories = Array.isArray(options.additionalDirectories) ? [...new Set(options.additionalDirectories.filter((directory) => typeof directory === "string" && directory.trim()).map((directory) => path.resolve(root, directory)))] : [];
375
+ const mcpServers = Array.isArray(options.mcpServers) ? clone(options.mcpServers.filter((server) => server && typeof server === "object" && !Array.isArray(server))) : [];
281
376
  const result = { cwd: root, additionalDirectories, mcpServers };
282
- if (
283
- options.provider === 'claude'
284
- && typeof options.farmingSystemPrompt === 'string'
285
- && options.farmingSystemPrompt.trim()
286
- ) {
377
+ if (options.provider === "claude" && typeof options.farmingSystemPrompt === "string" && options.farmingSystemPrompt.trim()) {
287
378
  result._meta = {
288
379
  systemPrompt: {
289
- type: 'preset',
290
- preset: 'claude_code',
291
- append: options.farmingSystemPrompt.trim(),
292
- },
380
+ type: "preset",
381
+ preset: "claude_code",
382
+ append: options.farmingSystemPrompt.trim()
383
+ }
293
384
  };
294
385
  }
295
386
  return result;
296
387
  }
297
-
298
388
  function promptContentForCapabilities(content, capabilities = {}) {
299
389
  const promptCapabilities = capabilities?.promptCapabilities || {};
300
- return (Array.isArray(content) ? content : []).flatMap(block => {
301
- if (!block || typeof block !== 'object') return [];
302
- if (!['image', 'audio'].includes(block.type)) return [clone(block)];
390
+ return (Array.isArray(content) ? content : []).flatMap((block) => {
391
+ if (!block || typeof block !== "object") return [];
392
+ if (!block.type || !["image", "audio"].includes(block.type)) return [clone(block)];
303
393
  if (promptCapabilities[block.type] === true) return [clone(block)];
304
-
305
- const label = block.type === 'audio' ? 'audio' : 'image';
306
- const attachmentPath = typeof block.path === 'string' && block.path.trim()
307
- ? path.resolve(block.path)
308
- : '';
394
+ const label = block.type === "audio" ? "audio" : "image";
395
+ const attachmentPath = typeof block.path === "string" && block.path.trim() ? path.resolve(block.path) : "";
309
396
  const name = attachmentPath ? path.basename(attachmentPath) : `attached ${label}`;
310
- const detail = attachmentPath
311
- ? `${label[0].toUpperCase()}${label.slice(1)} path: ${attachmentPath}`
312
- : `[The ACP Agent does not accept native ${label} content]`;
313
- return [{ type: 'text', text: `Attached ${label}: ${name}\n\n${detail}` }];
397
+ const detail = attachmentPath ? `${label.charAt(0).toUpperCase()}${label.slice(1)} path: ${attachmentPath}` : `[The ACP Agent does not accept native ${label} content]`;
398
+ return [{ type: "text", text: `Attached ${label}: ${name}
399
+
400
+ ${detail}` }];
314
401
  });
315
402
  }
316
-
317
- function supportsCodexSteer(capabilities = {}) {
403
+ function restoreMissingHistoryMedia(replayedState, checkpointState) {
404
+ const userEntries = (state) => state.entries.filter((entry) => entry?.type === "message" && entry.role === "user");
405
+ const entryText = (entry) => (Array.isArray(entry.content) ? entry.content : []).filter((block) => block?.type === "text").map((block) => String(block.text || "")).join("");
406
+ const replayedUsers = userEntries(replayedState);
407
+ const checkpointUsers = userEntries(checkpointState);
408
+ let restored = 0;
409
+ for (let index = 0; index < Math.min(replayedUsers.length, checkpointUsers.length); index += 1) {
410
+ const target = replayedUsers[index];
411
+ const source = checkpointUsers[index];
412
+ if (entryText(target) !== entryText(source)) continue;
413
+ const targetContent = Array.isArray(target.content) ? target.content : [];
414
+ const sourceMedia = (Array.isArray(source.content) ? source.content : []).filter((block) => block?.type === "image" || block?.type === "audio");
415
+ for (const block of sourceMedia) {
416
+ const duplicate = targetContent.some((candidate) => candidate?.type === block.type && candidate?.mimeType === block.mimeType && candidate?.data === block.data && candidate?.path === block.path);
417
+ if (duplicate) continue;
418
+ targetContent.push(clone(block));
419
+ restored += 1;
420
+ }
421
+ target.content = targetContent;
422
+ }
423
+ return restored;
424
+ }
425
+ function supportsCodexSteer(capabilities = {} = {}) {
318
426
  const capability = capabilities?._meta?.codex?.steer;
319
- return capability?.method === CODEX_STEER_METHOD
320
- && Number.isFinite(Number(capability.version))
321
- && Number(capability.version) >= 1;
427
+ return capability?.method === CODEX_STEER_METHOD && Number.isFinite(Number(capability.version)) && Number(capability.version) >= 1;
322
428
  }
323
-
324
429
  function isCodexSteerUnavailableError(error) {
430
+ const failure = asErrorLike(error);
325
431
  const text = [
326
- error?.message,
327
- error?.data?.details,
328
- error?.cause?.message,
329
- error?.cause?.data?.details,
330
- ].filter(Boolean).join(' ').toLowerCase();
331
- return text.includes('no active codex turn to steer')
332
- || text.includes('no active turn to steer')
333
- || /expected active turn id .* but found/.test(text)
334
- || text.includes('cannot steer a review turn')
335
- || text.includes('cannot steer a compact turn');
432
+ failure.message,
433
+ failure.data?.details,
434
+ failure.cause?.message,
435
+ failure.cause?.data?.details
436
+ ].filter(Boolean).join(" ").toLowerCase();
437
+ return text.includes("no active codex turn to steer") || text.includes("no active turn to steer") || /expected active turn id .* but found/.test(text) || text.includes("cannot steer a review turn") || text.includes("cannot steer a compact turn");
336
438
  }
337
-
338
439
  function childHasExited(child) {
339
- return !child
340
- || (child.exitCode !== null && child.exitCode !== undefined)
341
- || (child.signalCode !== null && child.signalCode !== undefined);
440
+ return !child || child.exitCode !== null && child.exitCode !== void 0 || child.signalCode !== null && child.signalCode !== void 0;
342
441
  }
343
-
344
442
  function processGroupHasExited(binding) {
345
- if (!binding?.ownsProcessGroup || !binding.child?.pid || process.platform === 'win32') {
443
+ if (!binding?.ownsProcessGroup || !binding.child?.pid || process.platform === "win32") {
346
444
  return childHasExited(binding?.child);
347
445
  }
348
446
  try {
349
447
  process.kill(-binding.child.pid, 0);
350
448
  return false;
351
449
  } catch (error) {
352
- return error?.code === 'ESRCH';
450
+ return asErrorLike(error).code === "ESRCH";
353
451
  }
354
452
  }
355
-
356
453
  async function waitForProcessTreeExit(binding, timeoutMs) {
357
454
  const deadline = Date.now() + timeoutMs;
358
455
  while (Date.now() <= deadline) {
359
456
  if (processGroupHasExited(binding)) return true;
360
- await new Promise(resolve => setTimeout(resolve, 25));
457
+ await new Promise((resolve) => setTimeout(resolve, 25));
361
458
  }
362
459
  return processGroupHasExited(binding);
363
460
  }
364
-
365
461
  function signalProcessTree(binding, signal) {
366
462
  if (!binding?.child || processGroupHasExited(binding)) return;
367
- if (binding.ownsProcessGroup && binding.child.pid && process.platform !== 'win32') {
463
+ if (binding.ownsProcessGroup && binding.child.pid && process.platform !== "win32") {
368
464
  try {
369
465
  process.kill(-binding.child.pid, signal);
370
466
  return;
371
467
  } catch (error) {
372
- if (error?.code === 'ESRCH') return;
468
+ if (asErrorLike(error).code === "ESRCH") return;
373
469
  }
374
470
  }
375
471
  binding.child.kill(signal);
376
472
  }
377
-
378
473
  async function stopBindingProcessAndWait(binding) {
379
474
  if (await waitForProcessTreeExit(binding, IDENTITY_ADAPTER_GRACEFUL_EXIT_MS)) return;
380
- signalProcessTree(binding, 'SIGTERM');
475
+ signalProcessTree(binding, "SIGTERM");
381
476
  if (await waitForProcessTreeExit(binding, IDENTITY_ADAPTER_TERMINATE_MS)) return;
382
- signalProcessTree(binding, 'SIGKILL');
477
+ signalProcessTree(binding, "SIGKILL");
383
478
  if (await waitForProcessTreeExit(binding, IDENTITY_ADAPTER_KILL_MS)) return;
384
- throw new Error(`ACP identity adapter process tree ${binding.child?.pid || ''} did not exit`);
479
+ throw new Error(`ACP identity adapter process tree ${binding.child?.pid || ""} did not exit`);
385
480
  }
386
-
387
481
  async function describeAcpProcessGroup(pid) {
388
482
  const processId = Number(pid);
389
- if (!Number.isSafeInteger(processId) || processId <= 0 || process.platform === 'win32') {
483
+ if (!Number.isSafeInteger(processId) || processId <= 0 || process.platform === "win32") {
390
484
  return null;
391
485
  }
392
486
  let stdout;
393
487
  try {
394
488
  ({ stdout } = await execFileAsync(
395
- '/bin/ps',
396
- ['-p', String(processId), '-o', 'pid=', '-o', 'pgid=', '-o', 'lstart='],
397
- { encoding: 'utf8', timeout: 1_000, maxBuffer: 16_384 },
489
+ "/bin/ps",
490
+ ["-p", String(processId), "-o", "pid=", "-o", "pgid=", "-o", "lstart="],
491
+ { encoding: "utf8", timeout: 1e3, maxBuffer: 16384 }
398
492
  ));
399
493
  } catch (error) {
400
- if (error?.code === 1 || error?.code === 'ESRCH') return null;
494
+ if (asErrorLike(error).code === 1 || asErrorLike(error).code === "ESRCH") return null;
401
495
  throw error;
402
496
  }
403
- const match = String(stdout || '').trim().match(/^(\d+)\s+(\d+)\s+(.+)$/);
497
+ const match = String(stdout || "").trim().match(/^(\d+)\s+(\d+)\s+(.+)$/);
404
498
  if (!match || Number(match[1]) !== processId) {
405
499
  throw new Error(`Could not read ACP process identity for pid ${processId}`);
406
500
  }
@@ -410,18 +504,12 @@ async function describeAcpProcessGroup(pid) {
410
504
  return {
411
505
  pid: processId,
412
506
  processGroupId: Number(match[2]),
413
- startedAt: match[3].trim(),
507
+ startedAt: match[3].trim()
414
508
  };
415
509
  }
416
-
417
510
  async function stopPersistedAcpProcessGroup(identity) {
418
- const expected = identity && typeof identity === 'object' ? identity : null;
419
- if (
420
- !expected
421
- || !Number.isSafeInteger(Number(expected.pid))
422
- || !Number.isSafeInteger(Number(expected.processGroupId))
423
- || !String(expected.startedAt || '').trim()
424
- ) {
511
+ const expected = identity && typeof identity === "object" ? identity : null;
512
+ if (!expected || !Number.isSafeInteger(Number(expected.pid)) || !Number.isSafeInteger(Number(expected.processGroupId)) || !String(expected.startedAt || "").trim()) {
425
513
  return { stopped: false, missingProof: true };
426
514
  }
427
515
  const processGroupId = Number(expected.processGroupId);
@@ -430,79 +518,69 @@ async function stopPersistedAcpProcessGroup(identity) {
430
518
  process.kill(-processGroupId, 0);
431
519
  return false;
432
520
  } catch (error) {
433
- return error?.code === 'ESRCH';
521
+ return asErrorLike(error).code === "ESRCH";
434
522
  }
435
523
  };
436
524
  const current = await describeAcpProcessGroup(Number(expected.pid));
437
525
  if (!current && groupHasExited()) return { stopped: true, alreadyExited: true };
438
- if (
439
- current
440
- && (
441
- current.processGroupId !== processGroupId
442
- || current.startedAt !== String(expected.startedAt)
443
- )
444
- ) {
526
+ if (current && (current.processGroupId !== processGroupId || current.startedAt !== String(expected.startedAt))) {
445
527
  return { stopped: false, identityMismatch: true };
446
528
  }
447
- const waitForExit = async timeoutMs => {
529
+ const waitForExit = async (timeoutMs) => {
448
530
  const deadline = Date.now() + timeoutMs;
449
531
  while (Date.now() <= deadline) {
450
532
  if (groupHasExited()) return true;
451
- await new Promise(resolve => setTimeout(resolve, 25));
533
+ await new Promise((resolve) => setTimeout(resolve, 25));
452
534
  }
453
535
  return groupHasExited();
454
536
  };
455
- const signal = value => {
537
+ const signal = (value) => {
456
538
  try {
457
539
  process.kill(-processGroupId, value);
458
540
  } catch (error) {
459
- if (error?.code !== 'ESRCH') throw error;
541
+ if (asErrorLike(error).code !== "ESRCH") throw error;
460
542
  }
461
543
  };
462
-
463
- signal('SIGTERM');
544
+ signal("SIGTERM");
464
545
  if (await waitForExit(IDENTITY_ADAPTER_TERMINATE_MS)) return { stopped: true };
465
- signal('SIGKILL');
546
+ signal("SIGKILL");
466
547
  if (await waitForExit(IDENTITY_ADAPTER_KILL_MS)) return { stopped: true };
467
548
  return { stopped: false, timedOut: true };
468
549
  }
469
-
470
550
  async function deleteProviderSessionIdentity(options = {}) {
471
- const provider = String(options.provider || '').trim().toLowerCase();
472
- const sessionId = String(options.sessionId || '').trim();
473
- if (!isSafeProviderSessionId(sessionId)) {
474
- throw new Error('Provider session rollback requires a safe exact session id');
551
+ const provider = String(options.provider || "").trim().toLowerCase();
552
+ const sessionId = String(options.sessionId || "").trim();
553
+ if (!(0, import_provider_session_id.isSafeProviderSessionId)(sessionId)) {
554
+ throw new Error("Provider session rollback requires a safe exact session id");
475
555
  }
476
556
  let args;
477
- if (provider === 'codex') args = ['delete', '--force', sessionId];
478
- else if (provider === 'opencode') args = ['session', 'delete', sessionId];
479
- else throw new Error(`${provider || 'Provider'} does not support identity rollback`);
480
- await execFileAsync(options.executable || getProviderAdapter(provider)?.executable, args, {
557
+ if (provider === "codex") args = ["delete", "--force", sessionId];
558
+ else if (provider === "opencode") args = ["session", "delete", sessionId];
559
+ else throw new Error(`${provider || "Provider"} does not support identity rollback`);
560
+ await execFileAsync(options.executable || (0, import_provider_adapters.getProviderAdapter)(provider)?.executable, args, {
481
561
  cwd: options.cwd,
482
562
  env: options.env,
483
- timeout: 15_000,
484
- maxBuffer: 1024 * 1024,
563
+ timeout: 15e3,
564
+ maxBuffer: 1024 * 1024
485
565
  });
486
566
  }
487
-
488
567
  function attachProviderSessionIdentity(error, identity, rollbackError) {
489
- const target = error instanceof Error ? error : new Error(String(error || 'Provider session identity failed'));
490
- Object.defineProperty(target, 'providerSessionIdentity', {
568
+ const target = error instanceof Error ? error : new Error(String(error || "Provider session identity failed"));
569
+ Object.defineProperty(target, "providerSessionIdentity", {
491
570
  value: identity,
492
571
  enumerable: false,
493
- configurable: true,
572
+ configurable: true
494
573
  });
495
574
  if (rollbackError) {
496
- Object.defineProperty(target, 'providerSessionRollbackError', {
575
+ Object.defineProperty(target, "providerSessionRollbackError", {
497
576
  value: rollbackError,
498
577
  enumerable: false,
499
- configurable: true,
578
+ configurable: true
500
579
  });
501
580
  }
502
581
  return target;
503
582
  }
504
-
505
- class AcpRuntime extends EventEmitter {
583
+ class AcpRuntime extends import_events.EventEmitter {
506
584
  constructor(options = {}) {
507
585
  super();
508
586
  this.spawn = options.spawn || spawn;
@@ -518,168 +596,173 @@ class AcpRuntime extends EventEmitter {
518
596
  this.historyReplayMaxWaitMs = options.historyReplayMaxWaitMs ?? DEFAULT_HISTORY_REPLAY_MAX_WAIT_MS;
519
597
  this.deleteProviderSessionIdentity = options.deleteProviderSessionIdentity || deleteProviderSessionIdentity;
520
598
  this.describeProcessGroup = options.describeAcpProcessGroup || describeAcpProcessGroup;
521
- this.checkpointStore = options.checkpointStore
522
- || (options.configDir ? new AcpCheckpointStore(options.configDir, options.checkpointOptions) : null);
523
- this.bindings = new Map();
599
+ this.checkpointStore = options.checkpointStore || (options.configDir ? new import_acp_checkpoint_store.AcpCheckpointStore(options.configDir, options.checkpointOptions) : null);
600
+ this.bindings = /* @__PURE__ */ new Map();
524
601
  this.disposing = false;
525
602
  this.disposePromise = null;
526
603
  this.disposed = false;
527
- this.clientFileSystem = options.clientFileSystem || new AcpClientFileSystem();
528
- this.clientTerminals = options.clientTerminals || new AcpClientTerminalManager({ spawn: options.terminalSpawn });
529
- }
530
-
604
+ this.clientFileSystem = options.clientFileSystem || new import_client_services.AcpClientFileSystem();
605
+ this.clientTerminals = options.clientTerminals || new import_client_services.AcpClientTerminalManager({ spawn: options.terminalSpawn });
606
+ this.browserPermissionDecision = typeof options.browserPermissionDecision === "function" ? options.browserPermissionDecision : (_agentId, tool, input) => defaultBrowserPermissionDecision({ tool, arguments: input });
607
+ }
608
+ /**
609
+ * @param {{
610
+ * agentId?: string,
611
+ * provider?: string,
612
+ * forkSourceSessionId?: string,
613
+ * forkSourceCheckpoint?: unknown,
614
+ * onForkSessionCreated?: (sessionId: string) => Promise<void> | void,
615
+ * [key: string]: unknown,
616
+ * }} [options]
617
+ */
531
618
  async prepareAgent(options = {}) {
532
619
  if (this.disposing || this.disposed) {
533
- throw new Error('ACP runtime is shutting down');
620
+ throw new Error("ACP runtime is shutting down");
534
621
  }
535
- const agentId = String(options.agentId || '');
536
- if (!agentId) throw new Error('ACP Agent id is required');
537
- if (this.bindings.has(agentId)) throw new Error('ACP Agent is already registered');
538
- const provider = String(options.provider || '').trim().toLowerCase();
622
+ const agentId = String(options.agentId || "");
623
+ if (!agentId) throw new Error("ACP Agent id is required");
624
+ if (this.bindings.has(agentId)) throw new Error("ACP Agent is already registered");
625
+ const provider = String(options.provider || "").trim().toLowerCase();
539
626
  const launch = this.resolveLaunch(provider, options);
540
627
  const cwd = path.resolve(options.cwd || process.cwd());
541
- const requestedSessionId = String(options.sessionId || '').trim();
542
- const forkSourceSessionId = String(options.forkSourceSessionId || '').trim();
628
+ const requestedSessionId = String(options.sessionId || "").trim();
629
+ const forkSourceSessionId = String(options.forkSourceSessionId || "").trim();
543
630
  const forkSourceCheckpoint = options.forkSourceCheckpoint || null;
544
- const forkSourceSessionCheckpoint = forkSourceCheckpoint?.version === 2
545
- ? forkSourceCheckpoint.sessionState
546
- : forkSourceCheckpoint;
547
- const revisionBase = Number.isFinite(Number(options.revisionBase))
548
- ? Math.max(0, Math.floor(Number(options.revisionBase)))
549
- : 0;
631
+ const forkSourceSessionCheckpoint = forkSourceCheckpoint?.version === 2 ? forkSourceCheckpoint.sessionState : forkSourceCheckpoint;
632
+ const revisionBase = Number.isFinite(Number(options.revisionBase)) ? Math.max(0, Math.floor(Number(options.revisionBase))) : 0;
550
633
  let forkSourceCheckpointState = null;
551
634
  if (forkSourceSessionId) {
552
635
  if (requestedSessionId) {
553
- throw new Error('ACP fork startup cannot also load a target session');
636
+ throw new Error("ACP fork startup cannot also load a target session");
554
637
  }
555
- if (!isSafeProviderSessionId(forkSourceSessionId)) {
556
- throw new Error('ACP fork startup requires a safe exact source session id');
638
+ if (!(0, import_provider_session_id.isSafeProviderSessionId)(forkSourceSessionId)) {
639
+ throw new Error("ACP fork startup requires a safe exact source session id");
557
640
  }
558
641
  if (!forkSourceCheckpoint) {
559
- throw new Error('ACP fork startup requires an exact source checkpoint');
560
- }
561
- const checkpointCwd = String(forkSourceSessionCheckpoint?.cwd || '').trim();
562
- if (
563
- String(forkSourceSessionCheckpoint?.provider || '') !== provider
564
- || String(forkSourceSessionCheckpoint?.sessionId || '') !== forkSourceSessionId
565
- || !checkpointCwd
566
- || path.resolve(checkpointCwd) !== cwd
567
- ) {
568
- throw new Error('ACP fork source checkpoint does not match the requested source');
569
- }
570
- forkSourceCheckpointState = AcpSessionState.fromCheckpoint(forkSourceSessionCheckpoint, {
642
+ throw new Error("ACP fork startup requires an exact source checkpoint");
643
+ }
644
+ const checkpointCwd = String(forkSourceSessionCheckpoint?.cwd || "").trim();
645
+ if (String(forkSourceSessionCheckpoint?.provider || "") !== provider || String(forkSourceSessionCheckpoint?.sessionId || "") !== forkSourceSessionId || !checkpointCwd || path.resolve(checkpointCwd) !== cwd) {
646
+ throw new Error("ACP fork source checkpoint does not match the requested source");
647
+ }
648
+ forkSourceCheckpointState = import_acp_session_state.AcpSessionState.fromCheckpoint(forkSourceSessionCheckpoint, {
571
649
  provider,
572
650
  sessionId: forkSourceSessionId,
573
651
  cwd,
574
- maxUpdates: this.maxUpdates,
652
+ maxUpdates: this.maxUpdates
575
653
  });
576
654
  if (!forkSourceCheckpointState) {
577
- throw new Error('ACP fork source checkpoint is invalid');
655
+ throw new Error("ACP fork source checkpoint is invalid");
578
656
  }
579
657
  }
580
658
  const sessionRequestOptions = acpSessionRequestOptions(options, cwd);
581
659
  const binding = {
582
660
  agentId,
583
661
  provider,
584
- providerHomeId: String(options.providerHomeId || 'default'),
662
+ providerHomeId: String(options.providerHomeId || "default"),
585
663
  cwd,
586
664
  sessionRequestOptions,
587
- env: (getProviderAdapter(provider)?.prepareAcpEnvironment || (value => value.env || process.env))(options),
665
+ env: ((0, import_provider_adapters.getProviderAdapter)(provider)?.prepareAcpEnvironment || ((value) => value.env || process.env))(options),
588
666
  launch,
589
667
  restartOptions: { ...options, agentId, provider },
590
- approvalMode: options.approvalMode || 'approve',
591
- ownsProcessGroup: process.platform !== 'win32',
668
+ approvalMode: options.approvalMode || "approve",
669
+ farmingBrowserApprovedSites: /* @__PURE__ */ new Set(),
670
+ farmingBrowserApprovalScopes: /* @__PURE__ */ new Map(),
671
+ ownsProcessGroup: process.platform !== "win32",
592
672
  child: null,
593
673
  connection: null,
594
674
  initializeResponse: null,
595
- sessionId: '',
596
- untrustedSessionId: '',
597
- state: 'connecting',
598
- error: '',
599
- stopReason: '',
675
+ sessionId: "",
676
+ untrustedSessionId: "",
677
+ state: "connecting",
678
+ error: "",
679
+ stopReason: "",
600
680
  modes: null,
601
681
  configOptions: [],
602
- pendingPermissions: new Map(),
603
- permissionResolvers: new Map(),
604
- pendingElicitations: new Map(),
605
- elicitationResolvers: new Map(),
606
- activeElicitations: new Map(),
607
- subagentStates: new Map(),
608
- subagentControls: new Map(),
682
+ pendingPermissions: /* @__PURE__ */ new Map(),
683
+ permissionResolvers: /* @__PURE__ */ new Map(),
684
+ pendingElicitations: /* @__PURE__ */ new Map(),
685
+ elicitationResolvers: /* @__PURE__ */ new Map(),
686
+ activeElicitations: /* @__PURE__ */ new Map(),
687
+ subagentStates: /* @__PURE__ */ new Map(),
688
+ subagentControls: /* @__PURE__ */ new Map(),
609
689
  nextSubagentGeneration: 1,
610
- interactionOrigins: new Map(),
690
+ interactionOrigins: /* @__PURE__ */ new Map(),
611
691
  // One binding owns at most one Turn. All Turn controls and its terminal
612
692
  // commit are fenced by this object before they may mutate shared state.
613
693
  activeTurn: null,
614
694
  nextTurnId: 1,
615
695
  supportsSteer: false,
616
696
  historyReplayActive: false,
617
- sessionState: null,
697
+ sessionState: new import_acp_session_state.AcpSessionState({
698
+ provider,
699
+ sessionId: "",
700
+ cwd,
701
+ maxUpdates: this.maxUpdates
702
+ }),
618
703
  authTerminal: null,
619
- patchDecisions: new Map(),
620
- patchDecisionInFlight: new Map(),
704
+ patchDecisions: /* @__PURE__ */ new Map(),
705
+ patchDecisionInFlight: /* @__PURE__ */ new Map(),
621
706
  checkpointProof: null,
622
707
  sessionMutation: null,
623
708
  configMutationTail: null,
624
- stderr: '',
709
+ deferredConfigChanges: /* @__PURE__ */ new Map(),
710
+ deferredConfigFlush: null,
711
+ deferredModeGeneration: 0,
712
+ deferredModeId: "",
713
+ stderr: "",
625
714
  exited: false,
626
- updatedAt: new Date().toISOString(),
715
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
627
716
  };
628
717
  this.bindings.set(agentId, binding);
629
718
  this.emitRuntime(binding);
630
-
631
719
  try {
632
- const gatedLaunch = binding.ownsProcessGroup
633
- ? {
634
- command: '/bin/sh',
635
- args: [
636
- '-c',
637
- 'IFS= read -r farming_acp_start || exit 0; exec "$@"',
638
- 'farming-acp-start-gate',
639
- launch.command,
640
- ...launch.args,
641
- ],
642
- }
643
- : launch;
720
+ const gatedLaunch = binding.ownsProcessGroup ? {
721
+ command: "/bin/sh",
722
+ args: [
723
+ "-c",
724
+ 'IFS= read -r farming_acp_start || exit 0; exec "$@"',
725
+ "farming-acp-start-gate",
726
+ launch.command,
727
+ ...launch.args
728
+ ]
729
+ } : launch;
644
730
  const child = this.spawn(gatedLaunch.command, gatedLaunch.args, {
645
731
  cwd: binding.cwd,
646
732
  env: binding.env,
647
- stdio: ['pipe', 'pipe', 'pipe'],
648
- detached: binding.ownsProcessGroup,
733
+ stdio: ["pipe", "pipe", "pipe"],
734
+ detached: binding.ownsProcessGroup
649
735
  });
650
736
  binding.child = child;
651
- child.stderr.on('data', chunk => {
652
- binding.stderr = `${binding.stderr}${chunk.toString('utf8')}`.slice(-16_000);
737
+ child.stderr.on("data", (chunk) => {
738
+ binding.stderr = `${binding.stderr}${chunk.toString("utf8")}`.slice(-16e3);
653
739
  });
654
- child.on('error', error => this.handleExit(binding, error));
655
- child.on('close', (code, signal) => {
740
+ child.on("error", (error) => this.handleExit(binding, error));
741
+ child.on("close", (code, signal) => {
656
742
  if (!binding.connection?.signal?.aborted) {
657
- const detail = binding.stderr.trim() || `ACP adapter exited with code ${code}${signal ? ` (${signal})` : ''}`;
743
+ const detail = binding.stderr.trim() || `ACP adapter exited with code ${code}${signal ? ` (${signal})` : ""}`;
658
744
  this.handleExit(binding, code === 0 ? null : new Error(detail));
659
745
  }
660
746
  });
661
- if (binding.ownsProcessGroup && typeof options.onProcessStarted === 'function') {
747
+ if (binding.ownsProcessGroup && typeof options.onProcessStarted === "function") {
662
748
  const processIdentity = await this.describeProcessGroup(child.pid);
663
749
  if (!processIdentity) {
664
- throw new Error(`ACP process ${child.pid || ''} exited before its identity was persisted`);
750
+ throw new Error(`ACP process ${child.pid || ""} exited before its identity was persisted`);
665
751
  }
666
752
  await options.onProcessStarted(processIdentity);
667
753
  }
668
754
  if (binding.ownsProcessGroup) {
669
755
  await new Promise((resolve, reject) => {
670
- child.stdin.write('start\n', error => {
756
+ child.stdin.write("start\n", (error) => {
671
757
  if (error) reject(error);
672
758
  else resolve();
673
759
  });
674
760
  });
675
761
  }
676
-
677
- const connection = this.createConnection
678
- ? await this.createConnection(this.clientHandlers(binding), child, binding)
679
- : await this.officialConnection(this.clientHandlers(binding), child);
762
+ const connection = this.createConnection ? await this.createConnection(this.clientHandlers(binding), child, binding) : await this.officialConnection(this.clientHandlers(binding), child);
680
763
  binding.connection = connection;
681
764
  this.requireOpenBinding(binding);
682
- connection.closed.catch(error => this.handleExit(binding, error));
765
+ connection.closed.catch((error) => this.handleExit(binding, error));
683
766
  const sdk = await loadAcpSdk();
684
767
  this.requireOpenBinding(binding);
685
768
  binding.initializeResponse = await withTimeout(connection.initialize({
@@ -691,20 +774,18 @@ class AcpRuntime extends EventEmitter {
691
774
  session: { configOptions: { boolean: {} } },
692
775
  plan: {},
693
776
  elicitation: { form: {}, url: {} },
694
- _meta: { terminal_output: true },
777
+ _meta: { terminal_output: true }
695
778
  },
696
- clientInfo: { name: 'farming', title: 'Farming', version: packageJson.version || '0.0.0' },
697
- }), this.initializeTimeoutMs, 'ACP initialize');
779
+ clientInfo: { name: "farming", title: "Farming", version: packageJson.version || "0.0.0" }
780
+ }), this.initializeTimeoutMs, "ACP initialize");
698
781
  this.requireOpenBinding(binding);
699
782
  if (binding.initializeResponse.protocolVersion !== sdk.PROTOCOL_VERSION) {
700
783
  throw new Error(`ACP protocol version mismatch: Agent selected ${binding.initializeResponse.protocolVersion}, Farming supports ${sdk.PROTOCOL_VERSION}`);
701
784
  }
702
- binding.supportsSteer = binding.provider === 'codex'
703
- && supportsCodexSteer(binding.initializeResponse.agentCapabilities);
704
-
785
+ binding.supportsSteer = binding.provider === "codex" && supportsCodexSteer(binding.initializeResponse.agentCapabilities);
705
786
  const sessionRequest = { sessionId: requestedSessionId, ...binding.sessionRequestOptions };
706
787
  let sessionResponse;
707
- let historyMode = 'new';
788
+ let historyMode = "new";
708
789
  if (forkSourceSessionId) {
709
790
  const capabilities = binding.initializeResponse.agentCapabilities || {};
710
791
  if (!capabilities.loadSession || !capabilities.sessionCapabilities?.fork) {
@@ -714,12 +795,12 @@ class AcpRuntime extends EventEmitter {
714
795
  throw new Error(`${provider} ACP Agent cannot release the loaded fork source`);
715
796
  }
716
797
  binding.sessionId = forkSourceSessionId;
717
- binding.sessionState = new AcpSessionState({
798
+ binding.sessionState = new import_acp_session_state.AcpSessionState({
718
799
  provider,
719
800
  sessionId: forkSourceSessionId,
720
801
  cwd: binding.cwd,
721
802
  maxUpdates: this.maxUpdates,
722
- revisionBase,
803
+ revisionBase
723
804
  });
724
805
  binding.historyReplayActive = true;
725
806
  let loadedSource;
@@ -727,10 +808,10 @@ class AcpRuntime extends EventEmitter {
727
808
  loadedSource = await withTimeout(
728
809
  connection.loadSession({ sessionId: forkSourceSessionId, ...binding.sessionRequestOptions }),
729
810
  this.sessionSetupTimeoutMs,
730
- 'ACP fork source session/load',
811
+ "ACP fork source session/load"
731
812
  );
732
813
  this.requireOpenBinding(binding);
733
- if (provider === 'qoder') await this.waitForHistoryReplay(binding);
814
+ if (provider === "qoder") await this.waitForHistoryReplay(binding);
734
815
  this.requireOpenBinding(binding);
735
816
  } finally {
736
817
  binding.historyReplayActive = false;
@@ -739,34 +820,31 @@ class AcpRuntime extends EventEmitter {
739
820
  const forked = await withTimeout(
740
821
  connection.unstable_forkSession({
741
822
  sessionId: forkSourceSessionId,
742
- ...binding.sessionRequestOptions,
823
+ ...binding.sessionRequestOptions
743
824
  }),
744
825
  this.sessionSetupTimeoutMs,
745
- 'ACP owned session/fork',
826
+ "ACP owned session/fork"
746
827
  );
747
- const forkedSessionId = String(forked?.sessionId || '').trim();
748
- if (
749
- !isSafeProviderSessionId(forkedSessionId)
750
- || forkedSessionId === forkSourceSessionId
751
- ) {
752
- throw new Error('ACP owned session/fork returned an invalid new session id');
828
+ const forkedSessionId = String(forked?.sessionId || "").trim();
829
+ if (!(0, import_provider_session_id.isSafeProviderSessionId)(forkedSessionId) || forkedSessionId === forkSourceSessionId) {
830
+ throw new Error("ACP owned session/fork returned an invalid new session id");
753
831
  }
754
- if (typeof options.onForkSessionCreated === 'function') {
832
+ if (typeof options.onForkSessionCreated === "function") {
755
833
  await options.onForkSessionCreated(forkedSessionId);
756
834
  }
757
835
  this.requireOpenBinding(binding);
758
836
  await withTimeout(
759
837
  connection.closeSession({ sessionId: forkSourceSessionId }),
760
838
  this.requestTimeoutMs,
761
- 'ACP fork source session/close',
839
+ "ACP fork source session/close"
762
840
  );
763
841
  this.requireOpenBinding(binding);
764
842
  const forkUpdates = binding.subagentStates.get(forkedSessionId);
765
843
  const restoredForkSource = this.restoreBindingCheckpoint(binding, forkSourceCheckpoint, {
766
- sessionId: forkedSessionId,
844
+ sessionId: forkedSessionId
767
845
  });
768
846
  if (!restoredForkSource) {
769
- throw new Error('ACP fork source checkpoint could not be restored');
847
+ throw new Error("ACP fork source checkpoint could not be restored");
770
848
  }
771
849
  binding.sessionId = forkedSessionId;
772
850
  binding.sessionState = restoredForkSource.sessionState;
@@ -776,7 +854,9 @@ class AcpRuntime extends EventEmitter {
776
854
  delete binding.restartOptions.forkSourceSessionId;
777
855
  delete binding.restartOptions.forkSourceCheckpoint;
778
856
  delete binding.restartOptions.onForkSessionCreated;
779
- if (forkUpdates?.updates?.some(item => item?.update?.sessionUpdate === 'available_commands_update')) {
857
+ if (forkUpdates?.updates?.some(
858
+ (item) => recordValue(item?.update).sessionUpdate === "available_commands_update"
859
+ )) {
780
860
  binding.sessionState.availableCommands = clone(forkUpdates.availableCommands);
781
861
  }
782
862
  sessionResponse = {
@@ -784,32 +864,36 @@ class AcpRuntime extends EventEmitter {
784
864
  ...forked,
785
865
  sessionId: forkedSessionId,
786
866
  modes: forked?.modes || loadedSource?.modes,
787
- configOptions: forked?.configOptions || loadedSource?.configOptions,
867
+ configOptions: forked?.configOptions || loadedSource?.configOptions
788
868
  };
789
- historyMode = 'fork';
869
+ historyMode = "fork";
790
870
  } else if (requestedSessionId) {
791
871
  const capabilities = binding.initializeResponse.agentCapabilities || {};
792
872
  let opened = false;
793
873
  let restoredCheckpointState = null;
794
874
  let restoredCheckpoint = null;
795
875
  let saved = null;
796
- if (options.historyMode === 'checkpoint' && this.checkpointStore) {
876
+ if (options.historyMode === "checkpoint" && this.checkpointStore) {
797
877
  saved = await this.checkpointStore.load(
798
878
  this.checkpointIdentity(binding, requestedSessionId),
799
- { allowDirty: true },
879
+ { allowDirty: true }
800
880
  );
801
881
  this.requireOpenBinding(binding);
802
- restoredCheckpoint = this.restoreBindingCheckpoint(binding, saved?.state, {
803
- sessionId: requestedSessionId,
804
- });
882
+ restoredCheckpoint = this.restoreBindingCheckpoint(
883
+ binding,
884
+ recordValue(saved?.state),
885
+ { sessionId: requestedSessionId }
886
+ );
805
887
  restoredCheckpointState = restoredCheckpoint?.sessionState || null;
888
+ if (restoredCheckpoint?.deferredConfigChanges instanceof Map) {
889
+ binding.deferredConfigChanges = restoredCheckpoint.deferredConfigChanges;
890
+ }
891
+ binding.deferredModeId = String(restoredCheckpoint?.deferredModeId || "");
806
892
  }
807
893
  if (capabilities.sessionCapabilities?.resume && restoredCheckpoint) {
808
- const providerStateMatches = restoredCheckpoint?.complete === true && saved?.exact === true
809
- ? await this.checkpointMatchesProviderSession(connection, capabilities, sessionRequest, saved)
810
- : false;
894
+ const providerStateMatches = restoredCheckpoint?.complete === true && saved?.exact === true ? await this.checkpointMatchesProviderSession(connection, capabilities, sessionRequest, saved) : false;
811
895
  this.requireOpenBinding(binding);
812
- if (providerStateMatches) {
896
+ if (providerStateMatches && restoredCheckpointState) {
813
897
  binding.sessionId = requestedSessionId;
814
898
  binding.sessionState = restoredCheckpointState;
815
899
  binding.subagentStates = restoredCheckpoint.subagentStates;
@@ -820,75 +904,65 @@ class AcpRuntime extends EventEmitter {
820
904
  sessionResponse = await withTimeout(
821
905
  connection.resumeSession(sessionRequest),
822
906
  this.sessionSetupTimeoutMs,
823
- 'ACP session/resume'
907
+ "ACP session/resume"
824
908
  );
825
909
  this.requireOpenBinding(binding);
826
- historyMode = 'checkpoint';
910
+ historyMode = "checkpoint";
827
911
  opened = true;
828
912
  } catch (error) {
829
913
  this.requireOpenBinding(binding);
830
914
  if (!capabilities.loadSession) throw error;
831
- console.warn(`ACP checkpoint resume failed for ${provider}; replaying history:`, error && (error.message || error));
915
+ console.warn(`ACP checkpoint resume failed for ${provider}; replaying history:`, asErrorLike(error).message || error);
832
916
  }
833
917
  }
834
918
  }
835
- if (!opened && options.historyMode !== 'resume' && capabilities.loadSession) {
919
+ if (!opened && options.historyMode !== "resume" && capabilities.loadSession) {
836
920
  const replayRevisionBase = Math.max(revisionBase, Number(restoredCheckpointState?.revision || 0));
837
921
  binding.sessionId = requestedSessionId;
838
- binding.sessionState = new AcpSessionState({
922
+ binding.sessionState = new import_acp_session_state.AcpSessionState({
839
923
  provider,
840
924
  sessionId: requestedSessionId,
841
925
  cwd: binding.cwd,
842
926
  maxUpdates: this.maxUpdates,
843
927
  revisionBase: replayRevisionBase,
844
- resetBeforeRevision: replayRevisionBase,
928
+ resetBeforeRevision: replayRevisionBase
845
929
  });
846
930
  binding.historyReplayActive = true;
847
931
  try {
848
932
  sessionResponse = await withTimeout(
849
933
  connection.loadSession(sessionRequest),
850
934
  this.sessionSetupTimeoutMs,
851
- 'ACP session/load'
935
+ "ACP session/load"
852
936
  );
853
937
  this.requireOpenBinding(binding);
854
- if (provider === 'qoder') await this.waitForHistoryReplay(binding);
938
+ if (provider === "qoder") await this.waitForHistoryReplay(binding);
855
939
  this.requireOpenBinding(binding);
856
940
  } finally {
857
941
  binding.historyReplayActive = false;
858
942
  }
859
943
  binding.sessionState.finishHistoryReplay();
860
- if (provider === 'codex' && binding.sessionState.hasCodexHistoryImageReferences()) {
861
- let imageDataByPath = new Map();
862
- try {
863
- imageDataByPath = await readCodexHistoryImageData(requestedSessionId, {
864
- codexHome: binding.env.CODEX_HOME,
865
- });
866
- } catch {
867
- // Local history images can still be restored from their adapter paths.
868
- }
869
- this.requireOpenBinding(binding);
870
- await binding.sessionState.hydrateCodexHistoryAttachments({ imageDataByPath });
871
- this.requireOpenBinding(binding);
944
+ if (provider === "qoder" && restoredCheckpointState) {
945
+ restoreMissingHistoryMedia(binding.sessionState, restoredCheckpointState);
872
946
  }
873
947
  this.restorePatchDecisions(binding, restoredCheckpoint?.patchDecisions);
874
- historyMode = 'load';
948
+ historyMode = "load";
875
949
  opened = true;
876
950
  } else if (!opened && capabilities.sessionCapabilities?.resume) {
877
951
  binding.sessionId = requestedSessionId;
878
- binding.sessionState = new AcpSessionState({
952
+ binding.sessionState = new import_acp_session_state.AcpSessionState({
879
953
  provider,
880
954
  sessionId: requestedSessionId,
881
955
  cwd: binding.cwd,
882
956
  maxUpdates: this.maxUpdates,
883
- revisionBase,
957
+ revisionBase
884
958
  });
885
959
  sessionResponse = await withTimeout(
886
960
  connection.resumeSession(sessionRequest),
887
961
  this.sessionSetupTimeoutMs,
888
- 'ACP session/resume'
962
+ "ACP session/resume"
889
963
  );
890
964
  this.requireOpenBinding(binding);
891
- historyMode = 'resume';
965
+ historyMode = "resume";
892
966
  opened = true;
893
967
  } else {
894
968
  if (!opened) throw new Error(`${provider} ACP Agent cannot load or resume session ${requestedSessionId}`);
@@ -897,75 +971,89 @@ class AcpRuntime extends EventEmitter {
897
971
  sessionResponse = await withTimeout(
898
972
  connection.newSession(binding.sessionRequestOptions),
899
973
  this.sessionSetupTimeoutMs,
900
- 'ACP session/new'
974
+ "ACP session/new"
901
975
  );
902
976
  this.requireOpenBinding(binding);
903
- const returnedSessionId = String(sessionResponse.sessionId || '').trim();
904
- if (!isSafeProviderSessionId(returnedSessionId)) {
977
+ const returnedSessionId = String(sessionResponse.sessionId || "").trim();
978
+ if (!(0, import_provider_session_id.isSafeProviderSessionId)(returnedSessionId)) {
905
979
  binding.untrustedSessionId = returnedSessionId;
906
- throw new Error('ACP session/new returned an invalid resumable session id');
980
+ throw new Error("ACP session/new returned an invalid resumable session id");
907
981
  }
908
982
  binding.sessionId = returnedSessionId;
909
- binding.sessionState = new AcpSessionState({ provider, sessionId: binding.sessionId, cwd: binding.cwd, maxUpdates: this.maxUpdates });
983
+ binding.sessionState = new import_acp_session_state.AcpSessionState({ provider, sessionId: binding.sessionId, cwd: binding.cwd, maxUpdates: this.maxUpdates });
910
984
  }
911
985
  this.requireOpenBinding(binding);
912
986
  binding.modes = sessionResponse?.modes || null;
913
987
  binding.configOptions = sessionResponse?.configOptions || [];
914
- binding.sessionState.currentModeId = String(binding.modes?.currentModeId || '');
988
+ binding.sessionState.currentModeId = String(binding.modes?.currentModeId || "");
915
989
  binding.sessionState.configOptions = JSON.parse(JSON.stringify(binding.configOptions));
916
- if (provider === 'codex' && options.serviceTier && options.serviceTier !== 'config') {
917
- const fastOption = binding.configOptions.find(option => (
918
- option.type === 'boolean'
919
- && /fast/i.test(`${option.id || ''} ${option.name || ''} ${option.category || ''}`)
920
- ));
921
- const fastEnabled = ['fast', 'priority'].includes(options.serviceTier);
990
+ if (provider === "claude" && historyMode === "new") {
991
+ const changes = [];
992
+ if (options.model && options.model !== "config") {
993
+ const modelOption = binding.configOptions.find((option) => option.type === "select" && (option.category === "model" || /(^|[\s_-])model([\s_-]|$)/i.test(`${option.id} ${option.name || ""}`)));
994
+ if (!modelOption) {
995
+ throw new Error("Claude ACP Agent did not advertise a Model configuration option");
996
+ }
997
+ changes.push({ configId: modelOption.id, value: options.model });
998
+ }
999
+ if (options.reasoningEffort && options.reasoningEffort !== "config") {
1000
+ const reasoningOption = binding.configOptions.find((option) => option.type === "select" && (option.category === "thought_level" || /(reasoning|thought|effort)/i.test(`${option.id} ${option.name || ""}`)));
1001
+ if (!reasoningOption) {
1002
+ throw new Error("Claude ACP Agent did not advertise a Reasoning configuration option");
1003
+ }
1004
+ changes.push({ configId: reasoningOption.id, value: options.reasoningEffort });
1005
+ }
1006
+ if (changes.length > 0) await this.applySessionConfigOptionsNow(binding, changes);
1007
+ }
1008
+ if (provider === "codex" && options.serviceTier && options.serviceTier !== "config") {
1009
+ const fastOption = binding.configOptions.find((option) => option.type === "boolean" && /fast/i.test(`${option.id || ""} ${option.name || ""} ${option.category || ""}`));
1010
+ const fastEnabled = ["fast", "priority"].includes(options.serviceTier);
922
1011
  if (fastOption && fastOption.currentValue !== fastEnabled) {
923
1012
  await this.applySessionConfigOption(binding, fastOption.id, fastEnabled, { emit: false });
924
1013
  }
925
1014
  }
926
1015
  this.requireOpenBinding(binding);
927
- binding.state = 'idle';
928
- binding.updatedAt = new Date().toISOString();
1016
+ binding.state = "idle";
1017
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
929
1018
  this.scheduleCheckpoint(binding, { exact: true });
930
1019
  this.emitRuntime(binding);
931
1020
  this.emitSession(binding);
1021
+ void this.flushDeferredSessionChanges(binding);
932
1022
  return {
933
1023
  sessionId: binding.sessionId,
934
1024
  historyMode,
935
1025
  protocolVersion: binding.initializeResponse.protocolVersion,
936
1026
  agentInfo: binding.initializeResponse.agentInfo || null,
937
1027
  capabilities: binding.initializeResponse.agentCapabilities || {},
938
- adapter: launch,
1028
+ adapter: launch
939
1029
  };
940
1030
  } catch (error) {
941
1031
  const runtimeError = new Error(acpErrorMessage(error), { cause: error });
942
1032
  this.handleExit(binding, runtimeError);
943
1033
  if (options.identityOnly === true) {
944
1034
  const returnedIdentity = binding.sessionId || binding.untrustedSessionId;
945
- const identity = returnedIdentity
946
- ? {
947
- provider,
948
- executable: options.executable || getProviderAdapter(provider)?.executable,
949
- env: binding.env,
950
- cwd: binding.cwd,
951
- sessionId: returnedIdentity,
952
- producerStopped: false,
953
- }
954
- : null;
1035
+ const identity = returnedIdentity ? {
1036
+ provider,
1037
+ executable: options.executable || (0, import_provider_adapters.getProviderAdapter)(provider)?.executable,
1038
+ env: binding.env,
1039
+ cwd: binding.cwd,
1040
+ sessionId: returnedIdentity,
1041
+ producerStopped: false
1042
+ } : null;
955
1043
  let producerStopped = false;
956
1044
  try {
957
1045
  await this.unregisterAgentAndWait(agentId);
958
1046
  producerStopped = true;
959
1047
  if (identity) identity.producerStopped = true;
960
1048
  } catch (cleanupError) {
961
- Object.defineProperty(runtimeError, 'adapterCleanupError', {
1049
+ Object.defineProperty(runtimeError, "adapterCleanupError", {
962
1050
  value: cleanupError,
963
1051
  enumerable: false,
964
- configurable: true,
1052
+ configurable: true
965
1053
  });
966
1054
  if (identity) attachProviderSessionIdentity(runtimeError, identity);
967
1055
  }
968
- if (identity && producerStopped && isSafeProviderSessionId(identity.sessionId)) {
1056
+ if (identity && producerStopped && (0, import_provider_session_id.isSafeProviderSessionId)(identity.sessionId)) {
969
1057
  try {
970
1058
  await this.deleteProviderSessionIdentity(identity);
971
1059
  } catch (rollbackError) {
@@ -983,42 +1071,39 @@ class AcpRuntime extends EventEmitter {
983
1071
  try {
984
1072
  binding.connection?.close();
985
1073
  } catch {
986
- // Process-tree cleanup below remains authoritative.
987
1074
  }
988
1075
  await stopBindingProcessAndWait(binding);
989
1076
  runtimeCleanupVerified = true;
990
1077
  }
991
1078
  } catch (cleanupError) {
992
- Object.defineProperty(runtimeError, 'adapterCleanupError', {
1079
+ Object.defineProperty(runtimeError, "adapterCleanupError", {
993
1080
  value: cleanupError,
994
1081
  enumerable: false,
995
- configurable: true,
1082
+ configurable: true
996
1083
  });
997
1084
  }
998
1085
  Object.defineProperties(runtimeError, {
999
1086
  runtimeCleanupAttempted: {
1000
1087
  value: true,
1001
1088
  enumerable: false,
1002
- configurable: true,
1089
+ configurable: true
1003
1090
  },
1004
1091
  runtimeCleanupVerified: {
1005
1092
  value: runtimeCleanupVerified === true,
1006
1093
  enumerable: false,
1007
- configurable: true,
1008
- },
1094
+ configurable: true
1095
+ }
1009
1096
  });
1010
1097
  if (!runtimeCleanupVerified && !this.isCurrentBinding(binding)) {
1011
1098
  try {
1012
1099
  binding.connection?.close();
1013
1100
  } catch {
1014
- // The detached binding remains only as an error cleanup handle.
1015
1101
  }
1016
1102
  }
1017
1103
  }
1018
1104
  throw runtimeError;
1019
1105
  }
1020
1106
  }
1021
-
1022
1107
  async createSessionIdentity(options = {}) {
1023
1108
  const agentId = `provider-session-${crypto.randomUUID()}`;
1024
1109
  let prepared = null;
@@ -1030,25 +1115,24 @@ class AcpRuntime extends EventEmitter {
1030
1115
  ...options,
1031
1116
  agentId,
1032
1117
  identityOnly: true,
1033
- sessionId: '',
1118
+ sessionId: ""
1034
1119
  });
1035
1120
  const binding = this.requireBinding(agentId);
1036
1121
  identity = {
1037
- provider: String(options.provider || '').trim().toLowerCase(),
1038
- executable: options.executable || getProviderAdapter(options.provider)?.executable,
1122
+ provider: String(options.provider || "").trim().toLowerCase(),
1123
+ executable: options.executable || (0, import_provider_adapters.getProviderAdapter)(options.provider)?.executable,
1039
1124
  env: binding.env,
1040
1125
  cwd: binding.cwd,
1041
1126
  sessionId: prepared.sessionId,
1042
- producerStopped: false,
1127
+ producerStopped: false
1043
1128
  };
1044
1129
  result = {
1045
1130
  ...prepared,
1046
- sessionRequestOptions: this.getSessionRequestOptions(agentId),
1131
+ sessionRequestOptions: this.getSessionRequestOptions(agentId)
1047
1132
  };
1048
1133
  } catch (error) {
1049
- failure = error instanceof Error ? error : new Error(String(error || 'Provider session identity failed'));
1134
+ failure = error instanceof Error ? error : new Error(String(error || "Provider session identity failed"));
1050
1135
  }
1051
-
1052
1136
  if (prepared) {
1053
1137
  let producerStopped = false;
1054
1138
  try {
@@ -1057,14 +1141,12 @@ class AcpRuntime extends EventEmitter {
1057
1141
  if (identity) identity.producerStopped = true;
1058
1142
  } catch (cleanupError) {
1059
1143
  if (!failure) {
1060
- failure = cleanupError instanceof Error
1061
- ? cleanupError
1062
- : new Error(String(cleanupError || 'ACP identity adapter cleanup failed'));
1144
+ failure = cleanupError instanceof Error ? cleanupError : new Error(String(cleanupError || "ACP identity adapter cleanup failed"));
1063
1145
  } else {
1064
- Object.defineProperty(failure, 'adapterCleanupError', {
1146
+ Object.defineProperty(failure, "adapterCleanupError", {
1065
1147
  value: cleanupError,
1066
1148
  enumerable: false,
1067
- configurable: true,
1149
+ configurable: true
1068
1150
  });
1069
1151
  }
1070
1152
  if (identity) failure = attachProviderSessionIdentity(failure, identity);
@@ -1078,88 +1160,143 @@ class AcpRuntime extends EventEmitter {
1078
1160
  }
1079
1161
  }
1080
1162
  if (failure) throw failure;
1163
+ if (!result) {
1164
+ throw new Error("Provider session identity completed without a result");
1165
+ }
1081
1166
  return result;
1082
1167
  }
1083
-
1084
1168
  isCurrentBinding(binding) {
1085
1169
  return Boolean(binding) && this.bindings.get(binding.agentId) === binding;
1086
1170
  }
1087
-
1088
1171
  requireCurrentBinding(binding) {
1089
1172
  if (!this.isCurrentBinding(binding)) {
1090
- throw new Error('ACP Agent binding is no longer active');
1173
+ throw new Error("ACP Agent binding is no longer active");
1091
1174
  }
1092
1175
  return binding;
1093
1176
  }
1094
-
1095
1177
  isOpenBinding(binding) {
1096
1178
  return this.isCurrentBinding(binding) && binding.exited !== true;
1097
1179
  }
1098
-
1099
1180
  requireOpenBinding(binding) {
1100
- if (this.disposing || this.disposed) throw new Error('ACP runtime is shutting down');
1181
+ if (this.disposing || this.disposed) throw new Error("ACP runtime is shutting down");
1101
1182
  this.requireCurrentBinding(binding);
1102
- if (binding.exited) throw new Error('ACP Agent connection is closed');
1183
+ if (binding.exited) throw new Error("ACP Agent connection is closed");
1103
1184
  return binding;
1104
1185
  }
1105
-
1106
1186
  isCurrentTurn(binding, turn) {
1107
1187
  return this.isOpenBinding(binding) && binding.activeTurn === turn;
1108
1188
  }
1109
-
1110
1189
  requireCurrentTurn(binding, turn, phases = null) {
1111
1190
  this.requireOpenBinding(binding);
1112
- if (
1113
- binding.activeTurn !== turn
1114
- || (Array.isArray(phases) && !phases.includes(turn?.phase))
1115
- ) {
1116
- throw new Error('No active Codex turn to steer');
1191
+ if (binding.activeTurn !== turn || Array.isArray(phases) && !phases.includes(turn?.phase)) {
1192
+ throw new Error("No active Codex turn to steer");
1117
1193
  }
1118
- return turn;
1119
1194
  }
1120
-
1121
1195
  beginTurn(binding) {
1122
1196
  this.requireOpenBinding(binding);
1123
1197
  if (binding.activeTurn) throw new Error(`ACP Agent is not ready (${binding.state})`);
1124
1198
  let resolveCompletion;
1125
- const completion = new Promise(resolve => {
1199
+ const completion = new Promise((resolve) => {
1126
1200
  resolveCompletion = resolve;
1127
1201
  });
1128
1202
  const turn = {
1129
1203
  id: binding.nextTurnId++,
1130
- phase: 'admitting',
1204
+ phase: "admitting",
1131
1205
  previousState: binding.state,
1132
1206
  providerSettled: false,
1133
1207
  controlTail: Promise.resolve(),
1134
1208
  cancelPromise: null,
1135
1209
  completion,
1136
- resolveCompletion,
1210
+ resolveCompletion
1137
1211
  };
1138
1212
  binding.activeTurn = turn;
1139
1213
  return turn;
1140
1214
  }
1141
-
1142
1215
  finishTurn(binding, turn, result) {
1143
1216
  if (binding.activeTurn !== turn) return false;
1144
1217
  binding.activeTurn = null;
1145
- turn.phase = 'completed';
1146
- turn.resolveCompletion(result);
1218
+ turn.phase = "completed";
1219
+ turn.resolveCompletion?.(result);
1220
+ void this.flushDeferredSessionChanges(binding);
1221
+ return true;
1222
+ }
1223
+ async flushDeferredSessionChanges(binding) {
1224
+ if (!this.isOpenBinding(binding) || binding.activeTurn || binding.deferredConfigFlush || !binding.deferredModeId && binding.deferredConfigChanges.size === 0) return;
1225
+ const modeId = binding.deferredModeId;
1226
+ const modeGeneration = binding.deferredModeGeneration;
1227
+ const originalModeId = String(binding.sessionState?.currentModeId || binding.modes?.currentModeId || "");
1228
+ const changes = [...binding.deferredConfigChanges.values()];
1229
+ const flush = this.enqueueSessionConfigMutation(binding, async () => {
1230
+ let modeApplied = false;
1231
+ try {
1232
+ if (modeId) {
1233
+ await this.setSessionModeNow(binding, modeId);
1234
+ modeApplied = true;
1235
+ }
1236
+ if (changes.length > 0) await this.setSessionConfigOptionsNow(binding, changes);
1237
+ } catch (error) {
1238
+ if (modeApplied && originalModeId && originalModeId !== modeId) {
1239
+ try {
1240
+ await this.setSessionModeNow(binding, originalModeId);
1241
+ } catch (rollbackError) {
1242
+ if (error && typeof error === "object") {
1243
+ Object.defineProperty(error, "modeRollbackError", {
1244
+ value: rollbackError,
1245
+ enumerable: false,
1246
+ configurable: true
1247
+ });
1248
+ }
1249
+ }
1250
+ }
1251
+ throw error;
1252
+ }
1253
+ }).then(() => {
1254
+ if (binding.deferredModeGeneration === modeGeneration) binding.deferredModeId = "";
1255
+ for (const change of changes) {
1256
+ if (binding.deferredConfigChanges.get(change.configId) === change) {
1257
+ binding.deferredConfigChanges.delete(change.configId);
1258
+ }
1259
+ }
1260
+ this.clearDeferredSessionError(binding);
1261
+ }, (error) => {
1262
+ if (binding.deferredModeGeneration === modeGeneration) binding.deferredModeId = "";
1263
+ for (const change of changes) {
1264
+ if (binding.deferredConfigChanges.get(change.configId) === change) {
1265
+ binding.deferredConfigChanges.delete(change.configId);
1266
+ }
1267
+ }
1268
+ const rollbackError = recordValue(error).modeRollbackError;
1269
+ const configRollbackError = recordValue(error).configRollbackError;
1270
+ binding.error = `Deferred session change was not applied: ${acpErrorMessage(error)}${configRollbackError ? ` Configuration rollback also failed: ${acpErrorMessage(configRollbackError)}` : ""}${rollbackError ? ` Permission mode rollback also failed: ${acpErrorMessage(rollbackError)}` : ""}`;
1271
+ }).finally(() => {
1272
+ if (binding.deferredConfigFlush === flush) binding.deferredConfigFlush = null;
1273
+ if (!this.isOpenBinding(binding)) return;
1274
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1275
+ this.scheduleCheckpoint(binding, { exact: true });
1276
+ this.emitRuntime(binding);
1277
+ void this.flushDeferredSessionChanges(binding);
1278
+ });
1279
+ binding.deferredConfigFlush = flush;
1280
+ }
1281
+ clearDeferredSessionError(binding) {
1282
+ if (!binding.error.startsWith("Deferred session change was not applied:")) return false;
1283
+ binding.error = "";
1147
1284
  return true;
1148
1285
  }
1149
-
1150
1286
  cancelAdmittingTurn(binding, turn) {
1151
- if (binding.activeTurn !== turn || turn.phase !== 'admitting') return false;
1287
+ if (binding.activeTurn !== turn || turn.phase !== "admitting") return false;
1152
1288
  binding.activeTurn = null;
1153
- turn.phase = 'cancelled';
1154
- binding.state = turn.previousState || 'idle';
1155
- turn.resolveCompletion({ status: 'cancelled-before-submission' });
1289
+ turn.phase = "cancelled";
1290
+ binding.state = String(turn.previousState || "idle");
1291
+ turn.resolveCompletion?.({ status: "cancelled-before-submission" });
1156
1292
  this.emitRuntime(binding);
1293
+ void this.flushDeferredSessionChanges(binding);
1157
1294
  return true;
1158
1295
  }
1159
-
1160
1296
  async enqueueTurnControl(turn, operation) {
1161
1297
  const previous = turn.controlTail || Promise.resolve();
1162
- const pending = previous.catch(() => {}).then(operation);
1298
+ const pending = previous.catch(() => {
1299
+ }).then(operation);
1163
1300
  turn.controlTail = pending;
1164
1301
  try {
1165
1302
  return await pending;
@@ -1167,134 +1304,96 @@ class AcpRuntime extends EventEmitter {
1167
1304
  if (turn.controlTail === pending) turn.controlTail = Promise.resolve();
1168
1305
  }
1169
1306
  }
1170
-
1171
1307
  ensureSubagentControl(binding, sessionId) {
1172
- const id = String(sessionId || '');
1173
- if (!id) return null;
1308
+ const id = String(sessionId || "");
1309
+ if (!id) throw new Error("ACP subagent control requires a session id");
1174
1310
  let control = binding.subagentControls.get(id);
1175
1311
  if (!control) {
1176
1312
  control = {
1177
1313
  sessionId: id,
1178
1314
  generation: binding.nextSubagentGeneration++,
1179
- phase: 'active',
1180
- error: '',
1181
- cancelPromise: null,
1315
+ phase: "active",
1316
+ error: "",
1317
+ cancelPromise: null
1182
1318
  };
1183
1319
  binding.subagentControls.set(id, control);
1184
1320
  }
1185
1321
  return control;
1186
1322
  }
1187
-
1188
1323
  resetSubagentControls(binding) {
1189
1324
  binding.subagentControls.clear();
1190
1325
  for (const sessionId of binding.subagentStates.keys()) {
1191
1326
  const control = this.ensureSubagentControl(binding, sessionId);
1192
- const parentTool = binding.sessionState?.entries.find(entry => (
1193
- entry?.type === 'tool'
1194
- && String(entry?._meta?.subagent_session_info?.session_id || '') === sessionId
1195
- ));
1327
+ const parentTool = binding.sessionState?.entries.find((entry) => entry?.type === "tool" && String(entry?._meta?.subagent_session_info?.session_id || "") === sessionId);
1196
1328
  if (parentTool) {
1197
1329
  this.updateSubagentControlFromParent(binding, parentTool);
1198
1330
  } else {
1199
- // Restored evidence without a parent Tool cannot prove that a child
1200
- // from the previous adapter process is still active.
1201
- control.phase = 'completed';
1331
+ control.phase = "completed";
1202
1332
  }
1203
1333
  }
1204
1334
  }
1205
-
1206
1335
  activeSubagentSessionIds(binding) {
1207
- return [...binding.subagentStates.keys()].filter(sessionId => {
1336
+ return [...binding.subagentStates.keys()].filter((sessionId) => {
1208
1337
  const control = this.ensureSubagentControl(binding, sessionId);
1209
- if (control?.cancelPromise || ['active', 'cancelling'].includes(control?.phase)) return true;
1210
- const hasInteraction = [...binding.pendingPermissions.values(), ...binding.pendingElicitations.values()]
1211
- .some(request => String(request?.sessionId || '') === sessionId);
1338
+ if (control?.cancelPromise || ["active", "cancelling"].includes(control?.phase)) return true;
1339
+ const hasInteraction = [...binding.pendingPermissions.values(), ...binding.pendingElicitations.values()].some((request) => String(request?.sessionId || "") === sessionId);
1212
1340
  if (hasInteraction) return true;
1213
- const parentTool = binding.sessionState?.entries.find(entry => (
1214
- entry?.type === 'tool'
1215
- && String(entry?._meta?.subagent_session_info?.session_id || '') === sessionId
1216
- ));
1217
- return ['pending', 'in_progress', 'in-progress', 'running']
1218
- .includes(String(parentTool?.status || '').toLowerCase());
1341
+ const parentTool = binding.sessionState?.entries.find((entry) => entry?.type === "tool" && String(entry?._meta?.subagent_session_info?.session_id || "") === sessionId);
1342
+ return ["pending", "in_progress", "in-progress", "running"].includes(String(parentTool?.status || "").toLowerCase());
1219
1343
  });
1220
1344
  }
1221
-
1222
1345
  updateSubagentControlFromParent(binding, update) {
1223
- const sessionId = String(update?._meta?.subagent_session_info?.session_id || '');
1346
+ const sessionId = String(update?._meta?.subagent_session_info?.session_id || "");
1224
1347
  if (!sessionId || !binding.subagentStates.has(sessionId)) return;
1225
1348
  const control = this.ensureSubagentControl(binding, sessionId);
1226
- const status = String(update?.status || '').toLowerCase();
1227
- if (['cancelled', 'canceled'].includes(status)) {
1228
- control.phase = 'cancelled';
1229
- control.error = '';
1230
- } else if (['completed', 'complete'].includes(status)) {
1231
- control.phase = 'completed';
1232
- control.error = '';
1233
- } else if (['failed', 'error'].includes(status)) {
1234
- control.phase = 'error';
1235
- control.error = String(update?.title || 'Subagent failed');
1236
- } else if (
1237
- ['pending', 'in_progress', 'in-progress', 'running'].includes(status)
1238
- && !['cancelling', 'cancelled', 'completed', 'error'].includes(control.phase)
1239
- ) {
1240
- control.phase = 'active';
1241
- control.error = '';
1349
+ const status = String(update?.status || "").toLowerCase();
1350
+ if (["cancelled", "canceled"].includes(status)) {
1351
+ control.phase = "cancelled";
1352
+ control.error = "";
1353
+ } else if (["completed", "complete"].includes(status)) {
1354
+ control.phase = "completed";
1355
+ control.error = "";
1356
+ } else if (["failed", "error"].includes(status)) {
1357
+ control.phase = "error";
1358
+ control.error = String(update?.title || "Subagent failed");
1359
+ } else if (["pending", "in_progress", "in-progress", "running"].includes(status) && !["cancelling", "cancelled", "completed", "error"].includes(control.phase)) {
1360
+ control.phase = "active";
1361
+ control.error = "";
1242
1362
  }
1243
1363
  }
1244
-
1245
1364
  beginSessionMutation(binding, action) {
1246
1365
  this.requireOpenBinding(binding);
1247
- if (
1248
- binding.sessionMutation
1249
- || binding.configMutationTail
1250
- || binding.patchDecisionInFlight.size > 0
1251
- || binding.activeTurn
1252
- || !['idle', 'error'].includes(binding.state)
1253
- ) {
1366
+ if (binding.sessionMutation || binding.configMutationTail || binding.patchDecisionInFlight.size > 0 || binding.activeTurn || !["idle", "error"].includes(binding.state)) {
1254
1367
  throw new Error(`ACP Agent is not ready for ${action} (${binding.state})`);
1255
1368
  }
1256
1369
  const mutation = { action };
1257
1370
  binding.sessionMutation = mutation;
1258
1371
  return mutation;
1259
1372
  }
1260
-
1261
1373
  endSessionMutation(binding, mutation) {
1262
1374
  if (binding.sessionMutation === mutation) binding.sessionMutation = null;
1263
1375
  }
1264
-
1265
1376
  requireConfigMutationReady(binding) {
1266
1377
  this.requireOpenBinding(binding);
1267
- if (
1268
- binding.sessionMutation
1269
- || binding.patchDecisionInFlight.size > 0
1270
- || binding.activeTurn
1271
- || !['idle', 'error'].includes(binding.state)
1272
- ) {
1378
+ if (binding.sessionMutation || binding.patchDecisionInFlight.size > 0 || binding.activeTurn || !["idle", "error"].includes(binding.state)) {
1273
1379
  throw new Error(`ACP Agent is not ready for configuration changes (${binding.state})`);
1274
1380
  }
1275
1381
  }
1276
-
1277
1382
  checkpointIdentity(binding, sessionId = binding?.sessionId) {
1278
1383
  if (!binding || !sessionId) return null;
1279
1384
  return {
1280
1385
  provider: binding.provider,
1281
- providerHomeId: binding.providerHomeId || 'default',
1386
+ providerHomeId: binding.providerHomeId || "default",
1282
1387
  sessionId,
1283
- cwd: binding.cwd,
1388
+ cwd: binding.cwd
1284
1389
  };
1285
1390
  }
1286
-
1287
1391
  scheduleCheckpoint(binding, _options = {}) {
1288
1392
  if (!this.isOpenBinding(binding)) return;
1289
1393
  const identity = this.checkpointIdentity(binding);
1290
1394
  if (!this.checkpointStore || !identity || !binding.sessionState) return;
1291
- // ACP currently has no conditional resume or provider-owned revision
1292
- // token. A timestamp/list check has a TOCTOU window, so runtime snapshots
1293
- // remain dirty and are used only as revision/reset fences. Full history
1294
- // load is the authoritative recovery path until such a proof is available.
1295
1395
  this.checkpointStore.schedule(identity, this.bindingCheckpoint(binding), { exact: false });
1296
1396
  }
1297
-
1298
1397
  async markCheckpointDirty(binding) {
1299
1398
  this.requireOpenBinding(binding);
1300
1399
  const identity = this.checkpointIdentity(binding);
@@ -1302,7 +1401,6 @@ class AcpRuntime extends EventEmitter {
1302
1401
  await this.checkpointStore.markDirty(identity);
1303
1402
  this.requireOpenBinding(binding);
1304
1403
  }
1305
-
1306
1404
  async writeCheckpoint(binding, _options = {}) {
1307
1405
  this.requireOpenBinding(binding);
1308
1406
  const identity = this.checkpointIdentity(binding);
@@ -1310,7 +1408,6 @@ class AcpRuntime extends EventEmitter {
1310
1408
  await this.checkpointStore.write(identity, this.bindingCheckpoint(binding), { exact: false });
1311
1409
  this.requireOpenBinding(binding);
1312
1410
  }
1313
-
1314
1411
  bindingCheckpoint(binding) {
1315
1412
  return {
1316
1413
  exportCheckpoint: () => ({
@@ -1319,125 +1416,129 @@ class AcpRuntime extends EventEmitter {
1319
1416
  sessionState: binding.sessionState?.exportCheckpoint() || null,
1320
1417
  subagentStates: [...binding.subagentStates.entries()].map(([sessionId, state]) => ({
1321
1418
  sessionId,
1322
- state: state.exportCheckpoint(),
1419
+ state: state.exportCheckpoint()
1323
1420
  })),
1324
1421
  patchDecisions: [...binding.patchDecisions.entries()],
1325
- providerProof: binding.checkpointProof ? clone(binding.checkpointProof) : null,
1326
- }),
1422
+ deferredConfigChanges: [...binding.deferredConfigChanges.entries()].map(([configId, change]) => [
1423
+ configId,
1424
+ clone(change.value)
1425
+ ]),
1426
+ deferredModeId: binding.deferredModeId,
1427
+ providerProof: binding.checkpointProof ? clone(binding.checkpointProof) : null
1428
+ })
1327
1429
  };
1328
1430
  }
1329
-
1330
1431
  restoreBindingCheckpoint(binding, checkpoint, options = {}) {
1331
1432
  if (!checkpoint) return null;
1332
- const mainCheckpoint = checkpoint.version === 2
1333
- ? checkpoint.sessionState
1334
- : checkpoint;
1335
- const sessionState = AcpSessionState.fromCheckpoint(mainCheckpoint, {
1433
+ const mainCheckpoint = checkpoint.version === 2 ? checkpoint.sessionState : checkpoint;
1434
+ const sessionState = import_acp_session_state.AcpSessionState.fromCheckpoint(mainCheckpoint, {
1336
1435
  provider: binding.provider,
1337
1436
  sessionId: options.sessionId || binding.sessionId,
1338
1437
  cwd: binding.cwd,
1339
- maxUpdates: this.maxUpdates,
1438
+ maxUpdates: this.maxUpdates
1340
1439
  });
1341
1440
  if (!sessionState) return null;
1342
- const subagentStates = new Map();
1441
+ const subagentStates = /* @__PURE__ */ new Map();
1343
1442
  if (checkpoint.version === 2 && Array.isArray(checkpoint.subagentStates)) {
1344
1443
  for (const item of checkpoint.subagentStates.slice(0, 32)) {
1345
- const sessionId = String(item?.sessionId || '');
1444
+ const sessionId = String(item?.sessionId || "");
1346
1445
  if (!sessionId) continue;
1347
- const state = AcpSessionState.fromCheckpoint(item?.state, {
1446
+ const state = import_acp_session_state.AcpSessionState.fromCheckpoint(item?.state, {
1348
1447
  provider: binding.provider,
1349
1448
  sessionId,
1350
1449
  cwd: binding.cwd,
1351
- maxUpdates: this.maxUpdates,
1450
+ maxUpdates: this.maxUpdates
1352
1451
  });
1353
1452
  if (state) subagentStates.set(sessionId, state);
1354
1453
  }
1355
1454
  }
1356
- const patchDecisions = new Map();
1455
+ const patchDecisions = /* @__PURE__ */ new Map();
1357
1456
  if (checkpoint.version === 2 && Array.isArray(checkpoint.patchDecisions)) {
1358
1457
  for (const item of checkpoint.patchDecisions) {
1359
1458
  if (!Array.isArray(item) || item.length !== 2) continue;
1360
- const key = String(item[0] || '');
1361
- const decision = String(item[1] || '');
1362
- if (key && ['kept', 'reverted'].includes(decision)) patchDecisions.set(key, decision);
1459
+ const key = String(item[0] || "");
1460
+ const decision = String(item[1] || "");
1461
+ if (key && ["kept", "reverted"].includes(decision)) patchDecisions.set(key, decision);
1462
+ }
1463
+ }
1464
+ const deferredConfigChanges = /* @__PURE__ */ new Map();
1465
+ if (checkpoint.version === 2 && Array.isArray(checkpoint.deferredConfigChanges)) {
1466
+ for (const item of checkpoint.deferredConfigChanges.slice(0, 32)) {
1467
+ if (!Array.isArray(item) || item.length !== 2) continue;
1468
+ const configId = String(item[0] || "");
1469
+ const value = item[1];
1470
+ if (!configId || !["string", "boolean", "number"].includes(typeof value)) continue;
1471
+ deferredConfigChanges.set(configId, { configId, value });
1363
1472
  }
1364
1473
  }
1474
+ const deferredModeId = checkpoint.version === 2 && typeof checkpoint.deferredModeId === "string" ? checkpoint.deferredModeId : "";
1365
1475
  return {
1366
1476
  sessionState,
1367
1477
  subagentStates,
1368
1478
  patchDecisions,
1479
+ deferredConfigChanges,
1480
+ deferredModeId,
1369
1481
  providerProof: checkpoint.version === 2 ? clone(checkpoint.providerProof) : null,
1370
- complete: checkpoint.version === 2 && checkpoint.complete === true,
1482
+ complete: checkpoint.version === 2 && checkpoint.complete === true
1371
1483
  };
1372
1484
  }
1373
-
1374
1485
  restorePatchDecisions(binding, decisions) {
1375
1486
  if (!(decisions instanceof Map) || !binding.sessionState) return;
1376
1487
  for (const [key, decision] of decisions) {
1377
- const separator = key.indexOf('\n');
1488
+ const separator = key.indexOf("\n");
1378
1489
  if (separator <= 0) continue;
1379
1490
  const toolCallId = key.slice(0, separator);
1380
1491
  const requestedPath = key.slice(separator + 1);
1381
1492
  const entry = binding.sessionState.toolEntries.get(toolCallId);
1382
1493
  if (!entry || binding.sessionState.isInternalEntry(entry)) continue;
1383
1494
  try {
1384
- patchBlock(entry, binding.cwd, requestedPath);
1495
+ (0, import_patch_decisions.patchBlock)(entry, binding.cwd, requestedPath);
1385
1496
  } catch {
1386
1497
  continue;
1387
1498
  }
1388
1499
  binding.patchDecisions.set(key, decision);
1389
- entry._meta = { ...(entry._meta || {}) };
1500
+ entry._meta = { ...entry._meta || {} };
1390
1501
  entry._meta.farming_patch_decisions = {
1391
- ...(entry._meta.farming_patch_decisions || {}),
1392
- [requestedPath]: decision,
1502
+ ...entry._meta.farming_patch_decisions || {},
1503
+ [requestedPath]: decision
1393
1504
  };
1394
1505
  }
1395
1506
  }
1396
-
1397
- async checkpointMatchesProviderSession(connection, capabilities, request, saved) {
1398
- const proof = saved?.state?.providerProof;
1399
- if (
1400
- !capabilities?.sessionCapabilities?.list
1401
- || !proof
1402
- || typeof proof.token !== 'string'
1403
- || !proof.token
1404
- ) return false;
1405
- let cursor = '';
1507
+ async checkpointMatchesProviderSession(connection, capabilities = {}, request, saved) {
1508
+ const proof = recordValue(recordValue(saved?.state).providerProof);
1509
+ if (!capabilities?.sessionCapabilities?.list || !proof || typeof proof.token !== "string" || !proof.token) return false;
1510
+ let cursor = "";
1406
1511
  try {
1407
1512
  for (let page = 0; page < 10; page += 1) {
1408
1513
  const response = await withTimeout(connection.listSessions({
1409
1514
  cwd: request.cwd,
1410
- ...(cursor ? { cursor } : {}),
1411
- }), this.requestTimeoutMs, 'ACP session/list checkpoint validation');
1412
- const session = (response?.sessions || []).find(item => item?.sessionId === request.sessionId);
1515
+ ...cursor ? { cursor } : {}
1516
+ }), this.requestTimeoutMs, "ACP session/list checkpoint validation");
1517
+ const session = (response?.sessions || []).find((item) => item?.sessionId === request.sessionId);
1413
1518
  if (session) {
1414
- const sessionCwd = path.resolve(String(session.cwd || ''));
1415
- const token = String(session?._meta?.checkpointRevision || session?.checkpointRevision || '');
1416
- return sessionCwd === path.resolve(request.cwd)
1417
- && token === proof.token
1418
- && path.resolve(String(proof.cwd || '')) === path.resolve(request.cwd);
1519
+ const sessionCwd = path.resolve(String(session.cwd || ""));
1520
+ const token = String(session?._meta?.checkpointRevision || session?.checkpointRevision || "");
1521
+ return sessionCwd === path.resolve(request.cwd) && token === proof.token && path.resolve(String(proof.cwd || "")) === path.resolve(request.cwd);
1419
1522
  }
1420
- cursor = String(response?.nextCursor || '');
1523
+ cursor = String(response?.nextCursor || "");
1421
1524
  if (!cursor) return false;
1422
1525
  }
1423
1526
  } catch (error) {
1424
- console.warn('Failed to validate ACP checkpoint against provider session metadata:', error && (error.message || error));
1527
+ console.warn("Failed to validate ACP checkpoint against provider session metadata:", asErrorLike(error).message || error);
1425
1528
  }
1426
1529
  return false;
1427
1530
  }
1428
-
1429
1531
  async officialConnection(handlers, child) {
1430
1532
  const sdk = await loadAcpSdk();
1431
1533
  const stream = sdk.ndJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout));
1432
1534
  return new sdk.ClientSideConnection(() => handlers, stream);
1433
1535
  }
1434
-
1435
1536
  async waitForHistoryReplay(binding) {
1436
1537
  const startedAt = Date.now();
1437
1538
  let lastUpdateCount = binding.sessionState?.updates.length || 0;
1438
1539
  let lastChangedAt = startedAt;
1439
1540
  while (Date.now() - startedAt < this.historyReplayMaxWaitMs) {
1440
- await new Promise(resolve => setTimeout(resolve, 50));
1541
+ await new Promise((resolve) => setTimeout(resolve, 50));
1441
1542
  if (!this.isOpenBinding(binding)) return;
1442
1543
  const now = Date.now();
1443
1544
  const updateCount = binding.sessionState?.updates.length || 0;
@@ -1445,125 +1546,115 @@ class AcpRuntime extends EventEmitter {
1445
1546
  lastUpdateCount = updateCount;
1446
1547
  lastChangedAt = now;
1447
1548
  }
1448
- if (
1449
- now - startedAt >= this.historyReplayMinWaitMs
1450
- && now - lastChangedAt >= this.historyReplayQuietMs
1451
- ) return;
1549
+ if (now - startedAt >= this.historyReplayMinWaitMs && now - lastChangedAt >= this.historyReplayQuietMs) return;
1452
1550
  }
1453
1551
  }
1454
-
1455
1552
  clientHandlers(binding) {
1456
- const openClientRequest = handler => async request => {
1553
+ const openClientRequest = (handler) => async (request) => {
1457
1554
  this.requireOpenBinding(binding);
1458
- if (binding.state === 'closed') throw new Error('ACP session is closed');
1555
+ if (binding.state === "closed") throw new Error("ACP session is closed");
1459
1556
  const response = await handler(request);
1460
1557
  this.requireOpenBinding(binding);
1461
- if (binding.state === 'closed') throw new Error('ACP session is closed');
1558
+ if (binding.state === "closed") throw new Error("ACP session is closed");
1462
1559
  return response;
1463
1560
  };
1464
1561
  return {
1465
- sessionUpdate: notification => {
1466
- if (!this.isOpenBinding(binding) || binding.state === 'closed') return;
1467
- const notificationSessionId = String(notification?.sessionId || '');
1562
+ sessionUpdate: (notification) => {
1563
+ if (!this.isOpenBinding(binding) || binding.state === "closed") return;
1564
+ const notificationSessionId = String(notification?.sessionId || "");
1468
1565
  const isPrimarySession = !binding.sessionId || !notificationSessionId || notificationSessionId === binding.sessionId;
1469
1566
  let targetState = isPrimarySession ? binding.sessionState : binding.subagentStates.get(notificationSessionId);
1470
1567
  if (!targetState && notificationSessionId && binding.subagentStates.size < 32) {
1471
- targetState = new AcpSessionState({
1568
+ targetState = new import_acp_session_state.AcpSessionState({
1472
1569
  provider: binding.provider,
1473
1570
  sessionId: notificationSessionId,
1474
1571
  cwd: binding.cwd,
1475
- maxUpdates: this.maxUpdates,
1572
+ maxUpdates: this.maxUpdates
1476
1573
  });
1477
1574
  binding.subagentStates.set(notificationSessionId, targetState);
1478
1575
  }
1479
1576
  if (!isPrimarySession && targetState) {
1480
1577
  this.ensureSubagentControl(binding, notificationSessionId);
1481
- const parentTool = binding.sessionState?.entries.find(entry => (
1482
- entry?.type === 'tool'
1483
- && String(entry?._meta?.subagent_session_info?.session_id || '') === notificationSessionId
1484
- ));
1578
+ const parentTool = binding.sessionState?.entries.find((entry) => entry?.type === "tool" && String(entry?._meta?.subagent_session_info?.session_id || "") === notificationSessionId);
1485
1579
  if (parentTool) this.updateSubagentControlFromParent(binding, parentTool);
1486
1580
  }
1487
1581
  if (targetState?.apply(notification)) {
1488
- const update = notification?.update;
1489
- if (isPrimarySession) this.updateSubagentControlFromParent(binding, update);
1490
- if (isPrimarySession && update?.sessionUpdate === 'current_mode_update' && binding.modes) {
1491
- binding.modes = { ...binding.modes, currentModeId: String(update.currentModeId || '') };
1582
+ const update = notification.update;
1583
+ if (isPrimarySession && update) this.updateSubagentControlFromParent(binding, update);
1584
+ if (isPrimarySession && update?.sessionUpdate === "current_mode_update" && binding.modes) {
1585
+ binding.modes = { ...binding.modes, currentModeId: String(update.currentModeId || "") };
1492
1586
  }
1493
- if (isPrimarySession && update?.sessionUpdate === 'config_option_update') {
1587
+ if (isPrimarySession && update?.sessionUpdate === "config_option_update") {
1494
1588
  binding.configOptions = JSON.parse(JSON.stringify(update.configOptions || []));
1495
1589
  }
1496
1590
  if (!isPrimarySession && binding.sessionState) {
1497
- const parentTool = binding.sessionState.entries.find(entry => (
1498
- entry?.type === 'tool'
1499
- && String(entry?._meta?.subagent_session_info?.session_id || '') === notificationSessionId
1500
- ));
1591
+ const parentTool = binding.sessionState.entries.find((entry) => entry?.type === "tool" && String(entry?._meta?.subagent_session_info?.session_id || "") === notificationSessionId);
1501
1592
  if (parentTool) binding.sessionState.touchEntry(parentTool);
1502
1593
  }
1503
- binding.updatedAt = new Date().toISOString();
1594
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1504
1595
  if (isPrimarySession && !binding.historyReplayActive && !binding.activeTurn) {
1505
1596
  this.scheduleCheckpoint(binding, { exact: true });
1506
1597
  }
1507
- // A loaded history can contain hundreds of ordered updates. Applying
1508
- // them one by one is necessary, but broadcasting every replay step
1509
- // makes clients repeatedly abort/refetch and remount rich content.
1510
- // prepareAgent emits one complete snapshot after the replay settles.
1511
1598
  if (!binding.historyReplayActive) this.emitSession(binding);
1512
1599
  }
1513
1600
  },
1514
- requestPermission: request => this.requestPermission(binding, request),
1515
- readTextFile: openClientRequest(request => this.clientFileSystem.readTextFile(binding, request)),
1516
- writeTextFile: openClientRequest(request => this.clientFileSystem.writeTextFile(binding, request)),
1517
- createTerminal: openClientRequest(request => this.clientTerminals.create(binding, request)),
1518
- terminalOutput: openClientRequest(request => this.clientTerminals.output(binding, request)),
1519
- waitForTerminalExit: openClientRequest(request => this.clientTerminals.waitForExit(binding, request)),
1520
- killTerminal: openClientRequest(request => this.clientTerminals.kill(binding, request)),
1521
- releaseTerminal: openClientRequest(request => this.clientTerminals.release(binding, request)),
1522
- unstable_createElicitation: request => this.requestElicitation(binding, request),
1523
- unstable_completeElicitation: notification => this.completeElicitation(binding, notification),
1601
+ requestPermission: (request) => this.requestPermission(binding, request),
1602
+ readTextFile: openClientRequest((request) => this.clientFileSystem.readTextFile(binding, request)),
1603
+ writeTextFile: openClientRequest((request) => this.clientFileSystem.writeTextFile(binding, request)),
1604
+ createTerminal: openClientRequest((request) => this.clientTerminals.create(binding, request)),
1605
+ terminalOutput: openClientRequest((request) => this.clientTerminals.output(binding, request)),
1606
+ waitForTerminalExit: openClientRequest((request) => this.clientTerminals.waitForExit(binding, request)),
1607
+ killTerminal: openClientRequest((request) => this.clientTerminals.kill(binding, request)),
1608
+ releaseTerminal: openClientRequest((request) => this.clientTerminals.release(binding, request)),
1609
+ unstable_createElicitation: (request) => this.requestElicitation(binding, request),
1610
+ unstable_completeElicitation: (notification) => this.completeElicitation(binding, notification)
1524
1611
  };
1525
1612
  }
1526
-
1527
1613
  requestPermission(binding, request) {
1528
- if (!this.isOpenBinding(binding) || binding.state === 'closed') {
1529
- return { outcome: { outcome: 'cancelled' } };
1530
- }
1531
- const requestSessionId = String(request?.sessionId || '');
1532
- if (
1533
- !requestSessionId
1534
- || (
1535
- requestSessionId !== binding.sessionId
1536
- && !binding.subagentStates.has(requestSessionId)
1537
- )
1538
- ) {
1539
- return { outcome: { outcome: 'cancelled' } };
1614
+ if (!this.isOpenBinding(binding) || binding.state === "closed") {
1615
+ return { outcome: { outcome: "cancelled" } };
1616
+ }
1617
+ const requestSessionId = String(request?.sessionId || "");
1618
+ if (!requestSessionId || requestSessionId !== binding.sessionId && !binding.subagentStates.has(requestSessionId)) {
1619
+ return { outcome: { outcome: "cancelled" } };
1620
+ }
1621
+ const browserTarget = farmingBrowserApprovalTarget(binding, request);
1622
+ const browserDecision = browserTarget ? this.browserPermissionDecisionFor(binding, browserTarget) : null;
1623
+ const browserAutomatic = browserDecision ? shouldAutoApproveFarmingBrowser(binding, browserDecision) : null;
1624
+ if (browserAutomatic?.approve) {
1625
+ return automaticBrowserPermissionResponse(request);
1540
1626
  }
1541
1627
  const automatic = autoPermissionResponse(request, binding.approvalMode);
1542
1628
  if (automatic) return automatic;
1543
1629
  const requestId = `acp-permission-${crypto.randomUUID()}`;
1544
1630
  binding.interactionOrigins.set(requestId, binding.state);
1545
- binding.state = 'waiting-for-permission';
1631
+ binding.state = "waiting-for-permission";
1546
1632
  const pending = { ...JSON.parse(JSON.stringify(request)), requestId };
1547
- pending.origin = String(request?.sessionId || '') && String(request.sessionId) !== binding.sessionId
1548
- ? 'subagent'
1549
- : 'agent';
1550
- pending.securityWarnings = permissionSecurityWarnings(pending);
1633
+ pending.origin = String(request?.sessionId || "") && String(request.sessionId) !== binding.sessionId ? "subagent" : "agent";
1634
+ pending.securityWarnings = (0, import_permission_security.permissionSecurityWarnings)(pending);
1551
1635
  binding.pendingPermissions.set(requestId, pending);
1636
+ if (browserAutomatic?.scopeKey) {
1637
+ binding.farmingBrowserApprovalScopes.set(requestId, browserAutomatic.scopeKey);
1638
+ }
1552
1639
  this.emitRuntime(binding);
1553
- return new Promise(resolve => binding.permissionResolvers.set(requestId, resolve));
1640
+ return new Promise((resolve) => binding.permissionResolvers.set(requestId, resolve));
1554
1641
  }
1555
-
1556
1642
  respondPermission(agentId, requestId, optionId, cancelled = false) {
1557
1643
  const binding = this.requireBinding(agentId);
1558
- const pending = binding.pendingPermissions.get(String(requestId || ''));
1559
- const resolve = binding.permissionResolvers.get(String(requestId || ''));
1560
- if (!pending || pending.requestId !== requestId || !resolve) throw new Error('ACP permission request is no longer pending');
1561
- let response = { outcome: { outcome: 'cancelled' } };
1644
+ const pending = binding.pendingPermissions.get(String(requestId || ""));
1645
+ const resolve = binding.permissionResolvers.get(String(requestId || ""));
1646
+ if (!pending || pending.requestId !== requestId || !resolve) throw new Error("ACP permission request is no longer pending");
1647
+ let response = { outcome: { outcome: "cancelled" } };
1562
1648
  if (!cancelled) {
1563
- const option = pending.options.find(item => item.optionId === optionId);
1564
- if (!option) throw new Error('Unknown ACP permission option');
1649
+ const option = pending.options.find((item) => item.optionId === optionId);
1650
+ if (!option) throw new Error("Unknown ACP permission option");
1565
1651
  response = selectedPermission(option);
1652
+ const scopeKey = binding.farmingBrowserApprovalScopes.get(requestId);
1653
+ if (option.kind === "allow_always" && scopeKey) {
1654
+ binding.farmingBrowserApprovedSites.add(scopeKey);
1655
+ }
1566
1656
  }
1657
+ binding.farmingBrowserApprovalScopes.delete(requestId);
1567
1658
  binding.permissionResolvers.delete(requestId);
1568
1659
  binding.pendingPermissions.delete(requestId);
1569
1660
  const origin = binding.interactionOrigins.get(requestId);
@@ -1573,53 +1664,63 @@ class AcpRuntime extends EventEmitter {
1573
1664
  this.emitRuntime(binding);
1574
1665
  return response;
1575
1666
  }
1576
-
1577
1667
  requestElicitation(binding, request) {
1578
- if (!this.isOpenBinding(binding) || binding.state === 'closed') return { action: 'cancel' };
1579
- const hasSessionScope = typeof request?.sessionId === 'string' && request.sessionId.length > 0;
1580
- const requestSessionId = hasSessionScope ? String(request.sessionId) : '';
1668
+ if (!this.isOpenBinding(binding) || binding.state === "closed") return { action: "cancel" };
1669
+ const hasSessionScope = typeof request?.sessionId === "string" && request.sessionId.length > 0;
1670
+ const requestSessionId = hasSessionScope ? String(request.sessionId) : "";
1581
1671
  const isPrimarySession = hasSessionScope && requestSessionId === binding.sessionId;
1582
1672
  const isRequestScoped = !hasSessionScope;
1583
1673
  if (!isRequestScoped && !isPrimarySession && !binding.subagentStates.has(requestSessionId)) {
1584
- throw new Error('ACP elicitation does not match an active session');
1674
+ throw new Error("ACP elicitation does not match an active session");
1675
+ }
1676
+ if (!["form", "url"].includes(String(request?.mode || ""))) {
1677
+ return { action: "cancel" };
1585
1678
  }
1586
- if (!['form', 'url'].includes(String(request?.mode || ''))) {
1587
- return { action: 'cancel' };
1679
+ const browserTarget = farmingBrowserApprovalTarget(binding, request);
1680
+ const browserDecision = browserTarget ? this.browserPermissionDecisionFor(binding, browserTarget) : null;
1681
+ const browserAutomatic = browserDecision ? shouldAutoApproveFarmingBrowser(binding, browserDecision) : null;
1682
+ if (browserAutomatic?.approve || browserTarget && binding.approvalMode === "full") {
1683
+ return automaticBrowserElicitationResponse(request);
1588
1684
  }
1685
+ if (browserTarget && binding.approvalMode === "ask") return { action: "cancel" };
1589
1686
  const requestId = `acp-elicitation-${crypto.randomUUID()}`;
1590
1687
  const cloned = JSON.parse(JSON.stringify(request));
1591
- const protocolRequestId = Object.prototype.hasOwnProperty.call(cloned, 'requestId')
1592
- ? cloned.requestId
1593
- : undefined;
1688
+ const protocolRequestId = Object.prototype.hasOwnProperty.call(cloned, "requestId") ? cloned.requestId : void 0;
1594
1689
  delete cloned.requestId;
1595
1690
  const pending = {
1596
1691
  ...cloned,
1597
- ...(protocolRequestId !== undefined ? { protocolRequestId } : {}),
1692
+ ...protocolRequestId !== void 0 ? { protocolRequestId } : {},
1598
1693
  requestId,
1599
- origin: isRequestScoped ? 'request' : isPrimarySession ? 'agent' : 'subagent',
1694
+ origin: isRequestScoped ? "request" : isPrimarySession ? "agent" : "subagent"
1600
1695
  };
1601
1696
  binding.interactionOrigins.set(requestId, binding.state);
1602
1697
  binding.pendingElicitations.set(requestId, pending);
1603
- binding.state = 'waiting-for-input';
1698
+ if (browserAutomatic?.scopeKey) {
1699
+ binding.farmingBrowserApprovalScopes.set(requestId, browserAutomatic.scopeKey);
1700
+ }
1701
+ binding.state = "waiting-for-input";
1604
1702
  this.emitRuntime(binding);
1605
- return new Promise(resolve => binding.elicitationResolvers.set(requestId, resolve));
1703
+ return new Promise((resolve) => binding.elicitationResolvers.set(requestId, resolve));
1606
1704
  }
1607
-
1608
1705
  respondElicitation(agentId, requestId, action, content) {
1609
1706
  const binding = this.requireBinding(agentId);
1610
- const id = String(requestId || '');
1707
+ const id = String(requestId || "");
1611
1708
  const pending = binding.pendingElicitations.get(id);
1612
1709
  const resolve = binding.elicitationResolvers.get(id);
1613
- if (!pending || !resolve) throw new Error('ACP input request is no longer pending');
1614
- const normalizedAction = String(action || 'cancel');
1615
- if (!['accept', 'decline', 'cancel'].includes(normalizedAction)) throw new Error('Unknown ACP input action');
1616
- const response = normalizedAction === 'accept'
1617
- ? { action: 'accept', ...(pending.mode === 'form' ? { content: validateElicitationContent(pending, content) } : {}) }
1618
- : { action: normalizedAction };
1710
+ if (!pending || !resolve) throw new Error("ACP input request is no longer pending");
1711
+ const normalizedAction = String(action || "cancel");
1712
+ if (!["accept", "decline", "cancel"].includes(normalizedAction)) throw new Error("Unknown ACP input action");
1713
+ const response = normalizedAction === "accept" ? { action: "accept", ...pending.mode === "form" ? { content: validateElicitationContent(pending, content) } : {} } : { action: normalizedAction };
1714
+ const scopeKey = binding.farmingBrowserApprovalScopes.get(id);
1715
+ const persist = String(recordValue(response.content).persist || "");
1716
+ if (normalizedAction === "accept" && scopeKey && ["session", "always"].includes(persist)) {
1717
+ binding.farmingBrowserApprovedSites.add(scopeKey);
1718
+ }
1719
+ binding.farmingBrowserApprovalScopes.delete(id);
1619
1720
  binding.elicitationResolvers.delete(id);
1620
1721
  binding.pendingElicitations.delete(id);
1621
- if (pending.mode === 'url' && normalizedAction === 'accept') {
1622
- binding.activeElicitations.set(String(pending.elicitationId || id), { ...pending, status: 'accepted' });
1722
+ if (pending.mode === "url" && normalizedAction === "accept") {
1723
+ binding.activeElicitations.set(String(pending.elicitationId || id), { ...pending, status: "accepted" });
1623
1724
  }
1624
1725
  const origin = binding.interactionOrigins.get(id);
1625
1726
  binding.interactionOrigins.delete(id);
@@ -1628,28 +1729,39 @@ class AcpRuntime extends EventEmitter {
1628
1729
  this.emitRuntime(binding);
1629
1730
  return response;
1630
1731
  }
1631
-
1732
+ browserPermissionDecisionFor(binding, target) {
1733
+ try {
1734
+ return this.browserPermissionDecision(binding.agentId, target.tool, target.arguments) || defaultBrowserPermissionDecision(target);
1735
+ } catch {
1736
+ return { requiresApproval: true, scopeKey: "", site: "" };
1737
+ }
1738
+ }
1632
1739
  completeElicitation(binding, notification) {
1633
- if (!this.isOpenBinding(binding) || binding.state === 'closed') return;
1634
- const elicitationId = String(notification?.elicitationId || '');
1740
+ if (!this.isOpenBinding(binding) || binding.state === "closed") return;
1741
+ const elicitationId = String(notification?.elicitationId || "");
1635
1742
  if (elicitationId) binding.activeElicitations.delete(elicitationId);
1636
1743
  this.emitRuntime(binding);
1637
1744
  }
1638
-
1639
1745
  async submitMessage(agentId, prompt, options = {}) {
1640
1746
  const binding = this.requireBinding(agentId);
1747
+ const delivery = options.delivery === "prompt" || options.delivery === "steer" ? options.delivery : "auto";
1748
+ if (delivery === "steer") {
1749
+ this.requireOpenBinding(binding);
1750
+ const turn = binding.activeTurn;
1751
+ if (turn?.phase !== "running" || turn.providerSettled === true || binding.provider !== "codex" || binding.supportsSteer !== true) {
1752
+ throw new Error("No active Codex turn to steer");
1753
+ }
1754
+ const result = await this.steer(agentId, prompt);
1755
+ options.onSubmitted?.();
1756
+ return { steered: true, ...result };
1757
+ }
1641
1758
  while (true) {
1642
1759
  this.requireOpenBinding(binding);
1643
1760
  const turn = binding.activeTurn;
1644
- if (turn?.phase === 'blocked') {
1761
+ if (turn?.phase === "blocked") {
1645
1762
  throw new Error(`ACP Agent is not ready (${binding.state})`);
1646
1763
  }
1647
- if (
1648
- turn?.phase === 'running'
1649
- && turn.providerSettled !== true
1650
- && binding.provider === 'codex'
1651
- && binding.supportsSteer === true
1652
- ) {
1764
+ if (delivery === "auto" && turn?.phase === "running" && turn.providerSettled !== true && binding.provider === "codex" && binding.supportsSteer === true) {
1653
1765
  try {
1654
1766
  const result = await this.steer(agentId, prompt);
1655
1767
  options.onSubmitted?.();
@@ -1667,49 +1779,43 @@ class AcpRuntime extends EventEmitter {
1667
1779
  return this.prompt(agentId, prompt, options);
1668
1780
  }
1669
1781
  }
1670
-
1671
1782
  async prompt(agentId, prompt, options = {}) {
1672
1783
  const binding = this.requireBinding(agentId);
1673
- if (
1674
- binding.exited
1675
- || binding.sessionMutation
1676
- || binding.activeTurn
1677
- || !['idle', 'error'].includes(binding.state)
1678
- ) {
1784
+ if (binding.exited || binding.sessionMutation || binding.activeTurn || !["idle", "error"].includes(binding.state)) {
1679
1785
  throw new Error(`ACP Agent is not ready (${binding.state})`);
1680
1786
  }
1681
- const rawContent = Array.isArray(prompt) ? prompt : [{ type: 'text', text: String(prompt || '') }];
1787
+ const rawContent = Array.isArray(prompt) ? prompt : [{ type: "text", text: String(prompt || "") }];
1682
1788
  const content = promptContentForCapabilities(
1683
1789
  rawContent,
1684
- binding.initializeResponse?.agentCapabilities || {},
1790
+ binding.initializeResponse?.agentCapabilities || {}
1685
1791
  );
1686
1792
  const turn = this.beginTurn(binding);
1687
1793
  try {
1688
1794
  const configMutation = binding.configMutationTail;
1689
- const patchDecisions = [...binding.patchDecisionInFlight.values()].map(item => item.promise);
1795
+ const patchDecisions = [...binding.patchDecisionInFlight.values()].map((item) => item.promise);
1690
1796
  await Promise.allSettled([
1691
- ...(configMutation ? [configMutation] : []),
1692
- ...patchDecisions,
1797
+ ...configMutation ? [configMutation] : [],
1798
+ ...patchDecisions
1693
1799
  ]);
1694
- if (!this.isCurrentTurn(binding, turn) || turn.phase !== 'admitting') {
1695
- throw new Error('ACP prompt was cancelled before submission');
1800
+ if (!this.isCurrentTurn(binding, turn) || turn.phase !== "admitting") {
1801
+ throw new Error("ACP prompt was cancelled before submission");
1696
1802
  }
1697
1803
  await this.markCheckpointDirty(binding);
1698
- if (!this.isCurrentTurn(binding, turn) || turn.phase !== 'admitting') {
1699
- throw new Error('ACP prompt was cancelled before submission');
1804
+ if (!this.isCurrentTurn(binding, turn) || turn.phase !== "admitting") {
1805
+ throw new Error("ACP prompt was cancelled before submission");
1700
1806
  }
1701
1807
  } catch (error) {
1702
1808
  if (this.isCurrentTurn(binding, turn)) {
1703
1809
  binding.state = turn.previousState;
1704
- this.finishTurn(binding, turn, { status: 'admission-failed' });
1810
+ this.finishTurn(binding, turn, { status: "admission-failed" });
1705
1811
  }
1706
1812
  throw error;
1707
1813
  }
1708
1814
  binding.sessionState.beginPrompt(content);
1709
- turn.phase = 'running';
1710
- binding.state = 'working';
1711
- binding.error = '';
1712
- binding.stopReason = '';
1815
+ turn.phase = "running";
1816
+ binding.state = "working";
1817
+ binding.error = "";
1818
+ binding.stopReason = "";
1713
1819
  this.emitRuntime(binding);
1714
1820
  this.emitSession(binding);
1715
1821
  let response;
@@ -1718,7 +1824,6 @@ class AcpRuntime extends EventEmitter {
1718
1824
  try {
1719
1825
  options.onSubmitted?.();
1720
1826
  } catch {
1721
- // Submission is already owned by the provider; admission callbacks cannot roll it back.
1722
1827
  }
1723
1828
  response = await responsePromise;
1724
1829
  turn.providerSettled = true;
@@ -1728,16 +1833,13 @@ class AcpRuntime extends EventEmitter {
1728
1833
  if (!this.isCurrentTurn(binding, turn)) throw runtimeError;
1729
1834
  await this.enqueueTurnControl(turn, async () => {
1730
1835
  if (!this.isCurrentTurn(binding, turn)) return;
1731
- binding.stopReason = 'error';
1732
- // JSON-RPC implementations commonly move the actionable provider text
1733
- // into error.data.details. Classify the normalized message so the
1734
- // ordered transcript and runtime snapshot cannot disagree.
1836
+ binding.stopReason = "error";
1735
1837
  binding.sessionState.recordError(runtimeError.message, acpErrorKind(runtimeError));
1736
- binding.sessionState.completePrompt('error');
1737
- binding.state = 'error';
1838
+ binding.sessionState.completePrompt();
1839
+ binding.state = "error";
1738
1840
  binding.error = runtimeError.message;
1739
- binding.updatedAt = new Date().toISOString();
1740
- this.finishTurn(binding, turn, { status: 'error', error: runtimeError });
1841
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1842
+ this.finishTurn(binding, turn, { status: "error", error: runtimeError });
1741
1843
  this.scheduleCheckpoint(binding, { exact: true });
1742
1844
  this.emitSession(binding);
1743
1845
  this.emitRuntime(binding);
@@ -1746,104 +1848,101 @@ class AcpRuntime extends EventEmitter {
1746
1848
  }
1747
1849
  return this.enqueueTurnControl(turn, async () => {
1748
1850
  this.requireCurrentTurn(binding, turn);
1749
- binding.stopReason = String(response?.stopReason || '');
1750
- binding.sessionState.completePrompt(binding.stopReason);
1751
- binding.state = 'idle';
1752
- binding.error = '';
1753
- binding.updatedAt = new Date().toISOString();
1754
- this.finishTurn(binding, turn, { status: 'completed', stopReason: binding.stopReason });
1851
+ binding.stopReason = String(response?.stopReason || "");
1852
+ binding.sessionState.completePrompt();
1853
+ binding.state = "idle";
1854
+ binding.error = "";
1855
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1856
+ this.finishTurn(binding, turn, { status: "completed", stopReason: binding.stopReason });
1755
1857
  this.scheduleCheckpoint(binding, { exact: true });
1756
1858
  this.emitSession(binding);
1757
1859
  this.emitRuntime(binding);
1758
1860
  return { sessionId: binding.sessionId, stopReason: binding.stopReason };
1759
1861
  });
1760
1862
  }
1761
-
1762
1863
  canSteer(agentId) {
1763
1864
  const binding = this.bindings.get(agentId);
1764
- return binding?.provider === 'codex'
1765
- && binding.supportsSteer === true
1766
- && binding.activeTurn?.phase === 'running'
1767
- && binding.activeTurn?.providerSettled !== true
1768
- && Boolean(binding.sessionId)
1769
- && Boolean(binding.connection);
1865
+ return binding?.provider === "codex" && binding.supportsSteer === true && binding.activeTurn?.phase === "running" && binding.activeTurn?.providerSettled !== true && Boolean(binding.sessionId) && Boolean(binding.connection);
1770
1866
  }
1771
-
1772
1867
  async steer(agentId, prompt) {
1773
1868
  const binding = this.requireBinding(agentId);
1774
- if (binding.provider !== 'codex' || binding.supportsSteer !== true) {
1869
+ if (binding.provider !== "codex" || binding.supportsSteer !== true) {
1775
1870
  throw new Error(`${binding.provider} ACP Agent does not support steer`);
1776
1871
  }
1777
- const rawContent = Array.isArray(prompt) ? prompt : [{ type: 'text', text: String(prompt || '') }];
1872
+ const rawContent = Array.isArray(prompt) ? prompt : [{ type: "text", text: String(prompt || "") }];
1778
1873
  const content = promptContentForCapabilities(
1779
1874
  rawContent,
1780
- binding.initializeResponse?.agentCapabilities || {},
1875
+ binding.initializeResponse?.agentCapabilities || {}
1781
1876
  );
1782
1877
  const turn = binding.activeTurn;
1783
- this.requireCurrentTurn(binding, turn, ['running']);
1878
+ this.requireCurrentTurn(binding, turn, ["running"]);
1784
1879
  const clientMessageId = `farming-steer-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
1785
1880
  const operation = async () => {
1786
- this.requireCurrentTurn(binding, turn, ['running']);
1787
- if (turn.providerSettled) throw new Error('No active Codex turn to steer');
1881
+ this.requireCurrentTurn(binding, turn, ["running"]);
1882
+ if (turn.providerSettled) throw new Error("No active Codex turn to steer");
1788
1883
  await this.markCheckpointDirty(binding);
1789
- this.requireCurrentTurn(binding, turn, ['running']);
1790
- if (turn.providerSettled) throw new Error('No active Codex turn to steer');
1884
+ this.requireCurrentTurn(binding, turn, ["running"]);
1885
+ if (turn.providerSettled) throw new Error("No active Codex turn to steer");
1886
+ const insertionIndex = binding.sessionState.entries.length;
1791
1887
  const response = await withTimeout(
1792
1888
  binding.connection.request(CODEX_STEER_METHOD, {
1793
1889
  sessionId: binding.sessionId,
1794
1890
  prompt: content,
1795
- clientMessageId,
1891
+ clientMessageId
1796
1892
  }),
1797
1893
  this.requestTimeoutMs,
1798
- 'Codex ACP steer',
1894
+ "Codex ACP steer"
1799
1895
  );
1800
- this.requireCurrentTurn(binding, turn, ['running']);
1896
+ this.requireCurrentTurn(binding, turn, ["running"]);
1897
+ const turnId = String(response?.turnId || "");
1898
+ if (binding.sessionState.recordAcceptedSteer(content, {
1899
+ messageId: clientMessageId,
1900
+ turnId,
1901
+ insertionIndex
1902
+ })) {
1903
+ this.emitSession(binding);
1904
+ }
1801
1905
  return {
1802
1906
  sessionId: binding.sessionId,
1803
- turnId: String(response?.turnId || ''),
1804
- clientMessageId,
1907
+ turnId,
1908
+ clientMessageId
1805
1909
  };
1806
1910
  };
1807
1911
  return this.enqueueTurnControl(turn, operation);
1808
1912
  }
1809
-
1810
1913
  async cancel(agentId) {
1811
1914
  const binding = this.requireBinding(agentId);
1812
1915
  this.requireOpenBinding(binding);
1813
- if (binding.state === 'closed') throw new Error('ACP session is closed');
1916
+ if (binding.state === "closed") throw new Error("ACP session is closed");
1814
1917
  if (!binding.sessionId) return false;
1815
1918
  const turn = binding.activeTurn;
1816
- if (turn?.phase === 'admitting') {
1919
+ if (turn?.phase === "admitting") {
1817
1920
  this.cancelAdmittingTurn(binding, turn);
1818
1921
  return true;
1819
1922
  }
1820
- if (!turn && (
1821
- binding.sessionMutation
1822
- || binding.configMutationTail
1823
- || binding.patchDecisionInFlight.size > 0
1824
- )) {
1923
+ if (!turn && (binding.sessionMutation || binding.configMutationTail || binding.patchDecisionInFlight.size > 0)) {
1825
1924
  throw new Error(`ACP Agent is not ready for cancellation (${binding.state})`);
1826
1925
  }
1827
1926
  if (turn?.cancelPromise) return turn.cancelPromise;
1828
-
1829
1927
  const stateBeforeCancellation = binding.state;
1830
1928
  let cancelAcknowledged = false;
1831
1929
  const cancelOperation = async () => {
1832
1930
  const activeSubagentSessionIds = this.activeSubagentSessionIds(binding);
1833
1931
  if (turn) {
1834
- this.requireCurrentTurn(binding, turn, ['running']);
1835
- if (turn.providerSettled) throw new Error('No active turn to cancel');
1836
- turn.phase = 'cancelling';
1932
+ this.requireCurrentTurn(binding, turn, ["running"]);
1933
+ if (turn.providerSettled) throw new Error("No active turn to cancel");
1934
+ turn.phase = "cancelling";
1837
1935
  }
1838
- binding.state = 'interrupting';
1936
+ binding.state = "interrupting";
1839
1937
  for (const resolve of binding.permissionResolvers.values()) {
1840
- resolve({ outcome: { outcome: 'cancelled' } });
1938
+ resolve({ outcome: { outcome: "cancelled" } });
1841
1939
  }
1842
- for (const resolve of binding.elicitationResolvers.values()) resolve({ action: 'cancel' });
1940
+ for (const resolve of binding.elicitationResolvers.values()) resolve({ action: "cancel" });
1843
1941
  binding.permissionResolvers.clear();
1844
1942
  binding.pendingPermissions.clear();
1845
1943
  binding.elicitationResolvers.clear();
1846
1944
  binding.pendingElicitations.clear();
1945
+ binding.farmingBrowserApprovalScopes.clear();
1847
1946
  binding.activeElicitations.clear();
1848
1947
  binding.interactionOrigins.clear();
1849
1948
  this.emitRuntime(binding);
@@ -1851,9 +1950,9 @@ class AcpRuntime extends EventEmitter {
1851
1950
  withTimeout(
1852
1951
  binding.connection.cancel({ sessionId: binding.sessionId }),
1853
1952
  this.cancelTimeoutMs,
1854
- 'ACP session/cancel'
1953
+ "ACP session/cancel"
1855
1954
  ),
1856
- ...activeSubagentSessionIds.map(sessionId => this.cancelSubagentControl(binding, sessionId)),
1955
+ ...activeSubagentSessionIds.map((sessionId) => this.cancelSubagentControl(binding, sessionId))
1857
1956
  ]);
1858
1957
  this.requireOpenBinding(binding);
1859
1958
  cancelAcknowledged = true;
@@ -1864,27 +1963,25 @@ class AcpRuntime extends EventEmitter {
1864
1963
  if (turn) await this.enqueueTurnControl(turn, cancelOperation);
1865
1964
  else await cancelOperation();
1866
1965
  if (!turn) {
1867
- if (binding.state === 'interrupting') {
1868
- binding.state = ['idle', 'error'].includes(stateBeforeCancellation)
1869
- ? stateBeforeCancellation
1870
- : 'idle';
1966
+ if (binding.state === "interrupting") {
1967
+ binding.state = ["idle", "error"].includes(stateBeforeCancellation) ? stateBeforeCancellation : "idle";
1871
1968
  }
1872
- binding.updatedAt = new Date().toISOString();
1969
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1873
1970
  this.emitRuntime(binding);
1874
1971
  return true;
1875
1972
  }
1876
- await withTimeout(turn.completion, this.cancelTimeoutMs, 'ACP turn cancellation');
1973
+ await withTimeout(turn.completion, this.cancelTimeoutMs, "ACP turn cancellation");
1877
1974
  return true;
1878
1975
  } catch (error) {
1879
1976
  const runtimeError = new Error(acpErrorMessage(error), { cause: error });
1880
1977
  if (!this.isOpenBinding(binding)) throw runtimeError;
1881
1978
  const markBlocked = () => {
1882
1979
  if (turn && binding.activeTurn !== turn) return;
1883
- if (turn) turn.phase = 'blocked';
1884
- binding.state = 'error';
1980
+ if (turn) turn.phase = "blocked";
1981
+ binding.state = "error";
1885
1982
  binding.error = runtimeError.message;
1886
- binding.stopReason = turn && cancelAcknowledged ? 'cancel_timeout' : 'cancel_error';
1887
- binding.updatedAt = new Date().toISOString();
1983
+ binding.stopReason = turn && cancelAcknowledged ? "cancel_timeout" : "cancel_error";
1984
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1888
1985
  this.emitSession(binding);
1889
1986
  this.emitRuntime(binding);
1890
1987
  };
@@ -1900,31 +1997,32 @@ class AcpRuntime extends EventEmitter {
1900
1997
  if (turn?.cancelPromise === cancellation) turn.cancelPromise = null;
1901
1998
  }
1902
1999
  }
1903
-
1904
2000
  cancelSubagentControl(binding, targetSessionId) {
1905
2001
  const control = this.ensureSubagentControl(binding, targetSessionId);
1906
2002
  if (control.cancelPromise) return control.cancelPromise;
1907
- if (['cancelled', 'completed'].includes(control.phase)) {
2003
+ if (["cancelled", "completed"].includes(control.phase)) {
1908
2004
  return Promise.resolve({ cancelled: true, sessionId: targetSessionId });
1909
2005
  }
1910
- control.phase = 'cancelling';
1911
- control.error = '';
2006
+ control.phase = "cancelling";
2007
+ control.error = "";
1912
2008
  for (const [requestId, pending] of binding.pendingPermissions.entries()) {
1913
- if (String(pending?.sessionId || '') !== targetSessionId) continue;
1914
- binding.permissionResolvers.get(requestId)?.({ outcome: { outcome: 'cancelled' } });
2009
+ if (String(pending?.sessionId || "") !== targetSessionId) continue;
2010
+ binding.permissionResolvers.get(requestId)?.({ outcome: { outcome: "cancelled" } });
1915
2011
  binding.permissionResolvers.delete(requestId);
1916
2012
  binding.pendingPermissions.delete(requestId);
2013
+ binding.farmingBrowserApprovalScopes.delete(requestId);
1917
2014
  binding.interactionOrigins.delete(requestId);
1918
2015
  }
1919
2016
  for (const [requestId, pending] of binding.pendingElicitations.entries()) {
1920
- if (String(pending?.sessionId || '') !== targetSessionId) continue;
1921
- binding.elicitationResolvers.get(requestId)?.({ action: 'cancel' });
2017
+ if (String(pending?.sessionId || "") !== targetSessionId) continue;
2018
+ binding.elicitationResolvers.get(requestId)?.({ action: "cancel" });
1922
2019
  binding.elicitationResolvers.delete(requestId);
1923
2020
  binding.pendingElicitations.delete(requestId);
2021
+ binding.farmingBrowserApprovalScopes.delete(requestId);
1924
2022
  binding.interactionOrigins.delete(requestId);
1925
2023
  }
1926
2024
  for (const [elicitationId, active] of binding.activeElicitations.entries()) {
1927
- if (String(active?.sessionId || '') === targetSessionId) binding.activeElicitations.delete(elicitationId);
2025
+ if (String(active?.sessionId || "") === targetSessionId) binding.activeElicitations.delete(elicitationId);
1928
2026
  }
1929
2027
  binding.state = interactiveRuntimeState(binding, binding.state);
1930
2028
  this.emitRuntime(binding);
@@ -1933,23 +2031,23 @@ class AcpRuntime extends EventEmitter {
1933
2031
  await withTimeout(
1934
2032
  binding.connection.cancel({ sessionId: targetSessionId }),
1935
2033
  this.cancelTimeoutMs,
1936
- 'ACP subagent session/cancel'
2034
+ "ACP subagent session/cancel"
1937
2035
  );
1938
2036
  this.requireOpenBinding(binding);
1939
2037
  if (binding.subagentControls.get(targetSessionId) !== control) {
1940
- throw new Error('ACP subagent control is no longer active');
2038
+ throw new Error("ACP subagent control is no longer active");
1941
2039
  }
1942
- control.phase = 'cancelled';
1943
- control.error = '';
1944
- binding.updatedAt = new Date().toISOString();
2040
+ control.phase = "cancelled";
2041
+ control.error = "";
2042
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1945
2043
  this.emitSession(binding);
1946
2044
  this.emitRuntime(binding);
1947
2045
  return { cancelled: true, sessionId: targetSessionId };
1948
2046
  } catch (error) {
1949
2047
  if (this.isOpenBinding(binding) && binding.subagentControls.get(targetSessionId) === control) {
1950
- control.phase = 'error';
2048
+ control.phase = "error";
1951
2049
  control.error = acpErrorMessage(error);
1952
- binding.updatedAt = new Date().toISOString();
2050
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1953
2051
  this.emitSession(binding);
1954
2052
  this.emitRuntime(binding);
1955
2053
  }
@@ -1961,51 +2059,48 @@ class AcpRuntime extends EventEmitter {
1961
2059
  if (binding.subagentControls.get(targetSessionId) === control && control.cancelPromise === cancellation) {
1962
2060
  control.cancelPromise = null;
1963
2061
  }
1964
- }).catch(() => {});
2062
+ }).catch(() => {
2063
+ });
1965
2064
  return cancellation;
1966
2065
  }
1967
-
1968
2066
  async cancelSubagent(agentId, sessionId) {
1969
2067
  const binding = this.requireBinding(agentId);
1970
2068
  this.requireOpenBinding(binding);
1971
- const targetSessionId = String(sessionId || '');
2069
+ const targetSessionId = String(sessionId || "");
1972
2070
  if (!targetSessionId || targetSessionId === binding.sessionId || !binding.subagentStates.has(targetSessionId)) {
1973
- throw new Error('ACP subagent session not found');
2071
+ throw new Error("ACP subagent session not found");
1974
2072
  }
1975
2073
  return this.cancelSubagentControl(binding, targetSessionId);
1976
2074
  }
1977
-
1978
2075
  async listSessions(agentId, options = {}) {
1979
2076
  const binding = this.requireBinding(agentId);
1980
2077
  this.requireOpenBinding(binding);
1981
2078
  const capabilities = binding.initializeResponse?.agentCapabilities?.sessionCapabilities;
1982
2079
  if (!capabilities?.list) throw new Error(`${binding.provider} ACP Agent does not support session/list`);
1983
2080
  const response = await withTimeout(binding.connection.listSessions({
1984
- ...(options.cwd ? { cwd: path.resolve(options.cwd) } : {}),
1985
- ...(Array.isArray(options.additionalDirectories)
1986
- ? { additionalDirectories: acpSessionRequestOptions(options, options.cwd || binding.cwd).additionalDirectories }
1987
- : {}),
1988
- ...(options.cursor ? { cursor: String(options.cursor) } : {}),
1989
- }), this.requestTimeoutMs, 'ACP session/list');
2081
+ ...options.cwd ? { cwd: path.resolve(options.cwd) } : {},
2082
+ ...Array.isArray(options.additionalDirectories) ? { additionalDirectories: acpSessionRequestOptions(options, options.cwd || binding.cwd).additionalDirectories } : {},
2083
+ ...options.cursor ? { cursor: String(options.cursor) } : {}
2084
+ }), this.requestTimeoutMs, "ACP session/list");
1990
2085
  this.requireOpenBinding(binding);
1991
2086
  return response;
1992
2087
  }
1993
-
1994
2088
  getSessionRequestOptions(agentId) {
1995
2089
  const binding = this.requireBinding(agentId);
1996
2090
  return clone(binding.sessionRequestOptions);
1997
2091
  }
1998
-
1999
2092
  async authenticate(agentId, methodId) {
2000
2093
  const binding = this.requireBinding(agentId);
2001
2094
  this.requireOpenBinding(binding);
2002
- if (binding.state === 'closed') throw new Error('ACP session is closed');
2003
- const mutation = this.beginSessionMutation(binding, 'authentication');
2004
- const method = binding.initializeResponse?.authMethods?.find(item => item.id === methodId);
2095
+ if (binding.state === "closed") throw new Error("ACP session is closed");
2096
+ const mutation = this.beginSessionMutation(binding, "authentication");
2097
+ const method = binding.initializeResponse?.authMethods?.find(
2098
+ (item) => item.id === methodId
2099
+ );
2005
2100
  let terminalReservationTransferred = false;
2006
2101
  try {
2007
- if (!method) throw new Error('Unknown ACP authentication method');
2008
- if (method.type === 'terminal' || method?._meta?.['terminal-auth']) {
2102
+ if (!method) throw new Error("Unknown ACP authentication method");
2103
+ if (method.type === "terminal" || recordValue(method._meta).type === "terminal" || recordValue(method._meta)["terminal-auth"]) {
2009
2104
  const result = await this.startTerminalAuthentication(binding, method, mutation);
2010
2105
  terminalReservationTransferred = true;
2011
2106
  return result;
@@ -2013,13 +2108,13 @@ class AcpRuntime extends EventEmitter {
2013
2108
  await withTimeout(
2014
2109
  binding.connection.authenticate({ methodId }),
2015
2110
  this.requestTimeoutMs,
2016
- 'ACP authenticate'
2111
+ "ACP authenticate"
2017
2112
  );
2018
2113
  this.requireOpenBinding(binding);
2019
- binding.error = '';
2020
- binding.stopReason = '';
2021
- binding.state = interactiveRuntimeState(binding, 'idle');
2022
- binding.updatedAt = new Date().toISOString();
2114
+ binding.error = "";
2115
+ binding.stopReason = "";
2116
+ binding.state = interactiveRuntimeState(binding, "idle");
2117
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2023
2118
  this.emitRuntime(binding);
2024
2119
  this.emitSession(binding);
2025
2120
  return { authenticated: true, methodId };
@@ -2027,20 +2122,19 @@ class AcpRuntime extends EventEmitter {
2027
2122
  if (!terminalReservationTransferred) this.endSessionMutation(binding, mutation);
2028
2123
  }
2029
2124
  }
2030
-
2031
2125
  async logout(agentId) {
2032
2126
  const binding = this.requireBinding(agentId);
2033
2127
  this.requireOpenBinding(binding);
2034
- const mutation = this.beginSessionMutation(binding, 'logout');
2128
+ const mutation = this.beginSessionMutation(binding, "logout");
2035
2129
  try {
2036
- if (binding.initializeResponse?.agentCapabilities?.auth?.logout == null) {
2130
+ if (recordValue(binding.initializeResponse?.agentCapabilities?.auth).logout == null) {
2037
2131
  throw new Error(`${binding.provider} ACP Agent does not support logout`);
2038
2132
  }
2039
- await withTimeout(binding.connection.logout({}), this.requestTimeoutMs, 'ACP logout');
2133
+ await withTimeout(binding.connection.logout({}), this.requestTimeoutMs, "ACP logout");
2040
2134
  this.requireOpenBinding(binding);
2041
- binding.error = '';
2042
- binding.stopReason = '';
2043
- binding.updatedAt = new Date().toISOString();
2135
+ binding.error = "";
2136
+ binding.stopReason = "";
2137
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2044
2138
  this.emitRuntime(binding);
2045
2139
  this.emitSession(binding);
2046
2140
  return { loggedOut: true };
@@ -2048,28 +2142,31 @@ class AcpRuntime extends EventEmitter {
2048
2142
  this.endSessionMutation(binding, mutation);
2049
2143
  }
2050
2144
  }
2051
-
2052
2145
  terminalAuthenticationLaunch(binding, method) {
2053
- const legacy = method?._meta?.['terminal-auth'];
2054
- if (legacy && typeof legacy === 'object' && legacy.command) {
2146
+ const metadata = method._meta && typeof method._meta === "object" ? method._meta : {};
2147
+ const legacy = metadata["terminal-auth"];
2148
+ if (legacy && typeof legacy === "object" && legacy.command) {
2055
2149
  return {
2056
2150
  command: String(legacy.command),
2057
2151
  args: Array.isArray(legacy.args) ? legacy.args.map(String) : [],
2058
- env: legacy.env && typeof legacy.env === 'object' ? legacy.env : {},
2152
+ env: legacy.env && typeof legacy.env === "object" ? legacy.env : {}
2059
2153
  };
2060
2154
  }
2061
- if (method.type !== 'terminal') throw new Error('ACP authentication method is not terminal based');
2155
+ const terminalMethod = method.type === "terminal" ? method : metadata.type === "terminal" ? metadata : null;
2156
+ if (!terminalMethod) throw new Error("ACP authentication method is not terminal based");
2062
2157
  return {
2063
2158
  command: binding.launch.command,
2064
- args: [...binding.launch.args, ...(Array.isArray(method.args) ? method.args.map(String) : [])],
2065
- env: method.env && typeof method.env === 'object' ? method.env : {},
2159
+ args: [
2160
+ ...binding.launch.args,
2161
+ ...Array.isArray(terminalMethod.args) ? terminalMethod.args.map(String) : []
2162
+ ],
2163
+ env: terminalMethod.env && typeof terminalMethod.env === "object" ? terminalMethod.env : {}
2066
2164
  };
2067
2165
  }
2068
-
2069
2166
  async startTerminalAuthentication(binding, method, mutation) {
2070
2167
  this.requireOpenBinding(binding);
2071
- if (binding.sessionMutation !== mutation) throw new Error('ACP authentication reservation is no longer active');
2072
- if (binding.authTerminal?.state === 'running') throw new Error('ACP terminal authentication is already running');
2168
+ if (binding.sessionMutation !== mutation) throw new Error("ACP authentication reservation is no longer active");
2169
+ if (binding.authTerminal?.state === "running") throw new Error("ACP terminal authentication is already running");
2073
2170
  const launch = this.terminalAuthenticationLaunch(binding, method);
2074
2171
  const created = await this.clientTerminals.create(binding, {
2075
2172
  sessionId: binding.sessionId,
@@ -2077,7 +2174,7 @@ class AcpRuntime extends EventEmitter {
2077
2174
  args: launch.args,
2078
2175
  cwd: binding.cwd,
2079
2176
  env: Object.entries(launch.env).map(([name, value]) => ({ name, value: String(value) })),
2080
- outputByteLimit: 2 * 1024 * 1024,
2177
+ outputByteLimit: 2 * 1024 * 1024
2081
2178
  });
2082
2179
  try {
2083
2180
  this.requireOpenBinding(binding);
@@ -2085,69 +2182,67 @@ class AcpRuntime extends EventEmitter {
2085
2182
  try {
2086
2183
  this.clientTerminals.release(binding, {
2087
2184
  sessionId: binding.sessionId,
2088
- terminalId: created.terminalId,
2185
+ terminalId: created.terminalId
2089
2186
  });
2090
2187
  } catch {
2091
- // Binding teardown may already have removed the terminal.
2092
2188
  }
2093
2189
  throw error;
2094
2190
  }
2095
2191
  binding.authTerminal = {
2096
2192
  terminalId: created.terminalId,
2097
- methodId: String(method.id || ''),
2098
- name: String(method.name || 'Sign in'),
2099
- state: 'running',
2100
- error: '',
2193
+ methodId: String(method.id || ""),
2194
+ name: String(method.name || "Sign in"),
2195
+ state: "running",
2196
+ error: ""
2101
2197
  };
2102
- binding.updatedAt = new Date().toISOString();
2198
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2103
2199
  this.emitRuntime(binding);
2104
2200
  this.emitSession(binding);
2105
2201
  void Promise.resolve(this.clientTerminals.waitForExit(binding, {
2106
2202
  sessionId: binding.sessionId,
2107
- terminalId: created.terminalId,
2108
- })).then(async exit => {
2203
+ terminalId: created.terminalId
2204
+ })).then(async (exit) => {
2109
2205
  if (!this.isOpenBinding(binding) || binding.sessionMutation !== mutation) return;
2110
2206
  if (exit.exitCode !== 0) {
2111
- binding.authTerminal.state = 'failed';
2112
- binding.authTerminal.error = `Sign-in command exited ${exit.exitCode ?? exit.signal ?? ''}`.trim();
2207
+ binding.authTerminal.state = "failed";
2208
+ binding.authTerminal.error = `Sign-in command exited ${exit.exitCode ?? exit.signal ?? ""}`.trim();
2113
2209
  this.endSessionMutation(binding, mutation);
2114
- binding.updatedAt = new Date().toISOString();
2210
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2115
2211
  this.emitRuntime(binding);
2116
2212
  this.emitSession(binding);
2117
2213
  return;
2118
2214
  }
2119
- binding.authTerminal.state = 'completed';
2120
- binding.updatedAt = new Date().toISOString();
2215
+ binding.authTerminal.state = "completed";
2216
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2121
2217
  this.emitSession(binding);
2122
- await this.restartAgentConnection(binding.agentId, mutation).catch(error => {
2218
+ await this.restartAgentConnection(binding.agentId, mutation).catch((error) => {
2123
2219
  const current = this.bindings.get(binding.agentId);
2124
2220
  if (current !== binding || current.exited) return;
2125
2221
  this.endSessionMutation(current, mutation);
2126
- current.state = 'error';
2222
+ current.state = "error";
2127
2223
  current.error = acpErrorMessage(error);
2128
- current.updatedAt = new Date().toISOString();
2224
+ current.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2129
2225
  this.emitRuntime(current);
2130
2226
  });
2131
- }).catch(error => {
2227
+ }).catch((error) => {
2132
2228
  if (!this.isOpenBinding(binding) || binding.sessionMutation !== mutation) return;
2133
- binding.authTerminal.state = 'failed';
2229
+ binding.authTerminal.state = "failed";
2134
2230
  binding.authTerminal.error = acpErrorMessage(error);
2135
2231
  this.endSessionMutation(binding, mutation);
2136
- binding.updatedAt = new Date().toISOString();
2232
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2137
2233
  this.emitRuntime(binding);
2138
2234
  this.emitSession(binding);
2139
2235
  });
2140
2236
  return { authenticated: false, methodId: method.id, terminalId: created.terminalId };
2141
2237
  }
2142
-
2143
2238
  async restartAgentConnection(agentId, mutation = null) {
2144
2239
  const binding = this.requireBinding(agentId);
2145
2240
  this.requireOpenBinding(binding);
2146
- if (binding.activeTurn || (binding.sessionMutation && binding.sessionMutation !== mutation)) {
2241
+ if (binding.activeTurn || binding.sessionMutation && binding.sessionMutation !== mutation) {
2147
2242
  throw new Error(`ACP Agent is not ready for restart (${binding.state})`);
2148
2243
  }
2149
2244
  if (mutation && binding.sessionMutation !== mutation) {
2150
- throw new Error('ACP restart reservation is no longer active');
2245
+ throw new Error("ACP restart reservation is no longer active");
2151
2246
  }
2152
2247
  const revisionBase = Number(binding.sessionState?.revision || 0);
2153
2248
  const options = {
@@ -2157,9 +2252,9 @@ class AcpRuntime extends EventEmitter {
2157
2252
  cwd: binding.cwd,
2158
2253
  env: binding.env,
2159
2254
  approvalMode: binding.approvalMode,
2160
- ...(binding.sessionId ? { sessionId: binding.sessionId } : {}),
2161
- ...(revisionBase > 0 ? { revisionBase } : {}),
2162
- ...(binding.sessionId ? { historyMode: 'checkpoint' } : {}),
2255
+ ...binding.sessionId ? { sessionId: binding.sessionId } : {},
2256
+ ...revisionBase > 0 ? { revisionBase } : {},
2257
+ ...binding.sessionId ? { historyMode: "checkpoint" } : {}
2163
2258
  };
2164
2259
  if (binding.sessionState && !binding.activeTurn) {
2165
2260
  await this.writeCheckpoint(binding, { exact: true });
@@ -2168,136 +2263,152 @@ class AcpRuntime extends EventEmitter {
2168
2263
  await this.unregisterAgentAndWait(agentId, binding);
2169
2264
  return this.prepareAgent(options);
2170
2265
  }
2171
-
2172
2266
  async forkSession(agentId, options = {}) {
2173
- return this.runWithForkReservation(agentId, options, async binding => {
2267
+ return this.runWithForkReservation(agentId, options, async (binding) => {
2174
2268
  const sessionOptions = acpSessionRequestOptions({
2175
2269
  additionalDirectories: options.additionalDirectories ?? binding.sessionRequestOptions.additionalDirectories,
2176
- mcpServers: options.mcpServers ?? binding.sessionRequestOptions.mcpServers,
2270
+ mcpServers: options.mcpServers ?? binding.sessionRequestOptions.mcpServers
2177
2271
  }, options.cwd || binding.cwd);
2178
2272
  const response = await withTimeout(binding.connection.unstable_forkSession({
2179
2273
  sessionId: options.sessionId || binding.sessionId,
2180
- ...sessionOptions,
2181
- }), this.sessionSetupTimeoutMs, 'ACP session/fork');
2274
+ ...sessionOptions
2275
+ }), this.sessionSetupTimeoutMs, "ACP session/fork");
2182
2276
  this.requireOpenBinding(binding);
2183
- const sessionId = String(response?.sessionId || '').trim();
2184
- if (!isSafeProviderSessionId(sessionId) || sessionId === binding.sessionId) {
2185
- throw new Error('ACP session/fork returned an invalid new session id');
2277
+ const sessionId = String(response?.sessionId || "").trim();
2278
+ if (!(0, import_provider_session_id.isSafeProviderSessionId)(sessionId) || sessionId === binding.sessionId) {
2279
+ throw new Error("ACP session/fork returned an invalid new session id");
2186
2280
  }
2187
2281
  return { ...response, sessionId };
2188
2282
  });
2189
2283
  }
2190
-
2191
- async runWithForkReservation(agentId, options = {}, operation) {
2284
+ async runWithForkReservation(agentId, options, operation) {
2192
2285
  const binding = this.requireBinding(agentId);
2193
- const mutation = this.beginSessionMutation(binding, 'fork');
2286
+ const mutation = this.beginSessionMutation(binding, "fork");
2194
2287
  try {
2195
2288
  const capabilities = binding.initializeResponse?.agentCapabilities?.sessionCapabilities;
2196
2289
  if (!capabilities?.fork) throw new Error(`${binding.provider} ACP Agent does not support session/fork`);
2197
2290
  if (options.requireLoad === true && !binding.initializeResponse?.agentCapabilities?.loadSession) {
2198
2291
  throw new Error(`${binding.provider} ACP Agent cannot load a forked conversation`);
2199
2292
  }
2200
- if (
2201
- Number.isFinite(options.expectedRevision)
2202
- && Number(binding.sessionState?.revision || 0) !== Math.floor(options.expectedRevision)
2203
- ) {
2204
- throw new Error('ACP conversation changed before it could be forked. Try again from the latest answer.');
2293
+ if (typeof options.expectedRevision === "number" && Number.isFinite(options.expectedRevision) && Number(binding.sessionState?.revision || 0) !== Math.floor(options.expectedRevision)) {
2294
+ throw new Error("ACP conversation changed before it could be forked. Try again from the latest answer.");
2205
2295
  }
2206
- if (typeof operation !== 'function') throw new Error('ACP fork operation is required');
2296
+ if (typeof operation !== "function") throw new Error("ACP fork operation is required");
2207
2297
  return await operation(binding);
2208
2298
  } finally {
2209
2299
  this.endSessionMutation(binding, mutation);
2210
2300
  }
2211
2301
  }
2212
-
2213
2302
  async deleteSession(agentId, sessionId) {
2214
2303
  const binding = this.requireBinding(agentId);
2215
- const mutation = this.beginSessionMutation(binding, 'session deletion');
2304
+ const mutation = this.beginSessionMutation(binding, "session deletion");
2216
2305
  try {
2217
2306
  const capabilities = binding.initializeResponse?.agentCapabilities?.sessionCapabilities;
2218
2307
  if (!capabilities?.delete) throw new Error(`${binding.provider} ACP Agent does not support session/delete`);
2219
2308
  await withTimeout(
2220
- binding.connection.deleteSession({ sessionId: String(sessionId || '') }),
2309
+ binding.connection.deleteSession({ sessionId: String(sessionId || "") }),
2221
2310
  this.requestTimeoutMs,
2222
- 'ACP session/delete'
2311
+ "ACP session/delete"
2223
2312
  );
2224
2313
  this.requireOpenBinding(binding);
2225
- return { deleted: true, sessionId: String(sessionId || '') };
2314
+ return { deleted: true, sessionId: String(sessionId || "") };
2226
2315
  } finally {
2227
2316
  this.endSessionMutation(binding, mutation);
2228
2317
  }
2229
2318
  }
2230
-
2231
2319
  async closeSession(agentId) {
2232
2320
  const binding = this.requireBinding(agentId);
2233
- const mutation = this.beginSessionMutation(binding, 'session close');
2321
+ const mutation = this.beginSessionMutation(binding, "session close");
2234
2322
  try {
2235
2323
  const capabilities = binding.initializeResponse?.agentCapabilities?.sessionCapabilities;
2236
2324
  if (!capabilities?.close) throw new Error(`${binding.provider} ACP Agent does not support session/close`);
2237
2325
  await withTimeout(
2238
2326
  binding.connection.closeSession({ sessionId: binding.sessionId }),
2239
2327
  this.requestTimeoutMs,
2240
- 'ACP session/close'
2328
+ "ACP session/close"
2241
2329
  );
2242
2330
  this.requireOpenBinding(binding);
2243
- binding.state = 'closed';
2331
+ binding.state = "closed";
2244
2332
  this.emitRuntime(binding);
2245
2333
  return { closed: true, sessionId: binding.sessionId };
2246
2334
  } finally {
2247
2335
  this.endSessionMutation(binding, mutation);
2248
2336
  }
2249
2337
  }
2250
-
2251
2338
  async setSessionMode(agentId, modeId) {
2252
2339
  const binding = this.requireBinding(agentId);
2340
+ if (binding.activeTurn || binding.deferredConfigFlush) {
2341
+ const normalizedModeId = String(modeId || "");
2342
+ const advertisedModes = Array.isArray(binding.modes?.availableModes) ? binding.modes.availableModes : [];
2343
+ if (!normalizedModeId || !advertisedModes.some((mode) => String(recordValue(mode).id || "") === normalizedModeId)) {
2344
+ throw new Error(`ACP Agent did not advertise mode ${normalizedModeId}`);
2345
+ }
2346
+ const previousModeId = binding.deferredModeId;
2347
+ const previousGeneration = binding.deferredModeGeneration;
2348
+ const generation = binding.deferredModeGeneration + 1;
2349
+ binding.deferredModeGeneration = generation;
2350
+ binding.deferredModeId = normalizedModeId;
2351
+ try {
2352
+ await this.writeCheckpoint(binding);
2353
+ } catch (error) {
2354
+ if (binding.deferredModeGeneration === generation) {
2355
+ binding.deferredModeGeneration = previousGeneration;
2356
+ binding.deferredModeId = previousModeId;
2357
+ }
2358
+ throw error;
2359
+ }
2360
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2361
+ this.emitRuntime(binding);
2362
+ return {
2363
+ sessionId: binding.sessionId,
2364
+ deferred: true,
2365
+ modeId: normalizedModeId,
2366
+ deferredModeId: normalizedModeId
2367
+ };
2368
+ }
2253
2369
  this.requireConfigMutationReady(binding);
2254
- return this.enqueueSessionConfigMutation(binding, () => (
2255
- this.setSessionModeNow(binding, modeId)
2256
- ));
2370
+ const result = await this.enqueueSessionConfigMutation(binding, () => this.setSessionModeNow(binding, modeId));
2371
+ if (this.clearDeferredSessionError(binding)) {
2372
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2373
+ this.emitRuntime(binding);
2374
+ }
2375
+ return result;
2257
2376
  }
2258
-
2259
2377
  async setSessionModeNow(binding, modeId) {
2260
2378
  this.requireOpenBinding(binding);
2261
2379
  await withTimeout(
2262
- binding.connection.setSessionMode({ sessionId: binding.sessionId, modeId: String(modeId || '') }),
2380
+ binding.connection.setSessionMode({ sessionId: binding.sessionId, modeId: String(modeId || "") }),
2263
2381
  this.requestTimeoutMs,
2264
- 'ACP session/set_mode'
2382
+ "ACP session/set_mode"
2265
2383
  );
2266
2384
  this.requireOpenBinding(binding);
2267
- binding.sessionState.currentModeId = String(modeId || '');
2385
+ binding.sessionState.currentModeId = String(modeId || "");
2268
2386
  if (binding.modes) binding.modes = { ...binding.modes, currentModeId: binding.sessionState.currentModeId };
2269
2387
  this.scheduleCheckpoint(binding, { exact: true });
2270
2388
  this.emitSession(binding);
2271
2389
  return { sessionId: binding.sessionId, modeId: binding.sessionState.currentModeId };
2272
2390
  }
2273
-
2274
2391
  async setSessionConfigOption(agentId, configId, value) {
2275
2392
  const binding = this.requireBinding(agentId);
2393
+ if (binding.activeTurn || binding.deferredConfigFlush) {
2394
+ return this.deferSessionConfigChanges(binding, [{ configId: String(configId || ""), value }]);
2395
+ }
2276
2396
  this.requireConfigMutationReady(binding);
2277
- return this.enqueueSessionConfigMutation(binding, () => (
2278
- this.setSessionConfigOptionNow(binding, configId, value)
2279
- ));
2397
+ const result = await this.enqueueSessionConfigMutation(binding, () => this.setSessionConfigOptionNow(binding, configId, value));
2398
+ if (this.clearDeferredSessionError(binding)) {
2399
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2400
+ this.emitRuntime(binding);
2401
+ }
2402
+ return result;
2280
2403
  }
2281
-
2282
2404
  async setSessionConfigOptionNow(binding, configId, value) {
2283
2405
  this.requireOpenBinding(binding);
2284
- const option = binding.configOptions?.find(candidate => candidate.id === String(configId || ''));
2285
- if (
2286
- binding.provider === 'codex'
2287
- && option?.type === 'select'
2288
- && /(^|[\s_-])model([\s_-]|$)/i.test(`${option.id} ${option.name || ''} ${option.category || ''}`)
2289
- ) {
2290
- // Let the adapter choose a supported fallback effort from its current
2291
- // snapshot first. The refresh extension requires an explicit effort and
2292
- // would otherwise reject a valid model change (for example ultra -> a
2293
- // model that tops out at max).
2406
+ const option = binding.configOptions?.find((candidate) => candidate.id === String(configId || ""));
2407
+ if (binding.provider === "codex" && option?.type === "select" && /(^|[\s_-])model([\s_-]|$)/i.test(`${option.id} ${option.name || ""} ${option.category || ""}`)) {
2294
2408
  await this.applySessionConfigOption(binding, configId, value, { emit: false });
2295
- const reasoning = binding.configOptions?.find(candidate => (
2296
- candidate.type === 'select'
2297
- && /(reasoning|thought)/i.test(`${candidate.id} ${candidate.name || ''} ${candidate.category || ''}`)
2298
- ));
2299
- if (typeof reasoning?.currentValue === 'string' && reasoning.currentValue) {
2300
- await this.refreshCodexSessionModel(binding, String(value ?? ''), reasoning.currentValue);
2409
+ const reasoning = binding.configOptions?.find((candidate) => candidate.type === "select" && /(reasoning|thought)/i.test(`${candidate.id} ${candidate.name || ""} ${candidate.category || ""}`));
2410
+ if (typeof reasoning?.currentValue === "string" && reasoning.currentValue) {
2411
+ await this.refreshCodexSessionModel(binding, String(value ?? ""), reasoning.currentValue);
2301
2412
  return this.applySessionConfigOption(binding, configId, value, { force: true });
2302
2413
  }
2303
2414
  this.emitSession(binding);
@@ -2305,27 +2416,68 @@ class AcpRuntime extends EventEmitter {
2305
2416
  }
2306
2417
  return this.applySessionConfigOption(binding, configId, value);
2307
2418
  }
2308
-
2309
2419
  async setSessionConfigOptions(agentId, changes) {
2310
2420
  const binding = this.requireBinding(agentId);
2421
+ if (binding.activeTurn || binding.deferredConfigFlush) {
2422
+ return this.deferSessionConfigChanges(binding, changes);
2423
+ }
2311
2424
  this.requireConfigMutationReady(binding);
2312
- return this.enqueueSessionConfigMutation(binding, () => (
2313
- this.setSessionConfigOptionsNow(binding, changes)
2314
- ));
2425
+ const result = await this.enqueueSessionConfigMutation(binding, () => this.setSessionConfigOptionsNow(binding, changes));
2426
+ if (this.clearDeferredSessionError(binding)) {
2427
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2428
+ this.emitRuntime(binding);
2429
+ }
2430
+ return result;
2431
+ }
2432
+ async deferSessionConfigChanges(binding, changes) {
2433
+ const normalized = Array.isArray(changes) ? changes.filter((change) => change && typeof change.configId === "string" && change.configId) : [];
2434
+ if (normalized.length === 0) throw new Error("ACP config options are required");
2435
+ for (const change of normalized) {
2436
+ const option = binding.configOptions.find((candidate) => candidate.id === change.configId);
2437
+ if (!option) throw new Error(`ACP Agent did not advertise config option ${change.configId}`);
2438
+ if (option.type === "boolean" && typeof change.value !== "boolean") {
2439
+ throw new Error(`ACP config option ${change.configId} requires a boolean value`);
2440
+ }
2441
+ if (option.type === "select" && typeof change.value !== "string") {
2442
+ throw new Error(`ACP config option ${change.configId} requires a string value`);
2443
+ }
2444
+ }
2445
+ const accepted = normalized.map((change) => ({ configId: change.configId, value: change.value }));
2446
+ const previous = /* @__PURE__ */ new Map();
2447
+ for (const change of accepted) {
2448
+ if (!previous.has(change.configId)) previous.set(change.configId, binding.deferredConfigChanges.get(change.configId));
2449
+ binding.deferredConfigChanges.set(change.configId, change);
2450
+ }
2451
+ try {
2452
+ await this.writeCheckpoint(binding);
2453
+ } catch (error) {
2454
+ for (const change of accepted) {
2455
+ if (binding.deferredConfigChanges.get(change.configId) !== change) continue;
2456
+ const previousChange = previous.get(change.configId);
2457
+ if (previousChange) binding.deferredConfigChanges.set(change.configId, previousChange);
2458
+ else binding.deferredConfigChanges.delete(change.configId);
2459
+ }
2460
+ throw error;
2461
+ }
2462
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2463
+ this.emitRuntime(binding);
2464
+ return {
2465
+ sessionId: binding.sessionId,
2466
+ deferred: true,
2467
+ configOptions: binding.configOptions,
2468
+ deferredConfigOptions: [...binding.deferredConfigChanges.values()],
2469
+ deferredModeId: binding.deferredModeId
2470
+ };
2315
2471
  }
2316
-
2317
2472
  async setSessionConfigOptionsNow(binding, changes) {
2318
2473
  this.requireOpenBinding(binding);
2319
- const normalized = Array.isArray(changes)
2320
- ? changes.filter(change => change && typeof change.configId === 'string' && Object.prototype.hasOwnProperty.call(change, 'value'))
2321
- : [];
2322
- if (normalized.length === 0) throw new Error('ACP config options are required');
2323
-
2324
- const originalValues = new Map();
2474
+ const normalized = Array.isArray(changes) ? changes.filter((change) => change && typeof change.configId === "string" && Object.prototype.hasOwnProperty.call(change, "value")) : [];
2475
+ if (normalized.length === 0) throw new Error("ACP config options are required");
2476
+ const originalValues = /* @__PURE__ */ new Map();
2325
2477
  for (const change of normalized) {
2326
2478
  if (originalValues.has(change.configId)) continue;
2327
- const option = binding.configOptions?.find(candidate => candidate.id === change.configId);
2328
- if (option && Object.prototype.hasOwnProperty.call(option, 'currentValue')) {
2479
+ const option = binding.configOptions?.find((candidate) => candidate.id === change.configId);
2480
+ if (option && Object.prototype.hasOwnProperty.call(option, "currentValue")) {
2329
2481
  originalValues.set(change.configId, option.currentValue);
2330
2482
  }
2331
2483
  }
@@ -2334,7 +2486,7 @@ class AcpRuntime extends EventEmitter {
2334
2486
  } catch (error) {
2335
2487
  const rollbackErrors = [];
2336
2488
  for (const [configId, value] of [...originalValues.entries()].reverse()) {
2337
- const current = binding.configOptions?.find(candidate => candidate.id === configId);
2489
+ const current = binding.configOptions?.find((candidate) => candidate.id === configId);
2338
2490
  if (current?.currentValue === value) continue;
2339
2491
  try {
2340
2492
  await this.setSessionConfigOptionNow(binding, configId, value);
@@ -2342,43 +2494,38 @@ class AcpRuntime extends EventEmitter {
2342
2494
  rollbackErrors.push(rollbackError);
2343
2495
  }
2344
2496
  }
2345
- if (rollbackErrors.length > 0 && error && typeof error === 'object') {
2346
- Object.defineProperty(error, 'configRollbackError', {
2347
- value: new AggregateError(rollbackErrors, 'ACP config rollback failed'),
2497
+ if (rollbackErrors.length > 0 && error && typeof error === "object") {
2498
+ Object.defineProperty(error, "configRollbackError", {
2499
+ value: new AggregateError(rollbackErrors, "ACP config rollback failed"),
2348
2500
  enumerable: false,
2349
- configurable: true,
2501
+ configurable: true
2350
2502
  });
2351
2503
  }
2352
2504
  throw error;
2353
2505
  }
2354
2506
  }
2355
-
2356
2507
  async applySessionConfigOptionsNow(binding, normalized) {
2357
- const configById = new Map((binding.configOptions || []).map(option => [option.id, option]));
2358
- const modelChange = normalized.find(change => {
2508
+ const configById = new Map(
2509
+ (binding.configOptions || []).map((option) => [option.id, option])
2510
+ );
2511
+ const modelChange = normalized.find((change) => {
2359
2512
  const option = configById.get(change.configId);
2360
- return option?.type === 'select'
2361
- && /(^|[\s_-])model([\s_-]|$)/i.test(`${option.id} ${option.name || ''} ${option.category || ''}`);
2513
+ return option?.type === "select" && /(^|[\s_-])model([\s_-]|$)/i.test(`${option.id} ${option.name || ""} ${option.category || ""}`);
2362
2514
  });
2363
- const reasoningChange = normalized.find(change => {
2515
+ const reasoningChange = normalized.find((change) => {
2364
2516
  const option = configById.get(change.configId);
2365
- return option?.type === 'select'
2366
- && /(reasoning|thought)/i.test(`${option.id} ${option.name || ''} ${option.category || ''}`);
2517
+ return option?.type === "select" && /(reasoning|thought)/i.test(`${option.id} ${option.name || ""} ${option.category || ""}`);
2367
2518
  });
2368
-
2369
2519
  let response;
2370
- const handled = new Set();
2371
- if (binding.provider === 'codex' && modelChange && reasoningChange) {
2520
+ const handled = /* @__PURE__ */ new Set();
2521
+ if (binding.provider === "codex" && modelChange && reasoningChange) {
2372
2522
  await this.applySessionConfigOption(binding, modelChange.configId, modelChange.value, { emit: false });
2373
2523
  await this.applySessionConfigOption(binding, reasoningChange.configId, reasoningChange.value, { emit: false });
2374
- const currentReasoning = binding.configOptions?.find(candidate => (
2375
- candidate.type === 'select'
2376
- && /(reasoning|thought)/i.test(`${candidate.id} ${candidate.name || ''} ${candidate.category || ''}`)
2377
- ));
2524
+ const currentReasoning = binding.configOptions?.find((candidate) => candidate.type === "select" && /(reasoning|thought)/i.test(`${candidate.id} ${candidate.name || ""} ${candidate.category || ""}`));
2378
2525
  await this.refreshCodexSessionModel(
2379
2526
  binding,
2380
- String(modelChange.value ?? ''),
2381
- String(currentReasoning?.currentValue || reasoningChange.value || '')
2527
+ String(modelChange.value ?? ""),
2528
+ String(currentReasoning?.currentValue || reasoningChange.value || "")
2382
2529
  );
2383
2530
  response = await this.applySessionConfigOption(binding, modelChange.configId, modelChange.value, { force: true });
2384
2531
  handled.add(modelChange);
@@ -2390,10 +2537,10 @@ class AcpRuntime extends EventEmitter {
2390
2537
  }
2391
2538
  return response;
2392
2539
  }
2393
-
2394
2540
  async enqueueSessionConfigMutation(binding, operation) {
2395
2541
  const previous = binding.configMutationTail || Promise.resolve();
2396
- const pending = previous.catch(() => {}).then(operation);
2542
+ const pending = previous.catch(() => {
2543
+ }).then(operation);
2397
2544
  binding.configMutationTail = pending;
2398
2545
  try {
2399
2546
  return await pending;
@@ -2401,41 +2548,37 @@ class AcpRuntime extends EventEmitter {
2401
2548
  if (binding.configMutationTail === pending) binding.configMutationTail = null;
2402
2549
  }
2403
2550
  }
2404
-
2405
2551
  async refreshCodexSessionModel(binding, model, effort) {
2406
2552
  this.requireOpenBinding(binding);
2407
2553
  await withTimeout(
2408
2554
  binding.connection.request(CODEX_SET_SESSION_MODEL_METHOD, {
2409
2555
  sessionId: binding.sessionId,
2410
- modelId: `${model}[${effort}]`,
2556
+ modelId: `${model}[${effort}]`
2411
2557
  }),
2412
2558
  this.requestTimeoutMs,
2413
- 'Codex ACP session/set_model capability refresh'
2559
+ "Codex ACP session/set_model capability refresh"
2414
2560
  );
2415
2561
  this.requireOpenBinding(binding);
2416
2562
  }
2417
-
2418
2563
  async applySessionConfigOption(binding, configId, value, options = {}) {
2419
2564
  this.requireOpenBinding(binding);
2420
- const normalizedConfigId = String(configId || '');
2421
- const currentOption = binding.configOptions?.find(candidate => candidate.id === normalizedConfigId);
2565
+ const normalizedConfigId = String(configId || "");
2566
+ const currentOption = binding.configOptions?.find((candidate) => candidate.id === normalizedConfigId);
2422
2567
  if (options.force !== true && currentOption?.currentValue === value) {
2423
2568
  if (options.emit !== false) this.emitSession(binding);
2424
2569
  return { sessionId: binding.sessionId, configOptions: binding.configOptions };
2425
2570
  }
2426
- const request = typeof value === 'boolean'
2427
- ? { sessionId: binding.sessionId, configId: normalizedConfigId, type: 'boolean', value }
2428
- : { sessionId: binding.sessionId, configId: normalizedConfigId, value: String(value ?? '') };
2571
+ const request = typeof value === "boolean" ? { sessionId: binding.sessionId, configId: normalizedConfigId, type: "boolean", value } : { sessionId: binding.sessionId, configId: normalizedConfigId, value: String(value ?? "") };
2429
2572
  let response;
2430
2573
  for (let attempt = 0; attempt < 2; attempt += 1) {
2431
2574
  response = await withTimeout(
2432
2575
  binding.connection.setSessionConfigOption(request),
2433
2576
  this.requestTimeoutMs,
2434
- 'ACP session/set_config_option'
2577
+ "ACP session/set_config_option"
2435
2578
  );
2436
2579
  this.requireOpenBinding(binding);
2437
2580
  binding.configOptions = response?.configOptions || binding.configOptions;
2438
- const confirmed = binding.configOptions?.find(candidate => candidate.id === normalizedConfigId);
2581
+ const confirmed = binding.configOptions?.find((candidate) => candidate.id === normalizedConfigId);
2439
2582
  if (confirmed?.currentValue === request.value) break;
2440
2583
  if (attempt === 1) {
2441
2584
  throw new Error(`ACP Agent did not confirm config option ${normalizedConfigId}`);
@@ -2446,18 +2589,16 @@ class AcpRuntime extends EventEmitter {
2446
2589
  if (options.emit !== false) this.emitSession(binding);
2447
2590
  return { sessionId: binding.sessionId, configOptions: binding.configOptions };
2448
2591
  }
2449
-
2450
2592
  getSession(agentId, options = {}) {
2451
2593
  const binding = this.requireBinding(agentId);
2452
2594
  const runtimeState = {
2453
2595
  state: binding.state,
2454
2596
  error: binding.error,
2455
- errorKind: binding.error ? acpErrorKind(binding.error) : '',
2597
+ errorKind: binding.error ? acpErrorKind(binding.error) : "",
2456
2598
  stopReason: binding.stopReason,
2457
2599
  supportsSteer: binding.supportsSteer === true,
2458
2600
  supportsFork: Boolean(
2459
- binding.initializeResponse?.agentCapabilities?.sessionCapabilities?.fork != null
2460
- && binding.initializeResponse?.agentCapabilities?.loadSession
2601
+ binding.initializeResponse?.agentCapabilities?.sessionCapabilities?.fork != null && binding.initializeResponse?.agentCapabilities?.loadSession
2461
2602
  ),
2462
2603
  protocolVersion: binding.initializeResponse?.protocolVersion || null,
2463
2604
  agentInfo: binding.initializeResponse?.agentInfo || null,
@@ -2465,152 +2606,139 @@ class AcpRuntime extends EventEmitter {
2465
2606
  authMethods: binding.initializeResponse?.authMethods || [],
2466
2607
  modes: binding.modes,
2467
2608
  configOptions: binding.configOptions,
2609
+ deferredConfigOptions: [...binding.deferredConfigChanges.values()],
2610
+ deferredModeId: binding.deferredModeId,
2468
2611
  pendingPermission: binding.pendingPermissions.values().next().value || null,
2469
2612
  pendingPermissions: [...binding.pendingPermissions.values()],
2470
2613
  pendingElicitation: binding.pendingElicitations.values().next().value || null,
2471
2614
  pendingElicitations: [...binding.pendingElicitations.values()],
2472
2615
  activeElicitations: [...binding.activeElicitations.values()],
2473
2616
  adapter: binding.launch,
2474
- authTerminal: binding.authTerminal
2475
- ? { ...binding.authTerminal, terminal: this.clientTerminals.display(binding.authTerminal.terminalId) }
2476
- : null,
2477
- updatedAt: binding.updatedAt,
2617
+ authTerminal: binding.authTerminal ? { ...binding.authTerminal, terminal: this.clientTerminals.display(binding.authTerminal.terminalId) } : null,
2618
+ updatedAt: binding.updatedAt
2478
2619
  };
2479
2620
  if (!binding.sessionState) {
2480
2621
  return {
2481
2622
  version: 1,
2482
- protocol: 'acp',
2623
+ protocol: "acp",
2483
2624
  provider: binding.provider,
2484
2625
  sessionId: binding.sessionId,
2485
2626
  cwd: binding.cwd,
2486
- title: '',
2487
- updatedAt: binding.updatedAt,
2627
+ title: "",
2488
2628
  truncated: false,
2489
2629
  entries: [],
2490
2630
  usage: null,
2491
2631
  availableCommands: [],
2492
- currentModeId: '',
2493
- configOptions: [],
2494
- ...runtimeState,
2632
+ currentModeId: "",
2633
+ ...runtimeState
2495
2634
  };
2496
2635
  }
2497
2636
  return binding.sessionState.snapshot(runtimeState, options);
2498
2637
  }
2499
-
2500
2638
  getTranscriptSession(agentId, options = {}) {
2501
2639
  const binding = this.requireBinding(agentId);
2502
- const slice = binding.sessionState
2503
- ? binding.sessionState.transcriptSlice(options)
2504
- : { entries: [], revision: 0, delta: false, hasMoreBefore: false };
2640
+ const slice = binding.sessionState ? binding.sessionState.transcriptSlice(options) : { entries: [], revision: 0, delta: false, hasMoreBefore: false };
2505
2641
  return {
2506
2642
  version: 2,
2507
- protocol: 'acp',
2643
+ protocol: "acp",
2508
2644
  provider: binding.provider,
2509
2645
  sessionId: binding.sessionId,
2510
2646
  cwd: binding.cwd,
2511
- title: binding.sessionState?.title || '',
2647
+ title: binding.sessionState?.title || "",
2512
2648
  updatedAt: binding.updatedAt,
2513
2649
  truncated: binding.sessionState?.truncated === true,
2514
2650
  state: binding.state,
2515
2651
  error: binding.error,
2516
- errorKind: binding.error ? acpErrorKind(binding.error) : '',
2652
+ errorKind: binding.error ? acpErrorKind(binding.error) : "",
2517
2653
  stopReason: binding.stopReason,
2518
- ...slice,
2654
+ plan: binding.sessionState?.plan == null ? null : JSON.parse(JSON.stringify(binding.sessionState.plan)),
2655
+ ...slice
2519
2656
  };
2520
2657
  }
2521
-
2522
2658
  getToolEntry(agentId, toolCallId) {
2523
2659
  const binding = this.requireBinding(agentId);
2524
- const entry = binding.sessionState?.toolEntries.get(String(toolCallId || ''));
2660
+ const entry = binding.sessionState?.toolEntries.get(String(toolCallId || ""));
2525
2661
  if (!entry || binding.sessionState.isInternalEntry(entry)) return null;
2526
2662
  const visible = JSON.parse(JSON.stringify(entry));
2527
- visible.content = (Array.isArray(visible.content) ? visible.content : []).map(block => {
2528
- if (block?.type !== 'terminal') return block;
2663
+ visible.content = (Array.isArray(visible.content) ? visible.content : []).map((block) => {
2664
+ if (block?.type !== "terminal") return block;
2529
2665
  const terminal = this.clientTerminals.display(block.terminalId);
2530
2666
  return terminal ? { ...block, terminal } : block;
2531
2667
  });
2532
2668
  return visible;
2533
2669
  }
2534
-
2535
2670
  getTranscriptEntry(agentId, entryId) {
2536
2671
  const binding = this.requireBinding(agentId);
2537
- const entries = (binding.sessionState?.entries || []).filter(candidate => (
2538
- String(candidate?.id || '') === String(entryId || '')
2539
- ));
2672
+ const entries = (binding.sessionState?.entries || []).filter((candidate) => String(candidate?.id || "") === String(entryId || ""));
2540
2673
  if (entries.length !== 1) return null;
2541
2674
  const [entry] = entries;
2542
2675
  if (!entry || binding.sessionState.isInternalEntry(entry)) return null;
2543
2676
  return entry;
2544
2677
  }
2545
-
2546
2678
  getPatchDecision(agentId, toolCallId, requestedPath) {
2547
2679
  const binding = this.requireBinding(agentId);
2548
- return binding.patchDecisions.get(`${String(toolCallId || '')}\n${String(requestedPath || '')}`) || '';
2680
+ return binding.patchDecisions.get(`${String(toolCallId || "")}
2681
+ ${String(requestedPath || "")}`) || "";
2549
2682
  }
2550
-
2551
2683
  async decidePatch(agentId, toolCallId, requestedPath, decision) {
2552
2684
  const binding = this.requireBinding(agentId);
2553
2685
  this.requireOpenBinding(binding);
2554
- if (
2555
- binding.sessionMutation
2556
- || binding.configMutationTail
2557
- || binding.activeTurn
2558
- || !['idle', 'error'].includes(binding.state)
2559
- ) {
2560
- throw new Error('Wait for the Agent to finish before deciding a patch');
2561
- }
2562
- const entry = binding.sessionState?.toolEntries.get(String(toolCallId || ''));
2563
- if (entry && binding.sessionState.isInternalEntry(entry)) throw new Error('ACP tool call not found');
2564
- if (!entry) throw new Error('ACP tool call not found');
2565
- const normalizedDecision = String(decision || '').trim().toLowerCase();
2566
- if (!['keep', 'revert'].includes(normalizedDecision)) throw new Error('ACP patch decision is invalid');
2567
- const key = `${String(toolCallId || '')}\n${String(requestedPath || '')}`;
2568
- const expectedAction = normalizedDecision === 'keep' ? 'kept' : 'reverted';
2686
+ if (binding.sessionMutation || binding.configMutationTail || binding.activeTurn || !["idle", "error"].includes(binding.state)) {
2687
+ throw new Error("Wait for the Agent to finish before deciding a patch");
2688
+ }
2689
+ const entry = binding.sessionState?.toolEntries.get(String(toolCallId || ""));
2690
+ if (entry && binding.sessionState.isInternalEntry(entry)) throw new Error("ACP tool call not found");
2691
+ if (!entry) throw new Error("ACP tool call not found");
2692
+ const normalizedDecision = String(decision || "").trim().toLowerCase();
2693
+ if (!["keep", "revert"].includes(normalizedDecision)) throw new Error("ACP patch decision is invalid");
2694
+ const key = `${String(toolCallId || "")}
2695
+ ${String(requestedPath || "")}`;
2696
+ const expectedAction = normalizedDecision === "keep" ? "kept" : "reverted";
2569
2697
  const existing = binding.patchDecisionInFlight.get(key);
2570
2698
  if (existing) {
2571
2699
  if (existing.decision !== normalizedDecision) {
2572
- throw new Error('ACP patch file already has a different decision in progress');
2700
+ throw new Error("ACP patch file already has a different decision in progress");
2573
2701
  }
2574
2702
  return existing.promise;
2575
2703
  }
2576
2704
  const committed = binding.patchDecisions.get(key);
2577
2705
  if (committed) {
2578
- if (committed !== expectedAction) throw new Error('ACP patch file already has a different decision');
2579
- const operation = (async () => {
2706
+ if (committed !== expectedAction) throw new Error("ACP patch file already has a different decision");
2707
+ const operation2 = (async () => {
2580
2708
  await this.writeCheckpoint(binding, { exact: true });
2581
2709
  return {
2582
2710
  action: committed,
2583
- path: String(requestedPath || ''),
2584
- toolCallId: String(toolCallId || ''),
2711
+ path: String(requestedPath || ""),
2712
+ toolCallId: String(toolCallId || "")
2585
2713
  };
2586
2714
  })();
2587
- const pending = { decision: normalizedDecision, promise: operation };
2588
- binding.patchDecisionInFlight.set(key, pending);
2715
+ const pending2 = { decision: normalizedDecision, promise: operation2 };
2716
+ binding.patchDecisionInFlight.set(key, pending2);
2589
2717
  try {
2590
- return await operation;
2718
+ return await operation2;
2591
2719
  } finally {
2592
- if (binding.patchDecisionInFlight.get(key) === pending) {
2720
+ if (binding.patchDecisionInFlight.get(key) === pending2) {
2593
2721
  binding.patchDecisionInFlight.delete(key);
2594
2722
  }
2595
2723
  }
2596
2724
  }
2597
2725
  const operation = (async () => {
2598
- let result = { action: 'kept', path: String(requestedPath || '') };
2599
- if (normalizedDecision === 'revert') {
2600
- result = await rejectPatch({ entry, root: binding.cwd, requestedPath });
2726
+ let result = { action: "kept", path: String(requestedPath || "") };
2727
+ if (normalizedDecision === "revert") {
2728
+ result = await (0, import_patch_decisions.rejectPatch)({ entry, root: binding.cwd, requestedPath });
2601
2729
  this.requireOpenBinding(binding);
2602
2730
  }
2603
2731
  binding.patchDecisions.set(key, result.action);
2604
- entry._meta = { ...(entry._meta || {}) };
2732
+ entry._meta = { ...entry._meta || {} };
2605
2733
  entry._meta.farming_patch_decisions = {
2606
- ...(entry._meta.farming_patch_decisions || {}),
2607
- [String(requestedPath || '')]: result.action,
2734
+ ...entry._meta.farming_patch_decisions || {},
2735
+ [String(requestedPath || "")]: result.action
2608
2736
  };
2609
2737
  binding.sessionState?.touchEntry(entry);
2610
- binding.updatedAt = new Date().toISOString();
2738
+ binding.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2611
2739
  await this.writeCheckpoint(binding, { exact: true });
2612
2740
  this.emitSession(binding);
2613
- return { ...result, toolCallId: String(toolCallId || '') };
2741
+ return { ...result, toolCallId: String(toolCallId || "") };
2614
2742
  })();
2615
2743
  const pending = { decision: normalizedDecision, promise: operation };
2616
2744
  binding.patchDecisionInFlight.set(key, pending);
@@ -2622,27 +2750,24 @@ class AcpRuntime extends EventEmitter {
2622
2750
  }
2623
2751
  }
2624
2752
  }
2625
-
2626
2753
  killTerminal(agentId, terminalId) {
2627
2754
  const binding = this.requireBinding(agentId);
2628
2755
  this.requireOpenBinding(binding);
2629
2756
  this.clientTerminals.kill(binding, {
2630
2757
  sessionId: binding.sessionId,
2631
- terminalId: String(terminalId || ''),
2758
+ terminalId: String(terminalId || "")
2632
2759
  });
2633
- return { killed: true, terminalId: String(terminalId || '') };
2760
+ return { killed: true, terminalId: String(terminalId || "") };
2634
2761
  }
2635
-
2636
2762
  inputTerminal(agentId, terminalId, input) {
2637
2763
  const binding = this.requireBinding(agentId);
2638
2764
  this.requireOpenBinding(binding);
2639
2765
  return this.clientTerminals.input(binding, {
2640
2766
  sessionId: binding.sessionId,
2641
2767
  terminalId,
2642
- input,
2768
+ input
2643
2769
  });
2644
2770
  }
2645
-
2646
2771
  resizeTerminal(agentId, terminalId, cols, rows) {
2647
2772
  const binding = this.requireBinding(agentId);
2648
2773
  this.requireOpenBinding(binding);
@@ -2650,136 +2775,112 @@ class AcpRuntime extends EventEmitter {
2650
2775
  sessionId: binding.sessionId,
2651
2776
  terminalId,
2652
2777
  cols,
2653
- rows,
2778
+ rows
2654
2779
  });
2655
2780
  }
2656
-
2657
2781
  getSubagentTranscriptSession(agentId, sessionId, options = {}) {
2658
2782
  const binding = this.requireBinding(agentId);
2659
- const id = String(sessionId || '');
2783
+ const id = String(sessionId || "");
2660
2784
  const state = binding.subagentStates.get(id);
2661
2785
  if (!state) return null;
2662
- const parentTool = binding.sessionState?.entries.find(entry => (
2663
- entry?.type === 'tool'
2664
- && String(entry?._meta?.subagent_session_info?.session_id || '') === id
2665
- ));
2666
- const status = String(parentTool?.status || '').toLowerCase();
2667
- const pendingPermission = [...binding.pendingPermissions.values()]
2668
- .some(request => String(request?.sessionId || '') === id);
2669
- const pendingElicitation = [...binding.pendingElicitations.values()]
2670
- .some(request => String(request?.sessionId || '') === id);
2786
+ const parentTool = binding.sessionState?.entries.find((entry) => entry?.type === "tool" && String(entry?._meta?.subagent_session_info?.session_id || "") === id);
2787
+ const status = String(parentTool?.status || "").toLowerCase();
2788
+ const pendingPermission = [...binding.pendingPermissions.values()].some((request) => String(request?.sessionId || "") === id);
2789
+ const pendingElicitation = [...binding.pendingElicitations.values()].some((request) => String(request?.sessionId || "") === id);
2671
2790
  const control = this.ensureSubagentControl(binding, id);
2672
- const active = ['pending', 'in_progress', 'in-progress', 'running'].includes(status);
2673
- const failed = ['failed', 'error'].includes(status);
2674
- const stateName = pendingPermission
2675
- ? 'waiting-for-permission'
2676
- : pendingElicitation
2677
- ? 'waiting-for-input'
2678
- : control.phase === 'cancelling'
2679
- ? 'interrupting'
2680
- : control.phase === 'error'
2681
- ? 'error'
2682
- : ['cancelled', 'completed'].includes(control.phase)
2683
- ? 'idle'
2684
- : active
2685
- ? 'working'
2686
- : failed
2687
- ? 'error'
2688
- : 'idle';
2689
- const controlFailed = control.phase === 'error';
2690
- const cancelled = control.phase === 'cancelled';
2791
+ const active = ["pending", "in_progress", "in-progress", "running"].includes(status);
2792
+ const failed = ["failed", "error"].includes(status);
2793
+ const stateName = pendingPermission ? "waiting-for-permission" : pendingElicitation ? "waiting-for-input" : control.phase === "cancelling" ? "interrupting" : control.phase === "error" ? "error" : ["cancelled", "completed"].includes(control.phase) ? "idle" : active ? "working" : failed ? "error" : "idle";
2794
+ const controlFailed = control.phase === "error";
2795
+ const cancelled = control.phase === "cancelled";
2691
2796
  return {
2692
2797
  version: 2,
2693
- protocol: 'acp',
2798
+ protocol: "acp",
2694
2799
  provider: binding.provider,
2695
2800
  sessionId: id,
2696
2801
  cwd: binding.cwd,
2697
- title: state.title || '',
2802
+ title: state.title || "",
2698
2803
  updatedAt: binding.updatedAt,
2699
2804
  truncated: state.truncated === true,
2700
2805
  state: stateName,
2701
- error: controlFailed ? control.error : failed ? String(parentTool?.title || 'Subagent failed') : '',
2702
- errorKind: controlFailed || failed ? 'agent' : '',
2703
- stopReason: controlFailed || failed ? 'error' : cancelled ? 'cancelled' : active ? '' : 'end_turn',
2704
- ...state.transcriptSlice(options),
2806
+ error: controlFailed ? control.error : failed ? String(parentTool?.title || "Subagent failed") : "",
2807
+ errorKind: controlFailed || failed ? "agent" : "",
2808
+ stopReason: controlFailed || failed ? "error" : cancelled ? "cancelled" : active ? "" : "end_turn",
2809
+ ...state.transcriptSlice(options)
2705
2810
  };
2706
2811
  }
2707
-
2708
2812
  hasBinding(agentId) {
2709
2813
  return this.bindings.has(agentId);
2710
2814
  }
2711
-
2712
2815
  requireBinding(agentId) {
2713
2816
  const binding = this.bindings.get(agentId);
2714
- if (!binding) throw new Error('ACP Agent is not registered');
2817
+ if (!binding) throw new Error("ACP Agent is not registered");
2715
2818
  return binding;
2716
2819
  }
2717
-
2718
2820
  emitRuntime(binding) {
2719
2821
  if (!this.isCurrentBinding(binding)) return false;
2720
- this.emit('agent-runtime', {
2822
+ this.emit("agent-runtime", {
2721
2823
  agentId: binding.agentId,
2722
2824
  provider: binding.provider,
2723
2825
  sessionId: binding.sessionId,
2724
2826
  state: binding.state,
2725
2827
  error: binding.error,
2726
- errorKind: binding.error ? acpErrorKind(binding.error) : '',
2828
+ errorKind: binding.error ? acpErrorKind(binding.error) : "",
2727
2829
  stopReason: binding.stopReason,
2728
2830
  supportsSteer: binding.supportsSteer === true,
2729
2831
  supportsFork: Boolean(
2730
- binding.initializeResponse?.agentCapabilities?.sessionCapabilities?.fork != null
2731
- && binding.initializeResponse?.agentCapabilities?.loadSession
2832
+ binding.initializeResponse?.agentCapabilities?.sessionCapabilities?.fork != null && binding.initializeResponse?.agentCapabilities?.loadSession
2732
2833
  ),
2733
2834
  pendingPermission: binding.pendingPermissions.values().next().value || null,
2734
2835
  pendingPermissions: [...binding.pendingPermissions.values()],
2735
2836
  pendingElicitation: binding.pendingElicitations.values().next().value || null,
2736
2837
  pendingElicitations: [...binding.pendingElicitations.values()],
2737
2838
  activeElicitations: [...binding.activeElicitations.values()],
2738
- updatedAt: binding.updatedAt,
2839
+ updatedAt: binding.updatedAt
2739
2840
  });
2740
2841
  return true;
2741
2842
  }
2742
-
2743
2843
  emitSession(binding) {
2744
2844
  if (!this.isCurrentBinding(binding)) return false;
2745
- this.emit('session', {
2845
+ this.emit("session", {
2746
2846
  agentId: binding.agentId,
2747
2847
  updatedAt: binding.updatedAt,
2748
2848
  revision: binding.sessionState?.revision || 0,
2849
+ title: binding.sessionState?.title || ""
2749
2850
  });
2750
2851
  return true;
2751
2852
  }
2752
-
2753
2853
  handleExit(binding, error) {
2754
2854
  if (!this.isCurrentBinding(binding) || binding.exited) return;
2755
2855
  binding.exited = true;
2756
2856
  const turn = binding.activeTurn;
2757
- const promptWasActive = Boolean(turn && turn.phase !== 'admitting');
2857
+ const promptWasActive = Boolean(turn && turn.phase !== "admitting");
2758
2858
  binding.activeTurn = null;
2759
2859
  if (error) {
2760
- binding.state = 'error';
2860
+ binding.state = "error";
2761
2861
  binding.error = acpErrorMessage(error);
2762
- binding.stopReason = 'error';
2763
- } else if (binding.state !== 'error') {
2764
- binding.state = 'stopped';
2765
- binding.stopReason = promptWasActive ? 'stopped' : binding.stopReason;
2862
+ binding.stopReason = "error";
2863
+ } else if (binding.state !== "error") {
2864
+ binding.state = "stopped";
2865
+ binding.stopReason = promptWasActive ? "stopped" : binding.stopReason;
2766
2866
  }
2767
2867
  if (promptWasActive && binding.sessionState) {
2768
2868
  if (error) binding.sessionState.recordError(binding.error, acpErrorKind(error));
2769
- binding.sessionState.completePrompt(binding.stopReason);
2869
+ binding.sessionState.completePrompt();
2770
2870
  }
2771
2871
  if (turn) {
2772
- turn.phase = 'completed';
2773
- turn.resolveCompletion({ status: 'connection-closed', error: error || null });
2872
+ turn.phase = "completed";
2873
+ turn.resolveCompletion?.({ status: "connection-closed", error: error || null });
2774
2874
  }
2775
2875
  for (const resolve of binding.permissionResolvers.values()) {
2776
- resolve({ outcome: { outcome: 'cancelled' } });
2876
+ resolve({ outcome: { outcome: "cancelled" } });
2777
2877
  }
2778
- for (const resolve of binding.elicitationResolvers.values()) resolve({ action: 'cancel' });
2878
+ for (const resolve of binding.elicitationResolvers.values()) resolve({ action: "cancel" });
2779
2879
  binding.permissionResolvers.clear();
2780
2880
  binding.pendingPermissions.clear();
2781
2881
  binding.elicitationResolvers.clear();
2782
2882
  binding.pendingElicitations.clear();
2883
+ binding.farmingBrowserApprovalScopes.clear();
2783
2884
  binding.activeElicitations.clear();
2784
2885
  binding.interactionOrigins.clear();
2785
2886
  binding.subagentStates.clear();
@@ -2788,7 +2889,6 @@ class AcpRuntime extends EventEmitter {
2788
2889
  if (promptWasActive) this.emitSession(binding);
2789
2890
  this.emitRuntime(binding);
2790
2891
  }
2791
-
2792
2892
  detachAgentBinding(binding, options = {}) {
2793
2893
  if (!binding || this.bindings.get(binding.agentId) !== binding) return false;
2794
2894
  if (binding.sessionState && !binding.activeTurn) this.scheduleCheckpoint(binding, { exact: true });
@@ -2797,15 +2897,16 @@ class AcpRuntime extends EventEmitter {
2797
2897
  const turn = binding.activeTurn;
2798
2898
  binding.activeTurn = null;
2799
2899
  if (turn) {
2800
- turn.phase = 'completed';
2801
- turn.resolveCompletion({ status: 'binding-detached' });
2900
+ turn.phase = "completed";
2901
+ turn.resolveCompletion?.({ status: "binding-detached" });
2802
2902
  }
2803
- for (const resolve of binding.permissionResolvers.values()) resolve({ outcome: { outcome: 'cancelled' } });
2804
- for (const resolve of binding.elicitationResolvers.values()) resolve({ action: 'cancel' });
2903
+ for (const resolve of binding.permissionResolvers.values()) resolve({ outcome: { outcome: "cancelled" } });
2904
+ for (const resolve of binding.elicitationResolvers.values()) resolve({ action: "cancel" });
2805
2905
  binding.permissionResolvers.clear();
2806
2906
  binding.pendingPermissions.clear();
2807
2907
  binding.elicitationResolvers.clear();
2808
2908
  binding.pendingElicitations.clear();
2909
+ binding.farmingBrowserApprovalScopes.clear();
2809
2910
  binding.activeElicitations.clear();
2810
2911
  binding.interactionOrigins.clear();
2811
2912
  binding.subagentStates.clear();
@@ -2814,25 +2915,21 @@ class AcpRuntime extends EventEmitter {
2814
2915
  try {
2815
2916
  binding.connection?.close();
2816
2917
  } catch {
2817
- // Process cleanup below remains authoritative if transport cleanup races.
2818
2918
  }
2819
2919
  if (binding.child?.stdin?.writable && !binding.child.stdin.destroyed) {
2820
2920
  try {
2821
2921
  binding.child.stdin.end();
2822
2922
  } catch {
2823
- // Process cleanup below remains authoritative if stdin already closed.
2824
2923
  }
2825
2924
  }
2826
2925
  return true;
2827
2926
  }
2828
-
2829
2927
  unregisterAgent(agentId, expectedBinding = null) {
2830
2928
  const binding = this.bindings.get(agentId);
2831
2929
  if (expectedBinding && binding !== expectedBinding) return;
2832
2930
  if (!binding || !this.detachAgentBinding(binding)) return;
2833
- signalProcessTree(binding, 'SIGTERM');
2931
+ signalProcessTree(binding, "SIGTERM");
2834
2932
  }
2835
-
2836
2933
  async unregisterAgentAndWait(agentId, expectedBinding = null) {
2837
2934
  const binding = this.bindings.get(agentId);
2838
2935
  if (expectedBinding && binding !== expectedBinding) return false;
@@ -2841,26 +2938,23 @@ class AcpRuntime extends EventEmitter {
2841
2938
  if (this.bindings.get(agentId) === binding) this.bindings.delete(agentId);
2842
2939
  return true;
2843
2940
  }
2844
-
2845
2941
  dispose() {
2846
2942
  if (this.disposed) return Promise.resolve();
2847
2943
  if (this.disposePromise) return this.disposePromise;
2848
-
2849
2944
  this.disposing = true;
2850
2945
  const disposePromise = this.performDispose();
2851
2946
  this.disposePromise = disposePromise;
2852
2947
  void disposePromise.finally(() => {
2853
2948
  if (this.disposePromise === disposePromise) this.disposePromise = null;
2854
2949
  if (!this.disposed) this.disposing = false;
2855
- }).catch(() => {});
2950
+ }).catch(() => {
2951
+ });
2856
2952
  return disposePromise;
2857
2953
  }
2858
-
2859
2954
  resumeAfterDisposeAbort() {
2860
2955
  this.disposed = false;
2861
2956
  this.disposing = false;
2862
2957
  }
2863
-
2864
2958
  async performDispose() {
2865
2959
  for (const binding of this.bindings.values()) {
2866
2960
  if (binding.sessionState && !binding.activeTurn) this.scheduleCheckpoint(binding, { exact: true });
@@ -2875,26 +2969,26 @@ class AcpRuntime extends EventEmitter {
2875
2969
  }
2876
2970
  }
2877
2971
  if (failures.length > 0) {
2878
- throw new AggregateError(failures, 'One or more ACP Agent process trees did not exit');
2972
+ throw new AggregateError(failures, "One or more ACP Agent process trees did not exit");
2879
2973
  }
2880
2974
  if (this.checkpointStore) await this.checkpointStore.dispose();
2881
2975
  this.disposed = true;
2882
2976
  }
2883
2977
  }
2884
-
2885
- module.exports = {
2886
- AcpRuntime,
2978
+ // Annotate the CommonJS export names for ESM import in node:
2979
+ 0 && (module.exports = {
2887
2980
  ADAPTER_VERSIONS,
2888
- acpSessionRequestOptions,
2981
+ AcpRuntime,
2982
+ CODEX_STEER_METHOD,
2889
2983
  acpErrorKind,
2984
+ acpSessionRequestOptions,
2890
2985
  autoPermissionResponse,
2891
2986
  codexAcpEnvironment,
2987
+ deleteProviderSessionIdentity,
2892
2988
  describeAcpProcessGroup,
2989
+ isCodexSteerUnavailableError,
2893
2990
  promptContentForCapabilities,
2894
2991
  resolveAcpLaunch,
2895
2992
  stopPersistedAcpProcessGroup,
2896
- supportsCodexSteer,
2897
- isCodexSteerUnavailableError,
2898
- CODEX_STEER_METHOD,
2899
- deleteProviderSessionIdentity,
2900
- };
2993
+ supportsCodexSteer
2994
+ });