@travisennis/acai 0.0.1 → 0.0.2

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 (323) hide show
  1. package/README.md +3 -4
  2. package/dist/commands/health-command.d.ts +2 -0
  3. package/dist/commands/health-command.js +59 -0
  4. package/dist/commands/manager.js +2 -0
  5. package/dist/commands/paste-command.d.ts +1 -1
  6. package/dist/commands/paste-command.js +155 -11
  7. package/dist/commands/reset-command.js +1 -0
  8. package/dist/index.js +1 -1
  9. package/dist/models/openrouter-provider.d.ts +4 -1
  10. package/dist/models/openrouter-provider.js +46 -4
  11. package/dist/models/providers.d.ts +1 -1
  12. package/dist/prompts/manager.d.ts +1 -0
  13. package/dist/prompts/manager.js +10 -0
  14. package/dist/prompts.js +8 -6
  15. package/dist/repl.js +49 -26
  16. package/dist/terminal/formatting.d.ts +16 -5
  17. package/dist/terminal/formatting.js +40 -6
  18. package/dist/terminal/index.d.ts +1 -1
  19. package/dist/terminal/index.js +54 -14
  20. package/dist/terminal/markdown.js +0 -1
  21. package/dist/terminal/supports-color.d.ts +16 -0
  22. package/dist/terminal/supports-color.js +121 -0
  23. package/dist/terminal/supports-hyperlinks.d.ts +7 -0
  24. package/dist/terminal/supports-hyperlinks.js +98 -0
  25. package/dist/tools/bash.js +95 -117
  26. package/dist/tools/code-interpreter.js +11 -1
  27. package/dist/tools/command-validation.d.ts +7 -3
  28. package/dist/tools/command-validation.js +67 -23
  29. package/dist/tools/delete-file.d.ts +4 -1
  30. package/dist/tools/delete-file.js +47 -3
  31. package/dist/tools/git-utils.d.ts +6 -0
  32. package/dist/tools/git-utils.js +89 -12
  33. package/dist/tools/grep.d.ts +20 -0
  34. package/dist/tools/grep.js +128 -40
  35. package/dist/tools/index.d.ts +2 -18
  36. package/dist/tools/index.js +4 -18
  37. package/package.json +30 -20
  38. package/.acai/acai.json +0 -9
  39. package/.acai/prompts/add-openrouter-model.md +0 -13
  40. package/.acai/prompts/project-status.md +0 -4
  41. package/.acai/prompts/update-architecture-document.md +0 -9
  42. package/.acai/rules/learned-rules.md +0 -9
  43. package/.ai/docs/available-tools.txt +0 -3
  44. package/.ai/docs/cognitive_complexity_refactoring_progress.md +0 -65
  45. package/.ai/docs/deleted_tools.md +0 -168
  46. package/.ai/docs/deleted_tools_88ced9ef.md +0 -56
  47. package/.ai/docs/image-pasting.md +0 -46
  48. package/.ai/docs/initialize-app.md +0 -117
  49. package/.ai/docs/issue-4-plan.md +0 -44
  50. package/.ai/docs/marked-renderer-debug.md +0 -15
  51. package/.ai/docs/marked-renderer-refactor-plan.md +0 -64
  52. package/.ai/docs/memory-use-cases.md +0 -55
  53. package/.ai/docs/prompt-consistency.md +0 -31
  54. package/.ai/docs/refactoring-tools.md +0 -98
  55. package/.ai/docs/system-prompt-update.md +0 -174
  56. package/.ai/docs/system_prompt.txt +0 -210
  57. package/.ai/docs/tasks.md +0 -49
  58. package/.ai/plan.md +0 -131
  59. package/.ai/prompt.md +0 -1
  60. package/.ai/scripts/fetch_models.js +0 -27
  61. package/.ai/scripts/generateSystemPrompt.ts +0 -15
  62. package/.ai/scripts/list-tools.mjs +0 -4
  63. package/.ai/scripts/p5_geometric_shapes.js +0 -149
  64. package/.husky/commit-msg +0 -1
  65. package/.husky/pre-commit +0 -3
  66. package/.husky/pre-push +0 -1
  67. package/.ignore +0 -4
  68. package/AGENTS.md +0 -25
  69. package/ARCHITECTURE.md +0 -304
  70. package/TODO.md +0 -2
  71. package/biome.json +0 -61
  72. package/commitlint.config.js +0 -3
  73. package/dist/source/cli.d.ts +0 -19
  74. package/dist/source/cli.js +0 -116
  75. package/dist/source/commands/application-log-command.d.ts +0 -2
  76. package/dist/source/commands/application-log-command.js +0 -43
  77. package/dist/source/commands/clear-command.d.ts +0 -2
  78. package/dist/source/commands/clear-command.js +0 -12
  79. package/dist/source/commands/compact-command.d.ts +0 -2
  80. package/dist/source/commands/compact-command.js +0 -51
  81. package/dist/source/commands/copy-command.d.ts +0 -2
  82. package/dist/source/commands/copy-command.js +0 -51
  83. package/dist/source/commands/edit-command.d.ts +0 -2
  84. package/dist/source/commands/edit-command.js +0 -53
  85. package/dist/source/commands/edit-prompt-command.d.ts +0 -2
  86. package/dist/source/commands/edit-prompt-command.js +0 -25
  87. package/dist/source/commands/exit-command.d.ts +0 -2
  88. package/dist/source/commands/exit-command.js +0 -14
  89. package/dist/source/commands/files-command.d.ts +0 -2
  90. package/dist/source/commands/files-command.js +0 -63
  91. package/dist/source/commands/generate-rules-command.d.ts +0 -2
  92. package/dist/source/commands/generate-rules-command.js +0 -61
  93. package/dist/source/commands/help-command.d.ts +0 -2
  94. package/dist/source/commands/help-command.js +0 -19
  95. package/dist/source/commands/init-command.d.ts +0 -2
  96. package/dist/source/commands/init-command.js +0 -40
  97. package/dist/source/commands/last-log-command.d.ts +0 -2
  98. package/dist/source/commands/last-log-command.js +0 -76
  99. package/dist/source/commands/manager.d.ts +0 -22
  100. package/dist/source/commands/manager.js +0 -123
  101. package/dist/source/commands/model-command.d.ts +0 -2
  102. package/dist/source/commands/model-command.js +0 -84
  103. package/dist/source/commands/paste-command.d.ts +0 -2
  104. package/dist/source/commands/paste-command.js +0 -40
  105. package/dist/source/commands/prompt-command.d.ts +0 -2
  106. package/dist/source/commands/prompt-command.js +0 -111
  107. package/dist/source/commands/reset-command.d.ts +0 -2
  108. package/dist/source/commands/reset-command.js +0 -16
  109. package/dist/source/commands/rules-command.d.ts +0 -2
  110. package/dist/source/commands/rules-command.js +0 -68
  111. package/dist/source/commands/save-command.d.ts +0 -2
  112. package/dist/source/commands/save-command.js +0 -14
  113. package/dist/source/commands/types.d.ts +0 -26
  114. package/dist/source/commands/types.js +0 -1
  115. package/dist/source/commands/usage-command.d.ts +0 -2
  116. package/dist/source/commands/usage-command.js +0 -21
  117. package/dist/source/config.d.ts +0 -60
  118. package/dist/source/config.js +0 -193
  119. package/dist/source/conversation-analyzer.d.ts +0 -10
  120. package/dist/source/conversation-analyzer.js +0 -88
  121. package/dist/source/dedent.d.ts +0 -3
  122. package/dist/source/dedent.js +0 -38
  123. package/dist/source/formatting.d.ts +0 -17
  124. package/dist/source/formatting.js +0 -103
  125. package/dist/source/index.d.ts +0 -18
  126. package/dist/source/index.js +0 -213
  127. package/dist/source/logger.d.ts +0 -2
  128. package/dist/source/logger.js +0 -24
  129. package/dist/source/mentions.d.ts +0 -9
  130. package/dist/source/mentions.js +0 -182
  131. package/dist/source/messages.d.ts +0 -69
  132. package/dist/source/messages.js +0 -261
  133. package/dist/source/middleware/audit-message.d.ts +0 -5
  134. package/dist/source/middleware/audit-message.js +0 -95
  135. package/dist/source/middleware/index.d.ts +0 -2
  136. package/dist/source/middleware/index.js +0 -2
  137. package/dist/source/middleware/rate-limit.d.ts +0 -4
  138. package/dist/source/middleware/rate-limit.js +0 -17
  139. package/dist/source/models/ai-config.d.ts +0 -12
  140. package/dist/source/models/ai-config.js +0 -87
  141. package/dist/source/models/anthropic-provider.d.ts +0 -25
  142. package/dist/source/models/anthropic-provider.js +0 -184
  143. package/dist/source/models/deepseek-provider.d.ts +0 -20
  144. package/dist/source/models/deepseek-provider.js +0 -42
  145. package/dist/source/models/google-provider.d.ts +0 -19
  146. package/dist/source/models/google-provider.js +0 -56
  147. package/dist/source/models/manager.d.ts +0 -15
  148. package/dist/source/models/manager.js +0 -48
  149. package/dist/source/models/openai-provider.d.ts +0 -22
  150. package/dist/source/models/openai-provider.js +0 -70
  151. package/dist/source/models/openrouter-provider.d.ts +0 -36
  152. package/dist/source/models/openrouter-provider.js +0 -276
  153. package/dist/source/models/providers.d.ts +0 -33
  154. package/dist/source/models/providers.js +0 -116
  155. package/dist/source/models/xai-provider.d.ts +0 -20
  156. package/dist/source/models/xai-provider.js +0 -47
  157. package/dist/source/parsing.d.ts +0 -2
  158. package/dist/source/parsing.js +0 -18
  159. package/dist/source/prompts/manager.d.ts +0 -19
  160. package/dist/source/prompts/manager.js +0 -71
  161. package/dist/source/prompts.d.ts +0 -4
  162. package/dist/source/prompts.js +0 -158
  163. package/dist/source/repl-prompt.d.ts +0 -14
  164. package/dist/source/repl-prompt.js +0 -147
  165. package/dist/source/repl.d.ts +0 -27
  166. package/dist/source/repl.js +0 -431
  167. package/dist/source/terminal/formatting.d.ts +0 -37
  168. package/dist/source/terminal/formatting.js +0 -106
  169. package/dist/source/terminal/index.d.ts +0 -94
  170. package/dist/source/terminal/index.js +0 -420
  171. package/dist/source/terminal/markdown-utils.d.ts +0 -2
  172. package/dist/source/terminal/markdown-utils.js +0 -81
  173. package/dist/source/terminal/markdown.d.ts +0 -1
  174. package/dist/source/terminal/markdown.js +0 -111
  175. package/dist/source/terminal/types.d.ts +0 -71
  176. package/dist/source/terminal/types.js +0 -1
  177. package/dist/source/terminal-output.d.ts +0 -8
  178. package/dist/source/terminal-output.js +0 -213
  179. package/dist/source/terminal-output.test.d.ts +0 -8
  180. package/dist/source/terminal-output.test.js +0 -213
  181. package/dist/source/token-tracker.d.ts +0 -14
  182. package/dist/source/token-tracker.js +0 -53
  183. package/dist/source/token-utils.d.ts +0 -7
  184. package/dist/source/token-utils.js +0 -13
  185. package/dist/source/tools/agent.d.ts +0 -17
  186. package/dist/source/tools/agent.js +0 -87
  187. package/dist/source/tools/bash.d.ts +0 -19
  188. package/dist/source/tools/bash.js +0 -294
  189. package/dist/source/tools/code-interpreter.d.ts +0 -12
  190. package/dist/source/tools/code-interpreter.js +0 -131
  191. package/dist/source/tools/command-validation.d.ts +0 -8
  192. package/dist/source/tools/command-validation.js +0 -69
  193. package/dist/source/tools/delete-file.d.ts +0 -12
  194. package/dist/source/tools/delete-file.js +0 -56
  195. package/dist/source/tools/directory-tree.d.ts +0 -12
  196. package/dist/source/tools/directory-tree.js +0 -38
  197. package/dist/source/tools/edit-file.d.ts +0 -19
  198. package/dist/source/tools/edit-file.js +0 -107
  199. package/dist/source/tools/filesystem-utils.d.ts +0 -22
  200. package/dist/source/tools/filesystem-utils.js +0 -191
  201. package/dist/source/tools/git-utils.d.ts +0 -14
  202. package/dist/source/tools/git-utils.js +0 -64
  203. package/dist/source/tools/grep.d.ts +0 -17
  204. package/dist/source/tools/grep.js +0 -138
  205. package/dist/source/tools/index.d.ts +0 -161
  206. package/dist/source/tools/index.js +0 -209
  207. package/dist/source/tools/memory-read.d.ts +0 -13
  208. package/dist/source/tools/memory-read.js +0 -135
  209. package/dist/source/tools/memory-write.d.ts +0 -12
  210. package/dist/source/tools/memory-write.js +0 -83
  211. package/dist/source/tools/move-file.d.ts +0 -13
  212. package/dist/source/tools/move-file.js +0 -44
  213. package/dist/source/tools/read-file.d.ts +0 -17
  214. package/dist/source/tools/read-file.js +0 -86
  215. package/dist/source/tools/read-multiple-files.d.ts +0 -14
  216. package/dist/source/tools/read-multiple-files.js +0 -55
  217. package/dist/source/tools/save-file.d.ts +0 -17
  218. package/dist/source/tools/save-file.js +0 -98
  219. package/dist/source/tools/think.d.ts +0 -11
  220. package/dist/source/tools/think.js +0 -45
  221. package/dist/source/tools/types.d.ts +0 -29
  222. package/dist/source/tools/types.js +0 -14
  223. package/dist/source/tools/web-fetch.d.ts +0 -47
  224. package/dist/source/tools/web-fetch.js +0 -246
  225. package/dist/source/tools/web-search.d.ts +0 -13
  226. package/dist/source/tools/web-search.js +0 -80
  227. package/dist/source/utils/process.d.ts +0 -36
  228. package/dist/source/utils/process.js +0 -75
  229. package/dist/source/version.d.ts +0 -1
  230. package/dist/source/version.js +0 -21
  231. package/dist/terminal-output.d.ts +0 -8
  232. package/dist/terminal-output.js +0 -213
  233. package/dist/tools/memory-read.d.ts +0 -13
  234. package/dist/tools/memory-read.js +0 -135
  235. package/dist/tools/memory-write.d.ts +0 -12
  236. package/dist/tools/memory-write.js +0 -83
  237. package/knip.json +0 -5
  238. package/source/cli.ts +0 -172
  239. package/source/commands/application-log-command.ts +0 -53
  240. package/source/commands/clear-command.ts +0 -14
  241. package/source/commands/compact-command.ts +0 -64
  242. package/source/commands/copy-command.ts +0 -55
  243. package/source/commands/edit-command.ts +0 -63
  244. package/source/commands/edit-prompt-command.ts +0 -31
  245. package/source/commands/exit-command.ts +0 -18
  246. package/source/commands/files-command.ts +0 -85
  247. package/source/commands/generate-rules-command.ts +0 -82
  248. package/source/commands/help-command.ts +0 -27
  249. package/source/commands/init-command.ts +0 -48
  250. package/source/commands/last-log-command.ts +0 -88
  251. package/source/commands/manager.ts +0 -151
  252. package/source/commands/model-command.ts +0 -123
  253. package/source/commands/paste-command.ts +0 -62
  254. package/source/commands/prompt-command.ts +0 -150
  255. package/source/commands/reset-command.ts +0 -22
  256. package/source/commands/rules-command.ts +0 -76
  257. package/source/commands/save-command.ts +0 -20
  258. package/source/commands/types.ts +0 -28
  259. package/source/commands/usage-command.ts +0 -26
  260. package/source/config.ts +0 -223
  261. package/source/conversation-analyzer.ts +0 -115
  262. package/source/dedent.ts +0 -53
  263. package/source/formatting.ts +0 -132
  264. package/source/index.ts +0 -240
  265. package/source/logger.ts +0 -29
  266. package/source/mentions.ts +0 -227
  267. package/source/messages.ts +0 -360
  268. package/source/middleware/audit-message.ts +0 -133
  269. package/source/middleware/index.ts +0 -2
  270. package/source/middleware/rate-limit.ts +0 -24
  271. package/source/models/ai-config.ts +0 -109
  272. package/source/models/anthropic-provider.ts +0 -199
  273. package/source/models/deepseek-provider.ts +0 -53
  274. package/source/models/google-provider.ts +0 -68
  275. package/source/models/manager.ts +0 -84
  276. package/source/models/openai-provider.ts +0 -81
  277. package/source/models/openrouter-provider.ts +0 -288
  278. package/source/models/providers.ts +0 -197
  279. package/source/models/xai-provider.ts +0 -59
  280. package/source/parsing.ts +0 -20
  281. package/source/prompts/manager.ts +0 -90
  282. package/source/prompts.ts +0 -172
  283. package/source/repl-prompt.ts +0 -196
  284. package/source/repl.ts +0 -572
  285. package/source/terminal/formatting.ts +0 -121
  286. package/source/terminal/index.ts +0 -518
  287. package/source/terminal/markdown-utils.ts +0 -89
  288. package/source/terminal/markdown.ts +0 -155
  289. package/source/terminal/types.ts +0 -84
  290. package/source/terminal-output.test.ts +0 -266
  291. package/source/token-tracker.ts +0 -78
  292. package/source/token-utils.ts +0 -17
  293. package/source/tools/agent.ts +0 -107
  294. package/source/tools/bash.ts +0 -367
  295. package/source/tools/code-interpreter.ts +0 -172
  296. package/source/tools/command-validation.ts +0 -81
  297. package/source/tools/delete-file.ts +0 -71
  298. package/source/tools/directory-tree.ts +0 -54
  299. package/source/tools/edit-file.ts +0 -155
  300. package/source/tools/filesystem-utils.ts +0 -265
  301. package/source/tools/git-utils.ts +0 -70
  302. package/source/tools/grep.ts +0 -184
  303. package/source/tools/index.ts +0 -278
  304. package/source/tools/memory-read.ts +0 -174
  305. package/source/tools/memory-write.ts +0 -105
  306. package/source/tools/move-file.ts +0 -59
  307. package/source/tools/read-file.ts +0 -129
  308. package/source/tools/read-multiple-files.ts +0 -80
  309. package/source/tools/save-file.ts +0 -147
  310. package/source/tools/think.ts +0 -51
  311. package/source/tools/types.ts +0 -58
  312. package/source/tools/web-fetch.ts +0 -327
  313. package/source/tools/web-search.ts +0 -101
  314. package/source/utils/process.ts +0 -121
  315. package/source/version.ts +0 -21
  316. package/test/commands/copy-command.test.ts +0 -69
  317. package/test/config.test.ts +0 -200
  318. package/test/terminal/markdown-utils.test.ts +0 -124
  319. package/test/tools/bash-tool.test.ts +0 -58
  320. package/test/tools/code-interpreter.test.ts +0 -91
  321. package/test/tools/command-validation.test.ts +0 -48
  322. package/tsconfig.build.json +0 -9
  323. package/tsconfig.json +0 -30
@@ -1,294 +0,0 @@
1
- import path from "node:path";
2
- import { input, select } from "@inquirer/prompts";
3
- import { tool } from "ai";
4
- import chalk from "chalk";
5
- import { z } from "zod";
6
- import { config } from "../config.js";
7
- import { executeCommand } from "../utils/process.js";
8
- import { CommandValidation } from "./command-validation.js";
9
- export const BashTool = {
10
- name: "bash",
11
- };
12
- function tokenize(inputStr) {
13
- const tokens = [];
14
- let current = "";
15
- let inSingle = false;
16
- let inDouble = false;
17
- for (let i = 0; i < inputStr.length; i++) {
18
- const ch = inputStr[i];
19
- if (ch === "'" && !inDouble) {
20
- inSingle = !inSingle;
21
- current += ch;
22
- continue;
23
- }
24
- if (ch === '"' && !inSingle) {
25
- inDouble = !inDouble;
26
- current += ch;
27
- continue;
28
- }
29
- if (!inSingle && !inDouble && /\s/.test(ch)) {
30
- if (current.length > 0) {
31
- const raw = current;
32
- const unquoted = raw.replace(/^['"]|['"]$/g, "");
33
- tokens.push({ raw, unquoted });
34
- current = "";
35
- }
36
- continue;
37
- }
38
- if (ch === "\\" && inDouble && i + 1 < inputStr.length) {
39
- const next = inputStr[i + 1];
40
- if (next === '"' || next === "\\") {
41
- current += next;
42
- i++;
43
- continue;
44
- }
45
- }
46
- current += ch;
47
- }
48
- if (current.length > 0) {
49
- const raw = current;
50
- const unquoted = raw.replace(/^['"]|['"]$/g, "");
51
- tokens.push({ raw, unquoted });
52
- }
53
- return tokens;
54
- }
55
- function shouldSkipPathValidation(tokens, index) {
56
- if (index === 0)
57
- return false;
58
- const cmd = tokens[0]?.unquoted;
59
- if (cmd !== "git")
60
- return false;
61
- const sub = tokens[1]?.unquoted;
62
- if (sub !== "commit" &&
63
- sub !== "tag" &&
64
- !(sub === "notes" && tokens[2]?.unquoted === "add")) {
65
- return false;
66
- }
67
- const prev = tokens[index - 1]?.unquoted;
68
- if (prev === "-m" || prev === "--message")
69
- return true;
70
- return false;
71
- }
72
- function looksLikeUrl(str) {
73
- return str.startsWith("http://") || str.startsWith("https://");
74
- }
75
- // Whitelist of allowed commands
76
- const ALLOWED_COMMANDS = [
77
- "chmod",
78
- "ls",
79
- "pwd",
80
- "cat",
81
- "grep",
82
- "find",
83
- "echo",
84
- "mkdir",
85
- "touch",
86
- "cp",
87
- "mv",
88
- "pwd",
89
- "wc",
90
- "diff",
91
- "sort",
92
- "head",
93
- "tail",
94
- "sleep",
95
- "npm",
96
- "npx",
97
- "node",
98
- "git",
99
- "gh",
100
- "rg",
101
- "jq",
102
- "sed",
103
- "awk",
104
- ];
105
- // Command execution timeout in milliseconds
106
- const DEFAULT_TIMEOUT = 1.5 * 60 * 1000; // 1.5 minutes
107
- // Initialize command validator with allowed commands
108
- const commandValidator = new CommandValidation(ALLOWED_COMMANDS);
109
- // Ensure path is within base directory
110
- function isPathWithinBaseDir(requestedPath, baseDir) {
111
- const normalizedRequestedPath = path.normalize(requestedPath);
112
- const normalizedBaseDir = path.normalize(baseDir);
113
- return normalizedRequestedPath.startsWith(normalizedBaseDir);
114
- }
115
- export const createBashTool = ({ baseDir, sendData, tokenCounter, terminal, autoAcceptAll, }) => {
116
- let autoAcceptCommands = autoAcceptAll;
117
- return {
118
- [BashTool.name]: tool({
119
- description: `Execute bash commands and return their output. Limited to a whitelist of safe commands: ${ALLOWED_COMMANDS.join(", ")}. Commands will only execute within the project directory for security. Always specify absolute paths to avoid errors.`,
120
- inputSchema: z.object({
121
- command: z
122
- .string()
123
- .describe("Full CLI command to execute. Must be from the allowed list without chaining operators."),
124
- cwd: z
125
- .string()
126
- .nullable()
127
- .describe("Working directory (default: project root). Must be within the project directory."),
128
- timeout: z
129
- .number()
130
- .nullable()
131
- .describe(`Command execution timeout in milliseconds. Default: ${DEFAULT_TIMEOUT}ms`),
132
- }),
133
- execute: async ({ command, cwd, timeout }, { toolCallId }) => {
134
- // Guard against null cwd and timeout
135
- const safeCwd = cwd == null ? baseDir : cwd;
136
- const safeTimeout = timeout == null ? DEFAULT_TIMEOUT : timeout;
137
- sendData?.({
138
- event: "tool-init",
139
- id: toolCallId,
140
- data: `Executing: ${chalk.cyan(command)} in ${chalk.cyan(safeCwd)}`,
141
- });
142
- // Validate command using CommandValidation
143
- if (!commandValidator.isValid(command)) {
144
- const errorMsg = `Command not allowed. Ensure all sub-commands are in the approved list: ${ALLOWED_COMMANDS.join(", ")} and no unsafe operators (>, <, \`, $()) are used.`;
145
- sendData?.({ event: "tool-error", id: toolCallId, data: errorMsg });
146
- return errorMsg;
147
- }
148
- // Validate working directory
149
- if (!isPathWithinBaseDir(safeCwd, baseDir)) {
150
- const errorMsg = `Working directory must be within the project directory: ${baseDir}`;
151
- sendData?.({ event: "tool-error", id: toolCallId, data: errorMsg });
152
- return errorMsg;
153
- }
154
- // Validate command arguments for paths outside baseDir
155
- const tokens = tokenize(command);
156
- for (let i = 0; i < tokens.length; i++) {
157
- const token = tokens[i];
158
- if (token == null)
159
- continue;
160
- const part = token.unquoted;
161
- if (shouldSkipPathValidation(tokens, i)) {
162
- continue;
163
- }
164
- if (looksLikeUrl(part)) {
165
- continue;
166
- }
167
- if (part.startsWith("/") ||
168
- part.includes("../") ||
169
- part.includes("./") ||
170
- (part.includes("/") && !part.startsWith("-"))) {
171
- try {
172
- const resolvedPath = path.resolve(safeCwd, part);
173
- if (!isPathWithinBaseDir(resolvedPath, baseDir)) {
174
- const errorMsg = `Command argument references path outside the project directory: ${part} (resolved to ${resolvedPath})`;
175
- sendData?.({
176
- event: "tool-error",
177
- id: toolCallId,
178
- data: errorMsg,
179
- });
180
- return errorMsg;
181
- }
182
- }
183
- catch (e) {
184
- console.info(`Could not resolve potential path argument: ${part}`, e);
185
- }
186
- }
187
- }
188
- // Prompt user for command execution approval (only in interactive mode)
189
- if (terminal) {
190
- if (!autoAcceptCommands) {
191
- await new Promise((resolve) => setTimeout(resolve, 1000));
192
- }
193
- terminal.lineBreak();
194
- terminal.writeln(`${chalk.blue.bold("●")} About to execute command: ${chalk.cyan(command)}`);
195
- terminal.writeln(`${chalk.gray("Working directory:")} ${safeCwd}`);
196
- terminal.lineBreak();
197
- let userChoice;
198
- if (autoAcceptCommands) {
199
- terminal.writeln(chalk.green("✓ Auto-accepting command (all future commands will be accepted)"));
200
- userChoice = "accept";
201
- }
202
- else {
203
- userChoice = await select({
204
- message: "What would you like to do with this command?",
205
- choices: [
206
- { name: "Execute this command", value: "accept" },
207
- {
208
- name: "Execute all future commands (including this)",
209
- value: "accept-all",
210
- },
211
- { name: "Reject this command", value: "reject" },
212
- ],
213
- default: "accept",
214
- });
215
- }
216
- terminal.lineBreak();
217
- if (userChoice === "accept-all") {
218
- autoAcceptCommands = true;
219
- terminal.writeln(chalk.yellow("✓ Auto-accept mode enabled for all future commands"));
220
- terminal.lineBreak();
221
- }
222
- if (userChoice === "reject") {
223
- const reason = await input({ message: "Feedback: " });
224
- terminal.lineBreak();
225
- const rejectionMsg = `Command rejected by user. Reason: ${reason}`;
226
- sendData?.({
227
- event: "tool-completion",
228
- id: toolCallId,
229
- data: rejectionMsg,
230
- });
231
- return rejectionMsg;
232
- }
233
- }
234
- try {
235
- const result = await executeCommand(command, {
236
- cwd: safeCwd,
237
- timeout: safeTimeout,
238
- shell: true,
239
- throwOnError: false,
240
- });
241
- if (result.signal === "SIGTERM") {
242
- const timeoutMessage = `Command timed out after ${safeTimeout}ms. This might be because the command is waiting for input.`;
243
- sendData?.({
244
- event: "tool-error",
245
- id: toolCallId,
246
- data: timeoutMessage,
247
- });
248
- return timeoutMessage;
249
- }
250
- const formattedResult = format(result);
251
- sendData?.({
252
- event: "tool-update",
253
- id: toolCallId,
254
- data: {
255
- primary: "Result",
256
- secondary: formattedResult.split("\n").slice(-5),
257
- },
258
- });
259
- let tokenCount = 0;
260
- try {
261
- tokenCount = tokenCounter.count(formattedResult);
262
- }
263
- catch (tokenError) {
264
- console.error("Error calculating token count:", tokenError);
265
- // Log or handle error, but don't block file return
266
- }
267
- const maxTokens = (await config.readProjectConfig()).tools.maxTokens;
268
- // Adjust max token check message if line selection was used
269
- const maxTokenMessage = `Output of commmand (${tokenCount} tokens) exceeds maximum allowed tokens (${maxTokens}). Please adjust how you call the command to get back more specific results`;
270
- const finalResult = tokenCount <= maxTokens ? formattedResult : maxTokenMessage;
271
- sendData?.({
272
- event: "tool-completion",
273
- id: toolCallId,
274
- data: tokenCount <= maxTokens
275
- ? "Command executed successfully."
276
- : `Output of commmand (${tokenCount} tokens) exceeds maximum allowed tokens (${maxTokens}).`,
277
- });
278
- return finalResult;
279
- }
280
- catch (error) {
281
- sendData?.({
282
- event: "tool-error",
283
- id: toolCallId,
284
- data: `Command failed: ${error.message}`,
285
- });
286
- return `Command failed: ${error.message}`;
287
- }
288
- },
289
- }),
290
- };
291
- };
292
- function format({ stdout, stderr, }) {
293
- return `${stdout}\n${stderr}`;
294
- }
@@ -1,12 +0,0 @@
1
- import type { SendData } from "./types.ts";
2
- export declare const CodeInterpreterTool: {
3
- name: "codeInterpreter";
4
- };
5
- export declare const createCodeInterpreterTool: ({ sendData, }: Readonly<{
6
- sendData?: SendData | undefined;
7
- }>) => {
8
- codeInterpreter: import("ai").Tool<{
9
- code: string;
10
- timeoutSeconds: number | null;
11
- }, string>;
12
- };
@@ -1,131 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { randomUUID } from "node:crypto";
3
- import { mkdir, rm, writeFile } from "node:fs/promises";
4
- import { join } from "node:path";
5
- import process from "node:process";
6
- import { tool } from "ai";
7
- import { z } from "zod";
8
- export const CodeInterpreterTool = {
9
- name: "codeInterpreter",
10
- };
11
- export const createCodeInterpreterTool = ({ sendData, }) => {
12
- return {
13
- [CodeInterpreterTool.name]: tool({
14
- description: "Executes JavaScript code in a separate Node.js process using Node's Permission Model. By default, the child process has no permissions except read/write within the current working directory. The tool returns stdout, stderr, and exitCode. Use console.log/console.error to produce output. Timeout defaults to 5 seconds and can be extended up to 60 seconds.",
15
- inputSchema: z.object({
16
- code: z.string().describe("JavaScript code to be executed."),
17
- timeoutSeconds: z
18
- .number()
19
- .int()
20
- .min(1)
21
- .max(60)
22
- .nullable()
23
- .describe("Execution timeout in seconds (1-60). Default 5."),
24
- }),
25
- execute: async ({ code, timeoutSeconds }, { toolCallId }) => {
26
- const workingDirectory = process.cwd();
27
- try {
28
- sendData?.({
29
- event: "tool-init",
30
- id: toolCallId,
31
- data: "Initializing code interpreter environment",
32
- });
33
- sendData?.({
34
- event: "tool-update",
35
- id: toolCallId,
36
- data: {
37
- primary: "Executing...",
38
- secondary: [
39
- `${"`".repeat(3)} javascript\n${code.slice(0, 500)}${"`".repeat(3)}`,
40
- ],
41
- },
42
- });
43
- if (code.trim().length === 0) {
44
- throw new Error("No code provided");
45
- }
46
- const timeoutMs = Math.min(Math.max((timeoutSeconds ?? 5) * 1000, 1000), 60000);
47
- const tmpBase = join(workingDirectory, ".acai-ci-tmp");
48
- await mkdir(tmpBase, { recursive: true });
49
- const scriptPath = join(tmpBase, `temp_script_${Date.now()}_${randomUUID()}.mjs`);
50
- await writeFile(scriptPath, code, { encoding: "utf8" });
51
- const args = [
52
- "--permission",
53
- `--allow-fs-read=${workingDirectory}`,
54
- `--allow-fs-write=${workingDirectory}`,
55
- scriptPath,
56
- ];
57
- const child = spawn(process.execPath, args, {
58
- cwd: workingDirectory,
59
- // do not rely solely on spawn's timeout; we implement manual timeout below
60
- stdio: "pipe",
61
- env: Object.assign({}, process.env, {
62
- // biome-ignore lint/style/useNamingConvention: Environment variable keys are uppercase by convention
63
- NO_COLOR: "true",
64
- // biome-ignore lint/style/useNamingConvention: Environment variable keys are uppercase by convention
65
- NODE_OPTIONS: "",
66
- }),
67
- });
68
- let stdout = "";
69
- let stderr = "";
70
- let timedOut = false;
71
- const timer = setTimeout(() => {
72
- timedOut = true;
73
- try {
74
- child.kill("SIGKILL");
75
- }
76
- catch { }
77
- }, timeoutMs);
78
- child.stdout.setEncoding("utf8");
79
- child.stderr.setEncoding("utf8");
80
- child.stdout.on("data", (chunk) => {
81
- stdout += String(chunk);
82
- });
83
- child.stderr.on("data", (chunk) => {
84
- stderr += String(chunk);
85
- });
86
- const completed = await new Promise((resolve, reject) => {
87
- child.on("error", (err) => reject(err));
88
- child.on("close", (code, signal) => resolve({ code, signal }));
89
- });
90
- clearTimeout(timer);
91
- // Cleanup temp file/directory
92
- await rm(scriptPath, { force: true });
93
- await rm(tmpBase, { force: true, recursive: true });
94
- if (timedOut) {
95
- throw new Error("Script timed out");
96
- }
97
- if (completed.code === null) {
98
- throw new Error(`Process terminated by signal ${completed.signal ?? "unknown"}`);
99
- }
100
- if (completed.code !== 0) {
101
- const message = `Process exited with code ${completed.code}. Stderr: ${stderr.trim()}`;
102
- throw new Error(message);
103
- }
104
- const result = {
105
- stdout: stdout.trim(),
106
- stderr: stderr.trim(),
107
- exitCode: completed.code ?? -1,
108
- };
109
- sendData?.({
110
- event: "tool-completion",
111
- id: toolCallId,
112
- data: "Code execution completed successfully",
113
- });
114
- return JSON.stringify(result, null, 2);
115
- }
116
- catch (err) {
117
- const errorMessage = err.name === "ETIMEDOUT" ||
118
- err.message.includes("timed out")
119
- ? "Script timed out"
120
- : `Error: ${err.message}`;
121
- sendData?.({
122
- event: "tool-error",
123
- id: toolCallId,
124
- data: errorMessage,
125
- });
126
- return errorMessage;
127
- }
128
- },
129
- }),
130
- };
131
- };
@@ -1,8 +0,0 @@
1
- export declare class CommandValidation {
2
- private readonly allowedCommands;
3
- private readonly unsafeOperatorPatterns;
4
- constructor(allowedCommands: string[]);
5
- private isCommandAllowed;
6
- private hasUnsafeOperators;
7
- isValid(command: string): boolean;
8
- }
@@ -1,69 +0,0 @@
1
- export class CommandValidation {
2
- allowedCommands;
3
- unsafeOperatorPatterns;
4
- constructor(allowedCommands) {
5
- this.allowedCommands = allowedCommands;
6
- this.unsafeOperatorPatterns = [
7
- /`/, // backticks
8
- /\$\(/, // $(
9
- />/, // redirect out
10
- /</, // redirect in
11
- ];
12
- }
13
- isCommandAllowed(command) {
14
- const baseCommand = command.split(" ")[0] || "";
15
- return this.allowedCommands.includes(baseCommand);
16
- }
17
- hasUnsafeOperators(command) {
18
- // Remove all quoted segments first
19
- const stripped = command
20
- .replace(/'([^'\\]|\\.)*'/g, "")
21
- .replace(/"([^"\\]|\\.)*"/g, "");
22
- // Check for unsafe operators only in unquoted portions
23
- return this.unsafeOperatorPatterns.some((re) => re.test(stripped));
24
- }
25
- isValid(command) {
26
- if (!command.trim())
27
- return false;
28
- // First check for unsafe operators in unquoted portions
29
- if (this.hasUnsafeOperators(command)) {
30
- return false;
31
- }
32
- // Process command while preserving quoted strings
33
- const subCommands = [];
34
- let currentSegment = "";
35
- let inSingleQuote = false;
36
- let inDoubleQuote = false;
37
- for (let i = 0; i < command.length; i++) {
38
- const char = command[i];
39
- // Handle quote states
40
- if (char === "'" && !inDoubleQuote)
41
- inSingleQuote = !inSingleQuote;
42
- if (char === '"' && !inSingleQuote)
43
- inDoubleQuote = !inDoubleQuote;
44
- // Split on operators only when not in quotes
45
- if (!inSingleQuote &&
46
- !inDoubleQuote &&
47
- (char === "&" || char === "|" || char === ";")) {
48
- if (currentSegment.trim()) {
49
- subCommands.push(currentSegment.trim());
50
- currentSegment = "";
51
- }
52
- // Skip the operator and any subsequent same operators (like && or ||)
53
- while (i + 1 < command.length &&
54
- ["&", "|", ";"].includes(command[i + 1] ?? "")) {
55
- i++;
56
- }
57
- }
58
- else {
59
- currentSegment += char;
60
- }
61
- }
62
- // Add the last segment
63
- if (currentSegment.trim()) {
64
- subCommands.push(currentSegment.trim());
65
- }
66
- // Validate all sub-commands
67
- return subCommands.every((cmd) => this.isCommandAllowed(cmd));
68
- }
69
- }
@@ -1,12 +0,0 @@
1
- import type { SendData } from "./types.ts";
2
- export declare const DeleteFileTool: {
3
- name: "deleteFile";
4
- };
5
- export declare const createDeleteFileTool: ({ workingDir, sendData, }: {
6
- workingDir: string;
7
- sendData?: SendData;
8
- }) => Promise<{
9
- deleteFile: import("ai").Tool<{
10
- path: string;
11
- }, string>;
12
- }>;
@@ -1,56 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import fs from "node:fs/promises";
3
- import { tool } from "ai";
4
- import chalk from "chalk";
5
- import { z } from "zod";
6
- import { joinWorkingDir, validatePath } from "./filesystem-utils.js";
7
- export const DeleteFileTool = {
8
- name: "deleteFile",
9
- };
10
- export const createDeleteFileTool = async ({ workingDir, sendData, }) => {
11
- const allowedDirectory = workingDir;
12
- return {
13
- [DeleteFileTool.name]: tool({
14
- description: "Delete a file permanently.",
15
- inputSchema: z.object({
16
- path: z.string().describe("Absolute path to the file to delete"),
17
- }),
18
- execute: async ({ path: userPath }, { toolCallId }) => {
19
- sendData?.({
20
- id: toolCallId,
21
- event: "tool-init",
22
- data: `Deleting file: ${chalk.cyan(userPath)}`,
23
- });
24
- try {
25
- const filePath = await validatePath(joinWorkingDir(userPath, workingDir), allowedDirectory);
26
- // Check if file exists before attempting delete
27
- if (!existsSync(filePath)) {
28
- throw new Error(`File not found: ${filePath}`);
29
- }
30
- // Ensure it's a file, not a directory
31
- const stats = await fs.stat(filePath);
32
- if (stats.isDirectory()) {
33
- throw new Error(`Path is a directory, not a file: ${filePath}`);
34
- }
35
- // Delete the original file
36
- await fs.unlink(filePath);
37
- sendData?.({
38
- id: toolCallId,
39
- event: "tool-completion",
40
- data: `File deleted successfully: ${userPath}`,
41
- });
42
- return `Successfully deleted ${filePath}`;
43
- }
44
- catch (error) {
45
- const errorMessage = `Failed to delete file: ${error.message}`;
46
- sendData?.({
47
- id: toolCallId,
48
- event: "tool-error",
49
- data: errorMessage,
50
- });
51
- return errorMessage;
52
- }
53
- },
54
- }),
55
- };
56
- };
@@ -1,12 +0,0 @@
1
- import type { SendData } from "./types.ts";
2
- export declare const DirectoryTreeTool: {
3
- name: "directoryTree";
4
- };
5
- export declare const createDirectoryTreeTool: ({ workingDir, sendData, }: {
6
- workingDir: string;
7
- sendData?: SendData;
8
- }) => Promise<{
9
- directoryTree: import("ai").Tool<{
10
- path: string;
11
- }, string>;
12
- }>;
@@ -1,38 +0,0 @@
1
- import { tool } from "ai";
2
- import chalk from "chalk";
3
- import { z } from "zod";
4
- import { directoryTree, joinWorkingDir, validatePath, } from "./filesystem-utils.js";
5
- export const DirectoryTreeTool = {
6
- name: "directoryTree",
7
- };
8
- export const createDirectoryTreeTool = async ({ workingDir, sendData, }) => {
9
- const allowedDirectory = workingDir;
10
- return {
11
- [DirectoryTreeTool.name]: tool({
12
- 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 project. 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.",
13
- inputSchema: z.object({
14
- path: z.string().describe("The path."),
15
- }),
16
- execute: async ({ path }, { toolCallId }) => {
17
- let validPath;
18
- try {
19
- sendData?.({
20
- id: toolCallId,
21
- event: "tool-init",
22
- data: `Listing directory tree: ${chalk.cyan(path)}`,
23
- });
24
- validPath = await validatePath(joinWorkingDir(path, workingDir), allowedDirectory);
25
- sendData?.({
26
- id: toolCallId,
27
- event: "tool-completion",
28
- data: "Done",
29
- });
30
- }
31
- catch (error) {
32
- return `Failed to show directory tree: ${error.message}`;
33
- }
34
- return directoryTree(validPath);
35
- },
36
- }),
37
- };
38
- };
@@ -1,19 +0,0 @@
1
- import type { Terminal } from "../terminal/index.ts";
2
- import type { SendData } from "./types.ts";
3
- export declare const EditFileTool: {
4
- name: "editFile";
5
- };
6
- export declare const createEditFileTool: ({ workingDir, terminal, sendData, autoAcceptAll, }: {
7
- workingDir: string;
8
- terminal?: Terminal;
9
- sendData?: SendData;
10
- autoAcceptAll: boolean;
11
- }) => Promise<{
12
- editFile: import("ai").Tool<{
13
- path: string;
14
- edits: {
15
- oldText: string;
16
- newText: string;
17
- }[];
18
- }, string>;
19
- }>;