@travisennis/acai 0.0.9 → 0.0.11

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 (403) hide show
  1. package/README.md +51 -760
  2. package/bin/acai +52 -0
  3. package/dist/agent/index.d.ts +12 -2
  4. package/dist/agent/index.d.ts.map +1 -1
  5. package/dist/agent/index.js +380 -199
  6. package/dist/agent/sub-agent.d.ts +23 -0
  7. package/dist/agent/sub-agent.d.ts.map +1 -0
  8. package/dist/agent/sub-agent.js +109 -0
  9. package/dist/cli/index.d.ts +26 -0
  10. package/dist/cli/index.d.ts.map +1 -0
  11. package/dist/{cli.js → cli/index.js} +84 -77
  12. package/dist/{stdin.d.ts → cli/stdin.d.ts} +2 -1
  13. package/dist/cli/stdin.d.ts.map +1 -0
  14. package/dist/{stdin.js → cli/stdin.js} +11 -0
  15. package/dist/commands/copy/index.js +2 -2
  16. package/dist/commands/copy/utils.d.ts.map +1 -1
  17. package/dist/commands/copy/utils.js +15 -13
  18. package/dist/commands/generate-rules/index.d.ts +1 -1
  19. package/dist/commands/generate-rules/index.d.ts.map +1 -1
  20. package/dist/commands/generate-rules/index.js +16 -101
  21. package/dist/commands/generate-rules/service.d.ts +22 -0
  22. package/dist/commands/generate-rules/service.d.ts.map +1 -0
  23. package/dist/commands/generate-rules/service.js +103 -0
  24. package/dist/commands/handoff/index.js +2 -2
  25. package/dist/commands/health/index.js +1 -1
  26. package/dist/commands/health/utils.d.ts +3 -2
  27. package/dist/commands/health/utils.d.ts.map +1 -1
  28. package/dist/commands/health/utils.js +6 -0
  29. package/dist/commands/history/index.d.ts +1 -1
  30. package/dist/commands/history/index.d.ts.map +1 -1
  31. package/dist/commands/history/index.js +17 -18
  32. package/dist/commands/history/types.d.ts +38 -0
  33. package/dist/commands/history/types.d.ts.map +1 -1
  34. package/dist/commands/history/utils.d.ts.map +1 -1
  35. package/dist/commands/history/utils.js +63 -58
  36. package/dist/commands/init/index.d.ts.map +1 -1
  37. package/dist/commands/init/index.js +3 -8
  38. package/dist/commands/init-project/index.d.ts.map +1 -1
  39. package/dist/commands/init-project/index.js +3 -3
  40. package/dist/commands/init-project/utils.d.ts +2 -1
  41. package/dist/commands/init-project/utils.d.ts.map +1 -1
  42. package/dist/commands/init-project/utils.js +10 -2
  43. package/dist/commands/list-tools/index.d.ts.map +1 -1
  44. package/dist/commands/list-tools/index.js +7 -31
  45. package/dist/commands/manager.d.ts +2 -2
  46. package/dist/commands/manager.d.ts.map +1 -1
  47. package/dist/commands/manager.js +55 -33
  48. package/dist/commands/model/index.d.ts.map +1 -1
  49. package/dist/commands/model/index.js +20 -151
  50. package/dist/commands/model/model-panel.d.ts +4 -0
  51. package/dist/commands/model/model-panel.d.ts.map +1 -0
  52. package/dist/commands/model/model-panel.js +144 -0
  53. package/dist/commands/paste/index.d.ts.map +1 -1
  54. package/dist/commands/paste/index.js +59 -62
  55. package/dist/commands/paste/utils.d.ts.map +1 -1
  56. package/dist/commands/paste/utils.js +88 -58
  57. package/dist/commands/pickup/index.d.ts.map +1 -1
  58. package/dist/commands/pickup/index.js +6 -3
  59. package/dist/commands/pickup/utils.js +3 -3
  60. package/dist/commands/resources/index.d.ts.map +1 -1
  61. package/dist/commands/resources/index.js +33 -50
  62. package/dist/commands/review/index.d.ts.map +1 -1
  63. package/dist/commands/review/index.js +3 -117
  64. package/dist/commands/review/review-panel.d.ts +3 -0
  65. package/dist/commands/review/review-panel.d.ts.map +1 -0
  66. package/dist/commands/review/review-panel.js +186 -0
  67. package/dist/commands/review/utils.d.ts +15 -1
  68. package/dist/commands/review/utils.d.ts.map +1 -1
  69. package/dist/commands/review/utils.js +127 -68
  70. package/dist/commands/session/index.d.ts +1 -1
  71. package/dist/commands/session/index.d.ts.map +1 -1
  72. package/dist/commands/session/index.js +124 -135
  73. package/dist/commands/shell/index.d.ts.map +1 -1
  74. package/dist/commands/shell/index.js +16 -1
  75. package/dist/commands/types.d.ts +2 -2
  76. package/dist/commands/types.d.ts.map +1 -1
  77. package/dist/{config.d.ts → config/index.d.ts} +20 -9
  78. package/dist/config/index.d.ts.map +1 -0
  79. package/dist/{config.js → config/index.js} +43 -42
  80. package/dist/execution/index.d.ts.map +1 -1
  81. package/dist/execution/index.js +75 -55
  82. package/dist/index.d.ts +1 -0
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +148 -141
  85. package/dist/middleware/cache.d.ts.map +1 -1
  86. package/dist/middleware/cache.js +18 -36
  87. package/dist/models/ai-config.d.ts +1 -0
  88. package/dist/models/ai-config.d.ts.map +1 -1
  89. package/dist/models/ai-config.js +4 -3
  90. package/dist/models/anthropic-provider.d.ts +2 -5
  91. package/dist/models/anthropic-provider.d.ts.map +1 -1
  92. package/dist/models/anthropic-provider.js +3 -70
  93. package/dist/models/deepseek-provider.d.ts +1 -0
  94. package/dist/models/deepseek-provider.d.ts.map +1 -1
  95. package/dist/models/google-provider.d.ts +2 -3
  96. package/dist/models/google-provider.d.ts.map +1 -1
  97. package/dist/models/google-provider.js +0 -26
  98. package/dist/models/groq-provider.d.ts +1 -0
  99. package/dist/models/groq-provider.d.ts.map +1 -1
  100. package/dist/models/manager.d.ts +13 -2
  101. package/dist/models/manager.d.ts.map +1 -1
  102. package/dist/models/manager.js +20 -8
  103. package/dist/models/openai-provider.d.ts +2 -5
  104. package/dist/models/openai-provider.d.ts.map +1 -1
  105. package/dist/models/openai-provider.js +0 -52
  106. package/dist/models/opencode-go-provider.d.ts +25 -0
  107. package/dist/models/opencode-go-provider.d.ts.map +1 -0
  108. package/dist/models/opencode-go-provider.js +78 -0
  109. package/dist/models/opencode-zen-provider.d.ts +7 -3
  110. package/dist/models/opencode-zen-provider.d.ts.map +1 -1
  111. package/dist/models/opencode-zen-provider.js +49 -10
  112. package/dist/models/openrouter-provider.d.ts +27 -31
  113. package/dist/models/openrouter-provider.d.ts.map +1 -1
  114. package/dist/models/openrouter-provider.js +121 -180
  115. package/dist/models/providers.d.ts +3 -3
  116. package/dist/models/providers.d.ts.map +1 -1
  117. package/dist/models/providers.js +6 -0
  118. package/dist/models/xai-provider.d.ts +4 -3
  119. package/dist/models/xai-provider.d.ts.map +1 -1
  120. package/dist/models/xai-provider.js +18 -18
  121. package/dist/modes/manager.d.ts +24 -0
  122. package/dist/modes/manager.d.ts.map +1 -0
  123. package/dist/modes/manager.js +77 -0
  124. package/dist/modes/prompts.d.ts +2 -0
  125. package/dist/modes/prompts.d.ts.map +1 -0
  126. package/dist/modes/prompts.js +142 -0
  127. package/dist/prompts/mentions.d.ts +11 -0
  128. package/dist/prompts/mentions.d.ts.map +1 -0
  129. package/dist/{mentions.js → prompts/mentions.js} +55 -85
  130. package/dist/{prompts.d.ts → prompts/system-prompt.d.ts} +7 -2
  131. package/dist/prompts/system-prompt.d.ts.map +1 -0
  132. package/dist/{prompts.js → prompts/system-prompt.js} +31 -16
  133. package/dist/repl/index.d.ts +174 -0
  134. package/dist/repl/index.d.ts.map +1 -0
  135. package/dist/{repl-new.js → repl/index.js} +397 -76
  136. package/dist/repl/project-status.d.ts +1 -0
  137. package/dist/repl/project-status.d.ts.map +1 -1
  138. package/dist/repl/project-status.js +4 -1
  139. package/dist/sessions/manager.d.ts +92 -0
  140. package/dist/sessions/manager.d.ts.map +1 -1
  141. package/dist/sessions/manager.js +262 -9
  142. package/dist/sessions/summary.d.ts +4 -0
  143. package/dist/sessions/summary.d.ts.map +1 -0
  144. package/dist/sessions/summary.js +30 -0
  145. package/dist/skills/index.d.ts +29 -0
  146. package/dist/skills/index.d.ts.map +1 -0
  147. package/dist/skills/index.js +294 -0
  148. package/dist/subagents/index.d.ts +16 -0
  149. package/dist/subagents/index.d.ts.map +1 -0
  150. package/dist/subagents/index.js +231 -0
  151. package/dist/terminal/control.d.ts +1 -1
  152. package/dist/terminal/control.d.ts.map +1 -1
  153. package/dist/terminal/control.js +3 -3
  154. package/dist/terminal/east-asian-width.d.ts.map +1 -1
  155. package/dist/terminal/east-asian-width.js +404 -351
  156. package/dist/terminal/keys.d.ts +17 -0
  157. package/dist/terminal/keys.d.ts.map +1 -1
  158. package/dist/terminal/keys.js +37 -0
  159. package/dist/terminal/select-prompt.d.ts.map +1 -1
  160. package/dist/terminal/select-prompt.js +24 -12
  161. package/dist/terminal/string-width.d.ts.map +1 -1
  162. package/dist/terminal/string-width.js +25 -27
  163. package/dist/terminal/style.d.ts.map +1 -1
  164. package/dist/terminal/style.js +4 -7
  165. package/dist/terminal/supports-color.d.ts.map +1 -1
  166. package/dist/terminal/supports-color.js +41 -27
  167. package/dist/terminal/table/cell.d.ts +12 -0
  168. package/dist/terminal/table/cell.d.ts.map +1 -1
  169. package/dist/terminal/table/cell.js +40 -25
  170. package/dist/terminal/table/layout-manager.d.ts.map +1 -1
  171. package/dist/terminal/table/layout-manager.js +100 -68
  172. package/dist/terminal/table/utils.d.ts +1 -1
  173. package/dist/terminal/table/utils.d.ts.map +1 -1
  174. package/dist/terminal/table/utils.js +17 -10
  175. package/dist/terminal/wrap-ansi.d.ts.map +1 -1
  176. package/dist/terminal/wrap-ansi.js +174 -105
  177. package/dist/tokens/tracker.d.ts +1 -0
  178. package/dist/tokens/tracker.d.ts.map +1 -1
  179. package/dist/tokens/tracker.js +3 -0
  180. package/dist/tools/agent.d.ts +27 -0
  181. package/dist/tools/agent.d.ts.map +1 -0
  182. package/dist/tools/agent.js +81 -0
  183. package/dist/tools/apply-patch.d.ts +62 -0
  184. package/dist/tools/apply-patch.d.ts.map +1 -0
  185. package/dist/tools/apply-patch.js +377 -0
  186. package/dist/tools/bash.d.ts +4 -3
  187. package/dist/tools/bash.d.ts.map +1 -1
  188. package/dist/tools/bash.js +349 -141
  189. package/dist/tools/directory-tree.d.ts +3 -3
  190. package/dist/tools/directory-tree.d.ts.map +1 -1
  191. package/dist/tools/directory-tree.js +8 -5
  192. package/dist/tools/dynamic-tool-loader.d.ts +3 -6
  193. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  194. package/dist/tools/dynamic-tool-loader.js +20 -4
  195. package/dist/tools/edit-file.d.ts +7 -7
  196. package/dist/tools/edit-file.d.ts.map +1 -1
  197. package/dist/tools/edit-file.js +292 -85
  198. package/dist/tools/glob.d.ts +6 -6
  199. package/dist/tools/glob.d.ts.map +1 -1
  200. package/dist/tools/glob.js +110 -63
  201. package/dist/tools/grep.d.ts +15 -12
  202. package/dist/tools/grep.d.ts.map +1 -1
  203. package/dist/tools/grep.js +315 -193
  204. package/dist/tools/index.d.ts +114 -9
  205. package/dist/tools/index.d.ts.map +1 -1
  206. package/dist/tools/index.js +39 -24
  207. package/dist/tools/ls.d.ts +2 -2
  208. package/dist/tools/ls.d.ts.map +1 -1
  209. package/dist/tools/ls.js +7 -5
  210. package/dist/tools/read-file.d.ts +4 -6
  211. package/dist/tools/read-file.d.ts.map +1 -1
  212. package/dist/tools/read-file.js +84 -39
  213. package/dist/tools/save-file.d.ts +3 -3
  214. package/dist/tools/save-file.d.ts.map +1 -1
  215. package/dist/tools/save-file.js +36 -31
  216. package/dist/tools/skill.d.ts +23 -0
  217. package/dist/tools/skill.d.ts.map +1 -0
  218. package/dist/tools/skill.js +65 -0
  219. package/dist/tools/think.d.ts.map +1 -1
  220. package/dist/tools/think.js +2 -9
  221. package/dist/tools/utils.d.ts +2 -0
  222. package/dist/tools/utils.d.ts.map +1 -1
  223. package/dist/tools/utils.js +12 -0
  224. package/dist/tools/web-fetch.d.ts +50 -0
  225. package/dist/tools/web-fetch.d.ts.map +1 -0
  226. package/dist/tools/web-fetch.js +446 -0
  227. package/dist/tools/web-search.d.ts +44 -0
  228. package/dist/tools/web-search.d.ts.map +1 -0
  229. package/dist/tools/web-search.js +226 -0
  230. package/dist/tui/autocomplete/attachment-provider.d.ts +3 -6
  231. package/dist/tui/autocomplete/attachment-provider.d.ts.map +1 -1
  232. package/dist/tui/autocomplete/attachment-provider.js +25 -78
  233. package/dist/tui/autocomplete/base-provider.d.ts +1 -0
  234. package/dist/tui/autocomplete/base-provider.d.ts.map +1 -1
  235. package/dist/tui/autocomplete/combined-provider.d.ts +1 -4
  236. package/dist/tui/autocomplete/combined-provider.d.ts.map +1 -1
  237. package/dist/tui/autocomplete/combined-provider.js +3 -17
  238. package/dist/tui/autocomplete/command-provider.d.ts +1 -0
  239. package/dist/tui/autocomplete/command-provider.d.ts.map +1 -1
  240. package/dist/tui/autocomplete/command-provider.js +3 -0
  241. package/dist/tui/autocomplete/file-search-provider.d.ts +2 -1
  242. package/dist/tui/autocomplete/file-search-provider.d.ts.map +1 -1
  243. package/dist/tui/autocomplete/file-search-provider.js +37 -17
  244. package/dist/tui/autocomplete/skill-provider.d.ts +17 -0
  245. package/dist/tui/autocomplete/skill-provider.d.ts.map +1 -0
  246. package/dist/tui/autocomplete/skill-provider.js +49 -0
  247. package/dist/tui/autocomplete/utils.d.ts +2 -1
  248. package/dist/tui/autocomplete/utils.d.ts.map +1 -1
  249. package/dist/tui/autocomplete/utils.js +25 -23
  250. package/dist/tui/autocomplete.d.ts +2 -2
  251. package/dist/tui/autocomplete.d.ts.map +1 -1
  252. package/dist/tui/autocomplete.js +3 -5
  253. package/dist/tui/components/assistant-message.d.ts.map +1 -1
  254. package/dist/tui/components/assistant-message.js +0 -4
  255. package/dist/tui/components/editor.d.ts +18 -3
  256. package/dist/tui/components/editor.d.ts.map +1 -1
  257. package/dist/tui/components/editor.js +211 -237
  258. package/dist/tui/components/footer.d.ts +6 -4
  259. package/dist/tui/components/footer.d.ts.map +1 -1
  260. package/dist/tui/components/footer.js +49 -25
  261. package/dist/tui/components/markdown.d.ts +10 -7
  262. package/dist/tui/components/markdown.d.ts.map +1 -1
  263. package/dist/tui/components/markdown.js +57 -39
  264. package/dist/tui/components/modal.d.ts.map +1 -1
  265. package/dist/tui/components/modal.js +35 -33
  266. package/dist/tui/components/notification.d.ts +13 -2
  267. package/dist/tui/components/notification.d.ts.map +1 -1
  268. package/dist/tui/components/notification.js +36 -2
  269. package/dist/tui/components/progress-bar.js +1 -1
  270. package/dist/tui/components/select-list.d.ts +1 -0
  271. package/dist/tui/components/select-list.d.ts.map +1 -1
  272. package/dist/tui/components/select-list.js +14 -11
  273. package/dist/tui/components/text.d.ts +16 -0
  274. package/dist/tui/components/text.d.ts.map +1 -1
  275. package/dist/tui/components/text.js +72 -57
  276. package/dist/tui/components/thinking-block.d.ts +9 -0
  277. package/dist/tui/components/thinking-block.d.ts.map +1 -1
  278. package/dist/tui/components/thinking-block.js +43 -11
  279. package/dist/tui/components/tool-execution.d.ts +5 -1
  280. package/dist/tui/components/tool-execution.d.ts.map +1 -1
  281. package/dist/tui/components/tool-execution.js +19 -10
  282. package/dist/tui/components/user-message.d.ts.map +1 -1
  283. package/dist/tui/components/user-message.js +0 -3
  284. package/dist/tui/components/welcome.d.ts +2 -1
  285. package/dist/tui/components/welcome.d.ts.map +1 -1
  286. package/dist/tui/components/welcome.js +2 -2
  287. package/dist/tui/editor-launcher.d.ts +3 -2
  288. package/dist/tui/editor-launcher.d.ts.map +1 -1
  289. package/dist/tui/index.d.ts +0 -1
  290. package/dist/tui/index.d.ts.map +1 -1
  291. package/dist/tui/terminal.d.ts.map +1 -1
  292. package/dist/tui/terminal.js +10 -2
  293. package/dist/tui/tui.d.ts +43 -0
  294. package/dist/tui/tui.d.ts.map +1 -1
  295. package/dist/tui/tui.js +166 -41
  296. package/dist/tui/utils.d.ts +1 -5
  297. package/dist/tui/utils.d.ts.map +1 -1
  298. package/dist/tui/utils.js +271 -44
  299. package/dist/utils/bash/parse.d.ts +19 -0
  300. package/dist/utils/bash/parse.d.ts.map +1 -0
  301. package/dist/utils/bash/parse.js +223 -0
  302. package/dist/utils/bash/quote.d.ts +6 -0
  303. package/dist/utils/bash/quote.d.ts.map +1 -0
  304. package/dist/utils/bash/quote.js +23 -0
  305. package/dist/utils/bash.d.ts.map +1 -1
  306. package/dist/utils/bash.js +211 -126
  307. package/dist/utils/command-protection.d.ts +28 -0
  308. package/dist/utils/command-protection.d.ts.map +1 -0
  309. package/dist/utils/command-protection.js +324 -0
  310. package/dist/utils/dedent.d.ts.map +1 -0
  311. package/dist/utils/env-expand.d.ts +2 -0
  312. package/dist/utils/env-expand.d.ts.map +1 -0
  313. package/dist/utils/env-expand.js +8 -0
  314. package/dist/utils/filesystem/path-display.d.ts +11 -0
  315. package/dist/utils/filesystem/path-display.d.ts.map +1 -0
  316. package/dist/utils/filesystem/path-display.js +32 -0
  317. package/dist/utils/filesystem/security.d.ts +2 -2
  318. package/dist/utils/filesystem/security.d.ts.map +1 -1
  319. package/dist/utils/filesystem/security.js +28 -30
  320. package/dist/utils/formatting.d.ts.map +1 -0
  321. package/dist/{formatting.js → utils/formatting.js} +1 -1
  322. package/dist/utils/git.d.ts +4 -0
  323. package/dist/utils/git.d.ts.map +1 -1
  324. package/dist/utils/git.js +30 -0
  325. package/dist/utils/glob.d.ts +1 -1
  326. package/dist/utils/glob.d.ts.map +1 -1
  327. package/dist/utils/logger.d.ts.map +1 -0
  328. package/dist/{logger.js → utils/logger.js} +1 -1
  329. package/dist/utils/parsing.d.ts.map +1 -0
  330. package/dist/utils/process.d.ts.map +1 -1
  331. package/dist/utils/process.js +90 -37
  332. package/dist/utils/templates.d.ts +2 -0
  333. package/dist/utils/templates.d.ts.map +1 -0
  334. package/dist/utils/templates.js +24 -0
  335. package/dist/utils/version.d.ts.map +1 -0
  336. package/dist/{version.js → utils/version.js} +1 -1
  337. package/package.json +35 -26
  338. package/dist/cli.d.ts +0 -23
  339. package/dist/cli.d.ts.map +0 -1
  340. package/dist/commands/add-directory/types.d.ts +0 -6
  341. package/dist/commands/add-directory/types.d.ts.map +0 -1
  342. package/dist/commands/add-directory/types.js +0 -1
  343. package/dist/commands/copy/types.d.ts +0 -3
  344. package/dist/commands/copy/types.d.ts.map +0 -1
  345. package/dist/commands/copy/types.js +0 -1
  346. package/dist/commands/exit/index.d.ts +0 -10
  347. package/dist/commands/exit/index.d.ts.map +0 -1
  348. package/dist/commands/exit/index.js +0 -21
  349. package/dist/commands/exit/types.d.ts +0 -8
  350. package/dist/commands/exit/types.d.ts.map +0 -1
  351. package/dist/commands/exit/types.js +0 -1
  352. package/dist/commands/exit/utils.d.ts +0 -2
  353. package/dist/commands/exit/utils.d.ts.map +0 -1
  354. package/dist/commands/exit/utils.js +0 -13
  355. package/dist/commands/prompt/index.d.ts +0 -5
  356. package/dist/commands/prompt/index.d.ts.map +0 -1
  357. package/dist/commands/prompt/index.js +0 -122
  358. package/dist/commands/prompt/types.d.ts +0 -15
  359. package/dist/commands/prompt/types.d.ts.map +0 -1
  360. package/dist/commands/prompt/types.js +0 -1
  361. package/dist/commands/prompt/utils.d.ts +0 -12
  362. package/dist/commands/prompt/utils.d.ts.map +0 -1
  363. package/dist/commands/prompt/utils.js +0 -107
  364. package/dist/commands/reset/index.d.ts +0 -3
  365. package/dist/commands/reset/index.d.ts.map +0 -1
  366. package/dist/commands/reset/index.js +0 -25
  367. package/dist/commands/reset/types.d.ts +0 -1
  368. package/dist/commands/reset/types.d.ts.map +0 -1
  369. package/dist/commands/reset/types.js +0 -3
  370. package/dist/commands/review/types.d.ts +0 -12
  371. package/dist/commands/review/types.d.ts.map +0 -1
  372. package/dist/commands/review/types.js +0 -1
  373. package/dist/commands/save/index.d.ts +0 -3
  374. package/dist/commands/save/index.d.ts.map +0 -1
  375. package/dist/commands/save/index.js +0 -19
  376. package/dist/config.d.ts.map +0 -1
  377. package/dist/dedent.d.ts.map +0 -1
  378. package/dist/formatting.d.ts.map +0 -1
  379. package/dist/logger.d.ts.map +0 -1
  380. package/dist/mentions.d.ts +0 -14
  381. package/dist/mentions.d.ts.map +0 -1
  382. package/dist/parsing.d.ts.map +0 -1
  383. package/dist/prompts.d.ts.map +0 -1
  384. package/dist/repl-new.d.ts +0 -65
  385. package/dist/repl-new.d.ts.map +0 -1
  386. package/dist/skills.d.ts +0 -16
  387. package/dist/skills.d.ts.map +0 -1
  388. package/dist/skills.js +0 -233
  389. package/dist/stdin.d.ts.map +0 -1
  390. package/dist/tui/autocomplete/path-provider.d.ts +0 -21
  391. package/dist/tui/autocomplete/path-provider.d.ts.map +0 -1
  392. package/dist/tui/autocomplete/path-provider.js +0 -164
  393. package/dist/utils/iterables.d.ts +0 -2
  394. package/dist/utils/iterables.d.ts.map +0 -1
  395. package/dist/utils/iterables.js +0 -6
  396. package/dist/version.d.ts.map +0 -1
  397. /package/dist/{dedent.d.ts → utils/dedent.d.ts} +0 -0
  398. /package/dist/{dedent.js → utils/dedent.js} +0 -0
  399. /package/dist/{formatting.d.ts → utils/formatting.d.ts} +0 -0
  400. /package/dist/{logger.d.ts → utils/logger.d.ts} +0 -0
  401. /package/dist/{parsing.d.ts → utils/parsing.d.ts} +0 -0
  402. /package/dist/{parsing.js → utils/parsing.js} +0 -0
  403. /package/dist/{version.d.ts → utils/version.d.ts} +0 -0
@@ -1,55 +1,234 @@
1
- import { execSync } from "node:child_process";
1
+ // import { execSync } from "node:child_process";
2
+ import { randomBytes } from "node:crypto";
3
+ import { mkdirSync, writeFileSync } from "node:fs";
4
+ import { dirname } from "node:path";
2
5
  import { z } from "zod";
3
6
  import { initExecutionEnvironment } from "../execution/index.js";
4
- import { logger } from "../logger.js";
5
7
  import style from "../terminal/style.js";
6
8
  import { resolveCwd, validatePaths } from "../utils/bash.js";
9
+ import { detectDestructiveCommand, formatBlockedCommandMessage, } from "../utils/command-protection.js";
10
+ import { expandEnvVars } from "../utils/env-expand.js";
11
+ import { logger } from "../utils/logger.js";
7
12
  import { convertNullString } from "../utils/zod.js";
8
13
  /**
9
14
  * Detects git commit commands with multi-line -m messages that will fail in shell.
10
- * Returns an error message if detected, or null if the command is safe.
15
+ * Writes the message to a temp file and returns an error with the file path.
16
+ * Returns null if the command is safe.
11
17
  */
12
18
  function detectMultilineGitCommit(command) {
13
19
  const trimmed = command.trim();
14
20
  // Check if it's a git commit command
15
- if (!trimmed.startsWith("git commit") && !trimmed.startsWith("git ")) {
21
+ if (!trimmed.startsWith("git commit")) {
16
22
  return null;
17
23
  }
18
- // Look for -m flag with a message containing newlines
24
+ // Look for -m or -am flags with a message containing newlines
19
25
  // Match patterns like: git commit -m "message\nwith\nnewlines"
26
+ // or: git commit -am "message\nwith\nnewlines"
20
27
  // Using [\s\S] instead of [^] to match any character including newlines
21
- const messageMatch = trimmed.match(/-m\s+["']([\s\S]*?)["']/);
28
+ const messageMatch = trimmed.match(/-am?\s+["']([\s\S]*?)["']/);
22
29
  if (!messageMatch) {
23
30
  return null;
24
31
  }
25
32
  const message = messageMatch[1];
26
33
  if (message.includes("\n")) {
27
- return `Multi-line commit messages with -m flag cause shell parsing errors. Instead:
28
- 1. Write the commit message to a temporary file (e.g., /tmp/acai/commit-msg.txt)
29
- 2. Use: git commit -F /tmp/acai/commit-msg.txt
30
- 3. Optionally remove the temp file after committing
31
-
32
- Example:
33
- First, create the file with the commit message using the write_file tool.
34
- Then run: git commit -F /tmp/acai/commit-msg.txt`;
34
+ const randomId = randomBytes(4).toString("hex");
35
+ const commitMsgPath = `/tmp/acai/commit-msg-${randomId}.txt`;
36
+ try {
37
+ mkdirSync(dirname(commitMsgPath), { recursive: true });
38
+ writeFileSync(commitMsgPath, message, "utf-8");
39
+ }
40
+ catch (error) {
41
+ logger.error(error, "Failed to write commit message to temp file");
42
+ }
43
+ return `Multi-line commit messages with -m flag cause shell parsing errors. The commit message has been written to:
44
+ ${commitMsgPath}
45
+ Use: git commit -F ${commitMsgPath}`;
35
46
  }
36
47
  return null;
37
48
  }
38
49
  export const BashTool = {
39
50
  name: "Bash",
40
51
  };
41
- const installedTools = getInstalledTools();
42
- const toolDescription = `Execute commands in a shell. Commands can execute only within the allowed directories. Always use absolute paths.
43
-
44
- Tools available:
45
- ${installedTools}`;
52
+ // const installedTools = getInstalledTools();
53
+ // const toolDescription = `Execute commands in a shell. Commands can execute only within the allowed directories. Always use absolute paths. Working directory persists between commands; shell state (everything else) does not. The shell environment is initialized from the user's profile (bash or zsh).
54
+ // IMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.
55
+ // Before executing the command, please follow these steps:
56
+ // 1. Directory Verification:
57
+ // - If the command will create new directories or files, first use \`ls\` to verify the parent directory exists and is the correct location
58
+ // - For example, before running "mkdir foo/bar", first use \`ls foo\` to check that "foo" exists and is the intended parent directory
59
+ // 2. Command Execution:
60
+ // - Always quote file paths that contain spaces with double quotes (e.g., cd "path with spaces/file.txt")
61
+ // - Examples of proper quoting:
62
+ // - cd "/Users/name/My Documents" (correct)
63
+ // - cd /Users/name/My Documents (incorrect - will fail)
64
+ // - python "/path/with spaces/script.py" (correct)
65
+ // - python /path/with spaces/script.py (incorrect - will fail)
66
+ // - After ensuring proper quoting, execute the command.
67
+ // - Capture the output of the command.
68
+ // Usage notes:
69
+ // - The command argument is required.
70
+ // - You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). If not specified, commands will timeout after 120000ms (2 minutes).
71
+ // - It is very helpful if you write a clear, concise description of what this command does. For simple commands, keep it brief (5-10 words). For complex commands (piped commands, obscure flags, or anything hard to understand at a glance), add enough context to clarify what it does.
72
+ // - If the output exceeds 30000 characters, output will be truncated before being returned to you.
73
+ // - You can use the \`background\` parameter to run the command in the background. Only use this if you don't need the result immediately and are OK being notified when the command completes later. You do not need to check the output right away - you'll be notified when it finishes. You do not need to use '&' at the end of the command when using this parameter.
74
+ // - Avoid using Bash with the \`find\`, \`grep\`, \`cat\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, or \`echo\` commands, unless explicitly instructed or when these commands are truly necessary for the task. Instead, always prefer using the dedicated tools for these commands:
75
+ // - File listing: Use LS or DirectoryTree (not ls)
76
+ // - File search: Use Glob (NOT find or ls)
77
+ // - Content search: Use Grep (NOT grep or rg)
78
+ // - Read files: Use Read (NOT cat/head/tail)
79
+ // - Edit files: Use Edit (NOT sed/awk)
80
+ // - Write files: Use Write (NOT echo >/cat <<EOF)
81
+ // - Communication: Output text directly (NOT echo/printf)
82
+ // - When issuing multiple commands:
83
+ // - If the commands are independent and can run in parallel, make multiple Bash tool calls in a single message. For example, if you need to run "git status" and "git diff", send a single message with two Bash tool calls in parallel.
84
+ // - If the commands depend on each other and must run sequentially, use a single Bash call with '&&' to chain them together (e.g., \`git add . && git commit -m "message" && git push\`). For instance, if one operation must complete before another starts (like mkdir before cp, Write before Bash for git operations, or git add before git commit), run these operations sequentially instead.
85
+ // - Use ';' only when you need to run commands sequentially but don't care if earlier commands fail
86
+ // - DO NOT use newlines to separate commands (newlines are ok in quoted strings)
87
+ // - Commands execute in the project root directory by default. Do NOT prepend \`cd <project-root> &&\` to commands—it's unnecessary.
88
+ // - Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of \`cd\`. You may use \`cd\` if the User explicitly requests it.
89
+ // <good-example>
90
+ // pytest /foo/bar/tests
91
+ // </good-example>
92
+ // <bad-example>
93
+ // cd /foo/bar && pytest tests
94
+ // </bad-example>
95
+ // ### Committing changes with git
96
+ // Only create commits when requested by the user. If unclear, ask first. When the user asks you to create a new git commit, follow these steps carefully:
97
+ // Git Safety Protocol:
98
+ // - NEVER update the git config
99
+ // - NEVER run destructive git commands (push --force, reset --hard, checkout ., restore ., clean -f, branch -D) unless the user explicitly requests these actions. Taking unauthorized destructive actions is unhelpful and can result in lost work, so it's best to ONLY run these commands when given direct instructions
100
+ // - NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it
101
+ // - NEVER run force push to main/master, warn the user if they request it
102
+ // - CRITICAL: Always create NEW commits rather than amending, unless the user explicitly requests a git amend. When a pre-commit hook fails, the commit did NOT happen — so --amend would modify the PREVIOUS commit, which may result in destroying work or losing previous changes. Instead, after hook failure, fix the issue, re-stage, and create a NEW commit
103
+ // - When staging files, prefer adding specific files by name rather than using "git add -A" or "git add .", which can accidentally include sensitive files (.env, credentials) or large binaries
104
+ // - NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit when explicitly asked, otherwise the user will feel that you are being too proactive
105
+ // 1. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following bash commands in parallel, each using the Bash tool:
106
+ // - Run a git status command to see all untracked files. IMPORTANT: Never use the -uall flag as it can cause memory issues on large repos.
107
+ // - Run a git diff command to see both staged and unstaged changes that will be committed.
108
+ // - Run a git log command to see recent commit messages, so that you can follow this repository's commit message style.
109
+ // 2. Analyze all staged changes (both previously staged and newly added) and draft a commit message:
110
+ // - Summarize the nature of the changes (eg. new feature, enhancement to an existing feature, bug fix, refactoring, test, docs, etc.). Ensure the message accurately reflects the changes and their purpose (i.e. "add" means a wholly new feature, "update" means an enhancement to an existing feature, "fix" means a bug fix, etc.).
111
+ // - Do not commit files that likely contain secrets (.env, credentials.json, etc). Warn the user if they specifically request to commit those files
112
+ // - Draft a concise (1-2 sentences) commit message that focuses on the "why" rather than the "what"
113
+ // - Ensure it accurately reflects the changes and their purpose
114
+ // 3. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following commands:
115
+ // - Add relevant untracked files to the staging area.
116
+ // - Run git status after the commit completes to verify success.
117
+ // Note: git status depends on the commit completing, so run it sequentially after the commit.
118
+ // 4. If the commit fails due to pre-commit hook: fix the issue and create a NEW commit
119
+ // Important notes:
120
+ // - NEVER run additional commands to read or explore code, besides git bash commands
121
+ // - DO NOT push to the remote repository unless the user explicitly asks you to do so
122
+ // - IMPORTANT: Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported.
123
+ // - IMPORTANT: Do not use --no-edit with git rebase commands, as the --no-edit flag is not a valid option for git rebase.
124
+ // - If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit
125
+ // - In order to ensure good formatting, ALWAYS pass the commit message via a HEREDOC, a la this example:
126
+ // <example>
127
+ // git commit -m "$(cat <<'EOF'
128
+ // Commit message here.
129
+ // EOF
130
+ // )"
131
+ // </example>
132
+ // ### Creating pull requests
133
+ // Use the gh command via the Bash tool for ALL GitHub-related tasks including working with issues, pull requests, checks, and releases. If given a Github URL use the gh command to get the information needed.
134
+ // IMPORTANT: When the user asks you to create a pull request, follow these steps carefully:
135
+ // 1. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following bash commands in parallel using the Bash tool, in order to understand the current state of the branch since it diverged from the main branch:
136
+ // - Run a git status command to see all untracked files (never use -uall flag)
137
+ // - Run a git diff command to see both staged and unstaged changes that will be committed
138
+ // - Check if the current branch tracks a remote branch and is up to date with the remote, so you know if you need to push to the remote
139
+ // - Run a git log command and \`git diff [base-branch]...HEAD\` to understand the full commit history for the current branch (from the time it diverged from the base branch)
140
+ // 2. Analyze all changes that will be included in the pull request, making sure to look at all relevant commits (NOT just the latest commit, but ALL commits that will be included in the pull request!!!), and draft a pull request title and summary:
141
+ // - Keep the PR title short (under 70 characters)
142
+ // - Use the description/body for details, not the title
143
+ // 3. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following commands in parallel:
144
+ // - Create new branch if needed
145
+ // - Push to remote with -u flag if needed
146
+ // - Create PR using gh pr create with the format below. Use a HEREDOC to pass the body to ensure correct formatting.
147
+ // <example>
148
+ // gh pr create --title "the pr title" --body "$(cat <<'EOF'
149
+ // #### Summary
150
+ // <1-3 bullet points>
151
+ // #### Test plan
152
+ // [Bulleted markdown checklist of TODOs for testing the pull request...]
153
+ // EOF
154
+ // )"
155
+ // </example>
156
+ // Important:
157
+ // - Return the PR URL when you're done, so the user can see it
158
+ // ### Other common operations
159
+ // - View comments on a Github PR: gh api repos/foo/bar/pulls/123/comments
160
+ // {
161
+ // "$schema": "https://json-schema.org/draft/2020-12/schema",
162
+ // "type": "object",
163
+ // "properties": {
164
+ // "command": {
165
+ // "description": "The command to execute",
166
+ // "type": "string"
167
+ // },
168
+ // "timeout": {
169
+ // "description": "Optional timeout in milliseconds (max 600000)",
170
+ // "type": "number"
171
+ // },
172
+ // "description": {
173
+ // "description": "Clear, concise description of what this command does in active voice. Never use words like "complex" or "risk" in the description - just describe what it does.\n\nFor simple commands (git, npm, standard CLI tools), keep it brief (5-10 words):\n- ls → "List files in current directory"\n- git status → "Show working tree status"\n- npm install → "Install package dependencies"\n\nFor commands that are harder to parse at a glance (piped commands, obscure flags, etc.), add enough context to clarify what it does:\n- find . -name "*.tmp" -exec rm {} \\; → "Find and delete all .tmp files recursively"\n- git reset --hard origin/main → "Discard all local changes and match remote main"\n- curl -s url | jq '.data[]' → "Fetch JSON from URL and extract data array elements"",
174
+ // "type": "string"
175
+ // },
176
+ // "run_in_background": {
177
+ // "description": "Set to true to run this command in the background. Use TaskOutput to read the output later.",
178
+ // "type": "boolean"
179
+ // },
180
+ // "dangerouslyDisableSandbox": {
181
+ // "description": "Set this to true to dangerously override sandbox mode and run commands without sandboxing.",
182
+ // "type": "boolean"
183
+ // },
184
+ // "_simulatedSedEdit": {
185
+ // "description": "Internal: pre-computed sed edit result from preview",
186
+ // "type": "object",
187
+ // "properties": {
188
+ // "filePath": {
189
+ // "type": "string"
190
+ // },
191
+ // "newContent": {
192
+ // "type": "string"
193
+ // }
194
+ // },
195
+ // "required": [
196
+ // "filePath",
197
+ // "newContent"
198
+ // ],
199
+ // "additionalProperties": false
200
+ // }
201
+ // },
202
+ // "required": [
203
+ // "command"
204
+ // ],
205
+ // "additionalProperties": false
206
+ // }
207
+ // Tools available:
208
+ // ${installedTools}`;
209
+ const simpleDescription = "Run terminal commands.";
46
210
  // Command execution timeout in milliseconds
47
211
  const DEFAULT_TIMEOUT = 1.5 * 60 * 1000; // 1.5 minutes
212
+ // Maximum output size in bytes (50KB) to prevent context window exhaustion
213
+ const MAX_OUTPUT_SIZE = 50 * 1024;
214
+ /**
215
+ * Truncates output if it exceeds MAX_OUTPUT_SIZE and adds a clear message.
216
+ * This prevents extremely large outputs from exhausting the context window.
217
+ */
218
+ function truncateOutput(output) {
219
+ if (output.length <= MAX_OUTPUT_SIZE) {
220
+ return output;
221
+ }
222
+ const truncatedLength = MAX_OUTPUT_SIZE;
223
+ const originalLength = output.length;
224
+ const truncated = output.slice(0, truncatedLength);
225
+ return `${truncated}\n\n[OUTPUT TRUNCATED: ${originalLength.toLocaleString()} characters total, showing first ${truncatedLength.toLocaleString()} characters. The output was too large and was truncated to prevent context window exhaustion. Consider using commands that produce smaller output (e.g., head, tail with line limits, or redirecting to a file).]`;
226
+ }
48
227
  const inputSchema = z.object({
49
228
  command: z.string().describe("Full CLI command to execute."),
50
229
  cwd: z
51
230
  .preprocess((val) => convertNullString(val), z.string().nullable())
52
- .describe("Working directory file path (default: project root). Must be within the project directory. Required but nullable."),
231
+ .describe("Optional working directory. Commands execute in the project root by default. Only specify if you need a different directory. Must be within allowed directories."),
53
232
  timeout: z
54
233
  .preprocess((val) => convertNullString(val), z.coerce.number().nullable())
55
234
  .describe(`Command execution timeout in milliseconds. Required but nullable. If null, the default value is ${DEFAULT_TIMEOUT}ms`),
@@ -58,143 +237,160 @@ const inputSchema = z.object({
58
237
  .optional()
59
238
  .describe("Run command in background. If true, command will run until program exit."),
60
239
  });
61
- export const createBashTool = async ({ baseDir, allowedDirs, }) => {
62
- const execEnv = await initExecutionEnvironment();
63
- const allowedDirectories = allowedDirs ?? [baseDir];
240
+ export const createBashTool = async (options) => {
241
+ const { primaryDir, allowedDirs } = options.workspace;
242
+ const configEnv = options.env ? expandEnvVars(options.env) : {};
243
+ const execEnv = await initExecutionEnvironment({
244
+ execution: {
245
+ env: {
246
+ ...configEnv,
247
+ },
248
+ },
249
+ });
250
+ const allowedDirectories = allowedDirs ?? [primaryDir];
251
+ function validateCommand(command, allowedDirs, cwd) {
252
+ const pathValidation = validatePaths(command, allowedDirs, cwd);
253
+ if (!pathValidation.isValid) {
254
+ throw new Error(pathValidation.error ?? "Unknown error.");
255
+ }
256
+ const multilineError = detectMultilineGitCommit(command);
257
+ if (multilineError) {
258
+ throw new Error(multilineError);
259
+ }
260
+ const destructiveCheck = detectDestructiveCommand(command);
261
+ if (destructiveCheck.blocked) {
262
+ throw new Error(formatBlockedCommandMessage(destructiveCheck));
263
+ }
264
+ }
265
+ function processCommand(cmd, isBackground) {
266
+ const stripped = stripTrailingAmpersand(cmd, isBackground);
267
+ return fixRgCommand(stripped);
268
+ }
269
+ function executeBackground(cmd, cwd, signal) {
270
+ const proc = execEnv.executeCommandInBackground(cmd, {
271
+ cwd,
272
+ abortSignal: signal,
273
+ onOutput: (output) => {
274
+ logger.debug({ output }, "Background command output:");
275
+ },
276
+ onError: (error) => {
277
+ logger.debug({ error }, "Background command error:");
278
+ },
279
+ onExit: (code) => {
280
+ logger.debug(`Background command exited with code ${code}`);
281
+ },
282
+ });
283
+ return `Background process started with PID: ${proc.pid}`;
284
+ }
285
+ async function executeSync(cmd, cwd, timeout, signal) {
286
+ const { output, exitCode, error } = await execEnv.executeCommand(cmd, {
287
+ cwd,
288
+ timeout,
289
+ abortSignal: signal,
290
+ preserveOutputOnError: true,
291
+ captureStderr: true,
292
+ throwOnError: false,
293
+ });
294
+ if (exitCode !== 0) {
295
+ const errorMessage = error
296
+ ? error.message
297
+ : `Command exited with code ${exitCode}`;
298
+ const combinedOutput = output
299
+ ? `${errorMessage}\n${output}`
300
+ : errorMessage;
301
+ throw new Error(truncateOutput(combinedOutput));
302
+ }
303
+ return truncateOutput(output);
304
+ }
64
305
  return {
65
306
  toolDef: {
66
- description: toolDescription,
307
+ description: simpleDescription,
67
308
  inputSchema,
68
309
  },
69
310
  display({ command }) {
70
- return `\n> ${style.cyan(command)}`;
311
+ return `${style.cyan(command)}`;
71
312
  },
72
313
  async execute({ command, cwd, timeout, background }, { abortSignal }) {
73
314
  if (abortSignal?.aborted) {
74
315
  throw new Error("Command execution aborted");
75
316
  }
76
- // grok doesn't follow my instructions
77
317
  const safeCwd = cwd === "null" ? null : cwd;
78
- const resolvedCwd = resolveCwd(safeCwd, baseDir, allowedDirectories);
318
+ const resolvedCwd = resolveCwd(safeCwd, primaryDir, allowedDirectories);
79
319
  const safeTimeout = timeout ?? DEFAULT_TIMEOUT;
80
- const pathValidation = validatePaths(command, allowedDirectories, resolvedCwd);
81
- if (!pathValidation.isValid) {
82
- throw new Error(pathValidation.error ?? "Unknown error.");
83
- }
84
- // Check for multi-line git commit messages that will fail
85
- const multilineError = detectMultilineGitCommit(command);
86
- if (multilineError) {
87
- throw new Error(multilineError);
88
- }
320
+ validateCommand(command, allowedDirectories, resolvedCwd);
89
321
  if (abortSignal?.aborted) {
90
322
  throw new Error("Command execution aborted before running the command");
91
323
  }
92
- // Handle background execution
324
+ const processedCommand = processCommand(command, background ?? false);
93
325
  if (background) {
94
- // Strip any existing & from command to avoid double backgrounding
95
- let processedCommand = command.trim();
96
- if (processedCommand.endsWith("&")) {
97
- logger.warn(`Stripping '&' from command since background=true: ${command}`);
98
- processedCommand = processedCommand.slice(0, -1).trim();
99
- }
100
- // Fix rg commands that don't have an explicit path
101
- processedCommand = fixRgCommand(processedCommand);
102
- const backgroundProcess = execEnv.executeCommandInBackground(processedCommand, {
103
- cwd: resolvedCwd,
104
- abortSignal,
105
- onOutput: (output) => {
106
- logger.debug({ output }, "Background command output:");
107
- },
108
- onError: (error) => {
109
- logger.debug({ error }, "Background command error:");
110
- },
111
- onExit: (code) => {
112
- logger.debug(`Background command exited with code ${code}`);
113
- },
114
- });
115
- return `Background process started with PID: ${backgroundProcess.pid}`;
326
+ return executeBackground(processedCommand, resolvedCwd, abortSignal);
116
327
  }
117
- // Handle regular synchronous execution
118
- // Strip & if present to ensure synchronous behavior
119
- let processedCommand = command.trim();
120
- if (processedCommand.endsWith("&")) {
121
- logger.warn(`Stripping '&' from command since background=false: ${command}`);
122
- processedCommand = processedCommand.slice(0, -1).trim();
123
- }
124
- // Fix rg commands that don't have an explicit path
125
- // rg hangs when stdin is a socket and no path is given
126
- processedCommand = fixRgCommand(processedCommand);
127
- const { output, exitCode } = await execEnv.executeCommand(processedCommand, {
128
- cwd: resolvedCwd,
129
- timeout: safeTimeout,
130
- abortSignal,
131
- preserveOutputOnError: true,
132
- captureStderr: true,
133
- throwOnError: false,
134
- });
135
- if (exitCode !== 0) {
136
- throw new Error(output);
137
- }
138
- return output;
328
+ return executeSync(processedCommand, resolvedCwd, safeTimeout, abortSignal);
139
329
  },
140
330
  };
141
331
  };
142
- function getInstalledTools() {
143
- // Check for required bash tools
144
- const tools = [
145
- {
146
- name: "git",
147
- command: "git --version",
148
- description: "Version control system - used for cloning repositories, checking out branches, committing changes, viewing history, and managing code versions",
149
- },
150
- {
151
- name: "gh",
152
- command: "gh --version",
153
- description: "GitHub CLI - used for creating pull requests, managing issues, interacting with GitHub API, and automating GitHub workflows",
154
- },
155
- {
156
- name: "rg",
157
- command: "rg --version",
158
- description: "ripgrep - fast text search tool for searching code patterns, file contents, and regular expressions across the codebase (use this instead of grep)",
159
- },
160
- {
161
- name: "fd",
162
- command: "fd --version",
163
- description: "Fast file finder - alternative to find command, used for finding files by name, pattern, or type with intuitive syntax (use this instead of find)",
164
- },
165
- {
166
- name: "ast-grep",
167
- command: "ast-grep --version",
168
- description: "AST-based code search - used for structural code search, refactoring, finding patterns in abstract syntax trees, and code transformations",
169
- },
170
- {
171
- name: "jq",
172
- command: "jq --version",
173
- description: "JSON processor - used for parsing, filtering, and manipulating JSON output from APIs, commands, and configuration files",
174
- },
175
- {
176
- name: "yq",
177
- command: "yq --version",
178
- description: "YAML processor - used for parsing and manipulating YAML files (configs, CI/CD pipelines, Kubernetes manifests) with jq-like syntax",
179
- },
180
- ];
181
- const toolStatus = tools
182
- .map((tool) => {
183
- let status = false;
184
- try {
185
- execSync(tool.command, { stdio: "ignore", timeout: 5000 });
186
- status = true;
187
- }
188
- catch (_error) {
189
- // Ignore error, tool is not installed
190
- }
191
- return { name: tool.name, description: tool.description, status };
192
- })
193
- .filter((tool) => tool.status)
194
- .map((tool) => `- **${tool.name}**: ${tool.description}`)
195
- .join("\n");
196
- return toolStatus;
197
- }
332
+ // function getInstalledTools() {
333
+ // // Check for required bash tools
334
+ // const tools = [
335
+ // {
336
+ // name: "git",
337
+ // command: "git --version",
338
+ // description:
339
+ // "Version control system - used for cloning repositories, checking out branches, committing changes, viewing history, and managing code versions",
340
+ // },
341
+ // {
342
+ // name: "gh",
343
+ // command: "gh --version",
344
+ // description:
345
+ // "GitHub CLI - used for creating pull requests, managing issues, interacting with GitHub API, and automating GitHub workflows",
346
+ // },
347
+ // {
348
+ // name: "rg",
349
+ // command: "rg --version",
350
+ // description:
351
+ // "ripgrep - fast text search tool for searching code patterns, file contents, and regular expressions across the codebase (use this instead of grep)",
352
+ // },
353
+ // {
354
+ // name: "fd",
355
+ // command: "fd --version",
356
+ // description:
357
+ // "Fast file finder - alternative to find command, used for finding files by name, pattern, or type with intuitive syntax (use this instead of find)",
358
+ // },
359
+ // {
360
+ // name: "ast-grep",
361
+ // command: "ast-grep --version",
362
+ // description:
363
+ // "AST-based code search - used for structural code search, refactoring, finding patterns in abstract syntax trees, and code transformations",
364
+ // },
365
+ // {
366
+ // name: "jq",
367
+ // command: "jq --version",
368
+ // description:
369
+ // "JSON processor - used for parsing, filtering, and manipulating JSON output from APIs, commands, and configuration files",
370
+ // },
371
+ // {
372
+ // name: "yq",
373
+ // command: "yq --version",
374
+ // description:
375
+ // "YAML processor - used for parsing and manipulating YAML files (configs, CI/CD pipelines, Kubernetes manifests) with jq-like syntax",
376
+ // },
377
+ // ];
378
+ // const toolStatus = tools
379
+ // .map((tool) => {
380
+ // let status = false;
381
+ // try {
382
+ // execSync(tool.command, { stdio: "ignore", timeout: 5000 });
383
+ // status = true;
384
+ // } catch (_error) {
385
+ // // Ignore error, tool is not installed
386
+ // }
387
+ // return { name: tool.name, description: tool.description, status };
388
+ // })
389
+ // .filter((tool) => tool.status)
390
+ // .map((tool) => `- **${tool.name}**: ${tool.description}`)
391
+ // .join("\n");
392
+ // return toolStatus;
393
+ // }
198
394
  /**
199
395
  * Fix rg commands that don't have an explicit path
200
396
  * rg hangs when stdin is a socket and no path is given
@@ -214,7 +410,7 @@ function fixRgCommand(command) {
214
410
  }
215
411
  // Simple heuristic: if last token starts with -, add .
216
412
  // This handles cases like: rg -l pattern --type ts --type js
217
- const tokens = trimmed.split(/\\s+/);
413
+ const tokens = trimmed.split(/\s+/);
218
414
  const lastToken = tokens[tokens.length - 1];
219
415
  if (lastToken?.startsWith("-")) {
220
416
  // Command ends with an option, need to add path
@@ -236,9 +432,9 @@ function fixRgCommand(command) {
236
432
  // If it's just alphanumeric with maybe some regex chars, it's probably a pattern
237
433
  // Common pattern chars: ., *, +, ?, [, ], ^, $, (, ), |, \\
238
434
  // But we want to be conservative - if it looks like a filename without path, add .
239
- if (!lastToken.includes("/") && !lastToken.includes("*")) {
240
- // Doesn't look like a path with glob or directory, likely a pattern
241
- // Need to add path
435
+ if (!lastToken.includes("/") &&
436
+ !lastToken.includes("*") &&
437
+ !lastToken.includes(".")) {
242
438
  logger.debug(`Adding '.' to rg command: ${command}`);
243
439
  return `${command} .`;
244
440
  }
@@ -249,3 +445,15 @@ function fixRgCommand(command) {
249
445
  logger.debug(`Adding '.' to rg command: ${command}`);
250
446
  return `${command} .`;
251
447
  }
448
+ /**
449
+ * Strips trailing '&' from command and logs a warning.
450
+ * Returns the processed command.
451
+ */
452
+ function stripTrailingAmpersand(command, isBackground) {
453
+ let processedCommand = command.trim();
454
+ if (processedCommand.endsWith("&")) {
455
+ logger.warn(`Stripping '&' from command since background=${String(isBackground)}: ${command}`);
456
+ processedCommand = processedCommand.slice(0, -1).trim();
457
+ }
458
+ return processedCommand;
459
+ }
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import type { WorkspaceContext } from "../index.ts";
2
3
  import type { ToolExecutionOptions } from "./types.ts";
3
4
  export declare const DirectoryTreeTool: {
4
5
  name: "DirectoryTree";
@@ -9,9 +10,8 @@ declare const inputSchema: z.ZodObject<{
9
10
  maxDepth: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedNumber<unknown>>>;
10
11
  }, z.core.$strip>;
11
12
  type DirectoryTreeInputSchema = z.infer<typeof inputSchema>;
12
- export declare const createDirectoryTreeTool: ({ workingDir, allowedDirs, }: {
13
- workingDir: string;
14
- allowedDirs?: string[];
13
+ export declare const createDirectoryTreeTool: (options: {
14
+ workspace: WorkspaceContext;
15
15
  }) => Promise<{
16
16
  toolDef: {
17
17
  description: string;
@@ -1 +1 @@
1
- {"version":3,"file":"directory-tree.d.ts","sourceRoot":"","sources":["../../source/tools/directory-tree.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAKvD,eAAO,MAAM,iBAAiB;;CAE7B,CAAC;AAEF,QAAA,MAAM,WAAW;;;;iBAYf,CAAC;AAEH,KAAK,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAE5D,eAAO,MAAM,uBAAuB,GAAU,8BAG3C;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;;;;;;;;;4CAO2C,wBAAwB;4CAW9B,wBAAwB,mBACvC,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;EAyBrB,CAAC"}
1
+ {"version":3,"file":"directory-tree.d.ts","sourceRoot":"","sources":["../../source/tools/directory-tree.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAKvD,eAAO,MAAM,iBAAiB;;CAE7B,CAAC;AAEF,QAAA,MAAM,WAAW;;;;iBAYf,CAAC;AAEH,KAAK,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAE5D,eAAO,MAAM,uBAAuB,GAAU,SAAS;IACrD,SAAS,EAAE,gBAAgB,CAAC;CAC7B;;;;;;;;;4CAS2C,wBAAwB;4CAY9B,wBAAwB,mBACvC,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;EAyBrB,CAAC"}
@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { z } from "zod";
4
4
  import style from "../terminal/style.js";
5
+ import { toDisplayPath } from "../utils/filesystem/path-display.js";
5
6
  import { joinWorkingDir, validatePath } from "../utils/filesystem/security.js";
6
7
  import ignore from "../utils/ignore.js";
7
8
  import { convertNullString } from "../utils/zod.js";
@@ -19,15 +20,17 @@ const inputSchema = z.object({
19
20
  .preprocess((val) => convertNullString(val), z.coerce.number().nullable())
20
21
  .describe(`Maximum recursion depth. Set to 0 for no limit. (default: ${DEFAULT_DEPTH_LIMIT})`),
21
22
  });
22
- export const createDirectoryTreeTool = async ({ workingDir, allowedDirs, }) => {
23
- const allowedDirectory = allowedDirs ?? [workingDir];
23
+ export const createDirectoryTreeTool = async (options) => {
24
+ const { primaryDir, allowedDirs } = options.workspace;
25
+ const allowedDirectory = allowedDirs ?? [primaryDir];
24
26
  return {
25
27
  toolDef: {
26
- description: `Get a directory tree structure for a given path. This tool will ignore any directories or files listed in a .gitignore file. Use this tool when you need to see a complete directory tree for a path in the allowed directories. This can be used to get an understanding of how a project is organized and what files are available before using other file system tools. Results are automatically limited to prevent overwhelming output. Default limits are ${DEFAULT_ITEM_LIMIT} items and ${DEFAULT_DEPTH_LIMIT} depth. Use maxResults and maxDepth parameters for better control over output size.`,
28
+ description: "Show directory structure as a recursive tree. Use this to explore nested directories and understand the overall project structure. For a simple flat list of a single directory, use LS instead.",
27
29
  inputSchema,
28
30
  },
29
31
  display({ path, maxDepth, maxResults }) {
30
- let display = `\n> ${style.cyan(path)}`;
32
+ const displayPath = toDisplayPath(path);
33
+ let display = `${style.cyan(displayPath)}`;
31
34
  if (maxDepth || maxResults) {
32
35
  const parts = [];
33
36
  if (maxDepth)
@@ -42,7 +45,7 @@ export const createDirectoryTreeTool = async ({ workingDir, allowedDirs, }) => {
42
45
  if (abortSignal?.aborted) {
43
46
  throw new Error("Directory tree listing aborted");
44
47
  }
45
- const validPath = await validatePath(joinWorkingDir(path, workingDir), allowedDirectory, { abortSignal });
48
+ const validPath = await validatePath(joinWorkingDir(path, primaryDir), allowedDirectory, { abortSignal });
46
49
  if (abortSignal?.aborted) {
47
50
  throw new Error("Directory tree listing aborted before tree generation");
48
51
  }