@travisennis/acai 0.0.6 → 0.0.7

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 (344) hide show
  1. package/README.md +186 -17
  2. package/bin/acai-wrapper.js +26 -0
  3. package/dist/agent/index.d.ts +15 -2
  4. package/dist/agent/index.d.ts.map +1 -1
  5. package/dist/agent/index.js +202 -174
  6. package/dist/api/exa/index.js +1 -1
  7. package/dist/cli.d.ts +2 -1
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +40 -7
  10. package/dist/commands/add-directory-command.d.ts +1 -1
  11. package/dist/commands/add-directory-command.d.ts.map +1 -1
  12. package/dist/commands/add-directory-command.js +1 -32
  13. package/dist/commands/application-log-command.d.ts +1 -1
  14. package/dist/commands/application-log-command.d.ts.map +1 -1
  15. package/dist/commands/application-log-command.js +2 -38
  16. package/dist/commands/clear-command.d.ts +1 -1
  17. package/dist/commands/clear-command.d.ts.map +1 -1
  18. package/dist/commands/clear-command.js +1 -5
  19. package/dist/commands/compact-command.d.ts.map +1 -1
  20. package/dist/commands/compact-command.js +0 -9
  21. package/dist/commands/context-command.d.ts +1 -1
  22. package/dist/commands/context-command.d.ts.map +1 -1
  23. package/dist/commands/context-command.js +13 -72
  24. package/dist/commands/copy-command.d.ts.map +1 -1
  25. package/dist/commands/copy-command.js +0 -19
  26. package/dist/commands/edit-command.d.ts +1 -1
  27. package/dist/commands/edit-command.d.ts.map +1 -1
  28. package/dist/commands/edit-command.js +3 -49
  29. package/dist/commands/edit-prompt-command.d.ts +1 -1
  30. package/dist/commands/edit-prompt-command.d.ts.map +1 -1
  31. package/dist/commands/edit-prompt-command.js +1 -26
  32. package/dist/commands/exit-command.d.ts +1 -4
  33. package/dist/commands/exit-command.d.ts.map +1 -1
  34. package/dist/commands/exit-command.js +2 -18
  35. package/dist/commands/files-command.d.ts +1 -1
  36. package/dist/commands/files-command.d.ts.map +1 -1
  37. package/dist/commands/files-command.js +1 -54
  38. package/dist/commands/generate-rules-command.d.ts +1 -1
  39. package/dist/commands/generate-rules-command.d.ts.map +1 -1
  40. package/dist/commands/generate-rules-command.js +18 -60
  41. package/dist/commands/handoff-command.d.ts.map +1 -1
  42. package/dist/commands/handoff-command.js +0 -11
  43. package/dist/commands/health-command.d.ts +1 -1
  44. package/dist/commands/health-command.d.ts.map +1 -1
  45. package/dist/commands/health-command.js +8 -103
  46. package/dist/commands/help-command.d.ts +1 -1
  47. package/dist/commands/help-command.d.ts.map +1 -1
  48. package/dist/commands/help-command.js +6 -14
  49. package/dist/commands/history-command.d.ts +1 -1
  50. package/dist/commands/history-command.d.ts.map +1 -1
  51. package/dist/commands/history-command.js +30 -106
  52. package/dist/commands/init-command.d.ts +1 -1
  53. package/dist/commands/init-command.d.ts.map +1 -1
  54. package/dist/commands/init-command.js +4 -23
  55. package/dist/commands/last-log-command.d.ts +1 -1
  56. package/dist/commands/last-log-command.d.ts.map +1 -1
  57. package/dist/commands/last-log-command.js +1 -28
  58. package/dist/commands/list-directories-command.d.ts +1 -1
  59. package/dist/commands/list-directories-command.d.ts.map +1 -1
  60. package/dist/commands/list-directories-command.js +1 -14
  61. package/dist/commands/list-tools-command.d.ts.map +1 -1
  62. package/dist/commands/list-tools-command.js +55 -78
  63. package/dist/commands/manager.d.ts +1 -8
  64. package/dist/commands/manager.d.ts.map +1 -1
  65. package/dist/commands/manager.js +7 -42
  66. package/dist/commands/model-command.d.ts +0 -22
  67. package/dist/commands/model-command.d.ts.map +1 -1
  68. package/dist/commands/model-command.js +5 -126
  69. package/dist/commands/paste-command.d.ts +1 -1
  70. package/dist/commands/paste-command.d.ts.map +1 -1
  71. package/dist/commands/paste-command.js +1 -79
  72. package/dist/commands/pickup-command.d.ts.map +1 -1
  73. package/dist/commands/pickup-command.js +3 -55
  74. package/dist/commands/prompt-command.d.ts +19 -1
  75. package/dist/commands/prompt-command.d.ts.map +1 -1
  76. package/dist/commands/prompt-command.js +172 -194
  77. package/dist/commands/remove-directory-command.d.ts +1 -1
  78. package/dist/commands/remove-directory-command.d.ts.map +1 -1
  79. package/dist/commands/remove-directory-command.js +1 -33
  80. package/dist/commands/reset-command.d.ts +1 -1
  81. package/dist/commands/reset-command.d.ts.map +1 -1
  82. package/dist/commands/reset-command.js +3 -11
  83. package/dist/commands/rules-command.d.ts +1 -1
  84. package/dist/commands/rules-command.d.ts.map +1 -1
  85. package/dist/commands/rules-command.js +1 -63
  86. package/dist/commands/save-command.d.ts +1 -1
  87. package/dist/commands/save-command.d.ts.map +1 -1
  88. package/dist/commands/save-command.js +1 -8
  89. package/dist/commands/shell-command.d.ts.map +1 -1
  90. package/dist/commands/shell-command.js +1 -48
  91. package/dist/commands/types.d.ts +0 -3
  92. package/dist/commands/types.d.ts.map +1 -1
  93. package/dist/commands/usage-command.d.ts +1 -1
  94. package/dist/commands/usage-command.d.ts.map +1 -1
  95. package/dist/commands/usage-command.js +5 -16
  96. package/dist/config.d.ts +17 -6
  97. package/dist/config.d.ts.map +1 -1
  98. package/dist/config.js +86 -53
  99. package/dist/execution/index.d.ts +17 -2
  100. package/dist/execution/index.d.ts.map +1 -1
  101. package/dist/execution/index.js +62 -20
  102. package/dist/formatting.d.ts +19 -0
  103. package/dist/formatting.d.ts.map +1 -1
  104. package/dist/formatting.js +54 -0
  105. package/dist/index.d.ts +1 -1
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +212 -153
  108. package/dist/messages.d.ts +3 -0
  109. package/dist/messages.d.ts.map +1 -1
  110. package/dist/messages.js +67 -3
  111. package/dist/models/anthropic-provider.d.ts.map +1 -1
  112. package/dist/models/anthropic-provider.js +0 -7
  113. package/dist/models/deepseek-provider.d.ts.map +1 -1
  114. package/dist/models/deepseek-provider.js +0 -2
  115. package/dist/models/google-provider.d.ts.map +1 -1
  116. package/dist/models/google-provider.js +0 -3
  117. package/dist/models/groq-provider.d.ts.map +1 -1
  118. package/dist/models/groq-provider.js +0 -1
  119. package/dist/models/openai-provider.d.ts.map +1 -1
  120. package/dist/models/openai-provider.js +0 -4
  121. package/dist/models/openrouter-provider.d.ts +10 -9
  122. package/dist/models/openrouter-provider.d.ts.map +1 -1
  123. package/dist/models/openrouter-provider.js +82 -88
  124. package/dist/models/providers.d.ts +4 -14
  125. package/dist/models/providers.d.ts.map +1 -1
  126. package/dist/models/providers.js +1 -57
  127. package/dist/models/xai-provider.d.ts.map +1 -1
  128. package/dist/models/xai-provider.js +0 -2
  129. package/dist/prompts.d.ts +9 -4
  130. package/dist/prompts.d.ts.map +1 -1
  131. package/dist/prompts.js +427 -99
  132. package/dist/repl/project-status-line.d.ts +1 -0
  133. package/dist/repl/project-status-line.d.ts.map +1 -1
  134. package/dist/repl/project-status-line.js +57 -27
  135. package/dist/repl-new.d.ts +0 -2
  136. package/dist/repl-new.d.ts.map +1 -1
  137. package/dist/repl-new.js +34 -54
  138. package/dist/skills.d.ts +20 -0
  139. package/dist/skills.d.ts.map +1 -0
  140. package/dist/skills.js +192 -0
  141. package/dist/terminal/control.d.ts +55 -0
  142. package/dist/terminal/control.d.ts.map +1 -0
  143. package/dist/terminal/control.js +109 -0
  144. package/dist/terminal/default-theme.d.ts +1 -1
  145. package/dist/terminal/default-theme.d.ts.map +1 -1
  146. package/dist/terminal/default-theme.js +24 -28
  147. package/dist/terminal/formatting.d.ts +23 -25
  148. package/dist/terminal/formatting.d.ts.map +1 -1
  149. package/dist/terminal/formatting.js +35 -52
  150. package/dist/terminal/highlight/index.d.ts.map +1 -1
  151. package/dist/terminal/highlight/index.js +3 -6
  152. package/dist/terminal/highlight/theme.d.ts.map +1 -1
  153. package/dist/terminal/highlight/theme.js +2 -6
  154. package/dist/terminal/index.d.ts +2 -101
  155. package/dist/terminal/index.d.ts.map +1 -1
  156. package/dist/terminal/index.js +2 -464
  157. package/dist/terminal/markdown.js +7 -5
  158. package/dist/terminal/strip-ansi.js +4 -4
  159. package/dist/terminal/table/cell.d.ts +114 -0
  160. package/dist/terminal/table/cell.d.ts.map +1 -0
  161. package/dist/terminal/table/cell.js +407 -0
  162. package/dist/terminal/table/debug.d.ts +15 -0
  163. package/dist/terminal/table/debug.d.ts.map +1 -0
  164. package/dist/terminal/table/debug.js +32 -0
  165. package/dist/terminal/table/index.d.ts +3 -0
  166. package/dist/terminal/table/index.d.ts.map +1 -0
  167. package/dist/terminal/table/index.js +2 -0
  168. package/dist/terminal/table/layout-manager.d.ts +27 -0
  169. package/dist/terminal/table/layout-manager.d.ts.map +1 -0
  170. package/dist/terminal/table/layout-manager.js +257 -0
  171. package/dist/terminal/table/table.d.ts +9 -0
  172. package/dist/terminal/table/table.d.ts.map +1 -0
  173. package/dist/terminal/table/table.js +97 -0
  174. package/dist/terminal/table/utils.d.ts +63 -0
  175. package/dist/terminal/table/utils.d.ts.map +1 -0
  176. package/dist/terminal/table/utils.js +326 -0
  177. package/dist/tokens/threshold.d.ts +6 -21
  178. package/dist/tokens/threshold.d.ts.map +1 -1
  179. package/dist/tokens/threshold.js +13 -31
  180. package/dist/tools/advanced-edit-file.d.ts.map +1 -1
  181. package/dist/tools/advanced-edit-file.js +5 -1
  182. package/dist/tools/agent.d.ts.map +1 -1
  183. package/dist/tools/agent.js +19 -5
  184. package/dist/tools/bash.d.ts +3 -1
  185. package/dist/tools/bash.d.ts.map +1 -1
  186. package/dist/tools/bash.js +204 -42
  187. package/dist/tools/batch.d.ts +34 -0
  188. package/dist/tools/batch.d.ts.map +1 -0
  189. package/dist/tools/batch.js +174 -0
  190. package/dist/tools/code-interpreter.d.ts.map +1 -1
  191. package/dist/tools/code-interpreter.js +25 -9
  192. package/dist/tools/delete-file.d.ts.map +1 -1
  193. package/dist/tools/delete-file.js +9 -2
  194. package/dist/tools/directory-tree.d.ts +0 -6
  195. package/dist/tools/directory-tree.d.ts.map +1 -1
  196. package/dist/tools/directory-tree.js +29 -18
  197. package/dist/tools/dynamic-tool-loader.d.ts +0 -4
  198. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  199. package/dist/tools/dynamic-tool-loader.js +2 -2
  200. package/dist/tools/edit-file.d.ts.map +1 -1
  201. package/dist/tools/edit-file.js +16 -3
  202. package/dist/tools/glob.d.ts.map +1 -1
  203. package/dist/tools/glob.js +24 -13
  204. package/dist/tools/grep.d.ts.map +1 -1
  205. package/dist/tools/grep.js +40 -25
  206. package/dist/tools/index.d.ts +17 -3
  207. package/dist/tools/index.d.ts.map +1 -1
  208. package/dist/tools/index.js +43 -1
  209. package/dist/tools/llm-edit-fixer.d.ts +0 -1
  210. package/dist/tools/llm-edit-fixer.d.ts.map +1 -1
  211. package/dist/tools/llm-edit-fixer.js +14 -28
  212. package/dist/tools/move-file.d.ts.map +1 -1
  213. package/dist/tools/move-file.js +8 -1
  214. package/dist/tools/read-file.d.ts.map +1 -1
  215. package/dist/tools/read-file.js +32 -23
  216. package/dist/tools/read-multiple-files.d.ts.map +1 -1
  217. package/dist/tools/read-multiple-files.js +102 -45
  218. package/dist/tools/save-file.d.ts +4 -4
  219. package/dist/tools/save-file.d.ts.map +1 -1
  220. package/dist/tools/save-file.js +20 -2
  221. package/dist/tools/think.d.ts.map +1 -1
  222. package/dist/tools/think.js +7 -1
  223. package/dist/tools/types.d.ts +5 -1
  224. package/dist/tools/types.d.ts.map +1 -1
  225. package/dist/tools/web-fetch.js +1 -1
  226. package/dist/tools/web-search.d.ts.map +1 -1
  227. package/dist/tools/web-search.js +24 -9
  228. package/dist/tui/components/assistant-message.js +1 -1
  229. package/dist/tui/components/box.d.ts +20 -0
  230. package/dist/tui/components/box.d.ts.map +1 -0
  231. package/dist/tui/components/box.js +81 -0
  232. package/dist/tui/components/editor.d.ts +60 -5
  233. package/dist/tui/components/editor.d.ts.map +1 -1
  234. package/dist/tui/components/editor.js +577 -115
  235. package/dist/tui/components/footer.d.ts +0 -12
  236. package/dist/tui/components/footer.d.ts.map +1 -1
  237. package/dist/tui/components/footer.js +19 -7
  238. package/dist/tui/components/header.d.ts +21 -0
  239. package/dist/tui/components/header.d.ts.map +1 -0
  240. package/dist/tui/components/header.js +63 -0
  241. package/dist/tui/components/loader.d.ts +5 -1
  242. package/dist/tui/components/loader.d.ts.map +1 -1
  243. package/dist/tui/components/loader.js +2 -2
  244. package/dist/tui/components/markdown.d.ts +26 -23
  245. package/dist/tui/components/markdown.d.ts.map +1 -1
  246. package/dist/tui/components/markdown.js +107 -54
  247. package/dist/tui/components/modal.d.ts +0 -11
  248. package/dist/tui/components/modal.d.ts.map +1 -1
  249. package/dist/tui/components/modal.js +0 -29
  250. package/dist/tui/components/progress-bar.d.ts +19 -0
  251. package/dist/tui/components/progress-bar.d.ts.map +1 -0
  252. package/dist/tui/components/progress-bar.js +78 -0
  253. package/dist/tui/components/prompt-status.d.ts +2 -1
  254. package/dist/tui/components/prompt-status.d.ts.map +1 -1
  255. package/dist/tui/components/prompt-status.js +7 -2
  256. package/dist/tui/components/select-list.d.ts +27 -1
  257. package/dist/tui/components/select-list.d.ts.map +1 -1
  258. package/dist/tui/components/select-list.js +93 -29
  259. package/dist/tui/components/spacer.d.ts +1 -1
  260. package/dist/tui/components/spacer.d.ts.map +1 -1
  261. package/dist/tui/components/spacer.js +2 -2
  262. package/dist/tui/components/table.d.ts +27 -0
  263. package/dist/tui/components/table.d.ts.map +1 -0
  264. package/dist/tui/components/table.js +125 -0
  265. package/dist/tui/components/thinking-block.d.ts.map +1 -1
  266. package/dist/tui/components/thinking-block.js +4 -1
  267. package/dist/tui/components/tool-execution.d.ts +8 -4
  268. package/dist/tui/components/tool-execution.d.ts.map +1 -1
  269. package/dist/tui/components/tool-execution.js +88 -80
  270. package/dist/tui/components/user-message.d.ts.map +1 -1
  271. package/dist/tui/components/user-message.js +6 -4
  272. package/dist/tui/index.d.ts +9 -5
  273. package/dist/tui/index.d.ts.map +1 -1
  274. package/dist/tui/index.js +5 -1
  275. package/dist/tui/terminal.d.ts +2 -1
  276. package/dist/tui/terminal.d.ts.map +1 -1
  277. package/dist/tui/terminal.js +28 -38
  278. package/dist/tui/tui.d.ts +2 -0
  279. package/dist/tui/tui.d.ts.map +1 -1
  280. package/dist/tui/tui.js +53 -33
  281. package/dist/tui/utils.d.ts +5 -0
  282. package/dist/tui/utils.d.ts.map +1 -1
  283. package/dist/tui/utils.js +81 -1
  284. package/dist/{tools/bash-utils.d.ts → utils/bash.d.ts} +3 -3
  285. package/dist/utils/bash.d.ts.map +1 -0
  286. package/dist/{tools/bash-utils.js → utils/bash.js} +22 -11
  287. package/dist/utils/{filesystem.d.ts → filesystem/operations.d.ts} +1 -1
  288. package/dist/utils/filesystem/operations.d.ts.map +1 -0
  289. package/dist/{tools/filesystem-utils.d.ts → utils/filesystem/security.d.ts} +3 -2
  290. package/dist/utils/filesystem/security.d.ts.map +1 -0
  291. package/dist/{tools/filesystem-utils.js → utils/filesystem/security.js} +62 -4
  292. package/dist/utils/funcs.d.ts +6 -0
  293. package/dist/utils/funcs.d.ts.map +1 -0
  294. package/dist/utils/funcs.js +6 -0
  295. package/dist/{tools/git-utils.d.ts → utils/git.d.ts} +1 -1
  296. package/dist/utils/git.d.ts.map +1 -0
  297. package/dist/{tools/git-utils.js → utils/git.js} +0 -6
  298. package/dist/utils/glob.js +1 -1
  299. package/dist/utils/{zod-utils.d.ts → zod.d.ts} +1 -1
  300. package/dist/utils/zod.d.ts.map +1 -0
  301. package/package.json +17 -17
  302. package/dist/agent/manual-loop.d.ts +0 -41
  303. package/dist/agent/manual-loop.d.ts.map +0 -1
  304. package/dist/agent/manual-loop.js +0 -278
  305. package/dist/repl/display-tool-messages.d.ts +0 -4
  306. package/dist/repl/display-tool-messages.d.ts.map +0 -1
  307. package/dist/repl/display-tool-messages.js +0 -58
  308. package/dist/repl/display-tool-use.d.ts +0 -14
  309. package/dist/repl/display-tool-use.d.ts.map +0 -1
  310. package/dist/repl/display-tool-use.js +0 -63
  311. package/dist/repl/get-prompt-header.d.ts +0 -8
  312. package/dist/repl/get-prompt-header.d.ts.map +0 -1
  313. package/dist/repl/get-prompt-header.js +0 -9
  314. package/dist/repl/prompt.d.ts +0 -21
  315. package/dist/repl/prompt.d.ts.map +0 -1
  316. package/dist/repl/prompt.js +0 -244
  317. package/dist/repl.d.ts +0 -29
  318. package/dist/repl.d.ts.map +0 -1
  319. package/dist/repl.js +0 -218
  320. package/dist/terminal/checkbox-prompt.d.ts +0 -36
  321. package/dist/terminal/checkbox-prompt.d.ts.map +0 -1
  322. package/dist/terminal/checkbox-prompt.js +0 -368
  323. package/dist/terminal/editor-prompt.d.ts +0 -10
  324. package/dist/terminal/editor-prompt.d.ts.map +0 -1
  325. package/dist/terminal/editor-prompt.js +0 -61
  326. package/dist/terminal/errors.d.ts +0 -19
  327. package/dist/terminal/errors.d.ts.map +0 -1
  328. package/dist/terminal/errors.js +0 -37
  329. package/dist/terminal/input-prompt.d.ts +0 -17
  330. package/dist/terminal/input-prompt.d.ts.map +0 -1
  331. package/dist/terminal/input-prompt.js +0 -181
  332. package/dist/terminal/search-prompt.d.ts +0 -20
  333. package/dist/terminal/search-prompt.d.ts.map +0 -1
  334. package/dist/terminal/search-prompt.js +0 -280
  335. package/dist/terminal/types.d.ts +0 -35
  336. package/dist/terminal/types.d.ts.map +0 -1
  337. package/dist/terminal/types.js +0 -1
  338. package/dist/tools/bash-utils.d.ts.map +0 -1
  339. package/dist/tools/filesystem-utils.d.ts.map +0 -1
  340. package/dist/tools/git-utils.d.ts.map +0 -1
  341. package/dist/utils/filesystem.d.ts.map +0 -1
  342. package/dist/utils/zod-utils.d.ts.map +0 -1
  343. /package/dist/utils/{filesystem.js → filesystem/operations.js} +0 -0
  344. /package/dist/utils/{zod-utils.js → zod.js} +0 -0
@@ -2,8 +2,8 @@ import fs from "node:fs/promises";
2
2
  import { isNumber } from "@travisennis/stdlib/typeguards";
3
3
  import { z } from "zod";
4
4
  import style from "../terminal/style.js";
5
- import { manageTokenLimit } from "../tokens/threshold.js";
6
- import { joinWorkingDir, validatePath } from "./filesystem-utils.js";
5
+ import { manageTokenLimit, TokenLimitExceededError, } from "../tokens/threshold.js";
6
+ import { joinWorkingDir, validatePath } from "../utils/filesystem/security.js";
7
7
  import { fileEncodingSchema } from "./types.js";
8
8
  export const ReadFileTool = {
9
9
  name: "readFile",
@@ -14,20 +14,17 @@ const inputSchema = z.object({
14
14
  startLine: z.coerce
15
15
  .number()
16
16
  .nullable()
17
- .describe("1-based line number to start reading from. Pass null to start at beginning of file"),
17
+ .describe("1-based line number to start reading from. Required but nullable. Pass null to start at beginning of file"),
18
18
  lineCount: z.coerce
19
19
  .number()
20
20
  .nullable()
21
- .describe("Maximum number of lines to read. Pass null to get all lines."),
21
+ .describe("Maximum number of lines to read. Required but nullable. Pass null to get all lines."),
22
22
  });
23
23
  export const createReadFileTool = async ({ workingDir, allowedDirs, tokenCounter, }) => {
24
24
  const allowedDirectory = allowedDirs ?? [workingDir];
25
25
  return {
26
26
  toolDef: {
27
- description: "Read the complete contents of a file from the file system unless startLine and lineCount are given to read a file selection. " +
28
- "Handles various text encodings and provides detailed error messages " +
29
- "if the file cannot be read. Use this tool when you need to examine " +
30
- "the contents of a single file. Only works within allowed directories.",
27
+ description: "Read the complete contents of a file from the file system unless startLine and lineCount are given to read a file selection. Handles various text encodings and provides detailed error messages if the file cannot be read. Use this tool when you need to examine the contents of a single file. Only works within allowed directories.",
31
28
  inputSchema,
32
29
  },
33
30
  async *execute({ path: providedPath, encoding, startLine, lineCount, }, { toolCallId, abortSignal }) {
@@ -67,21 +64,33 @@ export const createReadFileTool = async ({ workingDir, allowedDirs, tokenCounter
67
64
  const endIndex = Math.min(startIndex + count, totalLines);
68
65
  file = lines.slice(startIndex, endIndex).join("\n");
69
66
  }
70
- const result = await manageTokenLimit(file, tokenCounter, "ReadFile", isNumber(startLine) || isNumber(lineCount)
71
- ? "Consider adjusting startLine/lineCount or using grepFiles"
72
- : "Use startLine and lineCount parameters to read specific portions, or use grepFiles for targeted access", encoding);
73
- // Calculate line count for the returned content
74
- const linesRead = result.content.split("\n").length;
75
- yield {
76
- name: ReadFileTool.name,
77
- id: toolCallId,
78
- event: "tool-completion",
79
- // Include success, line count, and token count
80
- data: !result.truncated
81
- ? `Read ${linesRead} lines (${result.tokenCount} tokens)`
82
- : result.content,
83
- };
84
- yield result.content;
67
+ try {
68
+ const result = await manageTokenLimit(file, tokenCounter, "ReadFile", isNumber(startLine) || isNumber(lineCount)
69
+ ? "Consider adjusting startLine/lineCount or using grepFiles"
70
+ : "Use startLine and lineCount parameters to read specific portions, or use grepFiles for targeted access", encoding);
71
+ // Calculate line count for the returned content
72
+ const linesRead = result.content.split("\n").length;
73
+ yield {
74
+ name: ReadFileTool.name,
75
+ id: toolCallId,
76
+ event: "tool-completion",
77
+ data: `Read ${linesRead} lines (${result.tokenCount} tokens)`,
78
+ };
79
+ yield result.content;
80
+ }
81
+ catch (error) {
82
+ if (error instanceof TokenLimitExceededError) {
83
+ yield {
84
+ name: ReadFileTool.name,
85
+ event: "tool-error",
86
+ id: toolCallId,
87
+ data: error.message,
88
+ };
89
+ yield error.message;
90
+ return;
91
+ }
92
+ throw error;
93
+ }
85
94
  }
86
95
  catch (error) {
87
96
  const errorMsg = `${error.message}`;
@@ -1 +1 @@
1
- {"version":3,"file":"read-multiple-files.d.ts","sourceRoot":"","sources":["../../source/tools/read-multiple-files.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,qBAAqB;;CAEjC,CAAC;AAEF,QAAA,MAAM,WAAW;;iBAEf,CAAC;AAEH,KAAK,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhE,eAAO,MAAM,2BAA2B,GAAU,4CAI/C;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;CAC5B;;;;;;;uBAcgB,4BAA4B,+BACV,eAAe,GAC3C,cAAc,CAAC,UAAU,CAAC;EAwIhC,CAAC"}
1
+ {"version":3,"file":"read-multiple-files.d.ts","sourceRoot":"","sources":["../../source/tools/read-multiple-files.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAMzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,qBAAqB;;CAEjC,CAAC;AAEF,QAAA,MAAM,WAAW;;iBAEf,CAAC;AAEH,KAAK,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhE,eAAO,MAAM,2BAA2B,GAAU,4CAI/C;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;CAC5B;;;;;;;uBAcgB,4BAA4B,+BACV,eAAe,GAC3C,cAAc,CAAC,UAAU,CAAC;EAsMhC,CAAC"}
@@ -2,8 +2,8 @@ import { readFile } from "node:fs/promises";
2
2
  import { z } from "zod";
3
3
  import { formatFile } from "../formatting.js";
4
4
  import style from "../terminal/style.js";
5
- import { manageTokenLimit } from "../tokens/threshold.js";
6
- import { joinWorkingDir, validatePath } from "./filesystem-utils.js";
5
+ import { manageTokenLimit, TokenLimitExceededError, } from "../tokens/threshold.js";
6
+ import { joinWorkingDir, validatePath } from "../utils/filesystem/security.js";
7
7
  export const ReadMultipleFilesTool = {
8
8
  name: "readMultipleFiles",
9
9
  };
@@ -54,56 +54,113 @@ export const createReadMultipleFilesTool = async ({ workingDir, allowedDirs, tok
54
54
  };
55
55
  }
56
56
  // Apply token limit check to each file
57
- const managedResult = await manageTokenLimit(result.content ?? "", tokenCounter, "ReadMultipleFiles", "Use readFile with startLine/lineCount or grepFiles for targeted access");
58
- return {
59
- path: result.path,
60
- content: formatFile(result.path, managedResult.content, "markdown"),
61
- tokenCount: managedResult.tokenCount,
62
- error: null,
63
- truncated: managedResult.truncated,
64
- };
57
+ try {
58
+ const managedResult = await manageTokenLimit(result.content ?? "", tokenCounter, "ReadMultipleFiles", "Use readFile with startLine/lineCount or grepFiles for targeted access");
59
+ return {
60
+ path: result.path,
61
+ content: formatFile(result.path, managedResult.content, "markdown"),
62
+ tokenCount: managedResult.tokenCount,
63
+ error: null,
64
+ exceededLimit: false,
65
+ };
66
+ }
67
+ catch (error) {
68
+ if (error instanceof TokenLimitExceededError) {
69
+ return {
70
+ path: result.path,
71
+ content: error.message,
72
+ tokenCount: 0,
73
+ error: null,
74
+ exceededLimit: true,
75
+ };
76
+ }
77
+ throw error;
78
+ }
65
79
  }));
66
80
  const formattedResults = processedResults.map((r) => r.content);
67
- const finalResult = await manageTokenLimit(formattedResults.join("\n---\n"), tokenCounter, "ReadMultipleFiles", "Reduce number of files or use more specific paths");
68
- // Aggregate results with detailed breakdown
69
- let totalTokens = 0;
70
- let filesReadCount = 0;
71
- let filesExceededLimitCount = 0;
72
- let filesErrorCount = 0;
73
- for (const processedResult of processedResults) {
74
- if (processedResult.error) {
75
- filesErrorCount++;
81
+ try {
82
+ const finalResult = await manageTokenLimit(formattedResults.join("\n---\n"), tokenCounter, "ReadMultipleFiles", "Reduce number of files or use more specific paths");
83
+ // Aggregate results with detailed breakdown
84
+ let totalTokens = 0;
85
+ let filesReadCount = 0;
86
+ let filesExceededLimitCount = 0;
87
+ let filesErrorCount = 0;
88
+ for (const processedResult of processedResults) {
89
+ if (processedResult.error) {
90
+ filesErrorCount++;
91
+ }
92
+ else if (processedResult.exceededLimit) {
93
+ filesExceededLimitCount++;
94
+ totalTokens += processedResult.tokenCount;
95
+ }
96
+ else {
97
+ filesReadCount++;
98
+ totalTokens += processedResult.tokenCount;
99
+ }
76
100
  }
77
- else if (processedResult.truncated) {
78
- filesExceededLimitCount++;
79
- totalTokens += processedResult.tokenCount;
101
+ const parts = [];
102
+ if (filesReadCount > 0) {
103
+ parts.push(`Read ${filesReadCount} files successfully (${totalTokens} total tokens)`);
80
104
  }
81
- else {
82
- filesReadCount++;
83
- totalTokens += processedResult.tokenCount;
105
+ if (filesExceededLimitCount > 0) {
106
+ parts.push(`${filesExceededLimitCount} files exceeded token limit`);
84
107
  }
108
+ if (filesErrorCount > 0) {
109
+ parts.push(`${filesErrorCount} files could not be read`);
110
+ }
111
+ // Note: If we reach here, finalResult succeeded (no TokenLimitExceededError thrown)
112
+ const completionMessage = `${parts.join(", ")}.`;
113
+ yield {
114
+ name: ReadMultipleFilesTool.name,
115
+ id: toolCallId,
116
+ event: "tool-completion",
117
+ data: completionMessage,
118
+ };
119
+ yield finalResult.content;
85
120
  }
86
- const parts = [];
87
- if (filesReadCount > 0) {
88
- parts.push(`Read ${filesReadCount} files successfully (${totalTokens} total tokens)`);
89
- }
90
- if (filesExceededLimitCount > 0) {
91
- parts.push(`${filesExceededLimitCount} files exceeded token limit`);
92
- }
93
- if (filesErrorCount > 0) {
94
- parts.push(`${filesErrorCount} files could not be read`);
95
- }
96
- if (finalResult.truncated) {
97
- parts.push(`Combined output exceeded token limit. ${finalResult.content}`);
121
+ catch (error) {
122
+ if (error instanceof TokenLimitExceededError) {
123
+ // Combined output exceeded limit
124
+ const parts = [];
125
+ let totalTokens = 0;
126
+ let filesReadCount = 0;
127
+ let filesExceededLimitCount = 0;
128
+ let filesErrorCount = 0;
129
+ for (const processedResult of processedResults) {
130
+ if (processedResult.error) {
131
+ filesErrorCount++;
132
+ }
133
+ else if (processedResult.exceededLimit) {
134
+ filesExceededLimitCount++;
135
+ totalTokens += processedResult.tokenCount;
136
+ }
137
+ else {
138
+ filesReadCount++;
139
+ totalTokens += processedResult.tokenCount;
140
+ }
141
+ }
142
+ if (filesReadCount > 0) {
143
+ parts.push(`Read ${filesReadCount} files successfully (${totalTokens} total tokens)`);
144
+ }
145
+ if (filesExceededLimitCount > 0) {
146
+ parts.push(`${filesExceededLimitCount} files exceeded token limit`);
147
+ }
148
+ if (filesErrorCount > 0) {
149
+ parts.push(`${filesErrorCount} files could not be read`);
150
+ }
151
+ parts.push(`Combined output exceeded token limit. ${error.message}`);
152
+ const completionMessage = `${parts.join(", ")}.`;
153
+ yield {
154
+ name: ReadMultipleFilesTool.name,
155
+ event: "tool-error",
156
+ id: toolCallId,
157
+ data: completionMessage,
158
+ };
159
+ yield error.message;
160
+ return;
161
+ }
162
+ throw error;
98
163
  }
99
- const completionMessage = `${parts.join(", ")}.`;
100
- yield {
101
- name: ReadMultipleFilesTool.name,
102
- id: toolCallId,
103
- event: "tool-completion",
104
- data: completionMessage,
105
- };
106
- yield finalResult.content;
107
164
  }
108
165
  catch (error) {
109
166
  const errorMsg = error.message;
@@ -7,7 +7,7 @@ export declare const SaveFileTool: {
7
7
  declare const inputSchema: z.ZodObject<{
8
8
  path: z.ZodString;
9
9
  content: z.ZodString;
10
- encoding: z.ZodEnum<{
10
+ encoding: z.ZodDefault<z.ZodEnum<{
11
11
  utf8: "utf8";
12
12
  ascii: "ascii";
13
13
  "utf-8": "utf-8";
@@ -19,7 +19,7 @@ declare const inputSchema: z.ZodObject<{
19
19
  latin1: "latin1";
20
20
  binary: "binary";
21
21
  hex: "hex";
22
- }>;
22
+ }>>;
23
23
  }, z.core.$strip>;
24
24
  type SaveFileInputSchema = z.infer<typeof inputSchema>;
25
25
  export declare const createSaveFileTool: ({ workingDir, allowedDirs, }: {
@@ -31,7 +31,7 @@ export declare const createSaveFileTool: ({ workingDir, allowedDirs, }: {
31
31
  inputSchema: z.ZodObject<{
32
32
  path: z.ZodString;
33
33
  content: z.ZodString;
34
- encoding: z.ZodEnum<{
34
+ encoding: z.ZodDefault<z.ZodEnum<{
35
35
  utf8: "utf8";
36
36
  ascii: "ascii";
37
37
  "utf-8": "utf-8";
@@ -43,7 +43,7 @@ export declare const createSaveFileTool: ({ workingDir, allowedDirs, }: {
43
43
  latin1: "latin1";
44
44
  binary: "binary";
45
45
  hex: "hex";
46
- }>;
46
+ }>>;
47
47
  }, z.core.$strip>;
48
48
  };
49
49
  execute({ path: userPath, content, encoding }: SaveFileInputSchema, { toolCallId, abortSignal }: ToolCallOptions): AsyncGenerator<ToolResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"save-file.d.ts","sourceRoot":"","sources":["../../source/tools/save-file.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAEjE,eAAO,MAAM,YAAY;;CAExB,CAAC;AAEF,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;iBAMf,CAAC;AAEH,KAAK,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEvD,eAAO,MAAM,kBAAkB,GAAU,8BAGtC;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;;;;;;;;;;;;;;;;;;;;;mDAa4C,mBAAmB,+BAC7B,eAAe,GAC3C,cAAc,CAAC,UAAU,CAAC;EAuEhC,CAAC"}
1
+ {"version":3,"file":"save-file.d.ts","sourceRoot":"","sources":["../../source/tools/save-file.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAEjE,eAAO,MAAM,YAAY;;CAExB,CAAC;AAEF,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;iBAQf,CAAC;AAEH,KAAK,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEvD,eAAO,MAAM,kBAAkB,GAAU,8BAGtC;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;;;;;;;;;;;;;;;;;;;;;mDAa4C,mBAAmB,+BAC7B,eAAe,GAC3C,cAAc,CAAC,UAAU,CAAC;EAuFhC,CAAC"}
@@ -1,8 +1,10 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { z } from "zod";
4
+ import { config } from "../config.js";
5
+ import { clearProjectStatusCache } from "../repl/project-status-line.js";
4
6
  import style from "../terminal/style.js";
5
- import { joinWorkingDir, validatePath } from "./filesystem-utils.js";
7
+ import { joinWorkingDir, validateFileNotReadOnly, validatePath, } from "../utils/filesystem/security.js";
6
8
  import { fileEncodingSchema } from "./types.js";
7
9
  export const SaveFileTool = {
8
10
  name: "saveFile",
@@ -10,7 +12,9 @@ export const SaveFileTool = {
10
12
  const inputSchema = z.object({
11
13
  path: z.string().describe("Absolute path to file to save to"),
12
14
  content: z.string().describe("Content to save in the file"),
13
- encoding: fileEncodingSchema.describe('Encoding format for saving the file. Use "utf-8" as default for text files'),
15
+ encoding: fileEncodingSchema
16
+ .describe('Encoding format for saving the file. Use "utf-8" as default for text files')
17
+ .default("utf-8"),
14
18
  });
15
19
  export const createSaveFileTool = async ({ workingDir, allowedDirs, }) => {
16
20
  const allowedDirectory = allowedDirs ?? [workingDir];
@@ -34,6 +38,18 @@ export const createSaveFileTool = async ({ workingDir, allowedDirs, }) => {
34
38
  data: `${style.cyan(userPath)}`,
35
39
  };
36
40
  const filePath = await validatePath(joinWorkingDir(userPath, workingDir), allowedDirectory, { requireExistence: false, abortSignal });
41
+ // Check if file is read-only (only if it exists)
42
+ try {
43
+ await fs.stat(filePath);
44
+ const projectConfig = await config.getConfig();
45
+ validateFileNotReadOnly(filePath, projectConfig, workingDir);
46
+ }
47
+ catch (error) {
48
+ // File doesn't exist, so it's not read-only
49
+ if (error.code !== "ENOENT") {
50
+ throw error;
51
+ }
52
+ }
37
53
  // Check if path exists and is a directory
38
54
  try {
39
55
  const stat = await fs.stat(filePath);
@@ -67,6 +83,8 @@ export const createSaveFileTool = async ({ workingDir, allowedDirs, }) => {
67
83
  id: toolCallId,
68
84
  data: `Saved ${lines} lines, ${bytes} bytes`,
69
85
  };
86
+ // Clear project status cache since file operations change git status
87
+ clearProjectStatusCache();
70
88
  yield `File saved successfully: ${filePath}`;
71
89
  }
72
90
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"think.d.ts","sourceRoot":"","sources":["../../source/tools/think.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,SAAS;;CAErB,CAAC;AAWF,QAAA,MAAM,WAAW;;iBAEf,CAAC;AAGH,eAAO,MAAM,eAAe;;;;;;;yBAOT,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,+BACX,eAAe,GAC3C,cAAc,CAAC,UAAU,CAAC;CAqChC,CAAC"}
1
+ {"version":3,"file":"think.d.ts","sourceRoot":"","sources":["../../source/tools/think.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,SAAS;;CAErB,CAAC;AAWF,QAAA,MAAM,WAAW;;iBAEf,CAAC;AAGH,eAAO,MAAM,eAAe;;;;;;;yBAOT,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,+BACX,eAAe,GAC3C,cAAc,CAAC,UAAU,CAAC;CA4ChC,CAAC"}
@@ -32,7 +32,13 @@ export const createThinkTool = () => {
32
32
  name: ThinkTool.name,
33
33
  event: "tool-init",
34
34
  id: toolCallId,
35
- data: `\n${formattedThought}`,
35
+ data: "Logging thought",
36
+ };
37
+ yield {
38
+ name: ThinkTool.name,
39
+ event: "tool-update",
40
+ id: toolCallId,
41
+ data: `${formattedThought}`,
36
42
  };
37
43
  yield {
38
44
  name: ThinkTool.name,
@@ -21,6 +21,10 @@ interface ToolInitMessage extends BaseMessage {
21
21
  event: "tool-init";
22
22
  data: string;
23
23
  }
24
+ interface ToolUpdateMessage extends BaseMessage {
25
+ event: "tool-update";
26
+ data: string;
27
+ }
24
28
  interface ToolErrorMessage extends BaseMessage {
25
29
  event: "tool-error";
26
30
  data: string;
@@ -29,7 +33,7 @@ interface ToolCompletionMessage extends BaseMessage {
29
33
  event: "tool-completion";
30
34
  data: string;
31
35
  }
32
- export type Message = ToolInitMessage | ToolErrorMessage | ToolCompletionMessage;
36
+ type Message = ToolInitMessage | ToolUpdateMessage | ToolErrorMessage | ToolCompletionMessage;
33
37
  export type ToolResult = Message | string;
34
38
  export declare function isToolMessage(value: unknown): value is Message;
35
39
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;EAY7B,CAAC;AAEH,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,eAAgB,SAAQ,WAAW;IAC3C,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,gBAAiB,SAAQ,WAAW;IAC5C,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,qBAAsB,SAAQ,WAAW;IACjD,KAAK,EAAE,iBAAiB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,OAAO,GACf,eAAe,GACf,gBAAgB,GAChB,qBAAqB,CAAC;AAE1B,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1C,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAc9D"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;EAY7B,CAAC;AAEH,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,eAAgB,SAAQ,WAAW;IAC3C,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,iBAAkB,SAAQ,WAAW;IAC7C,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,gBAAiB,SAAQ,WAAW;IAC5C,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,qBAAsB,SAAQ,WAAW;IACjD,KAAK,EAAE,iBAAiB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,KAAK,OAAO,GACR,eAAe,GACf,iBAAiB,GACjB,gBAAgB,GAChB,qBAAqB,CAAC;AAE1B,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1C,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAc9D"}
@@ -22,7 +22,7 @@ export const createWebFetchTool = (options) => {
22
22
  id: toolCallId,
23
23
  data: `${style.cyan(url)}`,
24
24
  };
25
- logger.info(`Initiating fetch for URL: ${url}`);
25
+ logger.info(`${style.cyan(url)}`);
26
26
  const result = await readUrl(url, abortSignal);
27
27
  const urlContent = result.data;
28
28
  const tokenCount = options.tokenCounter.count(urlContent);
@@ -1 +1 @@
1
- {"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../source/tools/web-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAE1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAEF,QAAA,MAAM,WAAW;;iBAEf,CAAC;AAEH,eAAO,MAAM,mBAAmB,GAAI,mBAEjC;IACD,YAAY,EAAE,YAAY,CAAC;CAC5B;;;;;;;yBAQc,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,+BACT,eAAe,KAC3C,cAAc,CAAC,UAAU,CAAC;CA0D9B,CAAC"}
1
+ {"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../source/tools/web-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAE1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAKzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAEF,QAAA,MAAM,WAAW;;iBAEf,CAAC;AAEH,eAAO,MAAM,mBAAmB,GAAI,mBAEjC;IACD,YAAY,EAAE,YAAY,CAAC;CAC5B;;;;;;;yBAQc,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,+BACT,eAAe,KAC3C,cAAc,CAAC,UAAU,CAAC;CAwE9B,CAAC"}
@@ -2,7 +2,7 @@ import { SafeSearchType, search } from "duck-duck-scrape";
2
2
  import { z } from "zod";
3
3
  import Exa from "../api/exa/index.js";
4
4
  import style from "../terminal/style.js";
5
- import { manageTokenLimit } from "../tokens/threshold.js";
5
+ import { manageTokenLimit, TokenLimitExceededError, } from "../tokens/threshold.js";
6
6
  export const WebSearchTool = {
7
7
  name: "webSearch",
8
8
  };
@@ -32,14 +32,29 @@ export const createWebSearchTool = ({ tokenCounter, }) => {
32
32
  const result = await performSearch(query, abortSignal);
33
33
  const sources = result.results.map((source) => `## ${source.title}\nURL: ${source.url}\n\n${source.text}`);
34
34
  const resultText = `# Search Results:\n\n${sources.join("\n\n")}`;
35
- const searchResult = await manageTokenLimit(resultText, tokenCounter, "WebSearch", "Use more specific search queries or reduce number of results");
36
- yield {
37
- name: WebSearchTool.name,
38
- event: "tool-completion",
39
- id: toolCallId,
40
- data: `Found ${result.results.length} results (${searchResult.tokenCount} tokens)`,
41
- };
42
- yield searchResult.content;
35
+ try {
36
+ const searchResult = await manageTokenLimit(resultText, tokenCounter, "WebSearch", "Use more specific search queries or reduce number of results");
37
+ yield {
38
+ name: WebSearchTool.name,
39
+ event: "tool-completion",
40
+ id: toolCallId,
41
+ data: `Found ${result.results.length} results (${searchResult.tokenCount} tokens)`,
42
+ };
43
+ yield searchResult.content;
44
+ }
45
+ catch (error) {
46
+ if (error instanceof TokenLimitExceededError) {
47
+ yield {
48
+ name: WebSearchTool.name,
49
+ event: "tool-error",
50
+ id: toolCallId,
51
+ data: error.message,
52
+ };
53
+ yield error.message;
54
+ return;
55
+ }
56
+ throw error;
57
+ }
43
58
  }
44
59
  catch (error) {
45
60
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -24,6 +24,6 @@ export class AssistantMessageComponent extends Container {
24
24
  const content = message.content;
25
25
  // Assistant text messages with no background - trim the text
26
26
  // Set paddingY=0 to avoid extra spacing before tool executions
27
- this.contentContainer.addChild(new Markdown(content.trim(), undefined, undefined, undefined, 1, 0));
27
+ this.contentContainer.addChild(new Markdown(content.trim(), { paddingX: 1, paddingY: 0 }));
28
28
  }
29
29
  }
@@ -0,0 +1,20 @@
1
+ import type { Component } from "../tui.ts";
2
+ /**
3
+ * Box component - displays content in a bordered box with header
4
+ */
5
+ export declare class BoxComponent implements Component {
6
+ private header;
7
+ private content;
8
+ private width;
9
+ private cachedOutput?;
10
+ private cachedHeader?;
11
+ private cachedContent?;
12
+ private cachedWidth?;
13
+ constructor(header: string, content: string, width?: number);
14
+ setHeader(header: string): void;
15
+ setContent(content: string): void;
16
+ setWidth(width: number): void;
17
+ private invalidateCache;
18
+ render(width: number): string[];
19
+ }
20
+ //# sourceMappingURL=box.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"box.d.ts","sourceRoot":"","sources":["../../../source/tui/components/box.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C;;GAEG;AACH,qBAAa,YAAa,YAAW,SAAS;IAC5C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IAGtB,OAAO,CAAC,YAAY,CAAC,CAAW;IAChC,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,WAAW,CAAC,CAAS;gBAEjB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAM3D,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK/B,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKjC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7B,OAAO,CAAC,eAAe;IAOvB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAuDhC"}
@@ -0,0 +1,81 @@
1
+ import { getTerminalSize } from "../../terminal/control.js";
2
+ import { applyMarkdown } from "../../terminal/markdown.js";
3
+ import stripAnsi from "../../terminal/strip-ansi.js";
4
+ import wrapAnsi from "../../terminal/wrap-ansi.js";
5
+ /**
6
+ * Box component - displays content in a bordered box with header
7
+ */
8
+ export class BoxComponent {
9
+ header;
10
+ content;
11
+ width;
12
+ // Cache for rendered output
13
+ cachedOutput;
14
+ cachedHeader;
15
+ cachedContent;
16
+ cachedWidth;
17
+ constructor(header, content, width) {
18
+ this.header = header;
19
+ this.content = content;
20
+ this.width = width || 0;
21
+ }
22
+ setHeader(header) {
23
+ this.header = header;
24
+ this.invalidateCache();
25
+ }
26
+ setContent(content) {
27
+ this.content = content;
28
+ this.invalidateCache();
29
+ }
30
+ setWidth(width) {
31
+ this.width = width;
32
+ this.invalidateCache();
33
+ }
34
+ invalidateCache() {
35
+ this.cachedOutput = undefined;
36
+ this.cachedHeader = undefined;
37
+ this.cachedContent = undefined;
38
+ this.cachedWidth = undefined;
39
+ }
40
+ render(width) {
41
+ // Use provided width if specified, otherwise use component width or terminal size
42
+ let renderWidth = width || this.width;
43
+ if (renderWidth === 0) {
44
+ const { columns } = getTerminalSize();
45
+ const cols = columns > 0 ? columns : 80;
46
+ renderWidth = Math.max(4, cols - 4);
47
+ }
48
+ // Check cache
49
+ if (this.cachedOutput &&
50
+ this.cachedHeader === this.header &&
51
+ this.cachedContent === this.content &&
52
+ this.cachedWidth === renderWidth) {
53
+ return this.cachedOutput;
54
+ }
55
+ const paddedHeader = ` ${this.header} `;
56
+ const headerVisibleLen = stripAnsi(paddedHeader).length;
57
+ const headerStartPos = 1;
58
+ // Top border with header (use visible header length)
59
+ const leftDashes = headerStartPos;
60
+ const rightDashes = Math.max(0, renderWidth - leftDashes - headerVisibleLen);
61
+ const topBorder = `┌${"─".repeat(leftDashes)}${paddedHeader}${"─".repeat(rightDashes)}┐`;
62
+ // Prepare inner content: format markdown first, then wrap to inner width
63
+ const innerWidth = Math.max(1, renderWidth - 2);
64
+ const formatted = applyMarkdown(this.content);
65
+ const wrapped = wrapAnsi(formatted, innerWidth, { trim: false });
66
+ const contentLines = wrapped.split("\n").map((line) => {
67
+ const visibleLen = stripAnsi(line).length;
68
+ const padCount = Math.max(0, innerWidth - visibleLen);
69
+ return `│ ${line}${" ".repeat(padCount)} │`;
70
+ });
71
+ // Bottom border
72
+ const bottomBorder = `└${"─".repeat(renderWidth)}┘`;
73
+ const result = [topBorder, ...contentLines, bottomBorder];
74
+ // Update cache
75
+ this.cachedOutput = result;
76
+ this.cachedHeader = this.header;
77
+ this.cachedContent = this.content;
78
+ this.cachedWidth = renderWidth;
79
+ return result;
80
+ }
81
+ }