@imdigitalashish/zpi 0.1.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 (604) hide show
  1. package/CHANGELOG.md +2801 -0
  2. package/README.md +95 -0
  3. package/dist/cli/args.d.ts +47 -0
  4. package/dist/cli/args.d.ts.map +1 -0
  5. package/dist/cli/args.js +293 -0
  6. package/dist/cli/args.js.map +1 -0
  7. package/dist/cli/config-selector.d.ts +14 -0
  8. package/dist/cli/config-selector.d.ts.map +1 -0
  9. package/dist/cli/config-selector.js +31 -0
  10. package/dist/cli/config-selector.js.map +1 -0
  11. package/dist/cli/file-processor.d.ts +15 -0
  12. package/dist/cli/file-processor.d.ts.map +1 -0
  13. package/dist/cli/file-processor.js +79 -0
  14. package/dist/cli/file-processor.js.map +1 -0
  15. package/dist/cli/list-models.d.ts +9 -0
  16. package/dist/cli/list-models.d.ts.map +1 -0
  17. package/dist/cli/list-models.js +92 -0
  18. package/dist/cli/list-models.js.map +1 -0
  19. package/dist/cli/session-picker.d.ts +9 -0
  20. package/dist/cli/session-picker.d.ts.map +1 -0
  21. package/dist/cli/session-picker.js +34 -0
  22. package/dist/cli/session-picker.js.map +1 -0
  23. package/dist/cli.d.ts +3 -0
  24. package/dist/cli.d.ts.map +1 -0
  25. package/dist/cli.js +11 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/config.d.ts +68 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +203 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/core/agent-session.d.ts +571 -0
  32. package/dist/core/agent-session.d.ts.map +1 -0
  33. package/dist/core/agent-session.js +2353 -0
  34. package/dist/core/agent-session.js.map +1 -0
  35. package/dist/core/auth-storage.d.ts +129 -0
  36. package/dist/core/auth-storage.d.ts.map +1 -0
  37. package/dist/core/auth-storage.js +394 -0
  38. package/dist/core/auth-storage.js.map +1 -0
  39. package/dist/core/bash-executor.d.ts +47 -0
  40. package/dist/core/bash-executor.d.ts.map +1 -0
  41. package/dist/core/bash-executor.js +212 -0
  42. package/dist/core/bash-executor.js.map +1 -0
  43. package/dist/core/compaction/branch-summarization.d.ts +86 -0
  44. package/dist/core/compaction/branch-summarization.d.ts.map +1 -0
  45. package/dist/core/compaction/branch-summarization.js +242 -0
  46. package/dist/core/compaction/branch-summarization.js.map +1 -0
  47. package/dist/core/compaction/compaction.d.ts +121 -0
  48. package/dist/core/compaction/compaction.d.ts.map +1 -0
  49. package/dist/core/compaction/compaction.js +607 -0
  50. package/dist/core/compaction/compaction.js.map +1 -0
  51. package/dist/core/compaction/index.d.ts +7 -0
  52. package/dist/core/compaction/index.d.ts.map +1 -0
  53. package/dist/core/compaction/index.js +7 -0
  54. package/dist/core/compaction/index.js.map +1 -0
  55. package/dist/core/compaction/utils.d.ts +35 -0
  56. package/dist/core/compaction/utils.d.ts.map +1 -0
  57. package/dist/core/compaction/utils.js +138 -0
  58. package/dist/core/compaction/utils.js.map +1 -0
  59. package/dist/core/defaults.d.ts +3 -0
  60. package/dist/core/defaults.d.ts.map +1 -0
  61. package/dist/core/defaults.js +2 -0
  62. package/dist/core/defaults.js.map +1 -0
  63. package/dist/core/diagnostics.d.ts +15 -0
  64. package/dist/core/diagnostics.d.ts.map +1 -0
  65. package/dist/core/diagnostics.js +2 -0
  66. package/dist/core/diagnostics.js.map +1 -0
  67. package/dist/core/event-bus.d.ts +9 -0
  68. package/dist/core/event-bus.d.ts.map +1 -0
  69. package/dist/core/event-bus.js +25 -0
  70. package/dist/core/event-bus.js.map +1 -0
  71. package/dist/core/exec.d.ts +29 -0
  72. package/dist/core/exec.d.ts.map +1 -0
  73. package/dist/core/exec.js +71 -0
  74. package/dist/core/exec.js.map +1 -0
  75. package/dist/core/export-html/ansi-to-html.d.ts +22 -0
  76. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
  77. package/dist/core/export-html/ansi-to-html.js +249 -0
  78. package/dist/core/export-html/ansi-to-html.js.map +1 -0
  79. package/dist/core/export-html/index.d.ts +34 -0
  80. package/dist/core/export-html/index.d.ts.map +1 -0
  81. package/dist/core/export-html/index.js +222 -0
  82. package/dist/core/export-html/index.js.map +1 -0
  83. package/dist/core/export-html/template.css +971 -0
  84. package/dist/core/export-html/template.html +54 -0
  85. package/dist/core/export-html/template.js +1586 -0
  86. package/dist/core/export-html/tool-renderer.d.ts +35 -0
  87. package/dist/core/export-html/tool-renderer.d.ts.map +1 -0
  88. package/dist/core/export-html/tool-renderer.js +57 -0
  89. package/dist/core/export-html/tool-renderer.js.map +1 -0
  90. package/dist/core/export-html/vendor/highlight.min.js +1213 -0
  91. package/dist/core/export-html/vendor/marked.min.js +6 -0
  92. package/dist/core/extensions/index.d.ts +11 -0
  93. package/dist/core/extensions/index.d.ts.map +1 -0
  94. package/dist/core/extensions/index.js +9 -0
  95. package/dist/core/extensions/index.js.map +1 -0
  96. package/dist/core/extensions/loader.d.ts +25 -0
  97. package/dist/core/extensions/loader.d.ts.map +1 -0
  98. package/dist/core/extensions/loader.js +402 -0
  99. package/dist/core/extensions/loader.js.map +1 -0
  100. package/dist/core/extensions/runner.d.ts +146 -0
  101. package/dist/core/extensions/runner.d.ts.map +1 -0
  102. package/dist/core/extensions/runner.js +626 -0
  103. package/dist/core/extensions/runner.js.map +1 -0
  104. package/dist/core/extensions/types.d.ts +984 -0
  105. package/dist/core/extensions/types.d.ts.map +1 -0
  106. package/dist/core/extensions/types.js +35 -0
  107. package/dist/core/extensions/types.js.map +1 -0
  108. package/dist/core/extensions/wrapper.d.ts +27 -0
  109. package/dist/core/extensions/wrapper.d.ts.map +1 -0
  110. package/dist/core/extensions/wrapper.js +102 -0
  111. package/dist/core/extensions/wrapper.js.map +1 -0
  112. package/dist/core/footer-data-provider.d.ts +32 -0
  113. package/dist/core/footer-data-provider.d.ts.map +1 -0
  114. package/dist/core/footer-data-provider.js +134 -0
  115. package/dist/core/footer-data-provider.js.map +1 -0
  116. package/dist/core/index.d.ts +9 -0
  117. package/dist/core/index.d.ts.map +1 -0
  118. package/dist/core/index.js +9 -0
  119. package/dist/core/index.js.map +1 -0
  120. package/dist/core/keybindings.d.ts +55 -0
  121. package/dist/core/keybindings.d.ts.map +1 -0
  122. package/dist/core/keybindings.js +153 -0
  123. package/dist/core/keybindings.js.map +1 -0
  124. package/dist/core/memory.d.ts +64 -0
  125. package/dist/core/memory.d.ts.map +1 -0
  126. package/dist/core/memory.js +247 -0
  127. package/dist/core/memory.js.map +1 -0
  128. package/dist/core/messages.d.ts +77 -0
  129. package/dist/core/messages.d.ts.map +1 -0
  130. package/dist/core/messages.js +149 -0
  131. package/dist/core/messages.js.map +1 -0
  132. package/dist/core/model-registry.d.ts +102 -0
  133. package/dist/core/model-registry.d.ts.map +1 -0
  134. package/dist/core/model-registry.js +515 -0
  135. package/dist/core/model-registry.js.map +1 -0
  136. package/dist/core/model-resolver.d.ts +104 -0
  137. package/dist/core/model-resolver.d.ts.map +1 -0
  138. package/dist/core/model-resolver.js +403 -0
  139. package/dist/core/model-resolver.js.map +1 -0
  140. package/dist/core/package-manager.d.ts +151 -0
  141. package/dist/core/package-manager.d.ts.map +1 -0
  142. package/dist/core/package-manager.js +1426 -0
  143. package/dist/core/package-manager.js.map +1 -0
  144. package/dist/core/prompt-templates.d.ts +50 -0
  145. package/dist/core/prompt-templates.d.ts.map +1 -0
  146. package/dist/core/prompt-templates.js +251 -0
  147. package/dist/core/prompt-templates.js.map +1 -0
  148. package/dist/core/resolve-config-value.d.ts +17 -0
  149. package/dist/core/resolve-config-value.d.ts.map +1 -0
  150. package/dist/core/resolve-config-value.js +59 -0
  151. package/dist/core/resolve-config-value.js.map +1 -0
  152. package/dist/core/resource-loader.d.ts +184 -0
  153. package/dist/core/resource-loader.d.ts.map +1 -0
  154. package/dist/core/resource-loader.js +673 -0
  155. package/dist/core/resource-loader.js.map +1 -0
  156. package/dist/core/sdk.d.ts +90 -0
  157. package/dist/core/sdk.d.ts.map +1 -0
  158. package/dist/core/sdk.js +238 -0
  159. package/dist/core/sdk.js.map +1 -0
  160. package/dist/core/session-manager.d.ts +323 -0
  161. package/dist/core/session-manager.d.ts.map +1 -0
  162. package/dist/core/session-manager.js +1091 -0
  163. package/dist/core/session-manager.js.map +1 -0
  164. package/dist/core/settings-manager.d.ts +230 -0
  165. package/dist/core/settings-manager.d.ts.map +1 -0
  166. package/dist/core/settings-manager.js +656 -0
  167. package/dist/core/settings-manager.js.map +1 -0
  168. package/dist/core/skills.d.ts +58 -0
  169. package/dist/core/skills.d.ts.map +1 -0
  170. package/dist/core/skills.js +364 -0
  171. package/dist/core/skills.js.map +1 -0
  172. package/dist/core/slash-commands.d.ts +15 -0
  173. package/dist/core/slash-commands.d.ts.map +1 -0
  174. package/dist/core/slash-commands.js +23 -0
  175. package/dist/core/slash-commands.js.map +1 -0
  176. package/dist/core/system-prompt.d.ts +26 -0
  177. package/dist/core/system-prompt.d.ts.map +1 -0
  178. package/dist/core/system-prompt.js +150 -0
  179. package/dist/core/system-prompt.js.map +1 -0
  180. package/dist/core/timings.d.ts +7 -0
  181. package/dist/core/timings.d.ts.map +1 -0
  182. package/dist/core/timings.js +25 -0
  183. package/dist/core/timings.js.map +1 -0
  184. package/dist/core/tools/bash.d.ts +55 -0
  185. package/dist/core/tools/bash.d.ts.map +1 -0
  186. package/dist/core/tools/bash.js +242 -0
  187. package/dist/core/tools/bash.js.map +1 -0
  188. package/dist/core/tools/edit-diff.d.ts +63 -0
  189. package/dist/core/tools/edit-diff.d.ts.map +1 -0
  190. package/dist/core/tools/edit-diff.js +243 -0
  191. package/dist/core/tools/edit-diff.js.map +1 -0
  192. package/dist/core/tools/edit.d.ts +39 -0
  193. package/dist/core/tools/edit.d.ts.map +1 -0
  194. package/dist/core/tools/edit.js +146 -0
  195. package/dist/core/tools/edit.js.map +1 -0
  196. package/dist/core/tools/find.d.ts +39 -0
  197. package/dist/core/tools/find.d.ts.map +1 -0
  198. package/dist/core/tools/find.js +206 -0
  199. package/dist/core/tools/find.js.map +1 -0
  200. package/dist/core/tools/grep.d.ts +45 -0
  201. package/dist/core/tools/grep.d.ts.map +1 -0
  202. package/dist/core/tools/grep.js +239 -0
  203. package/dist/core/tools/grep.js.map +1 -0
  204. package/dist/core/tools/index.d.ts +102 -0
  205. package/dist/core/tools/index.d.ts.map +1 -0
  206. package/dist/core/tools/index.js +71 -0
  207. package/dist/core/tools/index.js.map +1 -0
  208. package/dist/core/tools/ls.d.ts +40 -0
  209. package/dist/core/tools/ls.d.ts.map +1 -0
  210. package/dist/core/tools/ls.js +118 -0
  211. package/dist/core/tools/ls.js.map +1 -0
  212. package/dist/core/tools/memory.d.ts +45 -0
  213. package/dist/core/tools/memory.d.ts.map +1 -0
  214. package/dist/core/tools/memory.js +346 -0
  215. package/dist/core/tools/memory.js.map +1 -0
  216. package/dist/core/tools/path-utils.d.ts +8 -0
  217. package/dist/core/tools/path-utils.d.ts.map +1 -0
  218. package/dist/core/tools/path-utils.js +81 -0
  219. package/dist/core/tools/path-utils.js.map +1 -0
  220. package/dist/core/tools/read.d.ts +39 -0
  221. package/dist/core/tools/read.d.ts.map +1 -0
  222. package/dist/core/tools/read.js +166 -0
  223. package/dist/core/tools/read.js.map +1 -0
  224. package/dist/core/tools/truncate.d.ts +70 -0
  225. package/dist/core/tools/truncate.d.ts.map +1 -0
  226. package/dist/core/tools/truncate.js +205 -0
  227. package/dist/core/tools/truncate.js.map +1 -0
  228. package/dist/core/tools/write.d.ts +29 -0
  229. package/dist/core/tools/write.d.ts.map +1 -0
  230. package/dist/core/tools/write.js +78 -0
  231. package/dist/core/tools/write.js.map +1 -0
  232. package/dist/index.d.ts +28 -0
  233. package/dist/index.d.ts.map +1 -0
  234. package/dist/index.js +43 -0
  235. package/dist/index.js.map +1 -0
  236. package/dist/main.d.ts +8 -0
  237. package/dist/main.d.ts.map +1 -0
  238. package/dist/main.js +651 -0
  239. package/dist/main.js.map +1 -0
  240. package/dist/migrations.d.ts +33 -0
  241. package/dist/migrations.d.ts.map +1 -0
  242. package/dist/migrations.js +261 -0
  243. package/dist/migrations.js.map +1 -0
  244. package/dist/modes/index.d.ts +9 -0
  245. package/dist/modes/index.d.ts.map +1 -0
  246. package/dist/modes/index.js +8 -0
  247. package/dist/modes/index.js.map +1 -0
  248. package/dist/modes/interactive/components/armin.d.ts +34 -0
  249. package/dist/modes/interactive/components/armin.d.ts.map +1 -0
  250. package/dist/modes/interactive/components/armin.js +333 -0
  251. package/dist/modes/interactive/components/armin.js.map +1 -0
  252. package/dist/modes/interactive/components/assistant-message.d.ts +16 -0
  253. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -0
  254. package/dist/modes/interactive/components/assistant-message.js +96 -0
  255. package/dist/modes/interactive/components/assistant-message.js.map +1 -0
  256. package/dist/modes/interactive/components/bash-execution.d.ts +35 -0
  257. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -0
  258. package/dist/modes/interactive/components/bash-execution.js +162 -0
  259. package/dist/modes/interactive/components/bash-execution.js.map +1 -0
  260. package/dist/modes/interactive/components/bordered-loader.d.ts +16 -0
  261. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -0
  262. package/dist/modes/interactive/components/bordered-loader.js +51 -0
  263. package/dist/modes/interactive/components/bordered-loader.js.map +1 -0
  264. package/dist/modes/interactive/components/branch-summary-message.d.ts +16 -0
  265. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -0
  266. package/dist/modes/interactive/components/branch-summary-message.js +44 -0
  267. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -0
  268. package/dist/modes/interactive/components/compaction-summary-message.d.ts +16 -0
  269. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -0
  270. package/dist/modes/interactive/components/compaction-summary-message.js +45 -0
  271. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -0
  272. package/dist/modes/interactive/components/config-selector.d.ts +71 -0
  273. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -0
  274. package/dist/modes/interactive/components/config-selector.js +479 -0
  275. package/dist/modes/interactive/components/config-selector.js.map +1 -0
  276. package/dist/modes/interactive/components/countdown-timer.d.ts +14 -0
  277. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -0
  278. package/dist/modes/interactive/components/countdown-timer.js +33 -0
  279. package/dist/modes/interactive/components/countdown-timer.js.map +1 -0
  280. package/dist/modes/interactive/components/custom-editor.d.ts +21 -0
  281. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -0
  282. package/dist/modes/interactive/components/custom-editor.js +70 -0
  283. package/dist/modes/interactive/components/custom-editor.js.map +1 -0
  284. package/dist/modes/interactive/components/custom-message.d.ts +20 -0
  285. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
  286. package/dist/modes/interactive/components/custom-message.js +79 -0
  287. package/dist/modes/interactive/components/custom-message.js.map +1 -0
  288. package/dist/modes/interactive/components/daxnuts.d.ts +23 -0
  289. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -0
  290. package/dist/modes/interactive/components/daxnuts.js +140 -0
  291. package/dist/modes/interactive/components/daxnuts.js.map +1 -0
  292. package/dist/modes/interactive/components/diff.d.ts +12 -0
  293. package/dist/modes/interactive/components/diff.d.ts.map +1 -0
  294. package/dist/modes/interactive/components/diff.js +133 -0
  295. package/dist/modes/interactive/components/diff.js.map +1 -0
  296. package/dist/modes/interactive/components/dynamic-border.d.ts +15 -0
  297. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -0
  298. package/dist/modes/interactive/components/dynamic-border.js +21 -0
  299. package/dist/modes/interactive/components/dynamic-border.js.map +1 -0
  300. package/dist/modes/interactive/components/extension-editor.d.ts +17 -0
  301. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
  302. package/dist/modes/interactive/components/extension-editor.js +102 -0
  303. package/dist/modes/interactive/components/extension-editor.js.map +1 -0
  304. package/dist/modes/interactive/components/extension-input.d.ts +23 -0
  305. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
  306. package/dist/modes/interactive/components/extension-input.js +61 -0
  307. package/dist/modes/interactive/components/extension-input.js.map +1 -0
  308. package/dist/modes/interactive/components/extension-selector.d.ts +24 -0
  309. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
  310. package/dist/modes/interactive/components/extension-selector.js +78 -0
  311. package/dist/modes/interactive/components/extension-selector.js.map +1 -0
  312. package/dist/modes/interactive/components/footer.d.ts +26 -0
  313. package/dist/modes/interactive/components/footer.d.ts.map +1 -0
  314. package/dist/modes/interactive/components/footer.js +213 -0
  315. package/dist/modes/interactive/components/footer.js.map +1 -0
  316. package/dist/modes/interactive/components/index.d.ts +32 -0
  317. package/dist/modes/interactive/components/index.d.ts.map +1 -0
  318. package/dist/modes/interactive/components/index.js +33 -0
  319. package/dist/modes/interactive/components/index.js.map +1 -0
  320. package/dist/modes/interactive/components/keybinding-hints.d.ts +41 -0
  321. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -0
  322. package/dist/modes/interactive/components/keybinding-hints.js +61 -0
  323. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -0
  324. package/dist/modes/interactive/components/login-dialog.d.ts +42 -0
  325. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -0
  326. package/dist/modes/interactive/components/login-dialog.js +145 -0
  327. package/dist/modes/interactive/components/login-dialog.js.map +1 -0
  328. package/dist/modes/interactive/components/model-selector.d.ts +47 -0
  329. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -0
  330. package/dist/modes/interactive/components/model-selector.js +271 -0
  331. package/dist/modes/interactive/components/model-selector.js.map +1 -0
  332. package/dist/modes/interactive/components/oauth-selector.d.ts +19 -0
  333. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -0
  334. package/dist/modes/interactive/components/oauth-selector.js +97 -0
  335. package/dist/modes/interactive/components/oauth-selector.js.map +1 -0
  336. package/dist/modes/interactive/components/scoped-models-selector.d.ts +49 -0
  337. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -0
  338. package/dist/modes/interactive/components/scoped-models-selector.js +275 -0
  339. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -0
  340. package/dist/modes/interactive/components/session-selector-search.d.ts +23 -0
  341. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -0
  342. package/dist/modes/interactive/components/session-selector-search.js +155 -0
  343. package/dist/modes/interactive/components/session-selector-search.js.map +1 -0
  344. package/dist/modes/interactive/components/session-selector.d.ts +95 -0
  345. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -0
  346. package/dist/modes/interactive/components/session-selector.js +851 -0
  347. package/dist/modes/interactive/components/session-selector.js.map +1 -0
  348. package/dist/modes/interactive/components/settings-selector.d.ts +58 -0
  349. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -0
  350. package/dist/modes/interactive/components/settings-selector.js +299 -0
  351. package/dist/modes/interactive/components/settings-selector.js.map +1 -0
  352. package/dist/modes/interactive/components/show-images-selector.d.ts +10 -0
  353. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -0
  354. package/dist/modes/interactive/components/show-images-selector.js +35 -0
  355. package/dist/modes/interactive/components/show-images-selector.js.map +1 -0
  356. package/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
  357. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -0
  358. package/dist/modes/interactive/components/skill-invocation-message.js +47 -0
  359. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -0
  360. package/dist/modes/interactive/components/theme-selector.d.ts +11 -0
  361. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -0
  362. package/dist/modes/interactive/components/theme-selector.js +46 -0
  363. package/dist/modes/interactive/components/theme-selector.js.map +1 -0
  364. package/dist/modes/interactive/components/thinking-selector.d.ts +11 -0
  365. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -0
  366. package/dist/modes/interactive/components/thinking-selector.js +47 -0
  367. package/dist/modes/interactive/components/thinking-selector.js.map +1 -0
  368. package/dist/modes/interactive/components/tool-execution.d.ts +70 -0
  369. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -0
  370. package/dist/modes/interactive/components/tool-execution.js +636 -0
  371. package/dist/modes/interactive/components/tool-execution.js.map +1 -0
  372. package/dist/modes/interactive/components/tree-selector.d.ts +68 -0
  373. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -0
  374. package/dist/modes/interactive/components/tree-selector.js +934 -0
  375. package/dist/modes/interactive/components/tree-selector.js.map +1 -0
  376. package/dist/modes/interactive/components/user-message-selector.d.ts +30 -0
  377. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -0
  378. package/dist/modes/interactive/components/user-message-selector.js +113 -0
  379. package/dist/modes/interactive/components/user-message-selector.js.map +1 -0
  380. package/dist/modes/interactive/components/user-message.d.ts +8 -0
  381. package/dist/modes/interactive/components/user-message.d.ts.map +1 -0
  382. package/dist/modes/interactive/components/user-message.js +16 -0
  383. package/dist/modes/interactive/components/user-message.js.map +1 -0
  384. package/dist/modes/interactive/components/visual-truncate.d.ts +24 -0
  385. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -0
  386. package/dist/modes/interactive/components/visual-truncate.js +33 -0
  387. package/dist/modes/interactive/components/visual-truncate.js.map +1 -0
  388. package/dist/modes/interactive/interactive-mode.d.ts +316 -0
  389. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -0
  390. package/dist/modes/interactive/interactive-mode.js +3848 -0
  391. package/dist/modes/interactive/interactive-mode.js.map +1 -0
  392. package/dist/modes/interactive/theme/dark.json +85 -0
  393. package/dist/modes/interactive/theme/light.json +84 -0
  394. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  395. package/dist/modes/interactive/theme/theme.d.ts +78 -0
  396. package/dist/modes/interactive/theme/theme.d.ts.map +1 -0
  397. package/dist/modes/interactive/theme/theme.js +944 -0
  398. package/dist/modes/interactive/theme/theme.js.map +1 -0
  399. package/dist/modes/print-mode.d.ts +28 -0
  400. package/dist/modes/print-mode.d.ts.map +1 -0
  401. package/dist/modes/print-mode.js +101 -0
  402. package/dist/modes/print-mode.js.map +1 -0
  403. package/dist/modes/rpc/rpc-client.d.ts +217 -0
  404. package/dist/modes/rpc/rpc-client.d.ts.map +1 -0
  405. package/dist/modes/rpc/rpc-client.js +405 -0
  406. package/dist/modes/rpc/rpc-client.js.map +1 -0
  407. package/dist/modes/rpc/rpc-mode.d.ts +20 -0
  408. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -0
  409. package/dist/modes/rpc/rpc-mode.js +511 -0
  410. package/dist/modes/rpc/rpc-mode.js.map +1 -0
  411. package/dist/modes/rpc/rpc-types.d.ts +409 -0
  412. package/dist/modes/rpc/rpc-types.d.ts.map +1 -0
  413. package/dist/modes/rpc/rpc-types.js +8 -0
  414. package/dist/modes/rpc/rpc-types.js.map +1 -0
  415. package/dist/utils/changelog.d.ts +21 -0
  416. package/dist/utils/changelog.d.ts.map +1 -0
  417. package/dist/utils/changelog.js +87 -0
  418. package/dist/utils/changelog.js.map +1 -0
  419. package/dist/utils/clipboard-image.d.ts +11 -0
  420. package/dist/utils/clipboard-image.d.ts.map +1 -0
  421. package/dist/utils/clipboard-image.js +162 -0
  422. package/dist/utils/clipboard-image.js.map +1 -0
  423. package/dist/utils/clipboard-native.d.ts +7 -0
  424. package/dist/utils/clipboard-native.d.ts.map +1 -0
  425. package/dist/utils/clipboard-native.js +14 -0
  426. package/dist/utils/clipboard-native.js.map +1 -0
  427. package/dist/utils/clipboard.d.ts +2 -0
  428. package/dist/utils/clipboard.d.ts.map +1 -0
  429. package/dist/utils/clipboard.js +67 -0
  430. package/dist/utils/clipboard.js.map +1 -0
  431. package/dist/utils/frontmatter.d.ts +8 -0
  432. package/dist/utils/frontmatter.d.ts.map +1 -0
  433. package/dist/utils/frontmatter.js +26 -0
  434. package/dist/utils/frontmatter.js.map +1 -0
  435. package/dist/utils/git.d.ts +26 -0
  436. package/dist/utils/git.d.ts.map +1 -0
  437. package/dist/utils/git.js +163 -0
  438. package/dist/utils/git.js.map +1 -0
  439. package/dist/utils/image-convert.d.ts +9 -0
  440. package/dist/utils/image-convert.d.ts.map +1 -0
  441. package/dist/utils/image-convert.js +35 -0
  442. package/dist/utils/image-convert.js.map +1 -0
  443. package/dist/utils/image-resize.d.ts +36 -0
  444. package/dist/utils/image-resize.d.ts.map +1 -0
  445. package/dist/utils/image-resize.js +181 -0
  446. package/dist/utils/image-resize.js.map +1 -0
  447. package/dist/utils/mime.d.ts +2 -0
  448. package/dist/utils/mime.d.ts.map +1 -0
  449. package/dist/utils/mime.js +26 -0
  450. package/dist/utils/mime.js.map +1 -0
  451. package/dist/utils/photon.d.ts +21 -0
  452. package/dist/utils/photon.d.ts.map +1 -0
  453. package/dist/utils/photon.js +121 -0
  454. package/dist/utils/photon.js.map +1 -0
  455. package/dist/utils/shell.d.ts +26 -0
  456. package/dist/utils/shell.d.ts.map +1 -0
  457. package/dist/utils/shell.js +186 -0
  458. package/dist/utils/shell.js.map +1 -0
  459. package/dist/utils/sleep.d.ts +5 -0
  460. package/dist/utils/sleep.d.ts.map +1 -0
  461. package/dist/utils/sleep.js +17 -0
  462. package/dist/utils/sleep.js.map +1 -0
  463. package/dist/utils/tools-manager.d.ts +3 -0
  464. package/dist/utils/tools-manager.d.ts.map +1 -0
  465. package/dist/utils/tools-manager.js +207 -0
  466. package/dist/utils/tools-manager.js.map +1 -0
  467. package/docs/compaction.md +390 -0
  468. package/docs/custom-provider.md +548 -0
  469. package/docs/development.md +69 -0
  470. package/docs/extensions.md +1935 -0
  471. package/docs/images/doom-extension.png +0 -0
  472. package/docs/images/exy.png +0 -0
  473. package/docs/images/interactive-mode.png +0 -0
  474. package/docs/images/tree-view.png +0 -0
  475. package/docs/json.md +79 -0
  476. package/docs/keybindings.md +174 -0
  477. package/docs/models.md +293 -0
  478. package/docs/packages.md +209 -0
  479. package/docs/prompt-templates.md +67 -0
  480. package/docs/providers.md +186 -0
  481. package/docs/rpc.md +1317 -0
  482. package/docs/sdk.md +968 -0
  483. package/docs/session.md +412 -0
  484. package/docs/settings.md +223 -0
  485. package/docs/shell-aliases.md +13 -0
  486. package/docs/skills.md +231 -0
  487. package/docs/terminal-setup.md +70 -0
  488. package/docs/termux.md +127 -0
  489. package/docs/themes.md +295 -0
  490. package/docs/tree.md +219 -0
  491. package/docs/tui.md +887 -0
  492. package/docs/windows.md +17 -0
  493. package/examples/README.md +25 -0
  494. package/examples/extensions/README.md +203 -0
  495. package/examples/extensions/antigravity-image-gen.ts +413 -0
  496. package/examples/extensions/auto-commit-on-exit.ts +49 -0
  497. package/examples/extensions/bash-spawn-hook.ts +30 -0
  498. package/examples/extensions/bookmark.ts +50 -0
  499. package/examples/extensions/claude-rules.ts +86 -0
  500. package/examples/extensions/commands.ts +72 -0
  501. package/examples/extensions/confirm-destructive.ts +59 -0
  502. package/examples/extensions/custom-compaction.ts +114 -0
  503. package/examples/extensions/custom-footer.ts +64 -0
  504. package/examples/extensions/custom-header.ts +73 -0
  505. package/examples/extensions/custom-provider-anthropic/index.ts +604 -0
  506. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  507. package/examples/extensions/custom-provider-anthropic/package.json +19 -0
  508. package/examples/extensions/custom-provider-gitlab-duo/index.ts +349 -0
  509. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  510. package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
  511. package/examples/extensions/custom-provider-qwen-cli/index.ts +345 -0
  512. package/examples/extensions/custom-provider-qwen-cli/package.json +16 -0
  513. package/examples/extensions/dirty-repo-guard.ts +56 -0
  514. package/examples/extensions/doom-overlay/README.md +46 -0
  515. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  516. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  517. package/examples/extensions/doom-overlay/doom/build.sh +152 -0
  518. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  519. package/examples/extensions/doom-overlay/doom-component.ts +132 -0
  520. package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  521. package/examples/extensions/doom-overlay/doom-keys.ts +104 -0
  522. package/examples/extensions/doom-overlay/index.ts +74 -0
  523. package/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  524. package/examples/extensions/dynamic-resources/SKILL.md +8 -0
  525. package/examples/extensions/dynamic-resources/dynamic.json +79 -0
  526. package/examples/extensions/dynamic-resources/dynamic.md +5 -0
  527. package/examples/extensions/dynamic-resources/index.ts +15 -0
  528. package/examples/extensions/event-bus.ts +43 -0
  529. package/examples/extensions/file-trigger.ts +41 -0
  530. package/examples/extensions/git-checkpoint.ts +53 -0
  531. package/examples/extensions/handoff.ts +150 -0
  532. package/examples/extensions/hello.ts +25 -0
  533. package/examples/extensions/inline-bash.ts +94 -0
  534. package/examples/extensions/input-transform.ts +43 -0
  535. package/examples/extensions/interactive-shell.ts +196 -0
  536. package/examples/extensions/mac-system-theme.ts +47 -0
  537. package/examples/extensions/message-renderer.ts +59 -0
  538. package/examples/extensions/minimal-mode.ts +426 -0
  539. package/examples/extensions/modal-editor.ts +85 -0
  540. package/examples/extensions/model-status.ts +31 -0
  541. package/examples/extensions/notify.ts +55 -0
  542. package/examples/extensions/overlay-qa-tests.ts +881 -0
  543. package/examples/extensions/overlay-test.ts +150 -0
  544. package/examples/extensions/permission-gate.ts +34 -0
  545. package/examples/extensions/pirate.ts +47 -0
  546. package/examples/extensions/plan-mode/README.md +65 -0
  547. package/examples/extensions/plan-mode/index.ts +340 -0
  548. package/examples/extensions/plan-mode/utils.ts +168 -0
  549. package/examples/extensions/preset.ts +398 -0
  550. package/examples/extensions/protected-paths.ts +30 -0
  551. package/examples/extensions/qna.ts +119 -0
  552. package/examples/extensions/question.ts +264 -0
  553. package/examples/extensions/questionnaire.ts +427 -0
  554. package/examples/extensions/rainbow-editor.ts +88 -0
  555. package/examples/extensions/reload-runtime.ts +37 -0
  556. package/examples/extensions/rpc-demo.ts +124 -0
  557. package/examples/extensions/sandbox/index.ts +318 -0
  558. package/examples/extensions/sandbox/package-lock.json +92 -0
  559. package/examples/extensions/sandbox/package.json +19 -0
  560. package/examples/extensions/send-user-message.ts +97 -0
  561. package/examples/extensions/session-name.ts +27 -0
  562. package/examples/extensions/shutdown-command.ts +63 -0
  563. package/examples/extensions/snake.ts +343 -0
  564. package/examples/extensions/space-invaders.ts +560 -0
  565. package/examples/extensions/ssh.ts +220 -0
  566. package/examples/extensions/status-line.ts +40 -0
  567. package/examples/extensions/subagent/README.md +172 -0
  568. package/examples/extensions/subagent/agents/planner.md +37 -0
  569. package/examples/extensions/subagent/agents/reviewer.md +35 -0
  570. package/examples/extensions/subagent/agents/scout.md +50 -0
  571. package/examples/extensions/subagent/agents/worker.md +24 -0
  572. package/examples/extensions/subagent/agents.ts +127 -0
  573. package/examples/extensions/subagent/index.ts +964 -0
  574. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  575. package/examples/extensions/subagent/prompts/implement.md +10 -0
  576. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  577. package/examples/extensions/summarize.ts +195 -0
  578. package/examples/extensions/system-prompt-header.ts +17 -0
  579. package/examples/extensions/timed-confirm.ts +70 -0
  580. package/examples/extensions/titlebar-spinner.ts +58 -0
  581. package/examples/extensions/todo.ts +299 -0
  582. package/examples/extensions/tool-override.ts +143 -0
  583. package/examples/extensions/tools.ts +146 -0
  584. package/examples/extensions/trigger-compact.ts +40 -0
  585. package/examples/extensions/truncated-tool.ts +192 -0
  586. package/examples/extensions/widget-placement.ts +17 -0
  587. package/examples/extensions/with-deps/index.ts +36 -0
  588. package/examples/extensions/with-deps/package-lock.json +31 -0
  589. package/examples/extensions/with-deps/package.json +22 -0
  590. package/examples/rpc-extension-ui.ts +632 -0
  591. package/examples/sdk/01-minimal.ts +22 -0
  592. package/examples/sdk/02-custom-model.ts +49 -0
  593. package/examples/sdk/03-custom-prompt.ts +55 -0
  594. package/examples/sdk/04-skills.ts +46 -0
  595. package/examples/sdk/05-tools.ts +56 -0
  596. package/examples/sdk/06-extensions.ts +88 -0
  597. package/examples/sdk/07-context-files.ts +40 -0
  598. package/examples/sdk/08-prompt-templates.ts +47 -0
  599. package/examples/sdk/09-api-keys-and-oauth.ts +48 -0
  600. package/examples/sdk/10-settings.ts +51 -0
  601. package/examples/sdk/11-sessions.ts +48 -0
  602. package/examples/sdk/12-full-control.ts +82 -0
  603. package/examples/sdk/README.md +144 -0
  604. package/package.json +96 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-diff.js","sourceRoot":"","sources":["../../../src/core/tools/edit-diff.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Shared diff computation utilities for the edit tool.\r\n * Used by both edit.ts (for execution) and tool-execution.ts (for preview rendering).\r\n */\r\n\r\nimport * as Diff from \"diff\";\r\nimport { constants } from \"fs\";\r\nimport { access, readFile } from \"fs/promises\";\r\nimport { resolveToCwd } from \"./path-utils.js\";\r\n\r\nexport function detectLineEnding(content: string): \"\\r\\n\" | \"\\n\" {\r\n\tconst crlfIdx = content.indexOf(\"\\r\\n\");\r\n\tconst lfIdx = content.indexOf(\"\\n\");\r\n\tif (lfIdx === -1) return \"\\n\";\r\n\tif (crlfIdx === -1) return \"\\n\";\r\n\treturn crlfIdx < lfIdx ? \"\\r\\n\" : \"\\n\";\r\n}\r\n\r\nexport function normalizeToLF(text: string): string {\r\n\treturn text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\r\n}\r\n\r\nexport function restoreLineEndings(text: string, ending: \"\\r\\n\" | \"\\n\"): string {\r\n\treturn ending === \"\\r\\n\" ? text.replace(/\\n/g, \"\\r\\n\") : text;\r\n}\r\n\r\n/**\r\n * Normalize text for fuzzy matching. Applies progressive transformations:\r\n * - Strip trailing whitespace from each line\r\n * - Normalize smart quotes to ASCII equivalents\r\n * - Normalize Unicode dashes/hyphens to ASCII hyphen\r\n * - Normalize special Unicode spaces to regular space\r\n */\r\nexport function normalizeForFuzzyMatch(text: string): string {\r\n\treturn (\r\n\t\ttext\r\n\t\t\t// Strip trailing whitespace per line\r\n\t\t\t.split(\"\\n\")\r\n\t\t\t.map((line) => line.trimEnd())\r\n\t\t\t.join(\"\\n\")\r\n\t\t\t// Smart single quotes → '\r\n\t\t\t.replace(/[\\u2018\\u2019\\u201A\\u201B]/g, \"'\")\r\n\t\t\t// Smart double quotes → \"\r\n\t\t\t.replace(/[\\u201C\\u201D\\u201E\\u201F]/g, '\"')\r\n\t\t\t// Various dashes/hyphens → -\r\n\t\t\t// U+2010 hyphen, U+2011 non-breaking hyphen, U+2012 figure dash,\r\n\t\t\t// U+2013 en-dash, U+2014 em-dash, U+2015 horizontal bar, U+2212 minus\r\n\t\t\t.replace(/[\\u2010\\u2011\\u2012\\u2013\\u2014\\u2015\\u2212]/g, \"-\")\r\n\t\t\t// Special spaces → regular space\r\n\t\t\t// U+00A0 NBSP, U+2002-U+200A various spaces, U+202F narrow NBSP,\r\n\t\t\t// U+205F medium math space, U+3000 ideographic space\r\n\t\t\t.replace(/[\\u00A0\\u2002-\\u200A\\u202F\\u205F\\u3000]/g, \" \")\r\n\t);\r\n}\r\n\r\nexport interface FuzzyMatchResult {\r\n\t/** Whether a match was found */\r\n\tfound: boolean;\r\n\t/** The index where the match starts (in the content that should be used for replacement) */\r\n\tindex: number;\r\n\t/** Length of the matched text */\r\n\tmatchLength: number;\r\n\t/** Whether fuzzy matching was used (false = exact match) */\r\n\tusedFuzzyMatch: boolean;\r\n\t/**\r\n\t * The content to use for replacement operations.\r\n\t * When exact match: original content. When fuzzy match: normalized content.\r\n\t */\r\n\tcontentForReplacement: string;\r\n}\r\n\r\n/**\r\n * Find oldText in content, trying exact match first, then fuzzy match.\r\n * When fuzzy matching is used, the returned contentForReplacement is the\r\n * fuzzy-normalized version of the content (trailing whitespace stripped,\r\n * Unicode quotes/dashes normalized to ASCII).\r\n */\r\nexport function fuzzyFindText(content: string, oldText: string): FuzzyMatchResult {\r\n\t// Try exact match first\r\n\tconst exactIndex = content.indexOf(oldText);\r\n\tif (exactIndex !== -1) {\r\n\t\treturn {\r\n\t\t\tfound: true,\r\n\t\t\tindex: exactIndex,\r\n\t\t\tmatchLength: oldText.length,\r\n\t\t\tusedFuzzyMatch: false,\r\n\t\t\tcontentForReplacement: content,\r\n\t\t};\r\n\t}\r\n\r\n\t// Try fuzzy match - work entirely in normalized space\r\n\tconst fuzzyContent = normalizeForFuzzyMatch(content);\r\n\tconst fuzzyOldText = normalizeForFuzzyMatch(oldText);\r\n\tconst fuzzyIndex = fuzzyContent.indexOf(fuzzyOldText);\r\n\r\n\tif (fuzzyIndex === -1) {\r\n\t\treturn {\r\n\t\t\tfound: false,\r\n\t\t\tindex: -1,\r\n\t\t\tmatchLength: 0,\r\n\t\t\tusedFuzzyMatch: false,\r\n\t\t\tcontentForReplacement: content,\r\n\t\t};\r\n\t}\r\n\r\n\t// When fuzzy matching, we work in the normalized space for replacement.\r\n\t// This means the output will have normalized whitespace/quotes/dashes,\r\n\t// which is acceptable since we're fixing minor formatting differences anyway.\r\n\treturn {\r\n\t\tfound: true,\r\n\t\tindex: fuzzyIndex,\r\n\t\tmatchLength: fuzzyOldText.length,\r\n\t\tusedFuzzyMatch: true,\r\n\t\tcontentForReplacement: fuzzyContent,\r\n\t};\r\n}\r\n\r\n/** Strip UTF-8 BOM if present, return both the BOM (if any) and the text without it */\r\nexport function stripBom(content: string): { bom: string; text: string } {\r\n\treturn content.startsWith(\"\\uFEFF\") ? { bom: \"\\uFEFF\", text: content.slice(1) } : { bom: \"\", text: content };\r\n}\r\n\r\n/**\r\n * Generate a unified diff string with line numbers and context.\r\n * Returns both the diff string and the first changed line number (in the new file).\r\n */\r\nexport function generateDiffString(\r\n\toldContent: string,\r\n\tnewContent: string,\r\n\tcontextLines = 4,\r\n): { diff: string; firstChangedLine: number | undefined } {\r\n\tconst parts = Diff.diffLines(oldContent, newContent);\r\n\tconst output: string[] = [];\r\n\r\n\tconst oldLines = oldContent.split(\"\\n\");\r\n\tconst newLines = newContent.split(\"\\n\");\r\n\tconst maxLineNum = Math.max(oldLines.length, newLines.length);\r\n\tconst lineNumWidth = String(maxLineNum).length;\r\n\r\n\tlet oldLineNum = 1;\r\n\tlet newLineNum = 1;\r\n\tlet lastWasChange = false;\r\n\tlet firstChangedLine: number | undefined;\r\n\r\n\tfor (let i = 0; i < parts.length; i++) {\r\n\t\tconst part = parts[i];\r\n\t\tconst raw = part.value.split(\"\\n\");\r\n\t\tif (raw[raw.length - 1] === \"\") {\r\n\t\t\traw.pop();\r\n\t\t}\r\n\r\n\t\tif (part.added || part.removed) {\r\n\t\t\t// Capture the first changed line (in the new file)\r\n\t\t\tif (firstChangedLine === undefined) {\r\n\t\t\t\tfirstChangedLine = newLineNum;\r\n\t\t\t}\r\n\r\n\t\t\t// Show the change\r\n\t\t\tfor (const line of raw) {\r\n\t\t\t\tif (part.added) {\r\n\t\t\t\t\tconst lineNum = String(newLineNum).padStart(lineNumWidth, \" \");\r\n\t\t\t\t\toutput.push(`+${lineNum} ${line}`);\r\n\t\t\t\t\tnewLineNum++;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// removed\r\n\t\t\t\t\tconst lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\r\n\t\t\t\t\toutput.push(`-${lineNum} ${line}`);\r\n\t\t\t\t\toldLineNum++;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tlastWasChange = true;\r\n\t\t} else {\r\n\t\t\t// Context lines - only show a few before/after changes\r\n\t\t\tconst nextPartIsChange = i < parts.length - 1 && (parts[i + 1].added || parts[i + 1].removed);\r\n\r\n\t\t\tif (lastWasChange || nextPartIsChange) {\r\n\t\t\t\t// Show context\r\n\t\t\t\tlet linesToShow = raw;\r\n\t\t\t\tlet skipStart = 0;\r\n\t\t\t\tlet skipEnd = 0;\r\n\r\n\t\t\t\tif (!lastWasChange) {\r\n\t\t\t\t\t// Show only last N lines as leading context\r\n\t\t\t\t\tskipStart = Math.max(0, raw.length - contextLines);\r\n\t\t\t\t\tlinesToShow = raw.slice(skipStart);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!nextPartIsChange && linesToShow.length > contextLines) {\r\n\t\t\t\t\t// Show only first N lines as trailing context\r\n\t\t\t\t\tskipEnd = linesToShow.length - contextLines;\r\n\t\t\t\t\tlinesToShow = linesToShow.slice(0, contextLines);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Add ellipsis if we skipped lines at start\r\n\t\t\t\tif (skipStart > 0) {\r\n\t\t\t\t\toutput.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\r\n\t\t\t\t\t// Update line numbers for the skipped leading context\r\n\t\t\t\t\toldLineNum += skipStart;\r\n\t\t\t\t\tnewLineNum += skipStart;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor (const line of linesToShow) {\r\n\t\t\t\t\tconst lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\r\n\t\t\t\t\toutput.push(` ${lineNum} ${line}`);\r\n\t\t\t\t\toldLineNum++;\r\n\t\t\t\t\tnewLineNum++;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Add ellipsis if we skipped lines at end\r\n\t\t\t\tif (skipEnd > 0) {\r\n\t\t\t\t\toutput.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\r\n\t\t\t\t\t// Update line numbers for the skipped trailing context\r\n\t\t\t\t\toldLineNum += skipEnd;\r\n\t\t\t\t\tnewLineNum += skipEnd;\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\t// Skip these context lines entirely\r\n\t\t\t\toldLineNum += raw.length;\r\n\t\t\t\tnewLineNum += raw.length;\r\n\t\t\t}\r\n\r\n\t\t\tlastWasChange = false;\r\n\t\t}\r\n\t}\r\n\r\n\treturn { diff: output.join(\"\\n\"), firstChangedLine };\r\n}\r\n\r\nexport interface EditDiffResult {\r\n\tdiff: string;\r\n\tfirstChangedLine: number | undefined;\r\n}\r\n\r\nexport interface EditDiffError {\r\n\terror: string;\r\n}\r\n\r\n/**\r\n * Compute the diff for an edit operation without applying it.\r\n * Used for preview rendering in the TUI before the tool executes.\r\n */\r\nexport async function computeEditDiff(\r\n\tpath: string,\r\n\toldText: string,\r\n\tnewText: string,\r\n\tcwd: string,\r\n): Promise<EditDiffResult | EditDiffError> {\r\n\tconst absolutePath = resolveToCwd(path, cwd);\r\n\r\n\ttry {\r\n\t\t// Check if file exists and is readable\r\n\t\ttry {\r\n\t\t\tawait access(absolutePath, constants.R_OK);\r\n\t\t} catch {\r\n\t\t\treturn { error: `File not found: ${path}` };\r\n\t\t}\r\n\r\n\t\t// Read the file\r\n\t\tconst rawContent = await readFile(absolutePath, \"utf-8\");\r\n\r\n\t\t// Strip BOM before matching (LLM won't include invisible BOM in oldText)\r\n\t\tconst { text: content } = stripBom(rawContent);\r\n\r\n\t\tconst normalizedContent = normalizeToLF(content);\r\n\t\tconst normalizedOldText = normalizeToLF(oldText);\r\n\t\tconst normalizedNewText = normalizeToLF(newText);\r\n\r\n\t\t// Find the old text using fuzzy matching (tries exact match first, then fuzzy)\r\n\t\tconst matchResult = fuzzyFindText(normalizedContent, normalizedOldText);\r\n\r\n\t\tif (!matchResult.found) {\r\n\t\t\treturn {\r\n\t\t\t\terror: `Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`,\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\t// Count occurrences using fuzzy-normalized content for consistency\r\n\t\tconst fuzzyContent = normalizeForFuzzyMatch(normalizedContent);\r\n\t\tconst fuzzyOldText = normalizeForFuzzyMatch(normalizedOldText);\r\n\t\tconst occurrences = fuzzyContent.split(fuzzyOldText).length - 1;\r\n\r\n\t\tif (occurrences > 1) {\r\n\t\t\treturn {\r\n\t\t\t\terror: `Found ${occurrences} occurrences of the text in ${path}. The text must be unique. Please provide more context to make it unique.`,\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\t// Compute the new content using the matched position\r\n\t\t// When fuzzy matching was used, contentForReplacement is the normalized version\r\n\t\tconst baseContent = matchResult.contentForReplacement;\r\n\t\tconst newContent =\r\n\t\t\tbaseContent.substring(0, matchResult.index) +\r\n\t\t\tnormalizedNewText +\r\n\t\t\tbaseContent.substring(matchResult.index + matchResult.matchLength);\r\n\r\n\t\t// Check if it would actually change anything\r\n\t\tif (baseContent === newContent) {\r\n\t\t\treturn {\r\n\t\t\t\terror: `No changes would be made to ${path}. The replacement produces identical content.`,\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\t// Generate the diff\r\n\t\treturn generateDiffString(baseContent, newContent);\r\n\t} catch (err) {\r\n\t\treturn { error: err instanceof Error ? err.message : String(err) };\r\n\t}\r\n}\r\n"]}
@@ -0,0 +1,39 @@
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import { type Static } from "@sinclair/typebox";
3
+ declare const editSchema: import("@sinclair/typebox").TObject<{
4
+ path: import("@sinclair/typebox").TString;
5
+ oldText: import("@sinclair/typebox").TString;
6
+ newText: import("@sinclair/typebox").TString;
7
+ }>;
8
+ export type EditToolInput = Static<typeof editSchema>;
9
+ export interface EditToolDetails {
10
+ /** Unified diff of the changes made */
11
+ diff: string;
12
+ /** Line number of the first change in the new file (for editor navigation) */
13
+ firstChangedLine?: number;
14
+ }
15
+ /**
16
+ * Pluggable operations for the edit tool.
17
+ * Override these to delegate file editing to remote systems (e.g., SSH).
18
+ */
19
+ export interface EditOperations {
20
+ /** Read file contents as a Buffer */
21
+ readFile: (absolutePath: string) => Promise<Buffer>;
22
+ /** Write content to a file */
23
+ writeFile: (absolutePath: string, content: string) => Promise<void>;
24
+ /** Check if file is readable and writable (throw if not) */
25
+ access: (absolutePath: string) => Promise<void>;
26
+ }
27
+ export interface EditToolOptions {
28
+ /** Custom operations for file editing. Default: local filesystem */
29
+ operations?: EditOperations;
30
+ }
31
+ export declare function createEditTool(cwd: string, options?: EditToolOptions): AgentTool<typeof editSchema>;
32
+ /** Default edit tool using process.cwd() - for backwards compatibility */
33
+ export declare const editTool: AgentTool<import("@sinclair/typebox").TObject<{
34
+ path: import("@sinclair/typebox").TString;
35
+ oldText: import("@sinclair/typebox").TString;
36
+ newText: import("@sinclair/typebox").TString;
37
+ }>, any>;
38
+ export {};
39
+ //# sourceMappingURL=edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../../src/core/tools/edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AActD,QAAA,MAAM,UAAU;;;;EAId,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,qCAAqC;IACrC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,8BAA8B;IAC9B,SAAS,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,4DAA4D;IAC5D,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAQD,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;CAC5B;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAyKnG;AAED,0EAA0E;AAC1E,eAAO,MAAM,QAAQ;;;;QAAgC,CAAC","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\r\nimport { type Static, Type } from \"@sinclair/typebox\";\r\nimport { constants } from \"fs\";\r\nimport { access as fsAccess, readFile as fsReadFile, writeFile as fsWriteFile } from \"fs/promises\";\r\nimport {\r\n\tdetectLineEnding,\r\n\tfuzzyFindText,\r\n\tgenerateDiffString,\r\n\tnormalizeForFuzzyMatch,\r\n\tnormalizeToLF,\r\n\trestoreLineEndings,\r\n\tstripBom,\r\n} from \"./edit-diff.js\";\r\nimport { resolveToCwd } from \"./path-utils.js\";\r\n\r\nconst editSchema = Type.Object({\r\n\tpath: Type.String({ description: \"Path to the file to edit (relative or absolute)\" }),\r\n\toldText: Type.String({ description: \"Exact text to find and replace (must match exactly)\" }),\r\n\tnewText: Type.String({ description: \"New text to replace the old text with\" }),\r\n});\r\n\r\nexport type EditToolInput = Static<typeof editSchema>;\r\n\r\nexport interface EditToolDetails {\r\n\t/** Unified diff of the changes made */\r\n\tdiff: string;\r\n\t/** Line number of the first change in the new file (for editor navigation) */\r\n\tfirstChangedLine?: number;\r\n}\r\n\r\n/**\r\n * Pluggable operations for the edit tool.\r\n * Override these to delegate file editing to remote systems (e.g., SSH).\r\n */\r\nexport interface EditOperations {\r\n\t/** Read file contents as a Buffer */\r\n\treadFile: (absolutePath: string) => Promise<Buffer>;\r\n\t/** Write content to a file */\r\n\twriteFile: (absolutePath: string, content: string) => Promise<void>;\r\n\t/** Check if file is readable and writable (throw if not) */\r\n\taccess: (absolutePath: string) => Promise<void>;\r\n}\r\n\r\nconst defaultEditOperations: EditOperations = {\r\n\treadFile: (path) => fsReadFile(path),\r\n\twriteFile: (path, content) => fsWriteFile(path, content, \"utf-8\"),\r\n\taccess: (path) => fsAccess(path, constants.R_OK | constants.W_OK),\r\n};\r\n\r\nexport interface EditToolOptions {\r\n\t/** Custom operations for file editing. Default: local filesystem */\r\n\toperations?: EditOperations;\r\n}\r\n\r\nexport function createEditTool(cwd: string, options?: EditToolOptions): AgentTool<typeof editSchema> {\r\n\tconst ops = options?.operations ?? defaultEditOperations;\r\n\r\n\treturn {\r\n\t\tname: \"edit\",\r\n\t\tlabel: \"edit\",\r\n\t\tdescription:\r\n\t\t\t\"Edit a file by replacing exact text. The oldText must match exactly (including whitespace). Use this for precise, surgical edits.\",\r\n\t\tparameters: editSchema,\r\n\t\texecute: async (\r\n\t\t\t_toolCallId: string,\r\n\t\t\t{ path, oldText, newText }: { path: string; oldText: string; newText: string },\r\n\t\t\tsignal?: AbortSignal,\r\n\t\t) => {\r\n\t\t\tconst absolutePath = resolveToCwd(path, cwd);\r\n\r\n\t\t\treturn new Promise<{\r\n\t\t\t\tcontent: Array<{ type: \"text\"; text: string }>;\r\n\t\t\t\tdetails: EditToolDetails | undefined;\r\n\t\t\t}>((resolve, reject) => {\r\n\t\t\t\t// Check if already aborted\r\n\t\t\t\tif (signal?.aborted) {\r\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet aborted = false;\r\n\r\n\t\t\t\t// Set up abort handler\r\n\t\t\t\tconst onAbort = () => {\r\n\t\t\t\t\taborted = true;\r\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\r\n\t\t\t\t};\r\n\r\n\t\t\t\tif (signal) {\r\n\t\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Perform the edit operation\r\n\t\t\t\t(async () => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\t// Check if file exists\r\n\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\tawait ops.access(absolutePath);\r\n\t\t\t\t\t\t} catch {\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treject(new Error(`File not found: ${path}`));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Check if aborted before reading\r\n\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Read the file\r\n\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\r\n\t\t\t\t\t\tconst rawContent = buffer.toString(\"utf-8\");\r\n\r\n\t\t\t\t\t\t// Check if aborted after reading\r\n\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Strip BOM before matching (LLM won't include invisible BOM in oldText)\r\n\t\t\t\t\t\tconst { bom, text: content } = stripBom(rawContent);\r\n\r\n\t\t\t\t\t\tconst originalEnding = detectLineEnding(content);\r\n\t\t\t\t\t\tconst normalizedContent = normalizeToLF(content);\r\n\t\t\t\t\t\tconst normalizedOldText = normalizeToLF(oldText);\r\n\t\t\t\t\t\tconst normalizedNewText = normalizeToLF(newText);\r\n\r\n\t\t\t\t\t\t// Find the old text using fuzzy matching (tries exact match first, then fuzzy)\r\n\t\t\t\t\t\tconst matchResult = fuzzyFindText(normalizedContent, normalizedOldText);\r\n\r\n\t\t\t\t\t\tif (!matchResult.found) {\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treject(\r\n\t\t\t\t\t\t\t\tnew Error(\r\n\t\t\t\t\t\t\t\t\t`Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`,\r\n\t\t\t\t\t\t\t\t),\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Count occurrences using fuzzy-normalized content for consistency\r\n\t\t\t\t\t\tconst fuzzyContent = normalizeForFuzzyMatch(normalizedContent);\r\n\t\t\t\t\t\tconst fuzzyOldText = normalizeForFuzzyMatch(normalizedOldText);\r\n\t\t\t\t\t\tconst occurrences = fuzzyContent.split(fuzzyOldText).length - 1;\r\n\r\n\t\t\t\t\t\tif (occurrences > 1) {\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treject(\r\n\t\t\t\t\t\t\t\tnew Error(\r\n\t\t\t\t\t\t\t\t\t`Found ${occurrences} occurrences of the text in ${path}. The text must be unique. Please provide more context to make it unique.`,\r\n\t\t\t\t\t\t\t\t),\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Check if aborted before writing\r\n\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Perform replacement using the matched text position\r\n\t\t\t\t\t\t// When fuzzy matching was used, contentForReplacement is the normalized version\r\n\t\t\t\t\t\tconst baseContent = matchResult.contentForReplacement;\r\n\t\t\t\t\t\tconst newContent =\r\n\t\t\t\t\t\t\tbaseContent.substring(0, matchResult.index) +\r\n\t\t\t\t\t\t\tnormalizedNewText +\r\n\t\t\t\t\t\t\tbaseContent.substring(matchResult.index + matchResult.matchLength);\r\n\r\n\t\t\t\t\t\t// Verify the replacement actually changed something\r\n\t\t\t\t\t\tif (baseContent === newContent) {\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treject(\r\n\t\t\t\t\t\t\t\tnew Error(\r\n\t\t\t\t\t\t\t\t\t`No changes made to ${path}. The replacement produced identical content. This might indicate an issue with special characters or the text not existing as expected.`,\r\n\t\t\t\t\t\t\t\t),\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tconst finalContent = bom + restoreLineEndings(newContent, originalEnding);\r\n\t\t\t\t\t\tawait ops.writeFile(absolutePath, finalContent);\r\n\r\n\t\t\t\t\t\t// Check if aborted after writing\r\n\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Clean up abort handler\r\n\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tconst diffResult = generateDiffString(baseContent, newContent);\r\n\t\t\t\t\t\tresolve({\r\n\t\t\t\t\t\t\tcontent: [\r\n\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\ttype: \"text\",\r\n\t\t\t\t\t\t\t\t\ttext: `Successfully replaced text in ${path}.`,\r\n\t\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\t],\r\n\t\t\t\t\t\t\tdetails: { diff: diffResult.diff, firstChangedLine: diffResult.firstChangedLine },\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} catch (error: any) {\r\n\t\t\t\t\t\t// Clean up abort handler\r\n\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (!aborted) {\r\n\t\t\t\t\t\t\treject(error);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t})();\r\n\t\t\t});\r\n\t\t},\r\n\t};\r\n}\r\n\r\n/** Default edit tool using process.cwd() - for backwards compatibility */\r\nexport const editTool = createEditTool(process.cwd());\r\n"]}
@@ -0,0 +1,146 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { constants } from "fs";
3
+ import { access as fsAccess, readFile as fsReadFile, writeFile as fsWriteFile } from "fs/promises";
4
+ import { detectLineEnding, fuzzyFindText, generateDiffString, normalizeForFuzzyMatch, normalizeToLF, restoreLineEndings, stripBom, } from "./edit-diff.js";
5
+ import { resolveToCwd } from "./path-utils.js";
6
+ const editSchema = Type.Object({
7
+ path: Type.String({ description: "Path to the file to edit (relative or absolute)" }),
8
+ oldText: Type.String({ description: "Exact text to find and replace (must match exactly)" }),
9
+ newText: Type.String({ description: "New text to replace the old text with" }),
10
+ });
11
+ const defaultEditOperations = {
12
+ readFile: (path) => fsReadFile(path),
13
+ writeFile: (path, content) => fsWriteFile(path, content, "utf-8"),
14
+ access: (path) => fsAccess(path, constants.R_OK | constants.W_OK),
15
+ };
16
+ export function createEditTool(cwd, options) {
17
+ const ops = options?.operations ?? defaultEditOperations;
18
+ return {
19
+ name: "edit",
20
+ label: "edit",
21
+ description: "Edit a file by replacing exact text. The oldText must match exactly (including whitespace). Use this for precise, surgical edits.",
22
+ parameters: editSchema,
23
+ execute: async (_toolCallId, { path, oldText, newText }, signal) => {
24
+ const absolutePath = resolveToCwd(path, cwd);
25
+ return new Promise((resolve, reject) => {
26
+ // Check if already aborted
27
+ if (signal?.aborted) {
28
+ reject(new Error("Operation aborted"));
29
+ return;
30
+ }
31
+ let aborted = false;
32
+ // Set up abort handler
33
+ const onAbort = () => {
34
+ aborted = true;
35
+ reject(new Error("Operation aborted"));
36
+ };
37
+ if (signal) {
38
+ signal.addEventListener("abort", onAbort, { once: true });
39
+ }
40
+ // Perform the edit operation
41
+ (async () => {
42
+ try {
43
+ // Check if file exists
44
+ try {
45
+ await ops.access(absolutePath);
46
+ }
47
+ catch {
48
+ if (signal) {
49
+ signal.removeEventListener("abort", onAbort);
50
+ }
51
+ reject(new Error(`File not found: ${path}`));
52
+ return;
53
+ }
54
+ // Check if aborted before reading
55
+ if (aborted) {
56
+ return;
57
+ }
58
+ // Read the file
59
+ const buffer = await ops.readFile(absolutePath);
60
+ const rawContent = buffer.toString("utf-8");
61
+ // Check if aborted after reading
62
+ if (aborted) {
63
+ return;
64
+ }
65
+ // Strip BOM before matching (LLM won't include invisible BOM in oldText)
66
+ const { bom, text: content } = stripBom(rawContent);
67
+ const originalEnding = detectLineEnding(content);
68
+ const normalizedContent = normalizeToLF(content);
69
+ const normalizedOldText = normalizeToLF(oldText);
70
+ const normalizedNewText = normalizeToLF(newText);
71
+ // Find the old text using fuzzy matching (tries exact match first, then fuzzy)
72
+ const matchResult = fuzzyFindText(normalizedContent, normalizedOldText);
73
+ if (!matchResult.found) {
74
+ if (signal) {
75
+ signal.removeEventListener("abort", onAbort);
76
+ }
77
+ reject(new Error(`Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`));
78
+ return;
79
+ }
80
+ // Count occurrences using fuzzy-normalized content for consistency
81
+ const fuzzyContent = normalizeForFuzzyMatch(normalizedContent);
82
+ const fuzzyOldText = normalizeForFuzzyMatch(normalizedOldText);
83
+ const occurrences = fuzzyContent.split(fuzzyOldText).length - 1;
84
+ if (occurrences > 1) {
85
+ if (signal) {
86
+ signal.removeEventListener("abort", onAbort);
87
+ }
88
+ reject(new Error(`Found ${occurrences} occurrences of the text in ${path}. The text must be unique. Please provide more context to make it unique.`));
89
+ return;
90
+ }
91
+ // Check if aborted before writing
92
+ if (aborted) {
93
+ return;
94
+ }
95
+ // Perform replacement using the matched text position
96
+ // When fuzzy matching was used, contentForReplacement is the normalized version
97
+ const baseContent = matchResult.contentForReplacement;
98
+ const newContent = baseContent.substring(0, matchResult.index) +
99
+ normalizedNewText +
100
+ baseContent.substring(matchResult.index + matchResult.matchLength);
101
+ // Verify the replacement actually changed something
102
+ if (baseContent === newContent) {
103
+ if (signal) {
104
+ signal.removeEventListener("abort", onAbort);
105
+ }
106
+ reject(new Error(`No changes made to ${path}. The replacement produced identical content. This might indicate an issue with special characters or the text not existing as expected.`));
107
+ return;
108
+ }
109
+ const finalContent = bom + restoreLineEndings(newContent, originalEnding);
110
+ await ops.writeFile(absolutePath, finalContent);
111
+ // Check if aborted after writing
112
+ if (aborted) {
113
+ return;
114
+ }
115
+ // Clean up abort handler
116
+ if (signal) {
117
+ signal.removeEventListener("abort", onAbort);
118
+ }
119
+ const diffResult = generateDiffString(baseContent, newContent);
120
+ resolve({
121
+ content: [
122
+ {
123
+ type: "text",
124
+ text: `Successfully replaced text in ${path}.`,
125
+ },
126
+ ],
127
+ details: { diff: diffResult.diff, firstChangedLine: diffResult.firstChangedLine },
128
+ });
129
+ }
130
+ catch (error) {
131
+ // Clean up abort handler
132
+ if (signal) {
133
+ signal.removeEventListener("abort", onAbort);
134
+ }
135
+ if (!aborted) {
136
+ reject(error);
137
+ }
138
+ }
139
+ })();
140
+ });
141
+ },
142
+ };
143
+ }
144
+ /** Default edit tool using process.cwd() - for backwards compatibility */
145
+ export const editTool = createEditTool(process.cwd());
146
+ //# sourceMappingURL=edit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/core/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\r\nimport { type Static, Type } from \"@sinclair/typebox\";\r\nimport { constants } from \"fs\";\r\nimport { access as fsAccess, readFile as fsReadFile, writeFile as fsWriteFile } from \"fs/promises\";\r\nimport {\r\n\tdetectLineEnding,\r\n\tfuzzyFindText,\r\n\tgenerateDiffString,\r\n\tnormalizeForFuzzyMatch,\r\n\tnormalizeToLF,\r\n\trestoreLineEndings,\r\n\tstripBom,\r\n} from \"./edit-diff.js\";\r\nimport { resolveToCwd } from \"./path-utils.js\";\r\n\r\nconst editSchema = Type.Object({\r\n\tpath: Type.String({ description: \"Path to the file to edit (relative or absolute)\" }),\r\n\toldText: Type.String({ description: \"Exact text to find and replace (must match exactly)\" }),\r\n\tnewText: Type.String({ description: \"New text to replace the old text with\" }),\r\n});\r\n\r\nexport type EditToolInput = Static<typeof editSchema>;\r\n\r\nexport interface EditToolDetails {\r\n\t/** Unified diff of the changes made */\r\n\tdiff: string;\r\n\t/** Line number of the first change in the new file (for editor navigation) */\r\n\tfirstChangedLine?: number;\r\n}\r\n\r\n/**\r\n * Pluggable operations for the edit tool.\r\n * Override these to delegate file editing to remote systems (e.g., SSH).\r\n */\r\nexport interface EditOperations {\r\n\t/** Read file contents as a Buffer */\r\n\treadFile: (absolutePath: string) => Promise<Buffer>;\r\n\t/** Write content to a file */\r\n\twriteFile: (absolutePath: string, content: string) => Promise<void>;\r\n\t/** Check if file is readable and writable (throw if not) */\r\n\taccess: (absolutePath: string) => Promise<void>;\r\n}\r\n\r\nconst defaultEditOperations: EditOperations = {\r\n\treadFile: (path) => fsReadFile(path),\r\n\twriteFile: (path, content) => fsWriteFile(path, content, \"utf-8\"),\r\n\taccess: (path) => fsAccess(path, constants.R_OK | constants.W_OK),\r\n};\r\n\r\nexport interface EditToolOptions {\r\n\t/** Custom operations for file editing. Default: local filesystem */\r\n\toperations?: EditOperations;\r\n}\r\n\r\nexport function createEditTool(cwd: string, options?: EditToolOptions): AgentTool<typeof editSchema> {\r\n\tconst ops = options?.operations ?? defaultEditOperations;\r\n\r\n\treturn {\r\n\t\tname: \"edit\",\r\n\t\tlabel: \"edit\",\r\n\t\tdescription:\r\n\t\t\t\"Edit a file by replacing exact text. The oldText must match exactly (including whitespace). Use this for precise, surgical edits.\",\r\n\t\tparameters: editSchema,\r\n\t\texecute: async (\r\n\t\t\t_toolCallId: string,\r\n\t\t\t{ path, oldText, newText }: { path: string; oldText: string; newText: string },\r\n\t\t\tsignal?: AbortSignal,\r\n\t\t) => {\r\n\t\t\tconst absolutePath = resolveToCwd(path, cwd);\r\n\r\n\t\t\treturn new Promise<{\r\n\t\t\t\tcontent: Array<{ type: \"text\"; text: string }>;\r\n\t\t\t\tdetails: EditToolDetails | undefined;\r\n\t\t\t}>((resolve, reject) => {\r\n\t\t\t\t// Check if already aborted\r\n\t\t\t\tif (signal?.aborted) {\r\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet aborted = false;\r\n\r\n\t\t\t\t// Set up abort handler\r\n\t\t\t\tconst onAbort = () => {\r\n\t\t\t\t\taborted = true;\r\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\r\n\t\t\t\t};\r\n\r\n\t\t\t\tif (signal) {\r\n\t\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Perform the edit operation\r\n\t\t\t\t(async () => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\t// Check if file exists\r\n\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\tawait ops.access(absolutePath);\r\n\t\t\t\t\t\t} catch {\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treject(new Error(`File not found: ${path}`));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Check if aborted before reading\r\n\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Read the file\r\n\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\r\n\t\t\t\t\t\tconst rawContent = buffer.toString(\"utf-8\");\r\n\r\n\t\t\t\t\t\t// Check if aborted after reading\r\n\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Strip BOM before matching (LLM won't include invisible BOM in oldText)\r\n\t\t\t\t\t\tconst { bom, text: content } = stripBom(rawContent);\r\n\r\n\t\t\t\t\t\tconst originalEnding = detectLineEnding(content);\r\n\t\t\t\t\t\tconst normalizedContent = normalizeToLF(content);\r\n\t\t\t\t\t\tconst normalizedOldText = normalizeToLF(oldText);\r\n\t\t\t\t\t\tconst normalizedNewText = normalizeToLF(newText);\r\n\r\n\t\t\t\t\t\t// Find the old text using fuzzy matching (tries exact match first, then fuzzy)\r\n\t\t\t\t\t\tconst matchResult = fuzzyFindText(normalizedContent, normalizedOldText);\r\n\r\n\t\t\t\t\t\tif (!matchResult.found) {\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treject(\r\n\t\t\t\t\t\t\t\tnew Error(\r\n\t\t\t\t\t\t\t\t\t`Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`,\r\n\t\t\t\t\t\t\t\t),\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Count occurrences using fuzzy-normalized content for consistency\r\n\t\t\t\t\t\tconst fuzzyContent = normalizeForFuzzyMatch(normalizedContent);\r\n\t\t\t\t\t\tconst fuzzyOldText = normalizeForFuzzyMatch(normalizedOldText);\r\n\t\t\t\t\t\tconst occurrences = fuzzyContent.split(fuzzyOldText).length - 1;\r\n\r\n\t\t\t\t\t\tif (occurrences > 1) {\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treject(\r\n\t\t\t\t\t\t\t\tnew Error(\r\n\t\t\t\t\t\t\t\t\t`Found ${occurrences} occurrences of the text in ${path}. The text must be unique. Please provide more context to make it unique.`,\r\n\t\t\t\t\t\t\t\t),\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Check if aborted before writing\r\n\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Perform replacement using the matched text position\r\n\t\t\t\t\t\t// When fuzzy matching was used, contentForReplacement is the normalized version\r\n\t\t\t\t\t\tconst baseContent = matchResult.contentForReplacement;\r\n\t\t\t\t\t\tconst newContent =\r\n\t\t\t\t\t\t\tbaseContent.substring(0, matchResult.index) +\r\n\t\t\t\t\t\t\tnormalizedNewText +\r\n\t\t\t\t\t\t\tbaseContent.substring(matchResult.index + matchResult.matchLength);\r\n\r\n\t\t\t\t\t\t// Verify the replacement actually changed something\r\n\t\t\t\t\t\tif (baseContent === newContent) {\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treject(\r\n\t\t\t\t\t\t\t\tnew Error(\r\n\t\t\t\t\t\t\t\t\t`No changes made to ${path}. The replacement produced identical content. This might indicate an issue with special characters or the text not existing as expected.`,\r\n\t\t\t\t\t\t\t\t),\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tconst finalContent = bom + restoreLineEndings(newContent, originalEnding);\r\n\t\t\t\t\t\tawait ops.writeFile(absolutePath, finalContent);\r\n\r\n\t\t\t\t\t\t// Check if aborted after writing\r\n\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Clean up abort handler\r\n\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tconst diffResult = generateDiffString(baseContent, newContent);\r\n\t\t\t\t\t\tresolve({\r\n\t\t\t\t\t\t\tcontent: [\r\n\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\ttype: \"text\",\r\n\t\t\t\t\t\t\t\t\ttext: `Successfully replaced text in ${path}.`,\r\n\t\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\t],\r\n\t\t\t\t\t\t\tdetails: { diff: diffResult.diff, firstChangedLine: diffResult.firstChangedLine },\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} catch (error: any) {\r\n\t\t\t\t\t\t// Clean up abort handler\r\n\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (!aborted) {\r\n\t\t\t\t\t\t\treject(error);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t})();\r\n\t\t\t});\r\n\t\t},\r\n\t};\r\n}\r\n\r\n/** Default edit tool using process.cwd() - for backwards compatibility */\r\nexport const editTool = createEditTool(process.cwd());\r\n"]}
@@ -0,0 +1,39 @@
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import { type Static } from "@sinclair/typebox";
3
+ import { type TruncationResult } from "./truncate.js";
4
+ declare const findSchema: import("@sinclair/typebox").TObject<{
5
+ pattern: import("@sinclair/typebox").TString;
6
+ path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
7
+ limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
8
+ }>;
9
+ export type FindToolInput = Static<typeof findSchema>;
10
+ export interface FindToolDetails {
11
+ truncation?: TruncationResult;
12
+ resultLimitReached?: number;
13
+ }
14
+ /**
15
+ * Pluggable operations for the find tool.
16
+ * Override these to delegate file search to remote systems (e.g., SSH).
17
+ */
18
+ export interface FindOperations {
19
+ /** Check if path exists */
20
+ exists: (absolutePath: string) => Promise<boolean> | boolean;
21
+ /** Find files matching glob pattern. Returns relative paths. */
22
+ glob: (pattern: string, cwd: string, options: {
23
+ ignore: string[];
24
+ limit: number;
25
+ }) => Promise<string[]> | string[];
26
+ }
27
+ export interface FindToolOptions {
28
+ /** Custom operations for find. Default: local filesystem + fd */
29
+ operations?: FindOperations;
30
+ }
31
+ export declare function createFindTool(cwd: string, options?: FindToolOptions): AgentTool<typeof findSchema>;
32
+ /** Default find tool using process.cwd() - for backwards compatibility */
33
+ export declare const findTool: AgentTool<import("@sinclair/typebox").TObject<{
34
+ pattern: import("@sinclair/typebox").TString;
35
+ path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
36
+ limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
37
+ }>, any>;
38
+ export {};
39
+ //# sourceMappingURL=find.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../../src/core/tools/find.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAOtD,OAAO,EAAiC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEnG,QAAA,MAAM,UAAU;;;;EAMd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAItD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,2BAA2B;IAC3B,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAC7D,gEAAgE;IAChE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;CACnH;AAUD,MAAM,WAAW,eAAe;IAC/B,iEAAiE;IACjE,UAAU,CAAC,EAAE,cAAc,CAAC;CAC5B;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CA0NnG;AAED,0EAA0E;AAC1E,eAAO,MAAM,QAAQ;;;;QAAgC,CAAC","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\r\nimport { type Static, Type } from \"@sinclair/typebox\";\r\nimport { spawnSync } from \"child_process\";\r\nimport { existsSync } from \"fs\";\r\nimport { globSync } from \"glob\";\r\nimport path from \"path\";\r\nimport { ensureTool } from \"../../utils/tools-manager.js\";\r\nimport { resolveToCwd } from \"./path-utils.js\";\r\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.js\";\r\n\r\nconst findSchema = Type.Object({\r\n\tpattern: Type.String({\r\n\t\tdescription: \"Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'\",\r\n\t}),\r\n\tpath: Type.Optional(Type.String({ description: \"Directory to search in (default: current directory)\" })),\r\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of results (default: 1000)\" })),\r\n});\r\n\r\nexport type FindToolInput = Static<typeof findSchema>;\r\n\r\nconst DEFAULT_LIMIT = 1000;\r\n\r\nexport interface FindToolDetails {\r\n\ttruncation?: TruncationResult;\r\n\tresultLimitReached?: number;\r\n}\r\n\r\n/**\r\n * Pluggable operations for the find tool.\r\n * Override these to delegate file search to remote systems (e.g., SSH).\r\n */\r\nexport interface FindOperations {\r\n\t/** Check if path exists */\r\n\texists: (absolutePath: string) => Promise<boolean> | boolean;\r\n\t/** Find files matching glob pattern. Returns relative paths. */\r\n\tglob: (pattern: string, cwd: string, options: { ignore: string[]; limit: number }) => Promise<string[]> | string[];\r\n}\r\n\r\nconst defaultFindOperations: FindOperations = {\r\n\texists: existsSync,\r\n\tglob: (_pattern, _searchCwd, _options) => {\r\n\t\t// This is a placeholder - actual fd execution happens in execute\r\n\t\treturn [];\r\n\t},\r\n};\r\n\r\nexport interface FindToolOptions {\r\n\t/** Custom operations for find. Default: local filesystem + fd */\r\n\toperations?: FindOperations;\r\n}\r\n\r\nexport function createFindTool(cwd: string, options?: FindToolOptions): AgentTool<typeof findSchema> {\r\n\tconst customOps = options?.operations;\r\n\r\n\treturn {\r\n\t\tname: \"find\",\r\n\t\tlabel: \"find\",\r\n\t\tdescription: `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 ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\r\n\t\tparameters: findSchema,\r\n\t\texecute: async (\r\n\t\t\t_toolCallId: string,\r\n\t\t\t{ pattern, path: searchDir, limit }: { pattern: string; path?: string; limit?: number },\r\n\t\t\tsignal?: AbortSignal,\r\n\t\t) => {\r\n\t\t\treturn new Promise((resolve, reject) => {\r\n\t\t\t\tif (signal?.aborted) {\r\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\r\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\r\n\r\n\t\t\t\t(async () => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\r\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\r\n\t\t\t\t\t\tconst ops = customOps ?? defaultFindOperations;\r\n\r\n\t\t\t\t\t\t// If custom operations provided with glob, use that\r\n\t\t\t\t\t\tif (customOps?.glob) {\r\n\t\t\t\t\t\t\tif (!(await ops.exists(searchPath))) {\r\n\t\t\t\t\t\t\t\treject(new Error(`Path not found: ${searchPath}`));\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tconst results = await ops.glob(pattern, searchPath, {\r\n\t\t\t\t\t\t\t\tignore: [\"**/node_modules/**\", \"**/.git/**\"],\r\n\t\t\t\t\t\t\t\tlimit: effectiveLimit,\r\n\t\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\r\n\r\n\t\t\t\t\t\t\tif (results.length === 0) {\r\n\t\t\t\t\t\t\t\tresolve({\r\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No files found matching pattern\" }],\r\n\t\t\t\t\t\t\t\t\tdetails: undefined,\r\n\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t// Relativize paths\r\n\t\t\t\t\t\t\tconst relativized = results.map((p) => {\r\n\t\t\t\t\t\t\t\tif (p.startsWith(searchPath)) {\r\n\t\t\t\t\t\t\t\t\treturn p.slice(searchPath.length + 1);\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\treturn path.relative(searchPath, p);\r\n\t\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\t\tconst resultLimitReached = relativized.length >= effectiveLimit;\r\n\t\t\t\t\t\t\tconst rawOutput = relativized.join(\"\\n\");\r\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\r\n\r\n\t\t\t\t\t\t\tlet resultOutput = truncation.content;\r\n\t\t\t\t\t\t\tconst details: FindToolDetails = {};\r\n\t\t\t\t\t\t\tconst notices: string[] = [];\r\n\r\n\t\t\t\t\t\t\tif (resultLimitReached) {\r\n\t\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} results limit reached`);\r\n\t\t\t\t\t\t\t\tdetails.resultLimitReached = effectiveLimit;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (truncation.truncated) {\r\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\r\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (notices.length > 0) {\r\n\t\t\t\t\t\t\t\tresultOutput += `\\n\\n[${notices.join(\". \")}]`;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tresolve({\r\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: resultOutput }],\r\n\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Default: use fd\r\n\t\t\t\t\t\tconst fdPath = await ensureTool(\"fd\", true);\r\n\t\t\t\t\t\tif (!fdPath) {\r\n\t\t\t\t\t\t\treject(new Error(\"fd is not available and could not be downloaded\"));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Build fd arguments\r\n\t\t\t\t\t\tconst args: string[] = [\r\n\t\t\t\t\t\t\t\"--glob\",\r\n\t\t\t\t\t\t\t\"--color=never\",\r\n\t\t\t\t\t\t\t\"--hidden\",\r\n\t\t\t\t\t\t\t\"--max-results\",\r\n\t\t\t\t\t\t\tString(effectiveLimit),\r\n\t\t\t\t\t\t];\r\n\r\n\t\t\t\t\t\t// Include .gitignore files\r\n\t\t\t\t\t\tconst gitignoreFiles = new Set<string>();\r\n\t\t\t\t\t\tconst rootGitignore = path.join(searchPath, \".gitignore\");\r\n\t\t\t\t\t\tif (existsSync(rootGitignore)) {\r\n\t\t\t\t\t\t\tgitignoreFiles.add(rootGitignore);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\tconst nestedGitignores = globSync(\"**/.gitignore\", {\r\n\t\t\t\t\t\t\t\tcwd: searchPath,\r\n\t\t\t\t\t\t\t\tdot: true,\r\n\t\t\t\t\t\t\t\tabsolute: true,\r\n\t\t\t\t\t\t\t\tignore: [\"**/node_modules/**\", \"**/.git/**\"],\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\tfor (const file of nestedGitignores) {\r\n\t\t\t\t\t\t\t\tgitignoreFiles.add(file);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} catch {\r\n\t\t\t\t\t\t\t// Ignore glob errors\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tfor (const gitignorePath of gitignoreFiles) {\r\n\t\t\t\t\t\t\targs.push(\"--ignore-file\", gitignorePath);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\targs.push(pattern, searchPath);\r\n\r\n\t\t\t\t\t\tconst result = spawnSync(fdPath, args, {\r\n\t\t\t\t\t\t\tencoding: \"utf-8\",\r\n\t\t\t\t\t\t\tmaxBuffer: 10 * 1024 * 1024,\r\n\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\r\n\r\n\t\t\t\t\t\tif (result.error) {\r\n\t\t\t\t\t\t\treject(new Error(`Failed to run fd: ${result.error.message}`));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tconst output = result.stdout?.trim() || \"\";\r\n\r\n\t\t\t\t\t\tif (result.status !== 0) {\r\n\t\t\t\t\t\t\tconst errorMsg = result.stderr?.trim() || `fd exited with code ${result.status}`;\r\n\t\t\t\t\t\t\tif (!output) {\r\n\t\t\t\t\t\t\t\treject(new Error(errorMsg));\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (!output) {\r\n\t\t\t\t\t\t\tresolve({\r\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No files found matching pattern\" }],\r\n\t\t\t\t\t\t\t\tdetails: undefined,\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tconst lines = output.split(\"\\n\");\r\n\t\t\t\t\t\tconst relativized: string[] = [];\r\n\r\n\t\t\t\t\t\tfor (const rawLine of lines) {\r\n\t\t\t\t\t\t\tconst line = rawLine.replace(/\\r$/, \"\").trim();\r\n\t\t\t\t\t\t\tif (!line) continue;\r\n\r\n\t\t\t\t\t\t\tconst hadTrailingSlash = line.endsWith(\"/\") || line.endsWith(\"\\\\\");\r\n\t\t\t\t\t\t\tlet relativePath = line;\r\n\t\t\t\t\t\t\tif (line.startsWith(searchPath)) {\r\n\t\t\t\t\t\t\t\trelativePath = line.slice(searchPath.length + 1);\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\trelativePath = path.relative(searchPath, line);\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (hadTrailingSlash && !relativePath.endsWith(\"/\")) {\r\n\t\t\t\t\t\t\t\trelativePath += \"/\";\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\trelativized.push(relativePath);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tconst resultLimitReached = relativized.length >= effectiveLimit;\r\n\t\t\t\t\t\tconst rawOutput = relativized.join(\"\\n\");\r\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\r\n\r\n\t\t\t\t\t\tlet resultOutput = truncation.content;\r\n\t\t\t\t\t\tconst details: FindToolDetails = {};\r\n\t\t\t\t\t\tconst notices: string[] = [];\r\n\r\n\t\t\t\t\t\tif (resultLimitReached) {\r\n\t\t\t\t\t\t\tnotices.push(\r\n\t\t\t\t\t\t\t\t`${effectiveLimit} results limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t\tdetails.resultLimitReached = effectiveLimit;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (truncation.truncated) {\r\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\r\n\t\t\t\t\t\t\tdetails.truncation = truncation;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (notices.length > 0) {\r\n\t\t\t\t\t\t\tresultOutput += `\\n\\n[${notices.join(\". \")}]`;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tresolve({\r\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: resultOutput }],\r\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} catch (e: any) {\r\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\treject(e);\r\n\t\t\t\t\t}\r\n\t\t\t\t})();\r\n\t\t\t});\r\n\t\t},\r\n\t};\r\n}\r\n\r\n/** Default find tool using process.cwd() - for backwards compatibility */\r\nexport const findTool = createFindTool(process.cwd());\r\n"]}
@@ -0,0 +1,206 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { spawnSync } from "child_process";
3
+ import { existsSync } from "fs";
4
+ import { globSync } from "glob";
5
+ import path from "path";
6
+ import { ensureTool } from "../../utils/tools-manager.js";
7
+ import { resolveToCwd } from "./path-utils.js";
8
+ import { DEFAULT_MAX_BYTES, formatSize, truncateHead } from "./truncate.js";
9
+ const findSchema = Type.Object({
10
+ pattern: Type.String({
11
+ description: "Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'",
12
+ }),
13
+ path: Type.Optional(Type.String({ description: "Directory to search in (default: current directory)" })),
14
+ limit: Type.Optional(Type.Number({ description: "Maximum number of results (default: 1000)" })),
15
+ });
16
+ const DEFAULT_LIMIT = 1000;
17
+ const defaultFindOperations = {
18
+ exists: existsSync,
19
+ glob: (_pattern, _searchCwd, _options) => {
20
+ // This is a placeholder - actual fd execution happens in execute
21
+ return [];
22
+ },
23
+ };
24
+ export function createFindTool(cwd, options) {
25
+ const customOps = options?.operations;
26
+ return {
27
+ name: "find",
28
+ label: "find",
29
+ 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 ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,
30
+ parameters: findSchema,
31
+ execute: async (_toolCallId, { pattern, path: searchDir, limit }, signal) => {
32
+ return new Promise((resolve, reject) => {
33
+ if (signal?.aborted) {
34
+ reject(new Error("Operation aborted"));
35
+ return;
36
+ }
37
+ const onAbort = () => reject(new Error("Operation aborted"));
38
+ signal?.addEventListener("abort", onAbort, { once: true });
39
+ (async () => {
40
+ try {
41
+ const searchPath = resolveToCwd(searchDir || ".", cwd);
42
+ const effectiveLimit = limit ?? DEFAULT_LIMIT;
43
+ const ops = customOps ?? defaultFindOperations;
44
+ // If custom operations provided with glob, use that
45
+ if (customOps?.glob) {
46
+ if (!(await ops.exists(searchPath))) {
47
+ reject(new Error(`Path not found: ${searchPath}`));
48
+ return;
49
+ }
50
+ const results = await ops.glob(pattern, searchPath, {
51
+ ignore: ["**/node_modules/**", "**/.git/**"],
52
+ limit: effectiveLimit,
53
+ });
54
+ signal?.removeEventListener("abort", onAbort);
55
+ if (results.length === 0) {
56
+ resolve({
57
+ content: [{ type: "text", text: "No files found matching pattern" }],
58
+ details: undefined,
59
+ });
60
+ return;
61
+ }
62
+ // Relativize paths
63
+ const relativized = results.map((p) => {
64
+ if (p.startsWith(searchPath)) {
65
+ return p.slice(searchPath.length + 1);
66
+ }
67
+ return path.relative(searchPath, p);
68
+ });
69
+ const resultLimitReached = relativized.length >= effectiveLimit;
70
+ const rawOutput = relativized.join("\n");
71
+ const truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });
72
+ let resultOutput = truncation.content;
73
+ const details = {};
74
+ const notices = [];
75
+ if (resultLimitReached) {
76
+ notices.push(`${effectiveLimit} results limit reached`);
77
+ details.resultLimitReached = effectiveLimit;
78
+ }
79
+ if (truncation.truncated) {
80
+ notices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);
81
+ details.truncation = truncation;
82
+ }
83
+ if (notices.length > 0) {
84
+ resultOutput += `\n\n[${notices.join(". ")}]`;
85
+ }
86
+ resolve({
87
+ content: [{ type: "text", text: resultOutput }],
88
+ details: Object.keys(details).length > 0 ? details : undefined,
89
+ });
90
+ return;
91
+ }
92
+ // Default: use fd
93
+ const fdPath = await ensureTool("fd", true);
94
+ if (!fdPath) {
95
+ reject(new Error("fd is not available and could not be downloaded"));
96
+ return;
97
+ }
98
+ // Build fd arguments
99
+ const args = [
100
+ "--glob",
101
+ "--color=never",
102
+ "--hidden",
103
+ "--max-results",
104
+ String(effectiveLimit),
105
+ ];
106
+ // Include .gitignore files
107
+ const gitignoreFiles = new Set();
108
+ const rootGitignore = path.join(searchPath, ".gitignore");
109
+ if (existsSync(rootGitignore)) {
110
+ gitignoreFiles.add(rootGitignore);
111
+ }
112
+ try {
113
+ const nestedGitignores = globSync("**/.gitignore", {
114
+ cwd: searchPath,
115
+ dot: true,
116
+ absolute: true,
117
+ ignore: ["**/node_modules/**", "**/.git/**"],
118
+ });
119
+ for (const file of nestedGitignores) {
120
+ gitignoreFiles.add(file);
121
+ }
122
+ }
123
+ catch {
124
+ // Ignore glob errors
125
+ }
126
+ for (const gitignorePath of gitignoreFiles) {
127
+ args.push("--ignore-file", gitignorePath);
128
+ }
129
+ args.push(pattern, searchPath);
130
+ const result = spawnSync(fdPath, args, {
131
+ encoding: "utf-8",
132
+ maxBuffer: 10 * 1024 * 1024,
133
+ });
134
+ signal?.removeEventListener("abort", onAbort);
135
+ if (result.error) {
136
+ reject(new Error(`Failed to run fd: ${result.error.message}`));
137
+ return;
138
+ }
139
+ const output = result.stdout?.trim() || "";
140
+ if (result.status !== 0) {
141
+ const errorMsg = result.stderr?.trim() || `fd exited with code ${result.status}`;
142
+ if (!output) {
143
+ reject(new Error(errorMsg));
144
+ return;
145
+ }
146
+ }
147
+ if (!output) {
148
+ resolve({
149
+ content: [{ type: "text", text: "No files found matching pattern" }],
150
+ details: undefined,
151
+ });
152
+ return;
153
+ }
154
+ const lines = output.split("\n");
155
+ const relativized = [];
156
+ for (const rawLine of lines) {
157
+ const line = rawLine.replace(/\r$/, "").trim();
158
+ if (!line)
159
+ continue;
160
+ const hadTrailingSlash = line.endsWith("/") || line.endsWith("\\");
161
+ let relativePath = line;
162
+ if (line.startsWith(searchPath)) {
163
+ relativePath = line.slice(searchPath.length + 1);
164
+ }
165
+ else {
166
+ relativePath = path.relative(searchPath, line);
167
+ }
168
+ if (hadTrailingSlash && !relativePath.endsWith("/")) {
169
+ relativePath += "/";
170
+ }
171
+ relativized.push(relativePath);
172
+ }
173
+ const resultLimitReached = relativized.length >= effectiveLimit;
174
+ const rawOutput = relativized.join("\n");
175
+ const truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });
176
+ let resultOutput = truncation.content;
177
+ const details = {};
178
+ const notices = [];
179
+ if (resultLimitReached) {
180
+ notices.push(`${effectiveLimit} results limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`);
181
+ details.resultLimitReached = effectiveLimit;
182
+ }
183
+ if (truncation.truncated) {
184
+ notices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);
185
+ details.truncation = truncation;
186
+ }
187
+ if (notices.length > 0) {
188
+ resultOutput += `\n\n[${notices.join(". ")}]`;
189
+ }
190
+ resolve({
191
+ content: [{ type: "text", text: resultOutput }],
192
+ details: Object.keys(details).length > 0 ? details : undefined,
193
+ });
194
+ }
195
+ catch (e) {
196
+ signal?.removeEventListener("abort", onAbort);
197
+ reject(e);
198
+ }
199
+ })();
200
+ });
201
+ },
202
+ };
203
+ }
204
+ /** Default find tool using process.cwd() - for backwards compatibility */
205
+ export const findTool = createFindTool(process.cwd());
206
+ //# sourceMappingURL=find.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find.js","sourceRoot":"","sources":["../../../src/core/tools/find.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\r\nimport { type Static, Type } from \"@sinclair/typebox\";\r\nimport { spawnSync } from \"child_process\";\r\nimport { existsSync } from \"fs\";\r\nimport { globSync } from \"glob\";\r\nimport path from \"path\";\r\nimport { ensureTool } from \"../../utils/tools-manager.js\";\r\nimport { resolveToCwd } from \"./path-utils.js\";\r\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.js\";\r\n\r\nconst findSchema = Type.Object({\r\n\tpattern: Type.String({\r\n\t\tdescription: \"Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'\",\r\n\t}),\r\n\tpath: Type.Optional(Type.String({ description: \"Directory to search in (default: current directory)\" })),\r\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of results (default: 1000)\" })),\r\n});\r\n\r\nexport type FindToolInput = Static<typeof findSchema>;\r\n\r\nconst DEFAULT_LIMIT = 1000;\r\n\r\nexport interface FindToolDetails {\r\n\ttruncation?: TruncationResult;\r\n\tresultLimitReached?: number;\r\n}\r\n\r\n/**\r\n * Pluggable operations for the find tool.\r\n * Override these to delegate file search to remote systems (e.g., SSH).\r\n */\r\nexport interface FindOperations {\r\n\t/** Check if path exists */\r\n\texists: (absolutePath: string) => Promise<boolean> | boolean;\r\n\t/** Find files matching glob pattern. Returns relative paths. */\r\n\tglob: (pattern: string, cwd: string, options: { ignore: string[]; limit: number }) => Promise<string[]> | string[];\r\n}\r\n\r\nconst defaultFindOperations: FindOperations = {\r\n\texists: existsSync,\r\n\tglob: (_pattern, _searchCwd, _options) => {\r\n\t\t// This is a placeholder - actual fd execution happens in execute\r\n\t\treturn [];\r\n\t},\r\n};\r\n\r\nexport interface FindToolOptions {\r\n\t/** Custom operations for find. Default: local filesystem + fd */\r\n\toperations?: FindOperations;\r\n}\r\n\r\nexport function createFindTool(cwd: string, options?: FindToolOptions): AgentTool<typeof findSchema> {\r\n\tconst customOps = options?.operations;\r\n\r\n\treturn {\r\n\t\tname: \"find\",\r\n\t\tlabel: \"find\",\r\n\t\tdescription: `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 ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\r\n\t\tparameters: findSchema,\r\n\t\texecute: async (\r\n\t\t\t_toolCallId: string,\r\n\t\t\t{ pattern, path: searchDir, limit }: { pattern: string; path?: string; limit?: number },\r\n\t\t\tsignal?: AbortSignal,\r\n\t\t) => {\r\n\t\t\treturn new Promise((resolve, reject) => {\r\n\t\t\t\tif (signal?.aborted) {\r\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\r\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\r\n\r\n\t\t\t\t(async () => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\r\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\r\n\t\t\t\t\t\tconst ops = customOps ?? defaultFindOperations;\r\n\r\n\t\t\t\t\t\t// If custom operations provided with glob, use that\r\n\t\t\t\t\t\tif (customOps?.glob) {\r\n\t\t\t\t\t\t\tif (!(await ops.exists(searchPath))) {\r\n\t\t\t\t\t\t\t\treject(new Error(`Path not found: ${searchPath}`));\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tconst results = await ops.glob(pattern, searchPath, {\r\n\t\t\t\t\t\t\t\tignore: [\"**/node_modules/**\", \"**/.git/**\"],\r\n\t\t\t\t\t\t\t\tlimit: effectiveLimit,\r\n\t\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\r\n\r\n\t\t\t\t\t\t\tif (results.length === 0) {\r\n\t\t\t\t\t\t\t\tresolve({\r\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No files found matching pattern\" }],\r\n\t\t\t\t\t\t\t\t\tdetails: undefined,\r\n\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t// Relativize paths\r\n\t\t\t\t\t\t\tconst relativized = results.map((p) => {\r\n\t\t\t\t\t\t\t\tif (p.startsWith(searchPath)) {\r\n\t\t\t\t\t\t\t\t\treturn p.slice(searchPath.length + 1);\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\treturn path.relative(searchPath, p);\r\n\t\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\t\tconst resultLimitReached = relativized.length >= effectiveLimit;\r\n\t\t\t\t\t\t\tconst rawOutput = relativized.join(\"\\n\");\r\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\r\n\r\n\t\t\t\t\t\t\tlet resultOutput = truncation.content;\r\n\t\t\t\t\t\t\tconst details: FindToolDetails = {};\r\n\t\t\t\t\t\t\tconst notices: string[] = [];\r\n\r\n\t\t\t\t\t\t\tif (resultLimitReached) {\r\n\t\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} results limit reached`);\r\n\t\t\t\t\t\t\t\tdetails.resultLimitReached = effectiveLimit;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (truncation.truncated) {\r\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\r\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (notices.length > 0) {\r\n\t\t\t\t\t\t\t\tresultOutput += `\\n\\n[${notices.join(\". \")}]`;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tresolve({\r\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: resultOutput }],\r\n\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Default: use fd\r\n\t\t\t\t\t\tconst fdPath = await ensureTool(\"fd\", true);\r\n\t\t\t\t\t\tif (!fdPath) {\r\n\t\t\t\t\t\t\treject(new Error(\"fd is not available and could not be downloaded\"));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// Build fd arguments\r\n\t\t\t\t\t\tconst args: string[] = [\r\n\t\t\t\t\t\t\t\"--glob\",\r\n\t\t\t\t\t\t\t\"--color=never\",\r\n\t\t\t\t\t\t\t\"--hidden\",\r\n\t\t\t\t\t\t\t\"--max-results\",\r\n\t\t\t\t\t\t\tString(effectiveLimit),\r\n\t\t\t\t\t\t];\r\n\r\n\t\t\t\t\t\t// Include .gitignore files\r\n\t\t\t\t\t\tconst gitignoreFiles = new Set<string>();\r\n\t\t\t\t\t\tconst rootGitignore = path.join(searchPath, \".gitignore\");\r\n\t\t\t\t\t\tif (existsSync(rootGitignore)) {\r\n\t\t\t\t\t\t\tgitignoreFiles.add(rootGitignore);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\tconst nestedGitignores = globSync(\"**/.gitignore\", {\r\n\t\t\t\t\t\t\t\tcwd: searchPath,\r\n\t\t\t\t\t\t\t\tdot: true,\r\n\t\t\t\t\t\t\t\tabsolute: true,\r\n\t\t\t\t\t\t\t\tignore: [\"**/node_modules/**\", \"**/.git/**\"],\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\tfor (const file of nestedGitignores) {\r\n\t\t\t\t\t\t\t\tgitignoreFiles.add(file);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} catch {\r\n\t\t\t\t\t\t\t// Ignore glob errors\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tfor (const gitignorePath of gitignoreFiles) {\r\n\t\t\t\t\t\t\targs.push(\"--ignore-file\", gitignorePath);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\targs.push(pattern, searchPath);\r\n\r\n\t\t\t\t\t\tconst result = spawnSync(fdPath, args, {\r\n\t\t\t\t\t\t\tencoding: \"utf-8\",\r\n\t\t\t\t\t\t\tmaxBuffer: 10 * 1024 * 1024,\r\n\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\r\n\r\n\t\t\t\t\t\tif (result.error) {\r\n\t\t\t\t\t\t\treject(new Error(`Failed to run fd: ${result.error.message}`));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tconst output = result.stdout?.trim() || \"\";\r\n\r\n\t\t\t\t\t\tif (result.status !== 0) {\r\n\t\t\t\t\t\t\tconst errorMsg = result.stderr?.trim() || `fd exited with code ${result.status}`;\r\n\t\t\t\t\t\t\tif (!output) {\r\n\t\t\t\t\t\t\t\treject(new Error(errorMsg));\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (!output) {\r\n\t\t\t\t\t\t\tresolve({\r\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No files found matching pattern\" }],\r\n\t\t\t\t\t\t\t\tdetails: undefined,\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tconst lines = output.split(\"\\n\");\r\n\t\t\t\t\t\tconst relativized: string[] = [];\r\n\r\n\t\t\t\t\t\tfor (const rawLine of lines) {\r\n\t\t\t\t\t\t\tconst line = rawLine.replace(/\\r$/, \"\").trim();\r\n\t\t\t\t\t\t\tif (!line) continue;\r\n\r\n\t\t\t\t\t\t\tconst hadTrailingSlash = line.endsWith(\"/\") || line.endsWith(\"\\\\\");\r\n\t\t\t\t\t\t\tlet relativePath = line;\r\n\t\t\t\t\t\t\tif (line.startsWith(searchPath)) {\r\n\t\t\t\t\t\t\t\trelativePath = line.slice(searchPath.length + 1);\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\trelativePath = path.relative(searchPath, line);\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (hadTrailingSlash && !relativePath.endsWith(\"/\")) {\r\n\t\t\t\t\t\t\t\trelativePath += \"/\";\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\trelativized.push(relativePath);\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tconst resultLimitReached = relativized.length >= effectiveLimit;\r\n\t\t\t\t\t\tconst rawOutput = relativized.join(\"\\n\");\r\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\r\n\r\n\t\t\t\t\t\tlet resultOutput = truncation.content;\r\n\t\t\t\t\t\tconst details: FindToolDetails = {};\r\n\t\t\t\t\t\tconst notices: string[] = [];\r\n\r\n\t\t\t\t\t\tif (resultLimitReached) {\r\n\t\t\t\t\t\t\tnotices.push(\r\n\t\t\t\t\t\t\t\t`${effectiveLimit} results limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\r\n\t\t\t\t\t\t\t);\r\n\t\t\t\t\t\t\tdetails.resultLimitReached = effectiveLimit;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (truncation.truncated) {\r\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\r\n\t\t\t\t\t\t\tdetails.truncation = truncation;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (notices.length > 0) {\r\n\t\t\t\t\t\t\tresultOutput += `\\n\\n[${notices.join(\". \")}]`;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tresolve({\r\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: resultOutput }],\r\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t} catch (e: any) {\r\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\treject(e);\r\n\t\t\t\t\t}\r\n\t\t\t\t})();\r\n\t\t\t});\r\n\t\t},\r\n\t};\r\n}\r\n\r\n/** Default find tool using process.cwd() - for backwards compatibility */\r\nexport const findTool = createFindTool(process.cwd());\r\n"]}