zidane 9.1.1 → 9.1.3

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-CeCavNlg.js} +7 -7
  2. package/dist/{acp-Di9WvMDF.js.map → acp-CeCavNlg.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-BKpjlJ8a.js} +2 -2
  11. package/dist/{auth-store-port-DFgf22oo.js.map → auth-store-port-BKpjlJ8a.js.map} +1 -1
  12. package/dist/{auto-update-restart-BFB7Ek87.js → auto-update-restart-CQJtndMG.js} +277 -41
  13. package/dist/auto-update-restart-CQJtndMG.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-DeRHgYvl.js} +4 -4
  27. package/dist/{cli-shared-CabruH8Z.js.map → cli-shared-DeRHgYvl.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-Bqg-qNBM.js} +2 -2
  50. package/dist/{credentials-wwETW8rI.js.map → credentials-Bqg-qNBM.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-CX7nbMCn.js} +4 -4
  58. package/dist/{discovery-DycXFxdA.js.map → discovery-CX7nbMCn.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-CxBGgU94.js} +6 -6
  62. package/dist/{engine-VQ86XGdG.js.map → engine-CxBGgU94.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-j_LFRBwS.js} +4 -4
  68. package/dist/{executor-C7RQrkEq.js.map → executor-j_LFRBwS.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-ADlhBQ_1.js} +8 -8
  74. package/dist/{extensions-BCx4QuGB.js.map → extensions-ADlhBQ_1.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-B-Dhmzzf.js} +2 -2
  82. package/dist/{google-Crva32sk.js.map → google-B-Dhmzzf.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-wO_6GW0y.js → host-C61ntFBC.js} +276 -103
  89. package/dist/host-C61ntFBC.js.map +1 -0
  90. package/dist/{host-BHMs9jsN.js → host-DEoEzQal.js} +13 -4
  91. package/dist/host-DEoEzQal.js.map +1 -0
  92. package/dist/{host-scoped-settings-CrbcqOkP.js → host-scoped-settings-WBYaCork.js} +2 -2
  93. package/dist/{host-scoped-settings-CrbcqOkP.js.map → host-scoped-settings-WBYaCork.js.map} +1 -1
  94. package/dist/{host-signals-Jsjd_-4g.js → host-signals-Cb2TlGtN.js} +5 -5
  95. package/dist/{host-signals-Jsjd_-4g.js.map → host-signals-Cb2TlGtN.js.map} +1 -1
  96. package/dist/{host-version-CNAr9pov.js → host-version-BIx4CuBM.js} +2 -2
  97. package/dist/{host-version-CNAr9pov.js.map → host-version-BIx4CuBM.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-DiH_P-wr.js} +4 -4
  115. package/dist/{ipc-BzWhIybr.js.map → ipc-DiH_P-wr.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-BbC_lOnn.js} +9 -9
  121. package/dist/{links-CJG_rFvf.js.map → links-BbC_lOnn.js.map} +1 -1
  122. package/dist/{loaded-entry-DTURJo_R.js → loaded-entry-C0vkCVNQ.js} +2 -2
  123. package/dist/{loaded-entry-DTURJo_R.js.map → loaded-entry-C0vkCVNQ.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-C3w8nO8f.js} +132 -31
  128. package/dist/memory-C3w8nO8f.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-DRAEpKOU.js} +3 -3
  137. package/dist/{path-display-COVV71Yu.js.map → path-display-DRAEpKOU.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-CpXV_uLE.js} +5 -5
  162. package/dist/providers-CpXV_uLE.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-CJHvmvaP.js} +2 -2
  168. package/dist/{registry-BKjeBnoy.js.map → registry-CJHvmvaP.js.map} +1 -1
  169. package/dist/{registry-B6Ww76iW.js → registry-CN6JlZKj.js} +2 -2
  170. package/dist/{registry-B6Ww76iW.js.map → registry-CN6JlZKj.js.map} +1 -1
  171. package/dist/{registry-B9INJwJR.js → registry-CnnKaY9s.js} +324 -39
  172. package/dist/registry-CnnKaY9s.js.map +1 -0
  173. package/dist/{remote-hosts-BMWoHCWO.js → remote-hosts-DoO9CJUQ.js} +4 -4
  174. package/dist/{remote-hosts-BMWoHCWO.js.map → remote-hosts-DoO9CJUQ.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-D_FpKFMw.js} +6 -6
  185. package/dist/{setting-BQBSyUq0.js.map → setting-D_FpKFMw.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-CW2UgHgb.js} +3 -3
  189. package/dist/{settings-keys-iI_Y-7MC.js.map → settings-keys-CW2UgHgb.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-XgDPIwQS.js} +3 -3
  203. package/dist/{system-freeze-m5o1sGIM.js.map → system-freeze-XgDPIwQS.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-szdW1Od9.js} +2 -2
  231. package/dist/{version-DqqqvHDP.js.map → version-szdW1Od9.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-C3l9jl9x.js} +2 -2
  235. package/dist/{wire-CLm2rMK0.js.map → wire-C3l9jl9x.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-CEHi0CiB.js} +4 -4
  239. package/dist/{ws-DfGGYQ4W.js.map → ws-CEHi0CiB.js.map} +1 -1
  240. package/dist/{ws-client-CFMbhsNq.js → ws-client-t8XNWxcq.js} +2 -2
  241. package/dist/{ws-client-CFMbhsNq.js.map → ws-client-t8XNWxcq.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
@@ -1,6 +1,6 @@
1
- import { t as createSyncEngine } from "./engine-VQ86XGdG.js";
2
- import { r as startWsSavedHosts } from "./ws-DfGGYQ4W.js";
3
- import { i as wsTransport, t as hostSignalHandlers } from "./host-signals-Jsjd_-4g.js";
1
+ import { t as createSyncEngine } from "./engine-CxBGgU94.js";
2
+ import { r as startWsSavedHosts } from "./ws-CEHi0CiB.js";
3
+ import { i as wsTransport, t as hostSignalHandlers } from "./host-signals-Cb2TlGtN.js";
4
4
  //#region src/tui/host/remote-hosts.ts
5
5
  /** The TUI's directory, as the shared saved-hosts sync sees it. */
6
6
  function savedHostsDirectory(directory) {
@@ -95,4 +95,4 @@ function startRemoteHosts(options, registry) {
95
95
  //#endregion
96
96
  export { startRemoteHosts };
97
97
 
98
- //# sourceMappingURL=remote-hosts-BMWoHCWO.js.map
98
+ //# sourceMappingURL=remote-hosts-DoO9CJUQ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"remote-hosts-BMWoHCWO.js","names":[],"sources":["../src/tui/host/remote-hosts.ts"],"sourcesContent":["/**\n * Saved servers in the window's host directory: loaded only when the\n * `remoteHosts` setting is on (`use-remote-hosts` imports this module\n * dynamically), so a window with it off never reads `hosts.json`, never\n * loads the WebSocket client and never dials anything.\n *\n * The registry ↔ directory sync and the connection loops are the shared\n * ones (`startWsSavedHosts`, `src/ipc/hosts`, the GUI's too); this module is\n * the TUI's glue: a directory entry per server carries a WebSocket\n * transport (the session controllers and session data dial through it),\n * and the server's presence and session changes feed the window.\n */\nimport type { HostEntry, HostRegistry } from '../../chat/hosts'\nimport type { SyncEngine, SyncEngineOptions } from '../../chat/sync/engine'\nimport type { SavedHostsController, SavedHostsDirectory } from '../../ipc/hosts'\nimport type { SessionPresence } from '../../ipc/index'\nimport type { HostDirectory } from './host-directory'\nimport { createSyncEngine } from '../../chat/sync/engine'\nimport { startWsSavedHosts } from '../../ipc/hosts'\nimport { wsTransport } from '../runtime/transport'\nimport { hostSignalHandlers } from './host-signals'\n\nexport interface RemoteHostsOptions {\n dataDir: string\n directory: HostDirectory\n onPresence?: (key: string, rows: readonly SessionPresence[]) => void\n /** A server (re)connected: its sessions can be listed. */\n onConnected?: (key: string) => void\n /** A server's sessions changed (another window created, renamed or deleted one). */\n onSessionsChanged?: (key: string) => void\n /** Settings sync to the saved servers (`src/chat/sync`): this computer's files. Absent: no sync. */\n sync?: Omit<SyncEngineOptions, 'dataDir'>\n}\n\nexport type RemoteHostsController = SavedHostsController & {\n /** Settings sync to each saved server (Settings → Hosts → a server → Sync). */\n sync?: SyncEngine | null\n}\n\n/** The TUI's directory, as the shared saved-hosts sync sees it. */\nfunction savedHostsDirectory(directory: HostDirectory): SavedHostsDirectory {\n return {\n saved: () => directory.servers().filter(host => !host.adHoc).map(host => ({ key: host.key, url: host.url ?? '' })),\n upsert: (entry: HostEntry, token) => {\n // Every dial through it (the connection loop, session data, controllers) checks it is still this server.\n const transport = wsTransport({ url: entry.url, expectHostId: entry.id, ...(token ? { token } : {}) })\n const known = directory.get(entry.id)\n if (known) {\n // In place: the entry (and the sessions routed to it) stays.\n directory.update(entry.id, { name: entry.name, url: entry.url, transport, client: null, status: 'connecting', error: undefined })\n return\n }\n directory.put({\n key: entry.id,\n kind: 'server',\n name: entry.name,\n url: entry.url,\n transport,\n client: null,\n status: 'connecting',\n ...(entry.serverName ? { serverName: entry.serverName } : {}),\n ...(entry.serverVersion ? { serverVersion: entry.serverVersion } : {}),\n })\n },\n update: (key, patch) => directory.update(key, patch),\n remove: key => directory.remove(key),\n }\n}\n\nexport function startRemoteHosts(options: RemoteHostsOptions, registry?: HostRegistry): RemoteHostsController {\n const { directory } = options\n /** `--host` already names this server: its saved entry would be a second connection to it. */\n const adHocUrl = directory.servers().find(host => host.adHoc)?.url\n const sync = options.sync ? createSyncEngine({ dataDir: options.dataDir, ...options.sync }) : null\n const handlers = hostSignalHandlers(options)\n const controller = startWsSavedHosts({\n dataDir: options.dataDir,\n ...(registry ? { registry } : {}),\n directory: savedHostsDirectory(directory),\n skip: entry => entry.url === adHocUrl,\n connect: (entry, _token, attempt) => {\n const host = directory.get(entry.id)\n if (!host)\n return Promise.reject(new Error(`${entry.name} is no longer in this window's hosts.`))\n return host.transport.connect({ appVersion: 'tui-hosts', passive: true, ...attempt })\n },\n onSignal: (key, signal) => {\n handlers.onSignal(key, signal)\n if (signal.kind === 'sync:changed')\n sync?.serverChanged(key)\n },\n onConnected: (key, client) => {\n handlers.onConnected(key, client)\n sync?.connected(key, client)\n },\n onDisconnected: (key) => {\n handlers.onDisconnected(key)\n sync?.disconnected(key)\n },\n })\n return {\n ...controller,\n // Removing a server keeps what it has; this computer stops syncing to it.\n remove: (id) => {\n const removed = controller.remove(id)\n if (removed)\n sync?.removed(id)\n return removed\n },\n stop: () => {\n sync?.stop()\n controller.stop()\n },\n sync,\n }\n}\n"],"mappings":";;;;;AAwCA,SAAS,oBAAoB,WAA+C;CAC1E,OAAO;EACL,aAAa,UAAU,QAAQ,CAAC,CAAC,QAAO,SAAQ,CAAC,KAAK,KAAK,CAAC,CAAC,KAAI,UAAS;GAAE,KAAK,KAAK;GAAK,KAAK,KAAK,OAAO;EAAG,EAAE;EACjH,SAAS,OAAkB,UAAU;GAEnC,MAAM,YAAY,YAAY;IAAE,KAAK,MAAM;IAAK,cAAc,MAAM;IAAI,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;GAAG,CAAC;GAErG,IADc,UAAU,IAAI,MAAM,EAC1B,GAAG;IAET,UAAU,OAAO,MAAM,IAAI;KAAE,MAAM,MAAM;KAAM,KAAK,MAAM;KAAK;KAAW,QAAQ;KAAM,QAAQ;KAAc,OAAO,KAAA;IAAU,CAAC;IAChI;GACF;GACA,UAAU,IAAI;IACZ,KAAK,MAAM;IACX,MAAM;IACN,MAAM,MAAM;IACZ,KAAK,MAAM;IACX;IACA,QAAQ;IACR,QAAQ;IACR,GAAI,MAAM,aAAa,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;IAC3D,GAAI,MAAM,gBAAgB,EAAE,eAAe,MAAM,cAAc,IAAI,CAAC;GACtE,CAAC;EACH;EACA,SAAS,KAAK,UAAU,UAAU,OAAO,KAAK,KAAK;EACnD,SAAQ,QAAO,UAAU,OAAO,GAAG;CACrC;AACF;AAEA,SAAgB,iBAAiB,SAA6B,UAAgD;CAC5G,MAAM,EAAE,cAAc;;CAEtB,MAAM,WAAW,UAAU,QAAQ,CAAC,CAAC,MAAK,SAAQ,KAAK,KAAK,CAAC,EAAE;CAC/D,MAAM,OAAO,QAAQ,OAAO,iBAAiB;EAAE,SAAS,QAAQ;EAAS,GAAG,QAAQ;CAAK,CAAC,IAAI;CAC9F,MAAM,WAAW,mBAAmB,OAAO;CAC3C,MAAM,aAAa,kBAAkB;EACnC,SAAS,QAAQ;EACjB,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EAC/B,WAAW,oBAAoB,SAAS;EACxC,OAAM,UAAS,MAAM,QAAQ;EAC7B,UAAU,OAAO,QAAQ,YAAY;GACnC,MAAM,OAAO,UAAU,IAAI,MAAM,EAAE;GACnC,IAAI,CAAC,MACH,OAAO,QAAQ,uBAAO,IAAI,MAAM,GAAG,MAAM,KAAK,sCAAsC,CAAC;GACvF,OAAO,KAAK,UAAU,QAAQ;IAAE,YAAY;IAAa,SAAS;IAAM,GAAG;GAAQ,CAAC;EACtF;EACA,WAAW,KAAK,WAAW;GACzB,SAAS,SAAS,KAAK,MAAM;GAC7B,IAAI,OAAO,SAAS,gBAClB,MAAM,cAAc,GAAG;EAC3B;EACA,cAAc,KAAK,WAAW;GAC5B,SAAS,YAAY,KAAK,MAAM;GAChC,MAAM,UAAU,KAAK,MAAM;EAC7B;EACA,iBAAiB,QAAQ;GACvB,SAAS,eAAe,GAAG;GAC3B,MAAM,aAAa,GAAG;EACxB;CACF,CAAC;CACD,OAAO;EACL,GAAG;EAEH,SAAS,OAAO;GACd,MAAM,UAAU,WAAW,OAAO,EAAE;GACpC,IAAI,SACF,MAAM,QAAQ,EAAE;GAClB,OAAO;EACT;EACA,YAAY;GACV,MAAM,KAAK;GACX,WAAW,KAAK;EAClB;EACA;CACF;AACF"}
1
+ {"version":3,"file":"remote-hosts-DoO9CJUQ.js","names":[],"sources":["../src/tui/host/remote-hosts.ts"],"sourcesContent":["/**\n * Saved servers in the window's host directory: loaded only when the\n * `remoteHosts` setting is on (`use-remote-hosts` imports this module\n * dynamically), so a window with it off never reads `hosts.json`, never\n * loads the WebSocket client and never dials anything.\n *\n * The registry ↔ directory sync and the connection loops are the shared\n * ones (`startWsSavedHosts`, `src/ipc/hosts`, the GUI's too); this module is\n * the TUI's glue: a directory entry per server carries a WebSocket\n * transport (the session controllers and session data dial through it),\n * and the server's presence and session changes feed the window.\n */\nimport type { HostEntry, HostRegistry } from '../../chat/hosts'\nimport type { SyncEngine, SyncEngineOptions } from '../../chat/sync/engine'\nimport type { SavedHostsController, SavedHostsDirectory } from '../../ipc/hosts'\nimport type { SessionPresence } from '../../ipc/index'\nimport type { HostDirectory } from './host-directory'\nimport { createSyncEngine } from '../../chat/sync/engine'\nimport { startWsSavedHosts } from '../../ipc/hosts'\nimport { wsTransport } from '../runtime/transport'\nimport { hostSignalHandlers } from './host-signals'\n\nexport interface RemoteHostsOptions {\n dataDir: string\n directory: HostDirectory\n onPresence?: (key: string, rows: readonly SessionPresence[]) => void\n /** A server (re)connected: its sessions can be listed. */\n onConnected?: (key: string) => void\n /** A server's sessions changed (another window created, renamed or deleted one). */\n onSessionsChanged?: (key: string) => void\n /** Settings sync to the saved servers (`src/chat/sync`): this computer's files. Absent: no sync. */\n sync?: Omit<SyncEngineOptions, 'dataDir'>\n}\n\nexport type RemoteHostsController = SavedHostsController & {\n /** Settings sync to each saved server (Settings → Hosts → a server → Sync). */\n sync?: SyncEngine | null\n}\n\n/** The TUI's directory, as the shared saved-hosts sync sees it. */\nfunction savedHostsDirectory(directory: HostDirectory): SavedHostsDirectory {\n return {\n saved: () => directory.servers().filter(host => !host.adHoc).map(host => ({ key: host.key, url: host.url ?? '' })),\n upsert: (entry: HostEntry, token) => {\n // Every dial through it (the connection loop, session data, controllers) checks it is still this server.\n const transport = wsTransport({ url: entry.url, expectHostId: entry.id, ...(token ? { token } : {}) })\n const known = directory.get(entry.id)\n if (known) {\n // In place: the entry (and the sessions routed to it) stays.\n directory.update(entry.id, { name: entry.name, url: entry.url, transport, client: null, status: 'connecting', error: undefined })\n return\n }\n directory.put({\n key: entry.id,\n kind: 'server',\n name: entry.name,\n url: entry.url,\n transport,\n client: null,\n status: 'connecting',\n ...(entry.serverName ? { serverName: entry.serverName } : {}),\n ...(entry.serverVersion ? { serverVersion: entry.serverVersion } : {}),\n })\n },\n update: (key, patch) => directory.update(key, patch),\n remove: key => directory.remove(key),\n }\n}\n\nexport function startRemoteHosts(options: RemoteHostsOptions, registry?: HostRegistry): RemoteHostsController {\n const { directory } = options\n /** `--host` already names this server: its saved entry would be a second connection to it. */\n const adHocUrl = directory.servers().find(host => host.adHoc)?.url\n const sync = options.sync ? createSyncEngine({ dataDir: options.dataDir, ...options.sync }) : null\n const handlers = hostSignalHandlers(options)\n const controller = startWsSavedHosts({\n dataDir: options.dataDir,\n ...(registry ? { registry } : {}),\n directory: savedHostsDirectory(directory),\n skip: entry => entry.url === adHocUrl,\n connect: (entry, _token, attempt) => {\n const host = directory.get(entry.id)\n if (!host)\n return Promise.reject(new Error(`${entry.name} is no longer in this window's hosts.`))\n return host.transport.connect({ appVersion: 'tui-hosts', passive: true, ...attempt })\n },\n onSignal: (key, signal) => {\n handlers.onSignal(key, signal)\n if (signal.kind === 'sync:changed')\n sync?.serverChanged(key)\n },\n onConnected: (key, client) => {\n handlers.onConnected(key, client)\n sync?.connected(key, client)\n },\n onDisconnected: (key) => {\n handlers.onDisconnected(key)\n sync?.disconnected(key)\n },\n })\n return {\n ...controller,\n // Removing a server keeps what it has; this computer stops syncing to it.\n remove: (id) => {\n const removed = controller.remove(id)\n if (removed)\n sync?.removed(id)\n return removed\n },\n stop: () => {\n sync?.stop()\n controller.stop()\n },\n sync,\n }\n}\n"],"mappings":";;;;;AAwCA,SAAS,oBAAoB,WAA+C;CAC1E,OAAO;EACL,aAAa,UAAU,QAAQ,CAAC,CAAC,QAAO,SAAQ,CAAC,KAAK,KAAK,CAAC,CAAC,KAAI,UAAS;GAAE,KAAK,KAAK;GAAK,KAAK,KAAK,OAAO;EAAG,EAAE;EACjH,SAAS,OAAkB,UAAU;GAEnC,MAAM,YAAY,YAAY;IAAE,KAAK,MAAM;IAAK,cAAc,MAAM;IAAI,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;GAAG,CAAC;GAErG,IADc,UAAU,IAAI,MAAM,EAC1B,GAAG;IAET,UAAU,OAAO,MAAM,IAAI;KAAE,MAAM,MAAM;KAAM,KAAK,MAAM;KAAK;KAAW,QAAQ;KAAM,QAAQ;KAAc,OAAO,KAAA;IAAU,CAAC;IAChI;GACF;GACA,UAAU,IAAI;IACZ,KAAK,MAAM;IACX,MAAM;IACN,MAAM,MAAM;IACZ,KAAK,MAAM;IACX;IACA,QAAQ;IACR,QAAQ;IACR,GAAI,MAAM,aAAa,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;IAC3D,GAAI,MAAM,gBAAgB,EAAE,eAAe,MAAM,cAAc,IAAI,CAAC;GACtE,CAAC;EACH;EACA,SAAS,KAAK,UAAU,UAAU,OAAO,KAAK,KAAK;EACnD,SAAQ,QAAO,UAAU,OAAO,GAAG;CACrC;AACF;AAEA,SAAgB,iBAAiB,SAA6B,UAAgD;CAC5G,MAAM,EAAE,cAAc;;CAEtB,MAAM,WAAW,UAAU,QAAQ,CAAC,CAAC,MAAK,SAAQ,KAAK,KAAK,CAAC,EAAE;CAC/D,MAAM,OAAO,QAAQ,OAAO,iBAAiB;EAAE,SAAS,QAAQ;EAAS,GAAG,QAAQ;CAAK,CAAC,IAAI;CAC9F,MAAM,WAAW,mBAAmB,OAAO;CAC3C,MAAM,aAAa,kBAAkB;EACnC,SAAS,QAAQ;EACjB,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EAC/B,WAAW,oBAAoB,SAAS;EACxC,OAAM,UAAS,MAAM,QAAQ;EAC7B,UAAU,OAAO,QAAQ,YAAY;GACnC,MAAM,OAAO,UAAU,IAAI,MAAM,EAAE;GACnC,IAAI,CAAC,MACH,OAAO,QAAQ,uBAAO,IAAI,MAAM,GAAG,MAAM,KAAK,sCAAsC,CAAC;GACvF,OAAO,KAAK,UAAU,QAAQ;IAAE,YAAY;IAAa,SAAS;IAAM,GAAG;GAAQ,CAAC;EACtF;EACA,WAAW,KAAK,WAAW;GACzB,SAAS,SAAS,KAAK,MAAM;GAC7B,IAAI,OAAO,SAAS,gBAClB,MAAM,cAAc,GAAG;EAC3B;EACA,cAAc,KAAK,WAAW;GAC5B,SAAS,YAAY,KAAK,MAAM;GAChC,MAAM,UAAU,KAAK,MAAM;EAC7B;EACA,iBAAiB,QAAQ;GACvB,SAAS,eAAe,GAAG;GAC3B,MAAM,aAAa,GAAG;EACxB;CACF,CAAC;CACD,OAAO;EACL,GAAG;EAEH,SAAS,OAAO;GACd,MAAM,UAAU,WAAW,OAAO,EAAE;GACpC,IAAI,SACF,MAAM,QAAQ,EAAE;GAClB,OAAO;EACT;EACA,YAAY;GACV,MAAM,KAAK;GACX,WAAW,KAAK;EAClB;EACA;CACF;AACF"}
@@ -230,6 +230,7 @@ function isVisible(event, settings) {
230
230
  case "run-summary": return settings.showRunReceipt;
231
231
  case "info": return settings.showCacheNotices || !isCacheNotice(event.notice);
232
232
  case "spawn-queued": return settings.transcriptDensity === "compact";
233
+ case "tool-progress": return false;
233
234
  default: return true;
234
235
  }
235
236
  }
@@ -543,6 +544,172 @@ function mayHaveStreamFailure(text) {
543
544
  return text.includes("[✗ Streaming failed") || text.includes("[⏹ Streaming was aborted");
544
545
  }
545
546
  //#endregion
547
+ //#region src/chat/shell-blocks.ts
548
+ /**
549
+ * Shell code blocks in a reply, run by the user (`Run here`, `Run in a
550
+ * terminal`): which fences run, what runs, and the saved last run of each
551
+ * block. A run never enters the conversation: the host keeps the last run of
552
+ * each block in the session's metadata ({@link BLOCK_RUNS_METADATA_KEY}).
553
+ *
554
+ * A one-line block runs as it is. A longer one becomes a temporary script on
555
+ * the host (`mktemp`, written through a here-document, removed after), run in
556
+ * the session's folder by the fence's shell. Run here closes the command's
557
+ * input, so a command that asks for some fails at once; in a terminal it can
558
+ * ask.
559
+ *
560
+ * Node-free (exported from `zidane/chat/pure`).
561
+ */
562
+ /** Fence languages that run. */
563
+ const SHELL_FENCE_LANGUAGES = /* @__PURE__ */ new Set([
564
+ "bash",
565
+ "sh",
566
+ "shell",
567
+ "zsh",
568
+ "console"
569
+ ]);
570
+ /** Longest block that runs, in characters. */
571
+ const SHELL_BLOCK_MAX_CHARS = 65536;
572
+ /** Output kept of a run (the end of it), in characters. */
573
+ const BLOCK_RUN_OUTPUT_CAP = 65536;
574
+ /** How long a Run here may take. */
575
+ const BLOCK_RUN_TIMEOUT_MS = 6e5;
576
+ /** Runs kept per session; the oldest go first. */
577
+ const BLOCK_RUNS_MAX = 50;
578
+ /** Session metadata key of the saved runs. */
579
+ const BLOCK_RUNS_METADATA_KEY = "blockRuns";
580
+ const PROMPT_LINE = /^\$ /;
581
+ /**
582
+ * Whether a fence of `language` runs.
583
+ *
584
+ * @param language - The fence's language, as written.
585
+ */
586
+ function isShellFence(language) {
587
+ return language !== void 0 && SHELL_FENCE_LANGUAGES.has(language.trim().toLowerCase());
588
+ }
589
+ function shellOf(language) {
590
+ const lang = language.trim().toLowerCase();
591
+ return lang === "zsh" ? "zsh" : lang === "sh" ? "sh" : "bash";
592
+ }
593
+ /**
594
+ * What runs for a block, or `null` when nothing does (another language, no
595
+ * command, too long). A block with `$ ` lines runs those lines only, without
596
+ * the prompt: the other lines are output.
597
+ *
598
+ * @param code - The block's text.
599
+ * @param language - The fence's language.
600
+ */
601
+ function shellBlockPlan(code, language) {
602
+ if (!isShellFence(language) || code.length > 65536) return null;
603
+ const lines = code.replace(/\r\n?/g, "\n").split("\n");
604
+ const script = (lines.some((line) => PROMPT_LINE.test(line)) ? lines.filter((line) => PROMPT_LINE.test(line)).map((line) => line.replace(PROMPT_LINE, "")) : lines).join("\n").trim();
605
+ if (script === "") return null;
606
+ const commands = script.split("\n").filter((line) => line.trim() !== "" && !line.trim().startsWith("#"));
607
+ if (commands.length === 0) return null;
608
+ return {
609
+ script,
610
+ shell: shellOf(language),
611
+ oneLine: commands.length === 1 && !commands[0].trimEnd().endsWith("\\")
612
+ };
613
+ }
614
+ /** `text` as one single-quoted shell word. */
615
+ function quote(text) {
616
+ return `'${text.replace(/'/g, `'\\''`)}'`;
617
+ }
618
+ /** A here-document delimiter the script never holds as a line. */
619
+ function delimiter(script) {
620
+ const lines = new Set(script.split("\n"));
621
+ let name = "ZIDANE_BLOCK";
622
+ for (let n = 1; lines.has(name); n++) name = `ZIDANE_BLOCK_${n}`;
623
+ return name;
624
+ }
625
+ /** The lines that write `script` to a new temporary file, its path in `$f`. */
626
+ function writeScript(script) {
627
+ const end = delimiter(script);
628
+ return `f=$(mktemp "\${TMPDIR:-/tmp}/zidane-block.XXXXXX") || exit 1\ncat > "$f" <<'${end}'\n${script}\n${end}\n`;
629
+ }
630
+ /**
631
+ * The command that runs a block in the session's folder, with no input, for Run here.
632
+ *
633
+ * @param plan - What runs ({@link shellBlockPlan}).
634
+ */
635
+ function blockRunCommand(plan) {
636
+ if (plan.oneLine) return `${plan.shell} -c ${quote(plan.script)} </dev/null`;
637
+ return `${writeScript(plan.script)}${plan.shell} "$f" </dev/null; code=$?; rm -f "$f"; exit $code`;
638
+ }
639
+ /**
640
+ * What is typed in a terminal to run a block there, ending with its Enter. The
641
+ * command keeps the terminal's input, so it can ask for some.
642
+ *
643
+ * @param plan - What runs ({@link shellBlockPlan}).
644
+ */
645
+ function blockTerminalInput(plan) {
646
+ if (plan.oneLine) return `${plan.script}\n`;
647
+ return `${writeScript(plan.script).replace(" || exit 1", "")}${plan.shell} "$f"; rm -f "$f"\n`;
648
+ }
649
+ /** FNV-1a of `text`, as 8 hex digits. */
650
+ function hash(text) {
651
+ let h = 2166136261;
652
+ for (let i = 0; i < text.length; i++) {
653
+ h ^= text.charCodeAt(i);
654
+ h = Math.imul(h, 16777619);
655
+ }
656
+ return (h >>> 0).toString(16).padStart(8, "0");
657
+ }
658
+ /**
659
+ * The key of a block's run: its reply and its code. An edited or regenerated
660
+ * reply is a new turn, so its blocks start without a run. Two identical
661
+ * blocks in one reply share their run.
662
+ *
663
+ * @param turnId - The reply the block is in.
664
+ * @param code - The block's text.
665
+ */
666
+ function blockRunKey(turnId, code) {
667
+ return `${turnId}:${hash(code)}`;
668
+ }
669
+ function isBlockRun(value) {
670
+ if (typeof value !== "object" || value === null) return false;
671
+ const run = value;
672
+ return typeof run.key === "string" && typeof run.turnId === "string" && typeof run.output === "string" && (run.exitCode === null || typeof run.exitCode === "number") && typeof run.durationMs === "number" && typeof run.finishedAt === "number";
673
+ }
674
+ /**
675
+ * The saved runs of a session, by key. What does not read as a run is left out.
676
+ *
677
+ * @param metadata - The session's metadata.
678
+ */
679
+ function readBlockRuns(metadata) {
680
+ const raw = metadata?.[BLOCK_RUNS_METADATA_KEY];
681
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return {};
682
+ const runs = {};
683
+ for (const [key, value] of Object.entries(raw)) if (isBlockRun(value) && value.key === key) runs[key] = value;
684
+ return runs;
685
+ }
686
+ /**
687
+ * The saved runs with `run` in, without runs whose reply is gone, at most
688
+ * {@link BLOCK_RUNS_MAX} (the latest kept).
689
+ *
690
+ * @param runs - The saved runs.
691
+ * @param run - The run to keep (it replaces the block's last one).
692
+ * @param turnIds - The session's turns: a run whose reply is not among them is dropped.
693
+ */
694
+ function withBlockRun(runs, run, turnIds) {
695
+ const kept = Object.values({
696
+ ...runs,
697
+ [run.key]: run
698
+ }).filter((entry) => turnIds.has(entry.turnId)).sort((a, b) => b.finishedAt - a.finishedAt).slice(0, 50);
699
+ return Object.fromEntries(kept.map((entry) => [entry.key, entry]));
700
+ }
701
+ /**
702
+ * `output` cut to its last {@link BLOCK_RUN_OUTPUT_CAP} characters.
703
+ *
704
+ * @param output - What a run wrote.
705
+ */
706
+ function capBlockOutput(output) {
707
+ return output.length > 65536 ? {
708
+ output: output.slice(-65536),
709
+ truncated: true
710
+ } : { output };
711
+ }
712
+ //#endregion
546
713
  //#region src/chat/browser/protocol.ts
547
714
  /** Every browser operation name. */
548
715
  const BROWSER_OPS = [
@@ -1549,6 +1716,6 @@ function parseRepoInput(raw) {
1549
1716
  };
1550
1717
  }
1551
1718
  //#endregion
1552
- export { machineKind as $, entryParent as A, BROWSER_OUTLINE_MAX_ELEMENTS as B, ENTRY_EMPTY_DIRS_LIMIT as C, copyNames as D, ENTRY_IMPORT_MAX_FILE_BYTES as E, BROWSER_ACTION_TIMEOUT_MS as F, mayHaveStreamFailure as G, BROWSER_TEXT_MAX_CHARS as H, BROWSER_EVALUATE_MAX_BYTES as I, MACHINE_PROTOCOL_VERSION as J, splitStreamFailure as K, BROWSER_MAX_WAIT_MS as L, freeEntryName as M, importEntries as N, createEntryOps as O, joinEntry as P, machineCredentialKey as Q, BROWSER_OPEN_MOUNT_MS as R, TerminalError as S, ENTRY_IMPORT_MAX_ENTRIES as T, BROWSER_WAIT_TIMEOUT_MS as U, BROWSER_REQUEST_SLACK_MS as V, BrowserOpError as W, MachineErrorCode as X, MACHINE_STREAM_CHUNK_BYTES as Y, isValidMachineName as Z, TERMINAL_OUTPUT_WINDOW as _, selectableTurnIds as _t, MEDIA_BY_EXTENSION as a, REASONING_NOTICE_LABEL as at, TERMINAL_VIEW_MAX_LINES as b, turnSelectionOwnership as bt, sliceEnd as c, isTurnHighlighted as ct, modePrefix as d, isVisibleDuringSearch as dt, parseMachineKind as et, modePrefixLength as f, messageSelectionOwnership as ft, TERMINAL_MAX_PER_SESSION as g, retagUserPromptEventsFromRefs as gt, TERMINAL_MAX_PER_SCOPE as h, retagUserPromptEvents as ht, hasTool as i, EDIT_TOOL_NAMES as it, entryPath as j, entryName as k, EMPTY_MODES as l, isUserBashEvent as lt, TERMINAL_HISTORY_MAX_CHARS as m, promptTurnRefs as mt, HOST_TOOLS as n, BASH_CALL_ID_PREFIX as nt, mediaTypeOfPath as o, isCacheNotice as ot, scanModes as p, promptHistoryFromEvents as pt, MACHINE_IDEMPOTENT_METHODS as q, capabilityTags as r, CACHE_NOTICE_LABEL as rt, OutputHistory as s, isEditErrorResult as st, parseRepoInput as t, toMachineName as tt, isMouseTracking as u, isVisible as ut, TERMINAL_READ_MAX_CHARS as v, selectionAfterTurnRemoval as vt, ENTRY_IMPORT_MAX_BYTES as w, TERMINAL_VIEW_SCROLLBACK as x, TERMINAL_TEXT_MAX_LINES as y, streamEventSearchText as yt, BROWSER_OPS as z };
1719
+ export { blockTerminalInput as $, entryParent as A, retagUserPromptEventsFromRefs as At, BROWSER_OUTLINE_MAX_ELEMENTS as B, ENTRY_EMPTY_DIRS_LIMIT as C, isUserBashEvent as Ct, copyNames as D, promptHistoryFromEvents as Dt, ENTRY_IMPORT_MAX_FILE_BYTES as E, messageSelectionOwnership as Et, BROWSER_ACTION_TIMEOUT_MS as F, BLOCK_RUNS_MAX as G, BROWSER_TEXT_MAX_CHARS as H, BROWSER_EVALUATE_MAX_BYTES as I, BLOCK_RUN_TIMEOUT_MS as J, BLOCK_RUNS_METADATA_KEY as K, BROWSER_MAX_WAIT_MS as L, freeEntryName as M, selectionAfterTurnRemoval as Mt, importEntries as N, streamEventSearchText as Nt, createEntryOps as O, promptTurnRefs as Ot, joinEntry as P, turnSelectionOwnership as Pt, blockRunKey as Q, BROWSER_OPEN_MOUNT_MS as R, TerminalError as S, isTurnHighlighted as St, ENTRY_IMPORT_MAX_ENTRIES as T, isVisibleDuringSearch as Tt, BROWSER_WAIT_TIMEOUT_MS as U, BROWSER_REQUEST_SLACK_MS as V, BrowserOpError as W, SHELL_FENCE_LANGUAGES as X, SHELL_BLOCK_MAX_CHARS as Y, blockRunCommand as Z, TERMINAL_OUTPUT_WINDOW as _, CACHE_NOTICE_LABEL as _t, MEDIA_BY_EXTENSION as a, mayHaveStreamFailure as at, TERMINAL_VIEW_MAX_LINES as b, isCacheNotice as bt, sliceEnd as c, MACHINE_PROTOCOL_VERSION as ct, modePrefix as d, isValidMachineName as dt, capBlockOutput as et, modePrefixLength as f, machineCredentialKey as ft, TERMINAL_MAX_PER_SESSION as g, BASH_CALL_ID_PREFIX as gt, TERMINAL_MAX_PER_SCOPE as h, toMachineName as ht, hasTool as i, withBlockRun as it, entryPath as j, selectableTurnIds as jt, entryName as k, retagUserPromptEvents as kt, EMPTY_MODES as l, MACHINE_STREAM_CHUNK_BYTES as lt, TERMINAL_HISTORY_MAX_CHARS as m, parseMachineKind as mt, HOST_TOOLS as n, readBlockRuns as nt, mediaTypeOfPath as o, splitStreamFailure as ot, scanModes as p, machineKind as pt, BLOCK_RUN_OUTPUT_CAP as q, capabilityTags as r, shellBlockPlan as rt, OutputHistory as s, MACHINE_IDEMPOTENT_METHODS as st, parseRepoInput as t, isShellFence as tt, isMouseTracking as u, MachineErrorCode as ut, TERMINAL_READ_MAX_CHARS as v, EDIT_TOOL_NAMES as vt, ENTRY_IMPORT_MAX_BYTES as w, isVisible as wt, TERMINAL_VIEW_SCROLLBACK as x, isEditErrorResult as xt, TERMINAL_TEXT_MAX_LINES as y, REASONING_NOTICE_LABEL as yt, BROWSER_OPS as z };
1553
1720
 
1554
- //# sourceMappingURL=repo-url-D4Dr8NfZ.js.map
1721
+ //# sourceMappingURL=repo-url-DLjjuVk_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-url-DLjjuVk_.js","names":[],"sources":["../src/chat/turn-selection.ts","../src/chat/machine-protocol.ts","../src/chat/stream-failure.ts","../src/chat/shell-blocks.ts","../src/chat/browser/protocol.ts","../src/chat/workspace/entries.ts","../src/chat/terminal/protocol.ts","../src/contexts/terminal-modes.ts","../src/chat/terminal/output-history.ts","../src/chat/workspace/media-type.ts","../src/chat/capabilities.ts","../src/chat/git/repo-url.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Transcript visibility + select-turn navigation — pure data rules consumed\n// by any renderer that walks a `StreamEvent[]`. They encode the user-facing\n// semantics (settings + edit-tool error prefixes) rather than any\n// presentation primitive, and import nothing node-bound — so they live in\n// their own leaf module that a browser-context renderer can import via\n// `zidane/chat/pure`. `store.ts` re-exports them; the TUI\n// re-exports them via `zidane/tui`.\n// ---------------------------------------------------------------------------\n\nimport type { SessionTurn } from '../types'\nimport type { Settings, StreamEvent } from './types'\nimport { searchHighlightRanges } from './history-search'\n\n/** Tools whose `tool-result` event is suppressed when `showEditDiffs` is on. */\nexport const EDIT_TOOL_NAMES: ReadonlySet<string> = new Set(['edit', 'multi_edit', 'write_file'])\n\n/**\n * Keep turn-selection mode alive after deleting its active row. Prefer the\n * row that slides into the deleted index; at the tail, select the new last\n * row. Returns null only when no selectable rows survive.\n *\n * @param before - Selectable turn ids before the removal.\n * @param removedId - Id of the removed turn.\n * @param after - Selectable turn ids after the removal.\n */\nexport function selectionAfterTurnRemoval(\n before: readonly string[],\n removedId: string,\n after: readonly string[],\n): string | null {\n if (after.includes(removedId))\n return removedId\n if (after.length === 0)\n return null\n const index = before.indexOf(removedId)\n return after[Math.min(Math.max(0, index), after.length - 1)] ?? null\n}\n\n/**\n * Recognize a tool-result body as carrying NON-success information so the\n * renderer doesn't suppress it under `showEditDiffs`. Categories:\n *\n * - `edit` → \"Edit error: …\"\n * - `write_file` permission errors wrapped by the loop → \"Tool failed: …\"\n * - `multi_edit` → single-line error `multi_edit error: …`, OR\n * a result carrying an `<edit-outcomes>…</edit-outcomes>` annotation\n * block. The host only appends the annotation when at least one hunk\n * was NOT applied, so its mere presence is the signal — the result\n * body needs to stay visible next to the diff so the user can read\n * denial / skip / failure reasons longer than the per-hunk badge.\n * - Fully-denied gate emit (`[fully denied] <edit-outcomes>…`) likewise\n * stays visible.\n *\n * Exported for unit-testability of the visibility matrix.\n *\n * @param text - Text of an edit tool result.\n */\nexport function isEditErrorResult(text: string): boolean {\n if (text.startsWith('Edit error:'))\n return true\n if (text.startsWith('Tool failed:'))\n return true\n if (text.startsWith('multi_edit error:'))\n return true\n if (text.startsWith('[fully denied]'))\n return true\n // The annotation block only appears when at least one hunk was NOT\n // applied (see `annotateEditResult` in `src/chat/host/edits/index.ts`), so a present\n // sentinel pair signals \"denial / skip / failure attached — surface\n // the result body so reasons are readable next to the diff badges\".\n if (text.includes('\\n<edit-outcomes>\\n') || text.startsWith('<edit-outcomes>\\n'))\n return true\n return false\n}\n\n/**\n * `callId` prefix minted by the TUI's `!` bash mode (see `runBashMode`\n * in `src/tui/commands/run-bash-mode.ts`). The prefix is the durable signal — it survives\n * persistence and replay — that a `shell` tool exchange was USER-initiated,\n * so renderers can keep it visible even when the tool-display settings\n * hide model-driven plumbing: the user typed the command and expects to\n * see it and what it printed.\n */\nexport const BASH_CALL_ID_PREFIX = 'bash_'\n\n/**\n * Is this event a user-initiated `!` bash exchange (vs. a model-driven shell call)?\n *\n * @param event - The event to test.\n */\nexport function isUserBashEvent(event: Pick<StreamEvent, 'tool' | 'callId'>): boolean {\n return event.tool === 'shell' && event.callId?.startsWith(BASH_CALL_ID_PREFIX) === true\n}\n\n/**\n * Prompt-history entries (↑/↓ cycling) from a transcript, in submit order:\n * every submitted prompt (`user-prompt` events, raw text) AND every `!` bash\n * command (its `tool` event, reconstructed as `!command` so a recalled entry\n * re-submits through the same bash path). Model-driven tool calls are\n * excluded — only what the user actually typed belongs in their history.\n * Works identically on live events and on `eventsFromTurns` replay, so bash\n * commands persist in the history across session reloads for free.\n */\nexport function promptHistoryFromEvents(events: readonly StreamEvent[]): string[] {\n const history: string[] = []\n for (const event of events) {\n // Skip synthetic echoes (command injected-prompt markers, context-note\n // `display` lines) — the user never typed them, so they must not\n // resurface via up-arrow recall.\n if (event.kind === 'user-prompt' && !event.synthetic)\n history.push(event.text)\n else if (event.kind === 'tool' && isUserBashEvent(event) && typeof event.input?.command === 'string')\n history.push(`!${event.input.command}`)\n }\n return history\n}\n\n/**\n * Retro-tag live `user-prompt` events with the id of their persisted turn.\n *\n * Live prompt echoes are appended to the stream BEFORE `agent.run()` mints\n * and persists the user turn, so they carry no `turnId` — which makes them\n * invisible to select-turn navigation, hover, and click (all keyed on\n * `turnId`), while the SAME prompt becomes selectable after a session reload\n * (replay tags every event). Hosts call this when the seeded turns land\n * (e.g. the `session:turns` hook, which fires right after the prompt turn\n * persists, before the first model turn).\n *\n * Matching rule, per prompt-bearing turn: the NEWEST `user-prompt` event\n * that has no `turnId` yet and whose text equals one of the turn's text\n * blocks — or the turn's `display` echo when the caller supplies one\n * (run-minted prompt turns never carry `display` themselves; the TUI's\n * command `runAgent` path injects the origin display onto a copy after the\n * sub-run resolves, since the echo event's text is the short display line,\n * not the full prompt). A prompt turn qualifies with at least one non-blank\n * text block, OR — the attachment-only submit — with media blocks\n * (document/image/audio/video) and no tool plumbing; the latter matches the\n * newest untagged blank-text event that carries attachment chips. Tool-\n * result-only user turns contribute nothing, and loop-injected turns\n * (`SessionTurn.injected`) are not prompts, so neither is ever matched.\n *\n * Pure — returns the SAME array instance when nothing matched, so hosts\n * can cheaply skip a re-render.\n *\n * @param events - Current transcript events.\n * @param appendedTurns - Turns just persisted, in order.\n */\nexport function retagUserPromptEvents(\n events: readonly StreamEvent[],\n appendedTurns: readonly SessionTurn[],\n): readonly StreamEvent[] {\n return retagUserPromptEventsFromRefs(events, promptTurnRefs(appendedTurns))\n}\n\n/**\n * Reduce persisted turns to the prompt refs the retag needs, dropping\n * non-prompt turns (assistant, tool results, loop-injected) entirely.\n *\n * Shared by the in-process path and the daemon broadcast so both select the\n * same turns as \"prompts\" — a divergence here would make a prompt selectable\n * on one surface and not the other.\n *\n * @param turns - Persisted turns, in order.\n */\nexport function promptTurnRefs(turns: readonly SessionTurn[]): PromptTurnRef[] {\n const isMediaBlock = (b: SessionTurn['content'][number]): boolean =>\n b.type === 'document' || b.type === 'image' || b.type === 'audio' || b.type === 'video'\n const hasPromptText = (t: SessionTurn): boolean =>\n t.content.some(b => b.type === 'text' && b.text.trim().length > 0)\n const isAttachmentOnly = (t: SessionTurn): boolean =>\n t.content.some(isMediaBlock) && !t.content.some(b => b.type === 'tool_result')\n\n return turns\n .filter(t => t.role === 'user' && !t.injected && (hasPromptText(t) || isAttachmentOnly(t)))\n .map(turn => ({\n id: turn.id,\n texts: [\n ...turn.content.filter(b => b.type === 'text').map(b => b.text),\n ...(turn.display ? [turn.display] : []),\n ],\n // Attachment-only prompts have no (non-blank) text to match on — their\n // live echo is a blank-text event whose identity is the attachment chips.\n attachmentOnly: !hasPromptText(turn) && isAttachmentOnly(turn),\n }))\n}\n\n/**\n * The minimum a prompt turn must carry to be matched against its live echo.\n *\n * Exists because the daemon has to send this over a wire: a full `SessionTurn`\n * carries every content block, including base64 image and document payloads,\n * which would be megabytes per prompt to ship for the sake of attaching an id.\n */\nexport interface PromptTurnRef {\n /** Id of the user turn. */\n id: string\n /** Text blocks plus the `display` override, if any. */\n texts: readonly string[]\n /** Whether the turn has attachments and no prompt text. */\n attachmentOnly: boolean\n}\n\n/**\n * Attach persisted turn ids to the live `user-prompt` events they correspond\n * to, so a just-sent prompt becomes selectable (hover, click, edit, delete)\n * without waiting for a session reload.\n *\n * Matching is newest-first and one-to-one: identical prompt text sent twice\n * must bind to two different turns, so each ref consumes exactly one untagged\n * event.\n *\n * @param events - Current transcript events.\n * @param refs - Prompt turn refs from {@link promptTurnRefs}.\n */\nexport function retagUserPromptEventsFromRefs(\n events: readonly StreamEvent[],\n refs: readonly PromptTurnRef[],\n): readonly StreamEvent[] {\n if (refs.length === 0)\n return events\n let changed = false\n const next = [...events]\n for (const ref of refs) {\n const texts = new Set(ref.texts)\n for (let i = next.length - 1; i >= 0; i--) {\n const e = next[i]!\n if (e.kind !== 'user-prompt' || e.turnId)\n continue\n const matched = texts.has(e.text)\n || (ref.attachmentOnly && e.text.trim().length === 0 && (e.attachments?.length ?? 0) > 0)\n if (matched) {\n next[i] = { ...e, turnId: ref.id }\n changed = true\n break\n }\n }\n }\n return changed ? next : events\n}\n\n/** Searchable text of one stream event — tool name, label, and body text. */\nexport function streamEventSearchText(event: StreamEvent): string {\n return [event.tool, event.label, event.text].filter(Boolean).join('\\n')\n}\n\n/**\n * Whether `event` shows while a search is active: whatever {@link isVisible}\n * shows, plus top-level rows the search matches.\n *\n * @param event - The event to test.\n * @param settings - The user's transcript settings.\n * @param query - The search query.\n */\nexport function isVisibleDuringSearch(event: StreamEvent, settings: Settings, query: string): boolean {\n if (isVisible(event, settings))\n return true\n // Search may reveal a matching top-level row that its normal preference\n // hides (thinking, tool results — including a subagent's final report).\n // Nested child output stays collapsed and signals through the visible\n // lifecycle parent instead.\n return (event.depth ?? 0) === 0\n && searchHighlightRanges(streamEventSearchText(event), query).length > 0\n}\n\n/** `notice.label` the host stamps on prompt-cache break/expiry rows (`host/notices/index.ts`). */\nexport const CACHE_NOTICE_LABEL = 'cache'\n\n/** `notice.label` the host stamps on replayed reasoning the provider dropped before sampling. */\nexport const REASONING_NOTICE_LABEL = 'reasoning'\n\n/**\n * Whether a notice is one `showCacheNotices` hides: a prompt-cache break or\n * expiry, or dropped reasoning (the same prefix churn, seen from the thinking side).\n *\n * @param notice - The event's notice, if any.\n */\nexport function isCacheNotice(notice: StreamEvent['notice']): boolean {\n return notice?.label === CACHE_NOTICE_LABEL || notice?.label === REASONING_NOTICE_LABEL\n}\n\n/**\n * Whether `event` shows in the transcript under the user's toggles, including\n * `hideSubagentOutput`, `showEditDiffs`, `showThinking` and `showToolResults`.\n * When subagent output is hidden:\n * - Child-agent events are filtered down to the `spawn-start` /\n * `spawn-end` markers so the user still sees \"🌱 working… 🌳 done\".\n * - The parent's `tool-result` for `spawn` is hidden too. Its body\n * duplicates `spawn-end`'s stats line *and* the parent's next\n * markdown turn; showing it again produces an extra\n * `┃ [sub-agent child-1] Completed …` block users just want gone.\n *\n * Renderer-agnostic — returns plain `boolean` so TUI / GUI consumers\n * can filter events identically.\n *\n * @param event - The event to test.\n * @param settings - The user's transcript settings.\n */\nexport function isVisible(event: StreamEvent, settings: Settings): boolean {\n // A codemode script's calls show under its row only with `codemodeShowCalls`,\n // except calls that run a subagent: their worker attaches to that row.\n if (event.parentToolCallId !== undefined && !event.runsNestedAgent && !settings.codemodeShowCalls)\n return false\n if (settings.hideSubagentOutput) {\n if ((event.depth ?? 0) > 0)\n return event.kind === 'spawn-start' || event.kind === 'spawn-end'\n if (event.kind === 'tool-result' && event.tool === 'spawn')\n return false\n }\n // Suppress successful `tool-result`s for edit/multi_edit/write_file when\n // the diff renderer is on — the diff itself is the success indicator;\n // the `Edited path: N replacements.` line just adds noise. Error\n // results bypass the suppression so failures stay visible.\n if (\n settings.showEditDiffs\n && event.kind === 'tool-result'\n && event.tool\n && EDIT_TOOL_NAMES.has(event.tool)\n && !isEditErrorResult(event.text)\n ) {\n return false\n }\n switch (event.kind) {\n case 'thinking': return settings.showThinking\n // User-initiated `!` bash rows are never hidden — the user ran the\n // command to SEE it and its output; `toolCallDisplay` / `showToolResults`\n // gate model plumbing only. Without the `tool` exemption, hiding tool\n // calls would leave bash output floating with no sign of what ran.\n case 'tool': return settings.toolCallDisplay !== 'hidden' || isUserBashEvent(event)\n case 'tool-result': return settings.showToolResults || isUserBashEvent(event)\n case 'run-summary': return settings.showRunReceipt\n case 'info': return settings.showCacheNotices || !isCacheNotice(event.notice)\n // State for its spawn call's line, never a row of its own: it reaches\n // the compact fold (which shows the call as waiting) and nothing else.\n case 'spawn-queued': return settings.transcriptDensity === 'compact'\n // State for its script's row (`scriptProgressByCall`), never a row of its own.\n case 'tool-progress': return false\n default: return true\n }\n}\n\n/**\n * Build the `resultTurnId → owningAssistantTurnId` map used by the select-\n * turn mode to coalesce a tool-call's surrounding turns into ONE navigation\n * stop.\n *\n * Protocol shape: every `tool_call` block in an assistant turn is closed by\n * a matching `tool_result` block in the *next* user turn (the agent loop's\n * history validator depends on this). When the next user turn's only events\n * are `tool-result`s — i.e. it's pure plumbing for the prior assistant\n * turn — we map it back to that assistant turn here. The select-turn nav\n * index ({@link selectableTurnIds}) skips owned turns, and the renderer's\n * highlight gate ({@link isTurnHighlighted}) extends the selection accent\n * from the assistant turn to the events of any turn it owns. Net effect:\n *\n * - Navigation never lands the cursor on a result-only turn whose own\n * events may be hidden by `showToolResults: false` — the cursor\n * wouldn't be visible.\n * - Selecting an assistant turn highlights the call AND its result as\n * one unit, matching the user's mental model of \"one message\".\n *\n * Owner-lookup is conservative: result-only turns with no matching prior\n * assistant turn (orphaned — usually because the parent was deleted)\n * stay selectable so the user can act on them via the turn-details modal.\n *\n * Subagent (`childId` set) events are ignored — they live in a separate\n * conversation tree.\n *\n * @param events - Transcript events in order.\n */\nexport function turnSelectionOwnership(events: readonly StreamEvent[]): Map<string, string> {\n // Build per-turn event-kind summary in render order. We need:\n // - Whether a turn is \"result-only\" (every event is `tool-result`).\n // - The most recent previous turn that emitted a `tool` event (= the\n // candidate owner for the next result-only turn).\n const orderedTurnIds: string[] = []\n const summaryByTurn = new Map<string, { kinds: StreamEvent['kind'][], resultCallIds: string[] }>()\n const callOwner = new Map<string, string>()\n for (const e of events) {\n if (!e.turnId)\n continue\n if (e.childId)\n continue\n let summary = summaryByTurn.get(e.turnId)\n if (!summary) {\n orderedTurnIds.push(e.turnId)\n summary = { kinds: [], resultCallIds: [] }\n summaryByTurn.set(e.turnId, summary)\n }\n summary.kinds.push(e.kind)\n if (e.callId) {\n if (e.kind === 'tool')\n callOwner.set(e.callId, e.turnId)\n else if (e.kind === 'tool-result')\n summary.resultCallIds.push(e.callId)\n }\n }\n\n const ownership = new Map<string, string>()\n let lastToolEmitterTurnId: string | null = null\n for (const tid of orderedTurnIds) {\n const { kinds, resultCallIds } = summaryByTurn.get(tid)!\n const isResultOnly = kinds.length > 0 && kinds.every(k => k === 'tool-result')\n if (isResultOnly) {\n // Prefer the exact callId owner: in a FILTERED transcript (search) an\n // unrelated tool-emitting turn can sit between a result and its true\n // owner, so adjacency alone would coalesce onto the interloper.\n const exactOwner = resultCallIds\n .map(callId => callOwner.get(callId))\n .find(owner => owner !== undefined && owner !== tid)\n if (exactOwner)\n ownership.set(tid, exactOwner)\n else if (lastToolEmitterTurnId)\n ownership.set(tid, lastToolEmitterTurnId)\n // No owner found — leave the orphan selectable. Don't update\n // `lastToolEmitterTurnId` either (a result-only turn never emits\n // a `tool` event itself).\n continue\n }\n if (kinds.includes('tool'))\n lastToolEmitterTurnId = tid\n }\n return ownership\n}\n\n/**\n * Render-time check: should `event` paint with the selection accent?\n *\n * `true` when the event's own turn is selected, OR when the selected turn\n * `owns` the event's turn via {@link turnSelectionOwnership} (the call and\n * its tool-result rows highlight together), OR when the event's turn owns the\n * selected turn (a result-only turn selected highlights its call). `false` when nothing is\n * selected or the relationship doesn't apply.\n *\n * Pure. Renderer-agnostic — the TUI's `<Transcript>` uses it; a GUI's\n * equivalent walks the same rule.\n *\n * @param event - The event being rendered.\n * @param selectedTurnId - The selected turn id, or `null` when nothing is selected.\n * @param ownership - Map from an owned turn id to its owner, from {@link turnSelectionOwnership}.\n */\nexport function isTurnHighlighted(\n event: Pick<StreamEvent, 'turnId'>,\n selectedTurnId: string | null,\n ownership: ReadonlyMap<string, string>,\n): boolean {\n if (selectedTurnId === null || !event.turnId)\n return false\n if (event.turnId === selectedTurnId)\n return true\n return ownership.get(event.turnId) === selectedTurnId\n || ownership.get(selectedTurnId) === event.turnId\n}\n\n/**\n * Ownership for \"one selection stop per message\": result-only turns fold\n * into their assistant turn (`turnSelectionOwnership`), and turns that only\n * did work (thinking, tool calls, worker markers) fold into the answer that\n * follows them in the same exchange. \"Read three files, then answered\" is\n * one stop, so ↑ moves one visible message at a time. An exchange that ends\n * in work alone stops on its first work turn. Same rule as the GUI's\n * `computeSelectStops`.\n *\n * @param events - Transcript events in order.\n */\nexport function messageSelectionOwnership(events: readonly StreamEvent[]): Map<string, string> {\n const base = turnSelectionOwnership(events)\n const resolve = (id: string): string => base.get(id) ?? id\n const stops = new Set<string>()\n const merged = new Map<string, string>()\n let pending: string[] = []\n const settle = (into: string | null) => {\n const target = into ?? pending[0]\n for (const id of pending) {\n if (target !== undefined && id !== target)\n merged.set(id, target)\n }\n if (target !== undefined)\n stops.add(target)\n pending = []\n }\n for (const event of events) {\n if (event.childId !== undefined || (event.depth ?? 0) > 0)\n continue\n if (event.kind === 'separator' || event.kind === 'user-prompt' || event.kind === 'compact-summary')\n settle(null)\n if (!event.turnId)\n continue\n const owner = resolve(event.turnId)\n const work = event.kind === 'tool' || event.kind === 'tool-result' || event.kind === 'thinking'\n || event.kind === 'spawn-start' || event.kind === 'spawn-end' || event.kind === 'command-detail'\n || (event.kind === 'info' && event.notice === undefined)\n if (event.kind === 'markdown' && event.text.trim()) {\n stops.add(owner)\n settle(owner)\n }\n else if (work) {\n if (!stops.has(owner) && !pending.includes(owner))\n pending.push(owner)\n }\n else if (event.kind !== 'user-prompt' && event.kind !== 'compact-summary') {\n settle(null)\n stops.add(owner)\n }\n else {\n stops.add(owner)\n }\n }\n settle(null)\n const out = new Map<string, string>()\n const final = (id: string): string => merged.get(id) ?? id\n for (const [raw, owner] of base) {\n const stop = final(owner)\n if (stop !== raw)\n out.set(raw, stop)\n }\n for (const [id, stop] of merged)\n out.set(id, stop)\n return out\n}\n\n/**\n * Deduplicated, in-order list of **parent-conversation** turn ids that appear\n * in a rendered transcript — the navigation index for the TUI's select-turn\n * mode. Three classes of turns are deliberately skipped:\n *\n * - **Subagent turns** (`childId` set). Nested execution detail; the\n * user's mental model of a \"message\" is the conversational exchange,\n * not each spawn turn. Also filtered out by `isVisible` under\n * `hideSubagentOutput: true` — selecting them would highlight nothing.\n * - **Result-only turns** — see {@link turnSelectionOwnership}. These get\n * coalesced into the assistant turn that emitted their tool_calls.\n * - **Settings-hidden turns** (when `settings` is supplied). A turn whose\n * every event fails {@link isVisible} would render no rows — landing\n * the cursor there hides it from the user entirely. The check is opt-\n * in so SDK callers without a Settings object get the\n * \"everything visible\" behavior.\n *\n * Synthetic events (separator, spawn-start, spawn-end) have no `turnId` and\n * are skipped naturally.\n *\n * @param events - Transcript events in order.\n * @param settings - When set, turns with no visible event are skipped.\n * @param visible - Overrides {@link isVisible} for the settings check.\n * @param opts - `byMessage` makes one stop per visible message.\n */\nexport function selectableTurnIds(\n events: readonly StreamEvent[],\n settings?: Settings,\n visible?: (event: StreamEvent) => boolean,\n opts?: { byMessage?: boolean },\n): string[] {\n // `byMessage`: one stop per visible message (`messageSelectionOwnership`).\n const ownership = opts?.byMessage ? messageSelectionOwnership(events) : turnSelectionOwnership(events)\n\n // Per-turn visible event count (only computed when settings is supplied).\n // We need this to drop turns whose every event is filtered out by user\n // toggles — otherwise `↑/↓` could land the cursor on a row that paints\n // nothing visible.\n const visibleCount = settings ? new Map<string, number>() : null\n if (settings && visibleCount) {\n for (const e of events) {\n if (!e.turnId || e.childId)\n continue\n if (!(visible ? visible(e) : isVisible(e, settings)))\n continue\n visibleCount.set(e.turnId, (visibleCount.get(e.turnId) ?? 0) + 1)\n }\n }\n\n const seen = new Set<string>()\n const ordered: string[] = []\n for (const e of events) {\n if (!e.turnId)\n continue\n if (e.childId)\n continue\n if (seen.has(e.turnId))\n continue\n if (ownership.has(e.turnId))\n continue // result-only — owned by an earlier assistant turn\n if (visibleCount && (visibleCount.get(e.turnId) ?? 0) === 0)\n continue // every event of this turn is hidden by user settings\n seen.add(e.turnId)\n ordered.push(e.turnId)\n }\n return ordered\n}\n","import type { JsonValue } from '../types'\n/**\n * The machine protocol (`docs/MACHINES.md`): what a machine and its host say\n * over the machine's own WebSocket. Leaf module, shared by the host engine\n * (`chat/host/machines`), the machine agent (`ipc/machine`) and the IPC\n * protocol (re-exported by `ipc/protocol.ts`).\n */\nimport type { EnvironmentConfig } from './environment'\n\n/** Bumped on an incompatible change; a host refuses any other version. */\nexport const MACHINE_PROTOCOL_VERSION = 1\n\n/** A directory a machine exposes to its host. */\nexport interface MachineRoot {\n /** Absolute path of the root on the machine. */\n path: string\n /** Display name for the root. */\n label?: string\n}\n\n/** What a machine can do, sent in `machine.register`. */\nexport interface MachineCapabilities {\n /** Runs commands (`exec.*`). */\n shell: boolean\n /** Opens terminals (`terminal.*`). */\n terminals: boolean\n /** Runs background tasks (`bg.*`). */\n background: boolean\n /** Prepares and tears down git worktrees (`env.prepareWorktree`, `env.teardownWorktree`). */\n worktrees: boolean\n /** `exec.stream*` (live stdin/stdout: context-scoped MCP servers). Absent on older machines. */\n stream?: boolean\n /** The machine runs every command under its own OS sandbox (its user's `sandbox*` settings). */\n sandboxed?: boolean\n /** Entry calls (`fs.stat`, `fs.readdir`, `fs.mkdir`, `fs.move`, `fs.copy`, `fs.remove`, `fs.emptyDirs`). Absent on older machines: the host runs commands instead. */\n entries?: boolean\n /** The machine's GPU device names (\"NVIDIA GeForce RTX 4090\", \"Apple M4 Pro\"). Absent on older machines. */\n gpu?: string[]\n}\n\n/** At most this many live `exec.stream` processes per machine. */\nexport const MACHINE_MAX_STREAMS = 16\n/** Largest `data` chunk (decoded bytes) of one `exec.stream.data` notification or `exec.stream.write`. */\nexport const MACHINE_STREAM_CHUNK_BYTES = 256 * 1024\n\n/** Params of `machine.register`, the first call a machine makes on its host. */\nexport interface MachineRegisterParams {\n /** Stable machine id. */\n machineId: string\n /** Machine name, valid per {@link isValidMachineName}. */\n name: string\n /** Directories the machine exposes. */\n roots: MachineRoot[]\n /** What the machine can do. */\n capabilities: MachineCapabilities\n /** Machine software version. */\n version: string\n /** The machine's {@link MACHINE_PROTOCOL_VERSION}. */\n protocolVersion: number\n}\n\n/** Result of `machine.register`. */\nexport interface MachineRegisterResult {\n /** Id the host bound the machine to. */\n machineId: string\n /** The host's id, when it reports one. */\n hostId?: string\n}\n\n/** A handle as the host names it: the machine rebuilds an unknown one (it restarted). */\nexport interface MachineHandleRef {\n id: string\n cwd: string\n}\n\n/** Options of `fs.list`. */\nexport interface MachineListOptions {\n glob?: boolean\n limit?: number\n metadata?: boolean\n gitignore?: boolean\n}\n\n/** A background task started by `bg.start`. */\nexport interface MachineTaskHandle {\n /** Task id. */\n taskId: string\n /** Process id on the machine. */\n pid: number\n /** Path on the machine that receives the task output. */\n outputPath: string\n}\n\n/** A machine's worktree, on its filesystem. */\nexport interface MachineWorktreeRef {\n path: string\n repoRoot: string\n}\n\n/** Requests the host sends to a machine: params → result. */\nexport interface MachineMethods {\n 'machine.ping': { params: Record<string, never>, result: { ok: true } }\n 'exec.spawn': { params: { handle: MachineHandleRef }, result: { id: string, cwd: string } }\n 'exec.run': { params: { handle: MachineHandleRef, callId: string, command: string, cwd?: string, env?: Record<string, string>, timeout?: number }, result: { stdout: string, stderr: string, exitCode: number } }\n 'exec.cancel': { params: { callId: string }, result: { cancelled: boolean } }\n 'exec.destroy': { params: { handle: MachineHandleRef }, result: { ok: true } }\n /** Start a live process; its output comes as `exec.stream.data` / `exec.stream.exit`, `exec.cancel` kills it. */\n 'exec.stream': { params: { handle: MachineHandleRef, callId: string, command: string, cwd?: string, env?: Record<string, string> }, result: { pid: number } }\n 'exec.stream.write': { params: { callId: string, data: string }, result: { ok: true } }\n 'fs.read': { params: { handle: MachineHandleRef, path: string, binary?: boolean }, result: { content: string } }\n /** `exclusive`: a new file only, refused when `path` exists (an entry create). */\n 'fs.write': { params: { handle: MachineHandleRef, path: string, content: string, exclusive?: boolean }, result: { ok: true } }\n 'fs.list': { params: { handle: MachineHandleRef, path: string, options?: MachineListOptions }, result: { entries: Array<string | { path: string, size?: number, mtimeMs?: number }> } }\n 'fs.size': { params: { handle: MachineHandleRef, path: string }, result: { size: number | null } }\n /** What `path` is (a symlink: a file, never followed); `null`: nothing there. */\n 'fs.stat': { params: { handle: MachineHandleRef, path: string }, result: { kind: 'file' | 'dir' | null } }\n /** The names in folder `path`. */\n 'fs.readdir': { params: { handle: MachineHandleRef, path: string }, result: { names: string[] } }\n /** Creates folder `path` and its missing parents. */\n 'fs.mkdir': { params: { handle: MachineHandleRef, path: string }, result: { ok: true } }\n /** Renames `from` to `to`; refused when `to` exists. */\n 'fs.move': { params: { handle: MachineHandleRef, from: string, to: string }, result: { ok: true } }\n /** Copies `from` (a folder whole) to `to`; refused when `to` exists. */\n 'fs.copy': { params: { handle: MachineHandleRef, from: string, to: string }, result: { ok: true } }\n /** Removes `path` (a folder whole). */\n 'fs.remove': { params: { handle: MachineHandleRef, path: string }, result: { ok: true } }\n /** Empty folders under `path`, relative to it, at most `limit`. */\n 'fs.emptyDirs': { params: { handle: MachineHandleRef, path: string, limit: number }, result: { paths: string[] } }\n 'bg.start': { params: { handle: MachineHandleRef, command: string, cwd?: string, env?: Record<string, string>, maxOutputBytes?: number }, result: MachineTaskHandle }\n 'bg.list': { params: { handle: MachineHandleRef }, result: { tasks: JsonValue[] } }\n 'bg.kill': { params: { handle: MachineHandleRef, taskId: string }, result: { exit: JsonValue | null } }\n 'bg.wait': { params: { handle: MachineHandleRef, taskId: string, timeoutMs?: number }, result: { exit: JsonValue | null } }\n 'terminal.open': { params: { handle: MachineHandleRef, cols: number, rows: number, cwd?: string }, result: { terminalId: string } }\n 'terminal.attach': { params: { terminalId: string }, result: { attached: boolean, backlog: string, total: number } }\n 'terminal.write': { params: { terminalId: string, data: string }, result: { ok: true } }\n 'terminal.resize': { params: { terminalId: string, cols: number, rows: number }, result: { ok: true } }\n 'terminal.kill': { params: { terminalId: string }, result: { ok: true } }\n 'terminal.detach': { params: { terminalId: string }, result: { ok: true } }\n 'env.checkFolder': { params: { cwd: string }, result: { cwd: string } }\n 'env.prepareWorktree': { params: { cwd: string, branch: string, base?: string, config: EnvironmentConfig }, result: { cwd: string, branch: string, base: string, ref: MachineWorktreeRef } }\n 'env.teardownWorktree': { params: { ref: MachineWorktreeRef, branch?: string, config: EnvironmentConfig }, result: { removed: boolean, reason?: string } }\n}\n\nexport type MachineMethodName = keyof MachineMethods\nexport type MachineParams<M extends MachineMethodName> = MachineMethods[M]['params']\nexport type MachineResult<M extends MachineMethodName> = MachineMethods[M]['result']\n\n/** Notifications a machine sends its host (base64 `data`). */\nexport interface MachineNotifications {\n 'terminal.data': { terminalId: string, data: string }\n 'terminal.exit': { terminalId: string, code: number }\n 'task.exit': { taskId: string, exit: JsonValue }\n 'exec.stream.data': { callId: string, stream: 'stdout' | 'stderr', data: string }\n 'exec.stream.exit': { callId: string, code: number }\n}\n\n/**\n * Calls whose re-send after a lost reply cannot change anything (reads, and\n * the idempotent handle calls: the machine keys handles by the host's id).\n * Everything else that was sent is reported as a lost result, never re-sent.\n */\nexport const MACHINE_IDEMPOTENT_METHODS: ReadonlySet<MachineMethodName> = new Set<MachineMethodName>([\n 'machine.ping',\n 'exec.spawn',\n 'exec.cancel',\n 'exec.destroy',\n 'fs.read',\n 'fs.list',\n 'fs.size',\n 'fs.stat',\n 'fs.readdir',\n 'fs.mkdir',\n 'fs.emptyDirs',\n 'bg.list',\n 'bg.wait',\n 'env.checkFolder',\n 'terminal.attach',\n])\n\n/** Methods a machine connection may call on its host. */\nexport const MACHINE_HOST_METHODS = ['machine.register'] as const\n\n/** Error codes of the machine protocol (JSON-RPC server-error range, apart from `IpcErrorCode`). */\nexport const MachineErrorCode = {\n /** A machine connection called a client method, or a client a machine one. */\n MethodNotAllowed: -32040,\n /** `machine.register` with a `protocolVersion` other than this host's `MACHINE_PROTOCOL_VERSION`. */\n VersionSkew: -32041,\n /** The name is held by another machine on this host. */\n NameTaken: -32042,\n /** A path or cwd outside the machine's roots, or in its data dir. */\n OutsideRoots: -32043,\n /** The machine id is bound to another (live) token, or this token was used by the machine before the host forgot it. */\n IdBound: -32044,\n /** No room now (a capacity limit): try again later, unlike a refusal. */\n Busy: -32045,\n} as const\n\n/** A machine as clients see it (`machines.list`, `environments.list`). */\nexport interface MachineInfo {\n /** Stable machine id. */\n id: string\n /** Machine name, valid per {@link isValidMachineName}. */\n name: string\n /** Directories the machine allows commands and file access in. */\n roots: MachineRoot[]\n /** Whether the machine is connected to the host now. */\n status: 'online' | 'offline'\n /** Time of the last connection, in epoch milliseconds. */\n lastSeen?: number\n /** Version the machine reported when it registered. */\n version?: string\n /** What it registered with (absent: never connected since this host recorded it). */\n capabilities?: Partial<MachineCapabilities>\n}\n\n/** `machine:status` payload. */\nexport interface MachineStatusChange {\n /** Id of the machine whose status changed. */\n machineId: string\n /** Name of the machine. */\n name: string\n /** New connection status. */\n status: 'online' | 'offline'\n}\n\n/**\n * What a local host's machine links are doing (`machines.links.status`,\n * `machine:links`): this computer shared with a saved server (it is the\n * machine), and saved servers used as machines (`local@<server>`, the\n * reverse direction over this host's own client connection).\n */\nexport type MachineLinkState = 'connecting' | 'connected' | 'reconnecting' | 'offline' | 'auth-refused' | 'identity' | 'version-mismatch' | 'refused'\n\n/** State of this computer's share to one saved server, where it acts as a machine. */\nexport interface MachineShareStatus {\n /** The saved server's host id. */\n hostId: string\n /** This computer's name there (`local@<name>`). */\n name: string\n /** Paths shared with the server. */\n roots: string[]\n /** Connection state of the link. */\n state: MachineLinkState\n /** Why it is not connected. Never a token. */\n detail?: string\n}\n\n/** State of one saved server used as a machine by this host. */\nexport interface MachineUseStatus {\n /** The saved server's host id. */\n hostId: string\n /** Connection state of the link. */\n state: MachineLinkState\n /** Why the link is not connected. Never a token. */\n detail?: string\n /** The server's machine name on this host, once attached. */\n machineName?: string\n}\n\n/** Status of every machine link of a local host. */\nexport interface MachineLinksStatus {\n /** This computer shared with saved servers. */\n shares: MachineShareStatus[]\n /** Saved servers used as machines. */\n uses: MachineUseStatus[]\n}\n\n/** Where a local host keeps the machine token a saved server gave it (credentials store). */\nexport function machineCredentialKey(hostId: string): string {\n return `machine:${hostId}`\n}\n\n/**\n * A machine name from a free-form one (a server's display name): the valid characters kept, the rest dashed.\n *\n * @param raw - Free-form name, such as a server's display name.\n */\nexport function toMachineName(raw: string): string {\n const cleaned = raw.trim().replace(/[^\\w.-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 64)\n return cleaned || 'machine'\n}\n\n/**\n * A machine-qualified environment kind: `<base>@<machine name>`.\n *\n * @param base - Base environment kind.\n * @param name - Machine name.\n */\nexport function machineKind(base: 'local' | 'worktree', name: string): string {\n return `${base}@${name}`\n}\n\n/**\n * `{ base, name }` of a machine-qualified kind, `null` for any other.\n *\n * @param kind - Environment kind, such as `local@laptop`.\n */\nexport function parseMachineKind(kind: string): { base: 'local' | 'worktree', name: string } | null {\n const match = /^(local|worktree)@(.+)$/.exec(kind)\n return match ? { base: match[1] as 'local' | 'worktree', name: match[2]! } : null\n}\n\n/**\n * A machine name: one path-safe segment, so `local@<name>` is unambiguous.\n *\n * @param name - Candidate machine name.\n */\nexport function isValidMachineName(name: string): boolean {\n return /^[\\w.-]{1,64}$/.test(name)\n}\n","/**\n * The markers the loop writes into an assistant turn when its stream ends\n * early (`src/loop-turn-stream.ts`, `src/loop-stream.ts`): `[✗ Streaming failed before any output: <message>]`\n * (or `mid-output`) when the provider throws, `[⏹ Streaming was aborted.]`\n * when the user stops the run. Either is appended blank-line-separated to\n * whatever had streamed. The marker stays in the persisted turn for the\n * model; hosts split it off to show a quiet \"stopped\" line instead of prose.\n */\n\n/** A stop marker split off an assistant reply by {@link splitStreamFailure}. */\nexport interface StreamFailure {\n /** The provider message, `''` when there is none (always for an abort). */\n message: string\n /** Text had streamed before the stream ended. */\n midOutput: boolean\n /** The user stopped the run; not a failure of the provider. */\n aborted: boolean\n}\n\nconst FAILED = /(?:^|\\n\\n)\\[✗ Streaming failed (before any output|mid-output)(?:: ([\\s\\S]*))?\\.?\\]\\s*$/\nconst ABORTED = /(?:^|\\n\\n)\\[⏹ Streaming was aborted\\.\\]\\s*$/\n\n/**\n * Split a reply into what the model wrote and the stop marker at its end, if any.\n *\n * @param text - Assistant message text that may end in a failure marker.\n */\nexport function splitStreamFailure(text: string): { text: string, failure: StreamFailure | null } {\n const aborted = ABORTED.exec(text)\n if (aborted) {\n const before = text.slice(0, aborted.index).trimEnd()\n return { text: before, failure: { message: '', midOutput: before !== '', aborted: true } }\n }\n const m = FAILED.exec(text)\n if (!m)\n return { text, failure: null }\n return {\n text: text.slice(0, m.index).trimEnd(),\n failure: { message: (m[2] ?? '').trim(), midOutput: m[1] === 'mid-output', aborted: false },\n }\n}\n\n/**\n * Cheap pre-check before splitting: the text may end in a stop marker.\n *\n * @param text - Assistant message text.\n */\nexport function mayHaveStreamFailure(text: string): boolean {\n return text.includes('[✗ Streaming failed') || text.includes('[⏹ Streaming was aborted')\n}\n\nexport { CONTINUE_PROMPT } from '../continue-prompt'\n","/**\n * Shell code blocks in a reply, run by the user (`Run here`, `Run in a\n * terminal`): which fences run, what runs, and the saved last run of each\n * block. A run never enters the conversation: the host keeps the last run of\n * each block in the session's metadata ({@link BLOCK_RUNS_METADATA_KEY}).\n *\n * A one-line block runs as it is. A longer one becomes a temporary script on\n * the host (`mktemp`, written through a here-document, removed after), run in\n * the session's folder by the fence's shell. Run here closes the command's\n * input, so a command that asks for some fails at once; in a terminal it can\n * ask.\n *\n * Node-free (exported from `zidane/chat/pure`).\n */\n\n/** Fence languages that run. */\nexport const SHELL_FENCE_LANGUAGES: ReadonlySet<string> = new Set(['bash', 'sh', 'shell', 'zsh', 'console'])\n\n/** The shell a block runs in, from its fence. */\nexport type BlockShell = 'bash' | 'zsh' | 'sh'\n\n/** What runs for a block. */\nexport interface ShellBlockPlan {\n /** The script: the block, or its `$ ` lines without the prompt. */\n script: string\n /** The shell it runs in: the fence's (`zsh`, `sh`), else `bash`. */\n shell: BlockShell\n /** One command line: run as it is, no temporary script. */\n oneLine: boolean\n}\n\n/** Longest block that runs, in characters. */\nexport const SHELL_BLOCK_MAX_CHARS = 64 * 1024\n\n/** Output kept of a run (the end of it), in characters. */\nexport const BLOCK_RUN_OUTPUT_CAP = 64 * 1024\n\n/** How long a Run here may take. */\nexport const BLOCK_RUN_TIMEOUT_MS = 10 * 60 * 1000\n\n/** Runs kept per session; the oldest go first. */\nexport const BLOCK_RUNS_MAX = 50\n\n/** Session metadata key of the saved runs. */\nexport const BLOCK_RUNS_METADATA_KEY = 'blockRuns'\n\nconst PROMPT_LINE = /^\\$ /\n\n/**\n * Whether a fence of `language` runs.\n *\n * @param language - The fence's language, as written.\n */\nexport function isShellFence(language: string | undefined): boolean {\n return language !== undefined && SHELL_FENCE_LANGUAGES.has(language.trim().toLowerCase())\n}\n\nfunction shellOf(language: string): BlockShell {\n const lang = language.trim().toLowerCase()\n return lang === 'zsh' ? 'zsh' : lang === 'sh' ? 'sh' : 'bash'\n}\n\n/**\n * What runs for a block, or `null` when nothing does (another language, no\n * command, too long). A block with `$ ` lines runs those lines only, without\n * the prompt: the other lines are output.\n *\n * @param code - The block's text.\n * @param language - The fence's language.\n */\nexport function shellBlockPlan(code: string, language: string | undefined): ShellBlockPlan | null {\n if (!isShellFence(language) || code.length > SHELL_BLOCK_MAX_CHARS)\n return null\n const lines = code.replace(/\\r\\n?/g, '\\n').split('\\n')\n const prompted = lines.some(line => PROMPT_LINE.test(line))\n const script = (prompted ? lines.filter(line => PROMPT_LINE.test(line)).map(line => line.replace(PROMPT_LINE, '')) : lines)\n .join('\\n')\n .trim()\n if (script === '')\n return null\n const commands = script.split('\\n').filter(line => line.trim() !== '' && !line.trim().startsWith('#'))\n if (commands.length === 0)\n return null\n return { script, shell: shellOf(language!), oneLine: commands.length === 1 && !commands[0]!.trimEnd().endsWith('\\\\') }\n}\n\n/** `text` as one single-quoted shell word. */\nfunction quote(text: string): string {\n return `'${text.replace(/'/g, `'\\\\''`)}'`\n}\n\n/** A here-document delimiter the script never holds as a line. */\nfunction delimiter(script: string): string {\n const lines = new Set(script.split('\\n'))\n let name = 'ZIDANE_BLOCK'\n for (let n = 1; lines.has(name); n++)\n name = `ZIDANE_BLOCK_${n}`\n return name\n}\n\n/** The lines that write `script` to a new temporary file, its path in `$f`. */\nfunction writeScript(script: string): string {\n const end = delimiter(script)\n return `f=$(mktemp \"\\${TMPDIR:-/tmp}/zidane-block.XXXXXX\") || exit 1\\ncat > \"$f\" <<'${end}'\\n${script}\\n${end}\\n`\n}\n\n/**\n * The command that runs a block in the session's folder, with no input, for Run here.\n *\n * @param plan - What runs ({@link shellBlockPlan}).\n */\nexport function blockRunCommand(plan: ShellBlockPlan): string {\n if (plan.oneLine)\n return `${plan.shell} -c ${quote(plan.script)} </dev/null`\n return `${writeScript(plan.script)}${plan.shell} \"$f\" </dev/null; code=$?; rm -f \"$f\"; exit $code`\n}\n\n/**\n * What is typed in a terminal to run a block there, ending with its Enter. The\n * command keeps the terminal's input, so it can ask for some.\n *\n * @param plan - What runs ({@link shellBlockPlan}).\n */\nexport function blockTerminalInput(plan: ShellBlockPlan): string {\n if (plan.oneLine)\n return `${plan.script}\\n`\n return `${writeScript(plan.script).replace(' || exit 1', '')}${plan.shell} \"$f\"; rm -f \"$f\"\\n`\n}\n\n/** What a window asks the host to run. */\nexport interface BlockRunRequest {\n /** The reply the block is in. */\n turnId: string\n /** The block's text. */\n code: string\n /** The fence's language. */\n language: string\n}\n\n/** The last run of a block, as the session keeps it. */\nexport interface BlockRun {\n /** {@link blockRunKey} of the block. */\n key: string\n /** The reply the block is in: a run whose reply is gone is dropped. */\n turnId: string\n /** What it wrote, stdout and stderr in arrival order, raw (ANSI codes kept): the last {@link BLOCK_RUN_OUTPUT_CAP} characters. */\n output: string\n /** Output was cut at its start. */\n truncated?: true\n /** `null` when it was stopped or could not start. */\n exitCode: number | null\n /** Why it ended early. */\n stopped?: 'cancelled' | 'timeout'\n /** How long it ran. */\n durationMs: number\n /** When it ended, epoch milliseconds. */\n finishedAt: number\n}\n\n/** FNV-1a of `text`, as 8 hex digits. */\nfunction hash(text: string): string {\n let h = 0x811C9DC5\n for (let i = 0; i < text.length; i++) {\n h ^= text.charCodeAt(i)\n h = Math.imul(h, 0x01000193)\n }\n return (h >>> 0).toString(16).padStart(8, '0')\n}\n\n/**\n * The key of a block's run: its reply and its code. An edited or regenerated\n * reply is a new turn, so its blocks start without a run. Two identical\n * blocks in one reply share their run.\n *\n * @param turnId - The reply the block is in.\n * @param code - The block's text.\n */\nexport function blockRunKey(turnId: string, code: string): string {\n return `${turnId}:${hash(code)}`\n}\n\nfunction isBlockRun(value: unknown): value is BlockRun {\n if (typeof value !== 'object' || value === null)\n return false\n const run = value as Record<string, unknown>\n return typeof run.key === 'string' && typeof run.turnId === 'string' && typeof run.output === 'string'\n && (run.exitCode === null || typeof run.exitCode === 'number') && typeof run.durationMs === 'number' && typeof run.finishedAt === 'number'\n}\n\n/**\n * The saved runs of a session, by key. What does not read as a run is left out.\n *\n * @param metadata - The session's metadata.\n */\nexport function readBlockRuns(metadata: Readonly<Record<string, unknown>> | undefined): Record<string, BlockRun> {\n const raw = metadata?.[BLOCK_RUNS_METADATA_KEY]\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw))\n return {}\n const runs: Record<string, BlockRun> = {}\n for (const [key, value] of Object.entries(raw)) {\n if (isBlockRun(value) && value.key === key)\n runs[key] = value\n }\n return runs\n}\n\n/**\n * The saved runs with `run` in, without runs whose reply is gone, at most\n * {@link BLOCK_RUNS_MAX} (the latest kept).\n *\n * @param runs - The saved runs.\n * @param run - The run to keep (it replaces the block's last one).\n * @param turnIds - The session's turns: a run whose reply is not among them is dropped.\n */\nexport function withBlockRun(runs: Readonly<Record<string, BlockRun>>, run: BlockRun, turnIds: ReadonlySet<string>): Record<string, BlockRun> {\n const kept = Object.values({ ...runs, [run.key]: run })\n .filter(entry => turnIds.has(entry.turnId))\n .sort((a, b) => b.finishedAt - a.finishedAt)\n .slice(0, BLOCK_RUNS_MAX)\n return Object.fromEntries(kept.map(entry => [entry.key, entry]))\n}\n\n/**\n * `output` cut to its last {@link BLOCK_RUN_OUTPUT_CAP} characters.\n *\n * @param output - What a run wrote.\n */\nexport function capBlockOutput(output: string): { output: string, truncated?: true } {\n return output.length > BLOCK_RUN_OUTPUT_CAP ? { output: output.slice(-BLOCK_RUN_OUTPUT_CAP), truncated: true } : { output }\n}\n","/**\n * The dev browser's automation contract: what the agent's `browser_*` tools\n * send, what the GUI (the process that owns the page) answers. Plain data\n * both ways, so it crosses the daemon socket and IPC unchanged.\n */\n\n/** A target on the page: a snapshot ref (preferred), a CSS selector / `text=` / `role=` locator, or a point. */\nexport interface BrowserTarget {\n /** Ref from the latest snapshot, such as `e12`. */\n ref?: string\n /** CSS selector, or a `text=` or `role=` locator. */\n selector?: string\n /** Viewport x coordinate in CSS pixels. Used with `y`. */\n x?: number\n /** Viewport y coordinate in CSS pixels. Used with `x`. */\n y?: number\n}\n\n/** Page load milestone a navigation waits for. `none` returns without waiting. */\nexport type BrowserWaitUntil = 'load' | 'domcontentloaded' | 'none'\n\n/** Input of each browser operation, keyed by operation name. */\nexport interface BrowserOpInputs {\n /** Opens the browser, optionally at a URL, and optionally shows its tab. */\n open: { url?: string, show?: boolean }\n /** Goes to a URL, or back, forward or reload. */\n navigate: { url?: string, action?: 'back' | 'forward' | 'reload', waitUntil?: BrowserWaitUntil, timeoutMs?: number }\n /** Reads the page. Takes no input. */\n snapshot: Record<string, never>\n /** Captures the viewport, or one element named by `ref`. */\n screenshot: { ref?: string }\n /** Clicks a target, waiting until it is actionable. */\n click: BrowserTarget & { timeoutMs?: number }\n /** Types text into a target, optionally clearing it first or submitting after. */\n type: BrowserTarget & { text: string, clear?: boolean, submit?: boolean, timeoutMs?: number }\n /** Presses a key with optional modifiers. */\n press: { key: string, modifiers?: ('Alt' | 'Control' | 'Meta' | 'Shift')[] }\n /** Scrolls the page or a target by `dx` and `dy` CSS pixels. */\n scroll: BrowserTarget & { dx?: number, dy?: number }\n /** Waits for text, a selector or a URL fragment to appear. */\n wait_for: { text?: string, selector?: string, urlIncludes?: string, timeoutMs?: number }\n /** Runs a JavaScript expression in the page. */\n evaluate: { expression: string }\n /** Reads console messages, optionally only newer than `since` and filtered by `level`. */\n console: { since?: number, level?: 'error' | 'warning' | 'all' }\n}\n\n/** Name of a browser operation. */\nexport type BrowserOp = keyof BrowserOpInputs\n\n/** Every browser operation name. */\nexport const BROWSER_OPS = [\n 'open',\n 'navigate',\n 'snapshot',\n 'screenshot',\n 'click',\n 'type',\n 'press',\n 'scroll',\n 'wait_for',\n 'evaluate',\n 'console',\n] as const satisfies readonly BrowserOp[]\n\n/** Where the page is: its URL, title and loading state. */\nexport interface BrowserStatus {\n /** Current page URL. */\n url: string\n /** Current page title. */\n title: string\n /** Whether the page is still loading. */\n loading: boolean\n /** Viewport size in CSS pixels, when known. */\n viewport?: { width: number, height: number }\n}\n\n/** What changed on the page because of an action; the agent reads this instead of re-snapshotting every step. */\nexport interface BrowserChange {\n /** The element acted on, by its accessible name (or tag when it has none). */\n target?: string\n /** Page URL after the action. */\n url?: string\n /** Page title after the action. */\n title?: string\n /** A JavaScript dialog the page opened, and what was done with it. */\n dialog?: { type: string, message: string, handled: 'accepted' | 'dismissed' }\n /** Console errors and failed requests since the action started. */\n errors?: string[]\n /** The page navigated or changed a lot: refs from the last snapshot may be gone. */\n refsStale?: boolean\n}\n\n/** One console message or failed request. */\nexport interface BrowserConsoleEntry {\n /** Sequence number, increasing per entry. */\n seq: number\n /** Severity of the message. */\n level: 'error' | 'warning' | 'info' | 'log' | 'debug'\n /** Message text. */\n text: string\n /** Set for failed network requests. */\n url?: string\n}\n\n/** A readable view of the page: status, element outline and visible text. */\nexport interface BrowserSnapshot {\n /** Where the page is. */\n status: BrowserStatus\n /** One line per interactive or landmark element, `[ref=eN]` on the ones you can act on. */\n outline: string\n /** Elements left out because of the cap. */\n truncated: number\n /** Visible page text, capped at {@link BROWSER_TEXT_MAX_CHARS} characters. */\n text: string\n /** Recent console errors and failed requests. */\n errors: string[]\n}\n\n/** A captured image of the viewport or of one element. */\nexport interface BrowserScreenshot {\n /** Base64 JPEG. */\n data: string\n /** MIME type of `data`. */\n mediaType: 'image/jpeg'\n /** Image width in pixels. */\n width: number\n /** Image height in pixels. */\n height: number\n /** Image pixels per CSS pixel: divide image coordinates by this to click. */\n scale: number\n}\n\n/** Result of each browser operation, keyed by operation name. */\nexport interface BrowserOpResults {\n /** Status after opening. */\n open: BrowserStatus\n /** Status after navigating. */\n navigate: BrowserStatus\n /** The page snapshot. */\n snapshot: BrowserSnapshot\n /** The captured image. */\n screenshot: BrowserScreenshot\n /** What the click changed. */\n click: BrowserChange\n /** What typing changed. */\n type: BrowserChange\n /** What the key press changed. */\n press: BrowserChange\n /** What scrolling changed, with the resulting scroll offsets. */\n scroll: BrowserChange & { scrollX?: number, scrollY?: number }\n /** Status once the wait condition held. */\n wait_for: BrowserStatus\n /** The value the expression produced. */\n evaluate: { value: unknown }\n /** Console entries and the cursor to pass as `since` next time. */\n console: { entries: BrowserConsoleEntry[], next: number }\n}\n\n/** Machine-readable reason a browser operation failed. */\nexport type BrowserErrorCode\n = | 'no_browser'\n | 'no_page'\n | 'stale_ref'\n | 'not_found'\n | 'not_actionable'\n | 'invalid_url'\n | 'invalid_input'\n | 'timeout'\n | 'interrupted'\n | 'cancelled'\n | 'too_large'\n | 'failed'\n\n/** A browser operation sent from the agent to the process that owns the page. */\nexport interface BrowserRequest<O extends BrowserOp = BrowserOp> {\n /** Id that pairs the response with this request. */\n requestId: string\n /** Session the operation belongs to. */\n sessionId: string\n /** Operation to run. */\n op: O\n /** Input for the operation. */\n input: BrowserOpInputs[O]\n /** Total time in ms the caller waits for the response. */\n timeoutMs: number\n}\n\n/** Answer to a {@link BrowserRequest}: the result, or an error code and message. */\nexport type BrowserResponse<O extends BrowserOp = BrowserOp>\n = | { ok: true, result: BrowserOpResults[O] }\n | { ok: false, error: { code: BrowserErrorCode, message: string } }\n\n/** Error thrown when a browser operation fails. `code` says why. */\nexport class BrowserOpError extends Error {\n /**\n * Creates a browser operation error.\n * @param code - Reason for the failure.\n * @param message - Human-readable description.\n */\n constructor(readonly code: BrowserErrorCode, message: string) {\n super(message)\n this.name = 'BrowserOpError'\n }\n}\n\n/** Default for an action's own wait (element to become actionable, text to appear). A request can raise it up to {@link BROWSER_MAX_WAIT_MS}. */\nexport const BROWSER_ACTION_TIMEOUT_MS = 5_000\n/** Default wait in ms for `wait_for`. */\nexport const BROWSER_WAIT_TIMEOUT_MS = 10_000\n/** Longest wait in ms an operation may request. */\nexport const BROWSER_MAX_WAIT_MS = 30_000\n/** How long the host waits for a page to mount and register before `open` gives up. */\nexport const BROWSER_OPEN_MOUNT_MS = 15_000\n/** Transport budget on top of the action's own wait. */\nexport const BROWSER_REQUEST_SLACK_MS = 5_000\n/** Largest serialized `evaluate` result in bytes. */\nexport const BROWSER_EVALUATE_MAX_BYTES = 64 * 1024\n/** Most elements listed in a snapshot outline. */\nexport const BROWSER_OUTLINE_MAX_ELEMENTS = 250\n/** Most page text characters in a snapshot. */\nexport const BROWSER_TEXT_MAX_CHARS = 8_000\n","/**\n * Entry actions on a folder's files: create a file or a folder, move\n * (rename), copy, remove, and import what was dropped from outside. Written\n * once over an `EntryPort` (`contexts/types.ts`): the desktop app's local\n * folders, a session's workspace in any execution context (a sandbox, a\n * container, a remote machine) and a server's sessions all run these same\n * rules; only the port differs (`contexts/entries.ts`).\n *\n * The rules: paths are relative to the folder, `/`-separated, never\n * absolute, never `.` / `..` / empty segments. Nothing is ever overwritten.\n * A create, move or rename onto a taken name is refused (`exists`); a copy\n * or an import takes the next free name (`a copy.ts`, `a copy 2.ts`).\n * Missing folders on the way are made. A folder never moves or copies into\n * itself. A rename that only changes case goes through a temporary name, so\n * it works on case-insensitive disks without replacing anything on others.\n *\n * Node-free (exported from `zidane/chat/pure` too): a browser builds the same\n * import over its own calls.\n */\nimport type { EntryKind, EntryPort } from '../../contexts/types'\n\nexport type { EntryKind, EntryPort } from '../../contexts/types'\n\n/** Why an entry action was refused. */\nexport type EntryRefusal\n /** The target name is taken. */\n = | 'exists'\n /** The source is gone. */\n | 'missing'\n /** Not a valid path or name, or a folder into itself, or a file where a folder must be. */\n | 'invalid'\n /** Out of bounds, unwritable, or the operation failed. */\n | 'denied'\n /** Over the import limits. */\n | 'too-large'\n\n/** What an entry action did: the path it ended at, or why it was refused. */\nexport type EntryResult\n = | { ok: true, path: string }\n | { ok: false, reason: EntryRefusal, message: string }\n\n/** Options of {@link EntryOps.create}. */\nexport interface EntryCreateOptions {\n /** A new file's bytes. Default: empty. */\n content?: Uint8Array\n /** Take the next free name (`a copy.ts`) when the name is taken, instead of refusing. */\n freeName?: boolean\n}\n\n/** The entry actions on one folder. Paths are relative to it; `''` is the folder itself. */\nexport interface EntryOps {\n /** Creates a file or a folder at `path`, making the folders on the way. */\n create: (path: string, kind: EntryKind, options?: EntryCreateOptions) => Promise<EntryResult>\n /** Moves (or renames) `from` to `to`, making the folders on the way. */\n move: (from: string, to: string) => Promise<EntryResult>\n /** Copies `from` into folder `toDir` under its name, or the next free one. */\n copy: (from: string, toDir: string) => Promise<EntryResult>\n /** Removes `path` (a folder whole). Where it goes (the trash, or nowhere) is the port's. */\n remove: (path: string) => Promise<EntryResult>\n}\n\n/** Most bytes one import brings in, all files together. */\nexport const ENTRY_IMPORT_MAX_BYTES = 50 * 1024 * 1024\n/** Most bytes of one imported file (one call over a connection). */\nexport const ENTRY_IMPORT_MAX_FILE_BYTES = 20 * 1024 * 1024\n/** Most entries one import brings in. */\nexport const ENTRY_IMPORT_MAX_ENTRIES = 5000\n/** Most empty folders a listing adds. */\nexport const ENTRY_EMPTY_DIRS_LIMIT = 2000\n\nconst MAX_NAME_BYTES = 255\n\n/**\n * `path` as the rules take it (no trailing `/`), or `null` when it is not a valid entry path.\n *\n * @param path - A path relative to the folder.\n * @param root - Whether `''` (the folder itself) is accepted.\n */\nexport function entryPath(path: string, root = false): string | null {\n if (typeof path !== 'string' || path.includes('\\0'))\n return null\n const trimmed = path.replace(/\\/+$/, '')\n if (trimmed === '')\n return root ? '' : null\n if (trimmed.startsWith('/'))\n return null\n const segments = trimmed.split('/')\n for (const segment of segments) {\n if (!segment || segment === '.' || segment === '..' || new TextEncoder().encode(segment).length > MAX_NAME_BYTES)\n return null\n }\n return trimmed\n}\n\n/**\n * The folder holding `path` (`''`: the root).\n *\n * @param path - A path relative to the workspace.\n */\nexport function entryParent(path: string): string {\n const at = path.lastIndexOf('/')\n return at < 0 ? '' : path.slice(0, at)\n}\n\n/**\n * The last segment of `path`.\n *\n * @param path - A path relative to the workspace.\n */\nexport function entryName(path: string): string {\n return path.slice(path.lastIndexOf('/') + 1)\n}\n\n/**\n * `name` in folder `dir`.\n *\n * @param dir - The folder (`''`: the root).\n * @param name - The entry's name.\n */\nexport function joinEntry(dir: string, name: string): string {\n return dir ? `${dir}/${name}` : name\n}\n\n/**\n * The names a copy of `name` tries, in order: itself, `a copy.ts`, `a copy 2.ts`, …\n * (a folder or a dotfile keeps no extension apart).\n *\n * @param name - The name to copy.\n * @param kind - A file or a folder: only a file keeps its extension at the end.\n */\nexport function* copyNames(name: string, kind: EntryKind): Generator<string> {\n const dot = kind === 'file' ? name.lastIndexOf('.') : -1\n const stem = dot > 0 ? name.slice(0, dot) : name\n const ext = dot > 0 ? name.slice(dot) : ''\n yield name\n yield `${stem} copy${ext}`\n for (let n = 2; ; n++)\n yield `${stem} copy ${n}${ext}`\n}\n\n/**\n * The first free name for `name` in folder `dir`, compared without case (a\n * case-insensitive disk sees `A.ts` and `a.ts` as one).\n *\n * @param port - The folder's port.\n * @param dir - Where the entry goes.\n * @param name - The name it would like.\n * @param kind - What it is (a file keeps its extension last).\n */\nexport async function freeEntryName(port: Pick<EntryPort, 'list'>, dir: string, name: string, kind: EntryKind): Promise<string> {\n const taken = new Set((await port.list(dir === '' ? '.' : dir).catch(() => [] as string[])).map(n => n.toLowerCase()))\n let tries = 0\n for (const candidate of copyNames(name, kind)) {\n if (!taken.has(candidate.toLowerCase()) || ++tries > 10_000)\n return candidate\n }\n return name\n}\n\nfunction refused(reason: EntryRefusal, message: string): EntryResult {\n return { ok: false, reason, message }\n}\n\n/** A port error as a refusal (its errno when it has one). */\nfunction failure(error: unknown): EntryResult {\n const code = (error as { code?: unknown })?.code\n const message = error instanceof Error ? error.message : String(error)\n if (code === 'EEXIST' || code === 'ENOTEMPTY' || /already exists/i.test(message))\n return refused('exists', message)\n if (code === 'ENOENT')\n return refused('missing', message)\n return refused('denied', message)\n}\n\n/**\n * The entry actions over `port`, whose paths are relative to the folder (the\n * caller's port maps them where they live).\n *\n * @param port - The folder's file operations.\n */\nexport function createEntryOps(port: EntryPort): EntryOps {\n const at = (path: string): string => (path === '' ? '.' : path)\n const stat = (path: string) => port.stat(at(path))\n\n /** Folder `dir` exists (made when missing); a refusal when a file holds its place. */\n const ensureFolder = async (dir: string): Promise<EntryResult | null> => {\n if (dir === '')\n return null\n const kind = await stat(dir)\n if (kind === 'file')\n return refused('invalid', `${dir} is a file, not a folder.`)\n if (kind === null)\n await port.mkdir(dir)\n return null\n }\n\n /** Whether `to`, taken, is only `from` under another case (a case-insensitive disk). */\n const sameEntryOtherCase = async (from: string, to: string): Promise<boolean> => {\n if (from === to || from.toLowerCase() !== to.toLowerCase())\n return false\n const names = await port.list(at(entryParent(to)))\n return !names.includes(entryName(to)) && names.includes(entryName(from))\n }\n\n const guarded = (action: () => Promise<EntryResult>): Promise<EntryResult> => action().catch(failure)\n\n return {\n create: (raw, kind, options = {}) => guarded(async () => {\n const path = entryPath(raw)\n if (path === null)\n return refused('invalid', `\"${raw}\" is not a valid name.`)\n const dir = entryParent(path)\n const blocked = await ensureFolder(dir)\n if (blocked)\n return blocked\n const target = options.freeName ? joinEntry(dir, await freeEntryName(port, dir, entryName(path), kind)) : path\n if (!options.freeName && (await stat(target)) !== null)\n return refused('exists', `${target} already exists.`)\n if (kind === 'dir')\n await port.mkdir(target)\n else\n await port.write(target, options.content ?? new Uint8Array())\n return { ok: true, path: target }\n }),\n\n move: (rawFrom, rawTo) => guarded(async () => {\n const from = entryPath(rawFrom)\n const to = entryPath(rawTo)\n if (from === null || to === null)\n return refused('invalid', `\"${from === null ? rawFrom : rawTo}\" is not a valid name.`)\n if (from === to)\n return { ok: true, path: to }\n const kind = await stat(from)\n if (kind === null)\n return refused('missing', `${from} is gone.`)\n if (to.startsWith(`${from}/`))\n return refused('invalid', `${from} can't move into itself.`)\n const blocked = await ensureFolder(entryParent(to))\n if (blocked)\n return blocked\n if ((await stat(to)) !== null) {\n if (!(await sameEntryOtherCase(from, to)))\n return refused('exists', `${to} already exists.`)\n // A case-only rename: through a free temporary name, so nothing is replaced.\n const step = joinEntry(entryParent(to), await freeEntryName(port, entryParent(to), `.${entryName(to)}.renaming`, kind))\n await port.move(from, step)\n await port.move(step, to)\n return { ok: true, path: to }\n }\n await port.move(from, to)\n return { ok: true, path: to }\n }),\n\n copy: (rawFrom, rawDir) => guarded(async () => {\n const from = entryPath(rawFrom)\n const dir = entryPath(rawDir, true)\n if (from === null || dir === null)\n return refused('invalid', `\"${from === null ? rawFrom : rawDir}\" is not a valid name.`)\n const kind = await stat(from)\n if (kind === null)\n return refused('missing', `${from} is gone.`)\n if (kind === 'dir' && (dir === from || dir.startsWith(`${from}/`)))\n return refused('invalid', `${from} can't be copied into itself.`)\n const blocked = await ensureFolder(dir)\n if (blocked)\n return blocked\n const target = joinEntry(dir, await freeEntryName(port, dir, entryName(from), kind))\n await port.copy(from, target)\n return { ok: true, path: target }\n }),\n\n remove: raw => guarded(async () => {\n const path = entryPath(raw)\n if (path === null)\n return refused('invalid', `\"${raw}\" is not a valid name.`)\n if ((await stat(path)) === null)\n return refused('missing', `${path} is gone.`)\n await port.remove(path)\n return { ok: true, path }\n }),\n }\n}\n\n/** One thing dropped from outside: a file (read when its turn comes) or a folder. */\nexport type EntryImportItem\n = | { name: string, size: number, read: () => Promise<Uint8Array> }\n | { name: string, children: EntryImportItem[] }\n\n/** What an import did: the top-level paths it made, and why it stopped when it did. */\nexport type EntryImportResult\n = | { ok: true, paths: string[] }\n | { ok: false, reason: EntryRefusal, message: string, paths: string[] }\n\n/** Limits of {@link importEntries}. */\nexport interface EntryImportLimits {\n /** All files together. Default {@link ENTRY_IMPORT_MAX_BYTES}. */\n maxBytes?: number\n /** One file. Default {@link ENTRY_IMPORT_MAX_FILE_BYTES}. */\n maxFileBytes?: number\n /** Entries (files and folders). Default {@link ENTRY_IMPORT_MAX_ENTRIES}. */\n maxEntries?: number\n}\n\n/**\n * Brings `items` into folder `dir` through `create` (one call per entry, so\n * no call carries more than one file): each top-level item takes a free name,\n * what is inside a dropped folder keeps its own. The limits are checked\n * before anything is written; a failure on the way stops the import and says\n * what was made.\n *\n * @param create - The folder's create (local, or over a connection).\n * @param dir - The folder to import into (`''`: the root).\n * @param items - What was dropped.\n * @param limits - Size and count limits.\n */\nexport async function importEntries(\n create: EntryOps['create'],\n dir: string,\n items: readonly EntryImportItem[],\n limits: EntryImportLimits = {},\n): Promise<EntryImportResult> {\n const maxBytes = limits.maxBytes ?? ENTRY_IMPORT_MAX_BYTES\n const maxFileBytes = limits.maxFileBytes ?? ENTRY_IMPORT_MAX_FILE_BYTES\n const maxEntries = limits.maxEntries ?? ENTRY_IMPORT_MAX_ENTRIES\n let bytes = 0\n let entries = 0\n let largest: { name: string, size: number } | null = null\n const measure = (list: readonly EntryImportItem[]): void => {\n for (const item of list) {\n entries++\n if ('children' in item) {\n measure(item.children)\n continue\n }\n bytes += item.size\n if (!largest || item.size > largest.size)\n largest = { name: item.name, size: item.size }\n }\n }\n measure(items)\n const mb = (n: number) => `${Math.round(n / (1024 * 1024))} MB`\n const big = largest as { name: string, size: number } | null\n if (big && big.size > maxFileBytes)\n return { ok: false, reason: 'too-large', message: `${big.name} is over ${mb(maxFileBytes)}.`, paths: [] }\n if (bytes > maxBytes)\n return { ok: false, reason: 'too-large', message: `The files are over ${mb(maxBytes)} together.`, paths: [] }\n if (entries > maxEntries)\n return { ok: false, reason: 'too-large', message: `That is over ${maxEntries} files and folders.`, paths: [] }\n\n const paths: string[] = []\n const bring = async (item: EntryImportItem, path: string, freeName: boolean): Promise<EntryResult> => {\n const made = 'children' in item\n ? await create(path, 'dir', { freeName })\n : await create(path, 'file', { freeName, content: await item.read() })\n if (!made.ok || !('children' in item))\n return made\n for (const child of item.children) {\n const inner = await bring(child, joinEntry(made.path, child.name), false)\n if (!inner.ok)\n return inner\n }\n return made\n }\n for (const item of items) {\n if (entryPath(item.name) === null || item.name.includes('/'))\n return { ok: false, reason: 'invalid', message: `\"${item.name}\" is not a valid name.`, paths }\n let made: EntryResult\n try {\n made = await bring(item, joinEntry(dir, item.name), true)\n }\n catch (error) {\n made = failure(error)\n }\n if (!made.ok)\n return { ...made, paths }\n paths.push(made.path)\n }\n return { ok: true, paths }\n}\n","/**\n * Terminals: the contract between the host that runs them (the daemon) and\n * the clients that show them (the GUI's drawer and panel tab). Pure types\n * and limits, safe for a renderer bundle.\n *\n * Output travels as text with a running character offset: a client knows\n * where each chunk starts, drops what it already has, and acknowledges what\n * it wrote. The host stops sending to clients that fall a window behind and\n * later resets them from history instead of queueing without end.\n */\n\n/** Who started it: the user, or the agent (a background `shell` task). */\nexport type TerminalOwner = 'user' | 'agent'\n\n/** Where it runs: the session's environment, or this machine in the project. */\nexport type TerminalTarget = 'session' | 'local'\n\n/**\n * `paused`: not connected right now (the sandbox paused, or the host\n * restarted) but it can be found again; opening it reconnects.\n */\nexport type TerminalStatus = 'starting' | 'running' | 'paused' | 'exited' | 'error'\n\n/**\n * A terminal not bound to a session: a plain shell on the host's machine, in\n * a project's folder (docs/PROJECT-SCOPE-AUDIT.md). `draftId` ties it to a\n * new-chat draft until `terminal.adopt` hands it to the session created from\n * that draft (or `terminal.releaseDraft` gives it back to the project).\n * Agents never see unbound terminals.\n */\nexport interface TerminalProjectScope {\n /** Project root (`projectRootOf`, computed by the host). */\n root: string\n /** New-chat draft the terminal is tied to. Absent: the terminal belongs to the project. */\n draftId?: string\n}\n\n/** Description of one terminal, as the host reports it to clients. */\nexport interface TerminalInfo {\n /** Terminal id. */\n id: string\n /** The session it belongs to; `''` for a project / draft terminal (see `scope`). */\n sessionId: string\n /** Set on project / draft terminals (`sessionId` is `''`). */\n scope?: TerminalProjectScope\n /** Stable name (\"Terminal 2\", or the agent's command). */\n label: string\n /** Title the program set (OSC 0/2), if any. */\n title?: string\n /** The program in the foreground, for terminals on this machine. */\n program?: string\n /** Who started the terminal. */\n owner: TerminalOwner\n /** Where the terminal runs. */\n target: TerminalTarget\n /** Environment kind it runs in (`local`, `worktree`, `docker`, `e2b`, …). */\n environment: string\n /** Working directory the terminal started in. */\n cwd: string\n /** Connection and process state. */\n status: TerminalStatus\n /** Exit code, once the process has exited. */\n exitCode?: number\n /** Failure message, when `status` is `error`. */\n error?: string\n /** Width in character cells. */\n cols: number\n /** Height in character cells. */\n rows: number\n /**\n * Bumped on every size change: signals and attach replies reach a view by\n * different routes, so it keeps the newest size, not the last to arrive.\n */\n sizeSeq: number\n /** The agent's terminal tools skip it. */\n hiddenFromAgent: boolean\n /** The background task it runs (agent terminals). */\n taskId?: string\n /** Creation time in epoch ms. */\n createdAt: number\n /** Time of the last output or input in epoch ms. */\n lastActivityAt: number\n}\n\n/** The terminals of one session and whether this host can run them. */\nexport interface TerminalSessionState {\n /** False when this host can't run terminals (the GUI without the daemon). */\n available: boolean\n /** Why not, when `available` is false. */\n reason?: string\n /** Kind of the session's environment, and whether it runs somewhere else. */\n environment: { kind: string, remote: boolean }\n /** Terminals of the session. */\n terminals: TerminalInfo[]\n}\n\n/** Opens a terminal in a session. */\nexport interface TerminalOpenInput {\n /** Session to open the terminal in. */\n sessionId: string\n /** Where to run it. @default 'session' */\n target?: TerminalTarget\n /** Initial width in character cells. */\n cols: number\n /** Initial height in character cells. */\n rows: number\n}\n\n/** Opens a project / draft terminal: a shell on the host's machine in `cwd`. */\nexport interface TerminalProjectOpenInput {\n /** Folder of the project. The shell starts here. */\n cwd: string\n /** New-chat draft to tie the terminal to. Absent: the terminal belongs to the project. */\n draftId?: string\n /** Initial width in character cells. */\n cols: number\n /** Initial height in character cells. */\n rows: number\n}\n\n/**\n * The terminals of a project (`draftId` absent) or of one draft. `cwd` is any\n * folder of the project; the host resolves its root.\n */\nexport interface TerminalProjectStateInput {\n /** Any folder of the project. */\n cwd: string\n /** Draft to list the terminals of. Absent: the project's terminals. */\n draftId?: string\n}\n\n/** The terminals of a project or of one draft, and whether this host can run them. */\nexport interface TerminalProjectState {\n /** False when this host cannot run terminals. */\n available: boolean\n /** Why not, when `available` is false. */\n reason?: string\n /** The resolved project root (what `terminal:project-changed` names). */\n root: string\n /** Terminals of the project or draft. */\n terminals: TerminalInfo[]\n}\n\n/** What `terminal.adopt` moved into the session (ids), and what it could not. */\nexport interface TerminalAdoptResult {\n /** Ids of the terminals moved into the session. */\n adopted: string[]\n /** Over the per-scope cap: left in the project. */\n skipped: string[]\n}\n\n/** What a client needs to start showing a terminal: its history, and where live output resumes. */\nexport interface TerminalAttachResult {\n /** The terminal that was attached. */\n terminal: TerminalInfo\n /** Output history to show first. */\n data: string\n /** Character offset where live output resumes. */\n offset: number\n}\n\n/** The agent's view: plain text lines, with a cursor for the next read. */\nexport interface TerminalReadResult {\n /** The terminal that was read. */\n terminal: TerminalInfo\n /** Plain-text output. */\n text: string\n /** Pass as `since` to get only newer lines. */\n next: number\n /** Lines dropped from the front because of the size cap. */\n truncated: number\n}\n\n/** Characters a client may be behind before the host stops sending to it. */\nexport const TERMINAL_OUTPUT_WINDOW = 256 * 1024\n/** History kept per terminal for new views (characters). */\nexport const TERMINAL_HISTORY_MAX_CHARS = 4 * 1024 * 1024\n/** Scrollback lines a desktop terminal view keeps (each mounted view holds its own). */\nexport const TERMINAL_VIEW_SCROLLBACK = 5_000\n/**\n * Lines a desktop view can show (its scrollback, plus a screen of up to\n * 1000 rows): what it asks `terminal.attach` for (`maxLines`) and what it\n * keeps of the output it drew.\n */\nexport const TERMINAL_VIEW_MAX_LINES = TERMINAL_VIEW_SCROLLBACK + 1000\n/** Plain-text lines kept per terminal for the agent. */\nexport const TERMINAL_TEXT_MAX_LINES = 5000\n/** Most the agent gets from one read (characters). */\nexport const TERMINAL_READ_MAX_CHARS = 16 * 1024\n/** Terminals a session, a project or a draft may have open at once (user terminals). */\nexport const TERMINAL_MAX_PER_SCOPE = 12\n/**\n * Terminals a session, a project or a draft may have open at once.\n * @deprecated Use {@link TERMINAL_MAX_PER_SCOPE}.\n */\nexport const TERMINAL_MAX_PER_SESSION = TERMINAL_MAX_PER_SCOPE\n\n/** Error thrown by terminal operations. `code` says why. */\nexport class TerminalError extends Error {\n /**\n * Creates a terminal error.\n * @param code - Reason for the failure.\n * @param message - Human-readable description.\n */\n constructor(readonly code: 'unavailable' | 'not_found' | 'limit' | 'not_running' | 'failed', message: string) {\n super(message)\n this.name = 'TerminalError'\n }\n}\n","/**\n * Terminal modes followed from a program's output: the DEC private modes\n * that outlive the output that set them (mouse tracking, cursor keys,\n * bracketed paste, the alternate screen) and the application keypad. A\n * replay that starts after the sequences that set them writes\n * {@link modePrefix} first, so the replaying terminal ends in the same state.\n * Pure, so the host (snapshots, mouse filtering) and the desktop app's views\n * read the same rules.\n */\n\n/** DEC private modes worth restoring: input modes and screen state that outlive the output that set them. */\nconst TRACKED_MODES = new Set([1, 7, 9, 12, 25, 47, 1000, 1002, 1003, 1004, 1005, 1006, 1015, 1016, 1047, 1049, 2004])\n/** On in a fresh terminal (autowrap, visible cursor): only a reset is worth replaying. */\nconst DEFAULT_ON = new Set([7, 25])\nconst ALT_MODES = [47, 1047, 1049]\n/** Modes that turn mouse reporting on: X10, normal, button-event, any-event. */\nconst MOUSE_MODES = [9, 1000, 1002, 1003]\n\n/** The terminal modes a program's output has left set, as {@link scanModes} follows them. */\nexport interface ModeState {\n /** DEC private modes last set (true) or reset (false). */\n readonly modes: ReadonlyMap<number, boolean>\n /** Application keypad (`ESC =`), when it was set or reset. */\n readonly keypad: boolean | null\n /** Stream offset of the sequence that entered the alternate screen, while it is active. */\n readonly altAt: number | null\n}\n\n/** The modes of a fresh terminal: nothing set or reset yet. */\nexport const EMPTY_MODES: ModeState = { modes: new Map(), keypad: null, altAt: null }\n\n// eslint-disable-next-line no-control-regex\nconst SEQUENCE = /\\x1B(?:\\[\\?([0-9;]*)([hl])|([=>c]))/g\n// eslint-disable-next-line no-control-regex\nconst PREFIX = /^(?:\\x1B\\[\\?\\d+[hl]|\\x1B=)*/\n\nconst altActive = (modes: ReadonlyMap<number, boolean>) => ALT_MODES.some(m => modes.get(m) === true)\n\n/**\n * The mode state after `text`, which starts at stream offset `base`. Returns `state` itself when nothing changed.\n *\n * @param state - The modes before `text`.\n * @param text - Program output to scan.\n * @param base - Stream offset of `text`'s first character, recorded in `altAt`.\n */\nexport function scanModes(state: ModeState, text: string, base: number): ModeState {\n if (!text.includes('\\x1B'))\n return state\n let next = state\n let modes: Map<number, boolean> | null = null\n SEQUENCE.lastIndex = 0\n for (let m = SEQUENCE.exec(text); m; m = SEQUENCE.exec(text)) {\n if (m[3] === 'c') {\n next = EMPTY_MODES\n modes = null\n continue\n }\n if (m[3]) {\n const keypad = m[3] === '='\n if (next.keypad !== keypad)\n next = { ...next, keypad }\n continue\n }\n const on = m[2] === 'h'\n const wasAlt = next.altAt !== null\n for (const p of m[1]!.split(';')) {\n const mode = Number(p)\n if (!TRACKED_MODES.has(mode) || next.modes.get(mode) === on)\n continue\n if (!modes) {\n modes = new Map(next.modes)\n next = { ...next, modes }\n }\n modes.set(mode, on)\n }\n if (modes && next.modes === modes) {\n const alt = altActive(modes)\n if (alt !== wasAlt)\n next = { ...next, altAt: alt ? base + m.index : null }\n }\n }\n return next\n}\n\n/**\n * Sequences that put a fresh terminal in `state`'s modes.\n *\n * @param state - The modes to restore.\n */\nexport function modePrefix(state: ModeState): string {\n let out = ''\n for (const [mode, on] of state.modes) {\n if (on !== DEFAULT_ON.has(mode))\n out += `\\x1B[?${mode}${on ? 'h' : 'l'}`\n }\n if (state.keypad)\n out += '\\x1B='\n return out\n}\n\n/**\n * Length of the mode sequences `text` starts with: at least the\n * {@link modePrefix} put in front of a snapshot. Output that itself starts\n * with mode sequences counts too, so this errs towards less output, never more.\n *\n * @param text - A replay that may start with a mode prefix.\n */\nexport function modePrefixLength(text: string): number {\n return PREFIX.exec(text)![0].length\n}\n\n/**\n * Whether the program asked for mouse reports.\n *\n * @param state - The modes to check.\n */\nexport function isMouseTracking(state: ModeState): boolean {\n return MOUSE_MODES.some(m => state.modes.get(m) === true)\n}\n","/**\n * A terminal's output kept by stream offset, so it can be replayed into a\n * fresh terminal (a view attaching, a view rebuilding its grid, a reset)\n * without replaying more than that terminal can hold. The host keeps one per\n * terminal for attaches and resets; each desktop view keeps one of what it\n * drew. Pure, safe for a renderer bundle.\n *\n * Chunks are stored in a head-indexed array, capped by characters (and,\n * optionally, by lines). A replay keeps only the last lines asked for (or the\n * last characters), cut right after a newline or right before an escape\n * sequence, so no sequence or surrogate pair is split. Cutting drops the\n * sequences that set up a running program (mouse tracking, cursor keys,\n * bracketed paste, the alternate screen), so the modes in force at the cut\n * are tracked per chunk and replayed first. A program still on the\n * alternate screen is replayed from where it entered it: it only repaints\n * what changes, so a tail of its output would leave the screen half drawn.\n */\nimport type { ModeState } from '../../contexts/terminal-modes'\nimport { EMPTY_MODES, modePrefix, scanModes } from '../../contexts/terminal-modes'\n\nexport type { ModeState } from '../../contexts/terminal-modes'\nexport { EMPTY_MODES, isMouseTracking, modePrefix, modePrefixLength, scanModes } from '../../contexts/terminal-modes'\n\n/** A sequence split across chunks is shorter than this: the tail after the last ESC is rescanned with the next chunk. */\nconst CARRY_MAX = 32\n\n/**\n * End of a slice of at most `size` chars from `from`, never between the halves of a surrogate pair.\n *\n * @param text - The text being sliced.\n * @param from - Index the slice starts at.\n * @param size - Most characters the slice may hold (at least one is taken).\n */\nexport function sliceEnd(text: string, from: number, size: number): number {\n const end = Math.min(text.length, from + Math.max(1, size))\n if (end < text.length && end - from > 1) {\n const code = text.charCodeAt(end - 1)\n if (code >= 0xD800 && code <= 0xDBFF)\n return end - 1\n }\n return end\n}\n\nfunction countLines(text: string): number {\n let n = 0\n for (let i = text.indexOf('\\n'); i !== -1; i = text.indexOf('\\n', i + 1)) n++\n return n\n}\n\ninterface Chunk {\n /** Stream offset of `data[0]`. */\n readonly at: number\n readonly data: string\n /** Modes in force before this chunk (its `carry` not yet applied). */\n readonly before: ModeState\n /** Unfinished sequence at the end of the previous chunk, scanned with this one. */\n readonly carry: string\n /** Starts a line (the previous chunk ended with a newline, or nothing came before): a replay can start here. */\n readonly clean: boolean\n /** Newlines in `data`, counted only under a line cap. */\n readonly lines: number\n}\n\n/** Optional caps for an {@link OutputHistory}. */\nexport interface OutputHistoryOptions {\n /**\n * Also evict once more than this many lines are kept, except while the\n * program is on the alternate screen (a replay needs all of it).\n */\n maxLines?: number\n}\n\n/** One terminal's output by stream offset, capped, replayable into a fresh terminal with its modes. */\nexport class OutputHistory {\n private chunks: Chunk[] = []\n private head = 0\n private chars = 0\n private lineCount = 0\n private state: ModeState = EMPTY_MODES\n private carry = ''\n private clean = true\n private readonly maxLines: number\n /** Stream offset after the last chunk. */\n end = 0\n\n /**\n * @param maxChars - Evict the oldest chunks once more characters than this are kept (the newest chunk always stays).\n * @param options - Further caps.\n */\n constructor(private readonly maxChars: number, options: OutputHistoryOptions = {}) {\n this.maxLines = options.maxLines ?? Infinity\n }\n\n /** Stream offset of the oldest character kept. */\n get start(): number {\n return this.head < this.chunks.length ? this.chunks[this.head]!.at : this.end\n }\n\n /** Characters kept. */\n get size(): number {\n return this.chars\n }\n\n /** Modes in force after everything pushed (an unfinished trailing sequence not yet applied). */\n get modes(): ModeState {\n return this.state\n }\n\n /**\n * Start over with `data`, which ends at stream offset `end` (a re-attach).\n *\n * @param end - Stream offset right after `data`.\n * @param data - The output to start from.\n */\n reset(end: number, data: string): void {\n this.chunks = []\n this.head = 0\n this.chars = 0\n this.lineCount = 0\n this.state = EMPTY_MODES\n this.carry = ''\n this.clean = true\n this.end = end - data.length\n this.push(data)\n }\n\n /**\n * Append output at the current end, then evict past the caps.\n *\n * @param data - The next output, continuing at {@link OutputHistory.end}.\n */\n push(data: string): void {\n if (!data)\n return\n const at = this.end\n const carry = this.carry\n const scanned = carry + data\n const lines = this.maxLines === Infinity ? 0 : countLines(data)\n this.chunks.push({ at, data, before: this.state, carry, clean: this.clean, lines })\n this.state = scanModes(this.state, scanned, at - carry.length)\n const esc = scanned.lastIndexOf('\\x1B')\n this.carry = esc >= 0 && scanned.length - esc < CARRY_MAX ? scanned.slice(esc) : ''\n this.clean = data.endsWith('\\n')\n this.end = at + data.length\n this.chars += data.length\n this.lineCount += lines\n while (this.chunks.length - this.head > 1 && this.overCap()) {\n const evicted = this.chunks[this.head]!\n this.chars -= evicted.data.length\n this.lineCount -= evicted.lines\n this.head++\n }\n // Drop evicted slots once they are most of the array: amortized O(1) per push.\n if (this.head > 64 && this.head * 2 > this.chunks.length) {\n this.chunks = this.chunks.slice(this.head)\n this.head = 0\n }\n }\n\n /**\n * Text kept between stream offsets `from` and `to`.\n *\n * @param from - Start offset, clamped to {@link OutputHistory.start}.\n * @param to - End offset, clamped to {@link OutputHistory.end}.\n */\n text(from = this.start, to = this.end): string {\n from = Math.max(from, this.start)\n to = Math.min(to, this.end)\n if (from >= to)\n return ''\n const parts: string[] = []\n for (let i = this.find(from); i < this.chunks.length; i++) {\n const c = this.chunks[i]!\n if (c.at >= to)\n break\n parts.push(c.at >= from && c.at + c.data.length <= to ? c.data : c.data.slice(from - c.at, to - c.at))\n }\n return parts.join('')\n }\n\n /**\n * What rebuilds the terminal's state up to stream offset `upTo`, keeping\n * about the last `lines` lines and at most `maxChars` characters of\n * output: the modes in force at the cut, then the output from there.\n *\n * @param lines - About how many trailing lines to keep (`Infinity` for all).\n * @param upTo - Stream offset to replay up to, clamped to {@link OutputHistory.end}.\n * @param maxChars - Most characters of output to replay.\n */\n replay(lines: number, upTo = this.end, maxChars = Infinity): string {\n upTo = Math.min(upTo, this.end)\n const floor = this.safeFrom(this.start, upTo)\n const from = upTo - maxChars > floor ? this.safeFrom(upTo - maxChars, upTo) : floor\n const cut = this.lineCut(from, upTo, lines)\n const state = this.stateAt(cut)\n if (state.altAt === null || state.altAt <= from || cut === from)\n return modePrefix(state) + this.text(cut, upTo)\n // Still on the alternate screen: the primary screen up to it, trimmed, then everything since it was entered.\n const altAt = state.altAt\n const primaryCut = this.lineCut(from, altAt, lines)\n return modePrefix(this.stateAt(primaryCut)) + this.text(primaryCut, altAt) + this.text(altAt, upTo)\n }\n\n private overCap(): boolean {\n if (this.chars > this.maxChars)\n return true\n return this.lineCount - this.chunks[this.head]!.lines > this.maxLines && this.state.altAt === null\n }\n\n /** Index of the chunk holding stream offset `offset` (the first kept one when it is older). */\n private find(offset: number): number {\n let lo = this.head\n let hi = this.chunks.length - 1\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1\n if (this.chunks[mid]!.at <= offset)\n lo = mid\n else hi = mid - 1\n }\n return lo\n }\n\n /**\n * The first offset from `offset` on (before `to`) where a replay can start:\n * a chunk that starts a line, right after a newline, or right before an\n * ESC. With none, `offset` itself, moved off the second half of a surrogate pair.\n */\n private safeFrom(offset: number, to: number): number {\n if (this.head >= this.chunks.length || offset >= to)\n return offset\n for (let i = this.find(offset); i < this.chunks.length; i++) {\n const c = this.chunks[i]!\n if (c.at >= to)\n break\n if (c.at >= offset && c.clean)\n return c.at\n const from = Math.max(0, offset - c.at)\n if (from > 0 && c.data.charCodeAt(from - 1) === 10)\n return offset\n const nl = c.data.indexOf('\\n', from)\n const esc = c.data.indexOf('\\x1B', from)\n const found = Math.min(nl === -1 ? Infinity : nl + 1, esc === -1 ? Infinity : esc)\n if (found !== Infinity)\n return c.at + found < to ? c.at + found : this.offSurrogate(offset)\n }\n return this.offSurrogate(offset)\n }\n\n private offSurrogate(offset: number): number {\n const c = this.chunks[this.find(offset)]!\n const code = c.data.charCodeAt(offset - c.at)\n return code >= 0xDC00 && code <= 0xDFFF ? offset + 1 : offset\n }\n\n /** Stream offset where the last `lines` lines before `to` start (just after a newline), or `from` when there are fewer. */\n private lineCut(from: number, to: number, lines: number): number {\n if (lines <= 0 || to <= from)\n return Math.max(from, to)\n if (lines === Infinity)\n return from\n let left = lines\n for (let i = this.find(to - 1); i >= this.head; i--) {\n const c = this.chunks[i]!\n if (c.at + c.data.length <= from)\n break\n let idx = Math.min(c.data.length, to - c.at)\n const floor = Math.max(0, from - c.at)\n while (idx > floor) {\n const nl = c.data.lastIndexOf('\\n', idx - 1)\n if (nl < floor)\n break\n // The newline ending the text ends its last line; it does not start another.\n if (c.at + nl + 1 < to && --left === 0)\n return c.at + nl + 1\n idx = nl\n }\n }\n return from\n }\n\n private stateAt(offset: number): ModeState {\n if (this.head >= this.chunks.length)\n return this.state\n const i = this.find(offset)\n const c = this.chunks[i]!\n const head = c.data.slice(0, Math.max(0, offset - c.at))\n return scanModes(c.before, c.carry + head, c.at - c.carry.length)\n }\n}\n","/**\n * Media a page shows in place of \"Binary file\": the formats a browser decodes\n * on its own, by file extension. Anything else stays binary.\n */\n/** What a media file is played as. */\nexport type MediaKind = 'image' | 'video' | 'audio' | 'pdf'\n\n/** A media file's kind and MIME type. */\nexport interface MediaType {\n /** How it plays. */\n kind: MediaKind\n /** Its MIME type. */\n mime: string\n}\n\n/** The media types by lowercase file extension. */\nexport const MEDIA_BY_EXTENSION: Readonly<Record<string, MediaType>> = {\n png: { kind: 'image', mime: 'image/png' },\n jpg: { kind: 'image', mime: 'image/jpeg' },\n jpeg: { kind: 'image', mime: 'image/jpeg' },\n gif: { kind: 'image', mime: 'image/gif' },\n webp: { kind: 'image', mime: 'image/webp' },\n avif: { kind: 'image', mime: 'image/avif' },\n svg: { kind: 'image', mime: 'image/svg+xml' },\n bmp: { kind: 'image', mime: 'image/bmp' },\n ico: { kind: 'image', mime: 'image/x-icon' },\n mp4: { kind: 'video', mime: 'video/mp4' },\n m4v: { kind: 'video', mime: 'video/mp4' },\n webm: { kind: 'video', mime: 'video/webm' },\n ogv: { kind: 'video', mime: 'video/ogg' },\n mov: { kind: 'video', mime: 'video/quicktime' },\n mp3: { kind: 'audio', mime: 'audio/mpeg' },\n wav: { kind: 'audio', mime: 'audio/wav' },\n ogg: { kind: 'audio', mime: 'audio/ogg' },\n oga: { kind: 'audio', mime: 'audio/ogg' },\n m4a: { kind: 'audio', mime: 'audio/mp4' },\n flac: { kind: 'audio', mime: 'audio/flac' },\n pdf: { kind: 'pdf', mime: 'application/pdf' },\n}\n\n/**\n * The media a path names, by its extension; `null` for everything else.\n *\n * @param path - A file path.\n */\nexport function mediaTypeOfPath(path: string): MediaType | null {\n const name = path.slice(path.lastIndexOf('/') + 1).toLowerCase()\n const dot = name.lastIndexOf('.')\n return dot > 0 ? (MEDIA_BY_EXTENSION[name.slice(dot + 1)] ?? null) : null\n}\n","/**\n * What a host can do (`host.capabilities`): its OS, the tools on its PATH,\n * its OS sandbox, its environment kinds and what it lets clients do. The\n * Hosts page shows it, and actions check it before they are offered (no\n * \"Open pull request\" where `gh` is missing). Node-free, re-exported by\n * `zidane/chat/pure`; the probe itself is `./capabilities-probe`.\n */\n\n/** A tool looked up on the host's PATH. */\nexport interface HostTool {\n /** The executable's name, for example `gh`. */\n name: string\n /** It is on PATH and executable. */\n found: boolean\n /** First line of `<tool> --version`, when it answered. */\n version?: string\n}\n\n/** A host's probed capabilities, as `host.capabilities` returns them. */\nexport interface HostCapabilities {\n /** The host's OS: `process.platform`, CPU architecture and kernel release. */\n os: { platform: string, arch: string, release: string }\n /** Every tool in {@link HOST_TOOLS}, found or not. */\n tools: HostTool[]\n /** The OS sandbox local sessions run under. */\n sandbox: { ok: boolean, backend?: string, reason?: string }\n /** Environment kinds a new session can pick there. */\n environments: { kind: string, label: string, available: boolean, reason?: string }[]\n /** What it lets clients do (the hello flags). */\n allows: { remoteInstalls: boolean, asMachine: boolean, sync: boolean, clone: boolean, createFolders: boolean }\n /** The workspace roots, with the free space of the first one when it could be read. */\n workspace: { roots: string[], freeBytes?: number }\n /** When it was probed, in epoch milliseconds. */\n probedAt: number\n /** Built from the hello alone: the server predates the probe. */\n partial?: boolean\n}\n\n/** The tools probed, in the order the UIs list them. */\nexport const HOST_TOOLS: readonly { name: string, label: string, icon: string, why: string }[] = [\n { name: 'git', label: 'git', icon: 'i-ph-git-branch', why: 'Worktrees, cloning, the git bar' },\n { name: 'gh', label: 'GitHub CLI', icon: 'i-ph-github-logo', why: 'Pull requests' },\n { name: 'glab', label: 'GitLab CLI', icon: 'i-ph-gitlab-logo', why: 'Merge requests' },\n { name: 'docker', label: 'Docker', icon: 'i-ph-cube', why: 'Docker sessions' },\n { name: 'node', label: 'Node.js', icon: 'i-ph-file-js', why: 'npm extensions, stdio MCP servers' },\n { name: 'bun', label: 'Bun', icon: 'i-ph-lightning', why: 'Extensions' },\n { name: 'python3', label: 'Python', icon: 'i-ph-file-py', why: 'Python MCP servers' },\n { name: 'rg', label: 'ripgrep', icon: 'i-ph-magnifying-glass', why: 'Fast search' },\n { name: 'ssh', label: 'ssh', icon: 'i-ph-terminal', why: 'git over ssh' },\n]\n\n/**\n * Whether `name` is on the host's PATH; `undefined` while unknown.\n *\n * @param capabilities - The host's capabilities, or nothing while they load.\n * @param name - The tool's name, as in {@link HOST_TOOLS}.\n */\nexport function hasTool(capabilities: HostCapabilities | null | undefined, name: string): boolean | undefined {\n return capabilities?.tools.find(tool => tool.name === name)?.found\n}\n\n/**\n * The short tags a host's row shows: the tools found and the cloud kinds available, at most `max`.\n *\n * @param capabilities - The host's capabilities.\n * @param max - How many tags to return; `more` counts the rest.\n */\nexport function capabilityTags(capabilities: HostCapabilities, max = 4): { tags: string[], more: number } {\n const all = [\n ...capabilities.tools.filter(tool => tool.found && tool.name !== 'ssh' && tool.name !== 'rg').map(tool => tool.name),\n ...capabilities.environments.filter(env => env.available && env.kind !== 'local' && env.kind !== 'worktree' && !env.kind.includes('@')).map(env => env.kind),\n ]\n const unique = [...new Set(all)]\n return { tags: unique.slice(0, max), more: Math.max(0, unique.length - max) }\n}\n","/**\n * What a pasted \"repository\" is: the URL git should clone, the folder name\n * it lands in, and a short label for the UI. Pure, shared by main (the\n * clone) and the renderer (the live preview under the field).\n *\n * Accepted: `owner/repo` (GitHub shorthand), `github.com/owner/repo`,\n * `https://host/owner/repo(.git)`, a GitHub web URL deep in the tree\n * (`/tree/<branch>/…`, `/blob/…`, `/pull/…`: the branch is kept when it is\n * in the URL), `git@host:owner/repo.git`, `ssh://…`, `git://…`, `file://…`.\n */\n\nexport interface RepoSpec {\n /** What `git clone` receives. */\n cloneUrl: string\n /** Default folder name: the repo's last path segment without `.git`. */\n name: string\n /** `owner/repo` on a known forge, else host + path. */\n label: string\n /** Branch named in a web URL (`/tree/<branch>`), cloned with `--branch`. */\n branch?: string\n /**\n * Everything after `/tree/` when it has more than one segment. Branch\n * names can contain `/`, so the clone matches it against the remote's\n * branches; `branch` (the first segment) is the fallback.\n */\n treePath?: string\n}\n\nconst SHORTHAND = /^([\\w.-]+)\\/([\\w.-]+?)(?:\\.git)?$/\nconst SCP = /^(?:[\\w.-]+@)?([A-Z0-9.-]+):(?!\\/\\/)(\\S+?)\\/?$/i\n/** Forges whose web URLs carry `/<owner>/<repo>/<view>/…` after the repo. */\nconst FORGE_VIEWS = new Set([\n 'tree',\n 'blob',\n 'commit',\n 'commits',\n 'pull',\n 'pulls',\n 'issues',\n 'releases',\n 'actions',\n '-',\n])\n\nfunction stripGit(segment: string): string {\n return segment.replace(/\\.git$/, '')\n}\n\nfunction nameOf(path: string): string | null {\n const last = stripGit(path.replace(/\\/+$/, '').split('/').pop() ?? '')\n return last && last !== '.' && last !== '..' ? last : null\n}\n\n/**\n * Reads a git or forge URL (or `owner/repo`) as what `git clone` would clone; `null` when it is not one.\n *\n * @param raw - What was pasted.\n */\nexport function parseRepoInput(raw: string): RepoSpec | null {\n const input = raw.trim()\n if (!input || /\\s/.test(input))\n return null\n\n // `owner/repo` → GitHub.\n const short = SHORTHAND.exec(input)\n if (short && !input.includes(':')) {\n const [, owner, repo] = short\n if (!nameOf(repo!))\n return null\n return { cloneUrl: `https://github.com/${owner}/${repo}.git`, name: repo!, label: `${owner}/${repo}` }\n }\n\n // `git@host:owner/repo.git` (scp-like syntax).\n const scp = SCP.exec(input)\n if (scp && !/^[a-z][a-z0-9+.-]*:\\/\\//i.test(input)) {\n const [, host, path] = scp\n const name = nameOf(path!)\n if (!name)\n return null\n return { cloneUrl: input, name, label: `${host}:${stripGit(path!)}` }\n }\n\n // Bare `host/owner/repo` → https.\n const withScheme = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(input)\n ? input\n : /^[\\w.-]+\\.[a-z]{2,}\\//i.test(input)\n ? `https://${input}`\n : null\n if (!withScheme)\n return null\n\n let url: URL\n try {\n url = new URL(withScheme)\n }\n catch {\n return null\n }\n const protocol = url.protocol.replace(/:$/, '')\n if (!['https', 'http', 'ssh', 'git', 'file'].includes(protocol))\n return null\n\n if (protocol === 'file') {\n const name = nameOf(url.pathname)\n return name ? { cloneUrl: input, name, label: url.pathname } : null\n }\n\n const segments = url.pathname.split('/').filter(Boolean)\n if (segments.length < 2)\n return null\n\n // Web URLs: cut at the view segment; `/tree/<branch>` names the branch.\n let branch: string | undefined\n let treePath: string | undefined\n const view = segments.findIndex((s, i) => i >= 2 && FORGE_VIEWS.has(s))\n let repoPath = segments\n if (view >= 2) {\n repoPath = segments.slice(0, view)\n const rest = segments.slice(view + (segments[view] === '-' ? 1 : 0))\n if (rest[0] === 'tree' && rest[1]) {\n try {\n branch = decodeURIComponent(rest[1])\n if (rest.length > 2)\n treePath = rest.slice(1).map(decodeURIComponent).join('/')\n }\n catch {\n // A stray `%`: clone the default branch rather than refuse the repo.\n branch = undefined\n treePath = undefined\n }\n }\n }\n const host = url.host\n const path = repoPath.join('/')\n const name = nameOf(path)\n if (!name)\n return null\n\n const isWebForge = protocol === 'https' || protocol === 'http'\n const cloneUrl = isWebForge\n ? `${url.protocol}//${url.username ? `${url.username}@` : ''}${host}/${stripGit(path)}.git`\n : input\n const label = host === 'github.com' ? stripGit(path) : `${host}/${stripGit(path)}`\n return { cloneUrl, name, label, ...(branch ? { branch } : {}), ...(treePath ? { treePath } : {}) }\n}\n"],"mappings":"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"}
package/dist/restate.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { MP as ToolContext, NP as ToolDef, fN as AgentStats, gI as StepKind, gP as ToolResultContent, kN as JsonValue, nP as SessionTurn, pL as SessionStore, qF as AwakeableOutcome, rI as DurableRuntime, uN as AgentClock, zI as ToolStateStore } from "./index-CGbOWa7y.js";
2
- import { f as ExecutionHandle, s as DetachedTasksCapability, v as TaskEntry, y as TaskExitInfo } from "./types-bDQagoiL.js";
1
+ import { IP as SessionTurn, JL as SessionStore, KN as AgentStats, OI as AwakeableOutcome, RI as DurableRuntime, WN as AgentClock, ZI as StepKind, ZP as ToolResultContent, bL as ToolStateStore, lP as JsonValue, mF as ToolDef, pF as ToolContext } from "./index-WlE93Q6d.js";
2
+ import { b as TaskExitInfo, p as ExecutionHandle, s as DetachedTasksCapability, y as TaskEntry } from "./types-2HrgolQz.js";
3
3
  //#region src/restate/types.d.ts
4
4
  /**
5
5
  * Minimal structural types mirroring the subset of `@restatedev/restate-sdk`
@@ -1,4 +1,4 @@
1
- import { C as TerminalProcess, S as TerminalOptions, _ as StreamHandle, d as ExecutionContext, g as SpawnConfig, h as ListFilesOptions, u as ExecResult } from "./types-bDQagoiL.js";
1
+ import { C as TerminalOptions, _ as SpawnConfig, d as ExecResult, f as ExecutionContext, g as ListFilesOptions, v as StreamHandle, w as TerminalProcess } from "./types-2HrgolQz.js";
2
2
  import { Buffer } from "node:buffer";
3
3
  //#region src/contexts/sandbox.d.ts
4
4
  /** Backend of a remote sandbox. Implement it to plug a sandbox service into {@link createSandboxContext}. */
@@ -64,4 +64,4 @@ interface SandboxProvider {
64
64
  declare function createSandboxContext(provider: SandboxProvider): ExecutionContext;
65
65
  //#endregion
66
66
  export { createSandboxContext as n, SandboxProvider as t };
67
- //# sourceMappingURL=sandbox-BwiPGKF7.d.ts.map
67
+ //# sourceMappingURL=sandbox-B4OW6oNx.d.ts.map