@kolisachint/hoocode-agent 0.4.162 → 0.4.164

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/cli/args.d.ts +0 -6
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +0 -31
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/config.d.ts +0 -40
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +4 -50
  9. package/dist/config.js.map +1 -1
  10. package/dist/core/agent-frontmatter.d.ts +0 -28
  11. package/dist/core/agent-frontmatter.d.ts.map +1 -1
  12. package/dist/core/agent-frontmatter.js +0 -6
  13. package/dist/core/agent-frontmatter.js.map +1 -1
  14. package/dist/core/agent-session-services.d.ts +0 -2
  15. package/dist/core/agent-session-services.d.ts.map +1 -1
  16. package/dist/core/agent-session-services.js +0 -2
  17. package/dist/core/agent-session-services.js.map +1 -1
  18. package/dist/core/agent-session.d.ts.map +1 -1
  19. package/dist/core/agent-session.js +0 -2
  20. package/dist/core/agent-session.js.map +1 -1
  21. package/dist/core/auth-guidance.d.ts +0 -1
  22. package/dist/core/auth-guidance.d.ts.map +1 -1
  23. package/dist/core/auth-guidance.js +1 -1
  24. package/dist/core/auth-guidance.js.map +1 -1
  25. package/dist/core/embsearch/chunker.d.ts +0 -2
  26. package/dist/core/embsearch/chunker.d.ts.map +1 -1
  27. package/dist/core/embsearch/chunker.js +1 -1
  28. package/dist/core/embsearch/chunker.js.map +1 -1
  29. package/dist/core/embsearch/index-meta.d.ts +0 -2
  30. package/dist/core/embsearch/index-meta.d.ts.map +1 -1
  31. package/dist/core/embsearch/index-meta.js +0 -6
  32. package/dist/core/embsearch/index-meta.js.map +1 -1
  33. package/dist/core/export-html/ansi-to-html.d.ts +0 -4
  34. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  35. package/dist/core/export-html/ansi-to-html.js +1 -1
  36. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  37. package/dist/core/extensions/index.d.ts +3 -3
  38. package/dist/core/extensions/index.d.ts.map +1 -1
  39. package/dist/core/extensions/index.js +1 -1
  40. package/dist/core/extensions/index.js.map +1 -1
  41. package/dist/core/extensions/plugins/authoring.d.ts +2 -2
  42. package/dist/core/extensions/plugins/authoring.d.ts.map +1 -1
  43. package/dist/core/extensions/plugins/authoring.js +0 -0
  44. package/dist/core/extensions/plugins/authoring.js.map +1 -1
  45. package/dist/core/extensions/plugins/formats/index.d.ts +2 -6
  46. package/dist/core/extensions/plugins/formats/index.d.ts.map +1 -1
  47. package/dist/core/extensions/plugins/formats/index.js +2 -3
  48. package/dist/core/extensions/plugins/formats/index.js.map +1 -1
  49. package/dist/core/extensions/plugins/formats/shared.d.ts +0 -2
  50. package/dist/core/extensions/plugins/formats/shared.d.ts.map +1 -1
  51. package/dist/core/extensions/plugins/formats/shared.js +1 -1
  52. package/dist/core/extensions/plugins/formats/shared.js.map +1 -1
  53. package/dist/core/extensions/plugins/formats/types.d.ts +4 -3
  54. package/dist/core/extensions/plugins/formats/types.d.ts.map +1 -1
  55. package/dist/core/extensions/plugins/formats/types.js.map +1 -1
  56. package/dist/core/extensions/plugins/install.d.ts +0 -2
  57. package/dist/core/extensions/plugins/install.d.ts.map +1 -1
  58. package/dist/core/extensions/plugins/install.js +1 -1
  59. package/dist/core/extensions/plugins/install.js.map +1 -1
  60. package/dist/core/extensions/plugins/manifest.d.ts +0 -6
  61. package/dist/core/extensions/plugins/manifest.d.ts.map +1 -1
  62. package/dist/core/extensions/plugins/manifest.js +0 -6
  63. package/dist/core/extensions/plugins/manifest.js.map +1 -1
  64. package/dist/core/extensions/plugins/marketplace.d.ts +3 -3
  65. package/dist/core/extensions/plugins/marketplace.d.ts.map +1 -1
  66. package/dist/core/extensions/plugins/marketplace.js.map +1 -1
  67. package/dist/core/extensions/types.d.ts +28 -28
  68. package/dist/core/extensions/types.d.ts.map +1 -1
  69. package/dist/core/extensions/types.js.map +1 -1
  70. package/dist/core/keybindings.d.ts +3 -3
  71. package/dist/core/keybindings.d.ts.map +1 -1
  72. package/dist/core/keybindings.js.map +1 -1
  73. package/dist/core/model-resolver.d.ts +0 -7
  74. package/dist/core/model-resolver.d.ts.map +1 -1
  75. package/dist/core/model-resolver.js +0 -56
  76. package/dist/core/model-resolver.js.map +1 -1
  77. package/dist/core/package-resource-discovery.d.ts +0 -10
  78. package/dist/core/package-resource-discovery.d.ts.map +1 -1
  79. package/dist/core/package-resource-discovery.js +7 -7
  80. package/dist/core/package-resource-discovery.js.map +1 -1
  81. package/dist/core/provider-health.d.ts +0 -2
  82. package/dist/core/provider-health.d.ts.map +1 -1
  83. package/dist/core/provider-health.js +1 -1
  84. package/dist/core/provider-health.js.map +1 -1
  85. package/dist/core/resolve-config-value.d.ts +0 -4
  86. package/dist/core/resolve-config-value.d.ts.map +1 -1
  87. package/dist/core/resolve-config-value.js +0 -15
  88. package/dist/core/resolve-config-value.js.map +1 -1
  89. package/dist/core/sdk.d.ts +3 -23
  90. package/dist/core/sdk.d.ts.map +1 -1
  91. package/dist/core/sdk.js +3 -5
  92. package/dist/core/sdk.js.map +1 -1
  93. package/dist/core/search/eval.d.ts +0 -3
  94. package/dist/core/search/eval.d.ts.map +1 -1
  95. package/dist/core/search/eval.js +1 -1
  96. package/dist/core/search/eval.js.map +1 -1
  97. package/dist/core/search/types.d.ts +2 -1
  98. package/dist/core/search/types.d.ts.map +1 -1
  99. package/dist/core/search/types.js.map +1 -1
  100. package/dist/core/session-cwd.d.ts +0 -1
  101. package/dist/core/session-cwd.d.ts.map +1 -1
  102. package/dist/core/session-cwd.js +1 -1
  103. package/dist/core/session-cwd.js.map +1 -1
  104. package/dist/core/settings-defaults.d.ts +0 -3
  105. package/dist/core/settings-defaults.d.ts.map +1 -1
  106. package/dist/core/settings-defaults.js +0 -3
  107. package/dist/core/settings-defaults.js.map +1 -1
  108. package/dist/core/settings-manager.d.ts +2 -9
  109. package/dist/core/settings-manager.d.ts.map +1 -1
  110. package/dist/core/settings-manager.js +0 -25
  111. package/dist/core/settings-manager.js.map +1 -1
  112. package/dist/core/settings-types.d.ts +9 -11
  113. package/dist/core/settings-types.d.ts.map +1 -1
  114. package/dist/core/settings-types.js.map +1 -1
  115. package/dist/core/subagent-inbox.d.ts +1 -3
  116. package/dist/core/subagent-inbox.d.ts.map +1 -1
  117. package/dist/core/subagent-inbox.js +1 -1
  118. package/dist/core/subagent-inbox.js.map +1 -1
  119. package/dist/core/subagent-pool.d.ts +0 -13
  120. package/dist/core/subagent-pool.d.ts.map +1 -1
  121. package/dist/core/subagent-pool.js +2 -2
  122. package/dist/core/subagent-pool.js.map +1 -1
  123. package/dist/core/task-store.d.ts +3 -3
  124. package/dist/core/task-store.d.ts.map +1 -1
  125. package/dist/core/task-store.js.map +1 -1
  126. package/dist/core/team-auto.d.ts +0 -2
  127. package/dist/core/team-auto.d.ts.map +1 -1
  128. package/dist/core/team-auto.js +1 -1
  129. package/dist/core/team-auto.js.map +1 -1
  130. package/dist/core/token-budget.d.ts +0 -13
  131. package/dist/core/token-budget.d.ts.map +1 -1
  132. package/dist/core/token-budget.js.map +1 -1
  133. package/dist/core/tools/bash.d.ts.map +1 -1
  134. package/dist/core/tools/bash.js +3 -1
  135. package/dist/core/tools/bash.js.map +1 -1
  136. package/dist/core/tools/edit-diff.d.ts +0 -38
  137. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  138. package/dist/core/tools/edit-diff.js +2 -9
  139. package/dist/core/tools/edit-diff.js.map +1 -1
  140. package/dist/core/tools/edit.d.ts.map +1 -1
  141. package/dist/core/tools/edit.js +5 -5
  142. package/dist/core/tools/edit.js.map +1 -1
  143. package/dist/core/tools/find.d.ts.map +1 -1
  144. package/dist/core/tools/find.js +8 -10
  145. package/dist/core/tools/find.js.map +1 -1
  146. package/dist/core/tools/grep.d.ts.map +1 -1
  147. package/dist/core/tools/grep.js +4 -4
  148. package/dist/core/tools/grep.js.map +1 -1
  149. package/dist/core/tools/index.d.ts +0 -24
  150. package/dist/core/tools/index.d.ts.map +1 -1
  151. package/dist/core/tools/index.js +0 -20
  152. package/dist/core/tools/index.js.map +1 -1
  153. package/dist/core/tools/ls.d.ts.map +1 -1
  154. package/dist/core/tools/ls.js +2 -2
  155. package/dist/core/tools/ls.js.map +1 -1
  156. package/dist/core/tools/native-search.d.ts +3 -2
  157. package/dist/core/tools/native-search.d.ts.map +1 -1
  158. package/dist/core/tools/native-search.js.map +1 -1
  159. package/dist/core/tools/path-utils.d.ts +0 -10
  160. package/dist/core/tools/path-utils.d.ts.map +1 -1
  161. package/dist/core/tools/path-utils.js +2 -2
  162. package/dist/core/tools/path-utils.js.map +1 -1
  163. package/dist/core/tools/plugins.d.ts +1 -20
  164. package/dist/core/tools/plugins.d.ts.map +1 -1
  165. package/dist/core/tools/plugins.js +2 -2
  166. package/dist/core/tools/plugins.js.map +1 -1
  167. package/dist/core/tools/propose-plugin.d.ts +0 -12
  168. package/dist/core/tools/propose-plugin.d.ts.map +1 -1
  169. package/dist/core/tools/propose-plugin.js +0 -1
  170. package/dist/core/tools/propose-plugin.js.map +1 -1
  171. package/dist/core/tools/read-dedup.d.ts +0 -2
  172. package/dist/core/tools/read-dedup.d.ts.map +1 -1
  173. package/dist/core/tools/read-dedup.js +1 -1
  174. package/dist/core/tools/read-dedup.js.map +1 -1
  175. package/dist/core/tools/read.d.ts.map +1 -1
  176. package/dist/core/tools/read.js +10 -8
  177. package/dist/core/tools/read.js.map +1 -1
  178. package/dist/core/tools/render-utils.d.ts +0 -5
  179. package/dist/core/tools/render-utils.d.ts.map +1 -1
  180. package/dist/core/tools/render-utils.js.map +1 -1
  181. package/dist/core/tools/search.d.ts +1 -4
  182. package/dist/core/tools/search.d.ts.map +1 -1
  183. package/dist/core/tools/search.js +6 -6
  184. package/dist/core/tools/search.js.map +1 -1
  185. package/dist/core/tools/webfetch.d.ts +1 -2
  186. package/dist/core/tools/webfetch.d.ts.map +1 -1
  187. package/dist/core/tools/webfetch.js.map +1 -1
  188. package/dist/core/tools/websearch.d.ts +1 -2
  189. package/dist/core/tools/websearch.d.ts.map +1 -1
  190. package/dist/core/tools/websearch.js.map +1 -1
  191. package/dist/core/tools/webtools-shared.d.ts +3 -5
  192. package/dist/core/tools/webtools-shared.d.ts.map +1 -1
  193. package/dist/core/tools/webtools-shared.js +1 -1
  194. package/dist/core/tools/webtools-shared.js.map +1 -1
  195. package/dist/core/warm-subagent-pool-instance.d.ts +0 -4
  196. package/dist/core/warm-subagent-pool-instance.d.ts.map +1 -1
  197. package/dist/core/warm-subagent-pool-instance.js +0 -10
  198. package/dist/core/warm-subagent-pool-instance.js.map +1 -1
  199. package/dist/core/wordmark.d.ts +1 -9
  200. package/dist/core/wordmark.d.ts.map +1 -1
  201. package/dist/core/wordmark.js +2 -26
  202. package/dist/core/wordmark.js.map +1 -1
  203. package/dist/extensions/core/config.d.ts +4 -3
  204. package/dist/extensions/core/config.d.ts.map +1 -1
  205. package/dist/extensions/core/config.js.map +1 -1
  206. package/dist/extensions/core/mcp-loader.d.ts +0 -18
  207. package/dist/extensions/core/mcp-loader.d.ts.map +1 -1
  208. package/dist/extensions/core/mcp-loader.js.map +1 -1
  209. package/dist/extensions/core/prompt-reactive/policy.d.ts +0 -8
  210. package/dist/extensions/core/prompt-reactive/policy.d.ts.map +1 -1
  211. package/dist/extensions/core/prompt-reactive/policy.js +1 -1
  212. package/dist/extensions/core/prompt-reactive/policy.js.map +1 -1
  213. package/dist/main.d.ts.map +1 -1
  214. package/dist/main.js +0 -30
  215. package/dist/main.js.map +1 -1
  216. package/dist/migrations.d.ts +0 -16
  217. package/dist/migrations.d.ts.map +1 -1
  218. package/dist/migrations.js +2 -2
  219. package/dist/migrations.js.map +1 -1
  220. package/dist/modes/interactive/brand.d.ts +0 -4
  221. package/dist/modes/interactive/brand.d.ts.map +1 -1
  222. package/dist/modes/interactive/brand.js +0 -4
  223. package/dist/modes/interactive/brand.js.map +1 -1
  224. package/dist/modes/interactive/components/index.d.ts +0 -4
  225. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  226. package/dist/modes/interactive/components/index.js +0 -5
  227. package/dist/modes/interactive/components/index.js.map +1 -1
  228. package/dist/modes/interactive/components/read-output.d.ts +0 -9
  229. package/dist/modes/interactive/components/read-output.d.ts.map +1 -1
  230. package/dist/modes/interactive/components/read-output.js +0 -20
  231. package/dist/modes/interactive/components/read-output.js.map +1 -1
  232. package/dist/modes/interactive/components/session-selector-search.d.ts +0 -17
  233. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  234. package/dist/modes/interactive/components/session-selector-search.js +2 -2
  235. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  236. package/dist/modes/interactive/components/settings-selector.d.ts +5 -14
  237. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  238. package/dist/modes/interactive/components/settings-selector.js +2 -2
  239. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  240. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  241. package/dist/modes/interactive/interactive-mode.js +0 -18
  242. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  243. package/dist/modes/interactive/login-controller.d.ts +1 -1
  244. package/dist/modes/interactive/login-controller.d.ts.map +1 -1
  245. package/dist/modes/interactive/login-controller.js +1 -1
  246. package/dist/modes/interactive/login-controller.js.map +1 -1
  247. package/dist/modes/interactive/resource-display.d.ts +0 -20
  248. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  249. package/dist/modes/interactive/resource-display.js +7 -7
  250. package/dist/modes/interactive/resource-display.js.map +1 -1
  251. package/dist/modes/interactive/theme/theme.d.ts +0 -4
  252. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  253. package/dist/modes/interactive/theme/theme.js +0 -7
  254. package/dist/modes/interactive/theme/theme.js.map +1 -1
  255. package/dist/modes/rpc/rpc-mode.d.ts +0 -1
  256. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  257. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  258. package/dist/modes/rpc/rpc-types.d.ts +0 -1
  259. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  260. package/dist/modes/rpc/rpc-types.js +3 -0
  261. package/dist/modes/rpc/rpc-types.js.map +1 -1
  262. package/dist/package-manager-cli.d.ts +0 -1
  263. package/dist/package-manager-cli.d.ts.map +1 -1
  264. package/dist/package-manager-cli.js.map +1 -1
  265. package/dist/utils/changelog.d.ts +0 -4
  266. package/dist/utils/changelog.d.ts.map +1 -1
  267. package/dist/utils/changelog.js +1 -1
  268. package/dist/utils/changelog.js.map +1 -1
  269. package/dist/utils/clipboard-native.d.ts +1 -1
  270. package/dist/utils/clipboard-native.d.ts.map +1 -1
  271. package/dist/utils/clipboard-native.js.map +1 -1
  272. package/dist/utils/paths.d.ts +0 -2
  273. package/dist/utils/paths.d.ts.map +1 -1
  274. package/dist/utils/paths.js +1 -1
  275. package/dist/utils/paths.js.map +1 -1
  276. package/dist/utils/plan/parser.d.ts +5 -4
  277. package/dist/utils/plan/parser.d.ts.map +1 -1
  278. package/dist/utils/plan/parser.js.map +1 -1
  279. package/dist/utils/tools-manager.d.ts +1 -2
  280. package/dist/utils/tools-manager.d.ts.map +1 -1
  281. package/dist/utils/tools-manager.js +2 -50
  282. package/dist/utils/tools-manager.js.map +1 -1
  283. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  284. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  285. package/examples/extensions/sandbox/package.json +1 -1
  286. package/examples/extensions/with-deps/package.json +1 -1
  287. package/package.json +4 -7
  288. package/dist/core/index.d.ts +0 -12
  289. package/dist/core/index.d.ts.map +0 -1
  290. package/dist/core/index.js +0 -12
  291. package/dist/core/index.js.map +0 -1
  292. package/dist/core/tools/browser/browser-continue.d.ts +0 -25
  293. package/dist/core/tools/browser/browser-continue.d.ts.map +0 -1
  294. package/dist/core/tools/browser/browser-continue.js +0 -84
  295. package/dist/core/tools/browser/browser-continue.js.map +0 -1
  296. package/dist/core/tools/browser/browser-run.d.ts +0 -48
  297. package/dist/core/tools/browser/browser-run.d.ts.map +0 -1
  298. package/dist/core/tools/browser/browser-run.js +0 -377
  299. package/dist/core/tools/browser/browser-run.js.map +0 -1
  300. package/dist/core/tools/browser/browsertools-shared.d.ts +0 -190
  301. package/dist/core/tools/browser/browsertools-shared.d.ts.map +0 -1
  302. package/dist/core/tools/browser/browsertools-shared.js +0 -335
  303. package/dist/core/tools/browser/browsertools-shared.js.map +0 -1
  304. package/dist/core/tools/browser/index.d.ts +0 -8
  305. package/dist/core/tools/browser/index.d.ts.map +0 -1
  306. package/dist/core/tools/browser/index.js +0 -8
  307. package/dist/core/tools/browser/index.js.map +0 -1
  308. package/dist/core/tools/doc/docedit.d.ts +0 -44
  309. package/dist/core/tools/doc/docedit.d.ts.map +0 -1
  310. package/dist/core/tools/doc/docedit.js +0 -133
  311. package/dist/core/tools/doc/docedit.js.map +0 -1
  312. package/dist/core/tools/doc/docgrep.d.ts +0 -28
  313. package/dist/core/tools/doc/docgrep.d.ts.map +0 -1
  314. package/dist/core/tools/doc/docgrep.js +0 -106
  315. package/dist/core/tools/doc/docgrep.js.map +0 -1
  316. package/dist/core/tools/doc/docpeek.d.ts +0 -25
  317. package/dist/core/tools/doc/docpeek.d.ts.map +0 -1
  318. package/dist/core/tools/doc/docpeek.js +0 -112
  319. package/dist/core/tools/doc/docpeek.js.map +0 -1
  320. package/dist/core/tools/doc/docread.d.ts +0 -32
  321. package/dist/core/tools/doc/docread.d.ts.map +0 -1
  322. package/dist/core/tools/doc/docread.js +0 -113
  323. package/dist/core/tools/doc/docread.js.map +0 -1
  324. package/dist/core/tools/doc/docscan.d.ts +0 -29
  325. package/dist/core/tools/doc/docscan.d.ts.map +0 -1
  326. package/dist/core/tools/doc/docscan.js +0 -110
  327. package/dist/core/tools/doc/docscan.js.map +0 -1
  328. package/dist/core/tools/doc/docwrite.d.ts +0 -44
  329. package/dist/core/tools/doc/docwrite.d.ts.map +0 -1
  330. package/dist/core/tools/doc/docwrite.js +0 -102
  331. package/dist/core/tools/doc/docwrite.js.map +0 -1
  332. package/dist/core/tools/doc/index.d.ts +0 -11
  333. package/dist/core/tools/doc/index.d.ts.map +0 -1
  334. package/dist/core/tools/doc/index.js +0 -11
  335. package/dist/core/tools/doc/index.js.map +0 -1
  336. package/dist/core/tools/filetools-shared.d.ts +0 -271
  337. package/dist/core/tools/filetools-shared.d.ts.map +0 -1
  338. package/dist/core/tools/filetools-shared.js +0 -403
  339. package/dist/core/tools/filetools-shared.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/tools/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core coding tools.\nexport {\n\ttype BashOperations,\n\ttype BashSpawnContext,\n\ttype BashSpawnHook,\n\ttype BashToolDetails,\n\ttype BashToolInput,\n\ttype BashToolOptions,\n\tcreateBashTool,\n\tcreateBashToolDefinition,\n\tcreateLocalBashOperations,\n} from \"./bash.js\";\n// Optional feature tools, grouped by feature (off by default or enabled per session).\nexport * from \"./browser/index.js\";\nexport * from \"./doc/index.js\";\nexport {\n\tcreateEditTool,\n\tcreateEditToolDefinition,\n\ttype EditOperations,\n\ttype EditToolDetails,\n\ttype EditToolInput,\n\ttype EditToolOptions,\n} from \"./edit.js\";\nexport { withFileMutationQueue } from \"./file-mutation-queue.js\";\nexport {\n\tcreateFindTool,\n\tcreateFindToolDefinition,\n\ttype FindOperations,\n\ttype FindToolDetails,\n\ttype FindToolInput,\n\ttype FindToolOptions,\n} from \"./find.js\";\nexport {\n\tcreateGrepTool,\n\tcreateGrepToolDefinition,\n\ttype GrepOperations,\n\ttype GrepToolDetails,\n\ttype GrepToolInput,\n\ttype GrepToolOptions,\n} from \"./grep.js\";\nexport {\n\tcreateLsTool,\n\tcreateLsToolDefinition,\n\ttype LsOperations,\n\ttype LsToolDetails,\n\ttype LsToolInput,\n\ttype LsToolOptions,\n} from \"./ls.js\";\nexport { expandPath, resolveReadPath, resolveToCwd } from \"./path-utils.js\";\nexport {\n\tcreateReadTool,\n\tcreateReadToolDefinition,\n\ttype ReadOperations,\n\ttype ReadToolDetails,\n\ttype ReadToolInput,\n\ttype ReadToolOptions,\n} from \"./read.js\";\n// Search: always active. It degrades to grep-backed lexical retrieval when no\n// semantic index is present; the `--enable-embsearchtools` flag only gates\n// whether the semantic index is built and fused in, not whether the tool exists.\nexport {\n\tcreateSearchTool,\n\tcreateSearchToolDefinition,\n\ttype SearchToolDetails,\n\ttype SearchToolInput,\n\ttype SearchToolOptions,\n} from \"./search.js\";\nexport {\n\tbuildTaskMainPrompt,\n\tcreateTaskOutputToolDefinition,\n\tcreateTaskToolDefinition,\n\ttype TaskOutputDetails,\n\ttype TaskToolDetails,\n} from \"./subagent.js\";\nexport { createTodoWriteToolDefinition, type TodoWriteDetails } from \"./todo.js\";\nexport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationOptions,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n\ttruncateTail,\n} from \"./truncate.js\";\nexport {\n\tcreateWebFetchTool,\n\tcreateWebFetchToolDefinition,\n\ttype WebFetchToolDetails,\n\ttype WebFetchToolInput,\n\ttype WebFetchToolOptions,\n} from \"./webfetch.js\";\nexport {\n\tcreateWebSearchTool,\n\tcreateWebSearchToolDefinition,\n\ttype WebSearchToolDetails,\n\ttype WebSearchToolInput,\n\ttype WebSearchToolOptions,\n} from \"./websearch.js\";\nexport {\n\tcreateWriteTool,\n\tcreateWriteToolDefinition,\n\ttype WriteOperations,\n\ttype WriteToolInput,\n\ttype WriteToolOptions,\n} from \"./write.js\";\n\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { type BashToolOptions, createBashToolDefinition } from \"./bash.js\";\nimport {\n\ttype BrowserContinueToolOptions,\n\ttype BrowserRunToolOptions,\n\tcreateBrowserContinueToolDefinition,\n\tcreateBrowserRunToolDefinition,\n} from \"./browser/index.js\";\nimport {\n\tcreateDocEditToolDefinition,\n\tcreateDocGrepToolDefinition,\n\tcreateDocPeekToolDefinition,\n\tcreateDocReadToolDefinition,\n\tcreateDocScanToolDefinition,\n\tcreateDocWriteToolDefinition,\n\ttype DocEditToolOptions,\n\ttype DocGrepToolOptions,\n\ttype DocPeekToolOptions,\n\ttype DocReadToolOptions,\n\ttype DocScanToolOptions,\n\ttype DocWriteToolOptions,\n} from \"./doc/index.js\";\nimport { createEditToolDefinition, type EditToolOptions } from \"./edit.js\";\nimport { createFindToolDefinition, type FindToolOptions } from \"./find.js\";\nimport { createGrepToolDefinition, type GrepToolOptions } from \"./grep.js\";\nimport { createLsToolDefinition, type LsToolOptions } from \"./ls.js\";\nimport { createReadToolDefinition, type ReadToolOptions } from \"./read.js\";\nimport { createSearchToolDefinition, type SearchToolOptions } from \"./search.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { createWebFetchToolDefinition, type WebFetchToolOptions } from \"./webfetch.js\";\nimport { createWebSearchToolDefinition, type WebSearchToolOptions } from \"./websearch.js\";\nimport { createWriteToolDefinition, type WriteToolOptions } from \"./write.js\";\n\nexport type Tool = AgentTool<any>;\nexport type ToolDef = ToolDefinition<any, any>;\n\nexport interface ToolsOptions {\n\tread?: ReadToolOptions;\n\tbash?: BashToolOptions;\n\twrite?: WriteToolOptions;\n\tedit?: EditToolOptions;\n\tgrep?: GrepToolOptions;\n\tfind?: FindToolOptions;\n\tls?: LsToolOptions;\n\tsearch?: SearchToolOptions;\n\twebfetch?: WebFetchToolOptions;\n\twebsearch?: WebSearchToolOptions;\n\tbrowser_run?: BrowserRunToolOptions;\n\tbrowser_continue?: BrowserContinueToolOptions;\n\tDocRead?: DocReadToolOptions;\n\tDocEdit?: DocEditToolOptions;\n\tDocWrite?: DocWriteToolOptions;\n\tDocScan?: DocScanToolOptions;\n\tDocGrep?: DocGrepToolOptions;\n\tDocPeek?: DocPeekToolOptions;\n}\n\n/**\n * Single source of truth for built-in tools: name → definition factory.\n * Everything else (name unions, option lookups, bundle helpers) derives\n * from this table, so adding or removing a tool touches exactly one entry\n * (plus its `ToolsOptions` key).\n */\nconst TOOL_FACTORIES = {\n\tread: createReadToolDefinition,\n\tbash: createBashToolDefinition,\n\tedit: createEditToolDefinition,\n\twrite: createWriteToolDefinition,\n\tgrep: createGrepToolDefinition,\n\tfind: createFindToolDefinition,\n\tls: createLsToolDefinition,\n\tsearch: createSearchToolDefinition,\n\twebfetch: createWebFetchToolDefinition,\n\twebsearch: createWebSearchToolDefinition,\n\tbrowser_run: createBrowserRunToolDefinition,\n\tbrowser_continue: createBrowserContinueToolDefinition,\n\tDocRead: createDocReadToolDefinition,\n\tDocEdit: createDocEditToolDefinition,\n\tDocWrite: createDocWriteToolDefinition,\n\tDocScan: createDocScanToolDefinition,\n\tDocGrep: createDocGrepToolDefinition,\n\tDocPeek: createDocPeekToolDefinition,\n} satisfies { [K in keyof ToolsOptions]-?: (cwd: string, options?: ToolsOptions[K]) => ToolDef };\n\nexport type ToolName = keyof typeof TOOL_FACTORIES;\n\nexport const allToolNames: Set<ToolName> = new Set(Object.keys(TOOL_FACTORIES) as ToolName[]);\n\n/** The default coding bundle (read/write + shell + search). */\nconst CODING_TOOL_NAMES: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\", \"grep\", \"find\", \"ls\", \"search\"];\n\n/** Read-only exploration bundle. */\nconst READ_ONLY_TOOL_NAMES: ToolName[] = [\"read\", \"grep\", \"find\", \"ls\", \"search\"];\n\nexport function createToolDefinition(toolName: ToolName, cwd: string, options?: ToolsOptions): ToolDef {\n\tconst factory = TOOL_FACTORIES[toolName] as (cwd: string, options?: ToolsOptions[ToolName]) => ToolDef;\n\tif (!factory) {\n\t\tthrow new Error(`Unknown tool name: ${toolName}`);\n\t}\n\treturn factory(cwd, options?.[toolName]);\n}\n\nexport function createTool(toolName: ToolName, cwd: string, options?: ToolsOptions): Tool {\n\treturn wrapToolDefinition(createToolDefinition(toolName, cwd, options)) as Tool;\n}\n\nexport function createCodingToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn CODING_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createReadOnlyToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createAllToolDefinitions(cwd: string, options?: ToolsOptions): Record<ToolName, ToolDef> {\n\tconst entries = [...allToolNames].map((name) => [name, createToolDefinition(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, ToolDef>;\n}\n\nexport function createCodingTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn CODING_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createReadOnlyTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createAllTools(cwd: string, options?: ToolsOptions): Record<ToolName, Tool> {\n\tconst entries = [...allToolNames].map((name) => [name, createTool(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, Tool>;\n}\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/tools/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core coding tools.\nexport {\n\ttype BashOperations,\n\ttype BashSpawnContext,\n\ttype BashSpawnHook,\n\ttype BashToolDetails,\n\ttype BashToolInput,\n\ttype BashToolOptions,\n\tcreateBashTool,\n\tcreateBashToolDefinition,\n\tcreateLocalBashOperations,\n} from \"./bash.js\";\nexport {\n\tcreateEditTool,\n\tcreateEditToolDefinition,\n\ttype EditOperations,\n\ttype EditToolDetails,\n\ttype EditToolInput,\n\ttype EditToolOptions,\n} from \"./edit.js\";\nexport { withFileMutationQueue } from \"./file-mutation-queue.js\";\nexport {\n\tcreateFindTool,\n\tcreateFindToolDefinition,\n\ttype FindOperations,\n\ttype FindToolDetails,\n\ttype FindToolInput,\n\ttype FindToolOptions,\n} from \"./find.js\";\nexport {\n\tcreateGrepTool,\n\tcreateGrepToolDefinition,\n\ttype GrepOperations,\n\ttype GrepToolDetails,\n\ttype GrepToolInput,\n\ttype GrepToolOptions,\n} from \"./grep.js\";\nexport {\n\tcreateLsTool,\n\tcreateLsToolDefinition,\n\ttype LsOperations,\n\ttype LsToolDetails,\n\ttype LsToolInput,\n\ttype LsToolOptions,\n} from \"./ls.js\";\nexport {\n\tcreateReadTool,\n\tcreateReadToolDefinition,\n\ttype ReadOperations,\n\ttype ReadToolDetails,\n\ttype ReadToolInput,\n\ttype ReadToolOptions,\n} from \"./read.js\";\nexport {\n\tbuildTaskMainPrompt,\n\tcreateTaskOutputToolDefinition,\n\tcreateTaskToolDefinition,\n\ttype TaskOutputDetails,\n\ttype TaskToolDetails,\n} from \"./subagent.js\";\nexport { createTodoWriteToolDefinition, type TodoWriteDetails } from \"./todo.js\";\nexport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationOptions,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n\ttruncateTail,\n} from \"./truncate.js\";\nexport {\n\tcreateWriteTool,\n\tcreateWriteToolDefinition,\n\ttype WriteOperations,\n\ttype WriteToolInput,\n\ttype WriteToolOptions,\n} from \"./write.js\";\n\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { type BashToolOptions, createBashToolDefinition } from \"./bash.js\";\nimport { createEditToolDefinition, type EditToolOptions } from \"./edit.js\";\nimport { createFindToolDefinition, type FindToolOptions } from \"./find.js\";\nimport { createGrepToolDefinition, type GrepToolOptions } from \"./grep.js\";\nimport { createLsToolDefinition, type LsToolOptions } from \"./ls.js\";\nimport { createReadToolDefinition, type ReadToolOptions } from \"./read.js\";\nimport { createSearchToolDefinition, type SearchToolOptions } from \"./search.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { createWebFetchToolDefinition, type WebFetchToolOptions } from \"./webfetch.js\";\nimport { createWebSearchToolDefinition, type WebSearchToolOptions } from \"./websearch.js\";\nimport { createWriteToolDefinition, type WriteToolOptions } from \"./write.js\";\n\nexport type Tool = AgentTool<any>;\nexport type ToolDef = ToolDefinition<any, any>;\n\nexport interface ToolsOptions {\n\tread?: ReadToolOptions;\n\tbash?: BashToolOptions;\n\twrite?: WriteToolOptions;\n\tedit?: EditToolOptions;\n\tgrep?: GrepToolOptions;\n\tfind?: FindToolOptions;\n\tls?: LsToolOptions;\n\tsearch?: SearchToolOptions;\n\twebfetch?: WebFetchToolOptions;\n\twebsearch?: WebSearchToolOptions;\n}\n\n/**\n * Single source of truth for built-in tools: name → definition factory.\n * Everything else (name unions, option lookups, bundle helpers) derives\n * from this table, so adding or removing a tool touches exactly one entry\n * (plus its `ToolsOptions` key).\n */\nconst TOOL_FACTORIES = {\n\tread: createReadToolDefinition,\n\tbash: createBashToolDefinition,\n\tedit: createEditToolDefinition,\n\twrite: createWriteToolDefinition,\n\tgrep: createGrepToolDefinition,\n\tfind: createFindToolDefinition,\n\tls: createLsToolDefinition,\n\tsearch: createSearchToolDefinition,\n\twebfetch: createWebFetchToolDefinition,\n\twebsearch: createWebSearchToolDefinition,\n} satisfies { [K in keyof ToolsOptions]-?: (cwd: string, options?: ToolsOptions[K]) => ToolDef };\n\nexport type ToolName = keyof typeof TOOL_FACTORIES;\n\nexport const allToolNames: Set<ToolName> = new Set(Object.keys(TOOL_FACTORIES) as ToolName[]);\n\n/** The default coding bundle (read/write + shell + search). */\nconst CODING_TOOL_NAMES: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\", \"grep\", \"find\", \"ls\", \"search\"];\n\n/** Read-only exploration bundle. */\nconst READ_ONLY_TOOL_NAMES: ToolName[] = [\"read\", \"grep\", \"find\", \"ls\", \"search\"];\n\nexport function createToolDefinition(toolName: ToolName, cwd: string, options?: ToolsOptions): ToolDef {\n\tconst factory = TOOL_FACTORIES[toolName] as (cwd: string, options?: ToolsOptions[ToolName]) => ToolDef;\n\tif (!factory) {\n\t\tthrow new Error(`Unknown tool name: ${toolName}`);\n\t}\n\treturn factory(cwd, options?.[toolName]);\n}\n\nexport function createTool(toolName: ToolName, cwd: string, options?: ToolsOptions): Tool {\n\treturn wrapToolDefinition(createToolDefinition(toolName, cwd, options)) as Tool;\n}\n\nexport function createCodingToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn CODING_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createReadOnlyToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createAllToolDefinitions(cwd: string, options?: ToolsOptions): Record<ToolName, ToolDef> {\n\tconst entries = [...allToolNames].map((name) => [name, createToolDefinition(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, ToolDef>;\n}\n\nexport function createCodingTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn CODING_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createReadOnlyTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createAllTools(cwd: string, options?: ToolsOptions): Record<ToolName, Tool> {\n\tconst entries = [...allToolNames].map((name) => [name, createTool(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, Tool>;\n}\n"]}
@@ -1,28 +1,16 @@
1
1
  // Core coding tools.
2
2
  export { createBashTool, createBashToolDefinition, createLocalBashOperations, } from "./bash.js";
3
- // Optional feature tools, grouped by feature (off by default or enabled per session).
4
- export * from "./browser/index.js";
5
- export * from "./doc/index.js";
6
3
  export { createEditTool, createEditToolDefinition, } from "./edit.js";
7
4
  export { withFileMutationQueue } from "./file-mutation-queue.js";
8
5
  export { createFindTool, createFindToolDefinition, } from "./find.js";
9
6
  export { createGrepTool, createGrepToolDefinition, } from "./grep.js";
10
7
  export { createLsTool, createLsToolDefinition, } from "./ls.js";
11
- export { expandPath, resolveReadPath, resolveToCwd } from "./path-utils.js";
12
8
  export { createReadTool, createReadToolDefinition, } from "./read.js";
13
- // Search: always active. It degrades to grep-backed lexical retrieval when no
14
- // semantic index is present; the `--enable-embsearchtools` flag only gates
15
- // whether the semantic index is built and fused in, not whether the tool exists.
16
- export { createSearchTool, createSearchToolDefinition, } from "./search.js";
17
9
  export { buildTaskMainPrompt, createTaskOutputToolDefinition, createTaskToolDefinition, } from "./subagent.js";
18
10
  export { createTodoWriteToolDefinition } from "./todo.js";
19
11
  export { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead, truncateLine, truncateTail, } from "./truncate.js";
20
- export { createWebFetchTool, createWebFetchToolDefinition, } from "./webfetch.js";
21
- export { createWebSearchTool, createWebSearchToolDefinition, } from "./websearch.js";
22
12
  export { createWriteTool, createWriteToolDefinition, } from "./write.js";
23
13
  import { createBashToolDefinition } from "./bash.js";
24
- import { createBrowserContinueToolDefinition, createBrowserRunToolDefinition, } from "./browser/index.js";
25
- import { createDocEditToolDefinition, createDocGrepToolDefinition, createDocPeekToolDefinition, createDocReadToolDefinition, createDocScanToolDefinition, createDocWriteToolDefinition, } from "./doc/index.js";
26
14
  import { createEditToolDefinition } from "./edit.js";
27
15
  import { createFindToolDefinition } from "./find.js";
28
16
  import { createGrepToolDefinition } from "./grep.js";
@@ -50,14 +38,6 @@ const TOOL_FACTORIES = {
50
38
  search: createSearchToolDefinition,
51
39
  webfetch: createWebFetchToolDefinition,
52
40
  websearch: createWebSearchToolDefinition,
53
- browser_run: createBrowserRunToolDefinition,
54
- browser_continue: createBrowserContinueToolDefinition,
55
- DocRead: createDocReadToolDefinition,
56
- DocEdit: createDocEditToolDefinition,
57
- DocWrite: createDocWriteToolDefinition,
58
- DocScan: createDocScanToolDefinition,
59
- DocGrep: createDocGrepToolDefinition,
60
- DocPeek: createDocPeekToolDefinition,
61
41
  };
62
42
  export const allToolNames = new Set(Object.keys(TOOL_FACTORIES));
63
43
  /** The default coding bundle (read/write + shell + search). */
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/tools/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core coding tools.\nexport {\n\ttype BashOperations,\n\ttype BashSpawnContext,\n\ttype BashSpawnHook,\n\ttype BashToolDetails,\n\ttype BashToolInput,\n\ttype BashToolOptions,\n\tcreateBashTool,\n\tcreateBashToolDefinition,\n\tcreateLocalBashOperations,\n} from \"./bash.js\";\n// Optional feature tools, grouped by feature (off by default or enabled per session).\nexport * from \"./browser/index.js\";\nexport * from \"./doc/index.js\";\nexport {\n\tcreateEditTool,\n\tcreateEditToolDefinition,\n\ttype EditOperations,\n\ttype EditToolDetails,\n\ttype EditToolInput,\n\ttype EditToolOptions,\n} from \"./edit.js\";\nexport { withFileMutationQueue } from \"./file-mutation-queue.js\";\nexport {\n\tcreateFindTool,\n\tcreateFindToolDefinition,\n\ttype FindOperations,\n\ttype FindToolDetails,\n\ttype FindToolInput,\n\ttype FindToolOptions,\n} from \"./find.js\";\nexport {\n\tcreateGrepTool,\n\tcreateGrepToolDefinition,\n\ttype GrepOperations,\n\ttype GrepToolDetails,\n\ttype GrepToolInput,\n\ttype GrepToolOptions,\n} from \"./grep.js\";\nexport {\n\tcreateLsTool,\n\tcreateLsToolDefinition,\n\ttype LsOperations,\n\ttype LsToolDetails,\n\ttype LsToolInput,\n\ttype LsToolOptions,\n} from \"./ls.js\";\nexport { expandPath, resolveReadPath, resolveToCwd } from \"./path-utils.js\";\nexport {\n\tcreateReadTool,\n\tcreateReadToolDefinition,\n\ttype ReadOperations,\n\ttype ReadToolDetails,\n\ttype ReadToolInput,\n\ttype ReadToolOptions,\n} from \"./read.js\";\n// Search: always active. It degrades to grep-backed lexical retrieval when no\n// semantic index is present; the `--enable-embsearchtools` flag only gates\n// whether the semantic index is built and fused in, not whether the tool exists.\nexport {\n\tcreateSearchTool,\n\tcreateSearchToolDefinition,\n\ttype SearchToolDetails,\n\ttype SearchToolInput,\n\ttype SearchToolOptions,\n} from \"./search.js\";\nexport {\n\tbuildTaskMainPrompt,\n\tcreateTaskOutputToolDefinition,\n\tcreateTaskToolDefinition,\n\ttype TaskOutputDetails,\n\ttype TaskToolDetails,\n} from \"./subagent.js\";\nexport { createTodoWriteToolDefinition, type TodoWriteDetails } from \"./todo.js\";\nexport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationOptions,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n\ttruncateTail,\n} from \"./truncate.js\";\nexport {\n\tcreateWebFetchTool,\n\tcreateWebFetchToolDefinition,\n\ttype WebFetchToolDetails,\n\ttype WebFetchToolInput,\n\ttype WebFetchToolOptions,\n} from \"./webfetch.js\";\nexport {\n\tcreateWebSearchTool,\n\tcreateWebSearchToolDefinition,\n\ttype WebSearchToolDetails,\n\ttype WebSearchToolInput,\n\ttype WebSearchToolOptions,\n} from \"./websearch.js\";\nexport {\n\tcreateWriteTool,\n\tcreateWriteToolDefinition,\n\ttype WriteOperations,\n\ttype WriteToolInput,\n\ttype WriteToolOptions,\n} from \"./write.js\";\n\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { type BashToolOptions, createBashToolDefinition } from \"./bash.js\";\nimport {\n\ttype BrowserContinueToolOptions,\n\ttype BrowserRunToolOptions,\n\tcreateBrowserContinueToolDefinition,\n\tcreateBrowserRunToolDefinition,\n} from \"./browser/index.js\";\nimport {\n\tcreateDocEditToolDefinition,\n\tcreateDocGrepToolDefinition,\n\tcreateDocPeekToolDefinition,\n\tcreateDocReadToolDefinition,\n\tcreateDocScanToolDefinition,\n\tcreateDocWriteToolDefinition,\n\ttype DocEditToolOptions,\n\ttype DocGrepToolOptions,\n\ttype DocPeekToolOptions,\n\ttype DocReadToolOptions,\n\ttype DocScanToolOptions,\n\ttype DocWriteToolOptions,\n} from \"./doc/index.js\";\nimport { createEditToolDefinition, type EditToolOptions } from \"./edit.js\";\nimport { createFindToolDefinition, type FindToolOptions } from \"./find.js\";\nimport { createGrepToolDefinition, type GrepToolOptions } from \"./grep.js\";\nimport { createLsToolDefinition, type LsToolOptions } from \"./ls.js\";\nimport { createReadToolDefinition, type ReadToolOptions } from \"./read.js\";\nimport { createSearchToolDefinition, type SearchToolOptions } from \"./search.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { createWebFetchToolDefinition, type WebFetchToolOptions } from \"./webfetch.js\";\nimport { createWebSearchToolDefinition, type WebSearchToolOptions } from \"./websearch.js\";\nimport { createWriteToolDefinition, type WriteToolOptions } from \"./write.js\";\n\nexport type Tool = AgentTool<any>;\nexport type ToolDef = ToolDefinition<any, any>;\n\nexport interface ToolsOptions {\n\tread?: ReadToolOptions;\n\tbash?: BashToolOptions;\n\twrite?: WriteToolOptions;\n\tedit?: EditToolOptions;\n\tgrep?: GrepToolOptions;\n\tfind?: FindToolOptions;\n\tls?: LsToolOptions;\n\tsearch?: SearchToolOptions;\n\twebfetch?: WebFetchToolOptions;\n\twebsearch?: WebSearchToolOptions;\n\tbrowser_run?: BrowserRunToolOptions;\n\tbrowser_continue?: BrowserContinueToolOptions;\n\tDocRead?: DocReadToolOptions;\n\tDocEdit?: DocEditToolOptions;\n\tDocWrite?: DocWriteToolOptions;\n\tDocScan?: DocScanToolOptions;\n\tDocGrep?: DocGrepToolOptions;\n\tDocPeek?: DocPeekToolOptions;\n}\n\n/**\n * Single source of truth for built-in tools: name → definition factory.\n * Everything else (name unions, option lookups, bundle helpers) derives\n * from this table, so adding or removing a tool touches exactly one entry\n * (plus its `ToolsOptions` key).\n */\nconst TOOL_FACTORIES = {\n\tread: createReadToolDefinition,\n\tbash: createBashToolDefinition,\n\tedit: createEditToolDefinition,\n\twrite: createWriteToolDefinition,\n\tgrep: createGrepToolDefinition,\n\tfind: createFindToolDefinition,\n\tls: createLsToolDefinition,\n\tsearch: createSearchToolDefinition,\n\twebfetch: createWebFetchToolDefinition,\n\twebsearch: createWebSearchToolDefinition,\n\tbrowser_run: createBrowserRunToolDefinition,\n\tbrowser_continue: createBrowserContinueToolDefinition,\n\tDocRead: createDocReadToolDefinition,\n\tDocEdit: createDocEditToolDefinition,\n\tDocWrite: createDocWriteToolDefinition,\n\tDocScan: createDocScanToolDefinition,\n\tDocGrep: createDocGrepToolDefinition,\n\tDocPeek: createDocPeekToolDefinition,\n} satisfies { [K in keyof ToolsOptions]-?: (cwd: string, options?: ToolsOptions[K]) => ToolDef };\n\nexport type ToolName = keyof typeof TOOL_FACTORIES;\n\nexport const allToolNames: Set<ToolName> = new Set(Object.keys(TOOL_FACTORIES) as ToolName[]);\n\n/** The default coding bundle (read/write + shell + search). */\nconst CODING_TOOL_NAMES: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\", \"grep\", \"find\", \"ls\", \"search\"];\n\n/** Read-only exploration bundle. */\nconst READ_ONLY_TOOL_NAMES: ToolName[] = [\"read\", \"grep\", \"find\", \"ls\", \"search\"];\n\nexport function createToolDefinition(toolName: ToolName, cwd: string, options?: ToolsOptions): ToolDef {\n\tconst factory = TOOL_FACTORIES[toolName] as (cwd: string, options?: ToolsOptions[ToolName]) => ToolDef;\n\tif (!factory) {\n\t\tthrow new Error(`Unknown tool name: ${toolName}`);\n\t}\n\treturn factory(cwd, options?.[toolName]);\n}\n\nexport function createTool(toolName: ToolName, cwd: string, options?: ToolsOptions): Tool {\n\treturn wrapToolDefinition(createToolDefinition(toolName, cwd, options)) as Tool;\n}\n\nexport function createCodingToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn CODING_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createReadOnlyToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createAllToolDefinitions(cwd: string, options?: ToolsOptions): Record<ToolName, ToolDef> {\n\tconst entries = [...allToolNames].map((name) => [name, createToolDefinition(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, ToolDef>;\n}\n\nexport function createCodingTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn CODING_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createReadOnlyTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createAllTools(cwd: string, options?: ToolsOptions): Record<ToolName, Tool> {\n\tconst entries = [...allToolNames].map((name) => [name, createTool(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, Tool>;\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/tools/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core coding tools.\nexport {\n\ttype BashOperations,\n\ttype BashSpawnContext,\n\ttype BashSpawnHook,\n\ttype BashToolDetails,\n\ttype BashToolInput,\n\ttype BashToolOptions,\n\tcreateBashTool,\n\tcreateBashToolDefinition,\n\tcreateLocalBashOperations,\n} from \"./bash.js\";\nexport {\n\tcreateEditTool,\n\tcreateEditToolDefinition,\n\ttype EditOperations,\n\ttype EditToolDetails,\n\ttype EditToolInput,\n\ttype EditToolOptions,\n} from \"./edit.js\";\nexport { withFileMutationQueue } from \"./file-mutation-queue.js\";\nexport {\n\tcreateFindTool,\n\tcreateFindToolDefinition,\n\ttype FindOperations,\n\ttype FindToolDetails,\n\ttype FindToolInput,\n\ttype FindToolOptions,\n} from \"./find.js\";\nexport {\n\tcreateGrepTool,\n\tcreateGrepToolDefinition,\n\ttype GrepOperations,\n\ttype GrepToolDetails,\n\ttype GrepToolInput,\n\ttype GrepToolOptions,\n} from \"./grep.js\";\nexport {\n\tcreateLsTool,\n\tcreateLsToolDefinition,\n\ttype LsOperations,\n\ttype LsToolDetails,\n\ttype LsToolInput,\n\ttype LsToolOptions,\n} from \"./ls.js\";\nexport {\n\tcreateReadTool,\n\tcreateReadToolDefinition,\n\ttype ReadOperations,\n\ttype ReadToolDetails,\n\ttype ReadToolInput,\n\ttype ReadToolOptions,\n} from \"./read.js\";\nexport {\n\tbuildTaskMainPrompt,\n\tcreateTaskOutputToolDefinition,\n\tcreateTaskToolDefinition,\n\ttype TaskOutputDetails,\n\ttype TaskToolDetails,\n} from \"./subagent.js\";\nexport { createTodoWriteToolDefinition, type TodoWriteDetails } from \"./todo.js\";\nexport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationOptions,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n\ttruncateTail,\n} from \"./truncate.js\";\nexport {\n\tcreateWriteTool,\n\tcreateWriteToolDefinition,\n\ttype WriteOperations,\n\ttype WriteToolInput,\n\ttype WriteToolOptions,\n} from \"./write.js\";\n\nimport type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { type BashToolOptions, createBashToolDefinition } from \"./bash.js\";\nimport { createEditToolDefinition, type EditToolOptions } from \"./edit.js\";\nimport { createFindToolDefinition, type FindToolOptions } from \"./find.js\";\nimport { createGrepToolDefinition, type GrepToolOptions } from \"./grep.js\";\nimport { createLsToolDefinition, type LsToolOptions } from \"./ls.js\";\nimport { createReadToolDefinition, type ReadToolOptions } from \"./read.js\";\nimport { createSearchToolDefinition, type SearchToolOptions } from \"./search.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { createWebFetchToolDefinition, type WebFetchToolOptions } from \"./webfetch.js\";\nimport { createWebSearchToolDefinition, type WebSearchToolOptions } from \"./websearch.js\";\nimport { createWriteToolDefinition, type WriteToolOptions } from \"./write.js\";\n\nexport type Tool = AgentTool<any>;\nexport type ToolDef = ToolDefinition<any, any>;\n\nexport interface ToolsOptions {\n\tread?: ReadToolOptions;\n\tbash?: BashToolOptions;\n\twrite?: WriteToolOptions;\n\tedit?: EditToolOptions;\n\tgrep?: GrepToolOptions;\n\tfind?: FindToolOptions;\n\tls?: LsToolOptions;\n\tsearch?: SearchToolOptions;\n\twebfetch?: WebFetchToolOptions;\n\twebsearch?: WebSearchToolOptions;\n}\n\n/**\n * Single source of truth for built-in tools: name → definition factory.\n * Everything else (name unions, option lookups, bundle helpers) derives\n * from this table, so adding or removing a tool touches exactly one entry\n * (plus its `ToolsOptions` key).\n */\nconst TOOL_FACTORIES = {\n\tread: createReadToolDefinition,\n\tbash: createBashToolDefinition,\n\tedit: createEditToolDefinition,\n\twrite: createWriteToolDefinition,\n\tgrep: createGrepToolDefinition,\n\tfind: createFindToolDefinition,\n\tls: createLsToolDefinition,\n\tsearch: createSearchToolDefinition,\n\twebfetch: createWebFetchToolDefinition,\n\twebsearch: createWebSearchToolDefinition,\n} satisfies { [K in keyof ToolsOptions]-?: (cwd: string, options?: ToolsOptions[K]) => ToolDef };\n\nexport type ToolName = keyof typeof TOOL_FACTORIES;\n\nexport const allToolNames: Set<ToolName> = new Set(Object.keys(TOOL_FACTORIES) as ToolName[]);\n\n/** The default coding bundle (read/write + shell + search). */\nconst CODING_TOOL_NAMES: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\", \"grep\", \"find\", \"ls\", \"search\"];\n\n/** Read-only exploration bundle. */\nconst READ_ONLY_TOOL_NAMES: ToolName[] = [\"read\", \"grep\", \"find\", \"ls\", \"search\"];\n\nexport function createToolDefinition(toolName: ToolName, cwd: string, options?: ToolsOptions): ToolDef {\n\tconst factory = TOOL_FACTORIES[toolName] as (cwd: string, options?: ToolsOptions[ToolName]) => ToolDef;\n\tif (!factory) {\n\t\tthrow new Error(`Unknown tool name: ${toolName}`);\n\t}\n\treturn factory(cwd, options?.[toolName]);\n}\n\nexport function createTool(toolName: ToolName, cwd: string, options?: ToolsOptions): Tool {\n\treturn wrapToolDefinition(createToolDefinition(toolName, cwd, options)) as Tool;\n}\n\nexport function createCodingToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn CODING_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createReadOnlyToolDefinitions(cwd: string, options?: ToolsOptions): ToolDef[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createToolDefinition(name, cwd, options));\n}\n\nexport function createAllToolDefinitions(cwd: string, options?: ToolsOptions): Record<ToolName, ToolDef> {\n\tconst entries = [...allToolNames].map((name) => [name, createToolDefinition(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, ToolDef>;\n}\n\nexport function createCodingTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn CODING_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createReadOnlyTools(cwd: string, options?: ToolsOptions): Tool[] {\n\treturn READ_ONLY_TOOL_NAMES.map((name) => createTool(name, cwd, options));\n}\n\nexport function createAllTools(cwd: string, options?: ToolsOptions): Record<ToolName, Tool> {\n\tconst entries = [...allToolNames].map((name) => [name, createTool(name, cwd, options)] as const);\n\treturn Object.fromEntries(entries) as Record<ToolName, Tool>;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../../src/core/tools/ls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAMjE,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAItF,OAAO,EAAiC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEnG,QAAA,MAAM,QAAQ;;;;EASZ,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC;AAIlD,MAAM,WAAW,aAAa;IAC7B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B,2BAA2B;IAC3B,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAC7D,wDAAwD;IACxD,IAAI,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC,GAAG;QAAE,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC;IACzG,mFAAmF;IACnF,OAAO,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;IAChE;;;OAGG;IACH,cAAc,CAAC,EAAE,CAChB,YAAY,EAAE,MAAM,KAElB,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC,CAAC,GAC5D,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC,CAAC;CACvD;AASD,MAAM,WAAW,aAAa;IAC7B,yEAAyE;IACzE,UAAU,CAAC,EAAE,YAAY,CAAC;CAC1B;AAkDD,wBAAgB,sBAAsB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,aAAa,GACrB,cAAc,CAAC,OAAO,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC,CAgK5D;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC,OAAO,QAAQ,CAAC,CAE7F","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { existsSync, readdirSync, statSync } from \"fs\";\nimport { readdir as fsReaddir } from \"fs/promises\";\nimport { minimatch } from \"minimatch\";\nimport nodePath from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport { resolveToCwd } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.js\";\n\nconst lsSchema = Type.Object({\n\tpath: Type.Optional(Type.String({ description: \"Directory to list (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of entries to return (default: 500)\" })),\n\tignore: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription:\n\t\t\t\t\"Glob patterns matched against entry names to exclude, e.g. ['node_modules', '*.log', '.git']. Matching is on the entry name only (ls is non-recursive); dotfiles are matched.\",\n\t\t}),\n\t),\n});\n\nexport type LsToolInput = Static<typeof lsSchema>;\n\nconst DEFAULT_LIMIT = 500;\n\nexport interface LsToolDetails {\n\ttruncation?: TruncationResult;\n\tentryLimitReached?: number;\n}\n\n/**\n * Pluggable operations for the ls tool.\n * Override these to delegate directory listing to remote systems (for example SSH).\n */\nexport interface LsOperations {\n\t/** Check if path exists */\n\texists: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Get file or directory stats. Throws if not found. */\n\tstat: (absolutePath: string) => Promise<{ isDirectory: () => boolean }> | { isDirectory: () => boolean };\n\t/** Read directory entries as strings (used when readdirEntries is not provided) */\n\treaddir: (absolutePath: string) => Promise<string[]> | string[];\n\t/**\n\t * Optional: read directory entries with type info in a single syscall.\n\t * When provided, eliminates per-entry stat() calls for the isDirectory check.\n\t */\n\treaddirEntries?: (\n\t\tabsolutePath: string,\n\t) =>\n\t\t| Promise<Array<{ name: string; isDirectory: () => boolean }>>\n\t\t| Array<{ name: string; isDirectory: () => boolean }>;\n}\n\nconst defaultLsOperations: LsOperations = {\n\texists: existsSync,\n\tstat: statSync,\n\treaddir: readdirSync,\n\treaddirEntries: (p) => fsReaddir(p, { withFileTypes: true }),\n};\n\nexport interface LsToolOptions {\n\t/** Custom operations for directory listing. Default: local filesystem */\n\toperations?: LsOperations;\n}\n\nfunction formatLsCall(\n\targs: { path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.js\").theme,\n): string {\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${path === null ? invalidArg : theme.fg(\"accent\", path)}`;\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatLsResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: LsToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.js\").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 entryLimit = result.details?.entryLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (entryLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (entryLimit) warnings.push(`${entryLimit} entries 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\nexport function createLsToolDefinition(\n\tcwd: string,\n\toptions?: LsToolOptions,\n): ToolDefinition<typeof lsSchema, LsToolDetails | undefined> {\n\tconst ops = options?.operations ?? defaultLsOperations;\n\treturn {\n\t\tname: \"ls\",\n\t\tlabel: \"ls\",\n\t\tdescription: `List directory contents. Returns entries sorted alphabetically, with '/' suffix for directories. Includes dotfiles. Lists a single directory (not recursive) and shows everything on disk; pass 'ignore' glob patterns to skip entries like node_modules or .git. Output is truncated to ${DEFAULT_LIMIT} entries or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\n\t\tpromptSnippet: \"List directory contents\",\n\t\tparameters: lsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, limit, ignore }: { path?: string; limit?: number; ignore?: string[] },\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\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\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 dirPath = resolveToCwd(path || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\n\t\t\t\t\t\t// Check if path exists.\n\t\t\t\t\t\tif (!(await ops.exists(dirPath))) {\n\t\t\t\t\t\t\treject(new Error(`Path not found: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if path is a directory.\n\t\t\t\t\t\tconst stat = await ops.stat(dirPath);\n\t\t\t\t\t\tif (!stat.isDirectory()) {\n\t\t\t\t\t\t\treject(new Error(`Not a directory: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Exclude entries matching any ignore glob. Match on the bare entry\n\t\t\t\t\t\t// name (ls is non-recursive) with dot:true so patterns can target\n\t\t\t\t\t\t// dotfiles like '.git'. Default behavior (no patterns) still shows\n\t\t\t\t\t\t// everything on disk.\n\t\t\t\t\t\tconst ignorePatterns = (ignore ?? []).filter((p) => typeof p === \"string\" && p.length > 0);\n\n\t\t\t\t\t\t// Fast path: use readdirEntries (single syscall with type info).\n\t\t\t\t\t\t// Slow path: fall back to readdir + per-entry stat.\n\t\t\t\t\t\tconst results: string[] = [];\n\t\t\t\t\t\tlet entryLimitReached = false;\n\n\t\t\t\t\t\tif (ops.readdirEntries) {\n\t\t\t\t\t\t\tlet dirents: Array<{ name: string; isDirectory: () => boolean }>;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tdirents = await ops.readdirEntries(dirPath);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${dirPath}`));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlet filtered = dirents;\n\t\t\t\t\t\t\tif (ignorePatterns.length > 0) {\n\t\t\t\t\t\t\t\tfiltered = dirents.filter(\n\t\t\t\t\t\t\t\t\t(d) => !ignorePatterns.some((pattern) => minimatch(d.name, pattern, { dot: 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\tfiltered.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));\n\t\t\t\t\t\t\tfor (const entry of filtered) {\n\t\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresults.push(entry.name + (entry.isDirectory() ? \"/\" : \"\"));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Fallback: readdir returns strings, stat each entry.\n\t\t\t\t\t\t\tlet entries: string[];\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tentries = await ops.readdir(dirPath);\n\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\tif (e instanceof Error) {\n\t\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${e.message}`));\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${String(e)}`));\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\tconst ignoreFiltered =\n\t\t\t\t\t\t\t\tignorePatterns.length > 0\n\t\t\t\t\t\t\t\t\t? entries.filter(\n\t\t\t\t\t\t\t\t\t\t\t(entry) => !ignorePatterns.some((pattern) => minimatch(entry, pattern, { dot: true })),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t: entries;\n\t\t\t\t\t\t\tignoreFiltered.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\t\t\t\t\t\t\tfor (const entry of ignoreFiltered) {\n\t\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst fullPath = nodePath.join(dirPath, entry);\n\t\t\t\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst entryStat = await ops.stat(fullPath);\n\t\t\t\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\n\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"(empty directory)\" }], details: undefined });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = results.join(\"\\n\");\n\t\t\t\t\t\t// Apply byte truncation. There is no separate line limit because entry count is already capped.\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\tconst details: LsToolDetails = {};\n\t\t\t\t\t\t// Build actionable notices for truncation and entry limits.\n\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\tif (entryLimitReached) {\n\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);\n\t\t\t\t\t\t\tdetails.entryLimitReached = effectiveLimit;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\toutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(e);\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(formatLsCall(args, theme));\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(formatLsResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createLsTool(cwd: string, options?: LsToolOptions): AgentTool<typeof lsSchema> {\n\treturn wrapToolDefinition(createLsToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../../src/core/tools/ls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAMjE,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAItF,OAAO,EAAiC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEnG,QAAA,MAAM,QAAQ;;;;EAQZ,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,QAAQ,CAAC,CAAC;AAIlD,MAAM,WAAW,aAAa;IAC7B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B,2BAA2B;IAC3B,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAC7D,wDAAwD;IACxD,IAAI,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC,GAAG;QAAE,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC;IACzG,mFAAmF;IACnF,OAAO,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;IAChE;;;OAGG;IACH,cAAc,CAAC,EAAE,CAChB,YAAY,EAAE,MAAM,KAElB,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC,CAAC,GAC5D,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC,CAAC;CACvD;AASD,MAAM,WAAW,aAAa;IAC7B,yEAAyE;IACzE,UAAU,CAAC,EAAE,YAAY,CAAC;CAC1B;AAkDD,wBAAgB,sBAAsB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,aAAa,GACrB,cAAc,CAAC,OAAO,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC,CAgK5D;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC,OAAO,QAAQ,CAAC,CAE7F","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { existsSync, readdirSync, statSync } from \"fs\";\nimport { readdir as fsReaddir } from \"fs/promises\";\nimport { minimatch } from \"minimatch\";\nimport nodePath from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport { resolveToCwd } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.js\";\n\nconst lsSchema = Type.Object({\n\tpath: Type.Optional(Type.String({ description: \"Directory to list (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of entries to return (default: 500)\" })),\n\tignore: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription: \"Globs matched against entry names to exclude, e.g. ['node_modules', '*.log'].\",\n\t\t}),\n\t),\n});\n\nexport type LsToolInput = Static<typeof lsSchema>;\n\nconst DEFAULT_LIMIT = 500;\n\nexport interface LsToolDetails {\n\ttruncation?: TruncationResult;\n\tentryLimitReached?: number;\n}\n\n/**\n * Pluggable operations for the ls tool.\n * Override these to delegate directory listing to remote systems (for example SSH).\n */\nexport interface LsOperations {\n\t/** Check if path exists */\n\texists: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Get file or directory stats. Throws if not found. */\n\tstat: (absolutePath: string) => Promise<{ isDirectory: () => boolean }> | { isDirectory: () => boolean };\n\t/** Read directory entries as strings (used when readdirEntries is not provided) */\n\treaddir: (absolutePath: string) => Promise<string[]> | string[];\n\t/**\n\t * Optional: read directory entries with type info in a single syscall.\n\t * When provided, eliminates per-entry stat() calls for the isDirectory check.\n\t */\n\treaddirEntries?: (\n\t\tabsolutePath: string,\n\t) =>\n\t\t| Promise<Array<{ name: string; isDirectory: () => boolean }>>\n\t\t| Array<{ name: string; isDirectory: () => boolean }>;\n}\n\nconst defaultLsOperations: LsOperations = {\n\texists: existsSync,\n\tstat: statSync,\n\treaddir: readdirSync,\n\treaddirEntries: (p) => fsReaddir(p, { withFileTypes: true }),\n};\n\nexport interface LsToolOptions {\n\t/** Custom operations for directory listing. Default: local filesystem */\n\toperations?: LsOperations;\n}\n\nfunction formatLsCall(\n\targs: { path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.js\").theme,\n): string {\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${path === null ? invalidArg : theme.fg(\"accent\", path)}`;\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatLsResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: LsToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.js\").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 entryLimit = result.details?.entryLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (entryLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (entryLimit) warnings.push(`${entryLimit} entries 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\nexport function createLsToolDefinition(\n\tcwd: string,\n\toptions?: LsToolOptions,\n): ToolDefinition<typeof lsSchema, LsToolDetails | undefined> {\n\tconst ops = options?.operations ?? defaultLsOperations;\n\treturn {\n\t\tname: \"ls\",\n\t\tlabel: \"ls\",\n\t\tdescription: `List one directory (not recursive), sorted alphabetically, '/' suffix for directories. Shows everything on disk including dotfiles and ignored paths; pass 'ignore' globs to skip entries. Truncates at ${DEFAULT_LIMIT} entries / ${DEFAULT_MAX_BYTES / 1024}KB.`,\n\t\tpromptSnippet: \"List directory contents\",\n\t\tparameters: lsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, limit, ignore }: { path?: string; limit?: number; ignore?: string[] },\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\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\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 dirPath = resolveToCwd(path || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\n\t\t\t\t\t\t// Check if path exists.\n\t\t\t\t\t\tif (!(await ops.exists(dirPath))) {\n\t\t\t\t\t\t\treject(new Error(`Path not found: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if path is a directory.\n\t\t\t\t\t\tconst stat = await ops.stat(dirPath);\n\t\t\t\t\t\tif (!stat.isDirectory()) {\n\t\t\t\t\t\t\treject(new Error(`Not a directory: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Exclude entries matching any ignore glob. Match on the bare entry\n\t\t\t\t\t\t// name (ls is non-recursive) with dot:true so patterns can target\n\t\t\t\t\t\t// dotfiles like '.git'. Default behavior (no patterns) still shows\n\t\t\t\t\t\t// everything on disk.\n\t\t\t\t\t\tconst ignorePatterns = (ignore ?? []).filter((p) => typeof p === \"string\" && p.length > 0);\n\n\t\t\t\t\t\t// Fast path: use readdirEntries (single syscall with type info).\n\t\t\t\t\t\t// Slow path: fall back to readdir + per-entry stat.\n\t\t\t\t\t\tconst results: string[] = [];\n\t\t\t\t\t\tlet entryLimitReached = false;\n\n\t\t\t\t\t\tif (ops.readdirEntries) {\n\t\t\t\t\t\t\tlet dirents: Array<{ name: string; isDirectory: () => boolean }>;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tdirents = await ops.readdirEntries(dirPath);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${dirPath}`));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlet filtered = dirents;\n\t\t\t\t\t\t\tif (ignorePatterns.length > 0) {\n\t\t\t\t\t\t\t\tfiltered = dirents.filter(\n\t\t\t\t\t\t\t\t\t(d) => !ignorePatterns.some((pattern) => minimatch(d.name, pattern, { dot: 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\tfiltered.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));\n\t\t\t\t\t\t\tfor (const entry of filtered) {\n\t\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresults.push(entry.name + (entry.isDirectory() ? \"/\" : \"\"));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Fallback: readdir returns strings, stat each entry.\n\t\t\t\t\t\t\tlet entries: string[];\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tentries = await ops.readdir(dirPath);\n\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\tif (e instanceof Error) {\n\t\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${e.message}`));\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${String(e)}`));\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\tconst ignoreFiltered =\n\t\t\t\t\t\t\t\tignorePatterns.length > 0\n\t\t\t\t\t\t\t\t\t? entries.filter(\n\t\t\t\t\t\t\t\t\t\t\t(entry) => !ignorePatterns.some((pattern) => minimatch(entry, pattern, { dot: true })),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t: entries;\n\t\t\t\t\t\t\tignoreFiltered.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\t\t\t\t\t\t\tfor (const entry of ignoreFiltered) {\n\t\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst fullPath = nodePath.join(dirPath, entry);\n\t\t\t\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst entryStat = await ops.stat(fullPath);\n\t\t\t\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\n\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"(empty directory)\" }], details: undefined });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = results.join(\"\\n\");\n\t\t\t\t\t\t// Apply byte truncation. There is no separate line limit because entry count is already capped.\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\tconst details: LsToolDetails = {};\n\t\t\t\t\t\t// Build actionable notices for truncation and entry limits.\n\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\tif (entryLimitReached) {\n\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);\n\t\t\t\t\t\t\tdetails.entryLimitReached = effectiveLimit;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\toutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(e);\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(formatLsCall(args, theme));\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(formatLsResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createLsTool(cwd: string, options?: LsToolOptions): AgentTool<typeof lsSchema> {\n\treturn wrapToolDefinition(createLsToolDefinition(cwd, options));\n}\n"]}
@@ -13,7 +13,7 @@ const lsSchema = Type.Object({
13
13
  path: Type.Optional(Type.String({ description: "Directory to list (default: current directory)" })),
14
14
  limit: Type.Optional(Type.Number({ description: "Maximum number of entries to return (default: 500)" })),
15
15
  ignore: Type.Optional(Type.Array(Type.String(), {
16
- description: "Glob patterns matched against entry names to exclude, e.g. ['node_modules', '*.log', '.git']. Matching is on the entry name only (ls is non-recursive); dotfiles are matched.",
16
+ description: "Globs matched against entry names to exclude, e.g. ['node_modules', '*.log'].",
17
17
  })),
18
18
  });
19
19
  const DEFAULT_LIMIT = 500;
@@ -64,7 +64,7 @@ export function createLsToolDefinition(cwd, options) {
64
64
  return {
65
65
  name: "ls",
66
66
  label: "ls",
67
- description: `List directory contents. Returns entries sorted alphabetically, with '/' suffix for directories. Includes dotfiles. Lists a single directory (not recursive) and shows everything on disk; pass 'ignore' glob patterns to skip entries like node_modules or .git. Output is truncated to ${DEFAULT_LIMIT} entries or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,
67
+ description: `List one directory (not recursive), sorted alphabetically, '/' suffix for directories. Shows everything on disk including dotfiles and ignored paths; pass 'ignore' globs to skip entries. Truncates at ${DEFAULT_LIMIT} entries / ${DEFAULT_MAX_BYTES / 1024}KB.`,
68
68
  promptSnippet: "List directory contents",
69
69
  parameters: lsSchema,
70
70
  async execute(_toolCallId, { path, limit, ignore }, signal, _onUpdate, _ctx) {
@@ -1 +1 @@
1
- {"version":3,"file":"ls.js","sourceRoot":"","sources":["../../../src/core/tools/ls.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { existsSync, readdirSync, statSync } from \"fs\";\nimport { readdir as fsReaddir } from \"fs/promises\";\nimport { minimatch } from \"minimatch\";\nimport nodePath from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport { resolveToCwd } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.js\";\n\nconst lsSchema = Type.Object({\n\tpath: Type.Optional(Type.String({ description: \"Directory to list (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of entries to return (default: 500)\" })),\n\tignore: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription:\n\t\t\t\t\"Glob patterns matched against entry names to exclude, e.g. ['node_modules', '*.log', '.git']. Matching is on the entry name only (ls is non-recursive); dotfiles are matched.\",\n\t\t}),\n\t),\n});\n\nexport type LsToolInput = Static<typeof lsSchema>;\n\nconst DEFAULT_LIMIT = 500;\n\nexport interface LsToolDetails {\n\ttruncation?: TruncationResult;\n\tentryLimitReached?: number;\n}\n\n/**\n * Pluggable operations for the ls tool.\n * Override these to delegate directory listing to remote systems (for example SSH).\n */\nexport interface LsOperations {\n\t/** Check if path exists */\n\texists: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Get file or directory stats. Throws if not found. */\n\tstat: (absolutePath: string) => Promise<{ isDirectory: () => boolean }> | { isDirectory: () => boolean };\n\t/** Read directory entries as strings (used when readdirEntries is not provided) */\n\treaddir: (absolutePath: string) => Promise<string[]> | string[];\n\t/**\n\t * Optional: read directory entries with type info in a single syscall.\n\t * When provided, eliminates per-entry stat() calls for the isDirectory check.\n\t */\n\treaddirEntries?: (\n\t\tabsolutePath: string,\n\t) =>\n\t\t| Promise<Array<{ name: string; isDirectory: () => boolean }>>\n\t\t| Array<{ name: string; isDirectory: () => boolean }>;\n}\n\nconst defaultLsOperations: LsOperations = {\n\texists: existsSync,\n\tstat: statSync,\n\treaddir: readdirSync,\n\treaddirEntries: (p) => fsReaddir(p, { withFileTypes: true }),\n};\n\nexport interface LsToolOptions {\n\t/** Custom operations for directory listing. Default: local filesystem */\n\toperations?: LsOperations;\n}\n\nfunction formatLsCall(\n\targs: { path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.js\").theme,\n): string {\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${path === null ? invalidArg : theme.fg(\"accent\", path)}`;\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatLsResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: LsToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.js\").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 entryLimit = result.details?.entryLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (entryLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (entryLimit) warnings.push(`${entryLimit} entries 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\nexport function createLsToolDefinition(\n\tcwd: string,\n\toptions?: LsToolOptions,\n): ToolDefinition<typeof lsSchema, LsToolDetails | undefined> {\n\tconst ops = options?.operations ?? defaultLsOperations;\n\treturn {\n\t\tname: \"ls\",\n\t\tlabel: \"ls\",\n\t\tdescription: `List directory contents. Returns entries sorted alphabetically, with '/' suffix for directories. Includes dotfiles. Lists a single directory (not recursive) and shows everything on disk; pass 'ignore' glob patterns to skip entries like node_modules or .git. Output is truncated to ${DEFAULT_LIMIT} entries or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\n\t\tpromptSnippet: \"List directory contents\",\n\t\tparameters: lsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, limit, ignore }: { path?: string; limit?: number; ignore?: string[] },\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\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\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 dirPath = resolveToCwd(path || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\n\t\t\t\t\t\t// Check if path exists.\n\t\t\t\t\t\tif (!(await ops.exists(dirPath))) {\n\t\t\t\t\t\t\treject(new Error(`Path not found: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if path is a directory.\n\t\t\t\t\t\tconst stat = await ops.stat(dirPath);\n\t\t\t\t\t\tif (!stat.isDirectory()) {\n\t\t\t\t\t\t\treject(new Error(`Not a directory: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Exclude entries matching any ignore glob. Match on the bare entry\n\t\t\t\t\t\t// name (ls is non-recursive) with dot:true so patterns can target\n\t\t\t\t\t\t// dotfiles like '.git'. Default behavior (no patterns) still shows\n\t\t\t\t\t\t// everything on disk.\n\t\t\t\t\t\tconst ignorePatterns = (ignore ?? []).filter((p) => typeof p === \"string\" && p.length > 0);\n\n\t\t\t\t\t\t// Fast path: use readdirEntries (single syscall with type info).\n\t\t\t\t\t\t// Slow path: fall back to readdir + per-entry stat.\n\t\t\t\t\t\tconst results: string[] = [];\n\t\t\t\t\t\tlet entryLimitReached = false;\n\n\t\t\t\t\t\tif (ops.readdirEntries) {\n\t\t\t\t\t\t\tlet dirents: Array<{ name: string; isDirectory: () => boolean }>;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tdirents = await ops.readdirEntries(dirPath);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${dirPath}`));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlet filtered = dirents;\n\t\t\t\t\t\t\tif (ignorePatterns.length > 0) {\n\t\t\t\t\t\t\t\tfiltered = dirents.filter(\n\t\t\t\t\t\t\t\t\t(d) => !ignorePatterns.some((pattern) => minimatch(d.name, pattern, { dot: 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\tfiltered.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));\n\t\t\t\t\t\t\tfor (const entry of filtered) {\n\t\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresults.push(entry.name + (entry.isDirectory() ? \"/\" : \"\"));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Fallback: readdir returns strings, stat each entry.\n\t\t\t\t\t\t\tlet entries: string[];\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tentries = await ops.readdir(dirPath);\n\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\tif (e instanceof Error) {\n\t\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${e.message}`));\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${String(e)}`));\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\tconst ignoreFiltered =\n\t\t\t\t\t\t\t\tignorePatterns.length > 0\n\t\t\t\t\t\t\t\t\t? entries.filter(\n\t\t\t\t\t\t\t\t\t\t\t(entry) => !ignorePatterns.some((pattern) => minimatch(entry, pattern, { dot: true })),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t: entries;\n\t\t\t\t\t\t\tignoreFiltered.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\t\t\t\t\t\t\tfor (const entry of ignoreFiltered) {\n\t\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst fullPath = nodePath.join(dirPath, entry);\n\t\t\t\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst entryStat = await ops.stat(fullPath);\n\t\t\t\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\n\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"(empty directory)\" }], details: undefined });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = results.join(\"\\n\");\n\t\t\t\t\t\t// Apply byte truncation. There is no separate line limit because entry count is already capped.\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\tconst details: LsToolDetails = {};\n\t\t\t\t\t\t// Build actionable notices for truncation and entry limits.\n\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\tif (entryLimitReached) {\n\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);\n\t\t\t\t\t\t\tdetails.entryLimitReached = effectiveLimit;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\toutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(e);\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(formatLsCall(args, theme));\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(formatLsResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createLsTool(cwd: string, options?: LsToolOptions): AgentTool<typeof lsSchema> {\n\treturn wrapToolDefinition(createLsToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"ls.js","sourceRoot":"","sources":["../../../src/core/tools/ls.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { existsSync, readdirSync, statSync } from \"fs\";\nimport { readdir as fsReaddir } from \"fs/promises\";\nimport { minimatch } from \"minimatch\";\nimport nodePath from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport { resolveToCwd } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.js\";\n\nconst lsSchema = Type.Object({\n\tpath: Type.Optional(Type.String({ description: \"Directory to list (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of entries to return (default: 500)\" })),\n\tignore: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription: \"Globs matched against entry names to exclude, e.g. ['node_modules', '*.log'].\",\n\t\t}),\n\t),\n});\n\nexport type LsToolInput = Static<typeof lsSchema>;\n\nconst DEFAULT_LIMIT = 500;\n\nexport interface LsToolDetails {\n\ttruncation?: TruncationResult;\n\tentryLimitReached?: number;\n}\n\n/**\n * Pluggable operations for the ls tool.\n * Override these to delegate directory listing to remote systems (for example SSH).\n */\nexport interface LsOperations {\n\t/** Check if path exists */\n\texists: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Get file or directory stats. Throws if not found. */\n\tstat: (absolutePath: string) => Promise<{ isDirectory: () => boolean }> | { isDirectory: () => boolean };\n\t/** Read directory entries as strings (used when readdirEntries is not provided) */\n\treaddir: (absolutePath: string) => Promise<string[]> | string[];\n\t/**\n\t * Optional: read directory entries with type info in a single syscall.\n\t * When provided, eliminates per-entry stat() calls for the isDirectory check.\n\t */\n\treaddirEntries?: (\n\t\tabsolutePath: string,\n\t) =>\n\t\t| Promise<Array<{ name: string; isDirectory: () => boolean }>>\n\t\t| Array<{ name: string; isDirectory: () => boolean }>;\n}\n\nconst defaultLsOperations: LsOperations = {\n\texists: existsSync,\n\tstat: statSync,\n\treaddir: readdirSync,\n\treaddirEntries: (p) => fsReaddir(p, { withFileTypes: true }),\n};\n\nexport interface LsToolOptions {\n\t/** Custom operations for directory listing. Default: local filesystem */\n\toperations?: LsOperations;\n}\n\nfunction formatLsCall(\n\targs: { path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.js\").theme,\n): string {\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${path === null ? invalidArg : theme.fg(\"accent\", path)}`;\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatLsResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: LsToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.js\").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 entryLimit = result.details?.entryLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (entryLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (entryLimit) warnings.push(`${entryLimit} entries 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\nexport function createLsToolDefinition(\n\tcwd: string,\n\toptions?: LsToolOptions,\n): ToolDefinition<typeof lsSchema, LsToolDetails | undefined> {\n\tconst ops = options?.operations ?? defaultLsOperations;\n\treturn {\n\t\tname: \"ls\",\n\t\tlabel: \"ls\",\n\t\tdescription: `List one directory (not recursive), sorted alphabetically, '/' suffix for directories. Shows everything on disk including dotfiles and ignored paths; pass 'ignore' globs to skip entries. Truncates at ${DEFAULT_LIMIT} entries / ${DEFAULT_MAX_BYTES / 1024}KB.`,\n\t\tpromptSnippet: \"List directory contents\",\n\t\tparameters: lsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, limit, ignore }: { path?: string; limit?: number; ignore?: string[] },\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\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\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 dirPath = resolveToCwd(path || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\n\t\t\t\t\t\t// Check if path exists.\n\t\t\t\t\t\tif (!(await ops.exists(dirPath))) {\n\t\t\t\t\t\t\treject(new Error(`Path not found: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if path is a directory.\n\t\t\t\t\t\tconst stat = await ops.stat(dirPath);\n\t\t\t\t\t\tif (!stat.isDirectory()) {\n\t\t\t\t\t\t\treject(new Error(`Not a directory: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Exclude entries matching any ignore glob. Match on the bare entry\n\t\t\t\t\t\t// name (ls is non-recursive) with dot:true so patterns can target\n\t\t\t\t\t\t// dotfiles like '.git'. Default behavior (no patterns) still shows\n\t\t\t\t\t\t// everything on disk.\n\t\t\t\t\t\tconst ignorePatterns = (ignore ?? []).filter((p) => typeof p === \"string\" && p.length > 0);\n\n\t\t\t\t\t\t// Fast path: use readdirEntries (single syscall with type info).\n\t\t\t\t\t\t// Slow path: fall back to readdir + per-entry stat.\n\t\t\t\t\t\tconst results: string[] = [];\n\t\t\t\t\t\tlet entryLimitReached = false;\n\n\t\t\t\t\t\tif (ops.readdirEntries) {\n\t\t\t\t\t\t\tlet dirents: Array<{ name: string; isDirectory: () => boolean }>;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tdirents = await ops.readdirEntries(dirPath);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${dirPath}`));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlet filtered = dirents;\n\t\t\t\t\t\t\tif (ignorePatterns.length > 0) {\n\t\t\t\t\t\t\t\tfiltered = dirents.filter(\n\t\t\t\t\t\t\t\t\t(d) => !ignorePatterns.some((pattern) => minimatch(d.name, pattern, { dot: 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\tfiltered.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));\n\t\t\t\t\t\t\tfor (const entry of filtered) {\n\t\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresults.push(entry.name + (entry.isDirectory() ? \"/\" : \"\"));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Fallback: readdir returns strings, stat each entry.\n\t\t\t\t\t\t\tlet entries: string[];\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tentries = await ops.readdir(dirPath);\n\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\tif (e instanceof Error) {\n\t\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${e.message}`));\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${String(e)}`));\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\tconst ignoreFiltered =\n\t\t\t\t\t\t\t\tignorePatterns.length > 0\n\t\t\t\t\t\t\t\t\t? entries.filter(\n\t\t\t\t\t\t\t\t\t\t\t(entry) => !ignorePatterns.some((pattern) => minimatch(entry, pattern, { dot: true })),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t: entries;\n\t\t\t\t\t\t\tignoreFiltered.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\t\t\t\t\t\t\tfor (const entry of ignoreFiltered) {\n\t\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst fullPath = nodePath.join(dirPath, entry);\n\t\t\t\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst entryStat = await ops.stat(fullPath);\n\t\t\t\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\n\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"(empty directory)\" }], details: undefined });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = results.join(\"\\n\");\n\t\t\t\t\t\t// Apply byte truncation. There is no separate line limit because entry count is already capped.\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\tconst details: LsToolDetails = {};\n\t\t\t\t\t\t// Build actionable notices for truncation and entry limits.\n\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\tif (entryLimitReached) {\n\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);\n\t\t\t\t\t\t\tdetails.entryLimitReached = effectiveLimit;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\toutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(e);\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(formatLsCall(args, theme));\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(formatLsResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createLsTool(cwd: string, options?: LsToolOptions): AgentTool<typeof lsSchema> {\n\treturn wrapToolDefinition(createLsToolDefinition(cwd, options));\n}\n"]}
@@ -18,7 +18,7 @@
18
18
  * are matched with `minimatch` and patterns with JS `RegExp`, and only
19
19
  * `.gitignore` files are honoured (not `.ignore` or global excludes).
20
20
  */
21
- export type EntryType = "f" | "d" | "l";
21
+ type EntryType = "f" | "d" | "l";
22
22
  export interface CollectedEntry {
23
23
  /** Absolute path. */
24
24
  abs: string;
@@ -54,7 +54,7 @@ export interface NativeFindOptions {
54
54
  * the caller applies its own dedupe/sort/limit.
55
55
  */
56
56
  export declare function nativeFind(root: string, opts: NativeFindOptions): string[];
57
- export interface NativeGrepMatch {
57
+ interface NativeGrepMatch {
58
58
  filePath: string;
59
59
  lineNumber: number;
60
60
  lineText: string;
@@ -87,4 +87,5 @@ export interface NativeGrepResult {
87
87
  export declare function nativeGrep(root: string, opts: NativeGrepOptions): Promise<NativeGrepResult>;
88
88
  /** Whether the native search path is forced regardless of fd/rg availability. */
89
89
  export declare function isNativeSearchForced(): boolean;
90
+ export {};
90
91
  //# sourceMappingURL=native-search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"native-search.d.ts","sourceRoot":"","sources":["../../../src/core/tools/native-search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAQH,MAAM,MAAM,SAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAUxC,MAAM,WAAW,cAAc;IAC9B,qBAAqB;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,SAAS,CAAC;CAChB;AAiCD,MAAM,WAAW,WAAW;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,iEAAiE;IACjE,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,cAAc,EAAE,CA8DrF;AA0DD,MAAM,WAAW,iBAAiB;IACjC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,SAAS,CAAC;IAChB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAkB1E;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC7D;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;CAC3B;AAeD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA+DjG;AAED,iFAAiF;AACjF,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C","sourcesContent":["/**\n * Native (pure-JS) fallbacks for the `find` and `grep` tools.\n *\n * The tools normally shell out to `fd` / `rg`, which are downloaded on demand\n * (see tools-manager.ts). In restricted environments those binaries may be\n * neither on PATH nor downloadable, and `HOOCODE_NATIVE_SEARCH=1` can also force\n * this path. Rather than failing the tool and asking the model to fall back to\n * `bash`, these functions reproduce the essential behaviour in JS so search\n * degrades automatically:\n *\n * - hierarchical `.gitignore` handling (each `.gitignore` is scoped to its own\n * subtree, matching fd's `--no-require-git` behaviour and issue #3303),\n * - hidden files included (like `fd --hidden` / `rg --hidden`),\n * - `.git` always skipped; `node_modules` skipped for `find` (mirrors the\n * tool's built-in excludes) but left to `.gitignore` for `grep` (like rg).\n *\n * These are best-effort approximations, not byte-for-byte fd/rg parity: globs\n * are matched with `minimatch` and patterns with JS `RegExp`, and only\n * `.gitignore` files are honoured (not `.ignore` or global excludes).\n */\n\nimport { readdirSync, readFileSync, statSync } from \"fs\";\nimport ignore, { type Ignore } from \"ignore\";\nimport { minimatch } from \"minimatch\";\nimport path from \"path\";\nimport { toPosixPath } from \"./fd-utils.js\";\n\nexport type EntryType = \"f\" | \"d\" | \"l\";\n\n/** Hard cap on entries enumerated during a single walk, so a pathological tree\n * can never hang the fallback. Well above any tool's own result limit. */\nconst MAX_ENTRIES = 200_000;\n\n/** Files larger than this are skipped by the grep fallback (rg streams; we read\n * whole files, so we guard against loading huge blobs into memory). */\nconst MAX_GREP_FILE_BYTES = 20 * 1024 * 1024;\n\nexport interface CollectedEntry {\n\t/** Absolute path. */\n\tabs: string;\n\t/** POSIX path relative to the walk root. */\n\trel: string;\n\ttype: EntryType;\n}\n\n/** A `.gitignore` matcher scoped to the subtree rooted at `baseDir`. */\ninterface GitignoreMatcher {\n\tbaseDir: string;\n\tig: Ignore;\n}\n\nfunction loadGitignore(dir: string): Ignore | undefined {\n\tlet content: string;\n\ttry {\n\t\tcontent = readFileSync(path.join(dir, \".gitignore\"), \"utf-8\");\n\t} catch {\n\t\treturn undefined;\n\t}\n\treturn ignore().add(content);\n}\n\n/**\n * Whether `absPath` is ignored by any applicable `.gitignore`. Each matcher only\n * applies to paths inside its `baseDir`, and the path is tested relative to that\n * base — so `a/.gitignore` scopes to `a/` and its descendants but never `b/`.\n */\nfunction isGitIgnored(absPath: string, isDir: boolean, matchers: GitignoreMatcher[]): boolean {\n\tfor (const m of matchers) {\n\t\tconst rel = path.relative(m.baseDir, absPath);\n\t\tif (rel === \"\" || rel.startsWith(\"..\") || path.isAbsolute(rel)) continue;\n\t\tconst relPosix = toPosixPath(rel) + (isDir ? \"/\" : \"\");\n\t\tif (m.ig.ignores(relPosix)) return true;\n\t}\n\treturn false;\n}\n\nexport interface WalkOptions {\n\t/** Max entry depth relative to root; direct children are depth 1. */\n\tmaxDepth?: number;\n\tsignal?: AbortSignal;\n\t/** Directory names to never descend into. Defaults to `.git`. */\n\talwaysSkipDirs?: Set<string>;\n}\n\n/**\n * Walk `root` depth-first, returning every entry not excluded by `.gitignore`\n * or an always-skip directory. Symlinks are reported but never followed (avoids\n * cycles). Enumeration stops at {@link MAX_ENTRIES}.\n */\nexport function collectEntries(root: string, opts: WalkOptions = {}): CollectedEntry[] {\n\tconst out: CollectedEntry[] = [];\n\tconst alwaysSkip = opts.alwaysSkipDirs ?? new Set([\".git\"]);\n\n\tconst rootMatchers: GitignoreMatcher[] = [];\n\tconst rootIg = loadGitignore(root);\n\tif (rootIg) rootMatchers.push({ baseDir: root, ig: rootIg });\n\n\t// `depth` is the depth of `dir`; its direct children are at depth + 1.\n\tconst stack: Array<{ dir: string; depth: number; matchers: GitignoreMatcher[] }> = [\n\t\t{ dir: root, depth: 0, matchers: rootMatchers },\n\t];\n\n\twhile (stack.length > 0) {\n\t\tif (out.length >= MAX_ENTRIES || opts.signal?.aborted) break;\n\t\tconst { dir, depth, matchers } = stack.pop()!;\n\n\t\tlet dirents: import(\"fs\").Dirent[];\n\t\ttry {\n\t\t\tdirents = readdirSync(dir, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue; // unreadable directory — skip rather than abort the whole walk\n\t\t}\n\n\t\tconst entryDepth = depth + 1;\n\t\tfor (const dirent of dirents) {\n\t\t\tif (out.length >= MAX_ENTRIES) break;\n\n\t\t\tconst name = dirent.name;\n\t\t\tconst abs = path.join(dir, name);\n\n\t\t\tlet type: EntryType;\n\t\t\tlet isDir = false;\n\t\t\tif (dirent.isSymbolicLink()) {\n\t\t\t\ttype = \"l\";\n\t\t\t} else if (dirent.isDirectory()) {\n\t\t\t\ttype = \"d\";\n\t\t\t\tisDir = true;\n\t\t\t} else if (dirent.isFile()) {\n\t\t\t\ttype = \"f\";\n\t\t\t} else {\n\t\t\t\tcontinue; // sockets, fifos, block devices, …\n\t\t\t}\n\n\t\t\tif (isDir && alwaysSkip.has(name)) continue;\n\t\t\tif (isGitIgnored(abs, isDir, matchers)) continue;\n\n\t\t\tif (opts.maxDepth === undefined || entryDepth <= opts.maxDepth) {\n\t\t\t\tout.push({ abs, rel: toPosixPath(path.relative(root, abs)), type });\n\t\t\t}\n\n\t\t\t// Descend only into real directories, and only if their children can\n\t\t\t// still be within the depth budget.\n\t\t\tif (isDir && (opts.maxDepth === undefined || entryDepth < opts.maxDepth)) {\n\t\t\t\tconst childIg = loadGitignore(abs);\n\t\t\t\tconst nextMatchers = childIg ? [...matchers, { baseDir: abs, ig: childIg }] : matchers;\n\t\t\t\tstack.push({ dir: abs, depth: entryDepth, matchers: nextMatchers });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn out;\n}\n\n/**\n * Reject globs fd's parser would reject. minimatch silently treats an unclosed\n * `[` or `{` as literal text, which made the fallback resolve \"no results\"\n * where the fd path errors — same call, different outcome. Error messages\n * mirror fd/globset so callers (and tests) can match either path.\n */\nfunction validateGlob(pattern: string): void {\n\tlet inClass = false;\n\tlet braceDepth = 0;\n\tfor (let i = 0; i < pattern.length; i++) {\n\t\tconst c = pattern[i];\n\t\tif (c === \"\\\\\") {\n\t\t\ti++; // skip escaped char\n\t\t} else if (inClass) {\n\t\t\tif (c === \"]\") inClass = false;\n\t\t} else if (c === \"[\") {\n\t\t\tinClass = true;\n\t\t} else if (c === \"{\") {\n\t\t\tbraceDepth++;\n\t\t} else if (c === \"}\") {\n\t\t\tif (braceDepth > 0) braceDepth--;\n\t\t}\n\t}\n\tif (inClass) {\n\t\tthrow new Error(`error parsing glob '${pattern}': unclosed character class; missing ']'`);\n\t}\n\tif (braceDepth > 0) {\n\t\tthrow new Error(`error parsing glob '${pattern}': unclosed alternate group; missing '}'`);\n\t}\n}\n\n/** fd smart-case: a pattern without uppercase letters matches case-insensitively. */\nfunction isSmartCaseInsensitive(pattern: string): boolean {\n\treturn !/[A-Z]/.test(pattern);\n}\n\n/**\n * Match a `find` glob against a POSIX relative path, mirroring fd's semantics:\n * a slashless pattern matches the basename at any depth; a pattern containing a\n * slash matches the full path and is anchored anywhere in the tree. Case\n * sensitivity is smart-case, like fd.\n */\nfunction matchesFindPattern(relPosix: string, pattern: string): boolean {\n\tconst nocase = isSmartCaseInsensitive(pattern);\n\tif (pattern.includes(\"/\")) {\n\t\tlet p = pattern;\n\t\tif (p.startsWith(\"/\")) {\n\t\t\tp = p.slice(1); // leading slash anchors to root; rel paths have no leading slash\n\t\t} else if (!p.startsWith(\"**/\") && p !== \"**\") {\n\t\t\tp = `**/${p}`;\n\t\t}\n\t\treturn minimatch(relPosix, p, { dot: true, nocase });\n\t}\n\treturn minimatch(relPosix, pattern, { dot: true, matchBase: true, nocase });\n}\n\nexport interface NativeFindOptions {\n\tpatterns: string[];\n\ttype: EntryType;\n\t/** Extra exclusion globs (already includes node_modules/.git for find). */\n\texcludeGlobs: string[];\n\tmaxDepth?: number;\n\talwaysSkipDirs?: Set<string>;\n\tsignal?: AbortSignal;\n}\n\n/**\n * Native replacement for the fd-backed search. Returns POSIX paths relative to\n * `root`, with a trailing slash on directories (like fd), unsorted/undeduped —\n * the caller applies its own dedupe/sort/limit.\n */\nexport function nativeFind(root: string, opts: NativeFindOptions): string[] {\n\tfor (const pattern of opts.patterns) validateGlob(pattern);\n\tfor (const glob of opts.excludeGlobs) validateGlob(glob);\n\n\tconst entries = collectEntries(root, {\n\t\tmaxDepth: opts.maxDepth,\n\t\tsignal: opts.signal,\n\t\talwaysSkipDirs: opts.alwaysSkipDirs,\n\t});\n\n\tconst results: string[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== opts.type) continue;\n\t\tif (opts.excludeGlobs.some((g) => minimatch(entry.rel, g, { dot: true }))) continue;\n\t\tif (!opts.patterns.some((pat) => matchesFindPattern(entry.rel, pat))) continue;\n\t\tresults.push(entry.type === \"d\" ? `${entry.rel}/` : entry.rel);\n\t}\n\treturn results;\n}\n\nexport interface NativeGrepMatch {\n\tfilePath: string;\n\tlineNumber: number;\n\tlineText: string;\n}\n\nexport interface NativeGrepOptions {\n\tpattern: string;\n\t/** True when `root` is a directory; false when it is a single file. */\n\tisDirectory: boolean;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\t/** Optional glob filter applied to file paths (like rg --glob). */\n\tglob?: string;\n\t/** Stop after this many matches. */\n\tlimit: number;\n\tsignal?: AbortSignal;\n\treadFile: (absolutePath: string) => Promise<string> | string;\n}\n\nexport interface NativeGrepResult {\n\tmatches: NativeGrepMatch[];\n\tmatchLimitReached: boolean;\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/** Cheap binary-file heuristic: a NUL byte in the first chunk. rg skips these. */\nfunction looksBinary(content: string): boolean {\n\tconst sampleLength = Math.min(content.length, 8192);\n\tfor (let i = 0; i < sampleLength; i++) {\n\t\tif (content.charCodeAt(i) === 0) return true;\n\t}\n\treturn false;\n}\n\n/**\n * Native replacement for the rg-backed content search. Collects up to `limit`\n * matches as `{ filePath, lineNumber, lineText }`, the same shape the tool's\n * formatter already consumes from rg's JSON output.\n *\n * Throws an Error tagged `invalidRegex` when a non-literal pattern is not a\n * valid JS regex, so the caller can surface the same \"pass literal: true\" hint.\n */\nexport async function nativeGrep(root: string, opts: NativeGrepOptions): Promise<NativeGrepResult> {\n\tlet regex: RegExp;\n\tconst flags = opts.ignoreCase ? \"i\" : \"\";\n\tif (opts.literal) {\n\t\tregex = new RegExp(escapeRegExp(opts.pattern), flags);\n\t} else {\n\t\ttry {\n\t\t\tregex = new RegExp(opts.pattern, flags);\n\t\t} catch (e) {\n\t\t\tconst error = new Error(e instanceof Error ? e.message : String(e)) as Error & { invalidRegex?: boolean };\n\t\t\terror.invalidRegex = true;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tlet files: string[];\n\tif (!opts.isDirectory) {\n\t\tfiles = [root];\n\t} else {\n\t\tconst entries = collectEntries(root, { signal: opts.signal });\n\t\tfiles = entries\n\t\t\t.filter((e) => e.type === \"f\")\n\t\t\t.filter((e) => {\n\t\t\t\tif (!opts.glob) return true;\n\t\t\t\treturn minimatch(e.rel, opts.glob, { dot: true, matchBase: !opts.glob.includes(\"/\") });\n\t\t\t})\n\t\t\t.map((e) => e.abs);\n\t}\n\n\tconst matches: NativeGrepMatch[] = [];\n\tlet matchLimitReached = false;\n\n\tfor (const filePath of files) {\n\t\tif (opts.signal?.aborted || matches.length >= opts.limit) break;\n\n\t\ttry {\n\t\t\tif (statSync(filePath).size > MAX_GREP_FILE_BYTES) continue;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet content: string;\n\t\ttry {\n\t\t\tcontent = await opts.readFile(filePath);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (looksBinary(content)) continue;\n\n\t\tconst lines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t// New RegExp per file with no /g flag → test() is stateless across lines.\n\t\t\tif (regex.test(lines[i])) {\n\t\t\t\tmatches.push({ filePath, lineNumber: i + 1, lineText: lines[i] });\n\t\t\t\tif (matches.length >= opts.limit) {\n\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { matches, matchLimitReached };\n}\n\n/** Whether the native search path is forced regardless of fd/rg availability. */\nexport function isNativeSearchForced(): boolean {\n\treturn process.env.HOOCODE_NATIVE_SEARCH === \"1\";\n}\n"]}
1
+ {"version":3,"file":"native-search.d.ts","sourceRoot":"","sources":["../../../src/core/tools/native-search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAQH,KAAK,SAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAUjC,MAAM,WAAW,cAAc;IAC9B,qBAAqB;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,SAAS,CAAC;CAChB;AAiCD,MAAM,WAAW,WAAW;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,iEAAiE;IACjE,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,cAAc,EAAE,CA8DrF;AA0DD,MAAM,WAAW,iBAAiB;IACjC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,SAAS,CAAC;IAChB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAkB1E;AAED,UAAU,eAAe;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC7D;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;CAC3B;AAeD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA+DjG;AAED,iFAAiF;AACjF,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C","sourcesContent":["/**\n * Native (pure-JS) fallbacks for the `find` and `grep` tools.\n *\n * The tools normally shell out to `fd` / `rg`, which are downloaded on demand\n * (see tools-manager.ts). In restricted environments those binaries may be\n * neither on PATH nor downloadable, and `HOOCODE_NATIVE_SEARCH=1` can also force\n * this path. Rather than failing the tool and asking the model to fall back to\n * `bash`, these functions reproduce the essential behaviour in JS so search\n * degrades automatically:\n *\n * - hierarchical `.gitignore` handling (each `.gitignore` is scoped to its own\n * subtree, matching fd's `--no-require-git` behaviour and issue #3303),\n * - hidden files included (like `fd --hidden` / `rg --hidden`),\n * - `.git` always skipped; `node_modules` skipped for `find` (mirrors the\n * tool's built-in excludes) but left to `.gitignore` for `grep` (like rg).\n *\n * These are best-effort approximations, not byte-for-byte fd/rg parity: globs\n * are matched with `minimatch` and patterns with JS `RegExp`, and only\n * `.gitignore` files are honoured (not `.ignore` or global excludes).\n */\n\nimport { readdirSync, readFileSync, statSync } from \"fs\";\nimport ignore, { type Ignore } from \"ignore\";\nimport { minimatch } from \"minimatch\";\nimport path from \"path\";\nimport { toPosixPath } from \"./fd-utils.js\";\n\ntype EntryType = \"f\" | \"d\" | \"l\";\n\n/** Hard cap on entries enumerated during a single walk, so a pathological tree\n * can never hang the fallback. Well above any tool's own result limit. */\nconst MAX_ENTRIES = 200_000;\n\n/** Files larger than this are skipped by the grep fallback (rg streams; we read\n * whole files, so we guard against loading huge blobs into memory). */\nconst MAX_GREP_FILE_BYTES = 20 * 1024 * 1024;\n\nexport interface CollectedEntry {\n\t/** Absolute path. */\n\tabs: string;\n\t/** POSIX path relative to the walk root. */\n\trel: string;\n\ttype: EntryType;\n}\n\n/** A `.gitignore` matcher scoped to the subtree rooted at `baseDir`. */\ninterface GitignoreMatcher {\n\tbaseDir: string;\n\tig: Ignore;\n}\n\nfunction loadGitignore(dir: string): Ignore | undefined {\n\tlet content: string;\n\ttry {\n\t\tcontent = readFileSync(path.join(dir, \".gitignore\"), \"utf-8\");\n\t} catch {\n\t\treturn undefined;\n\t}\n\treturn ignore().add(content);\n}\n\n/**\n * Whether `absPath` is ignored by any applicable `.gitignore`. Each matcher only\n * applies to paths inside its `baseDir`, and the path is tested relative to that\n * base — so `a/.gitignore` scopes to `a/` and its descendants but never `b/`.\n */\nfunction isGitIgnored(absPath: string, isDir: boolean, matchers: GitignoreMatcher[]): boolean {\n\tfor (const m of matchers) {\n\t\tconst rel = path.relative(m.baseDir, absPath);\n\t\tif (rel === \"\" || rel.startsWith(\"..\") || path.isAbsolute(rel)) continue;\n\t\tconst relPosix = toPosixPath(rel) + (isDir ? \"/\" : \"\");\n\t\tif (m.ig.ignores(relPosix)) return true;\n\t}\n\treturn false;\n}\n\nexport interface WalkOptions {\n\t/** Max entry depth relative to root; direct children are depth 1. */\n\tmaxDepth?: number;\n\tsignal?: AbortSignal;\n\t/** Directory names to never descend into. Defaults to `.git`. */\n\talwaysSkipDirs?: Set<string>;\n}\n\n/**\n * Walk `root` depth-first, returning every entry not excluded by `.gitignore`\n * or an always-skip directory. Symlinks are reported but never followed (avoids\n * cycles). Enumeration stops at {@link MAX_ENTRIES}.\n */\nexport function collectEntries(root: string, opts: WalkOptions = {}): CollectedEntry[] {\n\tconst out: CollectedEntry[] = [];\n\tconst alwaysSkip = opts.alwaysSkipDirs ?? new Set([\".git\"]);\n\n\tconst rootMatchers: GitignoreMatcher[] = [];\n\tconst rootIg = loadGitignore(root);\n\tif (rootIg) rootMatchers.push({ baseDir: root, ig: rootIg });\n\n\t// `depth` is the depth of `dir`; its direct children are at depth + 1.\n\tconst stack: Array<{ dir: string; depth: number; matchers: GitignoreMatcher[] }> = [\n\t\t{ dir: root, depth: 0, matchers: rootMatchers },\n\t];\n\n\twhile (stack.length > 0) {\n\t\tif (out.length >= MAX_ENTRIES || opts.signal?.aborted) break;\n\t\tconst { dir, depth, matchers } = stack.pop()!;\n\n\t\tlet dirents: import(\"fs\").Dirent[];\n\t\ttry {\n\t\t\tdirents = readdirSync(dir, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue; // unreadable directory — skip rather than abort the whole walk\n\t\t}\n\n\t\tconst entryDepth = depth + 1;\n\t\tfor (const dirent of dirents) {\n\t\t\tif (out.length >= MAX_ENTRIES) break;\n\n\t\t\tconst name = dirent.name;\n\t\t\tconst abs = path.join(dir, name);\n\n\t\t\tlet type: EntryType;\n\t\t\tlet isDir = false;\n\t\t\tif (dirent.isSymbolicLink()) {\n\t\t\t\ttype = \"l\";\n\t\t\t} else if (dirent.isDirectory()) {\n\t\t\t\ttype = \"d\";\n\t\t\t\tisDir = true;\n\t\t\t} else if (dirent.isFile()) {\n\t\t\t\ttype = \"f\";\n\t\t\t} else {\n\t\t\t\tcontinue; // sockets, fifos, block devices, …\n\t\t\t}\n\n\t\t\tif (isDir && alwaysSkip.has(name)) continue;\n\t\t\tif (isGitIgnored(abs, isDir, matchers)) continue;\n\n\t\t\tif (opts.maxDepth === undefined || entryDepth <= opts.maxDepth) {\n\t\t\t\tout.push({ abs, rel: toPosixPath(path.relative(root, abs)), type });\n\t\t\t}\n\n\t\t\t// Descend only into real directories, and only if their children can\n\t\t\t// still be within the depth budget.\n\t\t\tif (isDir && (opts.maxDepth === undefined || entryDepth < opts.maxDepth)) {\n\t\t\t\tconst childIg = loadGitignore(abs);\n\t\t\t\tconst nextMatchers = childIg ? [...matchers, { baseDir: abs, ig: childIg }] : matchers;\n\t\t\t\tstack.push({ dir: abs, depth: entryDepth, matchers: nextMatchers });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn out;\n}\n\n/**\n * Reject globs fd's parser would reject. minimatch silently treats an unclosed\n * `[` or `{` as literal text, which made the fallback resolve \"no results\"\n * where the fd path errors — same call, different outcome. Error messages\n * mirror fd/globset so callers (and tests) can match either path.\n */\nfunction validateGlob(pattern: string): void {\n\tlet inClass = false;\n\tlet braceDepth = 0;\n\tfor (let i = 0; i < pattern.length; i++) {\n\t\tconst c = pattern[i];\n\t\tif (c === \"\\\\\") {\n\t\t\ti++; // skip escaped char\n\t\t} else if (inClass) {\n\t\t\tif (c === \"]\") inClass = false;\n\t\t} else if (c === \"[\") {\n\t\t\tinClass = true;\n\t\t} else if (c === \"{\") {\n\t\t\tbraceDepth++;\n\t\t} else if (c === \"}\") {\n\t\t\tif (braceDepth > 0) braceDepth--;\n\t\t}\n\t}\n\tif (inClass) {\n\t\tthrow new Error(`error parsing glob '${pattern}': unclosed character class; missing ']'`);\n\t}\n\tif (braceDepth > 0) {\n\t\tthrow new Error(`error parsing glob '${pattern}': unclosed alternate group; missing '}'`);\n\t}\n}\n\n/** fd smart-case: a pattern without uppercase letters matches case-insensitively. */\nfunction isSmartCaseInsensitive(pattern: string): boolean {\n\treturn !/[A-Z]/.test(pattern);\n}\n\n/**\n * Match a `find` glob against a POSIX relative path, mirroring fd's semantics:\n * a slashless pattern matches the basename at any depth; a pattern containing a\n * slash matches the full path and is anchored anywhere in the tree. Case\n * sensitivity is smart-case, like fd.\n */\nfunction matchesFindPattern(relPosix: string, pattern: string): boolean {\n\tconst nocase = isSmartCaseInsensitive(pattern);\n\tif (pattern.includes(\"/\")) {\n\t\tlet p = pattern;\n\t\tif (p.startsWith(\"/\")) {\n\t\t\tp = p.slice(1); // leading slash anchors to root; rel paths have no leading slash\n\t\t} else if (!p.startsWith(\"**/\") && p !== \"**\") {\n\t\t\tp = `**/${p}`;\n\t\t}\n\t\treturn minimatch(relPosix, p, { dot: true, nocase });\n\t}\n\treturn minimatch(relPosix, pattern, { dot: true, matchBase: true, nocase });\n}\n\nexport interface NativeFindOptions {\n\tpatterns: string[];\n\ttype: EntryType;\n\t/** Extra exclusion globs (already includes node_modules/.git for find). */\n\texcludeGlobs: string[];\n\tmaxDepth?: number;\n\talwaysSkipDirs?: Set<string>;\n\tsignal?: AbortSignal;\n}\n\n/**\n * Native replacement for the fd-backed search. Returns POSIX paths relative to\n * `root`, with a trailing slash on directories (like fd), unsorted/undeduped —\n * the caller applies its own dedupe/sort/limit.\n */\nexport function nativeFind(root: string, opts: NativeFindOptions): string[] {\n\tfor (const pattern of opts.patterns) validateGlob(pattern);\n\tfor (const glob of opts.excludeGlobs) validateGlob(glob);\n\n\tconst entries = collectEntries(root, {\n\t\tmaxDepth: opts.maxDepth,\n\t\tsignal: opts.signal,\n\t\talwaysSkipDirs: opts.alwaysSkipDirs,\n\t});\n\n\tconst results: string[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== opts.type) continue;\n\t\tif (opts.excludeGlobs.some((g) => minimatch(entry.rel, g, { dot: true }))) continue;\n\t\tif (!opts.patterns.some((pat) => matchesFindPattern(entry.rel, pat))) continue;\n\t\tresults.push(entry.type === \"d\" ? `${entry.rel}/` : entry.rel);\n\t}\n\treturn results;\n}\n\ninterface NativeGrepMatch {\n\tfilePath: string;\n\tlineNumber: number;\n\tlineText: string;\n}\n\nexport interface NativeGrepOptions {\n\tpattern: string;\n\t/** True when `root` is a directory; false when it is a single file. */\n\tisDirectory: boolean;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\t/** Optional glob filter applied to file paths (like rg --glob). */\n\tglob?: string;\n\t/** Stop after this many matches. */\n\tlimit: number;\n\tsignal?: AbortSignal;\n\treadFile: (absolutePath: string) => Promise<string> | string;\n}\n\nexport interface NativeGrepResult {\n\tmatches: NativeGrepMatch[];\n\tmatchLimitReached: boolean;\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/** Cheap binary-file heuristic: a NUL byte in the first chunk. rg skips these. */\nfunction looksBinary(content: string): boolean {\n\tconst sampleLength = Math.min(content.length, 8192);\n\tfor (let i = 0; i < sampleLength; i++) {\n\t\tif (content.charCodeAt(i) === 0) return true;\n\t}\n\treturn false;\n}\n\n/**\n * Native replacement for the rg-backed content search. Collects up to `limit`\n * matches as `{ filePath, lineNumber, lineText }`, the same shape the tool's\n * formatter already consumes from rg's JSON output.\n *\n * Throws an Error tagged `invalidRegex` when a non-literal pattern is not a\n * valid JS regex, so the caller can surface the same \"pass literal: true\" hint.\n */\nexport async function nativeGrep(root: string, opts: NativeGrepOptions): Promise<NativeGrepResult> {\n\tlet regex: RegExp;\n\tconst flags = opts.ignoreCase ? \"i\" : \"\";\n\tif (opts.literal) {\n\t\tregex = new RegExp(escapeRegExp(opts.pattern), flags);\n\t} else {\n\t\ttry {\n\t\t\tregex = new RegExp(opts.pattern, flags);\n\t\t} catch (e) {\n\t\t\tconst error = new Error(e instanceof Error ? e.message : String(e)) as Error & { invalidRegex?: boolean };\n\t\t\terror.invalidRegex = true;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tlet files: string[];\n\tif (!opts.isDirectory) {\n\t\tfiles = [root];\n\t} else {\n\t\tconst entries = collectEntries(root, { signal: opts.signal });\n\t\tfiles = entries\n\t\t\t.filter((e) => e.type === \"f\")\n\t\t\t.filter((e) => {\n\t\t\t\tif (!opts.glob) return true;\n\t\t\t\treturn minimatch(e.rel, opts.glob, { dot: true, matchBase: !opts.glob.includes(\"/\") });\n\t\t\t})\n\t\t\t.map((e) => e.abs);\n\t}\n\n\tconst matches: NativeGrepMatch[] = [];\n\tlet matchLimitReached = false;\n\n\tfor (const filePath of files) {\n\t\tif (opts.signal?.aborted || matches.length >= opts.limit) break;\n\n\t\ttry {\n\t\t\tif (statSync(filePath).size > MAX_GREP_FILE_BYTES) continue;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet content: string;\n\t\ttry {\n\t\t\tcontent = await opts.readFile(filePath);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (looksBinary(content)) continue;\n\n\t\tconst lines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t// New RegExp per file with no /g flag → test() is stateless across lines.\n\t\t\tif (regex.test(lines[i])) {\n\t\t\t\tmatches.push({ filePath, lineNumber: i + 1, lineText: lines[i] });\n\t\t\t\tif (matches.length >= opts.limit) {\n\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { matches, matchLimitReached };\n}\n\n/** Whether the native search path is forced regardless of fd/rg availability. */\nexport function isNativeSearchForced(): boolean {\n\treturn process.env.HOOCODE_NATIVE_SEARCH === \"1\";\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"native-search.js","sourceRoot":"","sources":["../../../src/core/tools/native-search.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Native (pure-JS) fallbacks for the `find` and `grep` tools.\n *\n * The tools normally shell out to `fd` / `rg`, which are downloaded on demand\n * (see tools-manager.ts). In restricted environments those binaries may be\n * neither on PATH nor downloadable, and `HOOCODE_NATIVE_SEARCH=1` can also force\n * this path. Rather than failing the tool and asking the model to fall back to\n * `bash`, these functions reproduce the essential behaviour in JS so search\n * degrades automatically:\n *\n * - hierarchical `.gitignore` handling (each `.gitignore` is scoped to its own\n * subtree, matching fd's `--no-require-git` behaviour and issue #3303),\n * - hidden files included (like `fd --hidden` / `rg --hidden`),\n * - `.git` always skipped; `node_modules` skipped for `find` (mirrors the\n * tool's built-in excludes) but left to `.gitignore` for `grep` (like rg).\n *\n * These are best-effort approximations, not byte-for-byte fd/rg parity: globs\n * are matched with `minimatch` and patterns with JS `RegExp`, and only\n * `.gitignore` files are honoured (not `.ignore` or global excludes).\n */\n\nimport { readdirSync, readFileSync, statSync } from \"fs\";\nimport ignore, { type Ignore } from \"ignore\";\nimport { minimatch } from \"minimatch\";\nimport path from \"path\";\nimport { toPosixPath } from \"./fd-utils.js\";\n\nexport type EntryType = \"f\" | \"d\" | \"l\";\n\n/** Hard cap on entries enumerated during a single walk, so a pathological tree\n * can never hang the fallback. Well above any tool's own result limit. */\nconst MAX_ENTRIES = 200_000;\n\n/** Files larger than this are skipped by the grep fallback (rg streams; we read\n * whole files, so we guard against loading huge blobs into memory). */\nconst MAX_GREP_FILE_BYTES = 20 * 1024 * 1024;\n\nexport interface CollectedEntry {\n\t/** Absolute path. */\n\tabs: string;\n\t/** POSIX path relative to the walk root. */\n\trel: string;\n\ttype: EntryType;\n}\n\n/** A `.gitignore` matcher scoped to the subtree rooted at `baseDir`. */\ninterface GitignoreMatcher {\n\tbaseDir: string;\n\tig: Ignore;\n}\n\nfunction loadGitignore(dir: string): Ignore | undefined {\n\tlet content: string;\n\ttry {\n\t\tcontent = readFileSync(path.join(dir, \".gitignore\"), \"utf-8\");\n\t} catch {\n\t\treturn undefined;\n\t}\n\treturn ignore().add(content);\n}\n\n/**\n * Whether `absPath` is ignored by any applicable `.gitignore`. Each matcher only\n * applies to paths inside its `baseDir`, and the path is tested relative to that\n * base — so `a/.gitignore` scopes to `a/` and its descendants but never `b/`.\n */\nfunction isGitIgnored(absPath: string, isDir: boolean, matchers: GitignoreMatcher[]): boolean {\n\tfor (const m of matchers) {\n\t\tconst rel = path.relative(m.baseDir, absPath);\n\t\tif (rel === \"\" || rel.startsWith(\"..\") || path.isAbsolute(rel)) continue;\n\t\tconst relPosix = toPosixPath(rel) + (isDir ? \"/\" : \"\");\n\t\tif (m.ig.ignores(relPosix)) return true;\n\t}\n\treturn false;\n}\n\nexport interface WalkOptions {\n\t/** Max entry depth relative to root; direct children are depth 1. */\n\tmaxDepth?: number;\n\tsignal?: AbortSignal;\n\t/** Directory names to never descend into. Defaults to `.git`. */\n\talwaysSkipDirs?: Set<string>;\n}\n\n/**\n * Walk `root` depth-first, returning every entry not excluded by `.gitignore`\n * or an always-skip directory. Symlinks are reported but never followed (avoids\n * cycles). Enumeration stops at {@link MAX_ENTRIES}.\n */\nexport function collectEntries(root: string, opts: WalkOptions = {}): CollectedEntry[] {\n\tconst out: CollectedEntry[] = [];\n\tconst alwaysSkip = opts.alwaysSkipDirs ?? new Set([\".git\"]);\n\n\tconst rootMatchers: GitignoreMatcher[] = [];\n\tconst rootIg = loadGitignore(root);\n\tif (rootIg) rootMatchers.push({ baseDir: root, ig: rootIg });\n\n\t// `depth` is the depth of `dir`; its direct children are at depth + 1.\n\tconst stack: Array<{ dir: string; depth: number; matchers: GitignoreMatcher[] }> = [\n\t\t{ dir: root, depth: 0, matchers: rootMatchers },\n\t];\n\n\twhile (stack.length > 0) {\n\t\tif (out.length >= MAX_ENTRIES || opts.signal?.aborted) break;\n\t\tconst { dir, depth, matchers } = stack.pop()!;\n\n\t\tlet dirents: import(\"fs\").Dirent[];\n\t\ttry {\n\t\t\tdirents = readdirSync(dir, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue; // unreadable directory — skip rather than abort the whole walk\n\t\t}\n\n\t\tconst entryDepth = depth + 1;\n\t\tfor (const dirent of dirents) {\n\t\t\tif (out.length >= MAX_ENTRIES) break;\n\n\t\t\tconst name = dirent.name;\n\t\t\tconst abs = path.join(dir, name);\n\n\t\t\tlet type: EntryType;\n\t\t\tlet isDir = false;\n\t\t\tif (dirent.isSymbolicLink()) {\n\t\t\t\ttype = \"l\";\n\t\t\t} else if (dirent.isDirectory()) {\n\t\t\t\ttype = \"d\";\n\t\t\t\tisDir = true;\n\t\t\t} else if (dirent.isFile()) {\n\t\t\t\ttype = \"f\";\n\t\t\t} else {\n\t\t\t\tcontinue; // sockets, fifos, block devices, …\n\t\t\t}\n\n\t\t\tif (isDir && alwaysSkip.has(name)) continue;\n\t\t\tif (isGitIgnored(abs, isDir, matchers)) continue;\n\n\t\t\tif (opts.maxDepth === undefined || entryDepth <= opts.maxDepth) {\n\t\t\t\tout.push({ abs, rel: toPosixPath(path.relative(root, abs)), type });\n\t\t\t}\n\n\t\t\t// Descend only into real directories, and only if their children can\n\t\t\t// still be within the depth budget.\n\t\t\tif (isDir && (opts.maxDepth === undefined || entryDepth < opts.maxDepth)) {\n\t\t\t\tconst childIg = loadGitignore(abs);\n\t\t\t\tconst nextMatchers = childIg ? [...matchers, { baseDir: abs, ig: childIg }] : matchers;\n\t\t\t\tstack.push({ dir: abs, depth: entryDepth, matchers: nextMatchers });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn out;\n}\n\n/**\n * Reject globs fd's parser would reject. minimatch silently treats an unclosed\n * `[` or `{` as literal text, which made the fallback resolve \"no results\"\n * where the fd path errors — same call, different outcome. Error messages\n * mirror fd/globset so callers (and tests) can match either path.\n */\nfunction validateGlob(pattern: string): void {\n\tlet inClass = false;\n\tlet braceDepth = 0;\n\tfor (let i = 0; i < pattern.length; i++) {\n\t\tconst c = pattern[i];\n\t\tif (c === \"\\\\\") {\n\t\t\ti++; // skip escaped char\n\t\t} else if (inClass) {\n\t\t\tif (c === \"]\") inClass = false;\n\t\t} else if (c === \"[\") {\n\t\t\tinClass = true;\n\t\t} else if (c === \"{\") {\n\t\t\tbraceDepth++;\n\t\t} else if (c === \"}\") {\n\t\t\tif (braceDepth > 0) braceDepth--;\n\t\t}\n\t}\n\tif (inClass) {\n\t\tthrow new Error(`error parsing glob '${pattern}': unclosed character class; missing ']'`);\n\t}\n\tif (braceDepth > 0) {\n\t\tthrow new Error(`error parsing glob '${pattern}': unclosed alternate group; missing '}'`);\n\t}\n}\n\n/** fd smart-case: a pattern without uppercase letters matches case-insensitively. */\nfunction isSmartCaseInsensitive(pattern: string): boolean {\n\treturn !/[A-Z]/.test(pattern);\n}\n\n/**\n * Match a `find` glob against a POSIX relative path, mirroring fd's semantics:\n * a slashless pattern matches the basename at any depth; a pattern containing a\n * slash matches the full path and is anchored anywhere in the tree. Case\n * sensitivity is smart-case, like fd.\n */\nfunction matchesFindPattern(relPosix: string, pattern: string): boolean {\n\tconst nocase = isSmartCaseInsensitive(pattern);\n\tif (pattern.includes(\"/\")) {\n\t\tlet p = pattern;\n\t\tif (p.startsWith(\"/\")) {\n\t\t\tp = p.slice(1); // leading slash anchors to root; rel paths have no leading slash\n\t\t} else if (!p.startsWith(\"**/\") && p !== \"**\") {\n\t\t\tp = `**/${p}`;\n\t\t}\n\t\treturn minimatch(relPosix, p, { dot: true, nocase });\n\t}\n\treturn minimatch(relPosix, pattern, { dot: true, matchBase: true, nocase });\n}\n\nexport interface NativeFindOptions {\n\tpatterns: string[];\n\ttype: EntryType;\n\t/** Extra exclusion globs (already includes node_modules/.git for find). */\n\texcludeGlobs: string[];\n\tmaxDepth?: number;\n\talwaysSkipDirs?: Set<string>;\n\tsignal?: AbortSignal;\n}\n\n/**\n * Native replacement for the fd-backed search. Returns POSIX paths relative to\n * `root`, with a trailing slash on directories (like fd), unsorted/undeduped —\n * the caller applies its own dedupe/sort/limit.\n */\nexport function nativeFind(root: string, opts: NativeFindOptions): string[] {\n\tfor (const pattern of opts.patterns) validateGlob(pattern);\n\tfor (const glob of opts.excludeGlobs) validateGlob(glob);\n\n\tconst entries = collectEntries(root, {\n\t\tmaxDepth: opts.maxDepth,\n\t\tsignal: opts.signal,\n\t\talwaysSkipDirs: opts.alwaysSkipDirs,\n\t});\n\n\tconst results: string[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== opts.type) continue;\n\t\tif (opts.excludeGlobs.some((g) => minimatch(entry.rel, g, { dot: true }))) continue;\n\t\tif (!opts.patterns.some((pat) => matchesFindPattern(entry.rel, pat))) continue;\n\t\tresults.push(entry.type === \"d\" ? `${entry.rel}/` : entry.rel);\n\t}\n\treturn results;\n}\n\nexport interface NativeGrepMatch {\n\tfilePath: string;\n\tlineNumber: number;\n\tlineText: string;\n}\n\nexport interface NativeGrepOptions {\n\tpattern: string;\n\t/** True when `root` is a directory; false when it is a single file. */\n\tisDirectory: boolean;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\t/** Optional glob filter applied to file paths (like rg --glob). */\n\tglob?: string;\n\t/** Stop after this many matches. */\n\tlimit: number;\n\tsignal?: AbortSignal;\n\treadFile: (absolutePath: string) => Promise<string> | string;\n}\n\nexport interface NativeGrepResult {\n\tmatches: NativeGrepMatch[];\n\tmatchLimitReached: boolean;\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/** Cheap binary-file heuristic: a NUL byte in the first chunk. rg skips these. */\nfunction looksBinary(content: string): boolean {\n\tconst sampleLength = Math.min(content.length, 8192);\n\tfor (let i = 0; i < sampleLength; i++) {\n\t\tif (content.charCodeAt(i) === 0) return true;\n\t}\n\treturn false;\n}\n\n/**\n * Native replacement for the rg-backed content search. Collects up to `limit`\n * matches as `{ filePath, lineNumber, lineText }`, the same shape the tool's\n * formatter already consumes from rg's JSON output.\n *\n * Throws an Error tagged `invalidRegex` when a non-literal pattern is not a\n * valid JS regex, so the caller can surface the same \"pass literal: true\" hint.\n */\nexport async function nativeGrep(root: string, opts: NativeGrepOptions): Promise<NativeGrepResult> {\n\tlet regex: RegExp;\n\tconst flags = opts.ignoreCase ? \"i\" : \"\";\n\tif (opts.literal) {\n\t\tregex = new RegExp(escapeRegExp(opts.pattern), flags);\n\t} else {\n\t\ttry {\n\t\t\tregex = new RegExp(opts.pattern, flags);\n\t\t} catch (e) {\n\t\t\tconst error = new Error(e instanceof Error ? e.message : String(e)) as Error & { invalidRegex?: boolean };\n\t\t\terror.invalidRegex = true;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tlet files: string[];\n\tif (!opts.isDirectory) {\n\t\tfiles = [root];\n\t} else {\n\t\tconst entries = collectEntries(root, { signal: opts.signal });\n\t\tfiles = entries\n\t\t\t.filter((e) => e.type === \"f\")\n\t\t\t.filter((e) => {\n\t\t\t\tif (!opts.glob) return true;\n\t\t\t\treturn minimatch(e.rel, opts.glob, { dot: true, matchBase: !opts.glob.includes(\"/\") });\n\t\t\t})\n\t\t\t.map((e) => e.abs);\n\t}\n\n\tconst matches: NativeGrepMatch[] = [];\n\tlet matchLimitReached = false;\n\n\tfor (const filePath of files) {\n\t\tif (opts.signal?.aborted || matches.length >= opts.limit) break;\n\n\t\ttry {\n\t\t\tif (statSync(filePath).size > MAX_GREP_FILE_BYTES) continue;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet content: string;\n\t\ttry {\n\t\t\tcontent = await opts.readFile(filePath);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (looksBinary(content)) continue;\n\n\t\tconst lines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t// New RegExp per file with no /g flag → test() is stateless across lines.\n\t\t\tif (regex.test(lines[i])) {\n\t\t\t\tmatches.push({ filePath, lineNumber: i + 1, lineText: lines[i] });\n\t\t\t\tif (matches.length >= opts.limit) {\n\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { matches, matchLimitReached };\n}\n\n/** Whether the native search path is forced regardless of fd/rg availability. */\nexport function isNativeSearchForced(): boolean {\n\treturn process.env.HOOCODE_NATIVE_SEARCH === \"1\";\n}\n"]}
1
+ {"version":3,"file":"native-search.js","sourceRoot":"","sources":["../../../src/core/tools/native-search.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Native (pure-JS) fallbacks for the `find` and `grep` tools.\n *\n * The tools normally shell out to `fd` / `rg`, which are downloaded on demand\n * (see tools-manager.ts). In restricted environments those binaries may be\n * neither on PATH nor downloadable, and `HOOCODE_NATIVE_SEARCH=1` can also force\n * this path. Rather than failing the tool and asking the model to fall back to\n * `bash`, these functions reproduce the essential behaviour in JS so search\n * degrades automatically:\n *\n * - hierarchical `.gitignore` handling (each `.gitignore` is scoped to its own\n * subtree, matching fd's `--no-require-git` behaviour and issue #3303),\n * - hidden files included (like `fd --hidden` / `rg --hidden`),\n * - `.git` always skipped; `node_modules` skipped for `find` (mirrors the\n * tool's built-in excludes) but left to `.gitignore` for `grep` (like rg).\n *\n * These are best-effort approximations, not byte-for-byte fd/rg parity: globs\n * are matched with `minimatch` and patterns with JS `RegExp`, and only\n * `.gitignore` files are honoured (not `.ignore` or global excludes).\n */\n\nimport { readdirSync, readFileSync, statSync } from \"fs\";\nimport ignore, { type Ignore } from \"ignore\";\nimport { minimatch } from \"minimatch\";\nimport path from \"path\";\nimport { toPosixPath } from \"./fd-utils.js\";\n\ntype EntryType = \"f\" | \"d\" | \"l\";\n\n/** Hard cap on entries enumerated during a single walk, so a pathological tree\n * can never hang the fallback. Well above any tool's own result limit. */\nconst MAX_ENTRIES = 200_000;\n\n/** Files larger than this are skipped by the grep fallback (rg streams; we read\n * whole files, so we guard against loading huge blobs into memory). */\nconst MAX_GREP_FILE_BYTES = 20 * 1024 * 1024;\n\nexport interface CollectedEntry {\n\t/** Absolute path. */\n\tabs: string;\n\t/** POSIX path relative to the walk root. */\n\trel: string;\n\ttype: EntryType;\n}\n\n/** A `.gitignore` matcher scoped to the subtree rooted at `baseDir`. */\ninterface GitignoreMatcher {\n\tbaseDir: string;\n\tig: Ignore;\n}\n\nfunction loadGitignore(dir: string): Ignore | undefined {\n\tlet content: string;\n\ttry {\n\t\tcontent = readFileSync(path.join(dir, \".gitignore\"), \"utf-8\");\n\t} catch {\n\t\treturn undefined;\n\t}\n\treturn ignore().add(content);\n}\n\n/**\n * Whether `absPath` is ignored by any applicable `.gitignore`. Each matcher only\n * applies to paths inside its `baseDir`, and the path is tested relative to that\n * base — so `a/.gitignore` scopes to `a/` and its descendants but never `b/`.\n */\nfunction isGitIgnored(absPath: string, isDir: boolean, matchers: GitignoreMatcher[]): boolean {\n\tfor (const m of matchers) {\n\t\tconst rel = path.relative(m.baseDir, absPath);\n\t\tif (rel === \"\" || rel.startsWith(\"..\") || path.isAbsolute(rel)) continue;\n\t\tconst relPosix = toPosixPath(rel) + (isDir ? \"/\" : \"\");\n\t\tif (m.ig.ignores(relPosix)) return true;\n\t}\n\treturn false;\n}\n\nexport interface WalkOptions {\n\t/** Max entry depth relative to root; direct children are depth 1. */\n\tmaxDepth?: number;\n\tsignal?: AbortSignal;\n\t/** Directory names to never descend into. Defaults to `.git`. */\n\talwaysSkipDirs?: Set<string>;\n}\n\n/**\n * Walk `root` depth-first, returning every entry not excluded by `.gitignore`\n * or an always-skip directory. Symlinks are reported but never followed (avoids\n * cycles). Enumeration stops at {@link MAX_ENTRIES}.\n */\nexport function collectEntries(root: string, opts: WalkOptions = {}): CollectedEntry[] {\n\tconst out: CollectedEntry[] = [];\n\tconst alwaysSkip = opts.alwaysSkipDirs ?? new Set([\".git\"]);\n\n\tconst rootMatchers: GitignoreMatcher[] = [];\n\tconst rootIg = loadGitignore(root);\n\tif (rootIg) rootMatchers.push({ baseDir: root, ig: rootIg });\n\n\t// `depth` is the depth of `dir`; its direct children are at depth + 1.\n\tconst stack: Array<{ dir: string; depth: number; matchers: GitignoreMatcher[] }> = [\n\t\t{ dir: root, depth: 0, matchers: rootMatchers },\n\t];\n\n\twhile (stack.length > 0) {\n\t\tif (out.length >= MAX_ENTRIES || opts.signal?.aborted) break;\n\t\tconst { dir, depth, matchers } = stack.pop()!;\n\n\t\tlet dirents: import(\"fs\").Dirent[];\n\t\ttry {\n\t\t\tdirents = readdirSync(dir, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue; // unreadable directory — skip rather than abort the whole walk\n\t\t}\n\n\t\tconst entryDepth = depth + 1;\n\t\tfor (const dirent of dirents) {\n\t\t\tif (out.length >= MAX_ENTRIES) break;\n\n\t\t\tconst name = dirent.name;\n\t\t\tconst abs = path.join(dir, name);\n\n\t\t\tlet type: EntryType;\n\t\t\tlet isDir = false;\n\t\t\tif (dirent.isSymbolicLink()) {\n\t\t\t\ttype = \"l\";\n\t\t\t} else if (dirent.isDirectory()) {\n\t\t\t\ttype = \"d\";\n\t\t\t\tisDir = true;\n\t\t\t} else if (dirent.isFile()) {\n\t\t\t\ttype = \"f\";\n\t\t\t} else {\n\t\t\t\tcontinue; // sockets, fifos, block devices, …\n\t\t\t}\n\n\t\t\tif (isDir && alwaysSkip.has(name)) continue;\n\t\t\tif (isGitIgnored(abs, isDir, matchers)) continue;\n\n\t\t\tif (opts.maxDepth === undefined || entryDepth <= opts.maxDepth) {\n\t\t\t\tout.push({ abs, rel: toPosixPath(path.relative(root, abs)), type });\n\t\t\t}\n\n\t\t\t// Descend only into real directories, and only if their children can\n\t\t\t// still be within the depth budget.\n\t\t\tif (isDir && (opts.maxDepth === undefined || entryDepth < opts.maxDepth)) {\n\t\t\t\tconst childIg = loadGitignore(abs);\n\t\t\t\tconst nextMatchers = childIg ? [...matchers, { baseDir: abs, ig: childIg }] : matchers;\n\t\t\t\tstack.push({ dir: abs, depth: entryDepth, matchers: nextMatchers });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn out;\n}\n\n/**\n * Reject globs fd's parser would reject. minimatch silently treats an unclosed\n * `[` or `{` as literal text, which made the fallback resolve \"no results\"\n * where the fd path errors — same call, different outcome. Error messages\n * mirror fd/globset so callers (and tests) can match either path.\n */\nfunction validateGlob(pattern: string): void {\n\tlet inClass = false;\n\tlet braceDepth = 0;\n\tfor (let i = 0; i < pattern.length; i++) {\n\t\tconst c = pattern[i];\n\t\tif (c === \"\\\\\") {\n\t\t\ti++; // skip escaped char\n\t\t} else if (inClass) {\n\t\t\tif (c === \"]\") inClass = false;\n\t\t} else if (c === \"[\") {\n\t\t\tinClass = true;\n\t\t} else if (c === \"{\") {\n\t\t\tbraceDepth++;\n\t\t} else if (c === \"}\") {\n\t\t\tif (braceDepth > 0) braceDepth--;\n\t\t}\n\t}\n\tif (inClass) {\n\t\tthrow new Error(`error parsing glob '${pattern}': unclosed character class; missing ']'`);\n\t}\n\tif (braceDepth > 0) {\n\t\tthrow new Error(`error parsing glob '${pattern}': unclosed alternate group; missing '}'`);\n\t}\n}\n\n/** fd smart-case: a pattern without uppercase letters matches case-insensitively. */\nfunction isSmartCaseInsensitive(pattern: string): boolean {\n\treturn !/[A-Z]/.test(pattern);\n}\n\n/**\n * Match a `find` glob against a POSIX relative path, mirroring fd's semantics:\n * a slashless pattern matches the basename at any depth; a pattern containing a\n * slash matches the full path and is anchored anywhere in the tree. Case\n * sensitivity is smart-case, like fd.\n */\nfunction matchesFindPattern(relPosix: string, pattern: string): boolean {\n\tconst nocase = isSmartCaseInsensitive(pattern);\n\tif (pattern.includes(\"/\")) {\n\t\tlet p = pattern;\n\t\tif (p.startsWith(\"/\")) {\n\t\t\tp = p.slice(1); // leading slash anchors to root; rel paths have no leading slash\n\t\t} else if (!p.startsWith(\"**/\") && p !== \"**\") {\n\t\t\tp = `**/${p}`;\n\t\t}\n\t\treturn minimatch(relPosix, p, { dot: true, nocase });\n\t}\n\treturn minimatch(relPosix, pattern, { dot: true, matchBase: true, nocase });\n}\n\nexport interface NativeFindOptions {\n\tpatterns: string[];\n\ttype: EntryType;\n\t/** Extra exclusion globs (already includes node_modules/.git for find). */\n\texcludeGlobs: string[];\n\tmaxDepth?: number;\n\talwaysSkipDirs?: Set<string>;\n\tsignal?: AbortSignal;\n}\n\n/**\n * Native replacement for the fd-backed search. Returns POSIX paths relative to\n * `root`, with a trailing slash on directories (like fd), unsorted/undeduped —\n * the caller applies its own dedupe/sort/limit.\n */\nexport function nativeFind(root: string, opts: NativeFindOptions): string[] {\n\tfor (const pattern of opts.patterns) validateGlob(pattern);\n\tfor (const glob of opts.excludeGlobs) validateGlob(glob);\n\n\tconst entries = collectEntries(root, {\n\t\tmaxDepth: opts.maxDepth,\n\t\tsignal: opts.signal,\n\t\talwaysSkipDirs: opts.alwaysSkipDirs,\n\t});\n\n\tconst results: string[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== opts.type) continue;\n\t\tif (opts.excludeGlobs.some((g) => minimatch(entry.rel, g, { dot: true }))) continue;\n\t\tif (!opts.patterns.some((pat) => matchesFindPattern(entry.rel, pat))) continue;\n\t\tresults.push(entry.type === \"d\" ? `${entry.rel}/` : entry.rel);\n\t}\n\treturn results;\n}\n\ninterface NativeGrepMatch {\n\tfilePath: string;\n\tlineNumber: number;\n\tlineText: string;\n}\n\nexport interface NativeGrepOptions {\n\tpattern: string;\n\t/** True when `root` is a directory; false when it is a single file. */\n\tisDirectory: boolean;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\t/** Optional glob filter applied to file paths (like rg --glob). */\n\tglob?: string;\n\t/** Stop after this many matches. */\n\tlimit: number;\n\tsignal?: AbortSignal;\n\treadFile: (absolutePath: string) => Promise<string> | string;\n}\n\nexport interface NativeGrepResult {\n\tmatches: NativeGrepMatch[];\n\tmatchLimitReached: boolean;\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/** Cheap binary-file heuristic: a NUL byte in the first chunk. rg skips these. */\nfunction looksBinary(content: string): boolean {\n\tconst sampleLength = Math.min(content.length, 8192);\n\tfor (let i = 0; i < sampleLength; i++) {\n\t\tif (content.charCodeAt(i) === 0) return true;\n\t}\n\treturn false;\n}\n\n/**\n * Native replacement for the rg-backed content search. Collects up to `limit`\n * matches as `{ filePath, lineNumber, lineText }`, the same shape the tool's\n * formatter already consumes from rg's JSON output.\n *\n * Throws an Error tagged `invalidRegex` when a non-literal pattern is not a\n * valid JS regex, so the caller can surface the same \"pass literal: true\" hint.\n */\nexport async function nativeGrep(root: string, opts: NativeGrepOptions): Promise<NativeGrepResult> {\n\tlet regex: RegExp;\n\tconst flags = opts.ignoreCase ? \"i\" : \"\";\n\tif (opts.literal) {\n\t\tregex = new RegExp(escapeRegExp(opts.pattern), flags);\n\t} else {\n\t\ttry {\n\t\t\tregex = new RegExp(opts.pattern, flags);\n\t\t} catch (e) {\n\t\t\tconst error = new Error(e instanceof Error ? e.message : String(e)) as Error & { invalidRegex?: boolean };\n\t\t\terror.invalidRegex = true;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tlet files: string[];\n\tif (!opts.isDirectory) {\n\t\tfiles = [root];\n\t} else {\n\t\tconst entries = collectEntries(root, { signal: opts.signal });\n\t\tfiles = entries\n\t\t\t.filter((e) => e.type === \"f\")\n\t\t\t.filter((e) => {\n\t\t\t\tif (!opts.glob) return true;\n\t\t\t\treturn minimatch(e.rel, opts.glob, { dot: true, matchBase: !opts.glob.includes(\"/\") });\n\t\t\t})\n\t\t\t.map((e) => e.abs);\n\t}\n\n\tconst matches: NativeGrepMatch[] = [];\n\tlet matchLimitReached = false;\n\n\tfor (const filePath of files) {\n\t\tif (opts.signal?.aborted || matches.length >= opts.limit) break;\n\n\t\ttry {\n\t\t\tif (statSync(filePath).size > MAX_GREP_FILE_BYTES) continue;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet content: string;\n\t\ttry {\n\t\t\tcontent = await opts.readFile(filePath);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (looksBinary(content)) continue;\n\n\t\tconst lines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t// New RegExp per file with no /g flag → test() is stateless across lines.\n\t\t\tif (regex.test(lines[i])) {\n\t\t\t\tmatches.push({ filePath, lineNumber: i + 1, lineText: lines[i] });\n\t\t\t\tif (matches.length >= opts.limit) {\n\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { matches, matchLimitReached };\n}\n\n/** Whether the native search path is forced regardless of fd/rg availability. */\nexport function isNativeSearchForced(): boolean {\n\treturn process.env.HOOCODE_NATIVE_SEARCH === \"1\";\n}\n"]}
@@ -1,13 +1,3 @@
1
- /**
2
- * Check if a string is a file URL (starts with "file:///").
3
- */
4
- export declare function isFileUrl(filePath: string): boolean;
5
- /**
6
- * Convert a file URL to a file path.
7
- * Handles both Unix-style (file:///path) and Windows-style (file:///C:/path) file URLs.
8
- * Returns the original path if it's not a file URL.
9
- */
10
- export declare function normalizeFileUrl(filePath: string): string;
11
1
  export declare function expandPath(filePath: string): string;
12
2
  /**
13
3
  * Resolve a path relative to the given cwd.