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