@caupulican/pi-adaptative 0.80.103 → 0.81.0

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 (401) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/dist/cli/session-picker.d.ts +1 -1
  3. package/dist/cli/session-picker.d.ts.map +1 -1
  4. package/dist/cli/session-picker.js.map +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +7 -1
  7. package/dist/cli.js.map +1 -1
  8. package/dist/core/agent-session-runtime.d.ts +1 -1
  9. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  10. package/dist/core/agent-session-runtime.js +6 -6
  11. package/dist/core/agent-session-runtime.js.map +1 -1
  12. package/dist/core/agent-session-services.d.ts +1 -1
  13. package/dist/core/agent-session-services.d.ts.map +1 -1
  14. package/dist/core/agent-session-services.js.map +1 -1
  15. package/dist/core/agent-session.d.ts +152 -512
  16. package/dist/core/agent-session.d.ts.map +1 -1
  17. package/dist/core/agent-session.js +635 -4590
  18. package/dist/core/agent-session.js.map +1 -1
  19. package/dist/core/autonomy/session-lane-record.d.ts +1 -1
  20. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
  21. package/dist/core/autonomy/session-lane-record.js.map +1 -1
  22. package/dist/core/autonomy/status.d.ts +1 -0
  23. package/dist/core/autonomy/status.d.ts.map +1 -1
  24. package/dist/core/autonomy/status.js +1 -0
  25. package/dist/core/autonomy/status.js.map +1 -1
  26. package/dist/core/autonomy-telemetry.d.ts +80 -0
  27. package/dist/core/autonomy-telemetry.d.ts.map +1 -0
  28. package/dist/core/autonomy-telemetry.js +266 -0
  29. package/dist/core/autonomy-telemetry.js.map +1 -0
  30. package/dist/core/background-lane-controller.d.ts +186 -0
  31. package/dist/core/background-lane-controller.d.ts.map +1 -0
  32. package/dist/core/background-lane-controller.js +691 -0
  33. package/dist/core/background-lane-controller.js.map +1 -0
  34. package/dist/core/bash-execution-controller.d.ts +51 -0
  35. package/dist/core/bash-execution-controller.d.ts.map +1 -0
  36. package/dist/core/bash-execution-controller.js +96 -0
  37. package/dist/core/bash-execution-controller.js.map +1 -0
  38. package/dist/core/bash-executor.d.ts.map +1 -1
  39. package/dist/core/bash-executor.js +9 -2
  40. package/dist/core/bash-executor.js.map +1 -1
  41. package/dist/core/compaction-support.d.ts +56 -0
  42. package/dist/core/compaction-support.d.ts.map +1 -0
  43. package/dist/core/compaction-support.js +99 -0
  44. package/dist/core/compaction-support.js.map +1 -0
  45. package/dist/core/context/artifact-retrieval.d.ts +1 -1
  46. package/dist/core/context/artifact-retrieval.d.ts.map +1 -1
  47. package/dist/core/context/artifact-retrieval.js +1 -1
  48. package/dist/core/context/artifact-retrieval.js.map +1 -1
  49. package/dist/core/context/context-composition.d.ts.map +1 -1
  50. package/dist/core/context/context-composition.js +1 -1
  51. package/dist/core/context/context-composition.js.map +1 -1
  52. package/dist/core/context/tool-output-packer.d.ts +1 -1
  53. package/dist/core/context/tool-output-packer.d.ts.map +1 -1
  54. package/dist/core/context/tool-output-packer.js +1 -1
  55. package/dist/core/context/tool-output-packer.js.map +1 -1
  56. package/dist/core/context-gc.d.ts.map +1 -1
  57. package/dist/core/context-gc.js +1 -1
  58. package/dist/core/context-gc.js.map +1 -1
  59. package/dist/core/context-pipeline.d.ts +223 -0
  60. package/dist/core/context-pipeline.d.ts.map +1 -0
  61. package/dist/core/context-pipeline.js +594 -0
  62. package/dist/core/context-pipeline.js.map +1 -0
  63. package/dist/core/cost/daily-usage.d.ts +1 -1
  64. package/dist/core/cost/daily-usage.d.ts.map +1 -1
  65. package/dist/core/cost/daily-usage.js +1 -1
  66. package/dist/core/cost/daily-usage.js.map +1 -1
  67. package/dist/core/cost/session-usage.d.ts +1 -1
  68. package/dist/core/cost/session-usage.d.ts.map +1 -1
  69. package/dist/core/cost/session-usage.js +1 -1
  70. package/dist/core/cost/session-usage.js.map +1 -1
  71. package/dist/core/delegation/session-worker-result.d.ts +1 -1
  72. package/dist/core/delegation/session-worker-result.d.ts.map +1 -1
  73. package/dist/core/delegation/session-worker-result.js.map +1 -1
  74. package/dist/core/exec.d.ts +2 -0
  75. package/dist/core/exec.d.ts.map +1 -1
  76. package/dist/core/exec.js +15 -9
  77. package/dist/core/exec.js.map +1 -1
  78. package/dist/core/export-html/index.d.ts +1 -1
  79. package/dist/core/export-html/index.d.ts.map +1 -1
  80. package/dist/core/export-html/index.js +2 -2
  81. package/dist/core/export-html/index.js.map +1 -1
  82. package/dist/core/extensions/builtin.d.ts.map +1 -1
  83. package/dist/core/extensions/builtin.js +2 -2
  84. package/dist/core/extensions/builtin.js.map +1 -1
  85. package/dist/core/extensions/runner.d.ts +1 -1
  86. package/dist/core/extensions/runner.d.ts.map +1 -1
  87. package/dist/core/extensions/runner.js.map +1 -1
  88. package/dist/core/extensions/types.d.ts +2 -4
  89. package/dist/core/extensions/types.d.ts.map +1 -1
  90. package/dist/core/extensions/types.js.map +1 -1
  91. package/dist/core/goal-loop-controller.d.ts +24 -0
  92. package/dist/core/goal-loop-controller.d.ts.map +1 -0
  93. package/dist/core/goal-loop-controller.js +83 -0
  94. package/dist/core/goal-loop-controller.js.map +1 -0
  95. package/dist/core/goals/goal-runtime-snapshot.d.ts +1 -1
  96. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  97. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  98. package/dist/core/goals/session-goal-state.d.ts +1 -1
  99. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  100. package/dist/core/goals/session-goal-state.js.map +1 -1
  101. package/dist/core/index.d.ts +1 -1
  102. package/dist/core/index.d.ts.map +1 -1
  103. package/dist/core/index.js.map +1 -1
  104. package/dist/core/learning/learning-audit.d.ts +1 -1
  105. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  106. package/dist/core/learning/learning-audit.js.map +1 -1
  107. package/dist/core/learning/session-learning-decision.d.ts +1 -1
  108. package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
  109. package/dist/core/learning/session-learning-decision.js.map +1 -1
  110. package/dist/core/local-runtime-controller.d.ts +99 -0
  111. package/dist/core/local-runtime-controller.d.ts.map +1 -0
  112. package/dist/core/local-runtime-controller.js +214 -0
  113. package/dist/core/local-runtime-controller.js.map +1 -0
  114. package/dist/core/memory/providers/transcript-recall.d.ts.map +1 -1
  115. package/dist/core/memory/providers/transcript-recall.js +1 -1
  116. package/dist/core/memory/providers/transcript-recall.js.map +1 -1
  117. package/dist/core/memory-controller.d.ts +139 -0
  118. package/dist/core/memory-controller.d.ts.map +1 -0
  119. package/dist/core/memory-controller.js +323 -0
  120. package/dist/core/memory-controller.js.map +1 -0
  121. package/dist/core/model-router/status.d.ts +1 -1
  122. package/dist/core/model-router/status.d.ts.map +1 -1
  123. package/dist/core/model-router/status.js.map +1 -1
  124. package/dist/core/model-router-controller.d.ts +140 -0
  125. package/dist/core/model-router-controller.d.ts.map +1 -0
  126. package/dist/core/model-router-controller.js +623 -0
  127. package/dist/core/model-router-controller.js.map +1 -0
  128. package/dist/core/model-selection-controller.d.ts +95 -0
  129. package/dist/core/model-selection-controller.d.ts.map +1 -0
  130. package/dist/core/model-selection-controller.js +252 -0
  131. package/dist/core/model-selection-controller.js.map +1 -0
  132. package/dist/core/models/model-ref.d.ts +13 -0
  133. package/dist/core/models/model-ref.d.ts.map +1 -1
  134. package/dist/core/models/model-ref.js +22 -0
  135. package/dist/core/models/model-ref.js.map +1 -1
  136. package/dist/core/profile-filter-controller.d.ts +77 -0
  137. package/dist/core/profile-filter-controller.d.ts.map +1 -0
  138. package/dist/core/profile-filter-controller.js +159 -0
  139. package/dist/core/profile-filter-controller.js.map +1 -0
  140. package/dist/core/reflection-controller.d.ts +111 -0
  141. package/dist/core/reflection-controller.d.ts.map +1 -0
  142. package/dist/core/reflection-controller.js +412 -0
  143. package/dist/core/reflection-controller.js.map +1 -0
  144. package/dist/core/research/model-fitness.d.ts +12 -0
  145. package/dist/core/research/model-fitness.d.ts.map +1 -1
  146. package/dist/core/research/model-fitness.js +21 -0
  147. package/dist/core/research/model-fitness.js.map +1 -1
  148. package/dist/core/research/session-evidence-bundle.d.ts +1 -1
  149. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
  150. package/dist/core/research/session-evidence-bundle.js.map +1 -1
  151. package/dist/core/runtime-builder.d.ts +222 -0
  152. package/dist/core/runtime-builder.d.ts.map +1 -0
  153. package/dist/core/runtime-builder.js +640 -0
  154. package/dist/core/runtime-builder.js.map +1 -0
  155. package/dist/core/sdk.d.ts +2 -2
  156. package/dist/core/sdk.d.ts.map +1 -1
  157. package/dist/core/sdk.js +3 -4
  158. package/dist/core/sdk.js.map +1 -1
  159. package/dist/core/session-analytics.d.ts +96 -0
  160. package/dist/core/session-analytics.d.ts.map +1 -0
  161. package/dist/core/session-analytics.js +331 -0
  162. package/dist/core/session-analytics.js.map +1 -0
  163. package/dist/core/session-manager-factory.d.ts +18 -0
  164. package/dist/core/session-manager-factory.d.ts.map +1 -0
  165. package/dist/core/session-manager-factory.js +32 -0
  166. package/dist/core/session-manager-factory.js.map +1 -0
  167. package/dist/core/session-tree-navigator.d.ts +68 -0
  168. package/dist/core/session-tree-navigator.d.ts.map +1 -0
  169. package/dist/core/session-tree-navigator.js +217 -0
  170. package/dist/core/session-tree-navigator.js.map +1 -0
  171. package/dist/core/system-prompt-builder.d.ts +63 -0
  172. package/dist/core/system-prompt-builder.d.ts.map +1 -0
  173. package/dist/core/system-prompt-builder.js +181 -0
  174. package/dist/core/system-prompt-builder.js.map +1 -0
  175. package/dist/core/tool-gate-controller.d.ts +36 -0
  176. package/dist/core/tool-gate-controller.d.ts.map +1 -0
  177. package/dist/core/tool-gate-controller.js +94 -0
  178. package/dist/core/tool-gate-controller.js.map +1 -0
  179. package/dist/core/tools/artifact-retrieve.d.ts.map +1 -1
  180. package/dist/core/tools/artifact-retrieve.js +1 -1
  181. package/dist/core/tools/artifact-retrieve.js.map +1 -1
  182. package/dist/core/tools/bash.d.ts +4 -2
  183. package/dist/core/tools/bash.d.ts.map +1 -1
  184. package/dist/core/tools/bash.js +49 -7
  185. package/dist/core/tools/bash.js.map +1 -1
  186. package/dist/core/tools/file-mutation-queue.d.ts +6 -0
  187. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  188. package/dist/core/tools/file-mutation-queue.js +61 -1
  189. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  190. package/dist/core/tools/find.d.ts +1 -1
  191. package/dist/core/tools/find.d.ts.map +1 -1
  192. package/dist/core/tools/find.js +1 -1
  193. package/dist/core/tools/find.js.map +1 -1
  194. package/dist/core/tools/grep.d.ts +1 -1
  195. package/dist/core/tools/grep.d.ts.map +1 -1
  196. package/dist/core/tools/grep.js +1 -1
  197. package/dist/core/tools/grep.js.map +1 -1
  198. package/dist/core/tools/index.d.ts +1 -1
  199. package/dist/core/tools/index.d.ts.map +1 -1
  200. package/dist/core/tools/index.js +1 -1
  201. package/dist/core/tools/index.js.map +1 -1
  202. package/dist/core/tools/ls.d.ts +1 -1
  203. package/dist/core/tools/ls.d.ts.map +1 -1
  204. package/dist/core/tools/ls.js +1 -1
  205. package/dist/core/tools/ls.js.map +1 -1
  206. package/dist/core/tools/output-accumulator.d.ts +1 -1
  207. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  208. package/dist/core/tools/output-accumulator.js +1 -1
  209. package/dist/core/tools/output-accumulator.js.map +1 -1
  210. package/dist/core/tools/read.d.ts +1 -1
  211. package/dist/core/tools/read.d.ts.map +1 -1
  212. package/dist/core/tools/read.js +1 -1
  213. package/dist/core/tools/read.js.map +1 -1
  214. package/dist/core/tools/render-utils.d.ts.map +1 -1
  215. package/dist/core/tools/render-utils.js +1 -1
  216. package/dist/core/tools/render-utils.js.map +1 -1
  217. package/dist/index.d.ts +2 -3
  218. package/dist/index.d.ts.map +1 -1
  219. package/dist/index.js +3 -4
  220. package/dist/index.js.map +1 -1
  221. package/dist/main.d.ts.map +1 -1
  222. package/dist/main.js +13 -12
  223. package/dist/main.js.map +1 -1
  224. package/dist/modes/interactive/auth-dialogs-controller.d.ts +59 -0
  225. package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -0
  226. package/dist/modes/interactive/auth-dialogs-controller.js +398 -0
  227. package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -0
  228. package/dist/modes/interactive/auto-learn-controller.d.ts +168 -0
  229. package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -0
  230. package/dist/modes/interactive/auto-learn-controller.js +1239 -0
  231. package/dist/modes/interactive/auto-learn-controller.js.map +1 -0
  232. package/dist/modes/interactive/autocomplete-provider.d.ts +26 -0
  233. package/dist/modes/interactive/autocomplete-provider.d.ts.map +1 -0
  234. package/dist/modes/interactive/autocomplete-provider.js +103 -0
  235. package/dist/modes/interactive/autocomplete-provider.js.map +1 -0
  236. package/dist/modes/interactive/autonomy-commands.d.ts +38 -0
  237. package/dist/modes/interactive/autonomy-commands.d.ts.map +1 -0
  238. package/dist/modes/interactive/autonomy-commands.js +142 -0
  239. package/dist/modes/interactive/autonomy-commands.js.map +1 -0
  240. package/dist/modes/interactive/clipboard-input.d.ts +37 -0
  241. package/dist/modes/interactive/clipboard-input.d.ts.map +1 -0
  242. package/dist/modes/interactive/clipboard-input.js +59 -0
  243. package/dist/modes/interactive/clipboard-input.js.map +1 -0
  244. package/dist/modes/interactive/compaction-queue.d.ts +30 -0
  245. package/dist/modes/interactive/compaction-queue.d.ts.map +1 -0
  246. package/dist/modes/interactive/compaction-queue.js +91 -0
  247. package/dist/modes/interactive/compaction-queue.js.map +1 -0
  248. package/dist/modes/interactive/components/bash-execution.d.ts +1 -1
  249. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  250. package/dist/modes/interactive/components/bash-execution.js +1 -1
  251. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  252. package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
  253. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  254. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  255. package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
  256. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  257. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  258. package/dist/modes/interactive/components/custom-message.d.ts +1 -1
  259. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  260. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  261. package/dist/modes/interactive/components/session-selector-search.d.ts +1 -1
  262. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  263. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  264. package/dist/modes/interactive/components/session-selector.d.ts +1 -1
  265. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  266. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  267. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  268. package/dist/modes/interactive/components/tool-execution.js +2 -2
  269. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  270. package/dist/modes/interactive/components/tree-selector.d.ts +1 -1
  271. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  272. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  273. package/dist/modes/interactive/config-backup.d.ts +27 -0
  274. package/dist/modes/interactive/config-backup.d.ts.map +1 -0
  275. package/dist/modes/interactive/config-backup.js +146 -0
  276. package/dist/modes/interactive/config-backup.js.map +1 -0
  277. package/dist/modes/interactive/editor-overlay-host.d.ts +48 -0
  278. package/dist/modes/interactive/editor-overlay-host.d.ts.map +1 -0
  279. package/dist/modes/interactive/editor-overlay-host.js +43 -0
  280. package/dist/modes/interactive/editor-overlay-host.js.map +1 -0
  281. package/dist/modes/interactive/extension-ui-host.d.ts +165 -0
  282. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -0
  283. package/dist/modes/interactive/extension-ui-host.js +610 -0
  284. package/dist/modes/interactive/extension-ui-host.js.map +1 -0
  285. package/dist/modes/interactive/external-editor.d.ts +18 -0
  286. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  287. package/dist/modes/interactive/external-editor.js +107 -0
  288. package/dist/modes/interactive/external-editor.js.map +1 -0
  289. package/dist/modes/interactive/history-reload-math.d.ts +24 -0
  290. package/dist/modes/interactive/history-reload-math.d.ts.map +1 -0
  291. package/dist/modes/interactive/history-reload-math.js +129 -0
  292. package/dist/modes/interactive/history-reload-math.js.map +1 -0
  293. package/dist/modes/interactive/interactive-mode.d.ts +22 -238
  294. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  295. package/dist/modes/interactive/interactive-mode.js +714 -5910
  296. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  297. package/dist/modes/interactive/key-handlers.d.ts +46 -0
  298. package/dist/modes/interactive/key-handlers.d.ts.map +1 -0
  299. package/dist/modes/interactive/key-handlers.js +80 -0
  300. package/dist/modes/interactive/key-handlers.js.map +1 -0
  301. package/dist/modes/interactive/local-model-commands.d.ts +68 -0
  302. package/dist/modes/interactive/local-model-commands.d.ts.map +1 -0
  303. package/dist/modes/interactive/local-model-commands.js +288 -0
  304. package/dist/modes/interactive/local-model-commands.js.map +1 -0
  305. package/dist/modes/interactive/profile-menu-controller.d.ts +77 -0
  306. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -0
  307. package/dist/modes/interactive/profile-menu-controller.js +917 -0
  308. package/dist/modes/interactive/profile-menu-controller.js.map +1 -0
  309. package/dist/modes/interactive/report-commands.d.ts +46 -0
  310. package/dist/modes/interactive/report-commands.d.ts.map +1 -0
  311. package/dist/modes/interactive/report-commands.js +255 -0
  312. package/dist/modes/interactive/report-commands.js.map +1 -0
  313. package/dist/modes/interactive/resource-display.d.ts +73 -0
  314. package/dist/modes/interactive/resource-display.d.ts.map +1 -0
  315. package/dist/modes/interactive/resource-display.js +278 -0
  316. package/dist/modes/interactive/resource-display.js.map +1 -0
  317. package/dist/modes/interactive/resource-shell-commands.d.ts +64 -0
  318. package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -0
  319. package/dist/modes/interactive/resource-shell-commands.js +202 -0
  320. package/dist/modes/interactive/resource-shell-commands.js.map +1 -0
  321. package/dist/modes/interactive/session-flow-commands.d.ts +139 -0
  322. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -0
  323. package/dist/modes/interactive/session-flow-commands.js +458 -0
  324. package/dist/modes/interactive/session-flow-commands.js.map +1 -0
  325. package/dist/modes/interactive/session-io-commands.d.ts +73 -0
  326. package/dist/modes/interactive/session-io-commands.d.ts.map +1 -0
  327. package/dist/modes/interactive/session-io-commands.js +202 -0
  328. package/dist/modes/interactive/session-io-commands.js.map +1 -0
  329. package/dist/modes/interactive/settings-selector-flow.d.ts +42 -0
  330. package/dist/modes/interactive/settings-selector-flow.d.ts.map +1 -0
  331. package/dist/modes/interactive/settings-selector-flow.js +287 -0
  332. package/dist/modes/interactive/settings-selector-flow.js.map +1 -0
  333. package/dist/modes/interactive/signal-lifecycle.d.ts +55 -0
  334. package/dist/modes/interactive/signal-lifecycle.d.ts.map +1 -0
  335. package/dist/modes/interactive/signal-lifecycle.js +177 -0
  336. package/dist/modes/interactive/signal-lifecycle.js.map +1 -0
  337. package/dist/modes/interactive/startup-checks.d.ts +38 -0
  338. package/dist/modes/interactive/startup-checks.d.ts.map +1 -0
  339. package/dist/modes/interactive/startup-checks.js +189 -0
  340. package/dist/modes/interactive/startup-checks.js.map +1 -0
  341. package/dist/modes/rpc/rpc-client.d.ts +1 -1
  342. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  343. package/dist/modes/rpc/rpc-client.js.map +1 -1
  344. package/dist/modes/rpc/rpc-types.d.ts +1 -1
  345. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  346. package/dist/modes/rpc/rpc-types.js.map +1 -1
  347. package/dist/utils/paths.d.ts +2 -14
  348. package/dist/utils/paths.d.ts.map +1 -1
  349. package/dist/utils/paths.js +5 -30
  350. package/dist/utils/paths.js.map +1 -1
  351. package/dist/utils/process-memory.d.ts +8 -0
  352. package/dist/utils/process-memory.d.ts.map +1 -0
  353. package/dist/utils/process-memory.js +11 -0
  354. package/dist/utils/process-memory.js.map +1 -0
  355. package/dist/utils/shell.d.ts +0 -9
  356. package/dist/utils/shell.d.ts.map +1 -1
  357. package/dist/utils/shell.js +0 -37
  358. package/dist/utils/shell.js.map +1 -1
  359. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  360. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  361. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  362. package/examples/extensions/sandbox/package-lock.json +2 -2
  363. package/examples/extensions/sandbox/package.json +1 -1
  364. package/examples/extensions/with-deps/package-lock.json +2 -2
  365. package/examples/extensions/with-deps/package.json +1 -1
  366. package/examples/sdk/11-sessions.ts +8 -8
  367. package/examples/sdk/13-session-runtime.ts +1 -1
  368. package/npm-shrinkwrap.json +12 -12
  369. package/package.json +4 -4
  370. package/dist/core/compaction/branch-summarization.d.ts +0 -88
  371. package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
  372. package/dist/core/compaction/branch-summarization.js +0 -243
  373. package/dist/core/compaction/branch-summarization.js.map +0 -1
  374. package/dist/core/compaction/compaction.d.ts +0 -143
  375. package/dist/core/compaction/compaction.d.ts.map +0 -1
  376. package/dist/core/compaction/compaction.js +0 -659
  377. package/dist/core/compaction/compaction.js.map +0 -1
  378. package/dist/core/compaction/index.d.ts +0 -7
  379. package/dist/core/compaction/index.d.ts.map +0 -1
  380. package/dist/core/compaction/index.js +0 -7
  381. package/dist/core/compaction/index.js.map +0 -1
  382. package/dist/core/compaction/utils.d.ts +0 -38
  383. package/dist/core/compaction/utils.d.ts.map +0 -1
  384. package/dist/core/compaction/utils.js +0 -153
  385. package/dist/core/compaction/utils.js.map +0 -1
  386. package/dist/core/message-retention.d.ts +0 -26
  387. package/dist/core/message-retention.d.ts.map +0 -1
  388. package/dist/core/message-retention.js +0 -95
  389. package/dist/core/message-retention.js.map +0 -1
  390. package/dist/core/messages.d.ts +0 -77
  391. package/dist/core/messages.d.ts.map +0 -1
  392. package/dist/core/messages.js +0 -123
  393. package/dist/core/messages.js.map +0 -1
  394. package/dist/core/session-manager.d.ts +0 -337
  395. package/dist/core/session-manager.d.ts.map +0 -1
  396. package/dist/core/session-manager.js +0 -1328
  397. package/dist/core/session-manager.js.map +0 -1
  398. package/dist/core/tools/truncate.d.ts +0 -70
  399. package/dist/core/tools/truncate.d.ts.map +0 -1
  400. package/dist/core/tools/truncate.js +0 -215
  401. package/dist/core/tools/truncate.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"find.js","sourceRoot":"","sources":["../../../src/core/tools/find.ts"],"names":[],"mappings":"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","sourcesContent":["import { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport { Text } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ArtifactStore } from \"../context/context-artifacts.ts\";\nimport {\n\ttype BroadQueryTracker,\n\tbroadQueryInvalidationNote,\n\tformatArtifactNotice,\n\tnormalizeBroadQueryKey,\n\tpackToolOutput,\n} from \"../context/tool-output-packer.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport {\n\tdefaultFffSearchBackend,\n\ttype FffSearchBackend,\n\ttype FffSearchResult,\n\thasGitignoreInTree,\n\trelativePathInside,\n\tsafeGetFinder,\n} from \"./fff-search-backend.ts\";\nimport { pathExists, resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { defaultSearchRouter, type SearchRouter } from \"./search-router.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nfunction toPosixPath(value: string): string {\n\treturn value.split(path.sep).join(\"/\");\n}\n\nconst findSchema = Type.Object({\n\tpattern: Type.String({\n\t\tdescription:\n\t\t\t\"Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'. Use '.' to match all files.\",\n\t}),\n\tpath: Type.Optional(Type.String({ description: \"Directory to search in (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of results (default: 1000)\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive matching (default: false)\" })),\n});\n\nexport type FindToolInput = Static<typeof findSchema>;\n\nconst DEFAULT_LIMIT = 1000;\n\nexport interface FindToolDetails {\n\ttruncation?: TruncationResult;\n\tresultLimitReached?: number;\n\t/** Set only when output was packed to an artifact; see tool-output-packer.ts. */\n\tartifactId?: string;\n\t/** Set when this exact query has repeatedly produced broad/truncated results. */\n\tinvalidationCandidate?: boolean;\n}\n\n/**\n * Pluggable operations for the find tool.\n * Override these to delegate file search to remote systems (for example SSH).\n */\nexport interface FindOperations {\n\t/** Check if path exists */\n\texists: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Find files matching glob pattern. Returns relative or absolute paths. */\n\tglob: (pattern: string, cwd: string, options: { ignore: string[]; limit: number }) => Promise<string[]> | string[];\n}\n\nconst defaultFindOperations: FindOperations = {\n\texists: pathExists,\n\t// This is a placeholder. Actual fd execution happens in execute() when no custom glob is provided.\n\tglob: () => [],\n};\n\nexport interface FindToolOptions {\n\t/** Custom operations for find. Default: local filesystem plus routed FFF/fd search */\n\toperations?: FindOperations;\n\t/** FFF backend for resident indexed search. Set false to force fd fallback. */\n\tfff?: FffSearchBackend | false;\n\t/** Pure router that selects FFF or fd from request filters and environment facts. */\n\tsearchRouter?: SearchRouter;\n\t/**\n\t * Opt-in artifact store for first-capture-then-bound output packing (Phase 3). When\n\t * omitted (the default), behavior is byte-for-byte unchanged from before this option\n\t * existed: output is truncated the same way, just never artifact-backed.\n\t */\n\tartifactStore?: ArtifactStore;\n\t/** Opt-in tracker for repeated-broad-query \"do not repeat\" signals. Also default-off. */\n\tbroadQueryTracker?: BroadQueryTracker;\n}\n\nfunction formatFindCall(\n\targs: { pattern: string; path?: string; limit?: number } | undefined,\n\ttheme: Theme,\n\tcwd: string,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\", cwd) : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"find\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", pattern || \"\")) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatFindResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: FindToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst resultLimit = result.details?.resultLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (resultLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (resultLimit) warnings.push(`${resultLimit} results limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nfunction hasGlobSyntax(pattern: string): boolean {\n\treturn pattern === \".\" || /[*?[{]/.test(pattern);\n}\n\nfunction fffQueryParts(parts: string[]): string {\n\treturn parts.filter(Boolean).join(\" \");\n}\n\nfunction toSearchRelative(repoRelativePath: string, searchPathRelativeToCwd: string): string | undefined {\n\tif (!searchPathRelativeToCwd) return repoRelativePath;\n\tconst prefix = `${searchPathRelativeToCwd}/`;\n\tif (!repoRelativePath.startsWith(prefix)) return undefined;\n\treturn repoRelativePath.slice(prefix.length);\n}\n\nfunction fffGlobPattern(pattern: string, searchPathRelativeToCwd: string): string {\n\tconst effectivePattern = pattern === \".\" ? \"**/*\" : pattern;\n\tif (!searchPathRelativeToCwd) {\n\t\tif (effectivePattern.includes(\"/\") || effectivePattern.startsWith(\"**/\")) return effectivePattern;\n\t\treturn `**/${effectivePattern}`;\n\t}\n\tif (effectivePattern === \"**\" || effectivePattern === \"**/*\") return `${searchPathRelativeToCwd}/**/*`;\n\tif (effectivePattern.includes(\"/\")) return `${searchPathRelativeToCwd}/${effectivePattern}`;\n\treturn `${searchPathRelativeToCwd}/**/${effectivePattern}`;\n}\n\ninterface FindPackingOptions {\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n}\n\nfunction fffSearchOutput(\n\tresult: FffSearchResult,\n\tsearchPathRelativeToCwd: string,\n\teffectiveLimit: number,\n\tpacking: FindPackingOptions,\n) {\n\tconst relativized = result.items\n\t\t.map((item) => toSearchRelative(item.relativePath, searchPathRelativeToCwd))\n\t\t.filter((item): item is string => Boolean(item));\n\treturn formatFindResults(relativized, effectiveLimit, packing);\n}\n\nexport async function tryFffFind(options: {\n\tbackend: FffSearchBackend;\n\trouter: SearchRouter;\n\tcwd: string;\n\tsearchPath: string;\n\tpattern: string;\n\tignoreCase?: boolean;\n\teffectiveLimit: number;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\trawPath?: string;\n}): Promise<{ text: string; details: FindToolDetails } | undefined> {\n\tif (!(await pathExists(options.searchPath))) return undefined;\n\n\t// Kick off the FFF finder -- and, on a machine where fff-node isn't provisioned\n\t// yet, its lazy managed install -- unconditionally and as early as possible.\n\t// Routing below can still send THIS call to the fd fallback for reasons that\n\t// have nothing to do with tool availability (most commonly: the default result\n\t// limit is well above the FFF top-N threshold, see search-router.ts). That\n\t// outcome must not gate the install itself, or a machine that only ever issues\n\t// default-limit searches would never provision fff-node at all. getFinder() is\n\t// cached per basePath, so this costs nothing beyond the first call for a given\n\t// cwd -- the `await` further down, when this call does want FFF, reuses this\n\t// same in-flight/resolved promise instead of triggering the work twice.\n\t// safeGetFinder() guarantees this can never reject (a non-conforming custom\n\t// backend that throws synchronously still degrades to \"unavailable\"), so it\n\t// can neither produce an unhandled rejection nor fail this tool call outright.\n\tconst finderPromise = safeGetFinder(options.backend, options.cwd);\n\n\tconst searchPathRelativeToCwd = relativePathInside(options.cwd, options.searchPath);\n\tconst glob = hasGlobSyntax(options.pattern);\n\tconst baseRoute = options.router.route({\n\t\ttool: \"find\",\n\t\tglob,\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: searchPathRelativeToCwd !== undefined,\n\t\tgitignoreInTree: false,\n\t});\n\tif (baseRoute.backend !== \"fff\") return undefined;\n\tif (searchPathRelativeToCwd === undefined) return undefined;\n\n\tconst gitignoreInTree = await hasGitignoreInTree(options.searchPath);\n\tconst semanticRoute = options.router.route({\n\t\ttool: \"find\",\n\t\tglob,\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: true,\n\t\tgitignoreInTree,\n\t});\n\tif (semanticRoute.backend !== \"fff\") return undefined;\n\n\tconst finder = await finderPromise;\n\tconst finderRoute = options.router.route({\n\t\ttool: \"find\",\n\t\tglob,\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: Boolean(finder),\n\t\tpathResolvable: true,\n\t\tgitignoreInTree: false,\n\t});\n\tif (!finder || finderRoute.backend !== \"fff\") return undefined;\n\n\tconst packing: FindPackingOptions = {\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t};\n\n\tif (glob) {\n\t\tconst result = finder.glob(fffGlobPattern(options.pattern, searchPathRelativeToCwd), {\n\t\t\tpageSize: options.effectiveLimit,\n\t\t});\n\t\treturn result.ok\n\t\t\t? fffSearchOutput(result.value, searchPathRelativeToCwd, options.effectiveLimit, packing)\n\t\t\t: undefined;\n\t}\n\n\tconst pathConstraint = searchPathRelativeToCwd ? `${searchPathRelativeToCwd}/` : \"\";\n\tconst result = finder.fileSearch(fffQueryParts([pathConstraint, options.pattern]), {\n\t\tpageSize: options.effectiveLimit,\n\t});\n\treturn result.ok\n\t\t? fffSearchOutput(result.value, searchPathRelativeToCwd, options.effectiveLimit, packing)\n\t\t: undefined;\n}\n\nfunction formatFindResults(\n\trelativized: string[],\n\teffectiveLimit: number,\n\tpacking: FindPackingOptions,\n): { text: string; details: FindToolDetails } {\n\tif (relativized.length === 0) {\n\t\treturn { text: \"No files found matching pattern\", details: {} };\n\t}\n\n\tconst dirGroups = new Map<string, string[]>();\n\tconst extCounts = new Map<string, number>();\n\n\tfor (const p of relativized) {\n\t\tconst dir = path.dirname(p);\n\t\tconst base = path.basename(p);\n\t\tconst dirKey = dir === \".\" ? \"./\" : `${dir}/`;\n\t\tif (!dirGroups.has(dirKey)) {\n\t\t\tdirGroups.set(dirKey, []);\n\t\t}\n\t\tdirGroups.get(dirKey)!.push(base);\n\n\t\tconst ext = path.extname(p).toLowerCase() || \"(no extension)\";\n\t\textCounts.set(ext, (extCounts.get(ext) || 0) + 1);\n\t}\n\n\tconst sortedDirs = Array.from(dirGroups.keys()).sort((a, b) => a.localeCompare(b));\n\tconst formattedLines: string[] = [];\n\tfor (const dir of sortedDirs) {\n\t\tformattedLines.push(dir);\n\t\tconst files = dirGroups.get(dir)!;\n\t\tfiles.sort((a, b) => a.localeCompare(b));\n\t\tfor (const file of files) {\n\t\t\tformattedLines.push(` ${file}`);\n\t\t}\n\t}\n\n\tconst extSummaryParts = Array.from(extCounts.entries())\n\t\t.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))\n\t\t.map(([ext, count]) => `${ext}: ${count}`);\n\tconst extSummary = `Extensions: ${extSummaryParts.join(\", \")}`;\n\n\tconst resultLimitReached = relativized.length >= effectiveLimit;\n\tconst rawOutput = formattedLines.join(\"\\n\");\n\t// Measure -> pack (artifact-backed if oversized and a store was provided) -> notices.\n\tconst packed = packToolOutput(\n\t\t{\n\t\t\ttoolName: \"find\",\n\t\t\tpath: packing.rawPath,\n\t\t\trawContent: rawOutput,\n\t\t\t// No line limit here because the result limit already caps rows; only the byte\n\t\t\t// cap should apply, matching the pre-Slice-B truncateHead call exactly.\n\t\t\ttruncation: { maxLines: Number.MAX_SAFE_INTEGER },\n\t\t},\n\t\tpacking.artifactStore,\n\t\tpacking.toolCallId,\n\t);\n\tlet resultOutput = packed.content;\n\tconst details: FindToolDetails = {};\n\tconst notices: string[] = [];\n\tif (packed.artifactId) {\n\t\tnotices.push(formatArtifactNotice(packed.artifactId));\n\t\tdetails.artifactId = packed.artifactId;\n\t}\n\tif (resultLimitReached) {\n\t\tnotices.push(\n\t\t\t`${effectiveLimit} results limit reached. Use limit=${effectiveLimit * 2} for more, or narrow path/pattern`,\n\t\t);\n\t\tdetails.resultLimitReached = effectiveLimit;\n\t}\n\tif (packed.truncation.truncated) {\n\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t// Drop the duplicated bounded-preview text: it's already in the message's own\n\t\t// content, and re-including it here can push `details` past\n\t\t// MAX_RETAINED_TOOL_RESULT_DETAILS_BYTES (message-retention.ts), which replaces\n\t\t// the *entire* details object with a stub -- silently losing artifactId and every\n\t\t// other field alongside it. This is load-bearing beyond just the retention budget:\n\t\t// agent-session.ts's _releaseGcPackedArtifactReferences() reads artifactId back off\n\t\t// this same canonical message at eviction time (potentially many turns later), so\n\t\t// keeping `details` small here is what keeps that release path working at all. If\n\t\t// this field ever grows a large addition again, add a regression proving artifactId\n\t\t// survives compactToolResultDetailsForRetention (see\n\t\t// test/suite/agent-session-artifact-lifecycle.test.ts), not just a details-size check.\n\t\tdetails.truncation = { ...packed.truncation, content: \"\" };\n\t}\n\tif (resultLimitReached || packed.truncation.truncated) {\n\t\tconst note = broadQueryInvalidationNote(\n\t\t\tpacking.broadQueryTracker,\n\t\t\tnormalizeBroadQueryKey({ toolName: \"find\", pattern: packing.pattern, path: packing.rawPath }),\n\t\t\t`find \"${packing.pattern}\" in ${packing.rawPath ?? \".\"}`,\n\t\t);\n\t\tif (note) {\n\t\t\tnotices.push(note);\n\t\t\tdetails.invalidationCandidate = true;\n\t\t}\n\t}\n\tif (relativized.length > 0) {\n\t\tresultOutput += `\\n\\n[Summary - ${extSummary}]`;\n\t}\n\tif (notices.length > 0) {\n\t\tresultOutput += `\\n\\n[${notices.join(\". \")}]`;\n\t}\n\treturn { text: resultOutput, details };\n}\n\nexport function createFindToolDefinition(\n\tcwd: string,\n\toptions?: FindToolOptions,\n): ToolDefinition<typeof findSchema, FindToolDetails | undefined> {\n\tconst customOps = options?.operations;\n\tconst fffBackend = options?.fff === false ? undefined : (options?.fff ?? defaultFffSearchBackend);\n\tconst searchRouter = options?.searchRouter ?? defaultSearchRouter;\n\tconst artifactStore = options?.artifactStore;\n\tconst broadQueryTracker = options?.broadQueryTracker;\n\treturn {\n\t\tname: \"find\",\n\t\tlabel: \"find\",\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).`,\n\t\tpromptSnippet: \"Find files by glob pattern (respects .gitignore)\",\n\t\tparameters: findSchema,\n\t\ttoolGroup: \"explore\",\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tlimit,\n\t\t\t\tignoreCase,\n\t\t\t}: { pattern: string; path?: string; limit?: number; ignoreCase?: boolean },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet settled = false;\n\t\t\t\tlet stopChild: (() => void) | undefined;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tstopChild = undefined;\n\t\t\t\t\tfn();\n\t\t\t\t};\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tstopChild?.();\n\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t};\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\t\t\t\t\t\tconst ops = customOps ?? defaultFindOperations;\n\n\t\t\t\t\t\tlet effectivePattern = pattern;\n\t\t\t\t\t\tif (pattern === \".\") {\n\t\t\t\t\t\t\teffectivePattern = \"**/*\";\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!customOps && fffBackend) {\n\t\t\t\t\t\t\tconst fffResult = await tryFffFind({\n\t\t\t\t\t\t\t\tbackend: fffBackend,\n\t\t\t\t\t\t\t\trouter: searchRouter,\n\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\tsearchPath,\n\t\t\t\t\t\t\t\tpattern: effectivePattern,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\teffectiveLimit,\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (fffResult) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: fffResult.text }],\n\t\t\t\t\t\t\t\t\t\tdetails: Object.keys(fffResult.details).length > 0 ? fffResult.details : undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If custom operations provide glob(), use that instead of fd.\n\t\t\t\t\t\tif (customOps?.glob) {\n\t\t\t\t\t\t\tif (!(await ops.exists(searchPath))) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst results = await ops.glob(effectivePattern, searchPath, {\n\t\t\t\t\t\t\t\tignore: [\"**/node_modules/**\", \"**/.git/**\"],\n\t\t\t\t\t\t\t\tlimit: effectiveLimit,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Relativize paths against the search root for stable output.\n\t\t\t\t\t\t\tconst relativized = results.map((p) => {\n\t\t\t\t\t\t\t\tif (p.startsWith(searchPath)) return toPosixPath(p.slice(searchPath.length + 1));\n\t\t\t\t\t\t\t\treturn toPosixPath(path.relative(searchPath, p));\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tconst formatted = formatFindResults(relativized, effectiveLimit, {\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\tpattern: effectivePattern,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: formatted.text }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(formatted.details).length > 0 ? formatted.details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Default implementation uses fd.\n\t\t\t\t\t\tconst fdPath = await ensureTool(\"fd\", true);\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!fdPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"fd is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Build fd arguments. --no-require-git makes fd apply hierarchical .gitignore\n\t\t\t\t\t\t// semantics whether or not the search path is inside a git repository, without\n\t\t\t\t\t\t// leaking sibling-directory rules the way --ignore-file (a global source) would.\n\t\t\t\t\t\tconst args: string[] = [\n\t\t\t\t\t\t\t\"--glob\",\n\t\t\t\t\t\t\t\"--color=never\",\n\t\t\t\t\t\t\t\"--hidden\",\n\t\t\t\t\t\t\t\"--no-require-git\",\n\t\t\t\t\t\t\t\"--max-results\",\n\t\t\t\t\t\t\tString(effectiveLimit),\n\t\t\t\t\t\t];\n\t\t\t\t\t\tif (ignoreCase) {\n\t\t\t\t\t\t\targs.push(\"--ignore-case\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// fd --glob matches against the basename unless --full-path is set; in --full-path\n\t\t\t\t\t\t// mode it matches against the absolute candidate path, so a path-containing\n\t\t\t\t\t\t// pattern like 'src/**/*.spec.ts' needs a leading '**/' to match anything.\n\t\t\t\t\t\tlet finalPattern = effectivePattern;\n\t\t\t\t\t\tif (effectivePattern.includes(\"/\")) {\n\t\t\t\t\t\t\targs.push(\"--full-path\");\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t!effectivePattern.startsWith(\"/\") &&\n\t\t\t\t\t\t\t\t!effectivePattern.startsWith(\"**/\") &&\n\t\t\t\t\t\t\t\teffectivePattern !== \"**\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tfinalPattern = `**/${effectivePattern}`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\targs.push(\"--\", finalPattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(fdPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tconst lines: string[] = [];\n\n\t\t\t\t\t\tstopChild = () => {\n\t\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tlines.push(line);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Failed to run fd: ${error.message}`)));\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"close\", (code) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst output = lines.join(\"\\n\");\n\t\t\t\t\t\t\tif (code !== 0) {\n\t\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `fd exited with code ${code}`;\n\t\t\t\t\t\t\t\tif (!output) {\n\t\t\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst relativized: string[] = [];\n\t\t\t\t\t\t\tfor (const rawLine of lines) {\n\t\t\t\t\t\t\t\tconst line = rawLine.replace(/\\r$/, \"\").trim();\n\t\t\t\t\t\t\t\tif (!line) continue;\n\t\t\t\t\t\t\t\tconst hadTrailingSlash = line.endsWith(\"/\") || line.endsWith(\"\\\\\");\n\t\t\t\t\t\t\t\tlet relativePath = line;\n\t\t\t\t\t\t\t\tif (line.startsWith(searchPath)) {\n\t\t\t\t\t\t\t\t\trelativePath = line.slice(searchPath.length + 1);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\trelativePath = path.relative(searchPath, line);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (hadTrailingSlash && !relativePath.endsWith(\"/\")) relativePath += \"/\";\n\t\t\t\t\t\t\t\trelativized.push(toPosixPath(relativePath));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst formatted = formatFindResults(relativized, effectiveLimit, {\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\tpattern: effectivePattern,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: formatted.text }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(formatted.details).length > 0 ? formatted.details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst error = e instanceof Error ? e : new Error(String(e));\n\t\t\t\t\t\tsettle(() => reject(error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatFindCall(args, theme, context.cwd));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatFindResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createFindTool(cwd: string, options?: FindToolOptions): AgentTool<typeof findSchema> {\n\treturn wrapToolDefinition(createFindToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"find.js","sourceRoot":"","sources":["../../../src/core/tools/find.ts"],"names":[],"mappings":"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","sourcesContent":["import { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult } from \"@caupulican/pi-agent-core/node\";\nimport { Text } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ArtifactStore } from \"../context/context-artifacts.ts\";\nimport {\n\ttype BroadQueryTracker,\n\tbroadQueryInvalidationNote,\n\tformatArtifactNotice,\n\tnormalizeBroadQueryKey,\n\tpackToolOutput,\n} from \"../context/tool-output-packer.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport {\n\tdefaultFffSearchBackend,\n\ttype FffSearchBackend,\n\ttype FffSearchResult,\n\thasGitignoreInTree,\n\trelativePathInside,\n\tsafeGetFinder,\n} from \"./fff-search-backend.ts\";\nimport { pathExists, resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { defaultSearchRouter, type SearchRouter } from \"./search-router.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nfunction toPosixPath(value: string): string {\n\treturn value.split(path.sep).join(\"/\");\n}\n\nconst findSchema = Type.Object({\n\tpattern: Type.String({\n\t\tdescription:\n\t\t\t\"Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'. Use '.' to match all files.\",\n\t}),\n\tpath: Type.Optional(Type.String({ description: \"Directory to search in (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of results (default: 1000)\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive matching (default: false)\" })),\n});\n\nexport type FindToolInput = Static<typeof findSchema>;\n\nconst DEFAULT_LIMIT = 1000;\n\nexport interface FindToolDetails {\n\ttruncation?: TruncationResult;\n\tresultLimitReached?: number;\n\t/** Set only when output was packed to an artifact; see tool-output-packer.ts. */\n\tartifactId?: string;\n\t/** Set when this exact query has repeatedly produced broad/truncated results. */\n\tinvalidationCandidate?: boolean;\n}\n\n/**\n * Pluggable operations for the find tool.\n * Override these to delegate file search to remote systems (for example SSH).\n */\nexport interface FindOperations {\n\t/** Check if path exists */\n\texists: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Find files matching glob pattern. Returns relative or absolute paths. */\n\tglob: (pattern: string, cwd: string, options: { ignore: string[]; limit: number }) => Promise<string[]> | string[];\n}\n\nconst defaultFindOperations: FindOperations = {\n\texists: pathExists,\n\t// This is a placeholder. Actual fd execution happens in execute() when no custom glob is provided.\n\tglob: () => [],\n};\n\nexport interface FindToolOptions {\n\t/** Custom operations for find. Default: local filesystem plus routed FFF/fd search */\n\toperations?: FindOperations;\n\t/** FFF backend for resident indexed search. Set false to force fd fallback. */\n\tfff?: FffSearchBackend | false;\n\t/** Pure router that selects FFF or fd from request filters and environment facts. */\n\tsearchRouter?: SearchRouter;\n\t/**\n\t * Opt-in artifact store for first-capture-then-bound output packing (Phase 3). When\n\t * omitted (the default), behavior is byte-for-byte unchanged from before this option\n\t * existed: output is truncated the same way, just never artifact-backed.\n\t */\n\tartifactStore?: ArtifactStore;\n\t/** Opt-in tracker for repeated-broad-query \"do not repeat\" signals. Also default-off. */\n\tbroadQueryTracker?: BroadQueryTracker;\n}\n\nfunction formatFindCall(\n\targs: { pattern: string; path?: string; limit?: number } | undefined,\n\ttheme: Theme,\n\tcwd: string,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\", cwd) : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"find\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", pattern || \"\")) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatFindResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: FindToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst resultLimit = result.details?.resultLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (resultLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (resultLimit) warnings.push(`${resultLimit} results limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nfunction hasGlobSyntax(pattern: string): boolean {\n\treturn pattern === \".\" || /[*?[{]/.test(pattern);\n}\n\nfunction fffQueryParts(parts: string[]): string {\n\treturn parts.filter(Boolean).join(\" \");\n}\n\nfunction toSearchRelative(repoRelativePath: string, searchPathRelativeToCwd: string): string | undefined {\n\tif (!searchPathRelativeToCwd) return repoRelativePath;\n\tconst prefix = `${searchPathRelativeToCwd}/`;\n\tif (!repoRelativePath.startsWith(prefix)) return undefined;\n\treturn repoRelativePath.slice(prefix.length);\n}\n\nfunction fffGlobPattern(pattern: string, searchPathRelativeToCwd: string): string {\n\tconst effectivePattern = pattern === \".\" ? \"**/*\" : pattern;\n\tif (!searchPathRelativeToCwd) {\n\t\tif (effectivePattern.includes(\"/\") || effectivePattern.startsWith(\"**/\")) return effectivePattern;\n\t\treturn `**/${effectivePattern}`;\n\t}\n\tif (effectivePattern === \"**\" || effectivePattern === \"**/*\") return `${searchPathRelativeToCwd}/**/*`;\n\tif (effectivePattern.includes(\"/\")) return `${searchPathRelativeToCwd}/${effectivePattern}`;\n\treturn `${searchPathRelativeToCwd}/**/${effectivePattern}`;\n}\n\ninterface FindPackingOptions {\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n}\n\nfunction fffSearchOutput(\n\tresult: FffSearchResult,\n\tsearchPathRelativeToCwd: string,\n\teffectiveLimit: number,\n\tpacking: FindPackingOptions,\n) {\n\tconst relativized = result.items\n\t\t.map((item) => toSearchRelative(item.relativePath, searchPathRelativeToCwd))\n\t\t.filter((item): item is string => Boolean(item));\n\treturn formatFindResults(relativized, effectiveLimit, packing);\n}\n\nexport async function tryFffFind(options: {\n\tbackend: FffSearchBackend;\n\trouter: SearchRouter;\n\tcwd: string;\n\tsearchPath: string;\n\tpattern: string;\n\tignoreCase?: boolean;\n\teffectiveLimit: number;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\trawPath?: string;\n}): Promise<{ text: string; details: FindToolDetails } | undefined> {\n\tif (!(await pathExists(options.searchPath))) return undefined;\n\n\t// Kick off the FFF finder -- and, on a machine where fff-node isn't provisioned\n\t// yet, its lazy managed install -- unconditionally and as early as possible.\n\t// Routing below can still send THIS call to the fd fallback for reasons that\n\t// have nothing to do with tool availability (most commonly: the default result\n\t// limit is well above the FFF top-N threshold, see search-router.ts). That\n\t// outcome must not gate the install itself, or a machine that only ever issues\n\t// default-limit searches would never provision fff-node at all. getFinder() is\n\t// cached per basePath, so this costs nothing beyond the first call for a given\n\t// cwd -- the `await` further down, when this call does want FFF, reuses this\n\t// same in-flight/resolved promise instead of triggering the work twice.\n\t// safeGetFinder() guarantees this can never reject (a non-conforming custom\n\t// backend that throws synchronously still degrades to \"unavailable\"), so it\n\t// can neither produce an unhandled rejection nor fail this tool call outright.\n\tconst finderPromise = safeGetFinder(options.backend, options.cwd);\n\n\tconst searchPathRelativeToCwd = relativePathInside(options.cwd, options.searchPath);\n\tconst glob = hasGlobSyntax(options.pattern);\n\tconst baseRoute = options.router.route({\n\t\ttool: \"find\",\n\t\tglob,\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: searchPathRelativeToCwd !== undefined,\n\t\tgitignoreInTree: false,\n\t});\n\tif (baseRoute.backend !== \"fff\") return undefined;\n\tif (searchPathRelativeToCwd === undefined) return undefined;\n\n\tconst gitignoreInTree = await hasGitignoreInTree(options.searchPath);\n\tconst semanticRoute = options.router.route({\n\t\ttool: \"find\",\n\t\tglob,\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: true,\n\t\tgitignoreInTree,\n\t});\n\tif (semanticRoute.backend !== \"fff\") return undefined;\n\n\tconst finder = await finderPromise;\n\tconst finderRoute = options.router.route({\n\t\ttool: \"find\",\n\t\tglob,\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: Boolean(finder),\n\t\tpathResolvable: true,\n\t\tgitignoreInTree: false,\n\t});\n\tif (!finder || finderRoute.backend !== \"fff\") return undefined;\n\n\tconst packing: FindPackingOptions = {\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t};\n\n\tif (glob) {\n\t\tconst result = finder.glob(fffGlobPattern(options.pattern, searchPathRelativeToCwd), {\n\t\t\tpageSize: options.effectiveLimit,\n\t\t});\n\t\treturn result.ok\n\t\t\t? fffSearchOutput(result.value, searchPathRelativeToCwd, options.effectiveLimit, packing)\n\t\t\t: undefined;\n\t}\n\n\tconst pathConstraint = searchPathRelativeToCwd ? `${searchPathRelativeToCwd}/` : \"\";\n\tconst result = finder.fileSearch(fffQueryParts([pathConstraint, options.pattern]), {\n\t\tpageSize: options.effectiveLimit,\n\t});\n\treturn result.ok\n\t\t? fffSearchOutput(result.value, searchPathRelativeToCwd, options.effectiveLimit, packing)\n\t\t: undefined;\n}\n\nfunction formatFindResults(\n\trelativized: string[],\n\teffectiveLimit: number,\n\tpacking: FindPackingOptions,\n): { text: string; details: FindToolDetails } {\n\tif (relativized.length === 0) {\n\t\treturn { text: \"No files found matching pattern\", details: {} };\n\t}\n\n\tconst dirGroups = new Map<string, string[]>();\n\tconst extCounts = new Map<string, number>();\n\n\tfor (const p of relativized) {\n\t\tconst dir = path.dirname(p);\n\t\tconst base = path.basename(p);\n\t\tconst dirKey = dir === \".\" ? \"./\" : `${dir}/`;\n\t\tif (!dirGroups.has(dirKey)) {\n\t\t\tdirGroups.set(dirKey, []);\n\t\t}\n\t\tdirGroups.get(dirKey)!.push(base);\n\n\t\tconst ext = path.extname(p).toLowerCase() || \"(no extension)\";\n\t\textCounts.set(ext, (extCounts.get(ext) || 0) + 1);\n\t}\n\n\tconst sortedDirs = Array.from(dirGroups.keys()).sort((a, b) => a.localeCompare(b));\n\tconst formattedLines: string[] = [];\n\tfor (const dir of sortedDirs) {\n\t\tformattedLines.push(dir);\n\t\tconst files = dirGroups.get(dir)!;\n\t\tfiles.sort((a, b) => a.localeCompare(b));\n\t\tfor (const file of files) {\n\t\t\tformattedLines.push(` ${file}`);\n\t\t}\n\t}\n\n\tconst extSummaryParts = Array.from(extCounts.entries())\n\t\t.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))\n\t\t.map(([ext, count]) => `${ext}: ${count}`);\n\tconst extSummary = `Extensions: ${extSummaryParts.join(\", \")}`;\n\n\tconst resultLimitReached = relativized.length >= effectiveLimit;\n\tconst rawOutput = formattedLines.join(\"\\n\");\n\t// Measure -> pack (artifact-backed if oversized and a store was provided) -> notices.\n\tconst packed = packToolOutput(\n\t\t{\n\t\t\ttoolName: \"find\",\n\t\t\tpath: packing.rawPath,\n\t\t\trawContent: rawOutput,\n\t\t\t// No line limit here because the result limit already caps rows; only the byte\n\t\t\t// cap should apply, matching the pre-Slice-B truncateHead call exactly.\n\t\t\ttruncation: { maxLines: Number.MAX_SAFE_INTEGER },\n\t\t},\n\t\tpacking.artifactStore,\n\t\tpacking.toolCallId,\n\t);\n\tlet resultOutput = packed.content;\n\tconst details: FindToolDetails = {};\n\tconst notices: string[] = [];\n\tif (packed.artifactId) {\n\t\tnotices.push(formatArtifactNotice(packed.artifactId));\n\t\tdetails.artifactId = packed.artifactId;\n\t}\n\tif (resultLimitReached) {\n\t\tnotices.push(\n\t\t\t`${effectiveLimit} results limit reached. Use limit=${effectiveLimit * 2} for more, or narrow path/pattern`,\n\t\t);\n\t\tdetails.resultLimitReached = effectiveLimit;\n\t}\n\tif (packed.truncation.truncated) {\n\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t// Drop the duplicated bounded-preview text: it's already in the message's own\n\t\t// content, and re-including it here can push `details` past\n\t\t// MAX_RETAINED_TOOL_RESULT_DETAILS_BYTES (message-retention.ts), which replaces\n\t\t// the *entire* details object with a stub -- silently losing artifactId and every\n\t\t// other field alongside it. This is load-bearing beyond just the retention budget:\n\t\t// agent-session.ts's _releaseGcPackedArtifactReferences() reads artifactId back off\n\t\t// this same canonical message at eviction time (potentially many turns later), so\n\t\t// keeping `details` small here is what keeps that release path working at all. If\n\t\t// this field ever grows a large addition again, add a regression proving artifactId\n\t\t// survives compactToolResultDetailsForRetention (see\n\t\t// test/suite/agent-session-artifact-lifecycle.test.ts), not just a details-size check.\n\t\tdetails.truncation = { ...packed.truncation, content: \"\" };\n\t}\n\tif (resultLimitReached || packed.truncation.truncated) {\n\t\tconst note = broadQueryInvalidationNote(\n\t\t\tpacking.broadQueryTracker,\n\t\t\tnormalizeBroadQueryKey({ toolName: \"find\", pattern: packing.pattern, path: packing.rawPath }),\n\t\t\t`find \"${packing.pattern}\" in ${packing.rawPath ?? \".\"}`,\n\t\t);\n\t\tif (note) {\n\t\t\tnotices.push(note);\n\t\t\tdetails.invalidationCandidate = true;\n\t\t}\n\t}\n\tif (relativized.length > 0) {\n\t\tresultOutput += `\\n\\n[Summary - ${extSummary}]`;\n\t}\n\tif (notices.length > 0) {\n\t\tresultOutput += `\\n\\n[${notices.join(\". \")}]`;\n\t}\n\treturn { text: resultOutput, details };\n}\n\nexport function createFindToolDefinition(\n\tcwd: string,\n\toptions?: FindToolOptions,\n): ToolDefinition<typeof findSchema, FindToolDetails | undefined> {\n\tconst customOps = options?.operations;\n\tconst fffBackend = options?.fff === false ? undefined : (options?.fff ?? defaultFffSearchBackend);\n\tconst searchRouter = options?.searchRouter ?? defaultSearchRouter;\n\tconst artifactStore = options?.artifactStore;\n\tconst broadQueryTracker = options?.broadQueryTracker;\n\treturn {\n\t\tname: \"find\",\n\t\tlabel: \"find\",\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).`,\n\t\tpromptSnippet: \"Find files by glob pattern (respects .gitignore)\",\n\t\tparameters: findSchema,\n\t\ttoolGroup: \"explore\",\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tlimit,\n\t\t\t\tignoreCase,\n\t\t\t}: { pattern: string; path?: string; limit?: number; ignoreCase?: boolean },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet settled = false;\n\t\t\t\tlet stopChild: (() => void) | undefined;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tstopChild = undefined;\n\t\t\t\t\tfn();\n\t\t\t\t};\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tstopChild?.();\n\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t};\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\t\t\t\t\t\tconst ops = customOps ?? defaultFindOperations;\n\n\t\t\t\t\t\tlet effectivePattern = pattern;\n\t\t\t\t\t\tif (pattern === \".\") {\n\t\t\t\t\t\t\teffectivePattern = \"**/*\";\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!customOps && fffBackend) {\n\t\t\t\t\t\t\tconst fffResult = await tryFffFind({\n\t\t\t\t\t\t\t\tbackend: fffBackend,\n\t\t\t\t\t\t\t\trouter: searchRouter,\n\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\tsearchPath,\n\t\t\t\t\t\t\t\tpattern: effectivePattern,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\teffectiveLimit,\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (fffResult) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: fffResult.text }],\n\t\t\t\t\t\t\t\t\t\tdetails: Object.keys(fffResult.details).length > 0 ? fffResult.details : undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If custom operations provide glob(), use that instead of fd.\n\t\t\t\t\t\tif (customOps?.glob) {\n\t\t\t\t\t\t\tif (!(await ops.exists(searchPath))) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst results = await ops.glob(effectivePattern, searchPath, {\n\t\t\t\t\t\t\t\tignore: [\"**/node_modules/**\", \"**/.git/**\"],\n\t\t\t\t\t\t\t\tlimit: effectiveLimit,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Relativize paths against the search root for stable output.\n\t\t\t\t\t\t\tconst relativized = results.map((p) => {\n\t\t\t\t\t\t\t\tif (p.startsWith(searchPath)) return toPosixPath(p.slice(searchPath.length + 1));\n\t\t\t\t\t\t\t\treturn toPosixPath(path.relative(searchPath, p));\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tconst formatted = formatFindResults(relativized, effectiveLimit, {\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\tpattern: effectivePattern,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: formatted.text }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(formatted.details).length > 0 ? formatted.details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Default implementation uses fd.\n\t\t\t\t\t\tconst fdPath = await ensureTool(\"fd\", true);\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!fdPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"fd is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Build fd arguments. --no-require-git makes fd apply hierarchical .gitignore\n\t\t\t\t\t\t// semantics whether or not the search path is inside a git repository, without\n\t\t\t\t\t\t// leaking sibling-directory rules the way --ignore-file (a global source) would.\n\t\t\t\t\t\tconst args: string[] = [\n\t\t\t\t\t\t\t\"--glob\",\n\t\t\t\t\t\t\t\"--color=never\",\n\t\t\t\t\t\t\t\"--hidden\",\n\t\t\t\t\t\t\t\"--no-require-git\",\n\t\t\t\t\t\t\t\"--max-results\",\n\t\t\t\t\t\t\tString(effectiveLimit),\n\t\t\t\t\t\t];\n\t\t\t\t\t\tif (ignoreCase) {\n\t\t\t\t\t\t\targs.push(\"--ignore-case\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// fd --glob matches against the basename unless --full-path is set; in --full-path\n\t\t\t\t\t\t// mode it matches against the absolute candidate path, so a path-containing\n\t\t\t\t\t\t// pattern like 'src/**/*.spec.ts' needs a leading '**/' to match anything.\n\t\t\t\t\t\tlet finalPattern = effectivePattern;\n\t\t\t\t\t\tif (effectivePattern.includes(\"/\")) {\n\t\t\t\t\t\t\targs.push(\"--full-path\");\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t!effectivePattern.startsWith(\"/\") &&\n\t\t\t\t\t\t\t\t!effectivePattern.startsWith(\"**/\") &&\n\t\t\t\t\t\t\t\teffectivePattern !== \"**\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tfinalPattern = `**/${effectivePattern}`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\targs.push(\"--\", finalPattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(fdPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tconst lines: string[] = [];\n\n\t\t\t\t\t\tstopChild = () => {\n\t\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tlines.push(line);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Failed to run fd: ${error.message}`)));\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"close\", (code) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst output = lines.join(\"\\n\");\n\t\t\t\t\t\t\tif (code !== 0) {\n\t\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `fd exited with code ${code}`;\n\t\t\t\t\t\t\t\tif (!output) {\n\t\t\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst relativized: string[] = [];\n\t\t\t\t\t\t\tfor (const rawLine of lines) {\n\t\t\t\t\t\t\t\tconst line = rawLine.replace(/\\r$/, \"\").trim();\n\t\t\t\t\t\t\t\tif (!line) continue;\n\t\t\t\t\t\t\t\tconst hadTrailingSlash = line.endsWith(\"/\") || line.endsWith(\"\\\\\");\n\t\t\t\t\t\t\t\tlet relativePath = line;\n\t\t\t\t\t\t\t\tif (line.startsWith(searchPath)) {\n\t\t\t\t\t\t\t\t\trelativePath = line.slice(searchPath.length + 1);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\trelativePath = path.relative(searchPath, line);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (hadTrailingSlash && !relativePath.endsWith(\"/\")) relativePath += \"/\";\n\t\t\t\t\t\t\t\trelativized.push(toPosixPath(relativePath));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst formatted = formatFindResults(relativized, effectiveLimit, {\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\tpattern: effectivePattern,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: formatted.text }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(formatted.details).length > 0 ? formatted.details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst error = e instanceof Error ? e : new Error(String(e));\n\t\t\t\t\t\tsettle(() => reject(error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatFindCall(args, theme, context.cwd));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatFindResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createFindTool(cwd: string, options?: FindToolOptions): AgentTool<typeof findSchema> {\n\treturn wrapToolDefinition(createFindToolDefinition(cwd, options));\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  import type { AgentTool } from "@caupulican/pi-agent-core";
2
+ import { type TruncationResult } from "@caupulican/pi-agent-core/node";
2
3
  import { type Static, Type } from "typebox";
3
4
  import type { ArtifactStore } from "../context/context-artifacts.ts";
4
5
  import { type BroadQueryTracker } from "../context/tool-output-packer.ts";
5
6
  import type { ToolDefinition } from "../extensions/types.ts";
6
7
  import { type FffSearchBackend } from "./fff-search-backend.ts";
7
8
  import { type SearchRouter } from "./search-router.ts";
8
- import { type TruncationResult } from "./truncate.ts";
9
9
  declare const grepSchema: Type.TObject<{
10
10
  pattern: Type.TString;
11
11
  path: Type.TOptional<Type.TString>;
@@ -1 +1 @@
1
- {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EACN,KAAK,iBAAiB,EAKtB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAIN,KAAK,gBAAgB,EAIrB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAIN,KAAK,gBAAgB,EAErB,MAAM,eAAe,CAAC;AAEvB,QAAA,MAAM,UAAU;;;;;;;;EAYd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAGtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,mEAAmE;IACnE,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAClE,2CAA2C;IAC3C,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC7D;AAOD,MAAM,WAAW,eAAe;IAC/B,sFAAsF;IACtF,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,oFAAoF;IACpF,GAAG,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;IAC/B,qFAAqF;IACrF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,yFAAyF;IACzF,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACtC;AA0PD,wBAAsB,UAAU,CAAC,OAAO,EAAE;IACzC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GAAG,SAAS,CAAC,CAiFlE;AAED,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CA+ShE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG","sourcesContent":["import { readFile as fsReadFile, stat as fsStat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport { Text } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ArtifactStore } from \"../context/context-artifacts.ts\";\nimport {\n\ttype BroadQueryTracker,\n\tbroadQueryInvalidationNote,\n\tformatArtifactNotice,\n\tnormalizeBroadQueryKey,\n\tpackToolOutput,\n} from \"../context/tool-output-packer.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport {\n\tdefaultFffSearchBackend,\n\ttype FffGrepMatch,\n\ttype FffGrepResult,\n\ttype FffSearchBackend,\n\thasGitignoreInTree,\n\trelativePathInside,\n\tsafeGetFinder,\n} from \"./fff-search-backend.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { defaultSearchRouter, type SearchRouter } from \"./search-router.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateLine,\n} from \"./truncate.ts\";\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: \"Search pattern (regex or literal string)\" }),\n\tpath: Type.Optional(Type.String({ description: \"Directory or file to search (default: current directory)\" })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n\tliteral: Type.Optional(\n\t\tType.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" }),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Number({ description: \"Number of lines to show before and after each match (default: 0)\" }),\n\t),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of matches to return (default: 100)\" })),\n});\n\nexport type GrepToolInput = Static<typeof grepSchema>;\nconst DEFAULT_LIMIT = 100;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n\t/** Set only when output was packed to an artifact; see tool-output-packer.ts. */\n\tartifactId?: string;\n\t/** Set when this exact query has repeatedly produced broad/truncated results. */\n\tinvalidationCandidate?: boolean;\n}\n\n/**\n * Pluggable operations for the grep tool.\n * Override these to delegate search to remote systems (for example SSH).\n */\nexport interface GrepOperations {\n\t/** Check if path is a directory. Throws if path does not exist. */\n\tisDirectory: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Read file contents for context lines */\n\treadFile: (absolutePath: string) => Promise<string> | string;\n}\n\nconst defaultGrepOperations: GrepOperations = {\n\tisDirectory: async (p) => (await fsStat(p)).isDirectory(),\n\treadFile: (p) => fsReadFile(p, \"utf-8\"),\n};\n\nexport interface GrepToolOptions {\n\t/** Custom operations for grep. Default: local filesystem plus routed FFF/rg search */\n\toperations?: GrepOperations;\n\t/** FFF backend for resident indexed search. Set false to force ripgrep fallback. */\n\tfff?: FffSearchBackend | false;\n\t/** Pure router that selects FFF or rg from request filters and environment facts. */\n\tsearchRouter?: SearchRouter;\n\t/**\n\t * Opt-in artifact store for first-capture-then-bound output packing (Phase 3). When\n\t * omitted (the default), behavior is byte-for-byte unchanged from before this option\n\t * existed: output is truncated the same way, just never artifact-backed.\n\t */\n\tartifactStore?: ArtifactStore;\n\t/** Opt-in tracker for repeated-broad-query \"do not repeat\" signals. Also default-off. */\n\tbroadQueryTracker?: BroadQueryTracker;\n}\n\nfunction formatGrepCall(\n\targs: { pattern: string; path?: string; glob?: string; limit?: number } | undefined,\n\ttheme: Theme,\n\tcwd: string,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\", cwd) : null;\n\tconst glob = str(args?.glob);\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", `/${pattern || \"\"}/`)) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (glob) text += theme.fg(\"toolOutput\", ` (${glob})`);\n\tif (limit !== undefined) text += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\treturn text;\n}\n\nfunction formatGrepResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: GrepToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 15;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst matchLimit = result.details?.matchLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst linesTruncated = result.details?.linesTruncated;\n\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (matchLimit) warnings.push(`${matchLimit} matches limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\tif (linesTruncated) warnings.push(\"some lines truncated\");\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nfunction globConstraintForFff(glob: string | undefined): string {\n\tif (!glob) return \"\";\n\tif (glob.includes(\"/\") || glob.startsWith(\"**/\")) return glob;\n\treturn `**/${glob}`;\n}\n\nfunction fffGrepQuery(options: {\n\tpattern: string;\n\tglob?: string;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n}): string | undefined {\n\tconst parts: string[] = [];\n\tif (options.searchPathRelativeToCwd) {\n\t\tparts.push(options.isDirectory ? `${options.searchPathRelativeToCwd}/` : options.searchPathRelativeToCwd);\n\t}\n\tparts.push(globConstraintForFff(options.glob));\n\tparts.push(options.pattern);\n\treturn parts.filter(Boolean).join(\" \");\n}\n\nfunction fffDisplayPath(\n\tmatch: FffGrepMatch,\n\toptions: { isDirectory: boolean; searchPathRelativeToCwd: string },\n): string | undefined {\n\tif (!options.searchPathRelativeToCwd) return match.relativePath;\n\tif (!options.isDirectory) {\n\t\treturn match.relativePath === options.searchPathRelativeToCwd ? path.basename(match.relativePath) : undefined;\n\t}\n\tconst prefix = `${options.searchPathRelativeToCwd}/`;\n\tif (!match.relativePath.startsWith(prefix)) return undefined;\n\treturn match.relativePath.slice(prefix.length);\n}\n\nfunction appendFffMatchLines(options: {\n\tmatch: FffGrepMatch;\n\toutputLines: string[];\n\tlinesTruncated: { value: boolean };\n\tcontextValue: number;\n}): void {\n\tconst before = options.match.contextBefore ?? [];\n\tfor (let i = 0; i < before.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber - before.length + i;\n\t\tconst { text, wasTruncated } = truncateLine(before[i] ?? \"\");\n\t\tif (wasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${text}`);\n\t}\n\n\tconst { text, wasTruncated } = truncateLine(options.match.lineContent.replace(/\\r/g, \"\"));\n\tif (wasTruncated) options.linesTruncated.value = true;\n\toptions.outputLines.push(` ${options.match.lineNumber}: ${text}`);\n\n\tif (options.contextValue === 0) return;\n\tconst after = options.match.contextAfter ?? [];\n\tfor (let i = 0; i < after.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber + 1 + i;\n\t\tconst { text: contextText, wasTruncated: contextWasTruncated } = truncateLine(after[i] ?? \"\");\n\t\tif (contextWasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${contextText}`);\n\t}\n}\n\n/**\n * Shared \"measure -> pack -> notices\" tail for both the FFF and ripgrep result paths:\n * first-capture the raw output to an artifact if it's oversized and a store was provided\n * (Phase 3 tool-output-artifacts.md boundary rule), then append the same match-limit/\n * byte-limit/line-truncation/broad-query notices either path already produced.\n */\nfunction packGrepOutput(options: {\n\trawOutput: string;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n\tmatchLimitReached: number | false;\n\tlinesTruncated: boolean;\n}): { text: string; details: GrepToolDetails } {\n\tconst packed = packToolOutput(\n\t\t{\n\t\t\ttoolName: \"grep\",\n\t\t\tpath: options.rawPath,\n\t\t\trawContent: options.rawOutput,\n\t\t\t// No line limit here because the match limit already caps rows; only the byte\n\t\t\t// cap should apply, matching the pre-Slice-B truncateHead call exactly.\n\t\t\ttruncation: { maxLines: Number.MAX_SAFE_INTEGER },\n\t\t},\n\t\toptions.artifactStore,\n\t\toptions.toolCallId,\n\t);\n\tlet output = packed.content;\n\tconst details: GrepToolDetails = {};\n\n\tconst notices: string[] = [];\n\tif (packed.artifactId) {\n\t\tnotices.push(formatArtifactNotice(packed.artifactId));\n\t\tdetails.artifactId = packed.artifactId;\n\t}\n\tif (options.matchLimitReached) {\n\t\tnotices.push(\n\t\t\t`${options.matchLimitReached} matches limit reached. Use limit=${options.matchLimitReached * 2} for more, or refine pattern`,\n\t\t);\n\t\tdetails.matchLimitReached = options.matchLimitReached;\n\t}\n\tif (packed.truncation.truncated) {\n\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t// Drop the duplicated bounded-preview text: it's already in the message's own\n\t\t// content, and re-including it here can push `details` past\n\t\t// MAX_RETAINED_TOOL_RESULT_DETAILS_BYTES (message-retention.ts), which replaces\n\t\t// the *entire* details object with a stub -- silently losing artifactId and every\n\t\t// other field alongside it. This is load-bearing beyond just the retention budget:\n\t\t// agent-session.ts's _releaseGcPackedArtifactReferences() reads artifactId back off\n\t\t// this same canonical message at eviction time (potentially many turns later), so\n\t\t// keeping `details` small here is what keeps that release path working at all. If\n\t\t// this field ever grows a large addition again, add a regression proving artifactId\n\t\t// survives compactToolResultDetailsForRetention (see\n\t\t// test/suite/agent-session-artifact-lifecycle.test.ts), not just a details-size check.\n\t\tdetails.truncation = { ...packed.truncation, content: \"\" };\n\t}\n\tif (options.linesTruncated) {\n\t\tnotices.push(`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`);\n\t\tdetails.linesTruncated = true;\n\t}\n\tif (options.matchLimitReached || packed.truncation.truncated) {\n\t\tconst note = broadQueryInvalidationNote(\n\t\t\toptions.broadQueryTracker,\n\t\t\tnormalizeBroadQueryKey({\n\t\t\t\ttoolName: \"grep\",\n\t\t\t\tpattern: options.pattern,\n\t\t\t\tpath: options.rawPath,\n\t\t\t\tglob: options.glob,\n\t\t\t}),\n\t\t\t`grep \"${options.pattern}\" in ${options.rawPath ?? \".\"}`,\n\t\t);\n\t\tif (note) {\n\t\t\tnotices.push(note);\n\t\t\tdetails.invalidationCandidate = true;\n\t\t}\n\t}\n\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\treturn { text: output, details };\n}\n\nfunction formatFffGrepResult(options: {\n\tresult: FffGrepResult;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n\teffectiveLimit: number;\n\tcontextValue: number;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n}): { text: string; details: GrepToolDetails } {\n\tif (options.result.items.length === 0) return { text: \"No matches found\", details: {} };\n\n\tconst outputLines: string[] = [];\n\tconst linesTruncated = { value: false };\n\tlet currentPath = \"\";\n\tfor (const match of options.result.items) {\n\t\tconst displayPath = fffDisplayPath(match, options);\n\t\tif (!displayPath) continue;\n\t\tif (displayPath !== currentPath) {\n\t\t\tcurrentPath = displayPath;\n\t\t\toutputLines.push(`${displayPath}:`);\n\t\t}\n\t\tappendFffMatchLines({\n\t\t\tmatch,\n\t\t\toutputLines,\n\t\t\tlinesTruncated,\n\t\t\tcontextValue: options.contextValue,\n\t\t});\n\t}\n\n\tif (outputLines.length === 0) return { text: \"No matches found\", details: {} };\n\tconst rawOutput = outputLines.join(\"\\n\");\n\treturn packGrepOutput({\n\t\trawOutput,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t\tmatchLimitReached: options.result.nextCursor ? options.effectiveLimit : false,\n\t\tlinesTruncated: linesTruncated.value,\n\t});\n}\n\nexport async function tryFffGrep(options: {\n\tbackend: FffSearchBackend;\n\trouter: SearchRouter;\n\tcwd: string;\n\tsearchPath: string;\n\tpattern: string;\n\tglob?: string;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\tcontextValue: number;\n\teffectiveLimit: number;\n\tisDirectory: boolean;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\trawPath?: string;\n}): Promise<{ text: string; details: GrepToolDetails } | undefined> {\n\t// Kick off the FFF finder -- and, on a machine where fff-node isn't provisioned\n\t// yet, its lazy managed install -- unconditionally and as early as possible.\n\t// See the matching comment in find.ts's tryFffFind: routing below can still\n\t// send THIS call to the rg fallback for reasons unrelated to tool availability\n\t// (chiefly the default match limit exceeding the FFF top-N threshold), and\n\t// that outcome must not gate the install itself. getFinder() is cached per\n\t// basePath, so later calls -- including the `await` below -- reuse this same\n\t// in-flight/resolved promise instead of doing the work twice. safeGetFinder()\n\t// guarantees this can never reject (a non-conforming custom backend that\n\t// throws synchronously still degrades to \"unavailable\"), so it can neither\n\t// produce an unhandled rejection nor fail this tool call outright.\n\tconst finderPromise = safeGetFinder(options.backend, options.cwd);\n\n\tconst searchPathRelativeToCwd = relativePathInside(options.cwd, options.searchPath);\n\tconst baseRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: searchPathRelativeToCwd !== undefined,\n\t\tgitignoreInTree: false,\n\t});\n\tif (baseRoute.backend !== \"fff\") return undefined;\n\tif (searchPathRelativeToCwd === undefined) return undefined;\n\n\tconst gitignoreInTree = options.isDirectory ? await hasGitignoreInTree(options.searchPath) : false;\n\tconst semanticRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: true,\n\t\tgitignoreInTree,\n\t});\n\tif (semanticRoute.backend !== \"fff\") return undefined;\n\n\tconst finder = await finderPromise;\n\tconst finderRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: Boolean(finder),\n\t\tpathResolvable: true,\n\t\tgitignoreInTree: false,\n\t});\n\tif (!finder || finderRoute.backend !== \"fff\") return undefined;\n\n\tconst query = fffGrepQuery({\n\t\tpattern: options.pattern,\n\t\tglob: options.glob,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t});\n\tif (!query) return undefined;\n\n\tconst result = finder.grep(query, {\n\t\tmode: options.literal ? \"plain\" : \"regex\",\n\t\tsmartCase: false,\n\t\tmaxMatchesPerFile: options.effectiveLimit,\n\t\tbeforeContext: options.contextValue,\n\t\tafterContext: options.contextValue,\n\t\tpageSize: options.effectiveLimit,\n\t});\n\tif (!result.ok || result.value.regexFallbackError) return undefined;\n\treturn formatFffGrepResult({\n\t\tresult: result.value,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t\teffectiveLimit: options.effectiveLimit,\n\t\tcontextValue: options.contextValue,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t});\n}\n\nexport function createGrepToolDefinition(\n\tcwd: string,\n\toptions?: GrepToolOptions,\n): ToolDefinition<typeof grepSchema, GrepToolDetails | undefined> {\n\tconst customOps = options?.operations;\n\tconst fffBackend = options?.fff === false ? undefined : (options?.fff ?? defaultFffSearchBackend);\n\tconst searchRouter = options?.searchRouter ?? defaultSearchRouter;\n\tconst artifactStore = options?.artifactStore;\n\tconst broadQueryTracker = options?.broadQueryTracker;\n\treturn {\n\t\tname: \"grep\",\n\t\tlabel: \"grep\",\n\t\tdescription: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} matches or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH} chars.`,\n\t\tpromptSnippet: \"Search file contents for patterns (respects .gitignore)\",\n\t\tparameters: grepSchema,\n\t\ttoolGroup: \"explore\",\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tglob,\n\t\t\t\tignoreCase,\n\t\t\t\tliteral,\n\t\t\t\tcontext,\n\t\t\t\tlimit,\n\t\t\t}: {\n\t\t\t\tpattern: string;\n\t\t\t\tpath?: string;\n\t\t\t\tglob?: string;\n\t\t\t\tignoreCase?: boolean;\n\t\t\t\tliteral?: boolean;\n\t\t\t\tcontext?: number;\n\t\t\t\tlimit?: number;\n\t\t\t},\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (!settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tfn();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tconst ops = customOps ?? defaultGrepOperations;\n\t\t\t\t\t\tlet isDirectory: boolean;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tisDirectory = await ops.isDirectory(searchPath);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contextValue = context && context > 0 ? context : 0;\n\t\t\t\t\t\tconst effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT);\n\t\t\t\t\t\tconst formatPath = (filePath: string): string => {\n\t\t\t\t\t\t\tif (isDirectory) {\n\t\t\t\t\t\t\t\tconst relative = path.relative(searchPath, filePath);\n\t\t\t\t\t\t\t\tif (relative && !relative.startsWith(\"..\")) {\n\t\t\t\t\t\t\t\t\treturn relative.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn path.basename(filePath);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (!customOps && fffBackend) {\n\t\t\t\t\t\t\tconst fffResult = await tryFffGrep({\n\t\t\t\t\t\t\t\tbackend: fffBackend,\n\t\t\t\t\t\t\t\trouter: searchRouter,\n\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\tsearchPath,\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\tliteral,\n\t\t\t\t\t\t\t\tcontextValue,\n\t\t\t\t\t\t\t\teffectiveLimit,\n\t\t\t\t\t\t\t\tisDirectory,\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (fffResult) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: fffResult.text }],\n\t\t\t\t\t\t\t\t\t\tdetails: Object.keys(fffResult.details).length > 0 ? fffResult.details : undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgPath = await ensureTool(\"rg\", true);\n\t\t\t\t\t\tif (!rgPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst fileCache = new Map<string, string[]>();\n\t\t\t\t\t\tconst getFileLines = async (filePath: string): Promise<string[]> => {\n\t\t\t\t\t\t\tlet lines = fileCache.get(filePath);\n\t\t\t\t\t\t\tif (!lines) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst content = await ops.readFile(filePath);\n\t\t\t\t\t\t\t\t\tlines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tlines = [];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfileCache.set(filePath, lines);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn lines;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst args: string[] = [\"--json\", \"--line-number\", \"--color=never\", \"--hidden\"];\n\t\t\t\t\t\tif (ignoreCase) args.push(\"--ignore-case\");\n\t\t\t\t\t\tif (literal) args.push(\"--fixed-strings\");\n\t\t\t\t\t\tif (glob) args.push(\"--glob\", glob);\n\t\t\t\t\t\targs.push(\"--\", pattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(rgPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tlet matchCount = 0;\n\t\t\t\t\t\tlet matchLimitReached = false;\n\t\t\t\t\t\tlet linesTruncated = false;\n\t\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t\tlet killedDueToLimit = false;\n\t\t\t\t\t\tconst outputLines: string[] = [];\n\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst stopChild = (dueToLimit = false) => {\n\t\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\t\tkilledDueToLimit = dueToLimit;\n\t\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tstopChild();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst formatBlock = async (filePath: string, lineNumber: number): Promise<string[]> => {\n\t\t\t\t\t\t\tconst relativePath = formatPath(filePath);\n\t\t\t\t\t\t\tconst lines = await getFileLines(filePath);\n\t\t\t\t\t\t\tif (!lines.length) return [`${relativePath}:${lineNumber}: (unable to read file)`];\n\t\t\t\t\t\t\tconst block: string[] = [];\n\t\t\t\t\t\t\tconst start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber;\n\t\t\t\t\t\t\tconst end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;\n\t\t\t\t\t\t\tfor (let current = start; current <= end; current++) {\n\t\t\t\t\t\t\t\tconst lineText = lines[current - 1] ?? \"\";\n\t\t\t\t\t\t\t\tconst sanitized = lineText.replace(/\\r/g, \"\");\n\t\t\t\t\t\t\t\tconst isMatchLine = current === lineNumber;\n\t\t\t\t\t\t\t\t// Truncate long lines so grep output stays compact.\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tif (isMatchLine) block.push(`${relativePath}:${current}: ${truncatedText}`);\n\t\t\t\t\t\t\t\telse block.push(`${relativePath}-${current}- ${truncatedText}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn block;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// Collect matches during streaming, then format them after rg exits.\n\t\t\t\t\t\tconst matches: Array<{ filePath: string; lineNumber: number; lineText?: string }> = [];\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tif (!line.trim() || matchCount >= effectiveLimit) return;\n\t\t\t\t\t\t\tlet event: any;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tevent = JSON.parse(line);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"match\") {\n\t\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t\t\tconst filePath = event.data?.path?.text;\n\t\t\t\t\t\t\t\tconst lineNumber = event.data?.line_number;\n\t\t\t\t\t\t\t\tconst lineText = event.data?.lines?.text;\n\t\t\t\t\t\t\t\tif (filePath && typeof lineNumber === \"number\")\n\t\t\t\t\t\t\t\t\tmatches.push({ filePath, lineNumber, lineText });\n\t\t\t\t\t\t\t\tif (matchCount >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\t\t\t\t\tstopChild(true);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Failed to run ripgrep: ${error.message}`)));\n\t\t\t\t\t\t});\n\t\t\t\t\t\tchild.on(\"close\", async (code) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!killedDueToLimit && code !== 0 && code !== 1) {\n\t\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (matchCount === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Format matches after streaming finishes so custom readFile() backends can be async.\n\t\t\t\t\t\t\tconst fileGroups = new Map<string, string[]>();\n\t\t\t\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\t\tif (!fileGroups.has(relativePath)) {\n\t\t\t\t\t\t\t\t\tfileGroups.set(relativePath, []);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst group = fileGroups.get(relativePath)!;\n\n\t\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\t\tconst sanitized = match.lineText\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r\\n/g, \"\\n\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r/g, \"\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\t\tgroup.push(` ${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\t\tfor (const line of block) {\n\t\t\t\t\t\t\t\t\t\tif (line.startsWith(`${relativePath}:`)) {\n\t\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t\t} else if (line.startsWith(`${relativePath}-`)) {\n\t\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line}`);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tfor (const [relativePath, lines] of fileGroups) {\n\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:`);\n\t\t\t\t\t\t\t\tlet lastLine = \"\";\n\t\t\t\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\t\t\t\tif (line === lastLine) continue;\n\t\t\t\t\t\t\t\t\toutputLines.push(line);\n\t\t\t\t\t\t\t\t\tlastLine = line;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t\t// Measure -> pack (artifact-backed if oversized and a store was provided) -> notices.\n\t\t\t\t\t\t\t// There is no line limit here because the match limit already capped rows.\n\t\t\t\t\t\t\tconst { text: output, details } = packGrepOutput({\n\t\t\t\t\t\t\t\trawOutput,\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tmatchLimitReached: matchLimitReached ? effectiveLimit : false,\n\t\t\t\t\t\t\t\tlinesTruncated,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tsettle(() => reject(err as Error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepCall(args, theme, context.cwd));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createGrepTool(cwd: string, options?: GrepToolOptions): AgentTool<typeof grepSchema> {\n\treturn wrapToolDefinition(createGrepToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAIN,KAAK,gBAAgB,EAErB,MAAM,gCAAgC,CAAC;AAIxC,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EACN,KAAK,iBAAiB,EAKtB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAIN,KAAK,gBAAgB,EAIrB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAG5E,QAAA,MAAM,UAAU;;;;;;;;EAYd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAGtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,mEAAmE;IACnE,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAClE,2CAA2C;IAC3C,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC7D;AAOD,MAAM,WAAW,eAAe;IAC/B,sFAAsF;IACtF,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,oFAAoF;IACpF,GAAG,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;IAC/B,qFAAqF;IACrF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,yFAAyF;IACzF,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACtC;AA0PD,wBAAsB,UAAU,CAAC,OAAO,EAAE;IACzC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GAAG,SAAS,CAAC,CAiFlE;AAED,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CA+ShE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG","sourcesContent":["import { readFile as fsReadFile, stat as fsStat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateLine,\n} from \"@caupulican/pi-agent-core/node\";\nimport { Text } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ArtifactStore } from \"../context/context-artifacts.ts\";\nimport {\n\ttype BroadQueryTracker,\n\tbroadQueryInvalidationNote,\n\tformatArtifactNotice,\n\tnormalizeBroadQueryKey,\n\tpackToolOutput,\n} from \"../context/tool-output-packer.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport {\n\tdefaultFffSearchBackend,\n\ttype FffGrepMatch,\n\ttype FffGrepResult,\n\ttype FffSearchBackend,\n\thasGitignoreInTree,\n\trelativePathInside,\n\tsafeGetFinder,\n} from \"./fff-search-backend.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { defaultSearchRouter, type SearchRouter } from \"./search-router.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: \"Search pattern (regex or literal string)\" }),\n\tpath: Type.Optional(Type.String({ description: \"Directory or file to search (default: current directory)\" })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n\tliteral: Type.Optional(\n\t\tType.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" }),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Number({ description: \"Number of lines to show before and after each match (default: 0)\" }),\n\t),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of matches to return (default: 100)\" })),\n});\n\nexport type GrepToolInput = Static<typeof grepSchema>;\nconst DEFAULT_LIMIT = 100;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n\t/** Set only when output was packed to an artifact; see tool-output-packer.ts. */\n\tartifactId?: string;\n\t/** Set when this exact query has repeatedly produced broad/truncated results. */\n\tinvalidationCandidate?: boolean;\n}\n\n/**\n * Pluggable operations for the grep tool.\n * Override these to delegate search to remote systems (for example SSH).\n */\nexport interface GrepOperations {\n\t/** Check if path is a directory. Throws if path does not exist. */\n\tisDirectory: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Read file contents for context lines */\n\treadFile: (absolutePath: string) => Promise<string> | string;\n}\n\nconst defaultGrepOperations: GrepOperations = {\n\tisDirectory: async (p) => (await fsStat(p)).isDirectory(),\n\treadFile: (p) => fsReadFile(p, \"utf-8\"),\n};\n\nexport interface GrepToolOptions {\n\t/** Custom operations for grep. Default: local filesystem plus routed FFF/rg search */\n\toperations?: GrepOperations;\n\t/** FFF backend for resident indexed search. Set false to force ripgrep fallback. */\n\tfff?: FffSearchBackend | false;\n\t/** Pure router that selects FFF or rg from request filters and environment facts. */\n\tsearchRouter?: SearchRouter;\n\t/**\n\t * Opt-in artifact store for first-capture-then-bound output packing (Phase 3). When\n\t * omitted (the default), behavior is byte-for-byte unchanged from before this option\n\t * existed: output is truncated the same way, just never artifact-backed.\n\t */\n\tartifactStore?: ArtifactStore;\n\t/** Opt-in tracker for repeated-broad-query \"do not repeat\" signals. Also default-off. */\n\tbroadQueryTracker?: BroadQueryTracker;\n}\n\nfunction formatGrepCall(\n\targs: { pattern: string; path?: string; glob?: string; limit?: number } | undefined,\n\ttheme: Theme,\n\tcwd: string,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\", cwd) : null;\n\tconst glob = str(args?.glob);\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", `/${pattern || \"\"}/`)) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (glob) text += theme.fg(\"toolOutput\", ` (${glob})`);\n\tif (limit !== undefined) text += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\treturn text;\n}\n\nfunction formatGrepResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: GrepToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 15;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst matchLimit = result.details?.matchLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst linesTruncated = result.details?.linesTruncated;\n\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (matchLimit) warnings.push(`${matchLimit} matches limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\tif (linesTruncated) warnings.push(\"some lines truncated\");\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nfunction globConstraintForFff(glob: string | undefined): string {\n\tif (!glob) return \"\";\n\tif (glob.includes(\"/\") || glob.startsWith(\"**/\")) return glob;\n\treturn `**/${glob}`;\n}\n\nfunction fffGrepQuery(options: {\n\tpattern: string;\n\tglob?: string;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n}): string | undefined {\n\tconst parts: string[] = [];\n\tif (options.searchPathRelativeToCwd) {\n\t\tparts.push(options.isDirectory ? `${options.searchPathRelativeToCwd}/` : options.searchPathRelativeToCwd);\n\t}\n\tparts.push(globConstraintForFff(options.glob));\n\tparts.push(options.pattern);\n\treturn parts.filter(Boolean).join(\" \");\n}\n\nfunction fffDisplayPath(\n\tmatch: FffGrepMatch,\n\toptions: { isDirectory: boolean; searchPathRelativeToCwd: string },\n): string | undefined {\n\tif (!options.searchPathRelativeToCwd) return match.relativePath;\n\tif (!options.isDirectory) {\n\t\treturn match.relativePath === options.searchPathRelativeToCwd ? path.basename(match.relativePath) : undefined;\n\t}\n\tconst prefix = `${options.searchPathRelativeToCwd}/`;\n\tif (!match.relativePath.startsWith(prefix)) return undefined;\n\treturn match.relativePath.slice(prefix.length);\n}\n\nfunction appendFffMatchLines(options: {\n\tmatch: FffGrepMatch;\n\toutputLines: string[];\n\tlinesTruncated: { value: boolean };\n\tcontextValue: number;\n}): void {\n\tconst before = options.match.contextBefore ?? [];\n\tfor (let i = 0; i < before.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber - before.length + i;\n\t\tconst { text, wasTruncated } = truncateLine(before[i] ?? \"\");\n\t\tif (wasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${text}`);\n\t}\n\n\tconst { text, wasTruncated } = truncateLine(options.match.lineContent.replace(/\\r/g, \"\"));\n\tif (wasTruncated) options.linesTruncated.value = true;\n\toptions.outputLines.push(` ${options.match.lineNumber}: ${text}`);\n\n\tif (options.contextValue === 0) return;\n\tconst after = options.match.contextAfter ?? [];\n\tfor (let i = 0; i < after.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber + 1 + i;\n\t\tconst { text: contextText, wasTruncated: contextWasTruncated } = truncateLine(after[i] ?? \"\");\n\t\tif (contextWasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${contextText}`);\n\t}\n}\n\n/**\n * Shared \"measure -> pack -> notices\" tail for both the FFF and ripgrep result paths:\n * first-capture the raw output to an artifact if it's oversized and a store was provided\n * (Phase 3 tool-output-artifacts.md boundary rule), then append the same match-limit/\n * byte-limit/line-truncation/broad-query notices either path already produced.\n */\nfunction packGrepOutput(options: {\n\trawOutput: string;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n\tmatchLimitReached: number | false;\n\tlinesTruncated: boolean;\n}): { text: string; details: GrepToolDetails } {\n\tconst packed = packToolOutput(\n\t\t{\n\t\t\ttoolName: \"grep\",\n\t\t\tpath: options.rawPath,\n\t\t\trawContent: options.rawOutput,\n\t\t\t// No line limit here because the match limit already caps rows; only the byte\n\t\t\t// cap should apply, matching the pre-Slice-B truncateHead call exactly.\n\t\t\ttruncation: { maxLines: Number.MAX_SAFE_INTEGER },\n\t\t},\n\t\toptions.artifactStore,\n\t\toptions.toolCallId,\n\t);\n\tlet output = packed.content;\n\tconst details: GrepToolDetails = {};\n\n\tconst notices: string[] = [];\n\tif (packed.artifactId) {\n\t\tnotices.push(formatArtifactNotice(packed.artifactId));\n\t\tdetails.artifactId = packed.artifactId;\n\t}\n\tif (options.matchLimitReached) {\n\t\tnotices.push(\n\t\t\t`${options.matchLimitReached} matches limit reached. Use limit=${options.matchLimitReached * 2} for more, or refine pattern`,\n\t\t);\n\t\tdetails.matchLimitReached = options.matchLimitReached;\n\t}\n\tif (packed.truncation.truncated) {\n\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t// Drop the duplicated bounded-preview text: it's already in the message's own\n\t\t// content, and re-including it here can push `details` past\n\t\t// MAX_RETAINED_TOOL_RESULT_DETAILS_BYTES (message-retention.ts), which replaces\n\t\t// the *entire* details object with a stub -- silently losing artifactId and every\n\t\t// other field alongside it. This is load-bearing beyond just the retention budget:\n\t\t// agent-session.ts's _releaseGcPackedArtifactReferences() reads artifactId back off\n\t\t// this same canonical message at eviction time (potentially many turns later), so\n\t\t// keeping `details` small here is what keeps that release path working at all. If\n\t\t// this field ever grows a large addition again, add a regression proving artifactId\n\t\t// survives compactToolResultDetailsForRetention (see\n\t\t// test/suite/agent-session-artifact-lifecycle.test.ts), not just a details-size check.\n\t\tdetails.truncation = { ...packed.truncation, content: \"\" };\n\t}\n\tif (options.linesTruncated) {\n\t\tnotices.push(`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`);\n\t\tdetails.linesTruncated = true;\n\t}\n\tif (options.matchLimitReached || packed.truncation.truncated) {\n\t\tconst note = broadQueryInvalidationNote(\n\t\t\toptions.broadQueryTracker,\n\t\t\tnormalizeBroadQueryKey({\n\t\t\t\ttoolName: \"grep\",\n\t\t\t\tpattern: options.pattern,\n\t\t\t\tpath: options.rawPath,\n\t\t\t\tglob: options.glob,\n\t\t\t}),\n\t\t\t`grep \"${options.pattern}\" in ${options.rawPath ?? \".\"}`,\n\t\t);\n\t\tif (note) {\n\t\t\tnotices.push(note);\n\t\t\tdetails.invalidationCandidate = true;\n\t\t}\n\t}\n\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\treturn { text: output, details };\n}\n\nfunction formatFffGrepResult(options: {\n\tresult: FffGrepResult;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n\teffectiveLimit: number;\n\tcontextValue: number;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n}): { text: string; details: GrepToolDetails } {\n\tif (options.result.items.length === 0) return { text: \"No matches found\", details: {} };\n\n\tconst outputLines: string[] = [];\n\tconst linesTruncated = { value: false };\n\tlet currentPath = \"\";\n\tfor (const match of options.result.items) {\n\t\tconst displayPath = fffDisplayPath(match, options);\n\t\tif (!displayPath) continue;\n\t\tif (displayPath !== currentPath) {\n\t\t\tcurrentPath = displayPath;\n\t\t\toutputLines.push(`${displayPath}:`);\n\t\t}\n\t\tappendFffMatchLines({\n\t\t\tmatch,\n\t\t\toutputLines,\n\t\t\tlinesTruncated,\n\t\t\tcontextValue: options.contextValue,\n\t\t});\n\t}\n\n\tif (outputLines.length === 0) return { text: \"No matches found\", details: {} };\n\tconst rawOutput = outputLines.join(\"\\n\");\n\treturn packGrepOutput({\n\t\trawOutput,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t\tmatchLimitReached: options.result.nextCursor ? options.effectiveLimit : false,\n\t\tlinesTruncated: linesTruncated.value,\n\t});\n}\n\nexport async function tryFffGrep(options: {\n\tbackend: FffSearchBackend;\n\trouter: SearchRouter;\n\tcwd: string;\n\tsearchPath: string;\n\tpattern: string;\n\tglob?: string;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\tcontextValue: number;\n\teffectiveLimit: number;\n\tisDirectory: boolean;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\trawPath?: string;\n}): Promise<{ text: string; details: GrepToolDetails } | undefined> {\n\t// Kick off the FFF finder -- and, on a machine where fff-node isn't provisioned\n\t// yet, its lazy managed install -- unconditionally and as early as possible.\n\t// See the matching comment in find.ts's tryFffFind: routing below can still\n\t// send THIS call to the rg fallback for reasons unrelated to tool availability\n\t// (chiefly the default match limit exceeding the FFF top-N threshold), and\n\t// that outcome must not gate the install itself. getFinder() is cached per\n\t// basePath, so later calls -- including the `await` below -- reuse this same\n\t// in-flight/resolved promise instead of doing the work twice. safeGetFinder()\n\t// guarantees this can never reject (a non-conforming custom backend that\n\t// throws synchronously still degrades to \"unavailable\"), so it can neither\n\t// produce an unhandled rejection nor fail this tool call outright.\n\tconst finderPromise = safeGetFinder(options.backend, options.cwd);\n\n\tconst searchPathRelativeToCwd = relativePathInside(options.cwd, options.searchPath);\n\tconst baseRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: searchPathRelativeToCwd !== undefined,\n\t\tgitignoreInTree: false,\n\t});\n\tif (baseRoute.backend !== \"fff\") return undefined;\n\tif (searchPathRelativeToCwd === undefined) return undefined;\n\n\tconst gitignoreInTree = options.isDirectory ? await hasGitignoreInTree(options.searchPath) : false;\n\tconst semanticRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: true,\n\t\tgitignoreInTree,\n\t});\n\tif (semanticRoute.backend !== \"fff\") return undefined;\n\n\tconst finder = await finderPromise;\n\tconst finderRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: Boolean(finder),\n\t\tpathResolvable: true,\n\t\tgitignoreInTree: false,\n\t});\n\tif (!finder || finderRoute.backend !== \"fff\") return undefined;\n\n\tconst query = fffGrepQuery({\n\t\tpattern: options.pattern,\n\t\tglob: options.glob,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t});\n\tif (!query) return undefined;\n\n\tconst result = finder.grep(query, {\n\t\tmode: options.literal ? \"plain\" : \"regex\",\n\t\tsmartCase: false,\n\t\tmaxMatchesPerFile: options.effectiveLimit,\n\t\tbeforeContext: options.contextValue,\n\t\tafterContext: options.contextValue,\n\t\tpageSize: options.effectiveLimit,\n\t});\n\tif (!result.ok || result.value.regexFallbackError) return undefined;\n\treturn formatFffGrepResult({\n\t\tresult: result.value,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t\teffectiveLimit: options.effectiveLimit,\n\t\tcontextValue: options.contextValue,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t});\n}\n\nexport function createGrepToolDefinition(\n\tcwd: string,\n\toptions?: GrepToolOptions,\n): ToolDefinition<typeof grepSchema, GrepToolDetails | undefined> {\n\tconst customOps = options?.operations;\n\tconst fffBackend = options?.fff === false ? undefined : (options?.fff ?? defaultFffSearchBackend);\n\tconst searchRouter = options?.searchRouter ?? defaultSearchRouter;\n\tconst artifactStore = options?.artifactStore;\n\tconst broadQueryTracker = options?.broadQueryTracker;\n\treturn {\n\t\tname: \"grep\",\n\t\tlabel: \"grep\",\n\t\tdescription: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} matches or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH} chars.`,\n\t\tpromptSnippet: \"Search file contents for patterns (respects .gitignore)\",\n\t\tparameters: grepSchema,\n\t\ttoolGroup: \"explore\",\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tglob,\n\t\t\t\tignoreCase,\n\t\t\t\tliteral,\n\t\t\t\tcontext,\n\t\t\t\tlimit,\n\t\t\t}: {\n\t\t\t\tpattern: string;\n\t\t\t\tpath?: string;\n\t\t\t\tglob?: string;\n\t\t\t\tignoreCase?: boolean;\n\t\t\t\tliteral?: boolean;\n\t\t\t\tcontext?: number;\n\t\t\t\tlimit?: number;\n\t\t\t},\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (!settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tfn();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tconst ops = customOps ?? defaultGrepOperations;\n\t\t\t\t\t\tlet isDirectory: boolean;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tisDirectory = await ops.isDirectory(searchPath);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contextValue = context && context > 0 ? context : 0;\n\t\t\t\t\t\tconst effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT);\n\t\t\t\t\t\tconst formatPath = (filePath: string): string => {\n\t\t\t\t\t\t\tif (isDirectory) {\n\t\t\t\t\t\t\t\tconst relative = path.relative(searchPath, filePath);\n\t\t\t\t\t\t\t\tif (relative && !relative.startsWith(\"..\")) {\n\t\t\t\t\t\t\t\t\treturn relative.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn path.basename(filePath);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (!customOps && fffBackend) {\n\t\t\t\t\t\t\tconst fffResult = await tryFffGrep({\n\t\t\t\t\t\t\t\tbackend: fffBackend,\n\t\t\t\t\t\t\t\trouter: searchRouter,\n\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\tsearchPath,\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\tliteral,\n\t\t\t\t\t\t\t\tcontextValue,\n\t\t\t\t\t\t\t\teffectiveLimit,\n\t\t\t\t\t\t\t\tisDirectory,\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (fffResult) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: fffResult.text }],\n\t\t\t\t\t\t\t\t\t\tdetails: Object.keys(fffResult.details).length > 0 ? fffResult.details : undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgPath = await ensureTool(\"rg\", true);\n\t\t\t\t\t\tif (!rgPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst fileCache = new Map<string, string[]>();\n\t\t\t\t\t\tconst getFileLines = async (filePath: string): Promise<string[]> => {\n\t\t\t\t\t\t\tlet lines = fileCache.get(filePath);\n\t\t\t\t\t\t\tif (!lines) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst content = await ops.readFile(filePath);\n\t\t\t\t\t\t\t\t\tlines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tlines = [];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfileCache.set(filePath, lines);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn lines;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst args: string[] = [\"--json\", \"--line-number\", \"--color=never\", \"--hidden\"];\n\t\t\t\t\t\tif (ignoreCase) args.push(\"--ignore-case\");\n\t\t\t\t\t\tif (literal) args.push(\"--fixed-strings\");\n\t\t\t\t\t\tif (glob) args.push(\"--glob\", glob);\n\t\t\t\t\t\targs.push(\"--\", pattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(rgPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tlet matchCount = 0;\n\t\t\t\t\t\tlet matchLimitReached = false;\n\t\t\t\t\t\tlet linesTruncated = false;\n\t\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t\tlet killedDueToLimit = false;\n\t\t\t\t\t\tconst outputLines: string[] = [];\n\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst stopChild = (dueToLimit = false) => {\n\t\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\t\tkilledDueToLimit = dueToLimit;\n\t\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tstopChild();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst formatBlock = async (filePath: string, lineNumber: number): Promise<string[]> => {\n\t\t\t\t\t\t\tconst relativePath = formatPath(filePath);\n\t\t\t\t\t\t\tconst lines = await getFileLines(filePath);\n\t\t\t\t\t\t\tif (!lines.length) return [`${relativePath}:${lineNumber}: (unable to read file)`];\n\t\t\t\t\t\t\tconst block: string[] = [];\n\t\t\t\t\t\t\tconst start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber;\n\t\t\t\t\t\t\tconst end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;\n\t\t\t\t\t\t\tfor (let current = start; current <= end; current++) {\n\t\t\t\t\t\t\t\tconst lineText = lines[current - 1] ?? \"\";\n\t\t\t\t\t\t\t\tconst sanitized = lineText.replace(/\\r/g, \"\");\n\t\t\t\t\t\t\t\tconst isMatchLine = current === lineNumber;\n\t\t\t\t\t\t\t\t// Truncate long lines so grep output stays compact.\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tif (isMatchLine) block.push(`${relativePath}:${current}: ${truncatedText}`);\n\t\t\t\t\t\t\t\telse block.push(`${relativePath}-${current}- ${truncatedText}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn block;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// Collect matches during streaming, then format them after rg exits.\n\t\t\t\t\t\tconst matches: Array<{ filePath: string; lineNumber: number; lineText?: string }> = [];\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tif (!line.trim() || matchCount >= effectiveLimit) return;\n\t\t\t\t\t\t\tlet event: any;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tevent = JSON.parse(line);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"match\") {\n\t\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t\t\tconst filePath = event.data?.path?.text;\n\t\t\t\t\t\t\t\tconst lineNumber = event.data?.line_number;\n\t\t\t\t\t\t\t\tconst lineText = event.data?.lines?.text;\n\t\t\t\t\t\t\t\tif (filePath && typeof lineNumber === \"number\")\n\t\t\t\t\t\t\t\t\tmatches.push({ filePath, lineNumber, lineText });\n\t\t\t\t\t\t\t\tif (matchCount >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\t\t\t\t\tstopChild(true);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Failed to run ripgrep: ${error.message}`)));\n\t\t\t\t\t\t});\n\t\t\t\t\t\tchild.on(\"close\", async (code) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!killedDueToLimit && code !== 0 && code !== 1) {\n\t\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (matchCount === 0) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Format matches after streaming finishes so custom readFile() backends can be async.\n\t\t\t\t\t\t\tconst fileGroups = new Map<string, string[]>();\n\t\t\t\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\t\tif (!fileGroups.has(relativePath)) {\n\t\t\t\t\t\t\t\t\tfileGroups.set(relativePath, []);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst group = fileGroups.get(relativePath)!;\n\n\t\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\t\tconst sanitized = match.lineText\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r\\n/g, \"\\n\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r/g, \"\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\t\tgroup.push(` ${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\t\tfor (const line of block) {\n\t\t\t\t\t\t\t\t\t\tif (line.startsWith(`${relativePath}:`)) {\n\t\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t\t} else if (line.startsWith(`${relativePath}-`)) {\n\t\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line}`);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tfor (const [relativePath, lines] of fileGroups) {\n\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:`);\n\t\t\t\t\t\t\t\tlet lastLine = \"\";\n\t\t\t\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\t\t\t\tif (line === lastLine) continue;\n\t\t\t\t\t\t\t\t\toutputLines.push(line);\n\t\t\t\t\t\t\t\t\tlastLine = line;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t\t// Measure -> pack (artifact-backed if oversized and a store was provided) -> notices.\n\t\t\t\t\t\t\t// There is no line limit here because the match limit already capped rows.\n\t\t\t\t\t\t\tconst { text: output, details } = packGrepOutput({\n\t\t\t\t\t\t\t\trawOutput,\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tmatchLimitReached: matchLimitReached ? effectiveLimit : false,\n\t\t\t\t\t\t\t\tlinesTruncated,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tsettle(() => reject(err as Error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepCall(args, theme, context.cwd));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createGrepTool(cwd: string, options?: GrepToolOptions): AgentTool<typeof grepSchema> {\n\treturn wrapToolDefinition(createGrepToolDefinition(cwd, options));\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { readFile as fsReadFile, stat as fsStat } from "node:fs/promises";
2
2
  import { createInterface } from "node:readline";
3
+ import { DEFAULT_MAX_BYTES, formatSize, GREP_MAX_LINE_LENGTH, truncateLine, } from "@caupulican/pi-agent-core/node";
3
4
  import { Text } from "@caupulican/pi-tui";
4
5
  import { spawn } from "child_process";
5
6
  import path from "path";
@@ -12,7 +13,6 @@ import { resolveToCwd } from "./path-utils.js";
12
13
  import { getTextOutput, invalidArgText, shortenPath, str } from "./render-utils.js";
13
14
  import { defaultSearchRouter } from "./search-router.js";
14
15
  import { wrapToolDefinition } from "./tool-definition-wrapper.js";
15
- import { DEFAULT_MAX_BYTES, formatSize, GREP_MAX_LINE_LENGTH, truncateLine, } from "./truncate.js";
16
16
  const grepSchema = Type.Object({
17
17
  pattern: Type.String({ description: "Search pattern (regex or literal string)" }),
18
18
  path: Type.Optional(Type.String({ description: "Directory or file to search (default: current directory)" })),