@ashx-j/lunr-dev 0.2.13-dev.8.1 → 0.2.16-dev.9.1

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 (339) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/dist/builtin-extensions/ashxj-tui.d.ts +14 -0
  3. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  4. package/dist/builtin-extensions/ashxj-tui.js +37 -3
  5. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  6. package/dist/builtin-extensions/index.d.ts +1 -15
  7. package/dist/builtin-extensions/index.d.ts.map +1 -1
  8. package/dist/builtin-extensions/index.js +7 -21
  9. package/dist/builtin-extensions/index.js.map +1 -1
  10. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.d.ts.map +1 -1
  11. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js +6 -2
  12. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js.map +1 -1
  13. package/dist/builtin-extensions/pi-lsp-extension/src/index.d.ts +4 -0
  14. package/dist/builtin-extensions/pi-lsp-extension/src/index.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-lsp-extension/src/index.js +163 -169
  16. package/dist/builtin-extensions/pi-lsp-extension/src/index.js.map +1 -1
  17. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.d.ts +46 -0
  18. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.d.ts.map +1 -0
  19. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.js +109 -0
  20. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.js.map +1 -0
  21. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.d.ts +7 -0
  22. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.d.ts.map +1 -0
  23. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js +211 -0
  24. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js.map +1 -0
  25. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.d.ts +0 -5
  26. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.d.ts.map +1 -1
  27. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.js +0 -202
  28. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.js.map +1 -1
  29. package/dist/builtin-extensions/pi-mcp-adapter/index.d.ts.map +1 -1
  30. package/dist/builtin-extensions/pi-mcp-adapter/index.js +251 -94
  31. package/dist/builtin-extensions/pi-mcp-adapter/index.js.map +1 -1
  32. package/dist/builtin-extensions/pi-mcp-adapter/init.d.ts +4 -1
  33. package/dist/builtin-extensions/pi-mcp-adapter/init.d.ts.map +1 -1
  34. package/dist/builtin-extensions/pi-mcp-adapter/init.js +10 -3
  35. package/dist/builtin-extensions/pi-mcp-adapter/init.js.map +1 -1
  36. package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.d.ts.map +1 -1
  37. package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.js +6 -1
  38. package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.js.map +1 -1
  39. package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.d.ts.map +1 -1
  40. package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js +2 -1
  41. package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js.map +1 -1
  42. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.d.ts +1 -1
  43. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.d.ts.map +1 -1
  44. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js +1 -1
  45. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js.map +1 -1
  46. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +1 -1
  47. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  48. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +38 -14
  49. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  50. package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.d.ts.map +1 -1
  51. package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.js +1 -1
  52. package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.js.map +1 -1
  53. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +1 -1
  54. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
  55. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +1 -1
  56. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
  57. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +1 -1
  58. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  59. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +2 -1
  60. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  61. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.d.ts +1 -1
  62. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.d.ts.map +1 -1
  63. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js +2 -1
  64. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js.map +1 -1
  65. package/dist/builtin-extensions/pi-web-access/extract.d.ts.map +1 -1
  66. package/dist/builtin-extensions/pi-web-access/extract.js +105 -54
  67. package/dist/builtin-extensions/pi-web-access/extract.js.map +1 -1
  68. package/dist/builtin-extensions/pi-web-access/gemini-search.d.ts +1 -1
  69. package/dist/builtin-extensions/pi-web-access/gemini-search.d.ts.map +1 -1
  70. package/dist/builtin-extensions/pi-web-access/gemini-search.js +82 -65
  71. package/dist/builtin-extensions/pi-web-access/gemini-search.js.map +1 -1
  72. package/dist/builtin-extensions/pi-web-access/github-extract.d.ts.map +1 -1
  73. package/dist/builtin-extensions/pi-web-access/github-extract.js +2 -0
  74. package/dist/builtin-extensions/pi-web-access/github-extract.js.map +1 -1
  75. package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
  76. package/dist/builtin-extensions/pi-web-access/index.js +167 -77
  77. package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
  78. package/dist/builtin-extensions/pi-web-access/lazy.d.ts +18 -0
  79. package/dist/builtin-extensions/pi-web-access/lazy.d.ts.map +1 -0
  80. package/dist/builtin-extensions/pi-web-access/lazy.js +19 -0
  81. package/dist/builtin-extensions/pi-web-access/lazy.js.map +1 -0
  82. package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts +6 -0
  83. package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts.map +1 -0
  84. package/dist/builtin-extensions/pi-web-access/session-cleanup.js +17 -0
  85. package/dist/builtin-extensions/pi-web-access/session-cleanup.js.map +1 -0
  86. package/dist/catalog/publication.json +12 -12
  87. package/dist/cli-runtime.d.ts +3 -0
  88. package/dist/cli-runtime.d.ts.map +1 -0
  89. package/dist/cli-runtime.js +73 -0
  90. package/dist/cli-runtime.js.map +1 -0
  91. package/dist/cli.d.ts.map +1 -1
  92. package/dist/cli.js +14 -53
  93. package/dist/cli.js.map +1 -1
  94. package/dist/config.d.ts +1 -0
  95. package/dist/config.d.ts.map +1 -1
  96. package/dist/config.js +1 -0
  97. package/dist/config.js.map +1 -1
  98. package/dist/core/agent-session.d.ts +3 -0
  99. package/dist/core/agent-session.d.ts.map +1 -1
  100. package/dist/core/agent-session.js +56 -12
  101. package/dist/core/agent-session.js.map +1 -1
  102. package/dist/core/compaction/compaction.d.ts.map +1 -1
  103. package/dist/core/compaction/compaction.js +10 -5
  104. package/dist/core/compaction/compaction.js.map +1 -1
  105. package/dist/core/extensions/host-static.d.ts.map +1 -1
  106. package/dist/core/extensions/host-static.js +34 -12
  107. package/dist/core/extensions/host-static.js.map +1 -1
  108. package/dist/core/extensions/loader.d.ts +1 -2
  109. package/dist/core/extensions/loader.d.ts.map +1 -1
  110. package/dist/core/extensions/loader.js +10 -64
  111. package/dist/core/extensions/loader.js.map +1 -1
  112. package/dist/core/extensions/types.d.ts +2 -2
  113. package/dist/core/extensions/types.d.ts.map +1 -1
  114. package/dist/core/extensions/types.js.map +1 -1
  115. package/dist/core/footer-data-provider.d.ts.map +1 -1
  116. package/dist/core/footer-data-provider.js +2 -0
  117. package/dist/core/footer-data-provider.js.map +1 -1
  118. package/dist/core/permissions.d.ts +0 -2
  119. package/dist/core/permissions.d.ts.map +1 -1
  120. package/dist/core/permissions.js +10 -18
  121. package/dist/core/permissions.js.map +1 -1
  122. package/dist/core/sdk.d.ts +1 -1
  123. package/dist/core/sdk.d.ts.map +1 -1
  124. package/dist/core/sdk.js +1 -1
  125. package/dist/core/sdk.js.map +1 -1
  126. package/dist/core/slash-commands.d.ts.map +1 -1
  127. package/dist/core/slash-commands.js +0 -1
  128. package/dist/core/slash-commands.js.map +1 -1
  129. package/dist/core/timings.d.ts +2 -1
  130. package/dist/core/timings.d.ts.map +1 -1
  131. package/dist/core/timings.js +17 -2
  132. package/dist/core/timings.js.map +1 -1
  133. package/dist/gateway/commands.d.ts +1 -1
  134. package/dist/gateway/commands.d.ts.map +1 -1
  135. package/dist/gateway/commands.js +1 -18
  136. package/dist/gateway/commands.js.map +1 -1
  137. package/dist/main.d.ts +2 -2
  138. package/dist/main.d.ts.map +1 -1
  139. package/dist/main.js +57 -48
  140. package/dist/main.js.map +1 -1
  141. package/dist/modes/interactive/interactive-mode.d.ts +12 -21
  142. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  143. package/dist/modes/interactive/interactive-mode.js +120 -144
  144. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  145. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  146. package/dist/modes/interactive/theme/theme.js +95 -84
  147. package/dist/modes/interactive/theme/theme.js.map +1 -1
  148. package/dist/node-runtime/agent-session-services-IFJMSX7Z.js +36 -0
  149. package/dist/node-runtime/benchmark-request-UC7PD3V3.js +57 -0
  150. package/dist/node-runtime/brave-UWDA3I22.js +143 -0
  151. package/dist/node-runtime/builtin-extensions-LYZ3BFWQ.js +28 -0
  152. package/dist/node-runtime/chunk-2QKLKMKC.js +173 -0
  153. package/dist/node-runtime/chunk-3GHXVUAK.js +21 -0
  154. package/dist/node-runtime/chunk-3RCWXWAY.js +466 -0
  155. package/dist/node-runtime/chunk-3WFAEVKS.js +115 -0
  156. package/dist/node-runtime/chunk-3X3KZKMI.js +49 -0
  157. package/dist/node-runtime/chunk-4HXHDDCF.js +16 -0
  158. package/dist/node-runtime/chunk-4TLO4PO2.js +3427 -0
  159. package/dist/node-runtime/chunk-4ZWGEEAS.js +69 -0
  160. package/dist/node-runtime/chunk-53YJI7JU.js +137 -0
  161. package/dist/node-runtime/chunk-5P7PZMRU.js +610 -0
  162. package/dist/node-runtime/chunk-7N3YHTYF.js +26 -0
  163. package/dist/node-runtime/chunk-7NBZ5P7I.js +24 -0
  164. package/dist/node-runtime/chunk-A2KQXUJD.js +105 -0
  165. package/dist/node-runtime/chunk-AD6VXAO7.js +342 -0
  166. package/dist/node-runtime/chunk-AHSTJBIB.js +64 -0
  167. package/dist/node-runtime/chunk-AJX357CL.js +20211 -0
  168. package/dist/node-runtime/chunk-ARC4KOTI.js +11178 -0
  169. package/dist/node-runtime/chunk-AUXVGBO4.js +19 -0
  170. package/dist/node-runtime/chunk-AY6CAJSL.js +30 -0
  171. package/dist/node-runtime/chunk-BHO7O6E5.js +296 -0
  172. package/dist/node-runtime/chunk-BI3DHYCN.js +8845 -0
  173. package/dist/node-runtime/chunk-BR7YDUKA.js +109 -0
  174. package/dist/node-runtime/chunk-BRJX2PRC.js +53 -0
  175. package/dist/node-runtime/chunk-C4O2RSQQ.js +37 -0
  176. package/dist/node-runtime/chunk-CCZJ3PYY.js +17 -0
  177. package/dist/node-runtime/chunk-CDFZEWPU.js +8388 -0
  178. package/dist/node-runtime/chunk-CGBXPL3E.js +1171 -0
  179. package/dist/node-runtime/chunk-CJECDQKP.js +19 -0
  180. package/dist/node-runtime/chunk-DAPBPCBP.js +53 -0
  181. package/dist/node-runtime/chunk-DDGMHUOW.js +305 -0
  182. package/dist/node-runtime/chunk-DMMTJQMQ.js +43 -0
  183. package/dist/node-runtime/chunk-DVGWF6A2.js +1180 -0
  184. package/dist/node-runtime/chunk-ECD5L7YI.js +1369 -0
  185. package/dist/node-runtime/chunk-EDBJNRSM.js +46 -0
  186. package/dist/node-runtime/chunk-F4VQFJI2.js +1269 -0
  187. package/dist/node-runtime/chunk-FVDOXRUD.js +96 -0
  188. package/dist/node-runtime/chunk-GZQHMEWL.js +126 -0
  189. package/dist/node-runtime/chunk-H2EOZYMP.js +57 -0
  190. package/dist/node-runtime/chunk-HQCKFM2O.js +56 -0
  191. package/dist/node-runtime/chunk-HYHJIRDW.js +19 -0
  192. package/dist/node-runtime/chunk-I6R76AG7.js +22 -0
  193. package/dist/node-runtime/chunk-IPA627GP.js +296 -0
  194. package/dist/node-runtime/chunk-JHYKXIMM.js +378 -0
  195. package/dist/node-runtime/chunk-KKSIVROT.js +88 -0
  196. package/dist/node-runtime/chunk-LZAW4ZX3.js +633 -0
  197. package/dist/node-runtime/chunk-M3LZLQW2.js +98 -0
  198. package/dist/node-runtime/chunk-MGWCVY6Y.js +47 -0
  199. package/dist/node-runtime/chunk-MJQDX3BA.js +72 -0
  200. package/dist/node-runtime/chunk-MKKH27PH.js +8956 -0
  201. package/dist/node-runtime/chunk-MX3GJNXJ.js +986 -0
  202. package/dist/node-runtime/chunk-N77MY65L.js +966 -0
  203. package/dist/node-runtime/chunk-NUIFPZWX.js +209 -0
  204. package/dist/node-runtime/chunk-OBMWP3I5.js +68 -0
  205. package/dist/node-runtime/chunk-OR4L3IB2.js +42 -0
  206. package/dist/node-runtime/chunk-PBC2Y6GS.js +903 -0
  207. package/dist/node-runtime/chunk-PCGNAY2O.js +1324 -0
  208. package/dist/node-runtime/chunk-PCIGF2XK.js +250 -0
  209. package/dist/node-runtime/chunk-PGAJ5MO5.js +7558 -0
  210. package/dist/node-runtime/chunk-PL6JKXWI.js +3622 -0
  211. package/dist/node-runtime/chunk-PVCDKGR6.js +55 -0
  212. package/dist/node-runtime/chunk-Q4Q6D4IY.js +364 -0
  213. package/dist/node-runtime/chunk-Q5ZU2VRT.js +83 -0
  214. package/dist/node-runtime/chunk-QFWG2RVL.js +5477 -0
  215. package/dist/node-runtime/chunk-QH42CDX3.js +9451 -0
  216. package/dist/node-runtime/chunk-RQ2Q5IYR.js +72 -0
  217. package/dist/node-runtime/chunk-RQ5DNUNG.js +429 -0
  218. package/dist/node-runtime/chunk-RRIZE6QQ.js +17 -0
  219. package/dist/node-runtime/chunk-SN6G4OU6.js +4753 -0
  220. package/dist/node-runtime/chunk-SWSN6HAB.js +53 -0
  221. package/dist/node-runtime/chunk-TQNSPERU.js +949 -0
  222. package/dist/node-runtime/chunk-VRB2IYGG.js +53 -0
  223. package/dist/node-runtime/chunk-VSELYKWU.js +772 -0
  224. package/dist/node-runtime/chunk-W3CVH5RX.js +62 -0
  225. package/dist/node-runtime/chunk-WJVFOIB5.js +24921 -0
  226. package/dist/node-runtime/chunk-WOVTOV5P.js +5653 -0
  227. package/dist/node-runtime/chunk-XBWPBZBN.js +125 -0
  228. package/dist/node-runtime/chunk-XTHQ7XR7.js +509 -0
  229. package/dist/node-runtime/chunk-YF63P5ZT.js +864 -0
  230. package/dist/node-runtime/chunk-YSKSB3BJ.js +295 -0
  231. package/dist/node-runtime/chunk-ZCHMJ34K.js +130 -0
  232. package/dist/node-runtime/chunk-ZKMFUD3Q.js +2834 -0
  233. package/dist/node-runtime/cli-runtime.js +81 -0
  234. package/dist/node-runtime/clipboard-OZ63BBC6.js +12 -0
  235. package/dist/node-runtime/clipboard-image-7QR6GXVA.js +13 -0
  236. package/dist/node-runtime/command-L3LAHDIH.js +13 -0
  237. package/dist/node-runtime/commands-RL5YBW5I.js +291 -0
  238. package/dist/node-runtime/config-FMEOZSWE.js +77 -0
  239. package/dist/node-runtime/curator-server-XCM43VEF.js +3816 -0
  240. package/dist/node-runtime/customize-XEXL2DGQ.js +12 -0
  241. package/dist/node-runtime/direct-tool-executor-JVDXTO7A.js +188 -0
  242. package/dist/node-runtime/exa-LL64QZR2.js +329 -0
  243. package/dist/node-runtime/export-html-KR26FOUZ.js +150 -0
  244. package/dist/node-runtime/extension-input-RV5N6APL.js +14 -0
  245. package/dist/node-runtime/extension-selector-CPD5LWDD.js +14 -0
  246. package/dist/node-runtime/extract-XLQSJN4V.js +17 -0
  247. package/dist/node-runtime/file-sync-HCOP2QVF.js +117 -0
  248. package/dist/node-runtime/gateway-X2TI5X7F.js +2484 -0
  249. package/dist/node-runtime/gemini-api-QE7ANVDZ.js +29 -0
  250. package/dist/node-runtime/gemini-search-U7SUMPQA.js +330 -0
  251. package/dist/node-runtime/gemini-url-context-PXWCBQHK.js +103 -0
  252. package/dist/node-runtime/gemini-web-MM446SEH.js +14 -0
  253. package/dist/node-runtime/github-extract-F64RZOEA.js +619 -0
  254. package/dist/node-runtime/goal-CZQ7FFQJ.js +1831 -0
  255. package/dist/node-runtime/index.js +859 -0
  256. package/dist/node-runtime/init-NJV2T55N.js +28 -0
  257. package/dist/node-runtime/install-cli-TH7IJJQQ.js +308 -0
  258. package/dist/node-runtime/interactive-mode-KOM35YF2.js +56 -0
  259. package/dist/node-runtime/interactive-view-U6OILKF3.js +249 -0
  260. package/dist/node-runtime/lsp-manager-3ASUSO4T.js +1104 -0
  261. package/dist/node-runtime/lunr-cron-YJ5UHYRD.js +268 -0
  262. package/dist/node-runtime/main.js +54 -0
  263. package/dist/node-runtime/mcp-auth-flow-QIXHW6QN.js +32 -0
  264. package/dist/node-runtime/mcp-panel-IIGMXQGP.js +501 -0
  265. package/dist/node-runtime/mcp-setup-panel-FEK7663I.js +355 -0
  266. package/dist/node-runtime/memory-cap-3S4XRLNP.js +20 -0
  267. package/dist/node-runtime/model-tiers-NJLHUEGK.js +20 -0
  268. package/dist/node-runtime/openai-search-B3MSNCQA.js +288 -0
  269. package/dist/node-runtime/package-manager-cli-TZZHJCVI.js +749 -0
  270. package/dist/node-runtime/parallel-AI2MNSCU.js +265 -0
  271. package/dist/node-runtime/parser-manager-TQHWYDH7.js +152 -0
  272. package/dist/node-runtime/pdf-extract-IPE6H4HP.js +57 -0
  273. package/dist/node-runtime/perplexity-QVJW3I35.js +12 -0
  274. package/dist/node-runtime/pi-intercom-EEMBGQID.js +2215 -0
  275. package/dist/node-runtime/pi-mcp-adapter-QFB37AVN.js +422 -0
  276. package/dist/node-runtime/pi-ollama-cloud-4VZRMULP.js +1440 -0
  277. package/dist/node-runtime/pi-prompt-template-model-4QT4LLXF.js +3946 -0
  278. package/dist/node-runtime/pi-subagents-7XJ4H53P.js +6023 -0
  279. package/dist/node-runtime/pi-web-access-DPGAVKOA.js +1864 -0
  280. package/dist/node-runtime/print-mode-VWIRFDAC.js +12 -0
  281. package/dist/node-runtime/proxy-modes-HEEFK4KC.js +685 -0
  282. package/dist/node-runtime/rpc-entry.js +62 -0
  283. package/dist/node-runtime/rpc-mode-SJNSOA4G.js +13 -0
  284. package/dist/node-runtime/runtime-bridges-PPHNBFWL.js +14 -0
  285. package/dist/node-runtime/session-manager-MQNBYACL.js +35 -0
  286. package/dist/node-runtime/session-selector-5AZLJS6U.js +14 -0
  287. package/dist/node-runtime/settings-manager-5LF2VQWC.js +21 -0
  288. package/dist/node-runtime/src-Y7JSCK64.js +2407 -0
  289. package/dist/node-runtime/subagent-executor-5RNDEPIJ.js +8483 -0
  290. package/dist/node-runtime/summary-review-YSMXKITO.js +228 -0
  291. package/dist/node-runtime/tavily-WEZFVFP7.js +154 -0
  292. package/dist/node-runtime/timings-UAD5BEAS.js +16 -0
  293. package/dist/node-runtime/tool-renderer-MV5O452K.js +204 -0
  294. package/dist/node-runtime/update-cli-A253SZ7P.js +73 -0
  295. package/dist/node-runtime/v4-5MNC3H7G.js +424 -0
  296. package/dist/node-runtime/video-extract-OYT5WKS5.js +304 -0
  297. package/dist/node-runtime/workspace-index-6DBXSTJ6.js +163 -0
  298. package/dist/node-runtime/youtube-extract-TQYKGFGS.js +264 -0
  299. package/dist/startup/benchmark-request.d.ts +3 -0
  300. package/dist/startup/benchmark-request.d.ts.map +1 -0
  301. package/dist/startup/benchmark-request.js +65 -0
  302. package/dist/startup/benchmark-request.js.map +1 -0
  303. package/dist/startup/interactive-view.d.ts +55 -0
  304. package/dist/startup/interactive-view.d.ts.map +1 -0
  305. package/dist/startup/interactive-view.js +332 -0
  306. package/dist/startup/interactive-view.js.map +1 -0
  307. package/dist/startup/launch-routing.d.ts.map +1 -1
  308. package/dist/startup/launch-routing.js +9 -10
  309. package/dist/startup/launch-routing.js.map +1 -1
  310. package/dist/startup/startup-milestones.d.ts +1 -1
  311. package/dist/startup/startup-milestones.d.ts.map +1 -1
  312. package/dist/startup/startup-milestones.js +3 -2
  313. package/dist/startup/startup-milestones.js.map +1 -1
  314. package/dist/utils/await-with-abort.d.ts +2 -0
  315. package/dist/utils/await-with-abort.d.ts.map +1 -0
  316. package/dist/utils/await-with-abort.js +19 -0
  317. package/dist/utils/await-with-abort.js.map +1 -0
  318. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  319. package/dist/utils/syntax-highlight.js +10 -4
  320. package/dist/utils/syntax-highlight.js.map +1 -1
  321. package/docs/compaction.md +5 -3
  322. package/docs/development.md +5 -1
  323. package/docs/features.md +0 -1
  324. package/docs/interactive-startup.md +98 -0
  325. package/docs/usage.md +0 -1
  326. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  327. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  328. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  329. package/examples/extensions/gondolin/package-lock.json +2 -2
  330. package/examples/extensions/gondolin/package.json +1 -1
  331. package/examples/extensions/sandbox/package-lock.json +2 -2
  332. package/examples/extensions/sandbox/package.json +1 -1
  333. package/examples/extensions/with-deps/package-lock.json +2 -2
  334. package/examples/extensions/with-deps/package.json +1 -1
  335. package/package.json +20 -20
  336. package/dist/core/swarm.d.ts +0 -23
  337. package/dist/core/swarm.d.ts.map +0 -1
  338. package/dist/core/swarm.js +0 -45
  339. package/dist/core/swarm.js.map +0 -1
@@ -0,0 +1,2834 @@
1
+ import { createRequire as __lunrRequire } from "node:module"; const require = __lunrRequire(import.meta.url);
2
+ import {
3
+ processImage
4
+ } from "./chunk-AD6VXAO7.js";
5
+ import {
6
+ DEFAULT_MAX_BYTES,
7
+ DEFAULT_MAX_LINES,
8
+ formatSize,
9
+ truncateHead,
10
+ truncateLine,
11
+ truncateTail
12
+ } from "./chunk-53YJI7JU.js";
13
+ import {
14
+ formatGroupedCall,
15
+ getTextOutput,
16
+ invalidArgText,
17
+ normalizeDisplayText,
18
+ renderCollapsedSearchPath,
19
+ renderToolFileName,
20
+ renderToolPath,
21
+ replaceTabs,
22
+ shortenPath,
23
+ str,
24
+ toolGroupTree,
25
+ toolStatusDot,
26
+ toolStatusDotFromContext
27
+ } from "./chunk-GZQHMEWL.js";
28
+ import {
29
+ getShellConfig,
30
+ getShellEnv,
31
+ killProcessTree,
32
+ trackDetachedChildPid,
33
+ untrackDetachedChildPid
34
+ } from "./chunk-ZCHMJ34K.js";
35
+ import {
36
+ keyHint
37
+ } from "./chunk-C4O2RSQQ.js";
38
+ import {
39
+ getLanguageFromPath,
40
+ highlightCode,
41
+ theme
42
+ } from "./chunk-MX3GJNXJ.js";
43
+ import {
44
+ APP_NAME,
45
+ formatPathRelativeToCwdOrAbsolute,
46
+ getBinDir,
47
+ getReadmePath,
48
+ resolvePath,
49
+ waitForChildProcess
50
+ } from "./chunk-PCIGF2XK.js";
51
+
52
+ // packages/coding-agent/dist/modes/interactive/components/visual-truncate.js
53
+ import { Text } from "@ashx-j/lunr-tui";
54
+ function truncateToVisualLines(text, maxVisualLines, width, paddingX = 0) {
55
+ if (!text)
56
+ return { visualLines: [], skippedCount: 0 };
57
+ let allVisualLines = new Text(text, paddingX, 0).render(width);
58
+ if (allVisualLines.length <= maxVisualLines)
59
+ return { visualLines: allVisualLines, skippedCount: 0 };
60
+ let truncatedLines = allVisualLines.slice(-maxVisualLines), skippedCount = allVisualLines.length - maxVisualLines;
61
+ return { visualLines: truncatedLines, skippedCount };
62
+ }
63
+
64
+ // packages/coding-agent/dist/core/process-registry.js
65
+ import { spawn } from "node:child_process";
66
+ var isWin32 = process.platform === "win32", EXIT_NOISE_GATE_MS = 3e3, EXIT_TTL_MS = 300 * 1e3, MAX_TRACKED = 100, processes = /* @__PURE__ */ new Map();
67
+ function register(pid, command, cwd, sessionId) {
68
+ if (pid) {
69
+ if (processes.size >= MAX_TRACKED) {
70
+ let oldest;
71
+ for (let [p, entry] of processes) {
72
+ if (entry.status === "exited") {
73
+ oldest = { pid: p, entry };
74
+ break;
75
+ }
76
+ (!oldest || entry.startedAt < oldest.entry.startedAt) && (oldest = { pid: p, entry });
77
+ }
78
+ oldest && processes.delete(oldest.pid);
79
+ }
80
+ processes.set(pid, { pid, command, cwd, startedAt: Date.now(), status: "running", sessionId });
81
+ }
82
+ }
83
+ function markExited(pid, exitCode) {
84
+ if (!pid)
85
+ return;
86
+ let entry = processes.get(pid);
87
+ if (!entry)
88
+ return;
89
+ if (Date.now() - entry.startedAt < EXIT_NOISE_GATE_MS) {
90
+ processes.delete(pid);
91
+ return;
92
+ }
93
+ entry.status = "exited", entry.exitCode = exitCode ?? void 0, entry.exitedAt = Date.now();
94
+ }
95
+ function list(sessionId) {
96
+ return prune(), [...processes.values()].filter((p) => sessionId === void 0 || p.sessionId === sessionId);
97
+ }
98
+ function prune() {
99
+ for (let [pid, entry] of processes) {
100
+ if (entry.status === "exited") {
101
+ (!entry.exitedAt || Date.now() - entry.exitedAt > EXIT_TTL_MS) && processes.delete(pid);
102
+ continue;
103
+ }
104
+ isAlive(pid) || markExited(pid, null);
105
+ }
106
+ }
107
+ function isAlive(pid) {
108
+ try {
109
+ return process.kill(pid, 0), !0;
110
+ } catch {
111
+ return !1;
112
+ }
113
+ }
114
+ function kill(pid) {
115
+ processes.has(pid) && (killProcessTree(pid), processes.delete(pid));
116
+ }
117
+ function killAll(sessionId) {
118
+ for (let [pid, entry] of processes)
119
+ if (!(sessionId !== void 0 && entry.sessionId !== sessionId)) {
120
+ try {
121
+ killProcessTree(pid);
122
+ } catch {
123
+ }
124
+ processes.delete(pid);
125
+ }
126
+ }
127
+ function pause(pid) {
128
+ if (isWin32)
129
+ throw new Error("Pause/resume is unsupported on Windows.");
130
+ if (!processes.has(pid))
131
+ throw new Error(`Process ${pid} is not tracked.`);
132
+ try {
133
+ process.kill(pid, "SIGSTOP");
134
+ let entry = processes.get(pid);
135
+ entry && (entry.status = "paused");
136
+ } catch {
137
+ processes.delete(pid);
138
+ }
139
+ }
140
+ function resume(pid) {
141
+ if (isWin32)
142
+ throw new Error("Pause/resume is unsupported on Windows.");
143
+ if (!processes.has(pid))
144
+ throw new Error(`Process ${pid} is not tracked.`);
145
+ try {
146
+ process.kill(pid, "SIGCONT");
147
+ let entry = processes.get(pid);
148
+ entry && (entry.status = "running");
149
+ } catch {
150
+ processes.delete(pid);
151
+ }
152
+ }
153
+ function restart(pid) {
154
+ let entry = processes.get(pid);
155
+ if (entry) {
156
+ try {
157
+ killProcessTree(pid);
158
+ } catch {
159
+ }
160
+ processes.delete(pid);
161
+ try {
162
+ let shellConfig = getShellConfig(), child = spawn(shellConfig.shell, [...shellConfig.args, entry.command], {
163
+ cwd: entry.cwd,
164
+ detached: !0,
165
+ stdio: "ignore",
166
+ windowsHide: !0
167
+ });
168
+ if (child.pid)
169
+ return register(child.pid, entry.command, entry.cwd, entry.sessionId), child.unref(), child.pid;
170
+ } catch {
171
+ }
172
+ }
173
+ }
174
+ function isWindows() {
175
+ return isWin32;
176
+ }
177
+ function clearRegistry(sessionId) {
178
+ if (sessionId === void 0) {
179
+ processes.clear();
180
+ return;
181
+ }
182
+ for (let [pid, entry] of processes)
183
+ entry.sessionId === sessionId && processes.delete(pid);
184
+ }
185
+
186
+ // packages/coding-agent/dist/core/tools/bash.js
187
+ import { constants } from "node:fs";
188
+ import { access as fsAccess } from "node:fs/promises";
189
+ import { Container, Text as Text2, truncateToWidth } from "@ashx-j/lunr-tui";
190
+ import { spawn as spawn2 } from "child_process";
191
+ import { Type } from "typebox";
192
+
193
+ // packages/coding-agent/dist/core/tools/output-accumulator.js
194
+ import { randomBytes } from "node:crypto";
195
+ import { createWriteStream } from "node:fs";
196
+ import { tmpdir } from "node:os";
197
+ import { join } from "node:path";
198
+ function defaultTempFilePath(prefix) {
199
+ let id = randomBytes(8).toString("hex");
200
+ return join(tmpdir(), `${prefix}-${id}.log`);
201
+ }
202
+ function byteLength(text) {
203
+ return Buffer.byteLength(text, "utf-8");
204
+ }
205
+ var OutputAccumulator = class {
206
+ maxLines;
207
+ maxBytes;
208
+ maxRollingBytes;
209
+ tempFilePrefix;
210
+ decoder = new TextDecoder();
211
+ rawChunks = [];
212
+ tailText = "";
213
+ tailBytes = 0;
214
+ tailStartsAtLineBoundary = !0;
215
+ totalRawBytes = 0;
216
+ totalDecodedBytes = 0;
217
+ completedLines = 0;
218
+ totalLines = 0;
219
+ currentLineBytes = 0;
220
+ hasOpenLine = !1;
221
+ finished = !1;
222
+ tempFilePath;
223
+ tempFileStream;
224
+ constructor(options = {}) {
225
+ this.maxLines = options.maxLines ?? 2e3, this.maxBytes = options.maxBytes ?? 51200, this.maxRollingBytes = Math.max(this.maxBytes * 2, 1), this.tempFilePrefix = options.tempFilePrefix ?? "lunr-output";
226
+ }
227
+ append(data) {
228
+ if (this.finished)
229
+ throw new Error("Cannot append to a finished output accumulator");
230
+ this.totalRawBytes += data.length, this.appendDecodedText(this.decoder.decode(data, { stream: !0 })), this.tempFileStream || this.shouldUseTempFile() ? (this.ensureTempFile(), this.tempFileStream?.write(data)) : data.length > 0 && this.rawChunks.push(data);
231
+ }
232
+ finish() {
233
+ this.finished || (this.finished = !0, this.appendDecodedText(this.decoder.decode()), this.shouldUseTempFile() && this.ensureTempFile());
234
+ }
235
+ snapshot(options = {}) {
236
+ let tailTruncation = truncateTail(this.getSnapshotText(), {
237
+ maxLines: this.maxLines,
238
+ maxBytes: this.maxBytes
239
+ }), truncated = this.totalLines > this.maxLines || this.totalDecodedBytes > this.maxBytes, truncatedBy = truncated ? tailTruncation.truncatedBy ?? (this.totalDecodedBytes > this.maxBytes ? "bytes" : "lines") : null, truncation = {
240
+ ...tailTruncation,
241
+ truncated,
242
+ truncatedBy,
243
+ totalLines: this.totalLines,
244
+ totalBytes: this.totalDecodedBytes,
245
+ maxLines: this.maxLines,
246
+ maxBytes: this.maxBytes
247
+ };
248
+ return options.persistIfTruncated && truncation.truncated && this.ensureTempFile(), {
249
+ content: truncation.content,
250
+ truncation,
251
+ fullOutputPath: this.tempFilePath
252
+ };
253
+ }
254
+ async closeTempFile() {
255
+ if (!this.tempFileStream)
256
+ return;
257
+ let stream = this.tempFileStream;
258
+ this.tempFileStream = void 0, await new Promise((resolve2, reject) => {
259
+ let onError = (error) => {
260
+ stream.off("finish", onFinish), reject(error);
261
+ }, onFinish = () => {
262
+ stream.off("error", onError), resolve2();
263
+ };
264
+ stream.once("error", onError), stream.once("finish", onFinish), stream.end();
265
+ });
266
+ }
267
+ getLastLineBytes() {
268
+ return this.currentLineBytes;
269
+ }
270
+ appendDecodedText(text) {
271
+ if (text.length === 0)
272
+ return;
273
+ let bytes = byteLength(text);
274
+ this.totalDecodedBytes += bytes, this.tailText += text, this.tailBytes += bytes, this.tailBytes > this.maxRollingBytes * 2 && this.trimTail();
275
+ let newlines = 0, lastNewline = -1;
276
+ for (let i = text.indexOf(`
277
+ `); i !== -1; i = text.indexOf(`
278
+ `, i + 1))
279
+ newlines++, lastNewline = i;
280
+ if (newlines === 0)
281
+ this.currentLineBytes += bytes, this.hasOpenLine = !0;
282
+ else {
283
+ this.completedLines += newlines;
284
+ let tail = text.slice(lastNewline + 1);
285
+ this.currentLineBytes = byteLength(tail), this.hasOpenLine = tail.length > 0;
286
+ }
287
+ this.totalLines = this.completedLines + (this.hasOpenLine ? 1 : 0);
288
+ }
289
+ trimTail() {
290
+ let buffer = Buffer.from(this.tailText, "utf-8");
291
+ if (buffer.length <= this.maxRollingBytes) {
292
+ this.tailBytes = buffer.length;
293
+ return;
294
+ }
295
+ let start = buffer.length - this.maxRollingBytes;
296
+ for (; start < buffer.length && (buffer[start] & 192) === 128; )
297
+ start++;
298
+ this.tailStartsAtLineBoundary = start === 0 ? this.tailStartsAtLineBoundary : buffer[start - 1] === 10, this.tailText = buffer.subarray(start).toString("utf-8"), this.tailBytes = byteLength(this.tailText);
299
+ }
300
+ getSnapshotText() {
301
+ if (this.tailStartsAtLineBoundary)
302
+ return this.tailText;
303
+ let firstNewline = this.tailText.indexOf(`
304
+ `);
305
+ return firstNewline === -1 ? this.tailText : this.tailText.slice(firstNewline + 1);
306
+ }
307
+ shouldUseTempFile() {
308
+ return this.totalRawBytes > this.maxBytes || this.totalDecodedBytes > this.maxBytes || this.totalLines > this.maxLines;
309
+ }
310
+ ensureTempFile() {
311
+ if (!this.tempFilePath) {
312
+ this.tempFilePath = defaultTempFilePath(this.tempFilePrefix), this.tempFileStream = createWriteStream(this.tempFilePath);
313
+ for (let chunk of this.rawChunks)
314
+ this.tempFileStream.write(chunk);
315
+ this.rawChunks = [];
316
+ }
317
+ }
318
+ };
319
+
320
+ // packages/coding-agent/dist/core/tools/tool-definition-wrapper.js
321
+ function wrapToolDefinition(definition, ctxFactory) {
322
+ return {
323
+ name: definition.name,
324
+ label: definition.label,
325
+ description: definition.description,
326
+ parameters: definition.parameters,
327
+ prepareArguments: definition.prepareArguments,
328
+ executionMode: definition.executionMode,
329
+ execute: (toolCallId, params, signal, onUpdate) => definition.execute(toolCallId, params, signal, onUpdate, ctxFactory?.())
330
+ };
331
+ }
332
+ function createToolDefinitionFromAgentTool(tool) {
333
+ return {
334
+ name: tool.name,
335
+ label: tool.label,
336
+ description: tool.description,
337
+ parameters: tool.parameters,
338
+ prepareArguments: tool.prepareArguments,
339
+ executionMode: tool.executionMode,
340
+ execute: async (toolCallId, params, signal, onUpdate) => tool.execute(toolCallId, params, signal, onUpdate)
341
+ };
342
+ }
343
+
344
+ // packages/coding-agent/dist/core/tools/bash.js
345
+ var MAX_TIMEOUT_MS = 2147483647, MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1e3;
346
+ function resolveTimeoutMs(timeout) {
347
+ if (timeout === void 0)
348
+ return;
349
+ if (!Number.isFinite(timeout) || timeout <= 0)
350
+ throw new Error("Invalid timeout: must be a finite number of seconds");
351
+ let timeoutMs = timeout * 1e3;
352
+ if (timeoutMs > MAX_TIMEOUT_MS)
353
+ throw new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);
354
+ return timeoutMs;
355
+ }
356
+ var bashSchema = Type.Object({
357
+ command: Type.String({ description: "Bash command to execute" }),
358
+ timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" }))
359
+ });
360
+ function createLocalBashOperations(options) {
361
+ return {
362
+ exec: async (command, cwd, { onData, signal, timeout, env }) => {
363
+ let timeoutMs = resolveTimeoutMs(timeout);
364
+ if (signal?.aborted)
365
+ throw new Error("aborted");
366
+ let shellConfig = getShellConfig(options?.shellPath);
367
+ try {
368
+ await fsAccess(cwd, constants.F_OK);
369
+ } catch {
370
+ throw new Error(`Working directory does not exist: ${cwd}
371
+ Cannot execute bash commands.`);
372
+ }
373
+ let commandFromStdin = shellConfig.commandTransport === "stdin", child = spawn2(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {
374
+ cwd,
375
+ detached: process.platform !== "win32",
376
+ env: env ?? getShellEnv(),
377
+ stdio: [commandFromStdin ? "pipe" : "ignore", "pipe", "pipe"],
378
+ windowsHide: !0
379
+ });
380
+ if (commandFromStdin && (child.stdin?.on("error", () => {
381
+ }), child.stdin?.end(command)), child.pid && trackDetachedChildPid(child.pid), child.pid)
382
+ try {
383
+ register(child.pid, command, cwd, options?.sessionId);
384
+ } catch {
385
+ }
386
+ let timedOut = !1, timeoutHandle, onAbort = () => {
387
+ child.pid && killProcessTree(child.pid);
388
+ };
389
+ try {
390
+ timeoutMs !== void 0 && (timeoutHandle = setTimeout(() => {
391
+ timedOut = !0, child.pid && killProcessTree(child.pid);
392
+ }, timeoutMs)), child.stdout?.on("data", onData), child.stderr?.on("data", onData), signal && (signal.aborted ? onAbort() : signal.addEventListener("abort", onAbort, { once: !0 }));
393
+ let exitCode = await waitForChildProcess(child);
394
+ if (signal?.aborted)
395
+ throw new Error("aborted");
396
+ if (timedOut)
397
+ throw new Error(`timeout:${timeout}`);
398
+ return { exitCode };
399
+ } finally {
400
+ if (child.pid && untrackDetachedChildPid(child.pid), child.pid)
401
+ try {
402
+ markExited(child.pid, child.exitCode);
403
+ } catch {
404
+ }
405
+ timeoutHandle && clearTimeout(timeoutHandle), signal && signal.removeEventListener("abort", onAbort);
406
+ }
407
+ }
408
+ };
409
+ }
410
+ function resolveSpawnContext(command, cwd, spawnHook) {
411
+ let baseContext = { command, cwd, env: { ...getShellEnv() } };
412
+ return spawnHook ? spawnHook(baseContext) : baseContext;
413
+ }
414
+ var BASH_PREVIEW_LINES = 5, BASH_UPDATE_THROTTLE_MS = 100, BashResultRenderComponent = class extends Container {
415
+ state = {
416
+ cachedWidth: void 0,
417
+ cachedLines: void 0,
418
+ cachedSkipped: void 0
419
+ };
420
+ };
421
+ function formatDuration(ms) {
422
+ return `${(ms / 1e3).toFixed(1)}s`;
423
+ }
424
+ var MAX_COLLAPSED_COMMAND_CHARS = 100;
425
+ function formatBashCall(args, options) {
426
+ let command = str(args?.command), timeout = args?.timeout, timeoutSuffix = timeout && !options?.compact ? theme.fg("muted", ` (timeout ${timeout}s)`) : "", commandDisplay = command === null ? invalidArgText(theme) : command || theme.fg("toolOutput", "...");
427
+ if (!options?.expanded && command) {
428
+ let firstLine = command.split(`
429
+ `)[0], capped = firstLine.length > MAX_COLLAPSED_COMMAND_CHARS, base = capped ? firstLine.slice(0, MAX_COLLAPSED_COMMAND_CHARS) : firstLine;
430
+ commandDisplay = capped || base.length < command.length ? `${base} \u2026` : base;
431
+ }
432
+ return command && (commandDisplay = theme.fg("toolTitle", theme.bold(commandDisplay))), commandDisplay + timeoutSuffix;
433
+ }
434
+ function rebuildBashResultRenderComponent(component, result, options, showImages, startedAt, endedAt, compact = !1) {
435
+ let state = component.state;
436
+ component.clear();
437
+ let output = getTextOutput(result, showImages).trim(), truncation = result.details?.truncation, fullOutputPath = result.details?.fullOutputPath;
438
+ if (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith("]")) {
439
+ let footerStart = output.lastIndexOf(`
440
+
441
+ [`);
442
+ footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath) && (output = output.slice(0, footerStart).trimEnd());
443
+ }
444
+ if (!compact && output) {
445
+ let styledOutput = output.split(`
446
+ `).map((line) => theme.fg("toolOutput", line)).join(`
447
+ `);
448
+ options.expanded ? component.addChild(new Text2(`
449
+ ${styledOutput}`, 0, 0)) : component.addChild({
450
+ render: (width) => {
451
+ if (state.cachedLines === void 0 || state.cachedWidth !== width) {
452
+ let preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);
453
+ state.cachedLines = preview.visualLines, state.cachedSkipped = preview.skippedCount, state.cachedWidth = width;
454
+ }
455
+ if (state.cachedSkipped && state.cachedSkipped > 0) {
456
+ let hint = theme.fg("muted", `... (${state.cachedSkipped} earlier lines)`);
457
+ return ["", truncateToWidth(hint, width, "..."), ...state.cachedLines ?? []];
458
+ }
459
+ return ["", ...state.cachedLines ?? []];
460
+ },
461
+ invalidate: () => {
462
+ state.cachedWidth = void 0, state.cachedLines = void 0, state.cachedSkipped = void 0;
463
+ }
464
+ });
465
+ }
466
+ if (!compact && startedAt !== void 0) {
467
+ let label = options.isPartial ? "Elapsed" : "Took", endTime = endedAt ?? Date.now();
468
+ component.addChild(new Text2(`
469
+ ${theme.fg("muted", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));
470
+ }
471
+ }
472
+ function createBashToolDefinition(cwd, options) {
473
+ let ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath }), commandPrefix = options?.commandPrefix, spawnHook = options?.spawnHook;
474
+ return {
475
+ name: "bash",
476
+ label: "bash",
477
+ description: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${2e3} lines or ${51200 / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,
478
+ promptSnippet: "Execute bash commands (ls, grep, find, etc.)",
479
+ parameters: bashSchema,
480
+ async execute(_toolCallId, { command, timeout }, signal, onUpdate, _ctx) {
481
+ let resolvedCommand = commandPrefix ? `${commandPrefix}
482
+ ${command}` : command, spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook), output = new OutputAccumulator({ tempFilePrefix: "lunr-bash" }), acceptingOutput = !0, updateTimer, updateDirty = !1, lastUpdateAt = 0, emitOutputUpdate = () => {
483
+ if (!onUpdate || !updateDirty)
484
+ return;
485
+ updateDirty = !1, lastUpdateAt = Date.now();
486
+ let snapshot = output.snapshot({ persistIfTruncated: !0 });
487
+ onUpdate({
488
+ content: [{ type: "text", text: snapshot.content || "" }],
489
+ details: {
490
+ truncation: snapshot.truncation.truncated ? snapshot.truncation : void 0,
491
+ fullOutputPath: snapshot.fullOutputPath
492
+ }
493
+ });
494
+ }, clearUpdateTimer = () => {
495
+ updateTimer && (clearTimeout(updateTimer), updateTimer = void 0);
496
+ }, scheduleOutputUpdate = () => {
497
+ if (!onUpdate)
498
+ return;
499
+ updateDirty = !0;
500
+ let delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);
501
+ if (delay <= 0) {
502
+ clearUpdateTimer(), emitOutputUpdate();
503
+ return;
504
+ }
505
+ updateTimer ??= setTimeout(() => {
506
+ updateTimer = void 0, emitOutputUpdate();
507
+ }, delay);
508
+ };
509
+ onUpdate && onUpdate({ content: [], details: void 0 });
510
+ let handleData = (data) => {
511
+ acceptingOutput && (output.append(data), scheduleOutputUpdate());
512
+ }, finishOutput = async () => {
513
+ acceptingOutput = !1, output.finish(), clearUpdateTimer(), emitOutputUpdate();
514
+ let snapshot = output.snapshot({ persistIfTruncated: !0 });
515
+ return await output.closeTempFile(), snapshot;
516
+ }, formatOutput = (snapshot, emptyText = "(no output)") => {
517
+ let truncation = snapshot.truncation, text = snapshot.content || emptyText, details;
518
+ if (truncation.truncated) {
519
+ details = { truncation, fullOutputPath: snapshot.fullOutputPath };
520
+ let startLine = truncation.totalLines - truncation.outputLines + 1, endLine = truncation.totalLines;
521
+ if (truncation.lastLinePartial) {
522
+ let lastLineSize = formatSize(output.getLastLineBytes());
523
+ text += `
524
+
525
+ [Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;
526
+ } else truncation.truncatedBy === "lines" ? text += `
527
+
528
+ [Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]` : text += `
529
+
530
+ [Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(51200)} limit). Full output: ${snapshot.fullOutputPath}]`;
531
+ }
532
+ return { text, details };
533
+ }, appendStatus = (text, status) => `${text ? `${text}
534
+
535
+ ` : ""}${status}`;
536
+ try {
537
+ let exitCode;
538
+ try {
539
+ exitCode = (await ops.exec(spawnContext.command, spawnContext.cwd, {
540
+ onData: handleData,
541
+ signal,
542
+ timeout,
543
+ env: spawnContext.env
544
+ })).exitCode;
545
+ } catch (err) {
546
+ let snapshot2 = await finishOutput(), { text } = formatOutput(snapshot2, "");
547
+ if (err instanceof Error && err.message === "aborted")
548
+ throw new Error(appendStatus(text, "Command aborted"));
549
+ if (err instanceof Error && err.message.startsWith("timeout:")) {
550
+ let timeoutSecs = err.message.split(":")[1];
551
+ throw new Error(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`));
552
+ }
553
+ throw err;
554
+ }
555
+ let snapshot = await finishOutput(), { text: outputText, details } = formatOutput(snapshot);
556
+ if (exitCode !== 0 && exitCode !== null)
557
+ throw new Error(appendStatus(outputText, `Command exited with code ${exitCode}`));
558
+ return { content: [{ type: "text", text: outputText }], details };
559
+ } finally {
560
+ clearUpdateTimer();
561
+ }
562
+ },
563
+ renderCall(args, _theme, context) {
564
+ let state = context.state;
565
+ context.executionStarted && state.startedAt === void 0 && (state.startedAt = Date.now(), state.endedAt = void 0), !context.isPartial && state.startedAt !== void 0 && (state.endedAt ??= Date.now());
566
+ let compact = !context.isPartial && !context.expanded && !context.isError, detail = formatBashCall(args, { expanded: context.expanded, compact });
567
+ compact && state.startedAt !== void 0 && state.endedAt !== void 0 && (detail += theme.fg("muted", ` \u2014 Took ${formatDuration(state.endedAt - state.startedAt)}`));
568
+ let text = context.lastComponent ?? new Text2("", 0, 0);
569
+ return text.setText(formatGroupedCall({
570
+ role: context.groupRole ?? "singleton",
571
+ compact,
572
+ tree: toolGroupTree(context),
573
+ dot: toolStatusDotFromContext(context, theme),
574
+ title: theme.fg("toolTitle", theme.bold("$")),
575
+ detail
576
+ })), text;
577
+ },
578
+ renderResult(result, options2, _theme, context) {
579
+ let state = context.state;
580
+ state.startedAt !== void 0 && options2.isPartial && !state.interval && (state.interval = setInterval(() => context.invalidate(), 1e3)), (!options2.isPartial || context.isError) && (state.endedAt ??= Date.now(), state.interval && (clearInterval(state.interval), state.interval = void 0));
581
+ let component = context.lastComponent ?? new BashResultRenderComponent(), compact = !options2.isPartial && !options2.expanded && !context.isError;
582
+ return rebuildBashResultRenderComponent(component, result, options2, context.showImages, state.startedAt, state.endedAt, compact), component.invalidate(), component;
583
+ }
584
+ };
585
+ }
586
+ function createBashTool(cwd, options) {
587
+ return wrapToolDefinition(createBashToolDefinition(cwd, options));
588
+ }
589
+
590
+ // node_modules/diff/libesm/diff/base.js
591
+ var Diff = class {
592
+ diff(oldStr, newStr, options = {}) {
593
+ let callback;
594
+ typeof options == "function" ? (callback = options, options = {}) : "callback" in options && (callback = options.callback);
595
+ let oldString = this.castInput(oldStr, options), newString = this.castInput(newStr, options), oldTokens = this.removeEmpty(this.tokenize(oldString, options)), newTokens = this.removeEmpty(this.tokenize(newString, options));
596
+ return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
597
+ }
598
+ diffWithOptionsObj(oldTokens, newTokens, options, callback) {
599
+ var _a;
600
+ let done = (value) => {
601
+ if (value = this.postProcess(value, options), callback) {
602
+ setTimeout(function() {
603
+ callback(value);
604
+ }, 0);
605
+ return;
606
+ } else
607
+ return value;
608
+ }, newLen = newTokens.length, oldLen = oldTokens.length, editLength = 1, maxEditLength = newLen + oldLen;
609
+ options.maxEditLength != null && (maxEditLength = Math.min(maxEditLength, options.maxEditLength));
610
+ let maxExecutionTime = (_a = options.timeout) !== null && _a !== void 0 ? _a : 1 / 0, abortAfterTimestamp = Date.now() + maxExecutionTime, bestPath = [{ oldPos: -1, lastComponent: void 0 }], newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
611
+ if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen)
612
+ return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
613
+ let minDiagonalToConsider = -1 / 0, maxDiagonalToConsider = 1 / 0, execEditLength = () => {
614
+ for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
615
+ let basePath, removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
616
+ removePath && (bestPath[diagonalPath - 1] = void 0);
617
+ let canAdd = !1;
618
+ if (addPath) {
619
+ let addPathNewPos = addPath.oldPos - diagonalPath;
620
+ canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
621
+ }
622
+ let canRemove = removePath && removePath.oldPos + 1 < oldLen;
623
+ if (!canAdd && !canRemove) {
624
+ bestPath[diagonalPath] = void 0;
625
+ continue;
626
+ }
627
+ if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos ? basePath = this.addToPath(addPath, !0, !1, 0, options) : basePath = this.addToPath(removePath, !1, !0, 1, options), newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options), basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen)
628
+ return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || !0;
629
+ bestPath[diagonalPath] = basePath, basePath.oldPos + 1 >= oldLen && (maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1)), newPos + 1 >= newLen && (minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1));
630
+ }
631
+ editLength++;
632
+ };
633
+ if (callback)
634
+ (function exec() {
635
+ setTimeout(function() {
636
+ if (editLength > maxEditLength || Date.now() > abortAfterTimestamp)
637
+ return callback(void 0);
638
+ execEditLength() || exec();
639
+ }, 0);
640
+ })();
641
+ else
642
+ for (; editLength <= maxEditLength && Date.now() <= abortAfterTimestamp; ) {
643
+ let ret = execEditLength();
644
+ if (ret)
645
+ return ret;
646
+ }
647
+ }
648
+ addToPath(path3, added, removed, oldPosInc, options) {
649
+ let last = path3.lastComponent;
650
+ return last && !options.oneChangePerToken && last.added === added && last.removed === removed ? {
651
+ oldPos: path3.oldPos + oldPosInc,
652
+ lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
653
+ } : {
654
+ oldPos: path3.oldPos + oldPosInc,
655
+ lastComponent: { count: 1, added, removed, previousComponent: last }
656
+ };
657
+ }
658
+ extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
659
+ let newLen = newTokens.length, oldLen = oldTokens.length, oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
660
+ for (; newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options); )
661
+ newPos++, oldPos++, commonCount++, options.oneChangePerToken && (basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: !1, removed: !1 });
662
+ return commonCount && !options.oneChangePerToken && (basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: !1, removed: !1 }), basePath.oldPos = oldPos, newPos;
663
+ }
664
+ equals(left, right, options) {
665
+ return options.comparator ? options.comparator(left, right) : left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
666
+ }
667
+ removeEmpty(array) {
668
+ let ret = [];
669
+ for (let i = 0; i < array.length; i++)
670
+ array[i] && ret.push(array[i]);
671
+ return ret;
672
+ }
673
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
674
+ castInput(value, options) {
675
+ return value;
676
+ }
677
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
678
+ tokenize(value, options) {
679
+ return Array.from(value);
680
+ }
681
+ join(chars) {
682
+ return chars.join("");
683
+ }
684
+ postProcess(changeObjects, options) {
685
+ return changeObjects;
686
+ }
687
+ get useLongestToken() {
688
+ return !1;
689
+ }
690
+ buildValues(lastComponent, newTokens, oldTokens) {
691
+ let components = [], nextComponent;
692
+ for (; lastComponent; )
693
+ components.push(lastComponent), nextComponent = lastComponent.previousComponent, delete lastComponent.previousComponent, lastComponent = nextComponent;
694
+ components.reverse();
695
+ let componentLen = components.length, componentPos = 0, newPos = 0, oldPos = 0;
696
+ for (; componentPos < componentLen; componentPos++) {
697
+ let component = components[componentPos];
698
+ if (component.removed)
699
+ component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count)), oldPos += component.count;
700
+ else {
701
+ if (!component.added && this.useLongestToken) {
702
+ let value = newTokens.slice(newPos, newPos + component.count);
703
+ value = value.map(function(value2, i) {
704
+ let oldValue = oldTokens[oldPos + i];
705
+ return oldValue.length > value2.length ? oldValue : value2;
706
+ }), component.value = this.join(value);
707
+ } else
708
+ component.value = this.join(newTokens.slice(newPos, newPos + component.count));
709
+ newPos += component.count, component.added || (oldPos += component.count);
710
+ }
711
+ }
712
+ return components;
713
+ }
714
+ };
715
+
716
+ // node_modules/diff/libesm/util/string.js
717
+ function longestCommonPrefix(str1, str2) {
718
+ let i;
719
+ for (i = 0; i < str1.length && i < str2.length; i++)
720
+ if (str1[i] != str2[i])
721
+ return str1.slice(0, i);
722
+ return str1.slice(0, i);
723
+ }
724
+ function longestCommonSuffix(str1, str2) {
725
+ let i;
726
+ if (!str1 || !str2 || str1[str1.length - 1] != str2[str2.length - 1])
727
+ return "";
728
+ for (i = 0; i < str1.length && i < str2.length; i++)
729
+ if (str1[str1.length - (i + 1)] != str2[str2.length - (i + 1)])
730
+ return str1.slice(-i);
731
+ return str1.slice(-i);
732
+ }
733
+ function replacePrefix(string, oldPrefix, newPrefix) {
734
+ if (string.slice(0, oldPrefix.length) != oldPrefix)
735
+ throw Error(`string ${JSON.stringify(string)} doesn't start with prefix ${JSON.stringify(oldPrefix)}; this is a bug`);
736
+ return newPrefix + string.slice(oldPrefix.length);
737
+ }
738
+ function replaceSuffix(string, oldSuffix, newSuffix) {
739
+ if (!oldSuffix)
740
+ return string + newSuffix;
741
+ if (string.slice(-oldSuffix.length) != oldSuffix)
742
+ throw Error(`string ${JSON.stringify(string)} doesn't end with suffix ${JSON.stringify(oldSuffix)}; this is a bug`);
743
+ return string.slice(0, -oldSuffix.length) + newSuffix;
744
+ }
745
+ function removePrefix(string, oldPrefix) {
746
+ return replacePrefix(string, oldPrefix, "");
747
+ }
748
+ function removeSuffix(string, oldSuffix) {
749
+ return replaceSuffix(string, oldSuffix, "");
750
+ }
751
+ function maximumOverlap(string1, string2) {
752
+ return string2.slice(0, overlapCount(string1, string2));
753
+ }
754
+ function overlapCount(a, b) {
755
+ let startA = 0;
756
+ a.length > b.length && (startA = a.length - b.length);
757
+ let endB = b.length;
758
+ a.length < b.length && (endB = a.length);
759
+ let map = Array(endB), k = 0;
760
+ map[0] = 0;
761
+ for (let j = 1; j < endB; j++) {
762
+ for (b[j] == b[k] ? map[j] = map[k] : map[j] = k; k > 0 && b[j] != b[k]; )
763
+ k = map[k];
764
+ b[j] == b[k] && k++;
765
+ }
766
+ k = 0;
767
+ for (let i = startA; i < a.length; i++) {
768
+ for (; k > 0 && a[i] != b[k]; )
769
+ k = map[k];
770
+ a[i] == b[k] && k++;
771
+ }
772
+ return k;
773
+ }
774
+ function segment(string, segmenter) {
775
+ let parts = [];
776
+ for (let segmentObj of Array.from(segmenter.segment(string))) {
777
+ let segment2 = segmentObj.segment;
778
+ parts.length && /\s/.test(parts[parts.length - 1]) && /\s/.test(segment2) ? parts[parts.length - 1] += segment2 : parts.push(segment2);
779
+ }
780
+ return parts;
781
+ }
782
+ function trailingWs(string, segmenter) {
783
+ if (segmenter)
784
+ return leadingAndTrailingWs(string, segmenter)[1];
785
+ let i;
786
+ for (i = string.length - 1; i >= 0 && string[i].match(/\s/); i--)
787
+ ;
788
+ return string.substring(i + 1);
789
+ }
790
+ function leadingWs(string, segmenter) {
791
+ if (segmenter)
792
+ return leadingAndTrailingWs(string, segmenter)[0];
793
+ let match = string.match(/^\s*/);
794
+ return match ? match[0] : "";
795
+ }
796
+ function leadingAndTrailingWs(string, segmenter) {
797
+ if (!segmenter)
798
+ return [leadingWs(string), trailingWs(string)];
799
+ if (segmenter.resolvedOptions().granularity != "word")
800
+ throw new Error('The segmenter passed must have a granularity of "word"');
801
+ let segments = segment(string, segmenter), firstSeg = segments[0], lastSeg = segments[segments.length - 1], head = /\s/.test(firstSeg) ? firstSeg : "", tail = /\s/.test(lastSeg) ? lastSeg : "";
802
+ return [head, tail];
803
+ }
804
+
805
+ // node_modules/diff/libesm/diff/word.js
806
+ var extendedWordChars = "a-zA-Z0-9_\\u{AD}\\u{C0}-\\u{D6}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}", tokenizeIncludingWhitespace = new RegExp(`[${extendedWordChars}]+|\\s+|[^${extendedWordChars}]`, "ug"), WordDiff = class extends Diff {
807
+ equals(left, right, options) {
808
+ return options.ignoreCase && (left = left.toLowerCase(), right = right.toLowerCase()), left.trim() === right.trim();
809
+ }
810
+ tokenize(value, options = {}) {
811
+ let parts;
812
+ if (options.intlSegmenter) {
813
+ let segmenter = options.intlSegmenter;
814
+ if (segmenter.resolvedOptions().granularity != "word")
815
+ throw new Error('The segmenter passed must have a granularity of "word"');
816
+ parts = segment(value, segmenter);
817
+ } else
818
+ parts = value.match(tokenizeIncludingWhitespace) || [];
819
+ let tokens = [], prevPart = null;
820
+ return parts.forEach((part) => {
821
+ /\s/.test(part) ? prevPart == null ? tokens.push(part) : tokens.push(tokens.pop() + part) : prevPart != null && /\s/.test(prevPart) ? tokens[tokens.length - 1] == prevPart ? tokens.push(tokens.pop() + part) : tokens.push(prevPart + part) : tokens.push(part), prevPart = part;
822
+ }), tokens;
823
+ }
824
+ join(tokens) {
825
+ return tokens.map((token, i) => i == 0 ? token : token.replace(/^\s+/, "")).join("");
826
+ }
827
+ postProcess(changes, options) {
828
+ if (!changes || options.oneChangePerToken)
829
+ return changes;
830
+ let lastKeep = null, insertion = null, deletion = null;
831
+ return changes.forEach((change) => {
832
+ change.added ? insertion = change : change.removed ? deletion = change : ((insertion || deletion) && dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change, options.intlSegmenter), lastKeep = change, insertion = null, deletion = null);
833
+ }), (insertion || deletion) && dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null, options.intlSegmenter), changes;
834
+ }
835
+ }, wordDiff = new WordDiff();
836
+ function diffWords(oldStr, newStr, options) {
837
+ return options?.ignoreWhitespace != null && !options.ignoreWhitespace ? diffWordsWithSpace(oldStr, newStr, options) : wordDiff.diff(oldStr, newStr, options);
838
+ }
839
+ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep, segmenter) {
840
+ if (deletion && insertion) {
841
+ let [oldWsPrefix, oldWsSuffix] = leadingAndTrailingWs(deletion.value, segmenter), [newWsPrefix, newWsSuffix] = leadingAndTrailingWs(insertion.value, segmenter);
842
+ if (startKeep) {
843
+ let commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix);
844
+ startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix), deletion.value = removePrefix(deletion.value, commonWsPrefix), insertion.value = removePrefix(insertion.value, commonWsPrefix);
845
+ }
846
+ if (endKeep) {
847
+ let commonWsSuffix = longestCommonSuffix(oldWsSuffix, newWsSuffix);
848
+ endKeep.value = replacePrefix(endKeep.value, newWsSuffix, commonWsSuffix), deletion.value = removeSuffix(deletion.value, commonWsSuffix), insertion.value = removeSuffix(insertion.value, commonWsSuffix);
849
+ }
850
+ } else if (insertion) {
851
+ if (startKeep) {
852
+ let ws = leadingWs(insertion.value, segmenter);
853
+ insertion.value = insertion.value.substring(ws.length);
854
+ }
855
+ if (endKeep) {
856
+ let ws = leadingWs(endKeep.value, segmenter);
857
+ endKeep.value = endKeep.value.substring(ws.length);
858
+ }
859
+ } else if (startKeep && endKeep) {
860
+ let newWsFull = leadingWs(endKeep.value, segmenter), [delWsStart, delWsEnd] = leadingAndTrailingWs(deletion.value, segmenter), newWsStart = longestCommonPrefix(newWsFull, delWsStart);
861
+ deletion.value = removePrefix(deletion.value, newWsStart);
862
+ let newWsEnd = longestCommonSuffix(removePrefix(newWsFull, newWsStart), delWsEnd);
863
+ deletion.value = removeSuffix(deletion.value, newWsEnd), endKeep.value = replacePrefix(endKeep.value, newWsFull, newWsEnd), startKeep.value = replaceSuffix(startKeep.value, newWsFull, newWsFull.slice(0, newWsFull.length - newWsEnd.length));
864
+ } else if (endKeep) {
865
+ let endKeepWsPrefix = leadingWs(endKeep.value, segmenter), deletionWsSuffix = trailingWs(deletion.value, segmenter), overlap = maximumOverlap(deletionWsSuffix, endKeepWsPrefix);
866
+ deletion.value = removeSuffix(deletion.value, overlap);
867
+ } else if (startKeep) {
868
+ let startKeepWsSuffix = trailingWs(startKeep.value, segmenter), deletionWsPrefix = leadingWs(deletion.value, segmenter), overlap = maximumOverlap(startKeepWsSuffix, deletionWsPrefix);
869
+ deletion.value = removePrefix(deletion.value, overlap);
870
+ }
871
+ }
872
+ var WordsWithSpaceDiff = class extends Diff {
873
+ tokenize(value) {
874
+ let regex = new RegExp(`(\\r?\\n)|[${extendedWordChars}]+|[^\\S\\n\\r]+|[^${extendedWordChars}]`, "ug");
875
+ return value.match(regex) || [];
876
+ }
877
+ }, wordsWithSpaceDiff = new WordsWithSpaceDiff();
878
+ function diffWordsWithSpace(oldStr, newStr, options) {
879
+ return wordsWithSpaceDiff.diff(oldStr, newStr, options);
880
+ }
881
+
882
+ // node_modules/diff/libesm/diff/line.js
883
+ var LineDiff = class extends Diff {
884
+ constructor() {
885
+ super(...arguments), this.tokenize = tokenize;
886
+ }
887
+ equals(left, right, options) {
888
+ return options.ignoreWhitespace ? ((!options.newlineIsToken || !left.includes(`
889
+ `)) && (left = left.trim()), (!options.newlineIsToken || !right.includes(`
890
+ `)) && (right = right.trim())) : options.ignoreNewlineAtEof && !options.newlineIsToken && (left.endsWith(`
891
+ `) && (left = left.slice(0, -1)), right.endsWith(`
892
+ `) && (right = right.slice(0, -1))), super.equals(left, right, options);
893
+ }
894
+ }, lineDiff = new LineDiff();
895
+ function diffLines(oldStr, newStr, options) {
896
+ return lineDiff.diff(oldStr, newStr, options);
897
+ }
898
+ function tokenize(value, options) {
899
+ options.stripTrailingCr && (value = value.replace(/\r\n/g, `
900
+ `));
901
+ let retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
902
+ linesAndNewlines[linesAndNewlines.length - 1] || linesAndNewlines.pop();
903
+ for (let i = 0; i < linesAndNewlines.length; i++) {
904
+ let line = linesAndNewlines[i];
905
+ i % 2 && !options.newlineIsToken ? retLines[retLines.length - 1] += line : retLines.push(line);
906
+ }
907
+ return retLines;
908
+ }
909
+
910
+ // node_modules/diff/libesm/patch/create.js
911
+ var INCLUDE_HEADERS = {
912
+ includeIndex: !0,
913
+ includeUnderline: !0,
914
+ includeFileHeaders: !0
915
+ }, FILE_HEADERS_ONLY = {
916
+ includeIndex: !1,
917
+ includeUnderline: !1,
918
+ includeFileHeaders: !0
919
+ };
920
+ function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
921
+ let optionsObj;
922
+ options ? typeof options == "function" ? optionsObj = { callback: options } : optionsObj = options : optionsObj = {}, typeof optionsObj.context > "u" && (optionsObj.context = 4);
923
+ let context = optionsObj.context;
924
+ if (optionsObj.newlineIsToken)
925
+ throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");
926
+ if (optionsObj.callback) {
927
+ let { callback } = optionsObj;
928
+ diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {
929
+ let patch = diffLinesResultToPatch(diff);
930
+ callback(patch);
931
+ } }));
932
+ } else
933
+ return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
934
+ function diffLinesResultToPatch(diff) {
935
+ if (!diff)
936
+ return;
937
+ diff.push({ value: "", lines: [] });
938
+ function contextLines(lines) {
939
+ return lines.map(function(entry) {
940
+ return " " + entry;
941
+ });
942
+ }
943
+ let hunks = [], oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
944
+ for (let i = 0; i < diff.length; i++) {
945
+ let current = diff[i], lines = current.lines || splitLines(current.value);
946
+ if (current.lines = lines, current.added || current.removed) {
947
+ if (!oldRangeStart) {
948
+ let prev = diff[i - 1];
949
+ oldRangeStart = oldLine, newRangeStart = newLine, prev && (curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [], oldRangeStart -= curRange.length, newRangeStart -= curRange.length);
950
+ }
951
+ for (let line of lines)
952
+ curRange.push((current.added ? "+" : "-") + line);
953
+ current.added ? newLine += lines.length : oldLine += lines.length;
954
+ } else {
955
+ if (oldRangeStart)
956
+ if (lines.length <= context * 2 && i < diff.length - 2)
957
+ for (let line of contextLines(lines))
958
+ curRange.push(line);
959
+ else {
960
+ let contextSize = Math.min(lines.length, context);
961
+ for (let line of contextLines(lines.slice(0, contextSize)))
962
+ curRange.push(line);
963
+ let hunk = {
964
+ oldStart: oldRangeStart,
965
+ oldLines: oldLine - oldRangeStart + contextSize,
966
+ newStart: newRangeStart,
967
+ newLines: newLine - newRangeStart + contextSize,
968
+ lines: curRange
969
+ };
970
+ hunks.push(hunk), oldRangeStart = 0, newRangeStart = 0, curRange = [];
971
+ }
972
+ oldLine += lines.length, newLine += lines.length;
973
+ }
974
+ }
975
+ for (let hunk of hunks)
976
+ for (let i = 0; i < hunk.lines.length; i++)
977
+ hunk.lines[i].endsWith(`
978
+ `) ? hunk.lines[i] = hunk.lines[i].slice(0, -1) : (hunk.lines.splice(i + 1, 0, "\"), i++);
979
+ return {
980
+ oldFileName,
981
+ newFileName,
982
+ oldHeader,
983
+ newHeader,
984
+ hunks
985
+ };
986
+ }
987
+ }
988
+ function formatPatch(patch, headerOptions) {
989
+ if (headerOptions || (headerOptions = INCLUDE_HEADERS), Array.isArray(patch)) {
990
+ if (patch.length > 1 && !headerOptions.includeFileHeaders)
991
+ throw new Error("Cannot omit file headers on a multi-file patch. (The result would be unparseable; how would a tool trying to apply the patch know which changes are to which file?)");
992
+ return patch.map((p) => formatPatch(p, headerOptions)).join(`
993
+ `);
994
+ }
995
+ let ret = [];
996
+ headerOptions.includeIndex && patch.oldFileName == patch.newFileName && ret.push("Index: " + patch.oldFileName), headerOptions.includeUnderline && ret.push("==================================================================="), headerOptions.includeFileHeaders && (ret.push("--- " + patch.oldFileName + (typeof patch.oldHeader > "u" ? "" : " " + patch.oldHeader)), ret.push("+++ " + patch.newFileName + (typeof patch.newHeader > "u" ? "" : " " + patch.newHeader)));
997
+ for (let i = 0; i < patch.hunks.length; i++) {
998
+ let hunk = patch.hunks[i];
999
+ hunk.oldLines === 0 && (hunk.oldStart -= 1), hunk.newLines === 0 && (hunk.newStart -= 1), ret.push("@@ -" + hunk.oldStart + "," + hunk.oldLines + " +" + hunk.newStart + "," + hunk.newLines + " @@");
1000
+ for (let line of hunk.lines)
1001
+ ret.push(line);
1002
+ }
1003
+ return ret.join(`
1004
+ `) + `
1005
+ `;
1006
+ }
1007
+ function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
1008
+ if (typeof options == "function" && (options = { callback: options }), options?.callback) {
1009
+ let { callback } = options;
1010
+ structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: (patchObj) => {
1011
+ callback(patchObj ? formatPatch(patchObj, options.headerOptions) : void 0);
1012
+ } }));
1013
+ } else {
1014
+ let patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
1015
+ return patchObj ? formatPatch(patchObj, options?.headerOptions) : void 0;
1016
+ }
1017
+ }
1018
+ function splitLines(text) {
1019
+ let hasTrailingNl = text.endsWith(`
1020
+ `), result = text.split(`
1021
+ `).map((line) => line + `
1022
+ `);
1023
+ return hasTrailingNl ? result.pop() : result.push(result.pop().slice(0, -1)), result;
1024
+ }
1025
+
1026
+ // packages/coding-agent/dist/modes/interactive/components/diff.js
1027
+ function parseDiffLine(line) {
1028
+ let match = line.match(/^([+-\s])(\s*\d*)\s(.*)$/);
1029
+ return match ? { prefix: match[1], lineNum: match[2], content: match[3] } : null;
1030
+ }
1031
+ function replaceTabs2(text) {
1032
+ return text.replace(/\t/g, " ");
1033
+ }
1034
+ function renderIntraLineDiff(oldContent, newContent) {
1035
+ let wordDiff2 = diffWords(oldContent, newContent), removedLine = "", addedLine = "", isFirstRemoved = !0, isFirstAdded = !0;
1036
+ for (let part of wordDiff2)
1037
+ if (part.removed) {
1038
+ let value = part.value;
1039
+ if (isFirstRemoved) {
1040
+ let leadingWs2 = value.match(/^(\s*)/)?.[1] || "";
1041
+ value = value.slice(leadingWs2.length), removedLine += leadingWs2, isFirstRemoved = !1;
1042
+ }
1043
+ value && (removedLine += theme.inverse(value));
1044
+ } else if (part.added) {
1045
+ let value = part.value;
1046
+ if (isFirstAdded) {
1047
+ let leadingWs2 = value.match(/^(\s*)/)?.[1] || "";
1048
+ value = value.slice(leadingWs2.length), addedLine += leadingWs2, isFirstAdded = !1;
1049
+ }
1050
+ value && (addedLine += theme.inverse(value));
1051
+ } else
1052
+ removedLine += part.value, addedLine += part.value;
1053
+ return { removedLine, addedLine };
1054
+ }
1055
+ function renderDiff(diffText, _options = {}) {
1056
+ let lines = diffText.split(`
1057
+ `), result = [], i = 0;
1058
+ for (; i < lines.length; ) {
1059
+ let line = lines[i], parsed = parseDiffLine(line);
1060
+ if (!parsed) {
1061
+ result.push(theme.fg("toolDiffContext", line)), i++;
1062
+ continue;
1063
+ }
1064
+ if (parsed.prefix === "-") {
1065
+ let removedLines = [];
1066
+ for (; i < lines.length; ) {
1067
+ let p = parseDiffLine(lines[i]);
1068
+ if (!p || p.prefix !== "-")
1069
+ break;
1070
+ removedLines.push({ lineNum: p.lineNum, content: p.content }), i++;
1071
+ }
1072
+ let addedLines = [];
1073
+ for (; i < lines.length; ) {
1074
+ let p = parseDiffLine(lines[i]);
1075
+ if (!p || p.prefix !== "+")
1076
+ break;
1077
+ addedLines.push({ lineNum: p.lineNum, content: p.content }), i++;
1078
+ }
1079
+ if (removedLines.length === 1 && addedLines.length === 1) {
1080
+ let removed = removedLines[0], added = addedLines[0], { removedLine, addedLine } = renderIntraLineDiff(replaceTabs2(removed.content), replaceTabs2(added.content));
1081
+ result.push(theme.fg("toolDiffRemoved", `-${removed.lineNum} ${removedLine}`)), result.push(theme.fg("toolDiffAdded", `+${added.lineNum} ${addedLine}`));
1082
+ } else {
1083
+ for (let removed of removedLines)
1084
+ result.push(theme.fg("toolDiffRemoved", `-${removed.lineNum} ${replaceTabs2(removed.content)}`));
1085
+ for (let added of addedLines)
1086
+ result.push(theme.fg("toolDiffAdded", `+${added.lineNum} ${replaceTabs2(added.content)}`));
1087
+ }
1088
+ } else parsed.prefix === "+" ? (result.push(theme.fg("toolDiffAdded", `+${parsed.lineNum} ${replaceTabs2(parsed.content)}`)), i++) : (result.push(theme.fg("toolDiffContext", ` ${parsed.lineNum} ${replaceTabs2(parsed.content)}`)), i++);
1089
+ }
1090
+ return result.join(`
1091
+ `);
1092
+ }
1093
+
1094
+ // packages/coding-agent/dist/core/tools/edit-diff.js
1095
+ import { constants as constants3 } from "fs";
1096
+ import { access as access2, readFile } from "fs/promises";
1097
+
1098
+ // packages/coding-agent/dist/core/tools/path-utils.js
1099
+ import { accessSync, constants as constants2 } from "node:fs";
1100
+ import { access } from "node:fs/promises";
1101
+ var NARROW_NO_BREAK_SPACE = "\u202F";
1102
+ function tryMacOSScreenshotPath(filePath) {
1103
+ return filePath.replace(/ (AM|PM)\./gi, `${NARROW_NO_BREAK_SPACE}$1.`);
1104
+ }
1105
+ function tryNFDVariant(filePath) {
1106
+ return filePath.normalize("NFD");
1107
+ }
1108
+ function tryCurlyQuoteVariant(filePath) {
1109
+ return filePath.replace(/'/g, "\u2019");
1110
+ }
1111
+ function fileExists(filePath) {
1112
+ try {
1113
+ return accessSync(filePath, constants2.F_OK), !0;
1114
+ } catch {
1115
+ return !1;
1116
+ }
1117
+ }
1118
+ async function pathExists(filePath) {
1119
+ try {
1120
+ return await access(filePath, constants2.F_OK), !0;
1121
+ } catch {
1122
+ return !1;
1123
+ }
1124
+ }
1125
+ function resolveToCwd(filePath, cwd) {
1126
+ return resolvePath(filePath, cwd, { normalizeUnicodeSpaces: !0, stripAtPrefix: !0 });
1127
+ }
1128
+ function resolveReadPath(filePath, cwd) {
1129
+ let resolved = resolveToCwd(filePath, cwd);
1130
+ if (fileExists(resolved))
1131
+ return resolved;
1132
+ let amPmVariant = tryMacOSScreenshotPath(resolved);
1133
+ if (amPmVariant !== resolved && fileExists(amPmVariant))
1134
+ return amPmVariant;
1135
+ let nfdVariant = tryNFDVariant(resolved);
1136
+ if (nfdVariant !== resolved && fileExists(nfdVariant))
1137
+ return nfdVariant;
1138
+ let curlyVariant = tryCurlyQuoteVariant(resolved);
1139
+ if (curlyVariant !== resolved && fileExists(curlyVariant))
1140
+ return curlyVariant;
1141
+ let nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);
1142
+ return nfdCurlyVariant !== resolved && fileExists(nfdCurlyVariant) ? nfdCurlyVariant : resolved;
1143
+ }
1144
+ async function resolveReadPathAsync(filePath, cwd) {
1145
+ let resolved = resolveToCwd(filePath, cwd);
1146
+ if (await pathExists(resolved))
1147
+ return resolved;
1148
+ let amPmVariant = tryMacOSScreenshotPath(resolved);
1149
+ if (amPmVariant !== resolved && await pathExists(amPmVariant))
1150
+ return amPmVariant;
1151
+ let nfdVariant = tryNFDVariant(resolved);
1152
+ if (nfdVariant !== resolved && await pathExists(nfdVariant))
1153
+ return nfdVariant;
1154
+ let curlyVariant = tryCurlyQuoteVariant(resolved);
1155
+ if (curlyVariant !== resolved && await pathExists(curlyVariant))
1156
+ return curlyVariant;
1157
+ let nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);
1158
+ return nfdCurlyVariant !== resolved && await pathExists(nfdCurlyVariant) ? nfdCurlyVariant : resolved;
1159
+ }
1160
+
1161
+ // packages/coding-agent/dist/core/tools/edit-diff.js
1162
+ function detectLineEnding(content) {
1163
+ let crlfIdx = content.indexOf(`\r
1164
+ `), lfIdx = content.indexOf(`
1165
+ `);
1166
+ return lfIdx === -1 || crlfIdx === -1 ? `
1167
+ ` : crlfIdx < lfIdx ? `\r
1168
+ ` : `
1169
+ `;
1170
+ }
1171
+ function normalizeToLF(text) {
1172
+ return text.replace(/\r\n/g, `
1173
+ `).replace(/\r/g, `
1174
+ `);
1175
+ }
1176
+ function restoreLineEndings(text, ending) {
1177
+ return ending === `\r
1178
+ ` ? text.replace(/\n/g, `\r
1179
+ `) : text;
1180
+ }
1181
+ function normalizeForFuzzyMatch(text) {
1182
+ return text.normalize("NFKC").split(`
1183
+ `).map((line) => line.trimEnd()).join(`
1184
+ `).replace(/[\u2018\u2019\u201A\u201B]/g, "'").replace(/[\u201C\u201D\u201E\u201F]/g, '"').replace(/[\u2010\u2011\u2012\u2013\u2014\u2015\u2212]/g, "-").replace(/[\u00A0\u2002-\u200A\u202F\u205F\u3000]/g, " ");
1185
+ }
1186
+ function splitLinesWithEndings(content) {
1187
+ return content.match(/[^\n]*\n|[^\n]+/g) ?? [];
1188
+ }
1189
+ function getLineSpans(content) {
1190
+ let offset = 0;
1191
+ return splitLinesWithEndings(content).map((line) => {
1192
+ let span = { start: offset, end: offset + line.length };
1193
+ return offset = span.end, span;
1194
+ });
1195
+ }
1196
+ function getReplacementLineRange(lines, replacement) {
1197
+ let replacementStart = replacement.matchIndex, replacementEnd = replacement.matchIndex + replacement.matchLength, startLine = -1;
1198
+ for (let i = 0; i < lines.length; i++) {
1199
+ let line = lines[i];
1200
+ if (replacementStart >= line.start && replacementStart < line.end) {
1201
+ startLine = i;
1202
+ break;
1203
+ }
1204
+ }
1205
+ if (startLine === -1)
1206
+ throw new Error("Replacement range is outside the base content.");
1207
+ let endLine = startLine;
1208
+ for (; endLine < lines.length && lines[endLine].end < replacementEnd; )
1209
+ endLine++;
1210
+ if (endLine >= lines.length)
1211
+ throw new Error("Replacement range is outside the base content.");
1212
+ return { startLine, endLine: endLine + 1 };
1213
+ }
1214
+ function applyReplacements(content, replacements, offset = 0) {
1215
+ let result = content;
1216
+ for (let i = replacements.length - 1; i >= 0; i--) {
1217
+ let replacement = replacements[i], matchIndex = replacement.matchIndex - offset;
1218
+ result = result.substring(0, matchIndex) + replacement.newText + result.substring(matchIndex + replacement.matchLength);
1219
+ }
1220
+ return result;
1221
+ }
1222
+ function applyReplacementsPreservingUnchangedLines(originalContent, baseContent, replacements) {
1223
+ let originalLines = splitLinesWithEndings(originalContent), baseLines = getLineSpans(baseContent);
1224
+ if (originalLines.length !== baseLines.length)
1225
+ throw new Error("Cannot preserve unchanged lines because the base content has a different line count.");
1226
+ let groups = [], sortedReplacements = [...replacements].sort((a, b) => a.matchIndex - b.matchIndex);
1227
+ for (let replacement of sortedReplacements) {
1228
+ let range = getReplacementLineRange(baseLines, replacement), current = groups[groups.length - 1];
1229
+ if (current && range.startLine < current.endLine) {
1230
+ current.endLine = Math.max(current.endLine, range.endLine), current.replacements.push(replacement);
1231
+ continue;
1232
+ }
1233
+ groups.push({ ...range, replacements: [replacement] });
1234
+ }
1235
+ let originalLineIndex = 0, result = "";
1236
+ for (let group of groups) {
1237
+ result += originalLines.slice(originalLineIndex, group.startLine).join("");
1238
+ let groupStartOffset = baseLines[group.startLine].start, groupEndOffset = baseLines[group.endLine - 1].end;
1239
+ result += applyReplacements(baseContent.slice(groupStartOffset, groupEndOffset), group.replacements, groupStartOffset), originalLineIndex = group.endLine;
1240
+ }
1241
+ return result += originalLines.slice(originalLineIndex).join(""), result;
1242
+ }
1243
+ function fuzzyFindText(content, oldText) {
1244
+ let exactIndex = content.indexOf(oldText);
1245
+ if (exactIndex !== -1)
1246
+ return {
1247
+ found: !0,
1248
+ index: exactIndex,
1249
+ matchLength: oldText.length,
1250
+ usedFuzzyMatch: !1,
1251
+ contentForReplacement: content
1252
+ };
1253
+ let fuzzyContent = normalizeForFuzzyMatch(content), fuzzyOldText = normalizeForFuzzyMatch(oldText), fuzzyIndex = fuzzyContent.indexOf(fuzzyOldText);
1254
+ return fuzzyIndex === -1 ? {
1255
+ found: !1,
1256
+ index: -1,
1257
+ matchLength: 0,
1258
+ usedFuzzyMatch: !1,
1259
+ contentForReplacement: content
1260
+ } : {
1261
+ found: !0,
1262
+ index: fuzzyIndex,
1263
+ matchLength: fuzzyOldText.length,
1264
+ usedFuzzyMatch: !0,
1265
+ contentForReplacement: fuzzyContent
1266
+ };
1267
+ }
1268
+ function stripBom(content) {
1269
+ return content.startsWith("\uFEFF") ? { bom: "\uFEFF", text: content.slice(1) } : { bom: "", text: content };
1270
+ }
1271
+ function countOccurrences(content, oldText) {
1272
+ let fuzzyContent = normalizeForFuzzyMatch(content), fuzzyOldText = normalizeForFuzzyMatch(oldText);
1273
+ return fuzzyContent.split(fuzzyOldText).length - 1;
1274
+ }
1275
+ function getNotFoundError(path3, editIndex, totalEdits) {
1276
+ return totalEdits === 1 ? new Error(`Could not find the exact text in ${path3}. The old text must match exactly including all whitespace and newlines.`) : new Error(`Could not find edits[${editIndex}] in ${path3}. The oldText must match exactly including all whitespace and newlines.`);
1277
+ }
1278
+ function getDuplicateError(path3, editIndex, totalEdits, occurrences) {
1279
+ return totalEdits === 1 ? new Error(`Found ${occurrences} occurrences of the text in ${path3}. The text must be unique. Please provide more context to make it unique.`) : new Error(`Found ${occurrences} occurrences of edits[${editIndex}] in ${path3}. Each oldText must be unique. Please provide more context to make it unique.`);
1280
+ }
1281
+ function getEmptyOldTextError(path3, editIndex, totalEdits) {
1282
+ return totalEdits === 1 ? new Error(`oldText must not be empty in ${path3}.`) : new Error(`edits[${editIndex}].oldText must not be empty in ${path3}.`);
1283
+ }
1284
+ function getNoChangeError(path3, totalEdits) {
1285
+ return totalEdits === 1 ? new Error(`No changes made to ${path3}. The replacement produced identical content. This might indicate an issue with special characters or the text not existing as expected.`) : new Error(`No changes made to ${path3}. The replacements produced identical content.`);
1286
+ }
1287
+ function applyEditsToNormalizedContent(normalizedContent, edits, path3) {
1288
+ let normalizedEdits = edits.map((edit) => ({
1289
+ oldText: normalizeToLF(edit.oldText),
1290
+ newText: normalizeToLF(edit.newText)
1291
+ }));
1292
+ for (let i = 0; i < normalizedEdits.length; i++)
1293
+ if (normalizedEdits[i].oldText.length === 0)
1294
+ throw getEmptyOldTextError(path3, i, normalizedEdits.length);
1295
+ let usedFuzzyMatch = normalizedEdits.map((edit) => fuzzyFindText(normalizedContent, edit.oldText)).some((match) => match.usedFuzzyMatch), replacementBaseContent = usedFuzzyMatch ? normalizeForFuzzyMatch(normalizedContent) : normalizedContent, matchedEdits = [];
1296
+ for (let i = 0; i < normalizedEdits.length; i++) {
1297
+ let edit = normalizedEdits[i], matchResult = fuzzyFindText(replacementBaseContent, edit.oldText);
1298
+ if (!matchResult.found)
1299
+ throw getNotFoundError(path3, i, normalizedEdits.length);
1300
+ let occurrences = countOccurrences(replacementBaseContent, edit.oldText);
1301
+ if (occurrences > 1)
1302
+ throw getDuplicateError(path3, i, normalizedEdits.length, occurrences);
1303
+ matchedEdits.push({
1304
+ editIndex: i,
1305
+ matchIndex: matchResult.index,
1306
+ matchLength: matchResult.matchLength,
1307
+ newText: edit.newText
1308
+ });
1309
+ }
1310
+ matchedEdits.sort((a, b) => a.matchIndex - b.matchIndex);
1311
+ for (let i = 1; i < matchedEdits.length; i++) {
1312
+ let previous = matchedEdits[i - 1], current = matchedEdits[i];
1313
+ if (previous.matchIndex + previous.matchLength > current.matchIndex)
1314
+ throw new Error(`edits[${previous.editIndex}] and edits[${current.editIndex}] overlap in ${path3}. Merge them into one edit or target disjoint regions.`);
1315
+ }
1316
+ let baseContent = normalizedContent, newContent = usedFuzzyMatch ? applyReplacementsPreservingUnchangedLines(normalizedContent, replacementBaseContent, matchedEdits) : applyReplacements(replacementBaseContent, matchedEdits);
1317
+ if (baseContent === newContent)
1318
+ throw getNoChangeError(path3, normalizedEdits.length);
1319
+ return { baseContent, newContent };
1320
+ }
1321
+ function generateUnifiedPatch(path3, oldContent, newContent, contextLines = 4) {
1322
+ return createTwoFilesPatch(path3, path3, oldContent, newContent, void 0, void 0, {
1323
+ context: contextLines,
1324
+ headerOptions: FILE_HEADERS_ONLY
1325
+ });
1326
+ }
1327
+ function generateDiffString(oldContent, newContent, contextLines = 4) {
1328
+ let parts = diffLines(oldContent, newContent), output = [], oldLines = oldContent.split(`
1329
+ `), newLines = newContent.split(`
1330
+ `), maxLineNum = Math.max(oldLines.length, newLines.length), lineNumWidth = String(maxLineNum).length, oldLineNum = 1, newLineNum = 1, lastWasChange = !1, firstChangedLine;
1331
+ for (let i = 0; i < parts.length; i++) {
1332
+ let part = parts[i], raw = part.value.split(`
1333
+ `);
1334
+ if (raw[raw.length - 1] === "" && raw.pop(), part.added || part.removed) {
1335
+ firstChangedLine === void 0 && (firstChangedLine = newLineNum);
1336
+ for (let line of raw)
1337
+ if (part.added) {
1338
+ let lineNum = String(newLineNum).padStart(lineNumWidth, " ");
1339
+ output.push(`+${lineNum} ${line}`), newLineNum++;
1340
+ } else {
1341
+ let lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
1342
+ output.push(`-${lineNum} ${line}`), oldLineNum++;
1343
+ }
1344
+ lastWasChange = !0;
1345
+ } else {
1346
+ let nextPartIsChange = i < parts.length - 1 && (parts[i + 1].added || parts[i + 1].removed), hasLeadingChange = lastWasChange, hasTrailingChange = nextPartIsChange;
1347
+ if (hasLeadingChange && hasTrailingChange)
1348
+ if (raw.length <= contextLines * 2)
1349
+ for (let line of raw) {
1350
+ let lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
1351
+ output.push(` ${lineNum} ${line}`), oldLineNum++, newLineNum++;
1352
+ }
1353
+ else {
1354
+ let leadingLines = raw.slice(0, contextLines), trailingLines = raw.slice(raw.length - contextLines), skippedLines = raw.length - leadingLines.length - trailingLines.length;
1355
+ for (let line of leadingLines) {
1356
+ let lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
1357
+ output.push(` ${lineNum} ${line}`), oldLineNum++, newLineNum++;
1358
+ }
1359
+ output.push(` ${"".padStart(lineNumWidth, " ")} ...`), oldLineNum += skippedLines, newLineNum += skippedLines;
1360
+ for (let line of trailingLines) {
1361
+ let lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
1362
+ output.push(` ${lineNum} ${line}`), oldLineNum++, newLineNum++;
1363
+ }
1364
+ }
1365
+ else if (hasLeadingChange) {
1366
+ let shownLines = raw.slice(0, contextLines), skippedLines = raw.length - shownLines.length;
1367
+ for (let line of shownLines) {
1368
+ let lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
1369
+ output.push(` ${lineNum} ${line}`), oldLineNum++, newLineNum++;
1370
+ }
1371
+ skippedLines > 0 && (output.push(` ${"".padStart(lineNumWidth, " ")} ...`), oldLineNum += skippedLines, newLineNum += skippedLines);
1372
+ } else if (hasTrailingChange) {
1373
+ let skippedLines = Math.max(0, raw.length - contextLines);
1374
+ skippedLines > 0 && (output.push(` ${"".padStart(lineNumWidth, " ")} ...`), oldLineNum += skippedLines, newLineNum += skippedLines);
1375
+ for (let line of raw.slice(skippedLines)) {
1376
+ let lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
1377
+ output.push(` ${lineNum} ${line}`), oldLineNum++, newLineNum++;
1378
+ }
1379
+ } else
1380
+ oldLineNum += raw.length, newLineNum += raw.length;
1381
+ lastWasChange = !1;
1382
+ }
1383
+ }
1384
+ return { diff: output.join(`
1385
+ `), firstChangedLine };
1386
+ }
1387
+ async function computeEditsDiff(path3, edits, cwd) {
1388
+ let absolutePath = resolveToCwd(path3, cwd);
1389
+ try {
1390
+ try {
1391
+ await access2(absolutePath, constants3.R_OK);
1392
+ } catch (error) {
1393
+ let errorMessage = error instanceof Error && "code" in error ? `Error code: ${error.code}` : String(error);
1394
+ return { error: `Could not edit file: ${path3}. ${errorMessage}.` };
1395
+ }
1396
+ let rawContent = await readFile(absolutePath, "utf-8"), { text: content } = stripBom(rawContent), normalizedContent = normalizeToLF(content), { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path3);
1397
+ return generateDiffString(baseContent, newContent);
1398
+ } catch (err) {
1399
+ return { error: err instanceof Error ? err.message : String(err) };
1400
+ }
1401
+ }
1402
+
1403
+ // packages/coding-agent/dist/core/tools/file-mutation-queue.js
1404
+ import { realpath } from "node:fs/promises";
1405
+ import { resolve } from "node:path";
1406
+ var fileMutationQueues = /* @__PURE__ */ new Map(), registrationQueue = Promise.resolve();
1407
+ function isMissingPathError(error) {
1408
+ return typeof error == "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
1409
+ }
1410
+ async function getMutationQueueKey(filePath) {
1411
+ let resolvedPath = resolve(filePath);
1412
+ try {
1413
+ return await realpath(resolvedPath);
1414
+ } catch (error) {
1415
+ if (isMissingPathError(error))
1416
+ return resolvedPath;
1417
+ throw error;
1418
+ }
1419
+ }
1420
+ async function withFileMutationQueue(filePath, fn) {
1421
+ let registration = registrationQueue.then(async () => {
1422
+ let key2 = await getMutationQueueKey(filePath), currentQueue2 = fileMutationQueues.get(key2) ?? Promise.resolve(), releaseNext2, nextQueue = new Promise((resolveQueue) => {
1423
+ releaseNext2 = resolveQueue;
1424
+ }), chainedQueue2 = currentQueue2.then(() => nextQueue);
1425
+ return fileMutationQueues.set(key2, chainedQueue2), { key: key2, currentQueue: currentQueue2, chainedQueue: chainedQueue2, releaseNext: releaseNext2 };
1426
+ });
1427
+ registrationQueue = registration.then(() => {
1428
+ }, () => {
1429
+ });
1430
+ let { key, currentQueue, chainedQueue, releaseNext } = await registration;
1431
+ await currentQueue;
1432
+ try {
1433
+ return await fn();
1434
+ } finally {
1435
+ releaseNext(), fileMutationQueues.get(key) === chainedQueue && fileMutationQueues.delete(key);
1436
+ }
1437
+ }
1438
+
1439
+ // packages/coding-agent/dist/core/tools/edit.js
1440
+ import { Box, Container as Container2, Spacer, Text as Text3 } from "@ashx-j/lunr-tui";
1441
+ import { constants as constants4 } from "fs";
1442
+ import { access as fsAccess2, readFile as fsReadFile, writeFile as fsWriteFile } from "fs/promises";
1443
+ import { Type as Type2 } from "typebox";
1444
+ var replaceEditSchema = Type2.Object({
1445
+ oldText: Type2.String({
1446
+ description: "Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call."
1447
+ }),
1448
+ newText: Type2.String({ description: "Replacement text for this targeted edit." })
1449
+ }, {}), editSchema = Type2.Object({
1450
+ path: Type2.String({ description: "Path to the file to edit (relative or absolute)" }),
1451
+ edits: Type2.Array(replaceEditSchema, {
1452
+ description: "One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead."
1453
+ })
1454
+ }, {}), defaultEditOperations = {
1455
+ readFile: (path3) => fsReadFile(path3),
1456
+ writeFile: (path3, content) => fsWriteFile(path3, content, "utf-8"),
1457
+ access: (path3) => fsAccess2(path3, constants4.R_OK | constants4.W_OK)
1458
+ };
1459
+ function prepareEditArguments(input) {
1460
+ if (!input || typeof input != "object")
1461
+ return input;
1462
+ let args = input;
1463
+ if (typeof args.edits == "string")
1464
+ try {
1465
+ let parsed = JSON.parse(args.edits);
1466
+ Array.isArray(parsed) && (args.edits = parsed);
1467
+ } catch {
1468
+ }
1469
+ let legacy = args;
1470
+ if (typeof legacy.oldText != "string" || typeof legacy.newText != "string")
1471
+ return args;
1472
+ let edits = Array.isArray(legacy.edits) ? [...legacy.edits] : [];
1473
+ edits.push({ oldText: legacy.oldText, newText: legacy.newText });
1474
+ let { oldText: _oldText, newText: _newText, ...rest } = legacy;
1475
+ return { ...rest, edits };
1476
+ }
1477
+ function validateEditInput(input) {
1478
+ if (!Array.isArray(input.edits) || input.edits.length === 0)
1479
+ throw new Error("Edit tool input is invalid. edits must contain at least one replacement.");
1480
+ return { path: input.path, edits: input.edits };
1481
+ }
1482
+ function createEditCallRenderComponent() {
1483
+ return Object.assign(new Box(1, 1, (text) => text), {
1484
+ preview: void 0,
1485
+ previewArgsKey: void 0,
1486
+ previewPending: !1,
1487
+ settledError: !1
1488
+ });
1489
+ }
1490
+ function getEditCallRenderComponent(state, lastComponent) {
1491
+ if (lastComponent instanceof Box) {
1492
+ let component2 = lastComponent;
1493
+ return state.callComponent = component2, component2;
1494
+ }
1495
+ if (state.callComponent)
1496
+ return state.callComponent;
1497
+ let component = createEditCallRenderComponent();
1498
+ return state.callComponent = component, component;
1499
+ }
1500
+ function getRenderablePreviewInput(args) {
1501
+ if (!args)
1502
+ return null;
1503
+ let path3 = typeof args.path == "string" ? args.path : typeof args.file_path == "string" ? args.file_path : null;
1504
+ return path3 ? Array.isArray(args.edits) && args.edits.length > 0 && args.edits.every((edit) => typeof edit?.oldText == "string" && typeof edit?.newText == "string") ? { path: path3, edits: args.edits } : typeof args.oldText == "string" && typeof args.newText == "string" ? { path: path3, edits: [{ oldText: args.oldText, newText: args.newText }] } : null : null;
1505
+ }
1506
+ function formatEditCall(args, theme2, cwd, compact = !1) {
1507
+ let rawPath = str(args?.file_path ?? args?.path);
1508
+ return compact ? renderToolFileName(rawPath, theme2, cwd) : renderToolPath(rawPath, theme2, cwd);
1509
+ }
1510
+ function formatEditResult(args, preview, result, theme2, isError) {
1511
+ let rawPath = str(args?.file_path ?? args?.path), previewDiff = preview && !("error" in preview) ? preview.diff : void 0, previewError = preview && "error" in preview ? preview.error : void 0;
1512
+ if (isError) {
1513
+ let errorText = result.content.filter((c) => c.type === "text").map((c) => c.text || "").join(`
1514
+ `);
1515
+ return !errorText || errorText === previewError ? void 0 : theme2.fg("error", errorText);
1516
+ }
1517
+ let resultDiff = result.details?.diff;
1518
+ if (resultDiff && resultDiff !== previewDiff)
1519
+ return renderDiff(resultDiff, { filePath: rawPath ?? void 0 });
1520
+ }
1521
+ function getEditHeaderBg(preview, settledError, theme2) {
1522
+ return preview ? "error" in preview ? (text) => theme2.bg("toolErrorBg", text) : (text) => theme2.bg("toolSuccessBg", text) : settledError ? (text) => theme2.bg("toolErrorBg", text) : (text) => theme2.bg("toolPendingBg", text);
1523
+ }
1524
+ function buildEditCallComponent(component, args, theme2, cwd, dotState, compact = !1, role = "singleton", tree = compact) {
1525
+ component.setBgFn(getEditHeaderBg(component.preview, component.settledError, theme2)), component.clear();
1526
+ let grouped = tree && role !== "singleton", pathDisplay = formatEditCall(args, theme2, cwd, compact || grouped);
1527
+ if (component.addChild(new Text3(formatGroupedCall({
1528
+ role,
1529
+ compact,
1530
+ tree,
1531
+ dot: toolStatusDot(dotState, theme2),
1532
+ title: theme2.fg("toolTitle", theme2.bold("edit")),
1533
+ detail: pathDisplay
1534
+ }), 0, 0)), compact || grouped || !component.preview)
1535
+ return component;
1536
+ let body = "error" in component.preview ? theme2.fg("error", component.preview.error) : renderDiff(component.preview.diff);
1537
+ return component.addChild(new Spacer(1)), component.addChild(new Text3(body, 0, 0)), component;
1538
+ }
1539
+ function setEditPreview(component, preview, argsKey) {
1540
+ let current = component.preview, changed = current === void 0 || ("error" in current && "error" in preview ? current.error !== preview.error : "error" in current != "error" in preview) || !("error" in current) && !("error" in preview) && (current.diff !== preview.diff || current.firstChangedLine !== preview.firstChangedLine);
1541
+ return component.preview = preview, component.previewArgsKey = argsKey, component.previewPending = !1, changed;
1542
+ }
1543
+ function createEditToolDefinition(cwd, options) {
1544
+ let ops = options?.operations ?? defaultEditOperations;
1545
+ return {
1546
+ name: "edit",
1547
+ label: "edit",
1548
+ description: "Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.",
1549
+ promptSnippet: "Make precise file edits with exact text replacement, including multiple disjoint edits in one call",
1550
+ promptGuidelines: [
1551
+ "Use edit for precise changes (edits[].oldText must match exactly)",
1552
+ "When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls",
1553
+ "Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.",
1554
+ "Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions."
1555
+ ],
1556
+ parameters: editSchema,
1557
+ renderShell: "self",
1558
+ prepareArguments: prepareEditArguments,
1559
+ async execute(_toolCallId, input, signal, _onUpdate, _ctx) {
1560
+ let { path: path3, edits } = validateEditInput(input), absolutePath = resolveToCwd(path3, cwd);
1561
+ return withFileMutationQueue(absolutePath, async () => {
1562
+ let throwIfAborted = () => {
1563
+ if (signal?.aborted)
1564
+ throw new Error("Operation aborted");
1565
+ };
1566
+ throwIfAborted();
1567
+ try {
1568
+ await ops.access(absolutePath);
1569
+ } catch (error) {
1570
+ throwIfAborted();
1571
+ let errorMessage = error instanceof Error && "code" in error ? `Error code: ${error.code}` : String(error);
1572
+ throw new Error(`Could not edit file: ${path3}. ${errorMessage}.`);
1573
+ }
1574
+ throwIfAborted();
1575
+ let rawContent = (await ops.readFile(absolutePath)).toString("utf-8");
1576
+ throwIfAborted();
1577
+ let { bom, text: content } = stripBom(rawContent), originalEnding = detectLineEnding(content), normalizedContent = normalizeToLF(content), { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path3);
1578
+ throwIfAborted();
1579
+ let finalContent = bom + restoreLineEndings(newContent, originalEnding);
1580
+ await ops.writeFile(absolutePath, finalContent), throwIfAborted();
1581
+ let diffResult = generateDiffString(baseContent, newContent), patch = generateUnifiedPatch(path3, baseContent, newContent);
1582
+ return {
1583
+ content: [
1584
+ {
1585
+ type: "text",
1586
+ text: `Successfully replaced ${edits.length} block(s) in ${path3}.`
1587
+ }
1588
+ ],
1589
+ details: { diff: diffResult.diff, patch, firstChangedLine: diffResult.firstChangedLine }
1590
+ };
1591
+ });
1592
+ },
1593
+ renderCall(args, theme2, context) {
1594
+ let component = getEditCallRenderComponent(context.state, context.lastComponent), previewInput = getRenderablePreviewInput(args), argsKey = previewInput ? JSON.stringify({ path: previewInput.path, edits: previewInput.edits }) : void 0;
1595
+ if (component.previewArgsKey !== argsKey && (component.preview = void 0, component.previewArgsKey = argsKey, component.previewPending = !1, component.settledError = !1), context.argsComplete && previewInput && !component.preview && !component.previewPending) {
1596
+ component.previewPending = !0;
1597
+ let requestKey = argsKey;
1598
+ computeEditsDiff(previewInput.path, previewInput.edits, context.cwd).then((preview) => {
1599
+ component.previewArgsKey === requestKey && (setEditPreview(component, preview, requestKey), context.invalidate());
1600
+ });
1601
+ }
1602
+ return buildEditCallComponent(
1603
+ component,
1604
+ args,
1605
+ theme2,
1606
+ context.cwd,
1607
+ context.isPartial ? "pending" : context.isError ? "error" : "success",
1608
+ // lunr: compact-by-default
1609
+ !context.isPartial && !context.expanded && !context.isError,
1610
+ context.groupRole ?? "singleton",
1611
+ toolGroupTree(context)
1612
+ );
1613
+ },
1614
+ renderResult(result, _options, theme2, context) {
1615
+ let callComponent = context.state.callComponent, previewInput = getRenderablePreviewInput(context.args), argsKey = previewInput ? JSON.stringify({ path: previewInput.path, edits: previewInput.edits }) : void 0, typedResult = result, resultDiff = context.isError ? void 0 : typedResult.details?.diff, compact = !_options.isPartial && !_options.expanded && !context.isError, changed = !1;
1616
+ callComponent && (typeof resultDiff == "string" && (changed = setEditPreview(callComponent, { diff: resultDiff, firstChangedLine: typedResult.details?.firstChangedLine }, argsKey) || changed), callComponent.settledError !== context.isError && (callComponent.settledError = context.isError, changed = !0), (changed || compact) && buildEditCallComponent(callComponent, context.args, theme2, context.cwd, context.isPartial ? "pending" : context.isError ? "error" : "success", compact, context.groupRole ?? "singleton", toolGroupTree(context)));
1617
+ let output = compact ? void 0 : formatEditResult(context.args, callComponent?.preview, typedResult, theme2, context.isError), component = context.lastComponent ?? new Container2();
1618
+ return component.clear(), output && (component.addChild(new Spacer(1)), component.addChild(new Text3(output, 1, 0))), component;
1619
+ }
1620
+ };
1621
+ }
1622
+ function createEditTool(cwd, options) {
1623
+ return wrapToolDefinition(createEditToolDefinition(cwd, options));
1624
+ }
1625
+
1626
+ // packages/coding-agent/dist/utils/tools-manager.js
1627
+ import chalk from "chalk";
1628
+ import { spawnSync } from "child_process";
1629
+ import { chmodSync, createWriteStream as createWriteStream2, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "fs";
1630
+ import { arch, platform } from "os";
1631
+ import { join as join2 } from "path";
1632
+ import { Readable } from "stream";
1633
+ import { pipeline } from "stream/promises";
1634
+ var TOOLS_DIR = getBinDir(), NETWORK_TIMEOUT_MS = 1e4, DOWNLOAD_TIMEOUT_MS = 12e4;
1635
+ function isOfflineModeEnabled() {
1636
+ let value = process.env.PI_OFFLINE;
1637
+ return value ? value === "1" || value.toLowerCase() === "true" || value.toLowerCase() === "yes" : !1;
1638
+ }
1639
+ var TOOLS = {
1640
+ fd: {
1641
+ name: "fd",
1642
+ repo: "sharkdp/fd",
1643
+ binaryName: "fd",
1644
+ systemBinaryNames: ["fd", "fdfind"],
1645
+ tagPrefix: "v",
1646
+ getAssetName: (version, plat, architecture) => plat === "darwin" ? `fd-v${version}-${architecture === "arm64" ? "aarch64" : "x86_64"}-apple-darwin.tar.gz` : plat === "linux" ? `fd-v${version}-${architecture === "arm64" ? "aarch64" : "x86_64"}-unknown-linux-gnu.tar.gz` : plat === "win32" ? `fd-v${version}-${architecture === "arm64" ? "aarch64" : "x86_64"}-pc-windows-msvc.zip` : null
1647
+ },
1648
+ rg: {
1649
+ name: "ripgrep",
1650
+ repo: "BurntSushi/ripgrep",
1651
+ binaryName: "rg",
1652
+ tagPrefix: "",
1653
+ getAssetName: (version, plat, architecture) => plat === "darwin" ? `ripgrep-${version}-${architecture === "arm64" ? "aarch64" : "x86_64"}-apple-darwin.tar.gz` : plat === "linux" ? architecture === "arm64" ? `ripgrep-${version}-aarch64-unknown-linux-gnu.tar.gz` : `ripgrep-${version}-x86_64-unknown-linux-musl.tar.gz` : plat === "win32" ? `ripgrep-${version}-${architecture === "arm64" ? "aarch64" : "x86_64"}-pc-windows-msvc.zip` : null
1654
+ }
1655
+ };
1656
+ function commandExists(cmd) {
1657
+ try {
1658
+ let result = spawnSync(cmd, ["--version"], { stdio: "pipe" });
1659
+ return result.error === void 0 || result.error === null;
1660
+ } catch {
1661
+ return !1;
1662
+ }
1663
+ }
1664
+ function getToolPath(tool) {
1665
+ let config = TOOLS[tool];
1666
+ if (!config)
1667
+ return null;
1668
+ let localPath = join2(TOOLS_DIR, config.binaryName + (platform() === "win32" ? ".exe" : ""));
1669
+ if (existsSync(localPath))
1670
+ return localPath;
1671
+ let systemBinaryNames = config.systemBinaryNames ?? [config.binaryName];
1672
+ for (let systemBinaryName of systemBinaryNames)
1673
+ if (commandExists(systemBinaryName))
1674
+ return systemBinaryName;
1675
+ return null;
1676
+ }
1677
+ async function getLatestVersion(repo) {
1678
+ let response = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, {
1679
+ headers: { "User-Agent": `${APP_NAME}-coding-agent` },
1680
+ signal: AbortSignal.timeout(NETWORK_TIMEOUT_MS)
1681
+ });
1682
+ if (!response.ok)
1683
+ throw new Error(`GitHub API error: ${response.status}`);
1684
+ return (await response.json()).tag_name.replace(/^v/, "");
1685
+ }
1686
+ async function downloadFile(url, dest) {
1687
+ let response = await fetch(url, {
1688
+ signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
1689
+ });
1690
+ if (!response.ok)
1691
+ throw new Error(`Failed to download: ${response.status}`);
1692
+ if (!response.body)
1693
+ throw new Error("No response body");
1694
+ let fileStream = createWriteStream2(dest);
1695
+ await pipeline(Readable.fromWeb(response.body), fileStream);
1696
+ }
1697
+ function findBinaryRecursively(rootDir, binaryFileName) {
1698
+ let stack = [rootDir];
1699
+ for (; stack.length > 0; ) {
1700
+ let currentDir = stack.pop();
1701
+ if (!currentDir)
1702
+ continue;
1703
+ let entries = readdirSync(currentDir, { withFileTypes: !0 });
1704
+ for (let entry of entries) {
1705
+ let fullPath = join2(currentDir, entry.name);
1706
+ if (entry.isFile() && entry.name === binaryFileName)
1707
+ return fullPath;
1708
+ entry.isDirectory() && stack.push(fullPath);
1709
+ }
1710
+ }
1711
+ return null;
1712
+ }
1713
+ function formatSpawnFailure(result) {
1714
+ if (result.error?.message)
1715
+ return result.error.message;
1716
+ let stderr = result.stderr?.toString().trim();
1717
+ if (stderr)
1718
+ return stderr;
1719
+ let stdout = result.stdout?.toString().trim();
1720
+ return stdout || `exit status ${result.status ?? "unknown"}`;
1721
+ }
1722
+ function runExtractionCommand(command, args) {
1723
+ let result = spawnSync(command, args, { stdio: "pipe" });
1724
+ return !result.error && result.status === 0 ? null : `${command}: ${formatSpawnFailure(result)}`;
1725
+ }
1726
+ function extractTarGzArchive(archivePath, extractDir, assetName) {
1727
+ let failure = runExtractionCommand("tar", ["xzf", archivePath, "-C", extractDir]);
1728
+ if (failure)
1729
+ throw new Error(`Failed to extract ${assetName}: ${failure}`);
1730
+ }
1731
+ function getWindowsTarCommand() {
1732
+ let systemRoot = process.env.SystemRoot ?? process.env.WINDIR;
1733
+ if (systemRoot) {
1734
+ let systemTar = join2(systemRoot, "System32", "tar.exe");
1735
+ if (existsSync(systemTar))
1736
+ return systemTar;
1737
+ }
1738
+ return "tar.exe";
1739
+ }
1740
+ function extractZipArchive(archivePath, extractDir, assetName) {
1741
+ let failures = [];
1742
+ if (platform() === "win32") {
1743
+ let tarFailure = runExtractionCommand(getWindowsTarCommand(), ["xf", archivePath, "-C", extractDir]);
1744
+ if (!tarFailure)
1745
+ return;
1746
+ failures.push(tarFailure);
1747
+ let powershellFailure = runExtractionCommand("powershell.exe", [
1748
+ "-NoLogo",
1749
+ "-NoProfile",
1750
+ "-NonInteractive",
1751
+ "-ExecutionPolicy",
1752
+ "Bypass",
1753
+ "-Command",
1754
+ "& { param($archive, $destination) $ErrorActionPreference = 'Stop'; Expand-Archive -LiteralPath $archive -DestinationPath $destination -Force }",
1755
+ archivePath,
1756
+ extractDir
1757
+ ]);
1758
+ if (!powershellFailure)
1759
+ return;
1760
+ failures.push(powershellFailure);
1761
+ } else {
1762
+ let unzipFailure = runExtractionCommand("unzip", ["-q", archivePath, "-d", extractDir]);
1763
+ if (!unzipFailure)
1764
+ return;
1765
+ failures.push(unzipFailure);
1766
+ let tarFailure = runExtractionCommand("tar", ["xf", archivePath, "-C", extractDir]);
1767
+ if (!tarFailure)
1768
+ return;
1769
+ failures.push(tarFailure);
1770
+ }
1771
+ throw new Error(`Failed to extract ${assetName}: ${failures.join("; ")}`);
1772
+ }
1773
+ async function downloadTool(tool) {
1774
+ let config = TOOLS[tool];
1775
+ if (!config)
1776
+ throw new Error(`Unknown tool: ${tool}`);
1777
+ let plat = platform(), architecture = arch(), version = await getLatestVersion(config.repo);
1778
+ tool === "fd" && plat === "darwin" && architecture === "x64" && (version = "10.3.0");
1779
+ let assetName = config.getAssetName(version, plat, architecture);
1780
+ if (!assetName)
1781
+ throw new Error(`Unsupported platform: ${plat}/${architecture}`);
1782
+ mkdirSync(TOOLS_DIR, { recursive: !0 });
1783
+ let downloadUrl = `https://github.com/${config.repo}/releases/download/${config.tagPrefix}${version}/${assetName}`, archivePath = join2(TOOLS_DIR, assetName), binaryExt = plat === "win32" ? ".exe" : "", binaryPath = join2(TOOLS_DIR, config.binaryName + binaryExt);
1784
+ await downloadFile(downloadUrl, archivePath);
1785
+ let extractDir = join2(TOOLS_DIR, `extract_tmp_${config.binaryName}_${process.pid}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`);
1786
+ mkdirSync(extractDir, { recursive: !0 });
1787
+ try {
1788
+ if (assetName.endsWith(".tar.gz"))
1789
+ extractTarGzArchive(archivePath, extractDir, assetName);
1790
+ else if (assetName.endsWith(".zip"))
1791
+ extractZipArchive(archivePath, extractDir, assetName);
1792
+ else
1793
+ throw new Error(`Unsupported archive format: ${assetName}`);
1794
+ let binaryFileName = config.binaryName + binaryExt, extractedDir = join2(extractDir, assetName.replace(/\.(tar\.gz|zip)$/, "")), extractedBinary = [join2(extractedDir, binaryFileName), join2(extractDir, binaryFileName)].find((candidate) => existsSync(candidate));
1795
+ if (extractedBinary || (extractedBinary = findBinaryRecursively(extractDir, binaryFileName) ?? void 0), extractedBinary)
1796
+ renameSync(extractedBinary, binaryPath);
1797
+ else
1798
+ throw new Error(`Binary not found in archive: expected ${binaryFileName} under ${extractDir}`);
1799
+ plat !== "win32" && chmodSync(binaryPath, 493);
1800
+ } finally {
1801
+ rmSync(archivePath, { force: !0 }), rmSync(extractDir, { recursive: !0, force: !0 });
1802
+ }
1803
+ return binaryPath;
1804
+ }
1805
+ var TERMUX_PACKAGES = {
1806
+ fd: "fd",
1807
+ rg: "ripgrep"
1808
+ };
1809
+ async function ensureTool(tool, silent = !1) {
1810
+ let existingPath = getToolPath(tool);
1811
+ if (existingPath)
1812
+ return existingPath;
1813
+ let config = TOOLS[tool];
1814
+ if (config) {
1815
+ if (isOfflineModeEnabled()) {
1816
+ silent || console.log(chalk.yellow(`${config.name} not found. Offline mode enabled, skipping download.`));
1817
+ return;
1818
+ }
1819
+ if (platform() === "android") {
1820
+ let pkgName = TERMUX_PACKAGES[tool] ?? tool;
1821
+ silent || console.log(chalk.yellow(`${config.name} not found. Install with: pkg install ${pkgName}`));
1822
+ return;
1823
+ }
1824
+ silent || console.log(chalk.dim(`${config.name} not found. Downloading...`));
1825
+ try {
1826
+ let path3 = await downloadTool(tool);
1827
+ return silent || console.log(chalk.dim(`${config.name} installed to ${path3}`)), path3;
1828
+ } catch (e) {
1829
+ silent || console.log(chalk.yellow(`Failed to download ${config.name}: ${e instanceof Error ? e.message : e}`));
1830
+ return;
1831
+ }
1832
+ }
1833
+ }
1834
+
1835
+ // packages/coding-agent/dist/core/tools/find.js
1836
+ import { createInterface } from "node:readline";
1837
+ import { Text as Text4 } from "@ashx-j/lunr-tui";
1838
+ import { spawn as spawn3 } from "child_process";
1839
+ import path from "path";
1840
+ import { Type as Type3 } from "typebox";
1841
+ function toPosixPath(value) {
1842
+ return value.split(path.sep).join("/");
1843
+ }
1844
+ var findSchema = Type3.Object({
1845
+ pattern: Type3.String({
1846
+ description: "Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'"
1847
+ }),
1848
+ path: Type3.Optional(Type3.String({ description: "Directory to search in (default: current directory)" })),
1849
+ limit: Type3.Optional(Type3.Number({ description: "Maximum number of results (default: 1000)" }))
1850
+ }), DEFAULT_LIMIT = 1e3, defaultFindOperations = {
1851
+ exists: pathExists,
1852
+ // This is a placeholder. Actual fd execution happens in execute() when no custom glob is provided.
1853
+ glob: () => []
1854
+ };
1855
+ function formatFindCall(args, theme2, cwd, compact = !1) {
1856
+ let pattern = str(args?.pattern), rawPath = str(args?.path), limit = args?.limit, invalidArg = invalidArgText(theme2), text = pattern === null ? invalidArg : theme2.fg("accent", pattern || "");
1857
+ if (compact) {
1858
+ let collapsedPath = renderCollapsedSearchPath(rawPath, theme2, cwd);
1859
+ collapsedPath && (text += theme2.fg("toolOutput", " in ") + collapsedPath);
1860
+ } else {
1861
+ let path3 = rawPath !== null ? shortenPath(rawPath || ".") : null;
1862
+ text += theme2.fg("toolOutput", ` in ${path3 === null ? invalidArg : path3}`);
1863
+ }
1864
+ return limit !== void 0 && (text += theme2.fg("toolOutput", ` (limit ${limit})`)), text;
1865
+ }
1866
+ function formatFindResult(result, options, theme2, showImages) {
1867
+ let output = getTextOutput(result, showImages).trim(), text = "";
1868
+ if (output) {
1869
+ let lines = output.split(`
1870
+ `), maxLines = options.expanded ? lines.length : 20, displayLines = lines.slice(0, maxLines), remaining = lines.length - maxLines;
1871
+ text += `
1872
+ ${displayLines.map((line) => theme2.fg("toolOutput", line)).join(`
1873
+ `)}`, remaining > 0 && (text += `${theme2.fg("muted", `
1874
+ ... (${remaining} more lines,`)} ${keyHint("app.tools.expand", "to expand")}${theme2.fg("muted", ")")}`);
1875
+ }
1876
+ let resultLimit = result.details?.resultLimitReached, truncation = result.details?.truncation;
1877
+ if (resultLimit || truncation?.truncated) {
1878
+ let warnings = [];
1879
+ resultLimit && warnings.push(`${resultLimit} results limit`), truncation?.truncated && warnings.push(`${formatSize(truncation.maxBytes ?? 51200)} limit`), text += `
1880
+ ${theme2.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
1881
+ }
1882
+ return text;
1883
+ }
1884
+ function createFindToolDefinition(cwd, options) {
1885
+ let customOps = options?.operations;
1886
+ return {
1887
+ name: "find",
1888
+ label: "find",
1889
+ description: `Search for files by glob pattern. Returns matching file paths relative to the search directory. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} results or ${51200 / 1024}KB (whichever is hit first).`,
1890
+ promptSnippet: "Find files by glob pattern (respects .gitignore)",
1891
+ parameters: findSchema,
1892
+ async execute(_toolCallId, { pattern, path: searchDir, limit }, signal, _onUpdate, _ctx) {
1893
+ return new Promise((resolve2, reject) => {
1894
+ if (signal?.aborted) {
1895
+ reject(new Error("Operation aborted"));
1896
+ return;
1897
+ }
1898
+ let settled = !1, stopChild, settle = (fn) => {
1899
+ settled || (settled = !0, signal?.removeEventListener("abort", onAbort), stopChild = void 0, fn());
1900
+ }, onAbort = () => {
1901
+ stopChild?.(), settle(() => reject(new Error("Operation aborted")));
1902
+ };
1903
+ signal?.addEventListener("abort", onAbort, { once: !0 }), (async () => {
1904
+ try {
1905
+ let searchPath = resolveToCwd(searchDir || ".", cwd), effectiveLimit = limit ?? DEFAULT_LIMIT, ops = customOps ?? defaultFindOperations;
1906
+ if (customOps?.glob) {
1907
+ if (!await ops.exists(searchPath)) {
1908
+ settle(() => reject(new Error(`Path not found: ${searchPath}`)));
1909
+ return;
1910
+ }
1911
+ if (signal?.aborted) {
1912
+ settle(() => reject(new Error("Operation aborted")));
1913
+ return;
1914
+ }
1915
+ let results = await ops.glob(pattern, searchPath, {
1916
+ ignore: ["**/node_modules/**", "**/.git/**"],
1917
+ limit: effectiveLimit
1918
+ });
1919
+ if (signal?.aborted) {
1920
+ settle(() => reject(new Error("Operation aborted")));
1921
+ return;
1922
+ }
1923
+ if (results.length === 0) {
1924
+ settle(() => resolve2({
1925
+ content: [{ type: "text", text: "No files found matching pattern" }],
1926
+ details: void 0
1927
+ }));
1928
+ return;
1929
+ }
1930
+ let relativized = results.map((p) => p.startsWith(searchPath) ? toPosixPath(p.slice(searchPath.length + 1)) : toPosixPath(path.relative(searchPath, p))), resultLimitReached = relativized.length >= effectiveLimit, rawOutput = relativized.join(`
1931
+ `), truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER }), resultOutput = truncation.content, details = {}, notices = [];
1932
+ resultLimitReached && (notices.push(`${effectiveLimit} results limit reached`), details.resultLimitReached = effectiveLimit), truncation.truncated && (notices.push(`${formatSize(51200)} limit reached`), details.truncation = truncation), notices.length > 0 && (resultOutput += `
1933
+
1934
+ [${notices.join(". ")}]`), settle(() => resolve2({
1935
+ content: [{ type: "text", text: resultOutput }],
1936
+ details: Object.keys(details).length > 0 ? details : void 0
1937
+ }));
1938
+ return;
1939
+ }
1940
+ let fdPath = await ensureTool("fd", !0);
1941
+ if (signal?.aborted) {
1942
+ settle(() => reject(new Error("Operation aborted")));
1943
+ return;
1944
+ }
1945
+ if (!fdPath) {
1946
+ settle(() => reject(new Error("fd is not available and could not be downloaded")));
1947
+ return;
1948
+ }
1949
+ let args = ["--glob", "--color=never", "--hidden"], insideGitRepo = !1;
1950
+ for (let current = searchPath; ; ) {
1951
+ if (await pathExists(path.join(current, ".git"))) {
1952
+ insideGitRepo = !0;
1953
+ break;
1954
+ }
1955
+ let parent = path.dirname(current);
1956
+ if (parent === current)
1957
+ break;
1958
+ current = parent;
1959
+ }
1960
+ insideGitRepo || args.push("--no-require-git"), args.push("--max-results", String(effectiveLimit));
1961
+ let effectivePattern = pattern;
1962
+ pattern.includes("/") && (args.push("--full-path"), !pattern.startsWith("/") && !pattern.startsWith("**/") && pattern !== "**" && (effectivePattern = `**/${pattern}`)), args.push("--", effectivePattern, searchPath);
1963
+ let child = spawn3(fdPath, args, { stdio: ["ignore", "pipe", "pipe"] }), rl = createInterface({ input: child.stdout }), stderr = "", lines = [];
1964
+ stopChild = () => {
1965
+ child.killed || child.kill();
1966
+ };
1967
+ let cleanup = () => {
1968
+ rl.close();
1969
+ };
1970
+ child.stderr?.on("data", (chunk) => {
1971
+ stderr += chunk.toString();
1972
+ }), rl.on("line", (line) => {
1973
+ lines.push(line);
1974
+ }), child.on("error", (error) => {
1975
+ cleanup(), settle(() => reject(new Error(`Failed to run fd: ${error.message}`)));
1976
+ }), child.on("close", (code) => {
1977
+ if (cleanup(), signal?.aborted) {
1978
+ settle(() => reject(new Error("Operation aborted")));
1979
+ return;
1980
+ }
1981
+ let output = lines.join(`
1982
+ `);
1983
+ if (code !== 0) {
1984
+ let errorMsg = stderr.trim() || `fd exited with code ${code}`;
1985
+ if (!output) {
1986
+ settle(() => reject(new Error(errorMsg)));
1987
+ return;
1988
+ }
1989
+ }
1990
+ if (!output) {
1991
+ settle(() => resolve2({
1992
+ content: [{ type: "text", text: "No files found matching pattern" }],
1993
+ details: void 0
1994
+ }));
1995
+ return;
1996
+ }
1997
+ let relativized = [];
1998
+ for (let rawLine of lines) {
1999
+ let line = rawLine.replace(/\r$/, "").trim();
2000
+ if (!line)
2001
+ continue;
2002
+ let hadTrailingSlash = line.endsWith("/") || line.endsWith("\\"), relativePath = line;
2003
+ line.startsWith(searchPath) ? relativePath = line.slice(searchPath.length + 1) : relativePath = path.relative(searchPath, line), hadTrailingSlash && !relativePath.endsWith("/") && (relativePath += "/"), relativized.push(toPosixPath(relativePath));
2004
+ }
2005
+ let resultLimitReached = relativized.length >= effectiveLimit, rawOutput = relativized.join(`
2006
+ `), truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER }), resultOutput = truncation.content, details = {}, notices = [];
2007
+ resultLimitReached && (notices.push(`${effectiveLimit} results limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`), details.resultLimitReached = effectiveLimit), truncation.truncated && (notices.push(`${formatSize(51200)} limit reached`), details.truncation = truncation), notices.length > 0 && (resultOutput += `
2008
+
2009
+ [${notices.join(". ")}]`), settle(() => resolve2({
2010
+ content: [{ type: "text", text: resultOutput }],
2011
+ details: Object.keys(details).length > 0 ? details : void 0
2012
+ }));
2013
+ });
2014
+ } catch (e) {
2015
+ if (signal?.aborted) {
2016
+ settle(() => reject(new Error("Operation aborted")));
2017
+ return;
2018
+ }
2019
+ let error = e instanceof Error ? e : new Error(String(e));
2020
+ settle(() => reject(error));
2021
+ }
2022
+ })();
2023
+ });
2024
+ },
2025
+ renderCall(args, theme2, context) {
2026
+ let text = context.lastComponent ?? new Text4("", 0, 0), compact = !context.isPartial && !context.expanded && !context.isError;
2027
+ return text.setText(formatGroupedCall({
2028
+ role: context.groupRole ?? "singleton",
2029
+ compact,
2030
+ tree: toolGroupTree(context),
2031
+ dot: toolStatusDotFromContext(context, theme2),
2032
+ title: theme2.fg("toolTitle", theme2.bold("find")),
2033
+ detail: formatFindCall(args, theme2, context.cwd, !context.expanded)
2034
+ })), text;
2035
+ },
2036
+ renderResult(result, options2, theme2, context) {
2037
+ let text = context.lastComponent ?? new Text4("", 0, 0);
2038
+ return !options2.isPartial && !options2.expanded && !context.isError ? (text.setText(""), text) : (text.setText(formatFindResult(result, options2, theme2, context.showImages)), text);
2039
+ }
2040
+ };
2041
+ }
2042
+ function createFindTool(cwd, options) {
2043
+ return wrapToolDefinition(createFindToolDefinition(cwd, options));
2044
+ }
2045
+
2046
+ // packages/coding-agent/dist/core/tools/grep.js
2047
+ import { readFile as fsReadFile2, stat as fsStat } from "node:fs/promises";
2048
+ import { createInterface as createInterface2 } from "node:readline";
2049
+ import { Text as Text5 } from "@ashx-j/lunr-tui";
2050
+ import { spawn as spawn4 } from "child_process";
2051
+ import path2 from "path";
2052
+ import { Type as Type4 } from "typebox";
2053
+ var grepSchema = Type4.Object({
2054
+ pattern: Type4.String({ description: "Search pattern (regex or literal string)" }),
2055
+ path: Type4.Optional(Type4.String({ description: "Directory or file to search (default: current directory)" })),
2056
+ glob: Type4.Optional(Type4.String({ description: "Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'" })),
2057
+ ignoreCase: Type4.Optional(Type4.Boolean({ description: "Case-insensitive search (default: false)" })),
2058
+ literal: Type4.Optional(Type4.Boolean({ description: "Treat pattern as literal string instead of regex (default: false)" })),
2059
+ context: Type4.Optional(Type4.Number({ description: "Number of lines to show before and after each match (default: 0)" })),
2060
+ limit: Type4.Optional(Type4.Number({ description: "Maximum number of matches to return (default: 100)" }))
2061
+ }), DEFAULT_LIMIT2 = 100, defaultGrepOperations = {
2062
+ isDirectory: async (p) => (await fsStat(p)).isDirectory(),
2063
+ readFile: (p) => fsReadFile2(p, "utf-8")
2064
+ };
2065
+ function formatGrepCall(args, theme2, cwd, compact = !1) {
2066
+ let pattern = str(args?.pattern), rawPath = str(args?.path), glob = str(args?.glob), limit = args?.limit, invalidArg = invalidArgText(theme2), text = pattern === null ? invalidArg : theme2.fg("accent", `/${pattern || ""}/`);
2067
+ if (compact) {
2068
+ let collapsedPath = renderCollapsedSearchPath(rawPath, theme2, cwd);
2069
+ collapsedPath && (text += theme2.fg("toolOutput", " in ") + collapsedPath);
2070
+ } else {
2071
+ let path3 = rawPath !== null ? shortenPath(rawPath || ".") : null;
2072
+ text += theme2.fg("toolOutput", ` in ${path3 === null ? invalidArg : path3}`);
2073
+ }
2074
+ return glob && (text += theme2.fg("toolOutput", ` (${glob})`)), limit !== void 0 && (text += theme2.fg("toolOutput", ` limit ${limit}`)), text;
2075
+ }
2076
+ function formatGrepResult(result, options, theme2, showImages) {
2077
+ let output = getTextOutput(result, showImages).trim(), text = "";
2078
+ if (output) {
2079
+ let lines = output.split(`
2080
+ `), maxLines = options.expanded ? lines.length : 15, displayLines = lines.slice(0, maxLines), remaining = lines.length - maxLines;
2081
+ text += `
2082
+ ${displayLines.map((line) => theme2.fg("toolOutput", line)).join(`
2083
+ `)}`, remaining > 0 && (text += `${theme2.fg("muted", `
2084
+ ... (${remaining} more lines,`)} ${keyHint("app.tools.expand", "to expand")}${theme2.fg("muted", ")")}`);
2085
+ }
2086
+ let matchLimit = result.details?.matchLimitReached, truncation = result.details?.truncation, linesTruncated = result.details?.linesTruncated;
2087
+ if (matchLimit || truncation?.truncated || linesTruncated) {
2088
+ let warnings = [];
2089
+ matchLimit && warnings.push(`${matchLimit} matches limit`), truncation?.truncated && warnings.push(`${formatSize(truncation.maxBytes ?? 51200)} limit`), linesTruncated && warnings.push("some lines truncated"), text += `
2090
+ ${theme2.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
2091
+ }
2092
+ return text;
2093
+ }
2094
+ function createGrepToolDefinition(cwd, options) {
2095
+ let customOps = options?.operations;
2096
+ return {
2097
+ name: "grep",
2098
+ label: "grep",
2099
+ description: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT2} matches or ${51200 / 1024}KB (whichever is hit first). Long lines are truncated to ${500} chars.`,
2100
+ promptSnippet: "Search file contents for patterns (respects .gitignore)",
2101
+ parameters: grepSchema,
2102
+ async execute(_toolCallId, { pattern, path: searchDir, glob, ignoreCase, literal, context, limit }, signal, _onUpdate, _ctx) {
2103
+ return new Promise((resolve2, reject) => {
2104
+ if (signal?.aborted) {
2105
+ reject(new Error("Operation aborted"));
2106
+ return;
2107
+ }
2108
+ let settled = !1, settle = (fn) => {
2109
+ settled || (settled = !0, fn());
2110
+ };
2111
+ (async () => {
2112
+ try {
2113
+ let rgPath = await ensureTool("rg", !0);
2114
+ if (!rgPath) {
2115
+ settle(() => reject(new Error("ripgrep (rg) is not available and could not be downloaded")));
2116
+ return;
2117
+ }
2118
+ let searchPath = resolveToCwd(searchDir || ".", cwd), ops = customOps ?? defaultGrepOperations, isDirectory;
2119
+ try {
2120
+ isDirectory = await ops.isDirectory(searchPath);
2121
+ } catch {
2122
+ settle(() => reject(new Error(`Path not found: ${searchPath}`)));
2123
+ return;
2124
+ }
2125
+ let contextValue = context && context > 0 ? context : 0, effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT2), formatPath = (filePath) => {
2126
+ if (isDirectory) {
2127
+ let relative2 = path2.relative(searchPath, filePath);
2128
+ if (relative2 && !relative2.startsWith(".."))
2129
+ return relative2.replace(/\\/g, "/");
2130
+ }
2131
+ return path2.basename(filePath);
2132
+ }, fileCache = /* @__PURE__ */ new Map(), getFileLines = async (filePath) => {
2133
+ let lines = fileCache.get(filePath);
2134
+ if (!lines) {
2135
+ try {
2136
+ lines = (await ops.readFile(filePath)).replace(/\r\n/g, `
2137
+ `).replace(/\r/g, `
2138
+ `).split(`
2139
+ `);
2140
+ } catch {
2141
+ lines = [];
2142
+ }
2143
+ fileCache.set(filePath, lines);
2144
+ }
2145
+ return lines;
2146
+ }, args = ["--json", "--line-number", "--color=never", "--hidden"];
2147
+ ignoreCase && args.push("--ignore-case"), literal && args.push("--fixed-strings"), glob && args.push("--glob", glob), args.push("--", pattern, searchPath);
2148
+ let child = spawn4(rgPath, args, { stdio: ["ignore", "pipe", "pipe"] }), rl = createInterface2({ input: child.stdout }), stderr = "", matchCount = 0, matchLimitReached = !1, linesTruncated = !1, aborted = !1, killedDueToLimit = !1, outputLines = [], cleanup = () => {
2149
+ rl.close(), signal?.removeEventListener("abort", onAbort);
2150
+ }, stopChild = (dueToLimit = !1) => {
2151
+ child.killed || (killedDueToLimit = dueToLimit, child.kill());
2152
+ }, onAbort = () => {
2153
+ aborted = !0, stopChild();
2154
+ };
2155
+ signal?.addEventListener("abort", onAbort, { once: !0 }), child.stderr?.on("data", (chunk) => {
2156
+ stderr += chunk.toString();
2157
+ });
2158
+ let formatBlock = async (filePath, lineNumber) => {
2159
+ let relativePath = formatPath(filePath), lines = await getFileLines(filePath);
2160
+ if (!lines.length)
2161
+ return [`${relativePath}:${lineNumber}: (unable to read file)`];
2162
+ let block = [], start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber, end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;
2163
+ for (let current = start; current <= end; current++) {
2164
+ let sanitized = (lines[current - 1] ?? "").replace(/\r/g, ""), isMatchLine = current === lineNumber, { text: truncatedText, wasTruncated } = truncateLine(sanitized);
2165
+ wasTruncated && (linesTruncated = !0), isMatchLine ? block.push(`${relativePath}:${current}: ${truncatedText}`) : block.push(`${relativePath}-${current}- ${truncatedText}`);
2166
+ }
2167
+ return block;
2168
+ }, matches = [];
2169
+ rl.on("line", (line) => {
2170
+ if (!line.trim() || matchCount >= effectiveLimit)
2171
+ return;
2172
+ let event;
2173
+ try {
2174
+ event = JSON.parse(line);
2175
+ } catch {
2176
+ return;
2177
+ }
2178
+ if (event.type === "match") {
2179
+ matchCount++;
2180
+ let filePath = event.data?.path?.text, lineNumber = event.data?.line_number, lineText = event.data?.lines?.text;
2181
+ filePath && typeof lineNumber == "number" && matches.push({ filePath, lineNumber, lineText }), matchCount >= effectiveLimit && (matchLimitReached = !0, stopChild(!0));
2182
+ }
2183
+ }), child.on("error", (error) => {
2184
+ cleanup(), settle(() => reject(new Error(`Failed to run ripgrep: ${error.message}`)));
2185
+ }), child.on("close", async (code) => {
2186
+ if (cleanup(), aborted) {
2187
+ settle(() => reject(new Error("Operation aborted")));
2188
+ return;
2189
+ }
2190
+ if (!killedDueToLimit && code !== 0 && code !== 1) {
2191
+ let errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;
2192
+ settle(() => reject(new Error(errorMsg)));
2193
+ return;
2194
+ }
2195
+ if (matchCount === 0) {
2196
+ settle(() => resolve2({ content: [{ type: "text", text: "No matches found" }], details: void 0 }));
2197
+ return;
2198
+ }
2199
+ for (let match of matches)
2200
+ if (contextValue === 0 && match.lineText !== void 0) {
2201
+ let relativePath = formatPath(match.filePath), sanitized = match.lineText.replace(/\r\n/g, `
2202
+ `).replace(/\r/g, "").replace(/\n$/, ""), { text: truncatedText, wasTruncated } = truncateLine(sanitized);
2203
+ wasTruncated && (linesTruncated = !0), outputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedText}`);
2204
+ } else {
2205
+ let block = await formatBlock(match.filePath, match.lineNumber);
2206
+ outputLines.push(...block);
2207
+ }
2208
+ let rawOutput = outputLines.join(`
2209
+ `), truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER }), output = truncation.content, details = {}, notices = [];
2210
+ matchLimitReached && (notices.push(`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`), details.matchLimitReached = effectiveLimit), truncation.truncated && (notices.push(`${formatSize(51200)} limit reached`), details.truncation = truncation), linesTruncated && (notices.push(`Some lines truncated to ${500} chars. Use read tool to see full lines`), details.linesTruncated = !0), notices.length > 0 && (output += `
2211
+
2212
+ [${notices.join(". ")}]`), settle(() => resolve2({
2213
+ content: [{ type: "text", text: output }],
2214
+ details: Object.keys(details).length > 0 ? details : void 0
2215
+ }));
2216
+ });
2217
+ } catch (err) {
2218
+ settle(() => reject(err));
2219
+ }
2220
+ })();
2221
+ });
2222
+ },
2223
+ renderCall(args, theme2, context) {
2224
+ let text = context.lastComponent ?? new Text5("", 0, 0), compact = !context.isPartial && !context.expanded && !context.isError;
2225
+ return text.setText(formatGroupedCall({
2226
+ role: context.groupRole ?? "singleton",
2227
+ compact,
2228
+ tree: toolGroupTree(context),
2229
+ dot: toolStatusDotFromContext(context, theme2),
2230
+ title: theme2.fg("toolTitle", theme2.bold("grep")),
2231
+ detail: formatGrepCall(args, theme2, context.cwd, !context.expanded)
2232
+ })), text;
2233
+ },
2234
+ renderResult(result, options2, theme2, context) {
2235
+ let text = context.lastComponent ?? new Text5("", 0, 0);
2236
+ return !options2.isPartial && !options2.expanded && !context.isError ? (text.setText(""), text) : (text.setText(formatGrepResult(result, options2, theme2, context.showImages)), text);
2237
+ }
2238
+ };
2239
+ }
2240
+ function createGrepTool(cwd, options) {
2241
+ return wrapToolDefinition(createGrepToolDefinition(cwd, options));
2242
+ }
2243
+
2244
+ // packages/coding-agent/dist/core/tools/ls.js
2245
+ import { readdir as fsReaddir, stat as fsStat2 } from "node:fs/promises";
2246
+ import { Text as Text6 } from "@ashx-j/lunr-tui";
2247
+ import nodePath from "path";
2248
+ import { Type as Type5 } from "typebox";
2249
+ var lsSchema = Type5.Object({
2250
+ path: Type5.Optional(Type5.String({ description: "Directory to list (default: current directory)" })),
2251
+ limit: Type5.Optional(Type5.Number({ description: "Maximum number of entries to return (default: 500)" }))
2252
+ }), DEFAULT_LIMIT3 = 500, defaultLsOperations = {
2253
+ exists: pathExists,
2254
+ stat: fsStat2,
2255
+ readdir: fsReaddir
2256
+ };
2257
+ function formatLsCall(args, theme2, cwd, compact = !1) {
2258
+ let limit = args?.limit, rawPath = str(args?.path), text = compact ? renderToolFileName(rawPath || ".", theme2, cwd) : renderToolPath(rawPath, theme2, cwd, { emptyFallback: "." });
2259
+ return limit !== void 0 && (text += theme2.fg("toolOutput", ` (limit ${limit})`)), text;
2260
+ }
2261
+ function formatLsResult(result, options, theme2, showImages) {
2262
+ let output = getTextOutput(result, showImages).trim(), text = "";
2263
+ if (output) {
2264
+ let lines = output.split(`
2265
+ `), maxLines = options.expanded ? lines.length : 20, displayLines = lines.slice(0, maxLines), remaining = lines.length - maxLines;
2266
+ text += `
2267
+ ${displayLines.map((line) => theme2.fg("toolOutput", line)).join(`
2268
+ `)}`, remaining > 0 && (text += `${theme2.fg("muted", `
2269
+ ... (${remaining} more lines,`)} ${keyHint("app.tools.expand", "to expand")}${theme2.fg("muted", ")")}`);
2270
+ }
2271
+ let entryLimit = result.details?.entryLimitReached, truncation = result.details?.truncation;
2272
+ if (entryLimit || truncation?.truncated) {
2273
+ let warnings = [];
2274
+ entryLimit && warnings.push(`${entryLimit} entries limit`), truncation?.truncated && warnings.push(`${formatSize(truncation.maxBytes ?? 51200)} limit`), text += `
2275
+ ${theme2.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
2276
+ }
2277
+ return text;
2278
+ }
2279
+ function createLsToolDefinition(cwd, options) {
2280
+ let ops = options?.operations ?? defaultLsOperations;
2281
+ return {
2282
+ name: "ls",
2283
+ label: "ls",
2284
+ description: `List directory contents. Returns entries sorted alphabetically, with '/' suffix for directories. Includes dotfiles. Output is truncated to ${DEFAULT_LIMIT3} entries or ${51200 / 1024}KB (whichever is hit first).`,
2285
+ promptSnippet: "List directory contents",
2286
+ parameters: lsSchema,
2287
+ async execute(_toolCallId, { path: path3, limit }, signal, _onUpdate, _ctx) {
2288
+ return new Promise((resolve2, reject) => {
2289
+ if (signal?.aborted) {
2290
+ reject(new Error("Operation aborted"));
2291
+ return;
2292
+ }
2293
+ let onAbort = () => reject(new Error("Operation aborted"));
2294
+ signal?.addEventListener("abort", onAbort, { once: !0 }), (async () => {
2295
+ try {
2296
+ let dirPath = resolveToCwd(path3 || ".", cwd), effectiveLimit = limit ?? DEFAULT_LIMIT3;
2297
+ if (!await ops.exists(dirPath)) {
2298
+ reject(new Error(`Path not found: ${dirPath}`));
2299
+ return;
2300
+ }
2301
+ if (!(await ops.stat(dirPath)).isDirectory()) {
2302
+ reject(new Error(`Not a directory: ${dirPath}`));
2303
+ return;
2304
+ }
2305
+ let entries;
2306
+ try {
2307
+ entries = await ops.readdir(dirPath);
2308
+ } catch (e) {
2309
+ reject(new Error(`Cannot read directory: ${e.message}`));
2310
+ return;
2311
+ }
2312
+ entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
2313
+ let results = [], entryLimitReached = !1;
2314
+ for (let entry of entries) {
2315
+ if (results.length >= effectiveLimit) {
2316
+ entryLimitReached = !0;
2317
+ break;
2318
+ }
2319
+ let fullPath = nodePath.join(dirPath, entry), suffix = "";
2320
+ try {
2321
+ (await ops.stat(fullPath)).isDirectory() && (suffix = "/");
2322
+ } catch {
2323
+ continue;
2324
+ }
2325
+ results.push(entry + suffix);
2326
+ }
2327
+ if (signal?.removeEventListener("abort", onAbort), results.length === 0) {
2328
+ resolve2({ content: [{ type: "text", text: "(empty directory)" }], details: void 0 });
2329
+ return;
2330
+ }
2331
+ let rawOutput = results.join(`
2332
+ `), truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER }), output = truncation.content, details = {}, notices = [];
2333
+ entryLimitReached && (notices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`), details.entryLimitReached = effectiveLimit), truncation.truncated && (notices.push(`${formatSize(51200)} limit reached`), details.truncation = truncation), notices.length > 0 && (output += `
2334
+
2335
+ [${notices.join(". ")}]`), resolve2({
2336
+ content: [{ type: "text", text: output }],
2337
+ details: Object.keys(details).length > 0 ? details : void 0
2338
+ });
2339
+ } catch (e) {
2340
+ signal?.removeEventListener("abort", onAbort), reject(e);
2341
+ }
2342
+ })();
2343
+ });
2344
+ },
2345
+ renderCall(args, theme2, context) {
2346
+ let text = context.lastComponent ?? new Text6("", 0, 0), compact = !context.isPartial && !context.expanded && !context.isError;
2347
+ return text.setText(formatGroupedCall({
2348
+ role: context.groupRole ?? "singleton",
2349
+ compact,
2350
+ tree: toolGroupTree(context),
2351
+ dot: toolStatusDotFromContext(context, theme2),
2352
+ title: theme2.fg("toolTitle", theme2.bold("ls")),
2353
+ detail: formatLsCall(args, theme2, context.cwd, !context.expanded)
2354
+ })), text;
2355
+ },
2356
+ renderResult(result, options2, theme2, context) {
2357
+ let text = context.lastComponent ?? new Text6("", 0, 0);
2358
+ return !options2.isPartial && !options2.expanded && !context.isError ? (text.setText(""), text) : (text.setText(formatLsResult(result, options2, theme2, context.showImages)), text);
2359
+ }
2360
+ };
2361
+ }
2362
+ function createLsTool(cwd, options) {
2363
+ return wrapToolDefinition(createLsToolDefinition(cwd, options));
2364
+ }
2365
+
2366
+ // packages/coding-agent/dist/core/tools/read.js
2367
+ import { basename, dirname, isAbsolute, relative, resolve as resolvePath2, sep } from "node:path";
2368
+ import { Text as Text7 } from "@ashx-j/lunr-tui";
2369
+ import { constants as constants5 } from "fs";
2370
+ import { access as fsAccess3, readFile as fsReadFile3 } from "fs/promises";
2371
+ import { Type as Type6 } from "typebox";
2372
+
2373
+ // packages/coding-agent/dist/utils/mime.js
2374
+ import { open } from "node:fs/promises";
2375
+ var IMAGE_TYPE_SNIFF_BYTES = 4100, PNG_SIGNATURE = [137, 80, 78, 71, 13, 10, 26, 10];
2376
+ function detectSupportedImageMimeType(buffer) {
2377
+ return startsWith(buffer, [255, 216, 255]) ? buffer[3] === 247 ? null : "image/jpeg" : startsWith(buffer, PNG_SIGNATURE) ? isPng(buffer) && !isAnimatedPng(buffer) ? "image/png" : null : startsWithAscii(buffer, 0, "GIF") ? "image/gif" : startsWithAscii(buffer, 0, "RIFF") && startsWithAscii(buffer, 8, "WEBP") ? "image/webp" : startsWithAscii(buffer, 0, "BM") && isBmp(buffer) ? "image/bmp" : null;
2378
+ }
2379
+ async function detectSupportedImageMimeTypeFromFile(filePath) {
2380
+ let fileHandle = await open(filePath, "r");
2381
+ try {
2382
+ let buffer = Buffer.alloc(IMAGE_TYPE_SNIFF_BYTES), { bytesRead } = await fileHandle.read(buffer, 0, IMAGE_TYPE_SNIFF_BYTES, 0);
2383
+ return detectSupportedImageMimeType(buffer.subarray(0, bytesRead));
2384
+ } finally {
2385
+ await fileHandle.close();
2386
+ }
2387
+ }
2388
+ function isPng(buffer) {
2389
+ return buffer.length >= 16 && readUint32BE(buffer, PNG_SIGNATURE.length) === 13 && startsWithAscii(buffer, 12, "IHDR");
2390
+ }
2391
+ function isAnimatedPng(buffer) {
2392
+ let offset = PNG_SIGNATURE.length;
2393
+ for (; offset + 8 <= buffer.length; ) {
2394
+ let chunkLength = readUint32BE(buffer, offset), chunkTypeOffset = offset + 4;
2395
+ if (startsWithAscii(buffer, chunkTypeOffset, "acTL"))
2396
+ return !0;
2397
+ if (startsWithAscii(buffer, chunkTypeOffset, "IDAT"))
2398
+ return !1;
2399
+ let nextOffset = offset + 8 + chunkLength + 4;
2400
+ if (nextOffset <= offset || nextOffset > buffer.length)
2401
+ return !1;
2402
+ offset = nextOffset;
2403
+ }
2404
+ return !1;
2405
+ }
2406
+ function isBmp(buffer) {
2407
+ if (buffer.length < 26)
2408
+ return !1;
2409
+ let declaredFileSize = readUint32LE(buffer, 2), pixelDataOffset = readUint32LE(buffer, 10), dibHeaderSize = readUint32LE(buffer, 14);
2410
+ if (declaredFileSize !== 0 && declaredFileSize < 26 || pixelDataOffset < 14 + dibHeaderSize || declaredFileSize !== 0 && pixelDataOffset >= declaredFileSize)
2411
+ return !1;
2412
+ let colorPlanes, bitsPerPixel;
2413
+ if (dibHeaderSize === 12)
2414
+ colorPlanes = readUint16LE(buffer, 22), bitsPerPixel = readUint16LE(buffer, 24);
2415
+ else if (dibHeaderSize >= 40 && dibHeaderSize <= 124) {
2416
+ if (buffer.length < 30)
2417
+ return !1;
2418
+ colorPlanes = readUint16LE(buffer, 26), bitsPerPixel = readUint16LE(buffer, 28);
2419
+ } else
2420
+ return !1;
2421
+ return colorPlanes === 1 && [1, 4, 8, 16, 24, 32].includes(bitsPerPixel);
2422
+ }
2423
+ function readUint16LE(buffer, offset) {
2424
+ return (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8);
2425
+ }
2426
+ function readUint32BE(buffer, offset) {
2427
+ return (buffer[offset] ?? 0) * 16777216 + ((buffer[offset + 1] ?? 0) << 16) + ((buffer[offset + 2] ?? 0) << 8) + (buffer[offset + 3] ?? 0);
2428
+ }
2429
+ function readUint32LE(buffer, offset) {
2430
+ return (buffer[offset] ?? 0) + ((buffer[offset + 1] ?? 0) << 8) + ((buffer[offset + 2] ?? 0) << 16) + (buffer[offset + 3] ?? 0) * 16777216;
2431
+ }
2432
+ function startsWith(buffer, bytes) {
2433
+ return buffer.length < bytes.length ? !1 : bytes.every((byte, index) => buffer[index] === byte);
2434
+ }
2435
+ function startsWithAscii(buffer, offset, text) {
2436
+ if (buffer.length < offset + text.length)
2437
+ return !1;
2438
+ for (let index = 0; index < text.length; index++)
2439
+ if (buffer[offset + index] !== text.charCodeAt(index))
2440
+ return !1;
2441
+ return !0;
2442
+ }
2443
+
2444
+ // packages/coding-agent/dist/core/tools/read.js
2445
+ var readSchema = Type6.Object({
2446
+ path: Type6.String({ description: "Path to the file to read (relative or absolute)" }),
2447
+ offset: Type6.Optional(Type6.Number({ description: "Line number to start reading from (1-indexed)" })),
2448
+ limit: Type6.Optional(Type6.Number({ description: "Maximum number of lines to read" }))
2449
+ }), COMPACT_RESOURCE_FILE_NAMES = /* @__PURE__ */ new Set(["AGENTS.md", "AGENTS.MD", "CLAUDE.md", "CLAUDE.MD"]), defaultReadOperations = {
2450
+ readFile: (path3) => fsReadFile3(path3),
2451
+ access: (path3) => fsAccess3(path3, constants5.R_OK),
2452
+ detectImageMimeType: detectSupportedImageMimeTypeFromFile
2453
+ };
2454
+ function formatReadLineRange(args, theme2) {
2455
+ if (args?.offset === void 0 && args?.limit === void 0)
2456
+ return "";
2457
+ let startLine = args.offset ?? 1, endLine = args.limit !== void 0 ? startLine + args.limit - 1 : "";
2458
+ return theme2.fg("warning", `:${startLine}${endLine ? `-${endLine}` : ""}`);
2459
+ }
2460
+ function formatReadDetail(args, theme2, cwd, expanded = !1) {
2461
+ let pathDisplay = renderToolFileName(str(args?.file_path ?? args?.path), theme2, cwd), range = expanded ? formatReadLineRange(args, theme2) : "";
2462
+ return `${pathDisplay}${range}`;
2463
+ }
2464
+ function trimTrailingEmptyLines(lines) {
2465
+ let end = lines.length;
2466
+ for (; end > 0 && lines[end - 1] === ""; )
2467
+ end--;
2468
+ return lines.slice(0, end);
2469
+ }
2470
+ function getNonVisionImageNote(model) {
2471
+ if (!(!model || model.input.includes("image")))
2472
+ return "[Current model does not support images. The image will be omitted from this request.]";
2473
+ }
2474
+ function toPosixPath2(filePath) {
2475
+ return filePath.split(sep).join("/");
2476
+ }
2477
+ function getPiDocsClassification(absolutePath) {
2478
+ let packageRoot = dirname(getReadmePath()), relativePath = relative(resolvePath2(packageRoot), resolvePath2(absolutePath));
2479
+ if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath))
2480
+ return;
2481
+ let label = toPosixPath2(relativePath);
2482
+ if (label === "README.md" || label.startsWith("docs/") || label.startsWith("examples/"))
2483
+ return { kind: "docs", label };
2484
+ }
2485
+ function getCompactReadClassification(args, cwd) {
2486
+ let rawPath = str(args?.file_path ?? args?.path);
2487
+ if (!rawPath)
2488
+ return;
2489
+ let absolutePath = resolveToCwd(rawPath, cwd), fileName = basename(absolutePath);
2490
+ if (fileName === "SKILL.md")
2491
+ return { kind: "skill", label: basename(dirname(absolutePath)) || fileName };
2492
+ let docsClassification = getPiDocsClassification(absolutePath);
2493
+ if (docsClassification)
2494
+ return docsClassification;
2495
+ if (COMPACT_RESOURCE_FILE_NAMES.has(fileName))
2496
+ return { kind: "resource", label: formatPathRelativeToCwdOrAbsolute(absolutePath, cwd) };
2497
+ }
2498
+ function formatReadResult(args, result, options, theme2, showImages, _cwd, isError) {
2499
+ if (!options.expanded && !isError)
2500
+ return "";
2501
+ let rawPath = str(args?.file_path ?? args?.path), output = getTextOutput(result, showImages), lang = rawPath ? getLanguageFromPath(rawPath) : void 0, renderedLines = lang ? highlightCode(replaceTabs(output), lang) : output.split(`
2502
+ `), lines = trimTrailingEmptyLines(renderedLines), maxLines = options.expanded ? lines.length : 10, displayLines = lines.slice(0, maxLines), remaining = lines.length - maxLines, text = `
2503
+ ${displayLines.map((line) => lang ? replaceTabs(line) : theme2.fg("toolOutput", replaceTabs(line))).join(`
2504
+ `)}`;
2505
+ remaining > 0 && (text += `${theme2.fg("muted", `
2506
+ ... (${remaining} more lines,`)} ${keyHint("app.tools.expand", "to expand")}${theme2.fg("muted", ")")}`);
2507
+ let truncation = result.details?.truncation;
2508
+ return truncation?.truncated && (truncation.firstLineExceedsLimit ? text += `
2509
+ ${theme2.fg("warning", `[First line exceeds ${formatSize(truncation.maxBytes ?? 51200)} limit]`)}` : truncation.truncatedBy === "lines" ? text += `
2510
+ ${theme2.fg("warning", `[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${truncation.maxLines ?? 2e3} line limit)]`)}` : text += `
2511
+ ${theme2.fg("warning", `[Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? 51200)} limit)]`)}`), text;
2512
+ }
2513
+ function createReadToolDefinition(cwd, options) {
2514
+ let autoResizeImages = options?.autoResizeImages ?? !0, ops = options?.operations ?? defaultReadOperations;
2515
+ return {
2516
+ name: "read",
2517
+ label: "read",
2518
+ description: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${2e3} lines or ${51200 / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,
2519
+ promptSnippet: "Read file contents",
2520
+ promptGuidelines: ["Use read to examine files instead of cat or sed."],
2521
+ parameters: readSchema,
2522
+ async execute(_toolCallId, { path: path3, offset, limit }, signal, _onUpdate, ctx) {
2523
+ return new Promise((resolve2, reject) => {
2524
+ if (signal?.aborted) {
2525
+ reject(new Error("Operation aborted"));
2526
+ return;
2527
+ }
2528
+ let aborted = !1, onAbort = () => {
2529
+ aborted = !0, reject(new Error("Operation aborted"));
2530
+ };
2531
+ signal?.addEventListener("abort", onAbort, { once: !0 }), (async () => {
2532
+ try {
2533
+ let absolutePath = await resolveReadPathAsync(path3, cwd);
2534
+ if (aborted || (await ops.access(absolutePath), aborted))
2535
+ return;
2536
+ let mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : void 0, content, details, nonVisionImageNote = getNonVisionImageNote(ctx?.model);
2537
+ if (mimeType) {
2538
+ let buffer = await ops.readFile(absolutePath), processed = await processImage(buffer, mimeType, { autoResizeImages });
2539
+ if (processed.ok) {
2540
+ let textNote = `Read image file [${processed.mimeType}]`;
2541
+ processed.hints.length > 0 && (textNote += `
2542
+ ${processed.hints.join(`
2543
+ `)}`), nonVisionImageNote && (textNote += `
2544
+ ${nonVisionImageNote}`), content = [
2545
+ { type: "text", text: textNote },
2546
+ { type: "image", data: processed.data, mimeType: processed.mimeType }
2547
+ ];
2548
+ } else {
2549
+ let textNote = `Read image file [${mimeType}]
2550
+ ${processed.message}`;
2551
+ nonVisionImageNote && (textNote += `
2552
+ ${nonVisionImageNote}`), content = [{ type: "text", text: textNote }];
2553
+ }
2554
+ } else {
2555
+ let allLines = (await ops.readFile(absolutePath)).toString("utf-8").split(`
2556
+ `), totalFileLines = allLines.length, startLine = offset ? Math.max(0, offset - 1) : 0, startLineDisplay = startLine + 1;
2557
+ if (startLine >= allLines.length)
2558
+ throw new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);
2559
+ let selectedContent, userLimitedLines;
2560
+ if (limit !== void 0) {
2561
+ let endLine = Math.min(startLine + limit, allLines.length);
2562
+ selectedContent = allLines.slice(startLine, endLine).join(`
2563
+ `), userLimitedLines = endLine - startLine;
2564
+ } else
2565
+ selectedContent = allLines.slice(startLine).join(`
2566
+ `);
2567
+ let truncation = truncateHead(selectedContent), outputText;
2568
+ if (truncation.firstLineExceedsLimit) {
2569
+ let firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], "utf-8"));
2570
+ outputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(51200)} limit. Use bash: sed -n '${startLineDisplay}p' ${path3} | head -c ${51200}]`, details = { truncation };
2571
+ } else if (truncation.truncated) {
2572
+ let endLineDisplay = startLineDisplay + truncation.outputLines - 1, nextOffset = endLineDisplay + 1;
2573
+ outputText = truncation.content, truncation.truncatedBy === "lines" ? outputText += `
2574
+
2575
+ [Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]` : outputText += `
2576
+
2577
+ [Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(51200)} limit). Use offset=${nextOffset} to continue.]`, details = { truncation };
2578
+ } else if (userLimitedLines !== void 0 && startLine + userLimitedLines < allLines.length) {
2579
+ let remaining = allLines.length - (startLine + userLimitedLines), nextOffset = startLine + userLimitedLines + 1;
2580
+ outputText = `${truncation.content}
2581
+
2582
+ [${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;
2583
+ } else
2584
+ outputText = truncation.content;
2585
+ content = [{ type: "text", text: outputText }];
2586
+ }
2587
+ if (aborted)
2588
+ return;
2589
+ signal?.removeEventListener("abort", onAbort), resolve2({ content, details });
2590
+ } catch (error) {
2591
+ signal?.removeEventListener("abort", onAbort), aborted || reject(error);
2592
+ }
2593
+ })();
2594
+ });
2595
+ },
2596
+ renderCall(args, theme2, context) {
2597
+ let text = context.lastComponent ?? new Text7("", 0, 0), compact = !context.isPartial && !context.expanded && !context.isError, classification = context.expanded ? void 0 : getCompactReadClassification(args, context.cwd), title = theme2.fg("toolTitle", theme2.bold("read")), detail;
2598
+ return classification?.kind === "skill" ? (title = theme2.fg("customMessageLabel", "\x1B[1m[skill]\x1B[22m"), detail = theme2.fg("customMessageText", classification.label)) : classification ? (title = theme2.fg("toolTitle", theme2.bold(`read ${classification.kind}`)), detail = theme2.fg("accent", classification.label)) : detail = formatReadDetail(args, theme2, context.cwd, context.expanded), text.setText(formatGroupedCall({
2599
+ role: context.groupRole ?? "singleton",
2600
+ compact,
2601
+ tree: toolGroupTree(context),
2602
+ dot: toolStatusDotFromContext(context, theme2),
2603
+ title,
2604
+ detail
2605
+ })), text;
2606
+ },
2607
+ renderResult(result, options2, theme2, context) {
2608
+ let text = context.lastComponent ?? new Text7("", 0, 0);
2609
+ return !options2.isPartial && !options2.expanded && !context.isError ? (text.setText(""), text) : (text.setText(formatReadResult(context.args, result, options2, theme2, context.showImages, context.cwd, context.isError)), text);
2610
+ }
2611
+ };
2612
+ }
2613
+ function createReadTool(cwd, options) {
2614
+ return wrapToolDefinition(createReadToolDefinition(cwd, options));
2615
+ }
2616
+
2617
+ // packages/coding-agent/dist/core/tools/write.js
2618
+ import { Container as Container3, Text as Text8 } from "@ashx-j/lunr-tui";
2619
+ import { mkdir as fsMkdir, writeFile as fsWriteFile2 } from "fs/promises";
2620
+ import { dirname as dirname2 } from "path";
2621
+ import { Type as Type7 } from "typebox";
2622
+ var writeSchema = Type7.Object({
2623
+ path: Type7.String({ description: "Path to the file to write (relative or absolute)" }),
2624
+ content: Type7.String({ description: "Content to write to the file" })
2625
+ }), defaultWriteOperations = {
2626
+ writeFile: (path3, content) => fsWriteFile2(path3, content, "utf-8"),
2627
+ mkdir: (dir) => fsMkdir(dir, { recursive: !0 }).then(() => {
2628
+ })
2629
+ }, WriteCallRenderComponent = class extends Text8 {
2630
+ cache;
2631
+ constructor() {
2632
+ super("", 0, 0);
2633
+ }
2634
+ }, WRITE_PARTIAL_FULL_HIGHLIGHT_LINES = 50;
2635
+ function highlightSingleLine(line, lang) {
2636
+ return highlightCode(line, lang)[0] ?? "";
2637
+ }
2638
+ function refreshWriteHighlightPrefix(cache) {
2639
+ let prefixCount = Math.min(WRITE_PARTIAL_FULL_HIGHLIGHT_LINES, cache.normalizedLines.length);
2640
+ if (prefixCount === 0)
2641
+ return;
2642
+ let prefixSource = cache.normalizedLines.slice(0, prefixCount).join(`
2643
+ `), prefixHighlighted = highlightCode(prefixSource, cache.lang);
2644
+ for (let i = 0; i < prefixCount; i++)
2645
+ cache.highlightedLines[i] = prefixHighlighted[i] ?? highlightSingleLine(cache.normalizedLines[i] ?? "", cache.lang);
2646
+ }
2647
+ function rebuildWriteHighlightCacheFull(rawPath, fileContent) {
2648
+ let lang = rawPath ? getLanguageFromPath(rawPath) : void 0;
2649
+ if (!lang)
2650
+ return;
2651
+ let displayContent = normalizeDisplayText(fileContent), normalized = replaceTabs(displayContent);
2652
+ return {
2653
+ rawPath,
2654
+ lang,
2655
+ rawContent: fileContent,
2656
+ normalizedLines: normalized.split(`
2657
+ `),
2658
+ highlightedLines: highlightCode(normalized, lang)
2659
+ };
2660
+ }
2661
+ function updateWriteHighlightCacheIncremental(cache, rawPath, fileContent) {
2662
+ let lang = rawPath ? getLanguageFromPath(rawPath) : void 0;
2663
+ if (!lang)
2664
+ return;
2665
+ if (!cache || cache.lang !== lang || cache.rawPath !== rawPath || !fileContent.startsWith(cache.rawContent))
2666
+ return rebuildWriteHighlightCacheFull(rawPath, fileContent);
2667
+ if (fileContent.length === cache.rawContent.length)
2668
+ return cache;
2669
+ let deltaRaw = fileContent.slice(cache.rawContent.length), deltaDisplay = normalizeDisplayText(deltaRaw), deltaNormalized = replaceTabs(deltaDisplay);
2670
+ cache.rawContent = fileContent, cache.normalizedLines.length === 0 && (cache.normalizedLines.push(""), cache.highlightedLines.push(""));
2671
+ let segments = deltaNormalized.split(`
2672
+ `), lastIndex = cache.normalizedLines.length - 1;
2673
+ cache.normalizedLines[lastIndex] += segments[0], cache.highlightedLines[lastIndex] = highlightSingleLine(cache.normalizedLines[lastIndex], cache.lang);
2674
+ for (let i = 1; i < segments.length; i++)
2675
+ cache.normalizedLines.push(segments[i]), cache.highlightedLines.push(highlightSingleLine(segments[i], cache.lang));
2676
+ return refreshWriteHighlightPrefix(cache), cache;
2677
+ }
2678
+ function trimTrailingEmptyLines2(lines) {
2679
+ let end = lines.length;
2680
+ for (; end > 0 && lines[end - 1] === ""; )
2681
+ end--;
2682
+ return lines.slice(0, end);
2683
+ }
2684
+ function formatWriteCall(args, options, theme2, cache, cwd, compact = !1) {
2685
+ let rawPath = str(args?.file_path ?? args?.path), fileContent = str(args?.content), pathDisplay = compact ? renderToolFileName(rawPath, theme2, cwd) : renderToolPath(rawPath, theme2, cwd), text = `${theme2.fg("toolTitle", theme2.bold("write"))} ${pathDisplay}`;
2686
+ if (fileContent === null)
2687
+ text += `
2688
+
2689
+ ${theme2.fg("error", "[invalid content arg - expected string]")}`;
2690
+ else if (fileContent && !compact) {
2691
+ let lang = rawPath ? getLanguageFromPath(rawPath) : void 0, renderedLines = lang ? cache?.highlightedLines ?? highlightCode(replaceTabs(normalizeDisplayText(fileContent)), lang) : normalizeDisplayText(fileContent).split(`
2692
+ `), lines = trimTrailingEmptyLines2(renderedLines), totalLines = lines.length, maxLines = options.expanded ? lines.length : 10, displayLines = lines.slice(0, maxLines), remaining = lines.length - maxLines;
2693
+ text += `
2694
+
2695
+ ${displayLines.map((line) => lang ? line : theme2.fg("toolOutput", replaceTabs(line))).join(`
2696
+ `)}`, remaining > 0 && (text += `${theme2.fg("muted", `
2697
+ ... (${remaining} more lines, ${totalLines} total,`)} ${keyHint("app.tools.expand", "to expand")}${theme2.fg("muted", ")")}`);
2698
+ }
2699
+ return text;
2700
+ }
2701
+ function formatWriteResult(result, theme2) {
2702
+ if (!result.isError)
2703
+ return;
2704
+ let output = result.content.filter((c) => c.type === "text").map((c) => c.text || "").join(`
2705
+ `);
2706
+ if (output)
2707
+ return `
2708
+ ${theme2.fg("error", output)}`;
2709
+ }
2710
+ function createWriteToolDefinition(cwd, options) {
2711
+ let ops = options?.operations ?? defaultWriteOperations;
2712
+ return {
2713
+ name: "write",
2714
+ label: "write",
2715
+ description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
2716
+ promptSnippet: "Create or overwrite files",
2717
+ promptGuidelines: ["Use write only for new files or complete rewrites."],
2718
+ parameters: writeSchema,
2719
+ async execute(_toolCallId, { path: path3, content }, signal, _onUpdate, _ctx) {
2720
+ let absolutePath = resolveToCwd(path3, cwd), dir = dirname2(absolutePath);
2721
+ return withFileMutationQueue(absolutePath, async () => {
2722
+ let throwIfAborted = () => {
2723
+ if (signal?.aborted)
2724
+ throw new Error("Operation aborted");
2725
+ };
2726
+ return throwIfAborted(), await ops.mkdir(dir), throwIfAborted(), await ops.writeFile(absolutePath, content), throwIfAborted(), {
2727
+ content: [{ type: "text", text: `Successfully wrote ${content.length} bytes to ${path3}` }],
2728
+ details: void 0
2729
+ };
2730
+ });
2731
+ },
2732
+ renderCall(args, theme2, context) {
2733
+ let renderArgs = args, rawPath = str(renderArgs?.file_path ?? renderArgs?.path), fileContent = str(renderArgs?.content), component = context.lastComponent ?? new WriteCallRenderComponent();
2734
+ fileContent !== null ? component.cache = context.argsComplete ? rebuildWriteHighlightCacheFull(rawPath, fileContent) : updateWriteHighlightCacheIncremental(component.cache, rawPath, fileContent) : component.cache = void 0;
2735
+ let compact = !context.isPartial && !context.expanded && !context.isError, tree = toolGroupTree(context);
2736
+ if (compact || tree && context.groupRole && context.groupRole !== "singleton") {
2737
+ let detail = renderToolFileName(rawPath, theme2, context.cwd);
2738
+ fileContent === null && (detail += `
2739
+
2740
+ ${theme2.fg("error", "[invalid content arg - expected string]")}`), component.setText(formatGroupedCall({
2741
+ role: context.groupRole ?? "singleton",
2742
+ compact,
2743
+ tree,
2744
+ dot: toolStatusDotFromContext(context, theme2),
2745
+ title: theme2.fg("toolTitle", theme2.bold("write")),
2746
+ detail
2747
+ }));
2748
+ } else
2749
+ component.setText(`${toolStatusDotFromContext(context, theme2)} ${formatWriteCall(renderArgs, { expanded: context.expanded, isPartial: context.isPartial }, theme2, component.cache, context.cwd, !1)}`);
2750
+ return component;
2751
+ },
2752
+ renderResult(result, _options, theme2, context) {
2753
+ let output = formatWriteResult({ ...result, isError: context.isError }, theme2);
2754
+ if (!output) {
2755
+ let component = context.lastComponent ?? new Container3();
2756
+ return component.clear(), component;
2757
+ }
2758
+ let text = context.lastComponent ?? new Text8("", 0, 0);
2759
+ return text.setText(output), text;
2760
+ }
2761
+ };
2762
+ }
2763
+ function createWriteTool(cwd, options) {
2764
+ return wrapToolDefinition(createWriteToolDefinition(cwd, options));
2765
+ }
2766
+
2767
+ // packages/coding-agent/dist/core/tools/index.js
2768
+ function createAllToolDefinitions(cwd, options) {
2769
+ return {
2770
+ read: createReadToolDefinition(cwd, options?.read),
2771
+ bash: createBashToolDefinition(cwd, options?.bash),
2772
+ edit: createEditToolDefinition(cwd, options?.edit),
2773
+ write: createWriteToolDefinition(cwd, options?.write),
2774
+ grep: createGrepToolDefinition(cwd, options?.grep),
2775
+ find: createFindToolDefinition(cwd, options?.find),
2776
+ ls: createLsToolDefinition(cwd, options?.ls)
2777
+ };
2778
+ }
2779
+ function createCodingTools(cwd, options) {
2780
+ return [
2781
+ createReadTool(cwd, options?.read),
2782
+ createBashTool(cwd, options?.bash),
2783
+ createEditTool(cwd, options?.edit),
2784
+ createWriteTool(cwd, options?.write)
2785
+ ];
2786
+ }
2787
+ function createReadOnlyTools(cwd, options) {
2788
+ return [
2789
+ createReadTool(cwd, options?.read),
2790
+ createGrepTool(cwd, options?.grep),
2791
+ createFindTool(cwd, options?.find),
2792
+ createLsTool(cwd, options?.ls)
2793
+ ];
2794
+ }
2795
+
2796
+ export {
2797
+ wrapToolDefinition,
2798
+ createToolDefinitionFromAgentTool,
2799
+ truncateToVisualLines,
2800
+ list,
2801
+ kill,
2802
+ killAll,
2803
+ pause,
2804
+ resume,
2805
+ restart,
2806
+ isWindows,
2807
+ clearRegistry,
2808
+ createLocalBashOperations,
2809
+ createBashToolDefinition,
2810
+ createBashTool,
2811
+ renderDiff,
2812
+ resolveReadPath,
2813
+ generateUnifiedPatch,
2814
+ generateDiffString,
2815
+ withFileMutationQueue,
2816
+ createEditToolDefinition,
2817
+ createEditTool,
2818
+ getToolPath,
2819
+ ensureTool,
2820
+ createFindToolDefinition,
2821
+ createFindTool,
2822
+ createGrepToolDefinition,
2823
+ createGrepTool,
2824
+ createLsToolDefinition,
2825
+ createLsTool,
2826
+ detectSupportedImageMimeTypeFromFile,
2827
+ createReadToolDefinition,
2828
+ createReadTool,
2829
+ createWriteToolDefinition,
2830
+ createWriteTool,
2831
+ createAllToolDefinitions,
2832
+ createCodingTools,
2833
+ createReadOnlyTools
2834
+ };