zidane 9.1.1 → 9.1.4

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 (279) hide show
  1. package/dist/{acp-Di9WvMDF.js → acp-Cl4gCZN6.js} +7 -7
  2. package/dist/{acp-Di9WvMDF.js.map → acp-Cl4gCZN6.js.map} +1 -1
  3. package/dist/acp-cli.js +5 -5
  4. package/dist/acp.d.ts +2 -2
  5. package/dist/acp.js +1 -1
  6. package/dist/{agent-DJhpTS-B.js → agent-Dh_XZ7fj.js} +74 -19
  7. package/dist/agent-Dh_XZ7fj.js.map +1 -0
  8. package/dist/agent.d.ts +1 -1
  9. package/dist/agent.js +1 -1
  10. package/dist/{auth-store-port-DFgf22oo.js → auth-store-port-DBl2JUC6.js} +2 -2
  11. package/dist/{auth-store-port-DFgf22oo.js.map → auth-store-port-DBl2JUC6.js.map} +1 -1
  12. package/dist/{auto-update-restart-BFB7Ek87.js → auto-update-restart-CF_kjcJd.js} +277 -41
  13. package/dist/auto-update-restart-CF_kjcJd.js.map +1 -0
  14. package/dist/{browser-BcoCCB_n.js → browser-BkdeKnxO.js} +56 -2
  15. package/dist/browser-BkdeKnxO.js.map +1 -0
  16. package/dist/{browser-entry-ypi8CyE-.d.ts → browser-entry-BCwruqNa.d.ts} +10 -10
  17. package/dist/{browser-entry-ypi8CyE-.d.ts.map → browser-entry-BCwruqNa.d.ts.map} +1 -1
  18. package/dist/channels.d.ts +5 -5
  19. package/dist/chat/browser.d.ts +4 -4
  20. package/dist/chat/browser.js +6 -6
  21. package/dist/chat/pure.d.ts +5 -5
  22. package/dist/chat/pure.js +8 -8
  23. package/dist/chat.d.ts +5 -5
  24. package/dist/chat.js +55 -55
  25. package/dist/chat.js.map +1 -1
  26. package/dist/{cli-shared-CabruH8Z.js → cli-shared-DIV9c5Nr.js} +4 -4
  27. package/dist/{cli-shared-CabruH8Z.js.map → cli-shared-DIV9c5Nr.js.map} +1 -1
  28. package/dist/cli-style-DBEm6CyT.js +105 -0
  29. package/dist/cli-style-DBEm6CyT.js.map +1 -0
  30. package/dist/{client-core-CIixwznM.d.ts → client-core-C_4m_oL6.d.ts} +4 -4
  31. package/dist/{client-core-CIixwznM.d.ts.map → client-core-C_4m_oL6.d.ts.map} +1 -1
  32. package/dist/{client-CCaIXWue.d.ts → client-ygTASGis.d.ts} +2 -2
  33. package/dist/{client-CCaIXWue.d.ts.map → client-ygTASGis.d.ts.map} +1 -1
  34. package/dist/codemode-worker.js +8 -5
  35. package/dist/codemode-worker.js.map +1 -1
  36. package/dist/codemode.d.ts +16 -0
  37. package/dist/codemode.d.ts.map +1 -1
  38. package/dist/codemode.js +2 -2
  39. package/dist/{connection-loop-QmWL-fJf.d.ts → connection-loop-D_pRONCr.d.ts} +4 -4
  40. package/dist/{connection-loop-QmWL-fJf.d.ts.map → connection-loop-D_pRONCr.d.ts.map} +1 -1
  41. package/dist/contexts/daytona.d.ts +3 -3
  42. package/dist/contexts/docker.d.ts +1 -1
  43. package/dist/contexts/e2b.d.ts +2 -2
  44. package/dist/contexts/sandbox.d.ts +1 -1
  45. package/dist/{contexts-C72b0mMa.js → contexts-DLZTSRHU.js} +17 -106
  46. package/dist/contexts-DLZTSRHU.js.map +1 -0
  47. package/dist/contexts.d.ts +4 -4
  48. package/dist/contexts.js +2 -2
  49. package/dist/{credentials-wwETW8rI.js → credentials-D71duF64.js} +2 -2
  50. package/dist/{credentials-wwETW8rI.js.map → credentials-D71duF64.js.map} +1 -1
  51. package/dist/{cwd-picker-CcekODCt.js → cwd-picker-BsHA6HKv.js} +4 -4
  52. package/dist/{cwd-picker-CcekODCt.js.map → cwd-picker-BsHA6HKv.js.map} +1 -1
  53. package/dist/daemon-cli.js +4 -3
  54. package/dist/daemon-cli.js.map +1 -1
  55. package/dist/{decisions-CXmK0nz9.js → decisions-hsw5XS2g.js} +3 -1
  56. package/dist/decisions-hsw5XS2g.js.map +1 -0
  57. package/dist/{discovery-DycXFxdA.js → discovery-DD4wPWKS.js} +4 -4
  58. package/dist/{discovery-DycXFxdA.js.map → discovery-DD4wPWKS.js.map} +1 -1
  59. package/dist/durable/sqlite.d.ts +2 -2
  60. package/dist/durable.d.ts +1 -1
  61. package/dist/{engine-VQ86XGdG.js → engine-BDmtgr2O.js} +6 -6
  62. package/dist/{engine-VQ86XGdG.js.map → engine-BDmtgr2O.js.map} +1 -1
  63. package/dist/{eval-Bod0I1W_.js → eval-CfGUDAkN.js} +3 -3
  64. package/dist/{eval-Bod0I1W_.js.map → eval-CfGUDAkN.js.map} +1 -1
  65. package/dist/eval.d.ts +1 -1
  66. package/dist/eval.js +1 -1
  67. package/dist/{executor-C7RQrkEq.js → executor-EWOhLyd9.js} +4 -4
  68. package/dist/{executor-C7RQrkEq.js.map → executor-EWOhLyd9.js.map} +1 -1
  69. package/dist/{extension-mark-BqKdEZwF.js → extension-mark-_rhkDWL5.js} +9 -6
  70. package/dist/extension-mark-_rhkDWL5.js.map +1 -0
  71. package/dist/extensions/testing.d.ts +1 -1
  72. package/dist/extensions/testing.js +2 -2
  73. package/dist/{extensions-BCx4QuGB.js → extensions-DklXPjiq.js} +8 -8
  74. package/dist/{extensions-BCx4QuGB.js.map → extensions-DklXPjiq.js.map} +1 -1
  75. package/dist/{extensions-client-D8tEAcMw.d.ts → extensions-client-D4Q2XRKV.d.ts} +31 -5
  76. package/dist/extensions-client-D4Q2XRKV.d.ts.map +1 -0
  77. package/dist/extensions.d.ts +1 -1
  78. package/dist/extensions.js +6 -6
  79. package/dist/{fold-rules-DvLK8pbf.d.ts → fold-rules-1DpDwG9h.d.ts} +2 -2
  80. package/dist/{fold-rules-DvLK8pbf.d.ts.map → fold-rules-1DpDwG9h.d.ts.map} +1 -1
  81. package/dist/{google-Crva32sk.js → google-BtMW9KzL.js} +2 -2
  82. package/dist/{google-Crva32sk.js.map → google-BtMW9KzL.js.map} +1 -1
  83. package/dist/{headless-CCm-jLLT.js → headless-CQm19BL0.js} +4 -4
  84. package/dist/{headless-CCm-jLLT.js.map → headless-CQm19BL0.js.map} +1 -1
  85. package/dist/headless.d.ts +1 -1
  86. package/dist/headless.js +1 -1
  87. package/dist/history-worker.js +1 -1
  88. package/dist/{host-BHMs9jsN.js → host-DEoEzQal.js} +13 -4
  89. package/dist/host-DEoEzQal.js.map +1 -0
  90. package/dist/{host-scoped-settings-CrbcqOkP.js → host-scoped-settings-WBYaCork.js} +2 -2
  91. package/dist/{host-scoped-settings-CrbcqOkP.js.map → host-scoped-settings-WBYaCork.js.map} +1 -1
  92. package/dist/{host-signals-Jsjd_-4g.js → host-signals-91zyko_i.js} +5 -5
  93. package/dist/{host-signals-Jsjd_-4g.js.map → host-signals-91zyko_i.js.map} +1 -1
  94. package/dist/{host-wO_6GW0y.js → host-uP3t08w8.js} +276 -103
  95. package/dist/host-uP3t08w8.js.map +1 -0
  96. package/dist/{host-version-CNAr9pov.js → host-version-_RHlAB29.js} +2 -2
  97. package/dist/{host-version-CNAr9pov.js.map → host-version-_RHlAB29.js.map} +1 -1
  98. package/dist/{index-C6nnKu32.d.ts → index-B0PLo9jn.d.ts} +4 -4
  99. package/dist/{index-C6nnKu32.d.ts.map → index-B0PLo9jn.d.ts.map} +1 -1
  100. package/dist/{index-Djnc8Peh.d.ts → index-De4x-s76.d.ts} +14 -14
  101. package/dist/{index-Djnc8Peh.d.ts.map → index-De4x-s76.d.ts.map} +1 -1
  102. package/dist/{index-CGbOWa7y.d.ts → index-WlE93Q6d.d.ts} +411 -3
  103. package/dist/index-WlE93Q6d.d.ts.map +1 -0
  104. package/dist/{index-CCf_WeTQ.d.ts → index-f-XWIoYo.d.ts} +2 -2
  105. package/dist/{index-CCf_WeTQ.d.ts.map → index-f-XWIoYo.d.ts.map} +1 -1
  106. package/dist/index.d.ts +5 -5
  107. package/dist/index.js +17 -17
  108. package/dist/ipc/browser-types.d.ts +304 -7
  109. package/dist/ipc/browser-types.d.ts.map +1 -1
  110. package/dist/ipc/browser.d.ts +4 -4
  111. package/dist/ipc/browser.js +2 -2
  112. package/dist/ipc/remote.d.ts +6 -6
  113. package/dist/ipc/remote.js +3 -3
  114. package/dist/{ipc-BzWhIybr.js → ipc-CatnsVEd.js} +4 -4
  115. package/dist/{ipc-BzWhIybr.js.map → ipc-CatnsVEd.js.map} +1 -1
  116. package/dist/ipc.d.ts +10 -10
  117. package/dist/ipc.js +8 -8
  118. package/dist/{json-Dj-YATkZ.js → json-BjClr43H.js} +2 -20
  119. package/dist/json-BjClr43H.js.map +1 -0
  120. package/dist/{links-CJG_rFvf.js → links-a8C9eby4.js} +9 -9
  121. package/dist/{links-CJG_rFvf.js.map → links-a8C9eby4.js.map} +1 -1
  122. package/dist/{loaded-entry-DTURJo_R.js → loaded-entry-D6jzt5HQ.js} +2 -2
  123. package/dist/{loaded-entry-DTURJo_R.js.map → loaded-entry-D6jzt5HQ.js.map} +1 -1
  124. package/dist/mcp.d.ts +1 -1
  125. package/dist/{media-type-BtA0cbfI.d.ts → media-type-ZSmAGHvg.d.ts} +188 -7
  126. package/dist/media-type-ZSmAGHvg.d.ts.map +1 -0
  127. package/dist/{memory-DuVGrzbl.js → memory-CJy52DNi.js} +132 -31
  128. package/dist/memory-CJy52DNi.js.map +1 -0
  129. package/dist/model-test-CAtJ76kM.js.map +1 -1
  130. package/dist/{move-session-kylExJ5H.js → move-session-D7ILECs-.js} +4 -4
  131. package/dist/{move-session-kylExJ5H.js.map → move-session-D7ILECs-.js.map} +1 -1
  132. package/dist/{nested-call-record-DlzPeTB7.js → nested-call-record-OayszZBQ.js} +4 -3
  133. package/dist/nested-call-record-OayszZBQ.js.map +1 -0
  134. package/dist/output/stream-json.d.ts +1 -1
  135. package/dist/output/terminal.d.ts +1 -1
  136. package/dist/{path-display-COVV71Yu.js → path-display-CAWz-sMq.js} +3 -3
  137. package/dist/{path-display-COVV71Yu.js.map → path-display-CAWz-sMq.js.map} +1 -1
  138. package/dist/plugins.d.ts +1 -1
  139. package/dist/{prelude-CVKoUzV8.js → prelude-BwiSR1uA.js} +16 -5
  140. package/dist/prelude-BwiSR1uA.js.map +1 -0
  141. package/dist/{presets-CBt6rFfS.js → presets-CMY43nUP.js} +3 -3
  142. package/dist/{presets-CBt6rFfS.js.map → presets-CMY43nUP.js.map} +1 -1
  143. package/dist/presets.d.ts +1 -1
  144. package/dist/presets.js +1 -1
  145. package/dist/{protocol-CEVqBO-q.d.ts → protocol-C2lqKuMd.d.ts} +50 -7
  146. package/dist/protocol-C2lqKuMd.d.ts.map +1 -0
  147. package/dist/protocol-DOGyHgLQ.js.map +1 -1
  148. package/dist/protocol-NSllElLw.js.map +1 -1
  149. package/dist/providers/anthropic.d.ts +1 -1
  150. package/dist/providers/arcee.d.ts +1 -1
  151. package/dist/providers/baseten.d.ts +1 -1
  152. package/dist/providers/cerebras.d.ts +1 -1
  153. package/dist/providers/google.d.ts +1 -1
  154. package/dist/providers/google.js +1 -1
  155. package/dist/providers/local.d.ts +1 -1
  156. package/dist/providers/neuralwatt.d.ts +1 -1
  157. package/dist/providers/openai-compat.d.ts +1 -1
  158. package/dist/providers/openai.d.ts +1 -1
  159. package/dist/providers/openrouter.d.ts +1 -1
  160. package/dist/providers/xai.d.ts +1 -1
  161. package/dist/{providers-Z0TaBp1O.js → providers-zVRxiJDv.js} +5 -5
  162. package/dist/providers-zVRxiJDv.js.map +1 -0
  163. package/dist/providers.d.ts +1 -1
  164. package/dist/providers.js +1 -1
  165. package/dist/{readonly-db-D7Z-k0pQ.js → readonly-db-DrbT8tX6.js} +2 -2
  166. package/dist/{readonly-db-D7Z-k0pQ.js.map → readonly-db-DrbT8tX6.js.map} +1 -1
  167. package/dist/{registry-BKjeBnoy.js → registry-CBoYDIND.js} +2 -2
  168. package/dist/{registry-BKjeBnoy.js.map → registry-CBoYDIND.js.map} +1 -1
  169. package/dist/{registry-B6Ww76iW.js → registry-CQOU5jvF.js} +2 -2
  170. package/dist/{registry-B6Ww76iW.js.map → registry-CQOU5jvF.js.map} +1 -1
  171. package/dist/{registry-B9INJwJR.js → registry-YUUqbYGr.js} +324 -39
  172. package/dist/registry-YUUqbYGr.js.map +1 -0
  173. package/dist/{remote-hosts-BMWoHCWO.js → remote-hosts-CT8Q95dR.js} +4 -4
  174. package/dist/{remote-hosts-BMWoHCWO.js.map → remote-hosts-CT8Q95dR.js.map} +1 -1
  175. package/dist/{repo-url-D4Dr8NfZ.js → repo-url-DLjjuVk_.js} +169 -2
  176. package/dist/repo-url-DLjjuVk_.js.map +1 -0
  177. package/dist/restate.d.ts +2 -2
  178. package/dist/{sandbox-BwiPGKF7.d.ts → sandbox-B4OW6oNx.d.ts} +2 -2
  179. package/dist/{sandbox-BwiPGKF7.d.ts.map → sandbox-B4OW6oNx.d.ts.map} +1 -1
  180. package/dist/script-progress-CrZ507Qq.js +900 -0
  181. package/dist/script-progress-CrZ507Qq.js.map +1 -0
  182. package/dist/session/sqlite.d.ts +1 -1
  183. package/dist/session.d.ts +1 -1
  184. package/dist/{setting-BQBSyUq0.js → setting-_jh2OtiL.js} +6 -6
  185. package/dist/{setting-BQBSyUq0.js.map → setting-_jh2OtiL.js.map} +1 -1
  186. package/dist/{settings-catalog-4IU2i_jG.js → settings-catalog-DEZlXP51.js} +14 -2
  187. package/dist/settings-catalog-DEZlXP51.js.map +1 -0
  188. package/dist/{settings-keys-iI_Y-7MC.js → settings-keys-BT0_oKjO.js} +3 -3
  189. package/dist/{settings-keys-iI_Y-7MC.js.map → settings-keys-BT0_oKjO.js.map} +1 -1
  190. package/dist/{skills-CFXRItJ6.js → skills-CEbosUlM.js} +2 -2
  191. package/dist/{skills-CFXRItJ6.js.map → skills-CEbosUlM.js.map} +1 -1
  192. package/dist/skills.d.ts +1 -1
  193. package/dist/skills.js +1 -1
  194. package/dist/{source-Bl1Z501r.js → source-3ZnEPOSa.js} +3 -2
  195. package/dist/source-3ZnEPOSa.js.map +1 -0
  196. package/dist/{sqlite-runtime-BZ2L4RaG.d.ts → sqlite-runtime-CS_LBaAN.d.ts} +2 -2
  197. package/dist/sqlite-runtime-CS_LBaAN.d.ts.map +1 -0
  198. package/dist/{src-BY_ND2xn.js → src-BmTXDta8.js} +2 -2
  199. package/dist/{src-BY_ND2xn.js.map → src-BmTXDta8.js.map} +1 -1
  200. package/dist/{store-C6gI7FfZ.js → store-ByCDaKgJ.js} +14 -3
  201. package/dist/store-ByCDaKgJ.js.map +1 -0
  202. package/dist/{system-freeze-m5o1sGIM.js → system-freeze-DxJ-lRhu.js} +3 -3
  203. package/dist/{system-freeze-m5o1sGIM.js.map → system-freeze-DxJ-lRhu.js.map} +1 -1
  204. package/dist/{todo-edits-CbukbjyV.js → todo-edits-Dyj32ds6.js} +4 -3
  205. package/dist/todo-edits-Dyj32ds6.js.map +1 -0
  206. package/dist/tools/fetch-url.d.ts +1 -1
  207. package/dist/tools/web-search.d.ts +1 -1
  208. package/dist/{tools-CVTGhggj.js → tools-BsrGQ8K4.js} +2 -2
  209. package/dist/{tools-CVTGhggj.js.map → tools-BsrGQ8K4.js.map} +1 -1
  210. package/dist/tools.d.ts +1 -1
  211. package/dist/tools.js +3 -3
  212. package/dist/{transcript-anchors-CiSi_UBn.js → transcript-anchors-DMjvyUjk.js} +3 -3
  213. package/dist/{transcript-anchors-CiSi_UBn.js.map → transcript-anchors-DMjvyUjk.js.map} +1 -1
  214. package/dist/{transcript-reconcile-jbSBjLq2.js → transcript-reconcile-DpQO85wl.js} +3 -3
  215. package/dist/{transcript-reconcile-jbSBjLq2.js.map → transcript-reconcile-DpQO85wl.js.map} +1 -1
  216. package/dist/tui.d.ts +9 -9
  217. package/dist/tui.d.ts.map +1 -1
  218. package/dist/tui.js +289 -38
  219. package/dist/tui.js.map +1 -1
  220. package/dist/{types-bDQagoiL.d.ts → types-2HrgolQz.d.ts} +20 -8
  221. package/dist/types-2HrgolQz.d.ts.map +1 -0
  222. package/dist/types-4q1bFG53.js +122 -0
  223. package/dist/types-4q1bFG53.js.map +1 -0
  224. package/dist/{types-DnRd9_cA.d.ts → types-SXqk6hLD.d.ts} +3 -3
  225. package/dist/{types-DnRd9_cA.d.ts.map → types-SXqk6hLD.d.ts.map} +1 -1
  226. package/dist/types-myxheQkw.js.map +1 -1
  227. package/dist/types.d.ts +3 -3
  228. package/dist/{usage-summary-BfcXjiSM.js → usage-summary-BM7B3JdI.js} +2 -2
  229. package/dist/{usage-summary-BfcXjiSM.js.map → usage-summary-BM7B3JdI.js.map} +1 -1
  230. package/dist/{version-DqqqvHDP.js → version-DwQI12WA.js} +2 -2
  231. package/dist/{version-DqqqvHDP.js.map → version-DwQI12WA.js.map} +1 -1
  232. package/dist/{wait-task-BX4NcOOm.js → wait-task-BiI5UaZQ.js} +13 -3
  233. package/dist/wait-task-BiI5UaZQ.js.map +1 -0
  234. package/dist/{wire-CLm2rMK0.js → wire-Dxwxb7QQ.js} +2 -2
  235. package/dist/{wire-CLm2rMK0.js.map → wire-Dxwxb7QQ.js.map} +1 -1
  236. package/dist/{write-file-0E6TUJ9A.js → write-file-Dquu7MzB.js} +5 -3
  237. package/dist/write-file-Dquu7MzB.js.map +1 -0
  238. package/dist/{ws-DfGGYQ4W.js → ws-CA3o2nie.js} +4 -4
  239. package/dist/{ws-DfGGYQ4W.js.map → ws-CA3o2nie.js.map} +1 -1
  240. package/dist/{ws-client-CFMbhsNq.js → ws-client-C0iPAAzc.js} +2 -2
  241. package/dist/{ws-client-CFMbhsNq.js.map → ws-client-C0iPAAzc.js.map} +1 -1
  242. package/docs/CHAT.md +55 -0
  243. package/docs/CODEMODE.md +37 -0
  244. package/docs/EXTENSIONS.md +8 -6
  245. package/docs/RELEASE-NOTES-NEXT.md +48 -1
  246. package/docs/RELEASE.md +9 -1
  247. package/package.json +2 -3
  248. package/dist/agent-DJhpTS-B.js.map +0 -1
  249. package/dist/auto-update-restart-BFB7Ek87.js.map +0 -1
  250. package/dist/browser-BcoCCB_n.js.map +0 -1
  251. package/dist/contexts-C72b0mMa.js.map +0 -1
  252. package/dist/decisions-CXmK0nz9.js.map +0 -1
  253. package/dist/extension-mark-BqKdEZwF.js.map +0 -1
  254. package/dist/extensions-client-D8tEAcMw.d.ts.map +0 -1
  255. package/dist/host-BHMs9jsN.js.map +0 -1
  256. package/dist/host-wO_6GW0y.js.map +0 -1
  257. package/dist/index-CGbOWa7y.d.ts.map +0 -1
  258. package/dist/json-Dj-YATkZ.js.map +0 -1
  259. package/dist/media-type-BtA0cbfI.d.ts.map +0 -1
  260. package/dist/memory-DuVGrzbl.js.map +0 -1
  261. package/dist/nested-call-events-BYk8XvGX.js +0 -182
  262. package/dist/nested-call-events-BYk8XvGX.js.map +0 -1
  263. package/dist/nested-call-record-DlzPeTB7.js.map +0 -1
  264. package/dist/prelude-CVKoUzV8.js.map +0 -1
  265. package/dist/protocol-CEVqBO-q.d.ts.map +0 -1
  266. package/dist/providers-Z0TaBp1O.js.map +0 -1
  267. package/dist/registry-B9INJwJR.js.map +0 -1
  268. package/dist/repo-url-D4Dr8NfZ.js.map +0 -1
  269. package/dist/settings-catalog-4IU2i_jG.js.map +0 -1
  270. package/dist/source-Bl1Z501r.js.map +0 -1
  271. package/dist/sqlite-runtime-BZ2L4RaG.d.ts.map +0 -1
  272. package/dist/store-C6gI7FfZ.js.map +0 -1
  273. package/dist/todo-edits-CbukbjyV.js.map +0 -1
  274. package/dist/types-DTMEhKJO.js +0 -14
  275. package/dist/types-DTMEhKJO.js.map +0 -1
  276. package/dist/types-bDQagoiL.d.ts.map +0 -1
  277. package/dist/wait-task-BX4NcOOm.js.map +0 -1
  278. package/dist/write-file-0E6TUJ9A.js.map +0 -1
  279. package/scripts/eval.ts +0 -179
@@ -11,7 +11,7 @@
11
11
  * retires it, so an upgrade can never leave windows silently executing on a
12
12
  * process started from the previous release.
13
13
  */
14
- const ZIDANE_VERSION = "9.1.1";
14
+ const ZIDANE_VERSION = "9.1.4";
15
15
  /**
16
16
  * Compare two dotted versions (`7.0.19`, `7.1.0-beta.1`): negative when `a`
17
17
  * is older, positive when newer, 0 when equal. Pre-release tags are ignored
@@ -39,4 +39,4 @@ function parse(v) {
39
39
  //#endregion
40
40
  export { compareVersions as n, ZIDANE_VERSION as t };
41
41
 
42
- //# sourceMappingURL=version-DqqqvHDP.js.map
42
+ //# sourceMappingURL=version-DwQI12WA.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version-DqqqvHDP.js","names":["(pkg as { version?: string }).version"],"sources":["../package.json","../src/version.ts"],"sourcesContent":["","/**\n * The version of the zidane code this process is running — `package.json`\n * inlined at build time (Bun `--compile`, tsdown for `dist/`, and Vite for\n * the GUI main all fold JSON imports into the bundle, so this never reads\n * the filesystem at runtime and cannot report a NEIGHBOUR package's version\n * the way a `require('../package.json')` from a bundled chunk can).\n *\n * Used by the daemon handshake: a client running newer code than the daemon\n * retires it, so an upgrade can never leave windows silently executing on a\n * process started from the previous release.\n */\nimport pkg from '../package.json' with { type: 'json' }\n\nexport const ZIDANE_VERSION: string = (pkg as { version?: string }).version ?? '0.0.0'\n\n/**\n * Compare two dotted versions (`7.0.19`, `7.1.0-beta.1`): negative when `a`\n * is older, positive when newer, 0 when equal. Pre-release tags are ignored\n * — same release train, same code as far as the daemon fence is concerned.\n * Unparseable input compares equal (never fences on garbage).\n */\nexport function compareVersions(a: string, b: string): number {\n const pa = parse(a)\n const pb = parse(b)\n if (!pa || !pb)\n return 0\n for (let i = 0; i < 3; i++) {\n const d = (pa[i] ?? 0) - (pb[i] ?? 0)\n if (d !== 0)\n return d\n }\n return 0\n}\n\nfunction parse(v: string): number[] | null {\n const m = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(v.trim())\n return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null\n}\n"],"mappings":";;;;;;;;;;;;;ACaA,MAAa,iBAAyBA;;;;;;;AAQtC,SAAgB,gBAAgB,GAAW,GAAmB;CAC5D,MAAM,KAAK,MAAM,CAAC;CAClB,MAAM,KAAK,MAAM,CAAC;CAClB,IAAI,CAAC,MAAM,CAAC,IACV,OAAO;CACT,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;EAC1B,MAAM,KAAK,GAAG,MAAM,MAAM,GAAG,MAAM;EACnC,IAAI,MAAM,GACR,OAAO;CACX;CACA,OAAO;AACT;AAEA,SAAS,MAAM,GAA4B;CACzC,MAAM,IAAI,yBAAyB,KAAK,EAAE,KAAK,CAAC;CAChD,OAAO,IAAI;EAAC,OAAO,EAAE,EAAE;EAAG,OAAO,EAAE,EAAE;EAAG,OAAO,EAAE,EAAE;CAAC,IAAI;AAC1D"}
1
+ {"version":3,"file":"version-DwQI12WA.js","names":["(pkg as { version?: string }).version"],"sources":["../package.json","../src/version.ts"],"sourcesContent":["","/**\n * The version of the zidane code this process is running — `package.json`\n * inlined at build time (Bun `--compile`, tsdown for `dist/`, and Vite for\n * the GUI main all fold JSON imports into the bundle, so this never reads\n * the filesystem at runtime and cannot report a NEIGHBOUR package's version\n * the way a `require('../package.json')` from a bundled chunk can).\n *\n * Used by the daemon handshake: a client running newer code than the daemon\n * retires it, so an upgrade can never leave windows silently executing on a\n * process started from the previous release.\n */\nimport pkg from '../package.json' with { type: 'json' }\n\nexport const ZIDANE_VERSION: string = (pkg as { version?: string }).version ?? '0.0.0'\n\n/**\n * Compare two dotted versions (`7.0.19`, `7.1.0-beta.1`): negative when `a`\n * is older, positive when newer, 0 when equal. Pre-release tags are ignored\n * — same release train, same code as far as the daemon fence is concerned.\n * Unparseable input compares equal (never fences on garbage).\n */\nexport function compareVersions(a: string, b: string): number {\n const pa = parse(a)\n const pb = parse(b)\n if (!pa || !pb)\n return 0\n for (let i = 0; i < 3; i++) {\n const d = (pa[i] ?? 0) - (pb[i] ?? 0)\n if (d !== 0)\n return d\n }\n return 0\n}\n\nfunction parse(v: string): number[] | null {\n const m = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(v.trim())\n return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null\n}\n"],"mappings":";;;;;;;;;;;;;ACaA,MAAa,iBAAyBA;;;;;;;AAQtC,SAAgB,gBAAgB,GAAW,GAAmB;CAC5D,MAAM,KAAK,MAAM,CAAC;CAClB,MAAM,KAAK,MAAM,CAAC;CAClB,IAAI,CAAC,MAAM,CAAC,IACV,OAAO;CACT,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;EAC1B,MAAM,KAAK,GAAG,MAAM,MAAM,GAAG,MAAM;EACnC,IAAI,MAAM,GACR,OAAO;CACX;CACA,OAAO;AACT;AAEA,SAAS,MAAM,GAA4B;CACzC,MAAM,IAAI,yBAAyB,KAAK,EAAE,KAAK,CAAC;CAChD,OAAO,IAAI;EAAC,OAAO,EAAE,EAAE;EAAG,OAAO,EAAE,EAAE;EAAG,OAAO,EAAE,EAAE;CAAC,IAAI;AAC1D"}
@@ -2,7 +2,7 @@ import { p as errorMessage } from "./errors-C3z7pmOx.js";
2
2
  import { r as utf8ByteLength } from "./utils-CCliK45X.js";
3
3
  import { n as humanBytes } from "./format-bytes-LHrZVMIt.js";
4
4
  import { c as readStateKey, l as resolveReadStateMap, r as hashContent } from "./read-state-kgOvuIcp.js";
5
- import { t as resolveDetachedTasksCapability } from "./types-DTMEhKJO.js";
5
+ import { r as stripAnsi, t as resolveDetachedTasksCapability } from "./types-4q1bFG53.js";
6
6
  import { t as ToolFailure } from "./failure-_rDKdaLk.js";
7
7
  import { toolPrompts } from "./tools/prompts.js";
8
8
  import { d as formatTaskStatus, l as formatDuration, p as previewLine } from "./format-YgaIcuQ5.js";
@@ -1038,9 +1038,19 @@ function createShellTool(opts = {}) {
1038
1038
  if (typeof steerThresholdMs === "number" && Number.isFinite(steerThresholdMs) && steerThresholdMs > 0 && typeof timeout === "number" && Number.isFinite(timeout) && timeout > steerThresholdMs && allowBackground && typeof ctx.behavior?.tasksDir === "string" && ctx.behavior.tasksDir.length > 0 && ctx.execution.execBackground) throw new ToolFailure(`shell error: this blocking call requested a ${timeout}ms timeout, above the agent's ${steerThresholdMs}ms foreground ceiling. Re-issue with \`run_in_background: true\` (drop \`timeout\`): you'll get a task_id + output log immediately, and a <task-notification> when it finishes. If your very next step depends on the result, follow up with \`wait_task({ task_id })\` instead of polling.`);
1039
1039
  const execOpts = { signal: ctx.signal };
1040
1040
  if (typeof timeout === "number" && Number.isFinite(timeout) && timeout > 0) execOpts.timeout = Math.max(1, Math.ceil(timeout / 1e3));
1041
+ const reportProgress = ctx.reportProgress;
1042
+ if (reportProgress) execOpts.onOutput = (stream, text) => reportProgress({
1043
+ stream,
1044
+ text
1045
+ });
1041
1046
  const wantMetadata = metadata !== false;
1042
1047
  const startedAt = Date.now();
1043
- const result = await ctx.execution.exec(ctx.handle, cmd, execOpts);
1048
+ const raw = await ctx.execution.exec(ctx.handle, cmd, execOpts);
1049
+ const result = {
1050
+ ...raw,
1051
+ stdout: stripAnsi(raw.stdout),
1052
+ stderr: stripAnsi(raw.stderr)
1053
+ };
1044
1054
  const durationMs = Date.now() - startedAt;
1045
1055
  const cap = normalizeCap(maxOutputBytes);
1046
1056
  const semantic = interpretShellResult(cmd, result.exitCode);
@@ -1274,4 +1284,4 @@ const waitTask = {
1274
1284
  //#endregion
1275
1285
  export { resolveAttachmentFromTurns as _, shell as a, recordAgentExtensionWiring as b, isReadOnlyShellCommand as c, headSlice as d, middleTruncate as f, parseAttachmentHandle as g, mediaPayloadBytes as h, createShellTool as i, readPersistedBlobOnHost as l, mediaAgeoutMarker as m, waitTask as n, interpretShellResult as o, tailTruncate as p, shellKill as r, classifyShellCommand as s, WAIT_TASK_TIMED_OUT_PREFIX as t, writePersistedBlob as u, agentExtensionWiringOf as v, childExtensionOptions as y };
1276
1286
 
1277
- //# sourceMappingURL=wait-task-BX4NcOOm.js.map
1287
+ //# sourceMappingURL=wait-task-BiI5UaZQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait-task-BiI5UaZQ.js","names":[],"sources":["../src/agent-extension-wiring.ts","../src/attachment-handle.ts","../src/tools/truncate.ts","../src/persisted-blob-io.ts","../src/tools/shell-classify.ts","../src/tools/shell-semantics.ts","../src/tools/shell-reads.ts","../src/tools/shell.ts","../src/tools/shell-kill.ts","../src/tools/wait-task.ts"],"sourcesContent":["/**\n * Which extension runtime an agent's hook bus belongs to. `createAgent`\n * records it when it is given `extensionRuntime`; the spawn tool reads it to\n * hand the same runtime (and approval flow) to a child agent, and\n * `createTracingHooks` reads it to run the `tracing.redact` chain.\n *\n * Kept free of runtime imports so the tracer and the spawn tool can read it\n * without pulling in the agent loop.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from './agent-hooks'\nimport type { AgentExtensionRuntime, ExtensionCallScope, ToolCallApprover } from './agent-interceptors'\nimport type { ToolsCatalog } from './extensions/catalog'\n\n/** What a child agent inherits of its parent's extension wiring. */\nexport interface AgentExtensionWiring {\n /** The parent's extension runtime (interceptors, tools catalog). */\n readonly extensionRuntime: AgentExtensionRuntime\n /** The parent's approval flow for a `tool.call` `'ask'`, when it has one. */\n readonly approveToolCall?: ToolCallApprover\n /** The session interceptor inputs name for this agent's calls. */\n readonly sessionId: () => string | undefined\n}\n\nconst wirings = new WeakMap<Hookable<AgentHooks>, AgentExtensionWiring>()\n\n/**\n * Records the extension wiring of the agent that owns `hooks`.\n *\n * @param hooks - The agent's hook bus.\n * @param wiring - Its runtime, approval flow and session.\n */\nexport function recordAgentExtensionWiring(hooks: Hookable<AgentHooks>, wiring: AgentExtensionWiring): void {\n wirings.set(hooks, wiring)\n}\n\n/**\n * The extension wiring of the agent that owns `hooks`.\n *\n * @param hooks - An agent's hook bus.\n * @returns Its wiring, or `undefined` for an agent built without an extension runtime.\n */\nexport function agentExtensionWiringOf(hooks: Hookable<AgentHooks>): AgentExtensionWiring | undefined {\n return wirings.get(hooks)\n}\n\n/** The options a subagent gets from its parent's extension wiring (see {@link childExtensionOptions}). */\nexport interface ChildExtensionOptions {\n extensionRuntime: AgentExtensionRuntime\n approveToolCall?: ToolCallApprover\n extensionScope: ExtensionCallScope\n}\n\n/**\n * The extension options of a subagent: its parent's runtime, so the parent's\n * interceptors (`tool.call` among them) and tools catalog apply to the\n * child's calls too; the parent's approval flow, told which child asks; and\n * the parent's session and run for interceptor inputs.\n *\n * A subagent whose tools a subagent type narrowed (`tools`, `readonly`)\n * gets a tools catalog that can edit and remove its tools but not add any:\n * the type's filter stays the upper bound.\n *\n * @param wiring - The parent agent's wiring (`agentExtensionWiringOf(ctx.hooks)`).\n * @param child - The child's spawn id, the spawning run, and whether its tools were narrowed.\n * @param child.childId - Spawn id (`child-1`), passed to the approval flow.\n * @param child.parentRunId - The run that spawned it.\n * @param child.narrowed - Whether a subagent type filtered the child's tools.\n * @returns Options to spread into the child's `createAgent`.\n */\nexport function childExtensionOptions(wiring: AgentExtensionWiring, child: { childId: string, parentRunId?: string, narrowed?: boolean }): ChildExtensionOptions {\n const { extensionRuntime, approveToolCall } = wiring\n const tools = extensionRuntime.catalogs?.tools\n const runtime: AgentExtensionRuntime = child.narrowed && tools\n ? { ...extensionRuntime, catalogs: { ...extensionRuntime.catalogs, tools: { read: context => onlyBaseTools(tools.read(context), context) } } }\n : extensionRuntime\n return {\n extensionRuntime: runtime,\n // A grandchild's approver is wrapped again: the innermost child names itself.\n ...(approveToolCall ? { approveToolCall: (call, origin) => approveToolCall(call, origin ?? { childId: child.childId }) } : {}),\n extensionScope: {\n sessionId: wiring.sessionId,\n ...(child.parentRunId !== undefined ? { parentRunId: child.parentRunId } : {}),\n },\n }\n}\n\n/** A catalog read cut down to the tools of its base: edits and removals stay, additions go. */\nfunction onlyBaseTools(value: ReturnType<ToolsCatalog['read']>, context: Parameters<ToolsCatalog['read']>[0]): ReturnType<ToolsCatalog['read']> {\n if (!context?.base)\n return value\n const names = new Set(context.base.map(sourced => sourced.item.name))\n return { ...value, items: value.items.filter(tool => names.has(tool.name)) }\n}\n","/**\n * Attachment re-resolve handles + the media age-out marker.\n *\n * zidane keeps attachment bytes inline in `session.turns` (browsable history),\n * but ages old base64 OFF THE WIRE so a long session doesn't carry every\n * screenshot / pasted image forever (`behavior.mediaKeepTurns`). An aged-out\n * media block is replaced on the wire with a short text marker carrying a\n * stable `attachment://<hash>` handle; `read_file` resolves that handle back to\n * the original bytes from `session.turns` on demand, so nothing is ever lost -\n * a strict improvement over a dead \"[content cleared]\" stub.\n *\n * The handle is a content digest of the full base64 payload. It's stable across\n * turns (so markers stay byte-identical and the prompt cache holds), needs no\n * schema change / id threading at ingest, and avoids re-serving the wrong image\n * when two attachments share a prefix and length.\n */\n\nimport type { SessionContentBlock, ToolResultContent } from './types'\nimport { Buffer } from 'node:buffer'\nimport { createHash } from 'node:crypto'\nimport { humanBytes } from './format-bytes'\n\nexport const ATTACHMENT_HANDLE_SCHEME = 'attachment://'\n\n/**\n * Stable digest of the full base64 payload. We keep the visible handle short\n * (128-bit hex prefix) but hash the whole payload so same-size images with\n * identical headers / early pixels cannot alias.\n */\nfunction hashAttachmentData(data: string): string {\n return createHash('sha256').update(data).digest('hex').slice(0, 32)\n}\n\n/** Stable re-resolve handle for a base64 media payload. */\nexport function attachmentHandleFor(data: string): string {\n return `${ATTACHMENT_HANDLE_SCHEME}${hashAttachmentData(data)}`\n}\n\n/**\n * Parse an `attachment://<hash>` path back to its hash, or `null` when the path\n * isn't an attachment handle (i.e. a normal filesystem path). Used by\n * `read_file` to branch into the session re-resolve path.\n */\nexport function parseAttachmentHandle(path: string): string | null {\n if (!path.startsWith(ATTACHMENT_HANDLE_SCHEME))\n return null\n const hash = path.slice(ATTACHMENT_HANDLE_SCHEME.length).trim()\n return hash.length > 0 ? hash : null\n}\n\n/**\n * Payload byte length of a media block's `data` — raw text length for\n * text-encoded documents, decoded (padding-accurate) length for base64.\n */\nexport function mediaPayloadBytes(data: string, encoding?: 'base64' | 'text'): number {\n if (encoding === 'text')\n return Buffer.byteLength(data)\n return decodedBase64Bytes(data)\n}\n\n/** Decoded byte length of a base64 string (padding-accurate). */\nfunction decodedBase64Bytes(b64: string): number {\n if (b64.length === 0)\n return 0\n const pad = b64.endsWith('==') ? 2 : b64.endsWith('=') ? 1 : 0\n return Math.max(0, Math.floor((b64.length * 3) / 4) - pad)\n}\n\ninterface MediaLike {\n type: 'image' | 'document'\n mediaType: string\n data: string\n name?: string\n encoding?: 'base64' | 'text'\n}\n\n/**\n * Build the wire marker that replaces an aged-out media block. Stable for a\n * given payload (handle + size + mediaType) so the elided prefix stays\n * byte-identical across turns and the prompt cache holds.\n *\n * `readFileToolName` is the WIRE name of the file-read tool (e.g. `Read` when\n * the host aliases `read_file`), so the re-read hint names the tool the model\n * actually sees. Defaults to the canonical `read_file`. Pass `null` when the\n * media was stripped for emergency overflow recovery but no re-resolving tool\n * is available in this run.\n */\nexport function mediaAgeoutMarker(block: MediaLike, readFileToolName: string | null = 'read_file'): string {\n const handle = attachmentHandleFor(block.data)\n const size = humanBytes(mediaPayloadBytes(block.data, block.encoding))\n const named = block.name ? ` \"${block.name}\"` : ''\n const resolveHint = readFileToolName\n ? `Still saved in this session; re-read with ${readFileToolName} path=\"${handle}\" to view it again.`\n : `Still saved in this session as ${handle}, but no file-read tool is available in this run to re-open it.`\n return `[${block.type} aged out of context to save tokens -${named} ${block.mediaType}, ${size}. ${resolveHint}]`\n}\n\nexport interface ResolvedAttachment {\n kind: 'image' | 'document'\n mediaType: string\n data: string\n name?: string\n encoding?: 'base64' | 'text'\n}\n\nfunction matchMediaBlock(\n block: SessionContentBlock | ToolResultContent,\n hash: string,\n): ResolvedAttachment | null {\n if (block.type === 'image' && typeof (block as { data?: unknown }).data === 'string') {\n const data = (block as { data: string }).data\n if (attachmentHandleFor(data) !== `${ATTACHMENT_HANDLE_SCHEME}${hash}`)\n return null\n return { kind: 'image', mediaType: block.mediaType, data, ...(block.name ? { name: block.name } : {}) }\n }\n if (block.type === 'document' && typeof (block as { data?: unknown }).data === 'string') {\n const data = (block as { data: string }).data\n if (attachmentHandleFor(data) !== `${ATTACHMENT_HANDLE_SCHEME}${hash}`)\n return null\n const encoding = (block as { encoding?: 'base64' | 'text' }).encoding ?? 'base64'\n return { kind: 'document', mediaType: block.mediaType, data, encoding, ...(block.name ? { name: block.name } : {}) }\n }\n return null\n}\n\n/**\n * Find the original bytes for an `attachment://<hash>` handle by scanning\n * persisted turns. Walks newest-to-oldest so a re-pasted image resolves to its\n * latest copy. Searches both top-level `image`/`document` blocks and\n * image/document parts nested in `tool_result` outputs.\n *\n * Returns `null` when no match - the bytes were never present, or only ever\n * lived as an unresolved `ref` (host-offloaded; not recoverable from turns\n * alone).\n */\nexport function resolveAttachmentFromTurns(\n turns: readonly { content: readonly SessionContentBlock[] }[],\n hash: string,\n): ResolvedAttachment | null {\n for (let i = turns.length - 1; i >= 0; i--) {\n for (const block of turns[i].content) {\n const direct = matchMediaBlock(block, hash)\n if (direct)\n return direct\n if (block.type === 'tool_result' && Array.isArray(block.output)) {\n for (const part of block.output) {\n const nested = matchMediaBlock(part, hash)\n if (nested)\n return nested\n }\n }\n }\n }\n return null\n}\n","/**\n * Byte-budgeted truncation shared across tools: keep the end (`tailTruncate`,\n * for command output whose errors and summaries come last), the start and end\n * (`middleTruncate`, for content read for its structure), or the start\n * (`headSlice`, for previews).\n *\n * Budgets are UTF-8 *byte* counts, not character counts — wire/output\n * accounting is bytes, and a naive `String.prototype.slice` (UTF-16 code\n * units) under-counts multibyte text badly. Every cut lands on a whole code\n * point: the walks step by code point (surrogate pairs included), so an emoji\n * or CJK glyph is never split into a lone surrogate. Pure: no `node:buffer`.\n */\n\nimport { utf8ByteLength } from '../compact/utils'\n\n/** Options for {@link tailTruncate}. */\nexport interface TailTruncateOptions {\n /**\n * Build the marker inserted before the kept tail, given the number of\n * UTF-8 bytes dropped from the head. Defaults to\n * `…(<n> bytes truncated from head)…\\n`. Return an empty string to keep\n * the tail with no marker at all.\n */\n marker?: (droppedBytes: number) => string\n}\n\n/** Options for {@link middleTruncate}. */\nexport interface MiddleTruncateOptions {\n /**\n * Build the marker inserted between the kept start and end, given what was\n * dropped. Defaults to `\\n…(<n> bytes truncated from the middle)…\\n`.\n */\n marker?: (omitted: { bytes: number, chars: number }) => string\n /** Share of the budget kept from the start. Default 0.6. */\n headShare?: number\n}\n\nfunction defaultTailMarker(droppedBytes: number): string {\n return `…(${droppedBytes} bytes truncated from head)…\\n`\n}\n\nfunction defaultMiddleMarker(omitted: { bytes: number }): string {\n return `\\n…(${omitted.bytes} bytes truncated from the middle)…\\n`\n}\n\n/**\n * The longest start of `text` that fits in `maxBytes` UTF-8 bytes, with its\n * size. Returns `text` itself when it already fits.\n *\n * @param text - Text to slice.\n * @param maxBytes - UTF-8 bytes to keep. Zero or less keeps nothing.\n */\nexport function headSlice(text: string, maxBytes: number): { slice: string, bytes: number } {\n if (maxBytes <= 0)\n return { slice: '', bytes: 0 }\n const total = utf8ByteLength(text)\n if (total <= maxBytes)\n return { slice: text, bytes: total }\n let bytes = 0\n let end = 0\n // `for...of` yields whole code points, so a surrogate pair is never split.\n for (const ch of text) {\n const chBytes = utf8ByteLength(ch)\n if (bytes + chBytes > maxBytes)\n break\n bytes += chBytes\n end += ch.length\n }\n return { slice: text.slice(0, end), bytes }\n}\n\n/** The longest end of `text` that fits in `maxBytes` UTF-8 bytes. */\nfunction tailSlice(text: string, maxBytes: number): string {\n let bytes = 0\n let cut = text.length\n while (cut > 0) {\n let start = cut - 1\n const code = text.charCodeAt(start)\n // Low surrogate at the boundary → step back to include its high\n // surrogate so the pair stays intact.\n if (code >= 0xDC00 && code <= 0xDFFF && start > 0) {\n const high = text.charCodeAt(start - 1)\n if (high >= 0xD800 && high <= 0xDBFF)\n start -= 1\n }\n const codePointBytes = utf8ByteLength(text.slice(start, cut))\n if (bytes + codePointBytes > maxBytes)\n break\n bytes += codePointBytes\n cut = start\n }\n return text.slice(cut)\n}\n\n/**\n * Keep the last `maxBytes` UTF-8 bytes of `text`, dropping the head and\n * prefixing a marker. A non-positive `maxBytes` disables truncation and\n * returns `text` unchanged.\n *\n * `maxBytes` budgets the kept tail only; the marker is added on top and may\n * push the returned string slightly past `maxBytes`. That tradeoff is\n * intentional — folding the marker into the budget would shrink the content\n * actually shown. A leading run of U+FFFD (left by an upstream raw-byte slice\n * that landed mid-codepoint) is stripped from the kept tail.\n *\n * @param text - Text to truncate.\n * @param maxBytes - UTF-8 bytes of tail to keep. Zero or less disables truncation.\n * @param options - Marker override. See {@link TailTruncateOptions}.\n */\nexport function tailTruncate(text: string, maxBytes: number, options: TailTruncateOptions = {}): string {\n if (!Number.isFinite(maxBytes) || maxBytes <= 0)\n return text\n const totalBytes = utf8ByteLength(text)\n if (totalBytes <= maxBytes)\n return text\n const tail = tailSlice(text, maxBytes).replace(/^\\uFFFD+/, '')\n const marker = options.marker ?? defaultTailMarker\n return `${marker(totalBytes - utf8ByteLength(tail))}${tail}`\n}\n\n/**\n * Keep the start and the end of `text` within `maxBytes` UTF-8 bytes, with a\n * marker in the gap. A non-positive `maxBytes` disables truncation. As with\n * {@link tailTruncate}, the marker comes on top of the budget.\n *\n * @param text - Text to truncate.\n * @param maxBytes - UTF-8 bytes of start and end to keep. Zero or less disables truncation.\n * @param options - Marker and split. See {@link MiddleTruncateOptions}.\n */\nexport function middleTruncate(text: string, maxBytes: number, options: MiddleTruncateOptions = {}): string {\n if (!Number.isFinite(maxBytes) || maxBytes <= 0)\n return text\n const totalBytes = utf8ByteLength(text)\n if (totalBytes <= maxBytes)\n return text\n const head = headSlice(text, Math.floor(maxBytes * (options.headShare ?? 0.6)))\n const tail = tailSlice(text.slice(head.slice.length), maxBytes - head.bytes)\n const omitted = {\n bytes: totalBytes - head.bytes - utf8ByteLength(tail),\n chars: text.length - head.slice.length - tail.length,\n }\n return `${head.slice}${(options.marker ?? defaultMiddleMarker)(omitted)}${tail}`\n}\n","/**\n * Spilled tool results (`behavior.persistDir`) are zidane's own files, not the\n * workspace's. They are written and read through the execution context, so a\n * docker or sandbox run keeps them on its own filesystem. A process context\n * confined to a workspace root (`workspaceRoot`) or to writable roots refuses\n * them, though: the stub would point the model at a file it cannot write or\n * read back. On a process handle, these helpers fall back to the host\n * filesystem when the context refuses. Internal module.\n */\n\nimport type { ExecutionContext, ExecutionHandle } from './contexts/types'\nimport { mkdir, readFile, realpath, writeFile } from 'node:fs/promises'\nimport { dirname, isAbsolute, relative, resolve } from 'node:path'\nimport { errorMessage } from './errors'\n\nfunction isInside(root: string, target: string): boolean {\n const rel = relative(root, target)\n return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel)\n}\n\n/**\n * Write a spilled blob through the execution context, or on the host when an\n * in-process context refuses it.\n * @param execution - The run's execution context.\n * @param handle - The run's execution handle.\n * @param path - Blob path, inside `persistDir` (or the temp dir for codemode spills).\n * @param content - Blob text.\n * @param shouldRethrow - Errors to rethrow as-is instead of falling back (the run's durable runtime `isControlError`).\n */\nexport async function writePersistedBlob(execution: ExecutionContext, handle: ExecutionHandle, path: string, content: string, shouldRethrow?: (err: unknown) => boolean): Promise<void> {\n try {\n await execution.writeFile(handle, path, content)\n }\n catch (error) {\n if (handle.type !== 'process' || shouldRethrow?.(error))\n throw error\n const full = resolve(handle.cwd, path)\n try {\n await mkdir(dirname(full), { recursive: true })\n await writeFile(full, content, 'utf-8')\n }\n catch (hostError) {\n throw new Error(`${errorMessage(error)}; the host write failed too: ${errorMessage(hostError)}`)\n }\n }\n}\n\n/**\n * Read a file inside `persistDir` on the host. Used by `read_file` after an\n * in-process context refused the path. Symlinks are resolved first, so the\n * file must really live in `persistDir`.\n * @param persistDir - The run's `behavior.persistDir`.\n * @param handle - The run's execution handle.\n * @param path - Path the model asked for.\n * @returns The text, or `undefined` when this is not a blob the host may read.\n */\nexport async function readPersistedBlobOnHost(persistDir: string | undefined, handle: ExecutionHandle, path: string): Promise<string | undefined> {\n if (handle.type !== 'process' || !persistDir || !isAbsolute(persistDir))\n return undefined\n if (!isInside(resolve(persistDir), resolve(handle.cwd, path)))\n return undefined\n try {\n const [root, target] = await Promise.all([realpath(persistDir), realpath(resolve(handle.cwd, path))])\n return isInside(root, target) ? await readFile(target, 'utf-8') : undefined\n }\n catch {\n return undefined\n }\n}\n","/**\n * What a shell command does, read from its text. The one place that\n * classifies commands for the shell tool (scheduling, output truncation),\n * shell read tracking, the shell nudges, the evals and the usage report.\n * Pure string work: nothing is run.\n */\n\n// ---------------------------------------------------------------------------\n// Segments and tokens\n// ---------------------------------------------------------------------------\n\n/** One `&&` / `;` / newline-joined segment, with the separator after it (`null` after the last). */\nexport interface ShellSegment {\n /** The trimmed segment text. */\n text: string\n /** The separator that follows the segment, or `null` after the last one. */\n next: '&&' | ';' | null\n}\n\n/**\n * Split a command into `&&` / `;` / newline-joined segments, ignoring\n * separators inside single or double quotes (`sed -n '1,5p;9p' f` is one\n * segment). `||` is not a separator here: it stays inside the segment, whose\n * `|` then marks it as piped/compound.\n */\nexport function splitShellSegments(command: string): string[] {\n return splitShellSegmentsWithSeparators(command).map(seg => seg.text)\n}\n\n/** {@link splitShellSegments}, with the separator that follows each segment (`null` after the last). */\nexport function splitShellSegmentsWithSeparators(command: string): ShellSegment[] {\n const segments: ShellSegment[] = []\n let current = ''\n let quote: '\\'' | '\"' | null = null\n for (let i = 0; i < command.length; i++) {\n const ch = command[i]\n if (quote) {\n if (ch === quote)\n quote = null\n current += ch\n continue\n }\n if (ch === '\\'' || ch === '\"') {\n quote = ch\n current += ch\n continue\n }\n if (ch === ';' || ch === '\\n' || (ch === '&' && command[i + 1] === '&')) {\n segments.push({ text: current.trim(), next: ch === '&' ? '&&' : ';' })\n current = ''\n if (ch === '&')\n i++\n continue\n }\n current += ch\n }\n segments.push({ text: current.trim(), next: null })\n return segments.filter(seg => seg.text.length > 0)\n}\n\n/** A `&` outside quotes that isn't part of `&&` (backgrounding, `|&`). */\nexport function hasLoneAmpersand(command: string): boolean {\n let quote: '\\'' | '\"' | null = null\n for (let i = 0; i < command.length; i++) {\n const ch = command[i]\n if (quote) {\n if (ch === quote)\n quote = null\n continue\n }\n if (ch === '\\'' || ch === '\"') {\n quote = ch\n continue\n }\n if (ch === '&') {\n if (command[i + 1] === '&') {\n i++\n continue\n }\n return true\n }\n }\n return false\n}\n\n/**\n * Split on whitespace, honoring single and double quotes. Returns `null` on\n * an unbalanced quote or any backslash escape (not worth modelling).\n */\nexport function tokenizeShellSegment(segment: string): string[] | null {\n const tokens: string[] = []\n let current = ''\n let quote: '\\'' | '\"' | null = null\n let inToken = false\n for (const ch of segment) {\n if (quote) {\n if (ch === quote)\n quote = null\n else\n current += ch\n continue\n }\n if (ch === '\\\\')\n return null\n if (ch === '\\'' || ch === '\"') {\n quote = ch\n inToken = true\n continue\n }\n if (/\\s/.test(ch)) {\n if (inToken)\n tokens.push(current)\n current = ''\n inToken = false\n continue\n }\n current += ch\n inToken = true\n }\n if (quote)\n return null\n if (inToken)\n tokens.push(current)\n return tokens\n}\n\n// ---------------------------------------------------------------------------\n// Read-only verdict (scheduling)\n// ---------------------------------------------------------------------------\n\n/**\n * Best-effort read-only allow-list for the leading command token. Members\n * are commands that do not write to the workspace in ordinary use — `ls`,\n * `cat`, `pwd`, etc. Commands that *can*\n * mutate depending on flags (`find -delete`, `git tag <name>`, `tar -x`)\n * are intentionally excluded; the input-aware {@link isReadOnlyShellCommand}\n * predicate falls back to the conservative \"not safe\" answer for them, so\n * the scheduler barriers them.\n */\nconst SHELL_READ_ONLY_COMMANDS: ReadonlySet<string> = new Set([\n 'ls',\n 'cat',\n 'head',\n 'tail',\n 'wc',\n 'pwd',\n 'whoami',\n 'id',\n 'date',\n 'uname',\n 'hostname',\n 'tty',\n 'echo',\n 'printf',\n 'printenv',\n 'which',\n 'type',\n 'file',\n 'stat',\n 'grep',\n 'rg',\n 'ag',\n 'true',\n 'false',\n 'test',\n // Intentionally NOT included: `sed`, `awk`, `find`, `tar`, `xargs`,\n // `tee` — all can write to disk depending on flags / script body\n // (`sed -i`, `awk 'BEGIN { print > \"f\" }'`, `find -delete`, `tar\n // -x`). Conservative omission keeps the predicate fail-closed.\n //\n // `env` and `command` are also NOT here: they are wrappers that execute\n // their trailing argument (`env rm -rf x`, `command rm foo`), so listing\n // them would launder mutating commands through the read-only fleet. They\n // are handled as wrappers in {@link isReadOnlyShellCommand} instead.\n])\n\n/**\n * `git` subcommands that are pure reads regardless of arguments. Excludes\n * `branch`/`tag`/`remote` (which can mutate when given a name) and\n * `config` (which writes when given a value).\n */\nconst GIT_READ_ONLY_SUBCOMMANDS: ReadonlySet<string> = new Set([\n 'status',\n 'log',\n 'diff',\n 'show',\n 'blame',\n 'rev-parse',\n 'ls-files',\n 'ls-tree',\n 'cat-file',\n 'reflog',\n 'shortlog',\n 'describe',\n 'rev-list',\n 'name-rev',\n 'whatchanged',\n 'merge-base',\n 'symbolic-ref',\n])\n\n/**\n * Conservative read-only verdict for a shell command — used to opt a\n * `shell` invocation into the scheduler's concurrent fleet. Returns\n * `false` (fail-closed) on anything ambiguous so the scheduler barriers\n * it. Specifically:\n *\n * - Rejects compound commands (`;`, `&&`, `||`, `|`) and redirects (`>`,\n * `>>`, `<`) — even a pipe to a read-only sink is treated as too\n * complex to analyze.\n * - Rejects subshell / process substitution (`$(...)`, `` `...` ``,\n * `<(...)`, `>(...)`).\n * - Skips leading `VAR=value` env assignments to find the real\n * command token.\n * - Unwraps the `env` / `command` wrappers and classifies the wrapped\n * verb instead (`env rm -rf x` is NOT read-only; bare `env` is).\n * - Strips a possible absolute path on the command (`/usr/bin/ls` → `ls`).\n * - Allows the command iff its base name is in\n * {@link SHELL_READ_ONLY_COMMANDS} OR it's `git <subcmd>` where\n * `<subcmd>` is in {@link GIT_READ_ONLY_SUBCOMMANDS}.\n *\n * Cheap (no spawned process; regex + token scan). Safe to call from the\n * hot scheduler path.\n */\nexport function isReadOnlyShellCommand(command: unknown): boolean {\n if (typeof command !== 'string')\n return false\n const trimmed = command.trim()\n if (trimmed === '')\n return false\n\n // Shell metacharacters that could enable mutation, command chaining,\n // or backgrounding — any of these takes the command out of the\n // \"single read invocation\" shape we can analyze safely. Pipes (`|`)\n // are rejected even when piping to a read-only sink because parsing\n // both sides is more complexity than the win.\n //\n // >, <, >> — redirects\n // ;, &, \\n — command separators (and `&` covers backgrounding)\n // |, ||, && — pipes + boolean chains\n // `…`, $(…) — command substitution\n // <(…), >(…) — process substitution\n if (/[<>;&|`\\n]/.test(trimmed))\n return false\n if (trimmed.includes('$(') || trimmed.includes('<(') || trimmed.includes('>('))\n return false\n\n const tokens = trimmed.split(/\\s+/)\n let i = 0\n while (i < tokens.length) {\n // Skip leading VAR=value env assignments (e.g. `FOO=bar ls`,\n // `env FOO=bar ls`).\n while (i < tokens.length && /^[A-Z_]\\w*=/i.test(tokens[i]))\n i++\n const head = tokens[i]\n if (!head)\n return false\n\n // Strip a leading path: `/usr/bin/ls` → `ls`.\n const base = head.split('/').pop() ?? head\n\n // `env` / `command` execute their trailing argument — classify by the\n // wrapped verb, not the wrapper (`env rm -rf x` mutates). Skip the\n // wrapper plus its flags (`env -i`, `command -p`) and loop on what's\n // left. A bare `env` with no trailing command just prints the\n // environment — read-only. Anything else (`command -v rm` etc.) falls\n // through to the conservative verb check.\n if (base === 'env' || base === 'command') {\n i++\n while (i < tokens.length && tokens[i].startsWith('-'))\n i++\n if (i >= tokens.length)\n return base === 'env'\n continue\n }\n\n if (SHELL_READ_ONLY_COMMANDS.has(base))\n return true\n if (base === 'git') {\n const sub = tokens[i + 1]\n return typeof sub === 'string' && GIT_READ_ONLY_SUBCOMMANDS.has(sub)\n }\n return false\n }\n return false\n}\n\n// ---------------------------------------------------------------------------\n// Kind\n// ---------------------------------------------------------------------------\n\n/**\n * What a command does: `edit` writes files by script, `build` runs a build,\n * test, package or script tool, `git` runs git, `read` / `search` / `list`\n * only explore, `other` is anything else.\n */\nexport type ShellCommandKind = 'read' | 'search' | 'list' | 'edit' | 'build' | 'git' | 'other'\n\nconst READ_VERBS: ReadonlySet<string> = new Set(['cat', 'head', 'tail', 'nl'])\nconst SEARCH_VERBS: ReadonlySet<string> = new Set(['rg', 'grep', 'ag'])\nconst LIST_VERBS: ReadonlySet<string> = new Set(['ls', 'find', 'tree', 'wc', 'du', 'stat', 'file'])\n/** Segments that only decorate exploration output (`echo ---` separators, `cd`). */\nconst NEUTRAL_VERBS: ReadonlySet<string> = new Set(['cd', 'echo', 'printf', 'pwd'])\n/** Build, test, package and script runners, whose output ends with what matters. */\nconst BUILD_VERBS: ReadonlySet<string> = new Set(['bun', 'bunx', 'npm', 'npx', 'pnpm', 'yarn', 'node', 'deno', 'tsc', 'vitest', 'jest', 'eslint', 'make', 'cargo', 'go', 'python', 'python3', 'pytest', 'uv', 'pip', 'docker', 'vite', 'turbo'])\n/** `find` actions that delete or run commands. */\nconst FIND_ACTIONS = /\\s-(?:delete|exec|execdir|ok|okdir)\\b/\n\n/**\n * Scripted file writes: in-place sed/perl, python/node writing files,\n * `cat >` / heredoc-to-file, `tee`.\n */\nconst SCRIPTED_EDIT = /\\bsed\\s+(?:-[a-z]*\\s+)*-i\\b|\\bsed\\s+-[a-z]*i|\\bperl\\s+-[a-z]*i|\\.write_text\\(|\\.write\\(|open\\([^)]*,\\s*['\"][wa]\\+?['\"]|writeFileSync\\(|\\bcat\\s*>|<<-?\\s*['\"]?\\w+['\"]?\\s*>|\\btee\\s/\n\n/** Precedence once every segment is known: one unknown verb makes the whole command `other`. */\nconst KIND_PRECEDENCE: readonly ShellCommandKind[] = ['other', 'git', 'list', 'read', 'search']\n\n/**\n * Classify a command. A scripted write anywhere makes it `edit`, a build verb\n * anywhere `build`. Otherwise each segment is classified by its verb (`cd` and\n * `echo` separators are neutral, pipes count by their first command), and the\n * command takes the first kind of {@link KIND_PRECEDENCE} it contains, so\n * `rg x && sed -n 1,9p f` is a read and a build chained after a read never is.\n */\nexport function classifyShellCommand(command: string): ShellCommandKind {\n if (SCRIPTED_EDIT.test(command))\n return 'edit'\n const seen = new Set<ShellCommandKind>()\n for (const segment of splitShellSegments(command)) {\n const head = (segment.split('|')[0] ?? '').trim()\n const verb = head.split(/\\s+/)[0] ?? ''\n if (NEUTRAL_VERBS.has(verb))\n continue\n if (BUILD_VERBS.has(verb))\n return 'build'\n if (READ_VERBS.has(verb) || (verb === 'sed' && /\\s-n\\b/.test(segment)))\n seen.add('read')\n else if (SEARCH_VERBS.has(verb))\n seen.add('search')\n else if (LIST_VERBS.has(verb) && !(verb === 'find' && FIND_ACTIONS.test(head)))\n seen.add('list')\n else if (verb === 'git')\n seen.add('git')\n else\n seen.add('other')\n }\n return KIND_PRECEDENCE.find(kind => seen.has(kind)) ?? 'other'\n}\n\n/** Filters that only reshape exploration output piped into them. */\nconst FILTER_VERBS: ReadonlySet<string> = new Set(['sort', 'uniq', 'cut', 'tr', 'column', 'jq', 'awk'])\n\n/** The git subcommand of `git [-C dir] [-c k=v] [--flag] <sub> …`. */\nfunction gitSubcommand(tokens: string[]): string | undefined {\n for (let i = 1; i < tokens.length; i++) {\n if (tokens[i] === '-C' || tokens[i] === '-c')\n i++\n else if (!tokens[i].startsWith('-'))\n return tokens[i]\n }\n return undefined\n}\n\n/**\n * Whether a command only explores, so its output is read for its structure:\n * every stage of every pipe is a read, search, list, filter or read-only git\n * verb (`git push`, `cat in | python x.py` are not).\n */\nexport function isExploringShellCommand(command: string): boolean {\n const kind = classifyShellCommand(command)\n if (kind !== 'read' && kind !== 'search' && kind !== 'list' && kind !== 'git')\n return false\n return splitShellSegments(command).every(segment => segment.split('|').every((stage) => {\n const tokens = stage.trim().split(/\\s+/)\n const verb = tokens[0] ?? ''\n if (verb === 'git') {\n const sub = gitSubcommand(tokens)\n return sub !== undefined && GIT_READ_ONLY_SUBCOMMANDS.has(sub)\n }\n return NEUTRAL_VERBS.has(verb) || READ_VERBS.has(verb) || SEARCH_VERBS.has(verb) || FILTER_VERBS.has(verb)\n || (verb === 'sed' && /\\s-n\\b/.test(stage))\n || (LIST_VERBS.has(verb) && !(verb === 'find' && FIND_ACTIONS.test(stage)))\n }))\n}\n\n/**\n * Whether a command sends output into a file: a `>` / `>>` outside quotes\n * whose target is neither a file descriptor (`2>&1`) nor `/dev/null`.\n */\nexport function redirectsToFile(command: string): boolean {\n let quote: '\\'' | '\"' | null = null\n for (let i = 0; i < command.length; i++) {\n const ch = command[i]\n if (quote) {\n if (ch === quote)\n quote = null\n continue\n }\n if (ch === '\\'' || ch === '\"') {\n quote = ch\n continue\n }\n if (ch !== '>')\n continue\n let j = command[i + 1] === '>' ? i + 2 : i + 1\n while (command[j] === ' ')\n j++\n const target = /^[^\\s;&|]*/.exec(command.slice(j))?.[0] ?? ''\n if (command[j] !== '&' && target !== '/dev/null')\n return true\n i = j\n }\n return false\n}\n","/**\n * Per-command exit-code interpretation for the `shell` tool.\n *\n * Many command-line tools use non-zero exit codes to signal information that\n * is *not* an error — `grep` returns 1 for \"no matches found\", `diff` returns\n * 1 for \"files differ\", `find` returns 1 when some directories were\n * inaccessible, and `test`/`[` return 1 for \"condition false\". Treating\n * those uniformly as failures wastes turns: models retry or pivot when there\n * is nothing wrong.\n *\n * Mirrors `claude-code/tools/BashTool/commandSemantics.ts`.\n */\n\nexport interface CommandSemanticResult {\n /** Whether to surface this as an error to the model (`Exit code N` prefix). */\n isError: boolean\n /** Optional human-readable footer appended after the body, e.g. \"No matches found\". */\n message?: string\n}\n\ntype CommandSemantic = (exitCode: number) => CommandSemanticResult\n\nconst DEFAULT_SEMANTIC: CommandSemantic = exitCode => ({\n isError: exitCode !== 0,\n message: exitCode !== 0 ? `Command failed with exit code ${exitCode}` : undefined,\n})\n\nconst COMMAND_SEMANTICS: ReadonlyMap<string, CommandSemantic> = new Map<string, CommandSemantic>([\n // grep / ripgrep: 0 = matches, 1 = no matches, ≥2 = error.\n ['grep', exit => ({ isError: exit >= 2, message: exit === 1 ? 'No matches found' : undefined })],\n ['rg', exit => ({ isError: exit >= 2, message: exit === 1 ? 'No matches found' : undefined })],\n // diff: 0 = identical, 1 = differ, ≥2 = error.\n ['diff', exit => ({ isError: exit >= 2, message: exit === 1 ? 'Files differ' : undefined })],\n // find: 0 = ok, 1 = some dirs inaccessible (warning), ≥2 = error.\n ['find', exit => ({ isError: exit >= 2, message: exit === 1 ? 'Some directories were inaccessible' : undefined })],\n // test / [: 0 = condition true, 1 = condition false, ≥2 = error.\n ['test', exit => ({ isError: exit >= 2, message: exit === 1 ? 'Condition is false' : undefined })],\n ['[', exit => ({ isError: exit >= 2, message: exit === 1 ? 'Condition is false' : undefined })],\n])\n\n/**\n * Pick the semantic for a command line. Best-effort: walks the command from\n * right to left, taking the last segment after `|` / `&&` / `||` / `;` —\n * that's the segment whose exit code propagates. Don't depend on this for\n * security; it's a heuristic, not a parser.\n */\nexport function interpretShellResult(\n command: string,\n exitCode: number,\n): CommandSemanticResult {\n const base = extractTrailingCommand(command)\n const semantic = COMMAND_SEMANTICS.get(base) ?? DEFAULT_SEMANTIC\n return semantic(exitCode)\n}\n\nfunction extractTrailingCommand(command: string): string {\n // Split on the common chain operators. The exit code we see is the trailing\n // segment's. Quoted operators escape the split, but we don't try to be\n // perfect — false positives just fall back to default semantics.\n const segments = command.split(/\\|\\||&&|[;|\\n]/)\n const last = segments[segments.length - 1]?.trim() ?? command\n // First whitespace-delimited token of the trailing segment, sans leading\n // env assignments (`FOO=bar baz` → `baz`).\n const tokens = last.split(/\\s+/).filter(t => !/^[A-Z_]\\w*=/i.test(t))\n return tokens[0] ?? ''\n}\n","/**\n * `behavior.trackShellReads`: count simple shell file reads (`cat`, `head`,\n * `tail`, `nl`, `sed -n '<range>p'`) as reads in the per-session read-state,\n * so the `requireReadBeforeEdit` gate accepts a file the model inspected\n * through `shell`.\n *\n * The parser is deliberately narrow and fail-closed: anything it can't\n * classify registers nothing. Segments joined by `&&` / `;` are read\n * independently (a leading `cd dir &&` shifts the base for later segments;\n * a `cd` followed by `;` or a newline registers nothing, as it may have failed).\n * Any other segment, piped ones included, registers nothing for the whole\n * command: hashing happens after it ran, so a same-command write would be\n * recorded as content the model saw. A lone `&` (backgrounding) likewise.\n */\n\nimport type { ToolContext } from './types'\nimport { isAbsolute, join } from 'node:path'\nimport { hashContent, readStateKey, resolveReadStateMap } from './read-state'\nimport { hasLoneAmpersand, splitShellSegmentsWithSeparators, tokenizeShellSegment } from './shell-classify'\n\n/** Files above this size are not hashed (one whole read per file). */\nconst MAX_TRACKED_BYTES = 16 * 1024 * 1024\n\nconst SED_PRINT_SCRIPT = /^(?:(?:\\d+|\\$)(?:,(?:\\d+|\\$))?p;?)+$/\n\n/** `nl` options whose value may come as the next token (`nl -b a f`). */\nconst NL_VALUE_OPTIONS = new Set(['-b', '-s', '-w', '-v', '-i', '-n', '-d', '-h', '-f'])\n\n/** File operands of one read command, or `null` when it isn't a plain read. */\nfunction readOperands(tokens: string[]): string[] | null {\n const [verb, ...rest] = tokens\n const files: string[] = []\n if (verb === 'cat' || verb === 'nl') {\n for (const t of rest) {\n if (verb === 'nl' && (NL_VALUE_OPTIONS.has(t) || (t.startsWith('--') && !t.includes('='))))\n return null\n if (t.startsWith('-'))\n continue\n files.push(t)\n }\n return files\n }\n if (verb === 'head' || verb === 'tail') {\n for (let i = 0; i < rest.length; i++) {\n const t = rest[i]\n if (t === '-f' || t === '-F' || t === '--follow' || t.startsWith('--follow'))\n return null\n if (t === '-n' || t === '-c') {\n i++\n continue\n }\n if (t.startsWith('-'))\n continue\n files.push(t)\n }\n return files\n }\n if (verb === 'sed') {\n let quiet = false\n let script: string | undefined\n for (let i = 0; i < rest.length; i++) {\n const t = rest[i]\n if (t === '-n') {\n quiet = true\n continue\n }\n if (t === '-e') {\n if (script !== undefined)\n return null\n script = rest[++i]\n continue\n }\n if (t.startsWith('-'))\n return null // `-i` and friends can write\n if (script === undefined) {\n script = t\n continue\n }\n files.push(t)\n }\n if (!quiet || script === undefined || !SED_PRINT_SCRIPT.test(script))\n return null\n return files\n }\n return null\n}\n\n/**\n * Paths (relative to the shell's start directory, or absolute) that a\n * command reads in full view of the model. Empty when nothing qualifies.\n */\nexport function shellReadTargets(command: string): string[] {\n if (/[`<>]|\\$\\(/.test(command) || hasLoneAmpersand(command))\n return []\n const targets: string[] = []\n let base = ''\n for (const { text: segment, next } of splitShellSegmentsWithSeparators(command)) {\n if (segment.includes('|'))\n return []\n const tokens = tokenizeShellSegment(segment)\n if (!tokens || tokens.length === 0)\n return []\n if (tokens[0] === 'cd') {\n const dir = tokens[1]\n if (tokens.length !== 2 || dir === '-' || dir.startsWith('~') || dir.includes('$'))\n return []\n // After `;` / newline the rest runs even when the `cd` failed: the base is unknown.\n if (next === ';')\n return []\n base = isAbsolute(dir) ? dir : join(base, dir)\n continue\n }\n const files = readOperands(tokens)\n if (!files)\n return []\n for (const file of files) {\n if (/[*?[\\]$~]/.test(file))\n continue\n const path = isAbsolute(file) || base === '' ? file : join(base, file)\n if (!targets.includes(path))\n targets.push(path)\n }\n }\n return targets\n}\n\n/**\n * Record the files a successful shell command read. Each entry stores the\n * file's current hash (so the read-before-edit gate passes and drift is\n * still detected) and is marked `elided`, so `read_file` dedup never claims\n * the shell output is an already-visible read. An existing entry with the\n * same hash is left alone.\n */\nexport async function registerShellReads(command: string, ctx: ToolContext): Promise<void> {\n const targets = shellReadTargets(command)\n if (targets.length === 0)\n return\n const readState = resolveReadStateMap(ctx)\n if (!readState)\n return\n for (const path of targets) {\n try {\n const size = await ctx.execution.fileSize?.(ctx.handle, path) ?? null\n if (size !== null && size > MAX_TRACKED_BYTES)\n continue\n const raw = await ctx.execution.readFile(ctx.handle, path)\n const key = readStateKey(ctx.handle.cwd, path)\n const contentHash = hashContent(raw)\n if (readState.get(key)?.contentHash === contentHash)\n continue\n readState.set(key, { contentHash, offset: 1, limit: 0, maxBytes: 0, lineNumbers: false, mtimeMs: Date.now(), elided: true })\n }\n catch {\n // Unreadable or vanished: nothing to record.\n }\n }\n}\n","import type { ExecOptions, TaskStallInfo } from '../contexts'\nimport type { ToolContext, ToolDef } from './types'\nimport { previewLine } from '../chat/format'\nimport { stripAnsi } from '../contexts/ansi-strip'\nimport { ToolFailure } from './failure'\nimport { toolPrompts } from './prompts'\nimport { isExploringShellCommand, isReadOnlyShellCommand } from './shell-classify'\nimport { registerShellReads } from './shell-reads'\nimport { interpretShellResult } from './shell-semantics'\nimport { middleTruncate, tailTruncate } from './truncate'\n\n/** Default cap on combined stdout and stderr, in bytes (32 KiB). */\nconst DEFAULT_MAX_OUTPUT_BYTES = 32_768\n\n/**\n * Build the `shell` tool's description text from `toolPrompts.shell`.\n *\n * - The background-mode paragraphs are appended only when `allowBackground`\n * is true so the model isn't pointed at a feature the agent has disabled.\n * - The \"prefer the dedicated tool\" swap block is appended only for siblings\n * actually present in `registeredCanonicals` — re-running `ls`/`cat` to\n * \"verify\" a path the model already inspected through a dedicated tool is\n * a measurable Kimi/Sonnet failure mode. Hosts that ship `shell` without\n * `read_file`/`glob`/etc. don't see misleading nudges. Aliased names are\n * rendered via `toolAliases` so the printed name matches what the model\n * sees in the tool spec.\n */\nfunction buildShellDescription({\n allowBackground,\n registeredCanonicals,\n toolAliases,\n}: {\n allowBackground: boolean\n registeredCanonicals?: ReadonlySet<string>\n toolAliases?: Record<string, string>\n}): string {\n const prompt = toolPrompts.shell\n const lines = [prompt.core]\n\n if (registeredCanonicals && registeredCanonicals.size > 0) {\n const swaps: string[] = []\n for (const { canonical, label, instead } of prompt.swapHints) {\n if (!registeredCanonicals.has(canonical))\n continue\n const wireName = toolAliases?.[canonical] ?? canonical\n swaps.push(`- ${label}: use \\`${wireName}\\` (not ${instead})`)\n }\n if (swaps.length > 0) {\n lines.push('', prompt.preferDedicated, ...swaps, '', prompt.reminder)\n }\n }\n\n if (allowBackground)\n lines.push('', prompt.background)\n return lines.join('\\n')\n}\n\n/**\n * Build the `shell` tool's JSON-schema. The `run_in_background` field\n * is included only when `allowBackground` is true; the `timeout` /\n * `maxOutputBytes` / `metadata` field descriptions also drop their\n * \"Ignored in background mode\" qualifier when there's no background\n * mode to ignore.\n */\nfunction buildShellInputSchema({ allowBackground }: { allowBackground: boolean }): Record<string, unknown> {\n const bgQualifier = allowBackground ? ' Ignored in background mode.' : ''\n const bgQualifierOutput = allowBackground ? ' Ignored in background mode (output streams to disk).' : ''\n const properties: Record<string, unknown> = {\n command: { type: 'string', description: 'Shell command to run.' },\n description: { type: 'string', description: 'Short (5-10 words) human-readable intent of the command, in sentence case, e.g. \"List TypeScript sources in src\" or \"Install project dependencies\". Shown to the user as the call\\'s label in the transcript, next to the command, so they can follow the agent\\'s reasoning.' },\n timeout: { type: 'integer', description: `Per-call timeout in milliseconds. Enforced at whole-second granularity: values are rounded UP to the next second (e.g. 500 → 1s).${bgQualifier}` },\n maxOutputBytes: { type: 'integer', description: `Truncate combined stdout+stderr beyond this many bytes. Default: 32768. Set 0 for unlimited.${bgQualifierOutput}` },\n metadata: { type: 'boolean', description: `Append \\`(exit N, Nms)\\` footer and surface non-empty stderr on success. Default: true.${bgQualifier}` },\n }\n if (allowBackground) {\n properties.run_in_background = { type: 'boolean', description: 'Start the command in the background, returning a task handle. See the tool description for the full flow.' }\n }\n return {\n type: 'object',\n properties,\n required: ['command'],\n }\n}\n\n/** Options for {@link createShellTool}. */\nexport interface CreateShellToolOptions {\n /**\n * Whether to expose the `run_in_background` flag in the input schema +\n * the background-mode paragraphs in the description. When `false`, the\n * model never sees the flag and won't try to use it. The execute path\n * still has a defensive fallback: an explicit `run_in_background: true`\n * call (e.g. from a hand-crafted message) returns a clean error rather\n * than silently running foreground.\n *\n * Default: `true`.\n */\n allowBackground?: boolean\n\n /**\n * Canonical names of tools registered alongside `shell` on the same\n * agent. When non-empty, the description gains a \"prefer the dedicated\n * tool\" block for each known sibling (`read_file`, `glob`, `grep`,\n * `list_files`, `edit`, `write_file`) — useful against the\n * `ls`/`cat`-to-re-verify loop some models fall into when both a\n * dedicated tool AND `shell` are visible. Unknown / unrecognized names\n * are ignored.\n *\n * Set by `createAgent` per-run from the tool registry; hosts that\n * construct a `shell` directly can pass it explicitly. Omit to suppress\n * the block entirely (no nudge for shell-only agents, no nudge for\n * hosts that prefer to author their own anti-loop prose).\n */\n registeredCanonicals?: ReadonlySet<string>\n\n /**\n * The agent's `toolAliases` map, used to render the wire-level name of\n * each sibling in the swap block. Without this, the block always prints\n * canonical names — fine for the default preset, wrong for hosts that\n * alias-rename (the model would be told to call a name it doesn't see\n * in the tool spec).\n */\n toolAliases?: Record<string, string>\n}\n\n/**\n * Cap on `stdout` / `stderr` in the structured result. Larger than the\n * model-facing cap on purpose: a calling tool (codemode) filters the output\n * before anything reaches the model.\n */\nexport const SHELL_STRUCTURED_MAX_BYTES = 1024 * 1024\n\n/** Shape of {@link shellStructuredResult}, documented to calling tools as `outputSchema`. */\nconst SHELL_OUTPUT_SCHEMA: Record<string, unknown> = {\n anyOf: [\n {\n type: 'object',\n properties: {\n stdout: { type: 'string', description: `Standard output, cut to ${SHELL_STRUCTURED_MAX_BYTES} bytes when longer (start and end for reads, the end otherwise).` },\n stderr: { type: 'string', description: `Standard error, cut to ${SHELL_STRUCTURED_MAX_BYTES} bytes when longer (start and end for reads, the end otherwise).` },\n exit_code: { type: 'number' },\n duration_ms: { type: 'number' },\n truncated: { type: 'boolean', description: 'Whether stdout or stderr was cut.' },\n },\n required: ['stdout', 'stderr', 'exit_code', 'duration_ms', 'truncated'],\n },\n {\n // `run_in_background: true`\n type: 'object',\n properties: {\n task_id: { type: 'string', description: 'Pass to wait_task / shell_kill.' },\n output_path: { type: 'string' },\n pid: { type: 'number' },\n },\n required: ['task_id', 'output_path', 'pid'],\n },\n ],\n}\n\n/** Cut output to `cap` bytes: start and end for exploring commands, the end for the rest. */\nfunction truncateOutput(command: string, text: string, cap: number): string {\n return isExploringShellCommand(command) ? middleTruncate(text, cap) : tailTruncate(text, cap)\n}\n\n/** What a nested caller gets for a foreground run, for any exit code. */\nfunction shellStructuredResult(command: string, result: { stdout: string, stderr: string, exitCode: number }, durationMs: number) {\n const stdout = truncateOutput(command, result.stdout, SHELL_STRUCTURED_MAX_BYTES)\n const stderr = tailTruncate(result.stderr, SHELL_STRUCTURED_MAX_BYTES)\n return {\n stdout,\n stderr,\n exit_code: result.exitCode,\n duration_ms: durationMs,\n truncated: stdout !== result.stdout || stderr !== result.stderr,\n }\n}\n\n/**\n * Creates the `shell` tool, which runs a command in the execution context, in the foreground or as a background task.\n *\n * The default exported `shell` is equivalent to `createShellTool({ allowBackground: true })`.\n * Hosts that use `createAgent` typically do not call this directly: when\n * `behavior.tasksDir` is unset or `behavior.disableBackgroundTasks: true` is\n * set, the agent rewrites the registered built-in `shell` using this factory.\n *\n * Truncation is **tail-priority**: when stdout+stderr combined exceeds\n * `maxOutputBytes`, the head is dropped and a marker `…(N bytes truncated\n * from head)…` is inserted before the tail. Errors and exit summaries\n * usually live at the end of output, so keeping the tail preserves the\n * model's most useful signal. Commands that only explore (`cat`, `sed -n`,\n * `grep`, `ls`, `git log`…) keep their start and end instead: what a read\n * shows first is what it was run for.\n *\n * The combined cap defaults to 32 KiB and the per-call timeout follows the\n * execution context's own default (30 s for in-process).\n *\n * Read-only commands run in parallel with other safe tool calls. Anything else runs alone.\n *\n * @param opts - Background support and sibling tool names. See {@link CreateShellToolOptions}.\n * @example\n * ```ts\n * import { createShellTool } from 'zidane/tools'\n *\n * const shell = createShellTool({ allowBackground: false })\n * ```\n */\nexport function createShellTool(opts: CreateShellToolOptions = {}): ToolDef {\n const allowBackground = opts.allowBackground !== false\n const { registeredCanonicals, toolAliases } = opts\n return {\n // Conditional concurrency safety. Read-only commands (`ls`, `cat`,\n // `git status`, `rg`, …) fan out with other safe siblings; anything\n // mutating or ambiguous barriers. See {@link isReadOnlyShellCommand}\n // for the exact allow-list.\n isConcurrencySafe: input => isReadOnlyShellCommand(input.command),\n spec: {\n name: 'shell',\n description: buildShellDescription({ allowBackground, registeredCanonicals, toolAliases }),\n inputSchema: buildShellInputSchema({ allowBackground }),\n outputSchema: SHELL_OUTPUT_SCHEMA,\n },\n async execute({ command, timeout, maxOutputBytes, metadata, run_in_background }, ctx: ToolContext) {\n const cmd = command as string\n\n // Background mode — dispatches via `execBackground` and returns\n // immediately. The model gets a structured one-liner naming the\n // task id + output path; the actual completion notification arrives\n // on the next turn via the agent's `<task-notification>` injection\n // (see `pendingTaskNotifications` in `src/agent-task-notifications.ts`).\n //\n // Defense-in-depth: when this tool variant has `allowBackground:\n // false` the field isn't in the schema, but a forged input could\n // still set it — surface a clean error instead of silently\n // running foreground (which would surprise the caller).\n if (run_in_background === true) {\n if (!allowBackground)\n throw new ToolFailure('shell error: background mode is disabled for this agent (no `behavior.tasksDir` set, or `behavior.disableBackgroundTasks: true`). Fall back to foreground (drop `run_in_background`).')\n return runBackground(cmd, ctx)\n }\n\n // Long-timeout steering — see `behavior.shellLongTimeoutMs`. A\n // blocking call that pins the turn to a multi-minute transport\n // timeout is almost always a background task the model failed to\n // recognize as one. Refuse with a re-issue instruction, but ONLY\n // when background mode is actually available — otherwise the\n // blocking call is the model's only option and refusing it strands\n // the task.\n const steerThresholdMs = ctx.behavior?.shellLongTimeoutMs\n if (\n typeof steerThresholdMs === 'number' && Number.isFinite(steerThresholdMs) && steerThresholdMs > 0\n && typeof timeout === 'number' && Number.isFinite(timeout) && timeout > steerThresholdMs\n && allowBackground\n && typeof ctx.behavior?.tasksDir === 'string' && ctx.behavior.tasksDir.length > 0\n && ctx.execution.execBackground\n ) {\n throw new ToolFailure(`shell error: this blocking call requested a ${timeout}ms timeout, above the agent's ${steerThresholdMs}ms foreground ceiling. Re-issue with \\`run_in_background: true\\` (drop \\`timeout\\`): you'll get a task_id + output log immediately, and a <task-notification> when it finishes. If your very next step depends on the result, follow up with \\`wait_task({ task_id })\\` instead of polling.`)\n }\n\n // `ExecutionContext.exec` accepts a timeout in seconds; the tool surface\n // takes it in milliseconds so the value lines up with the rest of zidane's\n // ms-based timing. Round up so a 500ms request doesn't collapse to 0.\n //\n // `signal` is what makes `agent.cancelTool(callId)` actually reach\n // the underlying OS process. The loop hands us a unioned signal\n // (`AbortSignal.any([ctx.signal_run, perCallAbort.signal])`) via\n // `ctx.signal`; forwarding it into `exec` lets `child_process.exec`\n // send SIGTERM the moment any of the three layers (run abort,\n // per-call cancel, sibling-cascade) aborts. Without this, a\n // `sleep 60` survived its own cancellation message — orphaned\n // process, observable via `ps` after the run had supposedly\n // finished.\n const execOpts: ExecOptions = { signal: ctx.signal }\n if (typeof timeout === 'number' && Number.isFinite(timeout) && timeout > 0)\n execOpts.timeout = Math.max(1, Math.ceil(timeout / 1000))\n // Someone shows this call's live output (a codemode script streaming its progress).\n const reportProgress = ctx.reportProgress\n if (reportProgress)\n execOpts.onOutput = (stream, text) => reportProgress({ stream, text })\n\n const wantMetadata = metadata !== false\n const startedAt = Date.now()\n // Colors and cursor codes mean nothing to the model and cost tokens: it reads what a terminal would show.\n // The live output (`reportProgress`) keeps them for the UI.\n const raw = await ctx.execution.exec(ctx.handle, cmd, execOpts)\n const result = { ...raw, stdout: stripAnsi(raw.stdout), stderr: stripAnsi(raw.stderr) }\n const durationMs = Date.now() - startedAt\n\n const cap = normalizeCap(maxOutputBytes)\n const semantic = interpretShellResult(cmd, result.exitCode)\n ctx.reportStructured?.(shellStructuredResult(cmd, result, durationMs))\n\n // True success (exit 0): stdout body, cut by `truncateOutput`. With metadata,\n // surface non-empty stderr in a separate section (warnings, deprecation\n // notices) and append an `(exit 0, Nms)` footer.\n if (result.exitCode === 0) {\n const stdoutBody = result.stdout || '(no output)'\n const stdoutShown = truncateOutput(cmd, stdoutBody, cap)\n // Count plain file reads (`cat`, `sed -n`, …) toward read-state so the\n // read-before-edit gate accepts files inspected through shell (on unless\n // `trackShellReads: false`; no work without the gate).\n // A truncated output means the model saw only part of it: register nothing.\n if (ctx.behavior?.requireReadBeforeEdit === true && ctx.behavior.trackShellReads !== false && stdoutShown === stdoutBody)\n await registerShellReads(cmd, ctx)\n if (!wantMetadata)\n return stdoutShown\n const stderrTrimmed = result.stderr.trim()\n const stderrSection = stderrTrimmed\n ? `\\n[stderr]\\n${tailTruncate(stderrTrimmed, Math.min(cap, 2048))}`\n : ''\n return `${stdoutShown}${stderrSection}${absoluteCdNote(cmd, ctx.handle.cwd)}\\n(exit 0, ${durationMs}ms)`\n }\n\n // Per-command semantic override: non-zero exit codes that are NOT errors\n // (grep no-match, diff differ, find partial, test false). Don't surface\n // `Exit code N` — that misleads the model into retrying. Append a short\n // footer with the semantic interpretation so the model sees the why.\n if (!semantic.isError) {\n const body = (result.stdout || result.stderr || '').trim()\n const shown = truncateOutput(cmd, body, cap)\n const semanticFooter = semantic.message ? `\\n(${semantic.message})` : ''\n const timingFooter = wantMetadata ? `\\n(exit ${result.exitCode}, ${durationMs}ms)` : ''\n const head = shown.length > 0 ? shown : (semantic.message ?? '(no output)')\n return `${head}${semanticFooter}${timingFooter}`\n }\n\n // Real failure → keep the `Exit code N` line outside the truncation budget.\n // Truncating the joined body otherwise drops the exit-code prefix (it sits at\n // the head) the moment stdout overflows, leaving the model unable to tell\n // success from failure on large-output commands.\n const combined = `${result.stdout}\\n${result.stderr}`.trim()\n const header = wantMetadata\n ? `Exit code ${result.exitCode} (${durationMs}ms)`\n : `Exit code ${result.exitCode}`\n return `${header}\\n${tailTruncate(combined, cap)}`\n },\n }\n}\n\n/**\n * Detect a `cd` whose absolute target is the workspace root itself or a\n * path under it. Every shell call already starts at the root, so the\n * absolute prefix is pure token noise — and once one absolute `cd`\n * appears in the transcript, models tend to keep imitating it. Returns\n * the relative form to suggest, `''` when the `cd` is a no-op (target\n * === root), or `null` when no redundant `cd` is present. Targets\n * OUTSIDE the workspace are legitimate and never flagged.\n */\nexport function redundantAbsoluteCd(command: string, cwd: string | undefined): string | null {\n if (!cwd || !cwd.startsWith('/') || cwd === '/')\n return null\n const root = cwd.replace(/\\/+$/, '')\n // `cd <target>` at the start of the command or after a separator\n // (`&&`, `||`, `;`). Quoted targets may contain spaces; bare targets\n // stop at whitespace/separators.\n const re = /(?:^|&&|\\|\\||;)\\s*cd\\s+(?:'(\\/[^']*)'|\"(\\/[^\"]*)\"|(\\/[^\\s'\";|&]*))/g\n for (const m of command.matchAll(re)) {\n const target = (m[1] ?? m[2] ?? m[3]).replace(/\\/+$/, '')\n if (target === root)\n return ''\n if (target.startsWith(`${root}/`))\n return target.slice(root.length + 1)\n }\n return null\n}\n\n/**\n * One-line steer appended to a successful call's metadata footer when\n * {@link redundantAbsoluteCd} fires. Deliberately gentle and\n * self-extinguishing: it only ever appears when the model actually\n * emits a redundant absolute `cd`, and disappears as soon as it stops.\n */\nfunction absoluteCdNote(command: string, cwd: string | undefined): string {\n const rel = redundantAbsoluteCd(command, cwd)\n if (rel === null)\n return ''\n return rel === ''\n ? '\\n(note: every call already runs at the workspace root; this `cd` is redundant)'\n : `\\n(note: every call already runs at the workspace root; \\`cd ${rel}\\` suffices)`\n}\n\n/**\n * Default `shell` tool with background mode enabled.\n *\n * Most hosts use this directly via `basicTools`. When the agent's\n * `behavior.tasksDir` is unset OR `behavior.disableBackgroundTasks:\n * true` is set, `createAgent` auto-rewrites this identity to a\n * `createShellTool({ allowBackground: false })` variant so the model\n * never sees a flag it can't use. Hosts who want to bypass that\n * auto-rewrite can register a `createShellTool({ allowBackground })`\n * directly — the rewrite only fires on identity-equal references to\n * this constant.\n */\nexport const shell: ToolDef = createShellTool({ allowBackground: true })\n\n/**\n * Background-mode entry point for the `shell` tool. Settles fast,\n * registers an `onExit` callback that fires `background:exit` on the\n * agent's hook bus, and returns a structured one-liner to the model.\n *\n * Reachable only via the `allowBackground: true` variant; the\n * `allowBackground: false` variant short-circuits before this is\n * called and `createAgent` auto-rewrites the built-in to the\n * `false` variant when `behavior.tasksDir` is unset or\n * `behavior.disableBackgroundTasks: true` is set. The runtime checks\n * below are defense-in-depth for hosts who skip the auto-rewrite\n * (custom shell tool, run-level tools override, etc.):\n *\n * - `behavior.tasksDir` unset → host opted into the schema but\n * forgot to wire the log dir. Clean error, model can fall back to\n * foreground.\n * - `ctx.execution.execBackground` undefined → the context doesn't\n * support it (some remote sandboxes).\n * - `mkdir` on the output dir fails → the underlying filesystem\n * can't accommodate. Surface the error verbatim.\n */\nasync function runBackground(command: string, ctx: ToolContext): Promise<string> {\n const tasksDir = ctx.behavior?.tasksDir\n if (typeof tasksDir !== 'string' || tasksDir.length === 0) {\n throw new ToolFailure('shell error: background mode requires `behavior.tasksDir` to be set on the agent. The host has not opted into background tasks: either fall back to foreground (drop `run_in_background`) or ask the user to enable it.')\n }\n if (!ctx.execution.execBackground) {\n throw new ToolFailure(`shell error: the active execution context (${ctx.execution.type}) does not support background tasks. Fall back to foreground (drop \\`run_in_background\\`).`)\n }\n\n try {\n const outputCap = ctx.behavior?.backgroundOutputCap\n const stallWatchdogMs = ctx.behavior?.backgroundStallWatchdogMs\n const handle = await ctx.execution.execBackground(ctx.handle, command, {\n outputDir: tasksDir,\n onExit: (info) => {\n // Fire-and-forget. `callHook` returns a Promise (it may run\n // async listeners); we don't await — the agent's listener is\n // sync map.set, and the lifecycle is \"task already exited;\n // notify whoever cares\". Surface unhandled rejections under\n // ZIDANE_DEBUG only.\n Promise.resolve(ctx.hooks.callHook('background:exit', info))\n .catch((err: unknown) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/shell] background:exit hook rejected: ${err instanceof Error ? err.message : String(err)}\\n`)\n })\n },\n ...(typeof outputCap === 'number' && outputCap > 0 ? { maxOutputBytes: outputCap } : {}),\n ...(typeof stallWatchdogMs === 'number' && stallWatchdogMs > 0\n ? {\n stallTimeoutMs: stallWatchdogMs,\n onStall: (info: TaskStallInfo) => {\n // Same fire-and-forget contract as onExit above.\n Promise.resolve(ctx.hooks.callHook('background:stall', info))\n .catch((err: unknown) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/shell] background:stall hook rejected: ${err instanceof Error ? err.message : String(err)}\\n`)\n })\n },\n }\n : {}),\n })\n\n // Fire `background:start` AFTER the handle is returned so listeners\n // see a usable id + pid + path. Observational only — no caller\n // depends on this hook for behavior, so we don't await it on the\n // critical path.\n Promise.resolve(ctx.hooks.callHook('background:start', {\n taskId: handle.taskId,\n pid: handle.pid,\n command,\n cwd: ctx.handle.cwd,\n outputPath: handle.outputPath,\n startedAt: Date.now(),\n })).catch((err: unknown) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/shell] background:start hook rejected: ${err instanceof Error ? err.message : String(err)}\\n`)\n })\n\n const cmdPreview = previewLine(command, 60)\n // Depth-aware wake-up instruction. Subagents (depth > 0) get a\n // run-once `agent.run()` so there's no \"next turn\" for them to\n // observe the notification on; the notification ends up on the\n // PARENT's next user-turn after `spawn-child.ts`'s `reassignBackgroundTasks`\n // transfers ownership at child-destroy time. Telling a subagent to\n // \"wait for your next turn\" misleads it into polling, which blocks\n // the parent's spawn call until maxTurns hits.\n const inSubagent = (ctx.depth ?? 0) > 0\n const wakeupHint = inSubagent\n ? 'You are inside a `spawn`\\'d subagent: you have NO next user-turn to receive the notification on. Return a brief summary INCLUDING this task_id and end your turn now. Ownership of the task transfers to the parent agent when your run completes; the parent will see the `<task-notification>` on its next user-turn.'\n : 'The task is running in the background. You\\'ll receive a <task-notification> on your NEXT user-turn with the final status. End your current turn now; do NOT poll the output file in a loop, the notification IS the wake-up. To inspect progress, call `read_file({ path: <output> })` once. To terminate, use `shell_kill({ task_id })`.'\n // For scripts (codemode): the id to hand `wait_task` / `shell_kill`, not a sentence to parse.\n ctx.reportStructured?.({ task_id: handle.taskId, output_path: handle.outputPath, pid: handle.pid })\n return [\n `Started ${handle.taskId} (pid ${handle.pid}).`,\n ` command: ${cmdPreview}`,\n ` output: ${handle.outputPath}`,\n '',\n wakeupHint,\n ].join('\\n')\n }\n catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n throw new ToolFailure(`shell error: failed to start background task: ${msg}`)\n }\n}\n\nfunction normalizeCap(value: unknown): number {\n if (typeof value !== 'number' || !Number.isFinite(value))\n return DEFAULT_MAX_OUTPUT_BYTES\n if (value < 0)\n return DEFAULT_MAX_OUTPUT_BYTES\n return Math.floor(value)\n}\n","/**\n * `shell_kill` — terminate a running background task by id.\n *\n * Companion to the `shell` tool's `run_in_background: true` mode. The\n * model receives a `task_id` when it spawns a background task; this\n * tool routes a kill request through `ExecutionContext.killBackground`,\n * which SIGTERMs the whole process group (the foreground `exec`\n * implementation already documents the kill-tree rationale).\n *\n * The successful kill ALSO suppresses the would-be `<task-notification>`\n * on the next turn — the agent's `tool:after` listener (see\n * `src/agent-task-notifications.ts`) deletes the pending entry by\n * `task_id`. Without that, the model would get the kill result\n * inline AND a redundant notification on its next prompt.\n */\n\nimport type { ToolContext, ToolDef } from './types'\nimport { formatDuration, formatTaskStatus, previewLine } from '../chat/format'\nimport { ToolFailure } from './failure'\nimport { toolPrompts } from './prompts'\n\n/** The `shell_kill` tool. Sends SIGTERM to a background shell task by `task_id`. */\nexport const shellKill: ToolDef = {\n // Concurrency-safe — pure SIGTERM dispatch, no shared mutable state\n // beyond the per-context registry which is atomic.\n isConcurrencySafe: true,\n spec: {\n name: 'shell_kill',\n description: toolPrompts.shell_kill,\n inputSchema: {\n type: 'object',\n properties: {\n task_id: { type: 'string', description: 'The task id returned by a prior `shell({ run_in_background: true })` call.' },\n },\n required: ['task_id'],\n additionalProperties: false,\n },\n },\n async execute(input, ctx: ToolContext): Promise<string> {\n const taskId = input.task_id as string\n\n if (!ctx.execution.killBackground) {\n throw new ToolFailure(`shell_kill error: the active execution context (${ctx.execution.type}) does not support background tasks.`)\n }\n\n const info = await ctx.execution.killBackground(ctx.handle, taskId)\n if (!info) {\n return `shell_kill: no such task \"${taskId}\". It may have already exited and been cleaned up, or it was never started in this session.`\n }\n\n return [\n `Killed ${info.taskId}: ${formatTaskStatus(info)} after ${formatDuration(info.durationMs)}.`,\n ` command: ${previewLine(info.command, 60)}`,\n ` output: ${info.outputPath}`,\n ].join('\\n')\n },\n}\n","/**\n * `wait_task` — block until a background task exits (or a timeout elapses).\n *\n * Companion to `shell({ run_in_background: true })` for the cases where\n * the model genuinely needs the result before it can continue (a build\n * that gates a deploy, a migration that gates a test run) — without\n * burning turns polling the output file.\n *\n * The wait itself is delegated to `ExecutionContext.waitBackground`, an\n * injectable seam: the in-process context parks on its own `onExit`\n * machinery; durable hosts implement it as an awakeable park so a\n * crashed worker re-attaches to the same wait on replay.\n *\n * A successful wait ALSO suppresses the would-be `<task-notification>`\n * on the next turn — the agent's `tool:after` listener treats the\n * returned exit info as \"the model knows\". Timeouts do NOT suppress\n * (the task is still running; its eventual exit is still news).\n */\n\nimport type { ExecutionContext } from '../contexts/types'\nimport type { DurableToolDef, ToolContext, ToolDef } from './types'\nimport { formatDuration, formatTaskStatus, previewLine } from '../chat/format'\nimport { resolveDetachedTasksCapability } from '../contexts/types'\nimport { ToolFailure } from './failure'\nimport { toolPrompts } from './prompts'\n\n/**\n * Stable prefix on the timed-out result. The agent's notification\n * suppression keys on it: results carrying this prefix mean the task is\n * still running, so the pending `<task-notification>` must survive.\n */\nexport const WAIT_TASK_TIMED_OUT_PREFIX = 'wait_task: timed out'\n\nconst DEFAULT_TIMEOUT_MS = 120_000\nconst MAX_TIMEOUT_MS = 30 * 60_000\n\nconst waitTaskDef: DurableToolDef = {\n // NOT concurrency-safe: a parked wait can occupy a scheduler slot for\n // minutes; barrier semantics keep it from starving a sibling fleet.\n // Waiting has no effect of its own: a resumed durable run waits again.\n replay: 'safe',\n spec: {\n name: 'wait_task',\n description: toolPrompts.wait_task,\n inputSchema: {\n type: 'object',\n properties: {\n task_id: { type: 'string', description: 'The task id returned by a prior `shell({ run_in_background: true })` call.' },\n timeout_ms: { type: 'integer', description: `Max milliseconds to wait before giving up (task keeps running). Default: ${DEFAULT_TIMEOUT_MS}. Capped at ${MAX_TIMEOUT_MS}.` },\n },\n required: ['task_id'],\n additionalProperties: false,\n },\n },\n // A durable context's `waitBackground` parks on the runtime itself.\n durableBody: (execution: ExecutionContext) => (resolveDetachedTasksCapability(execution) === 'durable' ? 'composite' : undefined),\n async execute(input, ctx: ToolContext): Promise<string> {\n const taskId = input.task_id as string\n\n if (!ctx.execution.waitBackground) {\n throw new ToolFailure(`wait_task error: the active execution context (${ctx.execution.type}) does not support waiting on background tasks.`)\n }\n\n // Distinguish \"unknown task\" from \"still running\" up front —\n // `waitBackground` collapses both into `null` on its miss path.\n //\n // Skipped on DURABLE contexts. There `wait_task` is not a step of a\n // replaying run (its awakeable park can't nest in a recorded step, see\n // `durableBody` above), so its body re-runs in full on every replay.\n // This `listBackground` read is un-journaled, and branching on it gates\n // whether the *journaled* `waitBackground` (e.g. its register/probe/settle\n // entries) runs. If the runner's registry flips across attempts (a\n // restart mid-park drops the task), the branch flips and the journal\n // diverges (a journal mismatch). Durable hosts get the existence decision from\n // `waitBackground`'s own journaled probe instead (missing → `null` → the\n // timeout branch below). On non-durable contexts there's no journal to\n // diverge, so the more precise \"no such task\" message is kept.\n if (resolveDetachedTasksCapability(ctx.execution) !== 'durable' && ctx.execution.listBackground) {\n const entries = await ctx.execution.listBackground(ctx.handle)\n if (!entries.some(e => e.taskId === taskId)) {\n return `wait_task: no such task \"${taskId}\". It may have already exited and been cleaned up, or it was never started in this session.`\n }\n }\n\n const requested = typeof input.timeout_ms === 'number' && Number.isFinite(input.timeout_ms) && input.timeout_ms > 0\n ? input.timeout_ms\n : DEFAULT_TIMEOUT_MS\n const timeoutMs = Math.min(requested, MAX_TIMEOUT_MS)\n\n const info = await ctx.execution.waitBackground(ctx.handle, taskId, {\n timeoutMs,\n signal: ctx.signal,\n })\n\n if (!info) {\n return [\n `${WAIT_TASK_TIMED_OUT_PREFIX} after ${formatDuration(timeoutMs)}: ${taskId} is still running.`,\n 'You can wait again with a longer timeout, continue with other work (a `<task-notification>` arrives when it exits), or terminate it with `shell_kill`.',\n ].join('\\n')\n }\n\n return [\n `Task ${info.taskId} ${formatTaskStatus(info)} after ${formatDuration(info.durationMs)}.`,\n ` command: ${previewLine(info.command, 60)}`,\n ` output: ${info.outputPath}`,\n ].join('\\n')\n },\n}\n\n/**\n * The `wait_task` tool. Waits for a background shell task to exit and returns its final status. On timeout the task keeps running.\n */\nexport const waitTask: ToolDef = waitTaskDef\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Bt as checkSettingValue, Gt as settingDefault, Jt as DisposedError, Kt as settingScopes, Ut as isValueSetting, Wt as normalizeSettingValue, ht as toWireValue, mt as toWireSettings, pt as toWireActionStatus, qt as settingsForDefinition } from "./registry-B9INJwJR.js";
1
+ import { Jt as settingDefault, Kt as isValueSetting, Ut as checkSettingValue, Xt as settingsForDefinition, Yt as settingScopes, Zt as DisposedError, _t as toWireSettings, gt as toWireActionStatus, qt as normalizeSettingValue, vt as toWireValue } from "./registry-YUUqbYGr.js";
2
2
  import { Buffer } from "node:buffer";
3
3
  //#region src/extensions/settings/domain.ts
4
4
  /** A refused write. */
@@ -303,4 +303,4 @@ function jsonBytes(value) {
303
303
  //#endregion
304
304
  export { createSettingsDomain as a, SettingsWriteError as i, RpcErrorType as n, jsonBytes as r, RPC_MAX_PAYLOAD_BYTES as t };
305
305
 
306
- //# sourceMappingURL=wire-CLm2rMK0.js.map
306
+ //# sourceMappingURL=wire-Dxwxb7QQ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wire-CLm2rMK0.js","names":[],"sources":["../src/extensions/settings/domain.ts","../src/extensions/rpc/wire.ts"],"sourcesContent":["/**\n * The extension settings domain: `ctx.settings` for one extension, plus the\n * host-side surface Settings UIs use (write, actions, wire format).\n *\n * Values resolve session, then project, then user, then the declarative\n * config entry, then the default. A stored value that fails the setting's\n * checks is skipped, so the next layer answers.\n * Secret strings never sit in a settings layer: they live behind\n * {@link SettingsSecretPort} (the auth store) and take the user layer's place.\n */\n\nimport type { Disposable } from '../api/core'\nimport type { ActionSettingContext, ActionSettingStatus, ActionSettingStatusContext, SettingScope, SettingsDomain, SettingsSchema } from '../api/settings'\nimport type { ExtensionConfigActionStatus, ExtensionConfigValue } from '../config'\nimport type { ExtensionActionRunResult, ExtensionActionSummary } from '../config-actions'\nimport type { DomainDeps } from '../runtime/deps'\nimport type { StoredSettingValue, ValidateRunner, ValueSetting } from './validate'\nimport type { WireSettings } from './wire'\nimport { DisposedError } from '../api/core'\nimport { checkSettingValue, isValueSetting, normalizeSettingValue, settingDefault, settingScopes, settingsForDefinition } from './validate'\nimport { toWireActionStatus, toWireSettings, toWireValue } from './wire'\n\n/** A stored settings layer: a scope the user writes, or the declarative config entry. */\nexport type SettingsLayer = SettingScope | 'config'\n\n/** The auth store, as the settings domain sees it. Keys are per extension. */\nexport interface SettingsSecretPort {\n /** The stored secret. Synchronous: hosts read from a cache loaded before setup. */\n get: (extensionId: string, key: string) => string | undefined\n /** Stores the secret, or removes it when `value` is `undefined`. */\n set: (extensionId: string, key: string, value: string | undefined) => void | Promise<void>\n}\n\n/**\n * What a host provides to the settings domain. One port may serve every\n * extension: each call names the extension.\n */\nexport interface SettingsPort {\n /**\n * The values stored in one layer for the extension, by key. Synchronous:\n * hosts read from a cache. `sessionId` is set for the `session` layer.\n * Values are raw; the domain checks them.\n */\n read: (extensionId: string, layer: SettingsLayer, sessionId?: string) => Readonly<Record<string, unknown>> | undefined\n /** Stores a value in a user-writable scope, or clears it when `value` is `undefined`. */\n write: (extensionId: string, scope: SettingScope, key: string, value: StoredSettingValue | undefined, sessionId?: string) => void | Promise<void>\n /** Calls `listener` after any layer of the extension changed. Returns the unsubscribe. Optional: without it only writes made through the domain notify. */\n subscribe?: (extensionId: string, listener: () => void) => () => void\n /** Where secret strings live. */\n secrets: SettingsSecretPort\n}\n\n/** Which layer an effective value came from. `secret` is the auth store. */\nexport type SettingSource = SettingsLayer | 'secret' | 'default'\n\n/** A refused write. */\nexport class SettingsWriteError extends Error {\n /**\n * @param key - The setting.\n * @param reason - Why it was refused.\n */\n constructor(readonly key: string, readonly reason: string) {\n super(`setting \"${key}\": ${reason}`)\n this.name = 'SettingsWriteError'\n }\n}\n\n/** Options of a host-side write. */\nexport interface SettingsWriteOptions {\n /** The scope to write. Ignored for secrets, which always go to the auth store. */\n scope: SettingScope\n /** Required for the `session` scope. */\n sessionId?: string\n}\n\n/** The settings domain of one extension. */\nexport interface SettingsDomainInstance<S extends SettingsSchema = SettingsSchema> {\n /** `ctx.settings`: only `get`, `onChange` and `locked`. */\n readonly api: SettingsDomain<S>\n /** The cleaned schema. */\n readonly schema: SettingsSchema\n /** What `settingsForDefinition` dropped from the authored schema. */\n readonly issues: readonly string[]\n /** Where the effective value of `key` comes from, or `undefined` for an unknown or action key. */\n source: (key: string, opts?: { sessionId?: string }) => SettingSource | undefined\n /** Every effective value (secrets included), by key. Keys without a value are left out. */\n values: (opts?: { sessionId?: string }) => Record<string, StoredSettingValue>\n /** Checks a raw value for `key`. Returns an error message, or `undefined` when it would be accepted. */\n check: (key: string, value: unknown) => string | undefined\n /**\n * Writes a value (`undefined` clears it). Secret strings go to the auth\n * store. Throws {@link SettingsWriteError} for an unknown, action or\n * locked key, a scope the setting does not allow, or a value that fails\n * its checks. Listeners are notified when the effective value changed.\n */\n set: (key: string, value: unknown, opts: SettingsWriteOptions) => Promise<void>\n /**\n * What an action's `run` and `status` get besides the signal: `get` reads\n * this extension's effective values, `set` writes like a patch key (user\n * scope, else project; secrets to the auth store) and rejects with\n * {@link SettingsWriteError}. Settings-page actions get the same.\n */\n readonly actionAccess: Omit<ActionSettingContext, 'signal'>\n /** The action rows in wire shape. */\n actions: () => ExtensionActionSummary[]\n /** Runs an action's `status()` through the guard (3 s bound). `undefined`: none, failed, or empty. */\n actionStatus: (key: string) => Promise<ActionSettingStatus | undefined>\n /** Every action status in wire shape, keyed `extension:key`. */\n actionStatuses: () => Promise<Record<string, ExtensionConfigActionStatus>>\n /**\n * Runs an action. Its `patch` is checked per key: accepted values are\n * written (user scope, else project), the rest named in the message. A\n * throw, or a result with tone `error`, rejects with its message. The\n * result's `config` repeats the accepted non-secret values in wire shape\n * for UIs that persist it themselves.\n */\n runAction: (key: string, opts?: { signal?: AbortSignal }) => Promise<ExtensionActionRunResult>\n /** The schema, effective values and locks in the wire format the Settings UIs render. */\n wire: (opts?: { sessionId?: string }) => WireSettings\n}\n\n/** Bound on a passive `status()` probe, as `probeActionStatuses`. */\nconst ACTION_STATUS_TIMEOUT_MS = 3_000\n\nfunction sameValue(a: StoredSettingValue | undefined, b: StoredSettingValue | undefined): boolean {\n if (Array.isArray(a) && Array.isArray(b))\n return a.length === b.length && a.every((v, i) => v === b[i])\n return a === b\n}\n\n/**\n * `onChange` listeners of one extension: one port subscription while any\n * listener lives, each listener told only when its key's effective value\n * changed.\n */\nfunction createWatchers(deps: DomainDeps, port: SettingsPort, get: (key: string) => StoredSettingValue | undefined) {\n const { extensionId, owner, guard } = deps\n interface Watch { key: string, last: StoredSettingValue | undefined, listener: (value: StoredSettingValue | undefined) => void }\n const watches = new Set<Watch>()\n let unsubscribePort: (() => void) | undefined\n\n const recheck = (): void => {\n for (const watch of [...watches]) {\n if (!watches.has(watch))\n continue\n const next = get(watch.key)\n if (sameValue(next, watch.last))\n continue\n watch.last = next\n guard.callSync(`settings.onChange(${watch.key})`, () => watch.listener(next))\n }\n }\n\n const onChange = (key: string, listener: (value: StoredSettingValue | undefined) => void): Disposable => {\n if (owner.disposed)\n throw new DisposedError('settings.onChange')\n const watch: Watch = { key, last: get(key), listener }\n watches.add(watch)\n if (!unsubscribePort && port.subscribe)\n unsubscribePort = port.subscribe(extensionId, recheck)\n let cleanup: Disposable | undefined\n const dispose = (): void => {\n if (!watches.delete(watch))\n return\n cleanup?.dispose()\n if (watches.size === 0 && unsubscribePort) {\n unsubscribePort()\n unsubscribePort = undefined\n }\n }\n cleanup = owner.onCleanup(dispose)\n return { dispose }\n }\n\n return { onChange, recheck }\n}\n\n/**\n * Builds the settings domain of one extension.\n *\n * @param deps - The extension's runtime deps (id, owner, guard, logger).\n * @param port - The host's settings storage and auth store.\n * @param settings - The authored schema (`definition.settings`). Cleaned with `settingsForDefinition`.\n * @returns `api` for `ctx.settings`, and the host surface.\n */\nexport function createSettingsDomain<S extends SettingsSchema = SettingsSchema>(\n deps: DomainDeps,\n port: SettingsPort,\n settings?: S,\n): SettingsDomainInstance<S> {\n const { extensionId, owner, guard, logger } = deps\n const { schema, issues } = settingsForDefinition({ id: extensionId, settings })\n for (const issue of issues)\n logger.warn(`extension settings: ${issue}`, { extension: extensionId })\n\n const runValidate: ValidateRunner = (validate, value) => {\n const out = guard.callSync(`settings.validate`, () => validate(value), { fallback: 'invalid value' })\n return typeof out === 'string' && out.length > 0 ? out : undefined\n }\n\n const valueSetting = (key: string): ValueSetting | undefined => {\n const setting = Object.hasOwn(schema.items, key) ? schema.items[key] : undefined\n return setting && isValueSetting(setting) ? setting : undefined\n }\n\n const isSecret = (setting: ValueSetting): boolean => setting.type === 'string' && setting.secret === true\n\n /** The layer's value for `key` when present and valid. */\n const layerValue = (setting: ValueSetting, key: string, layer: SettingsLayer, sessionId?: string): StoredSettingValue | undefined => {\n const bag = port.read(extensionId, layer, layer === 'session' ? sessionId : undefined)\n if (!bag || !Object.hasOwn(bag, key))\n return undefined\n const raw = bag[key]\n if (raw === undefined || raw === null)\n return undefined\n const value = normalizeSettingValue(setting, raw)\n return checkSettingValue(setting, value, runValidate) === undefined ? value as StoredSettingValue : undefined\n }\n\n const secretValue = (setting: ValueSetting, key: string): StoredSettingValue | undefined => {\n const raw = port.secrets.get(extensionId, key)\n if (raw === undefined)\n return undefined\n return checkSettingValue(setting, raw, runValidate) === undefined ? raw : undefined\n }\n\n const resolve = (key: string, sessionId?: string): { value: StoredSettingValue | undefined, source: SettingSource } | undefined => {\n const setting = valueSetting(key)\n if (!setting)\n return undefined\n const layers: (SettingsLayer | 'secret')[] = isSecret(setting)\n ? ['secret', 'config']\n : sessionId !== undefined ? ['session', 'project', 'user', 'config'] : ['project', 'user', 'config']\n for (const layer of layers) {\n const value = layer === 'secret' ? secretValue(setting, key) : layerValue(setting, key, layer, sessionId)\n if (value !== undefined)\n return { value, source: layer }\n }\n return { value: settingDefault(setting), source: 'default' }\n }\n\n const get = (key: string, sessionId?: string): StoredSettingValue | undefined => resolve(key, sessionId)?.value\n\n const locked = (key: string): boolean => {\n const setting = valueSetting(key)\n return setting !== undefined && layerValue(setting, key, 'config') !== undefined\n }\n\n const { onChange, recheck } = createWatchers(deps, port, key => get(key))\n\n const api: SettingsDomain<S> = Object.freeze({\n get: ((key: string, opts?: { sessionId?: string }) => get(key, opts?.sessionId)) as SettingsDomain<S>['get'],\n onChange: onChange as unknown as SettingsDomain<S>['onChange'],\n locked: ((key: string) => locked(key)) as SettingsDomain<S>['locked'],\n })\n\n const check = (key: string, value: unknown): string | undefined => {\n const setting = valueSetting(key)\n if (!setting)\n return 'unknown setting'\n return checkSettingValue(setting, normalizeSettingValue(setting, value), runValidate)\n }\n\n const set = async (key: string, value: unknown, opts: SettingsWriteOptions): Promise<void> => {\n const setting = valueSetting(key)\n if (!setting)\n throw new SettingsWriteError(key, 'unknown setting')\n if (locked(key))\n throw new SettingsWriteError(key, 'locked by the config file')\n let normalized: StoredSettingValue | undefined\n if (value !== undefined) {\n const candidate = normalizeSettingValue(setting, value)\n const error = checkSettingValue(setting, candidate, runValidate)\n if (error !== undefined)\n throw new SettingsWriteError(key, error)\n normalized = candidate as StoredSettingValue\n }\n if (isSecret(setting)) {\n await port.secrets.set(extensionId, key, normalized as string | undefined)\n }\n else {\n if (!settingScopes(setting).includes(opts.scope))\n throw new SettingsWriteError(key, `cannot be set at the ${opts.scope} scope`)\n if (opts.scope === 'session' && !opts.sessionId)\n throw new SettingsWriteError(key, 'the session scope needs a sessionId')\n await port.write(extensionId, opts.scope, key, normalized, opts.scope === 'session' ? opts.sessionId : undefined)\n }\n recheck()\n }\n\n const values = (opts?: { sessionId?: string }): Record<string, StoredSettingValue> => {\n const out: Record<string, StoredSettingValue> = {}\n for (const key of Object.keys(schema.items)) {\n const value = get(key, opts?.sessionId)\n if (value !== undefined)\n out[key] = value\n }\n return out\n }\n\n /** Where an action's write of `key` goes: the user scope, else project; `undefined` when neither is allowed. Secrets ignore it. */\n const actionScope = (setting: ValueSetting): SettingScope | undefined =>\n isSecret(setting) ? 'user' : settingScopes(setting).find(s => s === 'user' || s === 'project')\n\n const actionAccess: Omit<ActionSettingContext, 'signal'> = Object.freeze({\n get: (key: string) => get(key),\n set: async (key: string, value: unknown) => {\n const setting = valueSetting(key)\n if (!setting)\n throw new SettingsWriteError(key, 'unknown setting')\n const scope = actionScope(setting)\n if (!scope)\n throw new SettingsWriteError(key, 'has neither a user nor a project scope')\n await set(key, value, { scope })\n },\n })\n const statusAccess: ActionSettingStatusContext = Object.freeze({ get: actionAccess.get })\n\n const actionSetting = (key: string) => {\n const setting = Object.hasOwn(schema.items, key) ? schema.items[key] : undefined\n return setting?.type === 'action' ? setting : undefined\n }\n\n const actionStatus = async (key: string): Promise<ActionSettingStatus | undefined> => {\n const status = actionSetting(key)?.status\n if (!status)\n return undefined\n const out = await guard.call(`settings.status(${key})`, () => status(statusAccess), { timeoutMs: ACTION_STATUS_TIMEOUT_MS, fallback: undefined })\n return out && typeof out.text === 'string' && out.text.length > 0 ? out : undefined\n }\n\n const actionStatuses = async (): Promise<Record<string, ExtensionConfigActionStatus>> => {\n const out: Record<string, ExtensionConfigActionStatus> = {}\n await Promise.all(Object.keys(schema.items).map(async (key) => {\n const status = await actionStatus(key)\n if (status)\n out[`${extensionId}:${key}`] = toWireActionStatus(status)\n }))\n return out\n }\n\n const runAction = async (key: string, opts: { signal?: AbortSignal } = {}): Promise<ExtensionActionRunResult> => {\n const action = actionSetting(key)\n if (!action)\n throw new Error(`\"${extensionId}\" has no action \"${key}\".`)\n if (owner.disposed)\n throw new DisposedError(`settings action \"${key}\"`)\n const signal = opts.signal ? AbortSignal.any([owner.signal, opts.signal]) : owner.signal\n let result\n try {\n result = (await action.run({ ...actionAccess, signal })) ?? undefined\n }\n catch (err) {\n logger.warn('extension settings action failed', { extension: extensionId, action: key, error: err instanceof Error ? err.message : String(err) })\n throw err\n }\n if (result?.tone === 'error')\n throw new Error(result.message || 'failed')\n const accepted: string[] = []\n const rejected: string[] = []\n const config: Record<string, ExtensionConfigValue> = {}\n for (const [patchKey, value] of Object.entries(result?.patch ?? {})) {\n const setting = valueSetting(patchKey)\n const scope = setting && actionScope(setting)\n if (!setting || !scope) {\n rejected.push(patchKey)\n continue\n }\n try {\n await set(patchKey, value, { scope })\n }\n catch (err) {\n if (!(err instanceof SettingsWriteError))\n throw err\n rejected.push(patchKey)\n continue\n }\n accepted.push(patchKey)\n if (!isSecret(setting))\n config[patchKey] = toWireValue(normalizeSettingValue(setting, value) as StoredSettingValue)\n }\n const parts = [result?.message || (accepted.length > 0 ? `updated ${accepted.join(', ')}` : 'done')]\n if (rejected.length > 0)\n parts.push(`(ignored invalid: ${rejected.join(', ')})`)\n return { message: parts.join(' '), ...(Object.keys(config).length > 0 ? { config } : {}) }\n }\n\n const wire = (opts?: { sessionId?: string }): WireSettings =>\n toWireSettings(extensionId, schema, values(opts), { locked: Object.keys(schema.items).filter(locked) })\n\n return {\n api,\n schema,\n issues,\n source: (key, opts) => resolve(key, opts?.sessionId)?.source,\n values,\n check,\n set,\n actionAccess,\n actions: () => wire().actions,\n actionStatus,\n actionStatuses,\n runAction,\n wire,\n }\n}\n","/**\n * The serializable shapes of RPC: what crosses the router, the IPC protocol\n * (`rpc.call` method, `rpc.event` signal) and HTTP (`POST /rpc/<contract>/<method>`).\n * Plain JSON only, so a host can forward them unchanged.\n */\n\nimport type { AccessScope } from '../api/core'\nimport { Buffer } from 'node:buffer'\n\n/** IPC method a protocol client calls to run an RPC method. Params {@link RpcCallParams}, result {@link RpcResponseEnvelope}. */\nexport const RPC_CALL_METHOD = 'rpc.call'\n\n/** IPC signal that carries an {@link RpcEventEnvelope} to protocol clients. */\nexport const RPC_EVENT_SIGNAL = 'rpc.event'\n\n/** Cap on the JSON size of a remote request input, response output or event data. */\nexport const RPC_MAX_PAYLOAD_BYTES = 1024 * 1024\n\n/** Reserved error types. Declared error names may not start with `rpc.`. */\nexport const RpcErrorType = {\n InvalidInput: 'rpc.invalid-input',\n InvalidOutput: 'rpc.invalid-output',\n Unavailable: 'rpc.unavailable',\n Aborted: 'rpc.aborted',\n Internal: 'rpc.internal',\n /** The caller's token scope is below the method's `scope`. */\n Forbidden: 'rpc.forbidden',\n} as const\n\n/**\n * Who made a call, as the router sees it: another extension, an\n * extension's own UI in a local renderer (named by its extension), or a\n * protocol client. What a call may reach is the host's `authorize` check\n * (the token scope of a remote connection), not the caller kind.\n */\nexport type RpcCaller\n = | { kind: 'extension', id: string }\n | { kind: 'ui', extensionId: string }\n | { kind: 'client', clientId: string }\n\n/** A call to one method. */\nexport interface RpcRequestEnvelope {\n /** Contract id. */\n contract: string\n /** Method name. */\n method: string\n /** JSON input. Absent for methods without input. */\n input?: unknown\n /** Project to route to. When several directories register the contract, this one wins; else the newest. */\n directory?: string\n}\n\n/** Params of the {@link RPC_CALL_METHOD} IPC method. */\nexport interface RpcCallParams extends RpcRequestEnvelope {\n /** Caller-chosen id, so a host can cancel the call (for example on `$/cancelRequest`). */\n callId?: string\n}\n\n/** A failed call. `type` is a declared error name or an {@link RpcErrorType}. */\nexport interface RpcWireError {\n /** Declared error name, or an {@link RpcErrorType}. */\n type: string\n /** Text for people. */\n message: string\n /** The declared error's data, validated against its schema. */\n data?: unknown\n}\n\n/** What the router recorded about a call. */\nexport interface RpcResponseMeta {\n /** Contract id of the request. */\n contract: string\n /** Method name of the request. */\n method: string\n /** The least token scope a protocol client needs for the method. `'chat'` when the method is unknown. */\n scope: AccessScope\n /** The extension that answered, when a registration was found. */\n extensionId?: string\n}\n\n/** The result of a call. */\nexport type RpcResult = { ok: true, output: unknown } | { ok: false, error: RpcWireError }\n\n/** A result with the router's metadata: the reply of {@link RPC_CALL_METHOD} and of HTTP. */\nexport type RpcResponseEnvelope = RpcResult & { meta: RpcResponseMeta }\n\n/** One emitted event, as subscribers and the {@link RPC_EVENT_SIGNAL} signal carry it. */\nexport interface RpcEventEnvelope {\n /** `rpc.<contract id>.<event>`. */\n type: string\n /** Contract id. */\n contract: string\n /** Event name within the contract. */\n event: string\n /** JSON object, validated against the event schema. */\n data: Readonly<Record<string, unknown>>\n /** The project the emitting extension runs in. */\n location: { directory: string }\n /** The emitting extension. */\n extensionId: string\n}\n\n/**\n * The HTTP path of a method.\n *\n * @param contract - Contract id.\n * @param method - Method name.\n * @returns `/rpc/<contract>/<method>`, each part URI-encoded.\n */\nexport function rpcHttpPath(contract: string, method: string): string {\n return `/rpc/${encodeURIComponent(contract)}/${encodeURIComponent(method)}`\n}\n\n/**\n * Reads contract and method from an HTTP path made by {@link rpcHttpPath}.\n *\n * @param path - The request path, without query.\n * @returns The parts, or `undefined` when the path is not an RPC path.\n */\nexport function parseRpcHttpPath(path: string): { contract: string, method: string } | undefined {\n const match = /^\\/rpc\\/([^/]+)\\/([^/]+)$/.exec(path)\n if (!match)\n return undefined\n try {\n return { contract: decodeURIComponent(match[1]!), method: decodeURIComponent(match[2]!) }\n }\n catch {\n return undefined\n }\n}\n\n/**\n * The HTTP status for a response. The body is always the envelope.\n *\n * @param response - The call's response.\n * @returns 200 ok, 400 invalid input, 404 unavailable, 499 aborted, 422 declared error, 500 otherwise.\n */\nexport function rpcHttpStatus(response: RpcResult): number {\n if (response.ok)\n return 200\n switch (response.error.type) {\n case RpcErrorType.InvalidInput: return 400\n case RpcErrorType.Forbidden: return 403\n case RpcErrorType.Unavailable: return 404\n case RpcErrorType.Aborted: return 499\n case RpcErrorType.InvalidOutput:\n case RpcErrorType.Internal: return 500\n default: return 422\n }\n}\n\n/**\n * Byte length of the JSON form of `value`, or `null` when it is not JSON.\n * `undefined` counts as 0 (an absent field).\n *\n * @param value - Value to measure.\n */\nexport function jsonBytes(value: unknown): number | null {\n if (value === undefined)\n return 0\n let text: string | undefined\n try {\n text = JSON.stringify(value)\n }\n catch {\n return null\n }\n return typeof text === 'string' ? Buffer.byteLength(text, 'utf8') : null\n}\n"],"mappings":";;;;AAwDA,IAAa,qBAAb,cAAwC,MAAM;CAKvB;CAAsB;;;;;CAA3C,YAAY,KAAsB,QAAyB;EACzD,MAAM,YAAY,IAAI,KAAK,QAAQ;EADhB,KAAA,MAAA;EAAsB,KAAA,SAAA;EAEzC,KAAK,OAAO;CACd;AACF;;AAyDA,MAAM,2BAA2B;AAEjC,SAAS,UAAU,GAAmC,GAA4C;CAChG,IAAI,MAAM,QAAQ,CAAC,KAAK,MAAM,QAAQ,CAAC,GACrC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,GAAG,MAAM,MAAM,EAAE,EAAE;CAC9D,OAAO,MAAM;AACf;;;;;;AAOA,SAAS,eAAe,MAAkB,MAAoB,KAAsD;CAClH,MAAM,EAAE,aAAa,OAAO,UAAU;CAEtC,MAAM,0BAAU,IAAI,IAAW;CAC/B,IAAI;CAEJ,MAAM,gBAAsB;EAC1B,KAAK,MAAM,SAAS,CAAC,GAAG,OAAO,GAAG;GAChC,IAAI,CAAC,QAAQ,IAAI,KAAK,GACpB;GACF,MAAM,OAAO,IAAI,MAAM,GAAG;GAC1B,IAAI,UAAU,MAAM,MAAM,IAAI,GAC5B;GACF,MAAM,OAAO;GACb,MAAM,SAAS,qBAAqB,MAAM,IAAI,UAAU,MAAM,SAAS,IAAI,CAAC;EAC9E;CACF;CAEA,MAAM,YAAY,KAAa,aAA0E;EACvG,IAAI,MAAM,UACR,MAAM,IAAI,cAAc,mBAAmB;EAC7C,MAAM,QAAe;GAAE;GAAK,MAAM,IAAI,GAAG;GAAG;EAAS;EACrD,QAAQ,IAAI,KAAK;EACjB,IAAI,CAAC,mBAAmB,KAAK,WAC3B,kBAAkB,KAAK,UAAU,aAAa,OAAO;EACvD,IAAI;EACJ,MAAM,gBAAsB;GAC1B,IAAI,CAAC,QAAQ,OAAO,KAAK,GACvB;GACF,SAAS,QAAQ;GACjB,IAAI,QAAQ,SAAS,KAAK,iBAAiB;IACzC,gBAAgB;IAChB,kBAAkB,KAAA;GACpB;EACF;EACA,UAAU,MAAM,UAAU,OAAO;EACjC,OAAO,EAAE,QAAQ;CACnB;CAEA,OAAO;EAAE;EAAU;CAAQ;AAC7B;;;;;;;;;AAUA,SAAgB,qBACd,MACA,MACA,UAC2B;CAC3B,MAAM,EAAE,aAAa,OAAO,OAAO,WAAW;CAC9C,MAAM,EAAE,QAAQ,WAAW,sBAAsB;EAAE,IAAI;EAAa;CAAS,CAAC;CAC9E,KAAK,MAAM,SAAS,QAClB,OAAO,KAAK,uBAAuB,SAAS,EAAE,WAAW,YAAY,CAAC;CAExE,MAAM,eAA+B,UAAU,UAAU;EACvD,MAAM,MAAM,MAAM,SAAS,2BAA2B,SAAS,KAAK,GAAG,EAAE,UAAU,gBAAgB,CAAC;EACpG,OAAO,OAAO,QAAQ,YAAY,IAAI,SAAS,IAAI,MAAM,KAAA;CAC3D;CAEA,MAAM,gBAAgB,QAA0C;EAC9D,MAAM,UAAU,OAAO,OAAO,OAAO,OAAO,GAAG,IAAI,OAAO,MAAM,OAAO,KAAA;EACvE,OAAO,WAAW,eAAe,OAAO,IAAI,UAAU,KAAA;CACxD;CAEA,MAAM,YAAY,YAAmC,QAAQ,SAAS,YAAY,QAAQ,WAAW;;CAGrG,MAAM,cAAc,SAAuB,KAAa,OAAsB,cAAuD;EACnI,MAAM,MAAM,KAAK,KAAK,aAAa,OAAO,UAAU,YAAY,YAAY,KAAA,CAAS;EACrF,IAAI,CAAC,OAAO,CAAC,OAAO,OAAO,KAAK,GAAG,GACjC,OAAO,KAAA;EACT,MAAM,MAAM,IAAI;EAChB,IAAI,QAAQ,KAAA,KAAa,QAAQ,MAC/B,OAAO,KAAA;EACT,MAAM,QAAQ,sBAAsB,SAAS,GAAG;EAChD,OAAO,kBAAkB,SAAS,OAAO,WAAW,MAAM,KAAA,IAAY,QAA8B,KAAA;CACtG;CAEA,MAAM,eAAe,SAAuB,QAAgD;EAC1F,MAAM,MAAM,KAAK,QAAQ,IAAI,aAAa,GAAG;EAC7C,IAAI,QAAQ,KAAA,GACV,OAAO,KAAA;EACT,OAAO,kBAAkB,SAAS,KAAK,WAAW,MAAM,KAAA,IAAY,MAAM,KAAA;CAC5E;CAEA,MAAM,WAAW,KAAa,cAAqG;EACjI,MAAM,UAAU,aAAa,GAAG;EAChC,IAAI,CAAC,SACH,OAAO,KAAA;EACT,MAAM,SAAuC,SAAS,OAAO,IACzD,CAAC,UAAU,QAAQ,IACnB,cAAc,KAAA,IAAY;GAAC;GAAW;GAAW;GAAQ;EAAQ,IAAI;GAAC;GAAW;GAAQ;EAAQ;EACrG,KAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,QAAQ,UAAU,WAAW,YAAY,SAAS,GAAG,IAAI,WAAW,SAAS,KAAK,OAAO,SAAS;GACxG,IAAI,UAAU,KAAA,GACZ,OAAO;IAAE;IAAO,QAAQ;GAAM;EAClC;EACA,OAAO;GAAE,OAAO,eAAe,OAAO;GAAG,QAAQ;EAAU;CAC7D;CAEA,MAAM,OAAO,KAAa,cAAuD,QAAQ,KAAK,SAAS,CAAC,EAAE;CAE1G,MAAM,UAAU,QAAyB;EACvC,MAAM,UAAU,aAAa,GAAG;EAChC,OAAO,YAAY,KAAA,KAAa,WAAW,SAAS,KAAK,QAAQ,MAAM,KAAA;CACzE;CAEA,MAAM,EAAE,UAAU,YAAY,eAAe,MAAM,OAAM,QAAO,IAAI,GAAG,CAAC;CAExE,MAAM,MAAyB,OAAO,OAAO;EAC3C,OAAO,KAAa,SAAkC,IAAI,KAAK,MAAM,SAAS;EACpE;EACV,UAAU,QAAgB,OAAO,GAAG;CACtC,CAAC;CAED,MAAM,SAAS,KAAa,UAAuC;EACjE,MAAM,UAAU,aAAa,GAAG;EAChC,IAAI,CAAC,SACH,OAAO;EACT,OAAO,kBAAkB,SAAS,sBAAsB,SAAS,KAAK,GAAG,WAAW;CACtF;CAEA,MAAM,MAAM,OAAO,KAAa,OAAgB,SAA8C;EAC5F,MAAM,UAAU,aAAa,GAAG;EAChC,IAAI,CAAC,SACH,MAAM,IAAI,mBAAmB,KAAK,iBAAiB;EACrD,IAAI,OAAO,GAAG,GACZ,MAAM,IAAI,mBAAmB,KAAK,2BAA2B;EAC/D,IAAI;EACJ,IAAI,UAAU,KAAA,GAAW;GACvB,MAAM,YAAY,sBAAsB,SAAS,KAAK;GACtD,MAAM,QAAQ,kBAAkB,SAAS,WAAW,WAAW;GAC/D,IAAI,UAAU,KAAA,GACZ,MAAM,IAAI,mBAAmB,KAAK,KAAK;GACzC,aAAa;EACf;EACA,IAAI,SAAS,OAAO,GAClB,MAAM,KAAK,QAAQ,IAAI,aAAa,KAAK,UAAgC;OAEtE;GACH,IAAI,CAAC,cAAc,OAAO,CAAC,CAAC,SAAS,KAAK,KAAK,GAC7C,MAAM,IAAI,mBAAmB,KAAK,wBAAwB,KAAK,MAAM,OAAO;GAC9E,IAAI,KAAK,UAAU,aAAa,CAAC,KAAK,WACpC,MAAM,IAAI,mBAAmB,KAAK,qCAAqC;GACzE,MAAM,KAAK,MAAM,aAAa,KAAK,OAAO,KAAK,YAAY,KAAK,UAAU,YAAY,KAAK,YAAY,KAAA,CAAS;EAClH;EACA,QAAQ;CACV;CAEA,MAAM,UAAU,SAAsE;EACpF,MAAM,MAA0C,CAAC;EACjD,KAAK,MAAM,OAAO,OAAO,KAAK,OAAO,KAAK,GAAG;GAC3C,MAAM,QAAQ,IAAI,KAAK,MAAM,SAAS;GACtC,IAAI,UAAU,KAAA,GACZ,IAAI,OAAO;EACf;EACA,OAAO;CACT;;CAGA,MAAM,eAAe,YACnB,SAAS,OAAO,IAAI,SAAS,cAAc,OAAO,CAAC,CAAC,MAAK,MAAK,MAAM,UAAU,MAAM,SAAS;CAE/F,MAAM,eAAqD,OAAO,OAAO;EACvE,MAAM,QAAgB,IAAI,GAAG;EAC7B,KAAK,OAAO,KAAa,UAAmB;GAC1C,MAAM,UAAU,aAAa,GAAG;GAChC,IAAI,CAAC,SACH,MAAM,IAAI,mBAAmB,KAAK,iBAAiB;GACrD,MAAM,QAAQ,YAAY,OAAO;GACjC,IAAI,CAAC,OACH,MAAM,IAAI,mBAAmB,KAAK,wCAAwC;GAC5E,MAAM,IAAI,KAAK,OAAO,EAAE,MAAM,CAAC;EACjC;CACF,CAAC;CACD,MAAM,eAA2C,OAAO,OAAO,EAAE,KAAK,aAAa,IAAI,CAAC;CAExF,MAAM,iBAAiB,QAAgB;EACrC,MAAM,UAAU,OAAO,OAAO,OAAO,OAAO,GAAG,IAAI,OAAO,MAAM,OAAO,KAAA;EACvE,OAAO,SAAS,SAAS,WAAW,UAAU,KAAA;CAChD;CAEA,MAAM,eAAe,OAAO,QAA0D;EACpF,MAAM,SAAS,cAAc,GAAG,CAAC,EAAE;EACnC,IAAI,CAAC,QACH,OAAO,KAAA;EACT,MAAM,MAAM,MAAM,MAAM,KAAK,mBAAmB,IAAI,UAAU,OAAO,YAAY,GAAG;GAAE,WAAW;GAA0B,UAAU,KAAA;EAAU,CAAC;EAChJ,OAAO,OAAO,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,SAAS,IAAI,MAAM,KAAA;CAC5E;CAEA,MAAM,iBAAiB,YAAkE;EACvF,MAAM,MAAmD,CAAC;EAC1D,MAAM,QAAQ,IAAI,OAAO,KAAK,OAAO,KAAK,CAAC,CAAC,IAAI,OAAO,QAAQ;GAC7D,MAAM,SAAS,MAAM,aAAa,GAAG;GACrC,IAAI,QACF,IAAI,GAAG,YAAY,GAAG,SAAS,mBAAmB,MAAM;EAC5D,CAAC,CAAC;EACF,OAAO;CACT;CAEA,MAAM,YAAY,OAAO,KAAa,OAAiC,CAAC,MAAyC;EAC/G,MAAM,SAAS,cAAc,GAAG;EAChC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,IAAI,YAAY,mBAAmB,IAAI,GAAG;EAC5D,IAAI,MAAM,UACR,MAAM,IAAI,cAAc,oBAAoB,IAAI,EAAE;EACpD,MAAM,SAAS,KAAK,SAAS,YAAY,IAAI,CAAC,MAAM,QAAQ,KAAK,MAAM,CAAC,IAAI,MAAM;EAClF,IAAI;EACJ,IAAI;GACF,SAAU,MAAM,OAAO,IAAI;IAAE,GAAG;IAAc;GAAO,CAAC,KAAM,KAAA;EAC9D,SACO,KAAK;GACV,OAAO,KAAK,oCAAoC;IAAE,WAAW;IAAa,QAAQ;IAAK,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAAE,CAAC;GAChJ,MAAM;EACR;EACA,IAAI,QAAQ,SAAS,SACnB,MAAM,IAAI,MAAM,OAAO,WAAW,QAAQ;EAC5C,MAAM,WAAqB,CAAC;EAC5B,MAAM,WAAqB,CAAC;EAC5B,MAAM,SAA+C,CAAC;EACtD,KAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,QAAQ,SAAS,CAAC,CAAC,GAAG;GACnE,MAAM,UAAU,aAAa,QAAQ;GACrC,MAAM,QAAQ,WAAW,YAAY,OAAO;GAC5C,IAAI,CAAC,WAAW,CAAC,OAAO;IACtB,SAAS,KAAK,QAAQ;IACtB;GACF;GACA,IAAI;IACF,MAAM,IAAI,UAAU,OAAO,EAAE,MAAM,CAAC;GACtC,SACO,KAAK;IACV,IAAI,EAAE,eAAe,qBACnB,MAAM;IACR,SAAS,KAAK,QAAQ;IACtB;GACF;GACA,SAAS,KAAK,QAAQ;GACtB,IAAI,CAAC,SAAS,OAAO,GACnB,OAAO,YAAY,YAAY,sBAAsB,SAAS,KAAK,CAAuB;EAC9F;EACA,MAAM,QAAQ,CAAC,QAAQ,YAAY,SAAS,SAAS,IAAI,WAAW,SAAS,KAAK,IAAI,MAAM,OAAO;EACnG,IAAI,SAAS,SAAS,GACpB,MAAM,KAAK,qBAAqB,SAAS,KAAK,IAAI,EAAE,EAAE;EACxD,OAAO;GAAE,SAAS,MAAM,KAAK,GAAG;GAAG,GAAI,OAAO,KAAK,MAAM,CAAC,CAAC,SAAS,IAAI,EAAE,OAAO,IAAI,CAAC;EAAG;CAC3F;CAEA,MAAM,QAAQ,SACZ,eAAe,aAAa,QAAQ,OAAO,IAAI,GAAG,EAAE,QAAQ,OAAO,KAAK,OAAO,KAAK,CAAC,CAAC,OAAO,MAAM,EAAE,CAAC;CAExG,OAAO;EACL;EACA;EACA;EACA,SAAS,KAAK,SAAS,QAAQ,KAAK,MAAM,SAAS,CAAC,EAAE;EACtD;EACA;EACA;EACA;EACA,eAAe,KAAK,CAAC,CAAC;EACtB;EACA;EACA;EACA;CACF;AACF;;;;ACrYA,MAAa,wBAAwB;;AAGrC,MAAa,eAAe;CAC1B,cAAc;CACd,eAAe;CACf,aAAa;CACb,SAAS;CACT,UAAU;;CAEV,WAAW;AACb;;;;;;;AAkIA,SAAgB,UAAU,OAA+B;CACvD,IAAI,UAAU,KAAA,GACZ,OAAO;CACT,IAAI;CACJ,IAAI;EACF,OAAO,KAAK,UAAU,KAAK;CAC7B,QACM;EACJ,OAAO;CACT;CACA,OAAO,OAAO,SAAS,WAAW,OAAO,WAAW,MAAM,MAAM,IAAI;AACtE"}
1
+ {"version":3,"file":"wire-Dxwxb7QQ.js","names":[],"sources":["../src/extensions/settings/domain.ts","../src/extensions/rpc/wire.ts"],"sourcesContent":["/**\n * The extension settings domain: `ctx.settings` for one extension, plus the\n * host-side surface Settings UIs use (write, actions, wire format).\n *\n * Values resolve session, then project, then user, then the declarative\n * config entry, then the default. A stored value that fails the setting's\n * checks is skipped, so the next layer answers.\n * Secret strings never sit in a settings layer: they live behind\n * {@link SettingsSecretPort} (the auth store) and take the user layer's place.\n */\n\nimport type { Disposable } from '../api/core'\nimport type { ActionSettingContext, ActionSettingStatus, ActionSettingStatusContext, SettingScope, SettingsDomain, SettingsSchema } from '../api/settings'\nimport type { ExtensionConfigActionStatus, ExtensionConfigValue } from '../config'\nimport type { ExtensionActionRunResult, ExtensionActionSummary } from '../config-actions'\nimport type { DomainDeps } from '../runtime/deps'\nimport type { StoredSettingValue, ValidateRunner, ValueSetting } from './validate'\nimport type { WireSettings } from './wire'\nimport { DisposedError } from '../api/core'\nimport { checkSettingValue, isValueSetting, normalizeSettingValue, settingDefault, settingScopes, settingsForDefinition } from './validate'\nimport { toWireActionStatus, toWireSettings, toWireValue } from './wire'\n\n/** A stored settings layer: a scope the user writes, or the declarative config entry. */\nexport type SettingsLayer = SettingScope | 'config'\n\n/** The auth store, as the settings domain sees it. Keys are per extension. */\nexport interface SettingsSecretPort {\n /** The stored secret. Synchronous: hosts read from a cache loaded before setup. */\n get: (extensionId: string, key: string) => string | undefined\n /** Stores the secret, or removes it when `value` is `undefined`. */\n set: (extensionId: string, key: string, value: string | undefined) => void | Promise<void>\n}\n\n/**\n * What a host provides to the settings domain. One port may serve every\n * extension: each call names the extension.\n */\nexport interface SettingsPort {\n /**\n * The values stored in one layer for the extension, by key. Synchronous:\n * hosts read from a cache. `sessionId` is set for the `session` layer.\n * Values are raw; the domain checks them.\n */\n read: (extensionId: string, layer: SettingsLayer, sessionId?: string) => Readonly<Record<string, unknown>> | undefined\n /** Stores a value in a user-writable scope, or clears it when `value` is `undefined`. */\n write: (extensionId: string, scope: SettingScope, key: string, value: StoredSettingValue | undefined, sessionId?: string) => void | Promise<void>\n /** Calls `listener` after any layer of the extension changed. Returns the unsubscribe. Optional: without it only writes made through the domain notify. */\n subscribe?: (extensionId: string, listener: () => void) => () => void\n /** Where secret strings live. */\n secrets: SettingsSecretPort\n}\n\n/** Which layer an effective value came from. `secret` is the auth store. */\nexport type SettingSource = SettingsLayer | 'secret' | 'default'\n\n/** A refused write. */\nexport class SettingsWriteError extends Error {\n /**\n * @param key - The setting.\n * @param reason - Why it was refused.\n */\n constructor(readonly key: string, readonly reason: string) {\n super(`setting \"${key}\": ${reason}`)\n this.name = 'SettingsWriteError'\n }\n}\n\n/** Options of a host-side write. */\nexport interface SettingsWriteOptions {\n /** The scope to write. Ignored for secrets, which always go to the auth store. */\n scope: SettingScope\n /** Required for the `session` scope. */\n sessionId?: string\n}\n\n/** The settings domain of one extension. */\nexport interface SettingsDomainInstance<S extends SettingsSchema = SettingsSchema> {\n /** `ctx.settings`: only `get`, `onChange` and `locked`. */\n readonly api: SettingsDomain<S>\n /** The cleaned schema. */\n readonly schema: SettingsSchema\n /** What `settingsForDefinition` dropped from the authored schema. */\n readonly issues: readonly string[]\n /** Where the effective value of `key` comes from, or `undefined` for an unknown or action key. */\n source: (key: string, opts?: { sessionId?: string }) => SettingSource | undefined\n /** Every effective value (secrets included), by key. Keys without a value are left out. */\n values: (opts?: { sessionId?: string }) => Record<string, StoredSettingValue>\n /** Checks a raw value for `key`. Returns an error message, or `undefined` when it would be accepted. */\n check: (key: string, value: unknown) => string | undefined\n /**\n * Writes a value (`undefined` clears it). Secret strings go to the auth\n * store. Throws {@link SettingsWriteError} for an unknown, action or\n * locked key, a scope the setting does not allow, or a value that fails\n * its checks. Listeners are notified when the effective value changed.\n */\n set: (key: string, value: unknown, opts: SettingsWriteOptions) => Promise<void>\n /**\n * What an action's `run` and `status` get besides the signal: `get` reads\n * this extension's effective values, `set` writes like a patch key (user\n * scope, else project; secrets to the auth store) and rejects with\n * {@link SettingsWriteError}. Settings-page actions get the same.\n */\n readonly actionAccess: Omit<ActionSettingContext, 'signal'>\n /** The action rows in wire shape. */\n actions: () => ExtensionActionSummary[]\n /** Runs an action's `status()` through the guard (3 s bound). `undefined`: none, failed, or empty. */\n actionStatus: (key: string) => Promise<ActionSettingStatus | undefined>\n /** Every action status in wire shape, keyed `extension:key`. */\n actionStatuses: () => Promise<Record<string, ExtensionConfigActionStatus>>\n /**\n * Runs an action. Its `patch` is checked per key: accepted values are\n * written (user scope, else project), the rest named in the message. A\n * throw, or a result with tone `error`, rejects with its message. The\n * result's `config` repeats the accepted non-secret values in wire shape\n * for UIs that persist it themselves.\n */\n runAction: (key: string, opts?: { signal?: AbortSignal }) => Promise<ExtensionActionRunResult>\n /** The schema, effective values and locks in the wire format the Settings UIs render. */\n wire: (opts?: { sessionId?: string }) => WireSettings\n}\n\n/** Bound on a passive `status()` probe, as `probeActionStatuses`. */\nconst ACTION_STATUS_TIMEOUT_MS = 3_000\n\nfunction sameValue(a: StoredSettingValue | undefined, b: StoredSettingValue | undefined): boolean {\n if (Array.isArray(a) && Array.isArray(b))\n return a.length === b.length && a.every((v, i) => v === b[i])\n return a === b\n}\n\n/**\n * `onChange` listeners of one extension: one port subscription while any\n * listener lives, each listener told only when its key's effective value\n * changed.\n */\nfunction createWatchers(deps: DomainDeps, port: SettingsPort, get: (key: string) => StoredSettingValue | undefined) {\n const { extensionId, owner, guard } = deps\n interface Watch { key: string, last: StoredSettingValue | undefined, listener: (value: StoredSettingValue | undefined) => void }\n const watches = new Set<Watch>()\n let unsubscribePort: (() => void) | undefined\n\n const recheck = (): void => {\n for (const watch of [...watches]) {\n if (!watches.has(watch))\n continue\n const next = get(watch.key)\n if (sameValue(next, watch.last))\n continue\n watch.last = next\n guard.callSync(`settings.onChange(${watch.key})`, () => watch.listener(next))\n }\n }\n\n const onChange = (key: string, listener: (value: StoredSettingValue | undefined) => void): Disposable => {\n if (owner.disposed)\n throw new DisposedError('settings.onChange')\n const watch: Watch = { key, last: get(key), listener }\n watches.add(watch)\n if (!unsubscribePort && port.subscribe)\n unsubscribePort = port.subscribe(extensionId, recheck)\n let cleanup: Disposable | undefined\n const dispose = (): void => {\n if (!watches.delete(watch))\n return\n cleanup?.dispose()\n if (watches.size === 0 && unsubscribePort) {\n unsubscribePort()\n unsubscribePort = undefined\n }\n }\n cleanup = owner.onCleanup(dispose)\n return { dispose }\n }\n\n return { onChange, recheck }\n}\n\n/**\n * Builds the settings domain of one extension.\n *\n * @param deps - The extension's runtime deps (id, owner, guard, logger).\n * @param port - The host's settings storage and auth store.\n * @param settings - The authored schema (`definition.settings`). Cleaned with `settingsForDefinition`.\n * @returns `api` for `ctx.settings`, and the host surface.\n */\nexport function createSettingsDomain<S extends SettingsSchema = SettingsSchema>(\n deps: DomainDeps,\n port: SettingsPort,\n settings?: S,\n): SettingsDomainInstance<S> {\n const { extensionId, owner, guard, logger } = deps\n const { schema, issues } = settingsForDefinition({ id: extensionId, settings })\n for (const issue of issues)\n logger.warn(`extension settings: ${issue}`, { extension: extensionId })\n\n const runValidate: ValidateRunner = (validate, value) => {\n const out = guard.callSync(`settings.validate`, () => validate(value), { fallback: 'invalid value' })\n return typeof out === 'string' && out.length > 0 ? out : undefined\n }\n\n const valueSetting = (key: string): ValueSetting | undefined => {\n const setting = Object.hasOwn(schema.items, key) ? schema.items[key] : undefined\n return setting && isValueSetting(setting) ? setting : undefined\n }\n\n const isSecret = (setting: ValueSetting): boolean => setting.type === 'string' && setting.secret === true\n\n /** The layer's value for `key` when present and valid. */\n const layerValue = (setting: ValueSetting, key: string, layer: SettingsLayer, sessionId?: string): StoredSettingValue | undefined => {\n const bag = port.read(extensionId, layer, layer === 'session' ? sessionId : undefined)\n if (!bag || !Object.hasOwn(bag, key))\n return undefined\n const raw = bag[key]\n if (raw === undefined || raw === null)\n return undefined\n const value = normalizeSettingValue(setting, raw)\n return checkSettingValue(setting, value, runValidate) === undefined ? value as StoredSettingValue : undefined\n }\n\n const secretValue = (setting: ValueSetting, key: string): StoredSettingValue | undefined => {\n const raw = port.secrets.get(extensionId, key)\n if (raw === undefined)\n return undefined\n return checkSettingValue(setting, raw, runValidate) === undefined ? raw : undefined\n }\n\n const resolve = (key: string, sessionId?: string): { value: StoredSettingValue | undefined, source: SettingSource } | undefined => {\n const setting = valueSetting(key)\n if (!setting)\n return undefined\n const layers: (SettingsLayer | 'secret')[] = isSecret(setting)\n ? ['secret', 'config']\n : sessionId !== undefined ? ['session', 'project', 'user', 'config'] : ['project', 'user', 'config']\n for (const layer of layers) {\n const value = layer === 'secret' ? secretValue(setting, key) : layerValue(setting, key, layer, sessionId)\n if (value !== undefined)\n return { value, source: layer }\n }\n return { value: settingDefault(setting), source: 'default' }\n }\n\n const get = (key: string, sessionId?: string): StoredSettingValue | undefined => resolve(key, sessionId)?.value\n\n const locked = (key: string): boolean => {\n const setting = valueSetting(key)\n return setting !== undefined && layerValue(setting, key, 'config') !== undefined\n }\n\n const { onChange, recheck } = createWatchers(deps, port, key => get(key))\n\n const api: SettingsDomain<S> = Object.freeze({\n get: ((key: string, opts?: { sessionId?: string }) => get(key, opts?.sessionId)) as SettingsDomain<S>['get'],\n onChange: onChange as unknown as SettingsDomain<S>['onChange'],\n locked: ((key: string) => locked(key)) as SettingsDomain<S>['locked'],\n })\n\n const check = (key: string, value: unknown): string | undefined => {\n const setting = valueSetting(key)\n if (!setting)\n return 'unknown setting'\n return checkSettingValue(setting, normalizeSettingValue(setting, value), runValidate)\n }\n\n const set = async (key: string, value: unknown, opts: SettingsWriteOptions): Promise<void> => {\n const setting = valueSetting(key)\n if (!setting)\n throw new SettingsWriteError(key, 'unknown setting')\n if (locked(key))\n throw new SettingsWriteError(key, 'locked by the config file')\n let normalized: StoredSettingValue | undefined\n if (value !== undefined) {\n const candidate = normalizeSettingValue(setting, value)\n const error = checkSettingValue(setting, candidate, runValidate)\n if (error !== undefined)\n throw new SettingsWriteError(key, error)\n normalized = candidate as StoredSettingValue\n }\n if (isSecret(setting)) {\n await port.secrets.set(extensionId, key, normalized as string | undefined)\n }\n else {\n if (!settingScopes(setting).includes(opts.scope))\n throw new SettingsWriteError(key, `cannot be set at the ${opts.scope} scope`)\n if (opts.scope === 'session' && !opts.sessionId)\n throw new SettingsWriteError(key, 'the session scope needs a sessionId')\n await port.write(extensionId, opts.scope, key, normalized, opts.scope === 'session' ? opts.sessionId : undefined)\n }\n recheck()\n }\n\n const values = (opts?: { sessionId?: string }): Record<string, StoredSettingValue> => {\n const out: Record<string, StoredSettingValue> = {}\n for (const key of Object.keys(schema.items)) {\n const value = get(key, opts?.sessionId)\n if (value !== undefined)\n out[key] = value\n }\n return out\n }\n\n /** Where an action's write of `key` goes: the user scope, else project; `undefined` when neither is allowed. Secrets ignore it. */\n const actionScope = (setting: ValueSetting): SettingScope | undefined =>\n isSecret(setting) ? 'user' : settingScopes(setting).find(s => s === 'user' || s === 'project')\n\n const actionAccess: Omit<ActionSettingContext, 'signal'> = Object.freeze({\n get: (key: string) => get(key),\n set: async (key: string, value: unknown) => {\n const setting = valueSetting(key)\n if (!setting)\n throw new SettingsWriteError(key, 'unknown setting')\n const scope = actionScope(setting)\n if (!scope)\n throw new SettingsWriteError(key, 'has neither a user nor a project scope')\n await set(key, value, { scope })\n },\n })\n const statusAccess: ActionSettingStatusContext = Object.freeze({ get: actionAccess.get })\n\n const actionSetting = (key: string) => {\n const setting = Object.hasOwn(schema.items, key) ? schema.items[key] : undefined\n return setting?.type === 'action' ? setting : undefined\n }\n\n const actionStatus = async (key: string): Promise<ActionSettingStatus | undefined> => {\n const status = actionSetting(key)?.status\n if (!status)\n return undefined\n const out = await guard.call(`settings.status(${key})`, () => status(statusAccess), { timeoutMs: ACTION_STATUS_TIMEOUT_MS, fallback: undefined })\n return out && typeof out.text === 'string' && out.text.length > 0 ? out : undefined\n }\n\n const actionStatuses = async (): Promise<Record<string, ExtensionConfigActionStatus>> => {\n const out: Record<string, ExtensionConfigActionStatus> = {}\n await Promise.all(Object.keys(schema.items).map(async (key) => {\n const status = await actionStatus(key)\n if (status)\n out[`${extensionId}:${key}`] = toWireActionStatus(status)\n }))\n return out\n }\n\n const runAction = async (key: string, opts: { signal?: AbortSignal } = {}): Promise<ExtensionActionRunResult> => {\n const action = actionSetting(key)\n if (!action)\n throw new Error(`\"${extensionId}\" has no action \"${key}\".`)\n if (owner.disposed)\n throw new DisposedError(`settings action \"${key}\"`)\n const signal = opts.signal ? AbortSignal.any([owner.signal, opts.signal]) : owner.signal\n let result\n try {\n result = (await action.run({ ...actionAccess, signal })) ?? undefined\n }\n catch (err) {\n logger.warn('extension settings action failed', { extension: extensionId, action: key, error: err instanceof Error ? err.message : String(err) })\n throw err\n }\n if (result?.tone === 'error')\n throw new Error(result.message || 'failed')\n const accepted: string[] = []\n const rejected: string[] = []\n const config: Record<string, ExtensionConfigValue> = {}\n for (const [patchKey, value] of Object.entries(result?.patch ?? {})) {\n const setting = valueSetting(patchKey)\n const scope = setting && actionScope(setting)\n if (!setting || !scope) {\n rejected.push(patchKey)\n continue\n }\n try {\n await set(patchKey, value, { scope })\n }\n catch (err) {\n if (!(err instanceof SettingsWriteError))\n throw err\n rejected.push(patchKey)\n continue\n }\n accepted.push(patchKey)\n if (!isSecret(setting))\n config[patchKey] = toWireValue(normalizeSettingValue(setting, value) as StoredSettingValue)\n }\n const parts = [result?.message || (accepted.length > 0 ? `updated ${accepted.join(', ')}` : 'done')]\n if (rejected.length > 0)\n parts.push(`(ignored invalid: ${rejected.join(', ')})`)\n return { message: parts.join(' '), ...(Object.keys(config).length > 0 ? { config } : {}) }\n }\n\n const wire = (opts?: { sessionId?: string }): WireSettings =>\n toWireSettings(extensionId, schema, values(opts), { locked: Object.keys(schema.items).filter(locked) })\n\n return {\n api,\n schema,\n issues,\n source: (key, opts) => resolve(key, opts?.sessionId)?.source,\n values,\n check,\n set,\n actionAccess,\n actions: () => wire().actions,\n actionStatus,\n actionStatuses,\n runAction,\n wire,\n }\n}\n","/**\n * The serializable shapes of RPC: what crosses the router, the IPC protocol\n * (`rpc.call` method, `rpc.event` signal) and HTTP (`POST /rpc/<contract>/<method>`).\n * Plain JSON only, so a host can forward them unchanged.\n */\n\nimport type { AccessScope } from '../api/core'\nimport { Buffer } from 'node:buffer'\n\n/** IPC method a protocol client calls to run an RPC method. Params {@link RpcCallParams}, result {@link RpcResponseEnvelope}. */\nexport const RPC_CALL_METHOD = 'rpc.call'\n\n/** IPC signal that carries an {@link RpcEventEnvelope} to protocol clients. */\nexport const RPC_EVENT_SIGNAL = 'rpc.event'\n\n/** Cap on the JSON size of a remote request input, response output or event data. */\nexport const RPC_MAX_PAYLOAD_BYTES = 1024 * 1024\n\n/** Reserved error types. Declared error names may not start with `rpc.`. */\nexport const RpcErrorType = {\n InvalidInput: 'rpc.invalid-input',\n InvalidOutput: 'rpc.invalid-output',\n Unavailable: 'rpc.unavailable',\n Aborted: 'rpc.aborted',\n Internal: 'rpc.internal',\n /** The caller's token scope is below the method's `scope`. */\n Forbidden: 'rpc.forbidden',\n} as const\n\n/**\n * Who made a call, as the router sees it: another extension, an\n * extension's own UI in a local renderer (named by its extension), or a\n * protocol client. What a call may reach is the host's `authorize` check\n * (the token scope of a remote connection), not the caller kind.\n */\nexport type RpcCaller\n = | { kind: 'extension', id: string }\n | { kind: 'ui', extensionId: string }\n | { kind: 'client', clientId: string }\n\n/** A call to one method. */\nexport interface RpcRequestEnvelope {\n /** Contract id. */\n contract: string\n /** Method name. */\n method: string\n /** JSON input. Absent for methods without input. */\n input?: unknown\n /** Project to route to. When several directories register the contract, this one wins; else the newest. */\n directory?: string\n}\n\n/** Params of the {@link RPC_CALL_METHOD} IPC method. */\nexport interface RpcCallParams extends RpcRequestEnvelope {\n /** Caller-chosen id, so a host can cancel the call (for example on `$/cancelRequest`). */\n callId?: string\n}\n\n/** A failed call. `type` is a declared error name or an {@link RpcErrorType}. */\nexport interface RpcWireError {\n /** Declared error name, or an {@link RpcErrorType}. */\n type: string\n /** Text for people. */\n message: string\n /** The declared error's data, validated against its schema. */\n data?: unknown\n}\n\n/** What the router recorded about a call. */\nexport interface RpcResponseMeta {\n /** Contract id of the request. */\n contract: string\n /** Method name of the request. */\n method: string\n /** The least token scope a protocol client needs for the method. `'chat'` when the method is unknown. */\n scope: AccessScope\n /** The extension that answered, when a registration was found. */\n extensionId?: string\n}\n\n/** The result of a call. */\nexport type RpcResult = { ok: true, output: unknown } | { ok: false, error: RpcWireError }\n\n/** A result with the router's metadata: the reply of {@link RPC_CALL_METHOD} and of HTTP. */\nexport type RpcResponseEnvelope = RpcResult & { meta: RpcResponseMeta }\n\n/** One emitted event, as subscribers and the {@link RPC_EVENT_SIGNAL} signal carry it. */\nexport interface RpcEventEnvelope {\n /** `rpc.<contract id>.<event>`. */\n type: string\n /** Contract id. */\n contract: string\n /** Event name within the contract. */\n event: string\n /** JSON object, validated against the event schema. */\n data: Readonly<Record<string, unknown>>\n /** The project the emitting extension runs in. */\n location: { directory: string }\n /** The emitting extension. */\n extensionId: string\n}\n\n/**\n * The HTTP path of a method.\n *\n * @param contract - Contract id.\n * @param method - Method name.\n * @returns `/rpc/<contract>/<method>`, each part URI-encoded.\n */\nexport function rpcHttpPath(contract: string, method: string): string {\n return `/rpc/${encodeURIComponent(contract)}/${encodeURIComponent(method)}`\n}\n\n/**\n * Reads contract and method from an HTTP path made by {@link rpcHttpPath}.\n *\n * @param path - The request path, without query.\n * @returns The parts, or `undefined` when the path is not an RPC path.\n */\nexport function parseRpcHttpPath(path: string): { contract: string, method: string } | undefined {\n const match = /^\\/rpc\\/([^/]+)\\/([^/]+)$/.exec(path)\n if (!match)\n return undefined\n try {\n return { contract: decodeURIComponent(match[1]!), method: decodeURIComponent(match[2]!) }\n }\n catch {\n return undefined\n }\n}\n\n/**\n * The HTTP status for a response. The body is always the envelope.\n *\n * @param response - The call's response.\n * @returns 200 ok, 400 invalid input, 404 unavailable, 499 aborted, 422 declared error, 500 otherwise.\n */\nexport function rpcHttpStatus(response: RpcResult): number {\n if (response.ok)\n return 200\n switch (response.error.type) {\n case RpcErrorType.InvalidInput: return 400\n case RpcErrorType.Forbidden: return 403\n case RpcErrorType.Unavailable: return 404\n case RpcErrorType.Aborted: return 499\n case RpcErrorType.InvalidOutput:\n case RpcErrorType.Internal: return 500\n default: return 422\n }\n}\n\n/**\n * Byte length of the JSON form of `value`, or `null` when it is not JSON.\n * `undefined` counts as 0 (an absent field).\n *\n * @param value - Value to measure.\n */\nexport function jsonBytes(value: unknown): number | null {\n if (value === undefined)\n return 0\n let text: string | undefined\n try {\n text = JSON.stringify(value)\n }\n catch {\n return null\n }\n return typeof text === 'string' ? Buffer.byteLength(text, 'utf8') : null\n}\n"],"mappings":"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"}
@@ -7,7 +7,7 @@ import { c as resumeChainRunIds } from "./session-BORxmqlM.js";
7
7
  import { i as styleReplacementForVia, n as resolveOldString, r as stripLineNumberPrefixes, t as describeVia } from "./edit-utils-BkGnT1Rv.js";
8
8
  import { a as readFileTargets, r as readFileBatchHeader } from "./format-bytes-LHrZVMIt.js";
9
9
  import { c as readStateKey, l as resolveReadStateMap, r as hashContent, s as noteStaleRejection, u as staleRefusalHint } from "./read-state-kgOvuIcp.js";
10
- import { _ as resolveAttachmentFromTurns, g as parseAttachmentHandle, l as readPersistedBlobOnHost, v as agentExtensionWiringOf, y as childExtensionOptions } from "./wait-task-BX4NcOOm.js";
10
+ import { _ as resolveAttachmentFromTurns, g as parseAttachmentHandle, l as readPersistedBlobOnHost, v as agentExtensionWiringOf, y as childExtensionOptions } from "./wait-task-BiI5UaZQ.js";
11
11
  import { i as isOutputExceededMessage } from "./output-cap-DajSaBRo.js";
12
12
  import { c as suspensionOf, r as RunSuspendedError } from "./errors-VVNmJD8V.js";
13
13
  import { n as looksBinary } from "./binary-detect-Dtj5NGns.js";
@@ -45,6 +45,7 @@ const BUBBLED_EVENTS = [
45
45
  "tool:after",
46
46
  "tool:error",
47
47
  "tool:cancelled",
48
+ "tool:progress",
48
49
  "validation:reject",
49
50
  "repeat-guard:exceeded",
50
51
  "background:start",
@@ -74,6 +75,7 @@ const CHILD_EVENT_NAME = {
74
75
  "validation:reject": "child:validation:reject",
75
76
  "repeat-guard:exceeded": "child:repeat-guard:exceeded",
76
77
  "tool:cancelled": "child:tool:cancelled",
78
+ "tool:progress": "child:tool:progress",
77
79
  "background:start": "child:background:start",
78
80
  "background:exit": "child:background:exit",
79
81
  "background:reassign": "child:background:reassign",
@@ -195,7 +197,7 @@ let agentModule;
195
197
  * `createSpawnTool` starts the load, so a child's first run doesn't wait on it.
196
198
  */
197
199
  function loadAgentModule() {
198
- agentModule ??= import("./agent-DJhpTS-B.js").then((n) => n.t);
200
+ agentModule ??= import("./agent-Dh_XZ7fj.js").then((n) => n.t);
199
201
  return agentModule;
200
202
  }
201
203
  /**
@@ -2039,4 +2041,4 @@ const writeFile = {
2039
2041
  //#endregion
2040
2042
  export { readFileAsBase64 as a, edit as c, recordArtifact as d, createSpawnTool as f, imageMediaTypeFor as i, wholeReadRefusal as l, readFile as n, multiEdit as o, withIsolatedSpawnTool as p, readFileLineNumbers as r, listFiles as s, writeFile as t, RECORD_ARTIFACT_TOOL as u };
2041
2043
 
2042
- //# sourceMappingURL=write-file-0E6TUJ9A.js.map
2044
+ //# sourceMappingURL=write-file-Dquu7MzB.js.map