@travisennis/acai 0.0.1 → 0.0.3

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 (324) 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.d.ts +1 -0
  9. package/dist/index.js +2 -1
  10. package/dist/models/openrouter-provider.d.ts +4 -1
  11. package/dist/models/openrouter-provider.js +46 -4
  12. package/dist/models/providers.d.ts +1 -1
  13. package/dist/prompts/manager.d.ts +1 -0
  14. package/dist/prompts/manager.js +10 -0
  15. package/dist/prompts.js +8 -6
  16. package/dist/repl.js +49 -26
  17. package/dist/terminal/formatting.d.ts +16 -5
  18. package/dist/terminal/formatting.js +40 -6
  19. package/dist/terminal/index.d.ts +1 -1
  20. package/dist/terminal/index.js +54 -14
  21. package/dist/terminal/markdown.js +0 -1
  22. package/dist/terminal/supports-color.d.ts +16 -0
  23. package/dist/terminal/supports-color.js +121 -0
  24. package/dist/terminal/supports-hyperlinks.d.ts +7 -0
  25. package/dist/terminal/supports-hyperlinks.js +98 -0
  26. package/dist/tools/bash.js +95 -117
  27. package/dist/tools/code-interpreter.js +11 -1
  28. package/dist/tools/command-validation.d.ts +7 -3
  29. package/dist/tools/command-validation.js +67 -23
  30. package/dist/tools/delete-file.d.ts +4 -1
  31. package/dist/tools/delete-file.js +47 -3
  32. package/dist/tools/git-utils.d.ts +6 -0
  33. package/dist/tools/git-utils.js +89 -12
  34. package/dist/tools/grep.d.ts +20 -0
  35. package/dist/tools/grep.js +128 -40
  36. package/dist/tools/index.d.ts +2 -18
  37. package/dist/tools/index.js +4 -18
  38. package/package.json +30 -20
  39. package/.acai/acai.json +0 -9
  40. package/.acai/prompts/add-openrouter-model.md +0 -13
  41. package/.acai/prompts/project-status.md +0 -4
  42. package/.acai/prompts/update-architecture-document.md +0 -9
  43. package/.acai/rules/learned-rules.md +0 -9
  44. package/.ai/docs/available-tools.txt +0 -3
  45. package/.ai/docs/cognitive_complexity_refactoring_progress.md +0 -65
  46. package/.ai/docs/deleted_tools.md +0 -168
  47. package/.ai/docs/deleted_tools_88ced9ef.md +0 -56
  48. package/.ai/docs/image-pasting.md +0 -46
  49. package/.ai/docs/initialize-app.md +0 -117
  50. package/.ai/docs/issue-4-plan.md +0 -44
  51. package/.ai/docs/marked-renderer-debug.md +0 -15
  52. package/.ai/docs/marked-renderer-refactor-plan.md +0 -64
  53. package/.ai/docs/memory-use-cases.md +0 -55
  54. package/.ai/docs/prompt-consistency.md +0 -31
  55. package/.ai/docs/refactoring-tools.md +0 -98
  56. package/.ai/docs/system-prompt-update.md +0 -174
  57. package/.ai/docs/system_prompt.txt +0 -210
  58. package/.ai/docs/tasks.md +0 -49
  59. package/.ai/plan.md +0 -131
  60. package/.ai/prompt.md +0 -1
  61. package/.ai/scripts/fetch_models.js +0 -27
  62. package/.ai/scripts/generateSystemPrompt.ts +0 -15
  63. package/.ai/scripts/list-tools.mjs +0 -4
  64. package/.ai/scripts/p5_geometric_shapes.js +0 -149
  65. package/.husky/commit-msg +0 -1
  66. package/.husky/pre-commit +0 -3
  67. package/.husky/pre-push +0 -1
  68. package/.ignore +0 -4
  69. package/AGENTS.md +0 -25
  70. package/ARCHITECTURE.md +0 -304
  71. package/TODO.md +0 -2
  72. package/biome.json +0 -61
  73. package/commitlint.config.js +0 -3
  74. package/dist/source/cli.d.ts +0 -19
  75. package/dist/source/cli.js +0 -116
  76. package/dist/source/commands/application-log-command.d.ts +0 -2
  77. package/dist/source/commands/application-log-command.js +0 -43
  78. package/dist/source/commands/clear-command.d.ts +0 -2
  79. package/dist/source/commands/clear-command.js +0 -12
  80. package/dist/source/commands/compact-command.d.ts +0 -2
  81. package/dist/source/commands/compact-command.js +0 -51
  82. package/dist/source/commands/copy-command.d.ts +0 -2
  83. package/dist/source/commands/copy-command.js +0 -51
  84. package/dist/source/commands/edit-command.d.ts +0 -2
  85. package/dist/source/commands/edit-command.js +0 -53
  86. package/dist/source/commands/edit-prompt-command.d.ts +0 -2
  87. package/dist/source/commands/edit-prompt-command.js +0 -25
  88. package/dist/source/commands/exit-command.d.ts +0 -2
  89. package/dist/source/commands/exit-command.js +0 -14
  90. package/dist/source/commands/files-command.d.ts +0 -2
  91. package/dist/source/commands/files-command.js +0 -63
  92. package/dist/source/commands/generate-rules-command.d.ts +0 -2
  93. package/dist/source/commands/generate-rules-command.js +0 -61
  94. package/dist/source/commands/help-command.d.ts +0 -2
  95. package/dist/source/commands/help-command.js +0 -19
  96. package/dist/source/commands/init-command.d.ts +0 -2
  97. package/dist/source/commands/init-command.js +0 -40
  98. package/dist/source/commands/last-log-command.d.ts +0 -2
  99. package/dist/source/commands/last-log-command.js +0 -76
  100. package/dist/source/commands/manager.d.ts +0 -22
  101. package/dist/source/commands/manager.js +0 -123
  102. package/dist/source/commands/model-command.d.ts +0 -2
  103. package/dist/source/commands/model-command.js +0 -84
  104. package/dist/source/commands/paste-command.d.ts +0 -2
  105. package/dist/source/commands/paste-command.js +0 -40
  106. package/dist/source/commands/prompt-command.d.ts +0 -2
  107. package/dist/source/commands/prompt-command.js +0 -111
  108. package/dist/source/commands/reset-command.d.ts +0 -2
  109. package/dist/source/commands/reset-command.js +0 -16
  110. package/dist/source/commands/rules-command.d.ts +0 -2
  111. package/dist/source/commands/rules-command.js +0 -68
  112. package/dist/source/commands/save-command.d.ts +0 -2
  113. package/dist/source/commands/save-command.js +0 -14
  114. package/dist/source/commands/types.d.ts +0 -26
  115. package/dist/source/commands/types.js +0 -1
  116. package/dist/source/commands/usage-command.d.ts +0 -2
  117. package/dist/source/commands/usage-command.js +0 -21
  118. package/dist/source/config.d.ts +0 -60
  119. package/dist/source/config.js +0 -193
  120. package/dist/source/conversation-analyzer.d.ts +0 -10
  121. package/dist/source/conversation-analyzer.js +0 -88
  122. package/dist/source/dedent.d.ts +0 -3
  123. package/dist/source/dedent.js +0 -38
  124. package/dist/source/formatting.d.ts +0 -17
  125. package/dist/source/formatting.js +0 -103
  126. package/dist/source/index.d.ts +0 -18
  127. package/dist/source/index.js +0 -213
  128. package/dist/source/logger.d.ts +0 -2
  129. package/dist/source/logger.js +0 -24
  130. package/dist/source/mentions.d.ts +0 -9
  131. package/dist/source/mentions.js +0 -182
  132. package/dist/source/messages.d.ts +0 -69
  133. package/dist/source/messages.js +0 -261
  134. package/dist/source/middleware/audit-message.d.ts +0 -5
  135. package/dist/source/middleware/audit-message.js +0 -95
  136. package/dist/source/middleware/index.d.ts +0 -2
  137. package/dist/source/middleware/index.js +0 -2
  138. package/dist/source/middleware/rate-limit.d.ts +0 -4
  139. package/dist/source/middleware/rate-limit.js +0 -17
  140. package/dist/source/models/ai-config.d.ts +0 -12
  141. package/dist/source/models/ai-config.js +0 -87
  142. package/dist/source/models/anthropic-provider.d.ts +0 -25
  143. package/dist/source/models/anthropic-provider.js +0 -184
  144. package/dist/source/models/deepseek-provider.d.ts +0 -20
  145. package/dist/source/models/deepseek-provider.js +0 -42
  146. package/dist/source/models/google-provider.d.ts +0 -19
  147. package/dist/source/models/google-provider.js +0 -56
  148. package/dist/source/models/manager.d.ts +0 -15
  149. package/dist/source/models/manager.js +0 -48
  150. package/dist/source/models/openai-provider.d.ts +0 -22
  151. package/dist/source/models/openai-provider.js +0 -70
  152. package/dist/source/models/openrouter-provider.d.ts +0 -36
  153. package/dist/source/models/openrouter-provider.js +0 -276
  154. package/dist/source/models/providers.d.ts +0 -33
  155. package/dist/source/models/providers.js +0 -116
  156. package/dist/source/models/xai-provider.d.ts +0 -20
  157. package/dist/source/models/xai-provider.js +0 -47
  158. package/dist/source/parsing.d.ts +0 -2
  159. package/dist/source/parsing.js +0 -18
  160. package/dist/source/prompts/manager.d.ts +0 -19
  161. package/dist/source/prompts/manager.js +0 -71
  162. package/dist/source/prompts.d.ts +0 -4
  163. package/dist/source/prompts.js +0 -158
  164. package/dist/source/repl-prompt.d.ts +0 -14
  165. package/dist/source/repl-prompt.js +0 -147
  166. package/dist/source/repl.d.ts +0 -27
  167. package/dist/source/repl.js +0 -431
  168. package/dist/source/terminal/formatting.d.ts +0 -37
  169. package/dist/source/terminal/formatting.js +0 -106
  170. package/dist/source/terminal/index.d.ts +0 -94
  171. package/dist/source/terminal/index.js +0 -420
  172. package/dist/source/terminal/markdown-utils.d.ts +0 -2
  173. package/dist/source/terminal/markdown-utils.js +0 -81
  174. package/dist/source/terminal/markdown.d.ts +0 -1
  175. package/dist/source/terminal/markdown.js +0 -111
  176. package/dist/source/terminal/types.d.ts +0 -71
  177. package/dist/source/terminal/types.js +0 -1
  178. package/dist/source/terminal-output.d.ts +0 -8
  179. package/dist/source/terminal-output.js +0 -213
  180. package/dist/source/terminal-output.test.d.ts +0 -8
  181. package/dist/source/terminal-output.test.js +0 -213
  182. package/dist/source/token-tracker.d.ts +0 -14
  183. package/dist/source/token-tracker.js +0 -53
  184. package/dist/source/token-utils.d.ts +0 -7
  185. package/dist/source/token-utils.js +0 -13
  186. package/dist/source/tools/agent.d.ts +0 -17
  187. package/dist/source/tools/agent.js +0 -87
  188. package/dist/source/tools/bash.d.ts +0 -19
  189. package/dist/source/tools/bash.js +0 -294
  190. package/dist/source/tools/code-interpreter.d.ts +0 -12
  191. package/dist/source/tools/code-interpreter.js +0 -131
  192. package/dist/source/tools/command-validation.d.ts +0 -8
  193. package/dist/source/tools/command-validation.js +0 -69
  194. package/dist/source/tools/delete-file.d.ts +0 -12
  195. package/dist/source/tools/delete-file.js +0 -56
  196. package/dist/source/tools/directory-tree.d.ts +0 -12
  197. package/dist/source/tools/directory-tree.js +0 -38
  198. package/dist/source/tools/edit-file.d.ts +0 -19
  199. package/dist/source/tools/edit-file.js +0 -107
  200. package/dist/source/tools/filesystem-utils.d.ts +0 -22
  201. package/dist/source/tools/filesystem-utils.js +0 -191
  202. package/dist/source/tools/git-utils.d.ts +0 -14
  203. package/dist/source/tools/git-utils.js +0 -64
  204. package/dist/source/tools/grep.d.ts +0 -17
  205. package/dist/source/tools/grep.js +0 -138
  206. package/dist/source/tools/index.d.ts +0 -161
  207. package/dist/source/tools/index.js +0 -209
  208. package/dist/source/tools/memory-read.d.ts +0 -13
  209. package/dist/source/tools/memory-read.js +0 -135
  210. package/dist/source/tools/memory-write.d.ts +0 -12
  211. package/dist/source/tools/memory-write.js +0 -83
  212. package/dist/source/tools/move-file.d.ts +0 -13
  213. package/dist/source/tools/move-file.js +0 -44
  214. package/dist/source/tools/read-file.d.ts +0 -17
  215. package/dist/source/tools/read-file.js +0 -86
  216. package/dist/source/tools/read-multiple-files.d.ts +0 -14
  217. package/dist/source/tools/read-multiple-files.js +0 -55
  218. package/dist/source/tools/save-file.d.ts +0 -17
  219. package/dist/source/tools/save-file.js +0 -98
  220. package/dist/source/tools/think.d.ts +0 -11
  221. package/dist/source/tools/think.js +0 -45
  222. package/dist/source/tools/types.d.ts +0 -29
  223. package/dist/source/tools/types.js +0 -14
  224. package/dist/source/tools/web-fetch.d.ts +0 -47
  225. package/dist/source/tools/web-fetch.js +0 -246
  226. package/dist/source/tools/web-search.d.ts +0 -13
  227. package/dist/source/tools/web-search.js +0 -80
  228. package/dist/source/utils/process.d.ts +0 -36
  229. package/dist/source/utils/process.js +0 -75
  230. package/dist/source/version.d.ts +0 -1
  231. package/dist/source/version.js +0 -21
  232. package/dist/terminal-output.d.ts +0 -8
  233. package/dist/terminal-output.js +0 -213
  234. package/dist/tools/memory-read.d.ts +0 -13
  235. package/dist/tools/memory-read.js +0 -135
  236. package/dist/tools/memory-write.d.ts +0 -12
  237. package/dist/tools/memory-write.js +0 -83
  238. package/knip.json +0 -5
  239. package/source/cli.ts +0 -172
  240. package/source/commands/application-log-command.ts +0 -53
  241. package/source/commands/clear-command.ts +0 -14
  242. package/source/commands/compact-command.ts +0 -64
  243. package/source/commands/copy-command.ts +0 -55
  244. package/source/commands/edit-command.ts +0 -63
  245. package/source/commands/edit-prompt-command.ts +0 -31
  246. package/source/commands/exit-command.ts +0 -18
  247. package/source/commands/files-command.ts +0 -85
  248. package/source/commands/generate-rules-command.ts +0 -82
  249. package/source/commands/help-command.ts +0 -27
  250. package/source/commands/init-command.ts +0 -48
  251. package/source/commands/last-log-command.ts +0 -88
  252. package/source/commands/manager.ts +0 -151
  253. package/source/commands/model-command.ts +0 -123
  254. package/source/commands/paste-command.ts +0 -62
  255. package/source/commands/prompt-command.ts +0 -150
  256. package/source/commands/reset-command.ts +0 -22
  257. package/source/commands/rules-command.ts +0 -76
  258. package/source/commands/save-command.ts +0 -20
  259. package/source/commands/types.ts +0 -28
  260. package/source/commands/usage-command.ts +0 -26
  261. package/source/config.ts +0 -223
  262. package/source/conversation-analyzer.ts +0 -115
  263. package/source/dedent.ts +0 -53
  264. package/source/formatting.ts +0 -132
  265. package/source/index.ts +0 -240
  266. package/source/logger.ts +0 -29
  267. package/source/mentions.ts +0 -227
  268. package/source/messages.ts +0 -360
  269. package/source/middleware/audit-message.ts +0 -133
  270. package/source/middleware/index.ts +0 -2
  271. package/source/middleware/rate-limit.ts +0 -24
  272. package/source/models/ai-config.ts +0 -109
  273. package/source/models/anthropic-provider.ts +0 -199
  274. package/source/models/deepseek-provider.ts +0 -53
  275. package/source/models/google-provider.ts +0 -68
  276. package/source/models/manager.ts +0 -84
  277. package/source/models/openai-provider.ts +0 -81
  278. package/source/models/openrouter-provider.ts +0 -288
  279. package/source/models/providers.ts +0 -197
  280. package/source/models/xai-provider.ts +0 -59
  281. package/source/parsing.ts +0 -20
  282. package/source/prompts/manager.ts +0 -90
  283. package/source/prompts.ts +0 -172
  284. package/source/repl-prompt.ts +0 -196
  285. package/source/repl.ts +0 -572
  286. package/source/terminal/formatting.ts +0 -121
  287. package/source/terminal/index.ts +0 -518
  288. package/source/terminal/markdown-utils.ts +0 -89
  289. package/source/terminal/markdown.ts +0 -155
  290. package/source/terminal/types.ts +0 -84
  291. package/source/terminal-output.test.ts +0 -266
  292. package/source/token-tracker.ts +0 -78
  293. package/source/token-utils.ts +0 -17
  294. package/source/tools/agent.ts +0 -107
  295. package/source/tools/bash.ts +0 -367
  296. package/source/tools/code-interpreter.ts +0 -172
  297. package/source/tools/command-validation.ts +0 -81
  298. package/source/tools/delete-file.ts +0 -71
  299. package/source/tools/directory-tree.ts +0 -54
  300. package/source/tools/edit-file.ts +0 -155
  301. package/source/tools/filesystem-utils.ts +0 -265
  302. package/source/tools/git-utils.ts +0 -70
  303. package/source/tools/grep.ts +0 -184
  304. package/source/tools/index.ts +0 -278
  305. package/source/tools/memory-read.ts +0 -174
  306. package/source/tools/memory-write.ts +0 -105
  307. package/source/tools/move-file.ts +0 -59
  308. package/source/tools/read-file.ts +0 -129
  309. package/source/tools/read-multiple-files.ts +0 -80
  310. package/source/tools/save-file.ts +0 -147
  311. package/source/tools/think.ts +0 -51
  312. package/source/tools/types.ts +0 -58
  313. package/source/tools/web-fetch.ts +0 -327
  314. package/source/tools/web-search.ts +0 -101
  315. package/source/utils/process.ts +0 -121
  316. package/source/version.ts +0 -21
  317. package/test/commands/copy-command.test.ts +0 -69
  318. package/test/config.test.ts +0 -200
  319. package/test/terminal/markdown-utils.test.ts +0 -124
  320. package/test/tools/bash-tool.test.ts +0 -58
  321. package/test/tools/code-interpreter.test.ts +0 -91
  322. package/test/tools/command-validation.test.ts +0 -48
  323. package/tsconfig.build.json +0 -9
  324. package/tsconfig.json +0 -30
package/source/dedent.ts DELETED
@@ -1,53 +0,0 @@
1
- type Dedent = (strings: TemplateStringsArray, ...values: unknown[]) => string;
2
-
3
- const spaces = /^(\s+)\S+/;
4
-
5
- export const dedent: Dedent = (
6
- strings: TemplateStringsArray,
7
- ...values: unknown[]
8
- ): string => {
9
- // Perform interpolation
10
- let result = "";
11
- for (let i = 0; i < strings.raw.length; i++) {
12
- const next =
13
- strings.raw[i] ??
14
- ""
15
- // handle escaped newlines, backticks, and interpolation characters
16
- .replace(/\\\n[ \t]*/g, "")
17
- .replace(/\\`/g, "`")
18
- .replace(/\\\$/g, "$")
19
- .replace(/\\\{/g, "{");
20
-
21
- result += next;
22
-
23
- if (i < values.length) {
24
- result += values[i];
25
- }
26
- }
27
-
28
- // Strip indentation
29
- const lines = result.split("\n");
30
- let mindent: null | number = null;
31
-
32
- for (const line of lines) {
33
- const m = line.match(spaces);
34
- if (m) {
35
- const indent = m[1]?.length ?? 0;
36
- mindent = mindent === null ? indent : Math.min(mindent, indent);
37
- }
38
- }
39
-
40
- if (mindent !== null) {
41
- result = lines
42
- .map((l) => (l[0] === " " || l[0] === "\t" ? l.slice(mindent) : l))
43
- .join("\n");
44
- }
45
-
46
- // Trim leading and trailing whitespace
47
- result = result.trim();
48
-
49
- // Handle escaped newlines at the end
50
- result = result.replace(/\\n/g, "\n");
51
-
52
- return result;
53
- };
@@ -1,132 +0,0 @@
1
- import path from "node:path";
2
-
3
- const MD_CODE_BLOCK = /```(?:[\w-]+)?\n(.*?)```/s;
4
-
5
- /**
6
- * Extracts the first code block content from the given text.
7
- * If a Markdown-style triple backtick code block is found, returns its inner content.
8
- * Otherwise, returns the original text unchanged.
9
- *
10
- * @param text - The input string potentially containing a Markdown code block.
11
- * @returns The extracted code inside the first code block, or the original text if no block is found.
12
- */
13
- export const extractCodeBlock = (text: string): string => {
14
- const pattern = MD_CODE_BLOCK;
15
- const match = text.match(pattern);
16
- if (match) {
17
- return match[1] ?? "";
18
- }
19
- return text;
20
- };
21
-
22
- export function extractXml(text: string, tag: string): string {
23
- const match = text.match(new RegExp(`<${tag}>(.*?)</${tag}>`, "s"));
24
- return match ? (match[1] ?? "") : "";
25
- }
26
-
27
- export function removeAllLineBreaks(text: string) {
28
- return text.replace(/(\r\n|\n|\r)/gm, " ");
29
- }
30
-
31
- export function removeHtmlTags(text: string) {
32
- return text.replace(/<[^>]*>?/gm, "");
33
- }
34
-
35
- const MD_TRIPLE_QUOTE = "```";
36
-
37
- export type FormatType = "xml" | "markdown" | "bracket";
38
-
39
- const codeBlockExtensions: Record<string, string> = {
40
- js: "javascript",
41
- ts: "typescript",
42
- py: "python",
43
- rb: "ruby",
44
- java: "java",
45
- cpp: "cpp",
46
- cs: "csharp",
47
- go: "go",
48
- rs: "rust",
49
- php: "php",
50
- html: "html",
51
- css: "css",
52
- json: "json",
53
- yml: "yaml",
54
- yaml: "yaml",
55
- md: "markdown",
56
- sql: "sql",
57
- sh: "bash",
58
- bash: "bash",
59
- txt: "text",
60
- };
61
-
62
- export function formatFile(
63
- file: string,
64
- content: string,
65
- format: FormatType,
66
- ): string {
67
- const fileExtension = path.extname(file).slice(1);
68
- const codeBlockName = codeBlockExtensions[fileExtension] || fileExtension;
69
- switch (format) {
70
- case "xml":
71
- return `<file>\n<name>${file}</name>\n<content>\n${content}\n</content>\n</file>`;
72
- case "markdown":
73
- return `## File: ${file}\n${MD_TRIPLE_QUOTE} ${codeBlockName}\n${content}\n${MD_TRIPLE_QUOTE}`;
74
- case "bracket":
75
- return `[file name]: ${file}\n[file content begin]\n${content}\n[file content end]`;
76
- default:
77
- throw new Error(`Unsupported format: ${format}`);
78
- }
79
- }
80
-
81
- export function formatUrl(
82
- siteUrl: string,
83
- content: string,
84
- format: FormatType,
85
- ): string {
86
- switch (format) {
87
- case "xml":
88
- return `<webpage>\n<url>${siteUrl}</url>\n<content>\n${content}\n</content>\n</webpage>`;
89
- case "markdown":
90
- return `## URL: ${siteUrl}\n${MD_TRIPLE_QUOTE}\n${content}\n${MD_TRIPLE_QUOTE}`;
91
- case "bracket":
92
- return `[url]: ${siteUrl}\n[url content begin]\n${content}\n[url content end]`;
93
- default:
94
- throw new Error(`Unsupported format: ${format}`);
95
- }
96
- }
97
-
98
- export function formatCodeSnippet(
99
- file: string,
100
- content: string,
101
- format: FormatType,
102
- ) {
103
- const fileExtension = path.extname(file).slice(1);
104
- const codeBlockName = codeBlockExtensions[fileExtension] || fileExtension;
105
- switch (format) {
106
- case "xml":
107
- return `<code>\n${content}\n</code>`;
108
- case "markdown":
109
- return `${MD_TRIPLE_QUOTE} ${codeBlockName}\n${content}\n${MD_TRIPLE_QUOTE}`;
110
- case "bracket":
111
- return `[code begin]\n${content}\n[code end]`;
112
- default:
113
- throw new Error(`Unsupported format: ${format}`);
114
- }
115
- }
116
-
117
- export function formatBlock(
118
- content: string,
119
- blockName: string,
120
- format: FormatType,
121
- ): string {
122
- switch (format) {
123
- case "xml":
124
- return `<${blockName}>\n${content}\n</${blockName}>\n</file>`;
125
- case "markdown":
126
- return `## ${blockName}\n${MD_TRIPLE_QUOTE}\n${content}\n${MD_TRIPLE_QUOTE}`;
127
- case "bracket":
128
- return `[${blockName} begin]\n${content}\n[${blockName} end]`;
129
- default:
130
- throw new Error(`Unsupported format: ${format}`);
131
- }
132
- }
package/source/index.ts DELETED
@@ -1,240 +0,0 @@
1
- import { text } from "node:stream/consumers";
2
- import { parseArgs } from "node:util";
3
- import { select } from "@inquirer/prompts";
4
- import { asyncTry } from "@travisennis/stdlib/try";
5
- import { isDefined } from "@travisennis/stdlib/typeguards";
6
- import { Cli } from "./cli.ts";
7
- import { CommandManager } from "./commands/manager.ts";
8
- import { config } from "./config.ts";
9
- import { logger } from "./logger.ts";
10
- import { MessageHistory } from "./messages.ts";
11
- import { ModelManager } from "./models/manager.ts";
12
- import { isSupportedModel, type ModelName } from "./models/providers.ts";
13
- import { PromptManager } from "./prompts/manager.ts";
14
- import { Repl } from "./repl.ts";
15
- import { initTerminal } from "./terminal/index.ts";
16
- import { TokenTracker } from "./token-tracker.ts";
17
- import { TokenCounter } from "./token-utils.ts";
18
- import type { Message } from "./tools/types.ts";
19
- import { getPackageVersion } from "./version.ts";
20
-
21
- const helpText = `
22
- Usage
23
- $ acai <input>
24
-
25
- Options
26
- --model, -m Sets the model to use
27
- --prompt, -p Sets the prompt
28
- --oneshot, -o Run once and exit
29
- --continue Load the most recent conversation
30
- --resume Select a recent conversation to resume
31
- --autoAcceptAll Accept all commands and edits without prompting
32
- --help, -h Show help
33
- --version, -v Show version
34
-
35
- Examples
36
- $ acai --model anthopric:sonnet
37
- $ acai -p "initial prompt"
38
- $ acai -p "one-shot prompt" -o
39
- `;
40
-
41
- const parsed = parseArgs({
42
- options: {
43
- model: { type: "string", short: "m" },
44
- prompt: { type: "string", short: "p" },
45
- oneshot: { type: "boolean", short: "o", default: false },
46
- continue: { type: "boolean", default: false },
47
- resume: { type: "boolean", default: false },
48
- autoAcceptAll: { type: "boolean", default: false },
49
- help: { type: "boolean", short: "h" },
50
- version: { type: "boolean", short: "v" },
51
- },
52
- allowPositionals: true,
53
- });
54
-
55
- const flags = parsed.values;
56
- const input = parsed.positionals;
57
-
58
- /**
59
- * Global error handler function.
60
- * @param {Error} error - The error to be handled.
61
- * @throws {Error} Rethrows the error after logging it.
62
- */
63
- export function handleError(error: Error): void {
64
- logger.error({ error: error }, error.message);
65
- }
66
-
67
- export type Flags = typeof flags;
68
-
69
- async function main() {
70
- const appConfig = await config.ensureAppConfig("acai");
71
-
72
- if (flags.version === true) {
73
- console.info(getPackageVersion());
74
- process.exit(0);
75
- }
76
-
77
- if (flags.help === true) {
78
- console.info(helpText);
79
- process.exit(0);
80
- }
81
-
82
- const appDir = config.app;
83
- const messageHistoryDir = await appDir.ensurePath("message-history");
84
-
85
- // --- Argument Validation ---
86
- if (flags.continue === true && flags.resume === true) {
87
- console.error("Cannot use --continue and --resume flags together.");
88
- process.exit(1);
89
- }
90
-
91
- const hasContinueOrResume = flags.continue === true || flags.resume === true;
92
-
93
- if (hasContinueOrResume && flags.oneshot === true) {
94
- console.error("Cannot use --continue or --resume with --oneshot.");
95
- process.exit(1);
96
- }
97
-
98
- // --- Determine Initial Prompt (potential conflict) ---
99
- const positionalPrompt = input.at(0);
100
- let stdInPrompt: string | undefined;
101
- // Check if there's data available on stdin
102
- if (!process.stdin.isTTY) {
103
- try {
104
- // Non-TTY stdin means data is being piped in
105
- stdInPrompt = await text(process.stdin);
106
- } catch (error) {
107
- console.error(`Error reading stdin: ${(error as Error).message}`);
108
- }
109
- }
110
-
111
- const initialPromptInput =
112
- typeof flags.prompt === "string" && flags.prompt.length > 0
113
- ? flags.prompt
114
- : positionalPrompt && positionalPrompt.length > 0
115
- ? positionalPrompt
116
- : undefined;
117
-
118
- if (hasContinueOrResume && isDefined(initialPromptInput)) {
119
- console.error("Cannot use --continue or --resume with an initial prompt.");
120
- process.exit(1);
121
- }
122
-
123
- const terminal = initTerminal();
124
- terminal.setTitle(`acai: ${process.cwd()}`);
125
-
126
- const chosenModel: ModelName = isSupportedModel(flags.model)
127
- ? (flags.model as ModelName)
128
- : "openrouter:sonnet4";
129
-
130
- const modelManager = new ModelManager({
131
- stateDir: await appDir.ensurePath("audit"),
132
- });
133
- modelManager.setModel("repl", chosenModel);
134
- modelManager.setModel("cli", chosenModel);
135
- modelManager.setModel("title-conversation", "openrouter:gemini-flash25");
136
- modelManager.setModel("conversation-summarizer", "openrouter:gemini-flash25");
137
- modelManager.setModel("tool-repair", "openai:gpt-4.1");
138
- modelManager.setModel("conversation-analyzer", "openrouter:gemini-flash25");
139
- modelManager.setModel("init-project", chosenModel);
140
- modelManager.setModel("task-agent", "openrouter:gemini-flash25");
141
-
142
- const tokenTracker = new TokenTracker();
143
- const tokenCounter = new TokenCounter();
144
-
145
- const messageHistory = new MessageHistory({
146
- stateDir: messageHistoryDir,
147
- modelManager,
148
- tokenTracker,
149
- });
150
- messageHistory.on("update-title", (title) => terminal.setTitle(title));
151
-
152
- if (flags.continue === true) {
153
- const histories = await MessageHistory.load(messageHistoryDir, 1);
154
- const latestHistory = histories.at(0);
155
- if (latestHistory) {
156
- messageHistory.restore(latestHistory);
157
- console.info(`Resuming conversation: ${latestHistory.title}`);
158
- // Set terminal title after restoring
159
- terminal.setTitle(latestHistory.title || `acai: ${process.cwd()}`);
160
- } else {
161
- logger.info("No previous conversation found to continue.");
162
- }
163
- } else if (flags.resume === true) {
164
- const histories = await MessageHistory.load(messageHistoryDir, 10);
165
- if (histories.length > 0) {
166
- const choice = await select({
167
- message: "Select a conversation to resume:",
168
- choices: histories.map((h, index) => ({
169
- name: `${index + 1}: ${h.title} (${h.updatedAt.toLocaleString()})`,
170
- value: index,
171
- description: `${h.messages.length} messages`,
172
- })),
173
- });
174
- const selectedHistory = histories.at(choice);
175
- if (selectedHistory) {
176
- messageHistory.restore(selectedHistory);
177
- logger.info(`Resuming conversation: ${selectedHistory.title}`);
178
- // Set terminal title after restoring
179
- terminal.setTitle(selectedHistory.title || `acai: ${process.cwd()}`);
180
- } else {
181
- // This case should theoretically not happen if choice is valid
182
- logger.error("Selected history index out of bounds.");
183
- }
184
- } else {
185
- logger.info("No previous conversations found to resume.");
186
- }
187
- }
188
-
189
- // --- Setup Prompt Manager (only if not continuing/resuming) ---
190
- const promptManager = new PromptManager(tokenCounter);
191
- if (!hasContinueOrResume && isDefined(initialPromptInput)) {
192
- promptManager.set(initialPromptInput);
193
- }
194
-
195
- if (stdInPrompt) {
196
- promptManager.addContext(stdInPrompt);
197
- }
198
-
199
- const toolEvents: Map<string, Message[]> = new Map();
200
-
201
- const commands = new CommandManager({
202
- promptManager,
203
- modelManager,
204
- terminal,
205
- messageHistory,
206
- tokenTracker,
207
- config,
208
- tokenCounter,
209
- toolEvents,
210
- });
211
-
212
- if (flags.oneshot === true) {
213
- const cliProcess = new Cli({
214
- promptManager,
215
- config: appConfig,
216
- messageHistory,
217
- modelManager,
218
- tokenTracker,
219
- tokenCounter,
220
- });
221
- return (await asyncTry(cliProcess.run())).recover(handleError);
222
- }
223
-
224
- const repl = new Repl({
225
- promptManager,
226
- terminal,
227
- config: appConfig,
228
- messageHistory,
229
- modelManager,
230
- tokenTracker,
231
- commands,
232
- tokenCounter,
233
- toolEvents,
234
- autoAcceptAll: flags.autoAcceptAll === true,
235
- });
236
-
237
- return (await asyncTry(repl.run())).recover(handleError);
238
- }
239
-
240
- main();
package/source/logger.ts DELETED
@@ -1,29 +0,0 @@
1
- import { join } from "node:path";
2
- import pino from "pino";
3
- import { config } from "./config.ts";
4
-
5
- const transport = pino.transport({
6
- target: "pino-roll",
7
- options: {
8
- file: join(config.app.ensurePathSync("logs"), "acai.log"),
9
- size: "10m",
10
- symlink: true,
11
- limit: {
12
- count: 3,
13
- },
14
- mkdir: true,
15
- },
16
- });
17
-
18
- export const logger = pino(
19
- {
20
- level: process.env["LOG_LEVEL"] ?? "debug",
21
- formatters: {
22
- level: (label) => {
23
- return { level: label.toUpperCase() };
24
- },
25
- },
26
- timestamp: pino.stdTimeFunctions.isoTime,
27
- },
28
- transport,
29
- );
@@ -1,227 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import { isString } from "@travisennis/stdlib/typeguards";
4
- import type { FormatType } from "./formatting.ts";
5
- import { formatFile, formatUrl } from "./formatting.ts";
6
- import type { ModelMetadata } from "./models/providers.ts";
7
- import type { ContextItem } from "./prompts/manager.ts";
8
- import { type ReadUrlResult, readUrl } from "./tools/web-fetch.ts";
9
- import { executeCommand } from "./utils/process.ts";
10
-
11
- interface CommandContext {
12
- model: ModelMetadata;
13
- baseDir: string;
14
- match: string;
15
- }
16
-
17
- // Helper function to recursively read all files in a directory
18
- async function readDirectoryRecursive(
19
- dirPath: string,
20
- format: FormatType,
21
- ): Promise<string> {
22
- const allContents: string[] = [];
23
-
24
- async function readDir(
25
- currentPath: string,
26
- relativePath = "",
27
- ): Promise<void> {
28
- const entries = await fs.readdir(currentPath, { withFileTypes: true });
29
-
30
- for (const entry of entries) {
31
- const fullPath = path.join(currentPath, entry.name);
32
- const relativeFilePath = path.join(relativePath, entry.name);
33
-
34
- if (entry.isDirectory()) {
35
- await readDir(fullPath, relativeFilePath);
36
- } else if (entry.isFile()) {
37
- try {
38
- const fileContents = await fs.readFile(fullPath, "utf8");
39
- allContents.push(formatFile(relativeFilePath, fileContents, format));
40
- } catch (error) {
41
- allContents.push(
42
- `Error reading file ${relativeFilePath}: ${error instanceof Error ? error.message : "Unknown error"}`,
43
- );
44
- }
45
- }
46
- }
47
- }
48
-
49
- await readDir(dirPath);
50
-
51
- if (allContents.length === 0) {
52
- return `Directory ${path.basename(dirPath)} is empty or contains no readable files.`;
53
- }
54
-
55
- return allContents.join("\n\n");
56
- }
57
-
58
- // Returns the formatted string or an error message string
59
- async function processFileCommand(context: CommandContext): Promise<string> {
60
- const { baseDir, match } = context;
61
- const filePath = match.trim();
62
- const format = context.model.promptFormat;
63
-
64
- try {
65
- // Resolve paths to absolute to prevent traversal issues
66
- const resolvedBaseDir = path.resolve(baseDir);
67
- const resolvedFilePath = path.resolve(resolvedBaseDir, filePath);
68
-
69
- // Security Check: Ensure the resolved path is still within the base directory
70
- if (!resolvedFilePath.startsWith(resolvedBaseDir + path.sep)) {
71
- return `Error: Access denied. Attempted to read file outside the allowed directory: ${filePath}`;
72
- }
73
-
74
- // Check if path exists
75
- const stats = await fs.stat(resolvedFilePath);
76
-
77
- // If it's a directory, read all files recursively
78
- if (stats.isDirectory()) {
79
- return await readDirectoryRecursive(resolvedFilePath, format);
80
- }
81
-
82
- // If it's a file, process as before
83
- if (stats.isFile()) {
84
- const fileContents = await fs.readFile(resolvedFilePath, "utf8");
85
- return formatFile(filePath, fileContents, format);
86
- }
87
-
88
- return `Error: ${filePath} is neither a regular file nor directory.`;
89
- } catch (error) {
90
- // Handle both ENOENT (file not found) and permission errors
91
- if (error && typeof error === "object" && "code" in error) {
92
- if (error.code === "ENOENT") {
93
- return `Error: File or directory not found: ${filePath}\nPlease check that the path is correct and exists.`;
94
- }
95
- if (error.code === "EACCES") {
96
- return `Error: Permission denied accessing: ${filePath}`;
97
- }
98
- }
99
- if (error instanceof Error) {
100
- return `Error accessing ${filePath}: ${error.message}`;
101
- }
102
- // Fallback for unknown error types
103
- return `Error accessing ${filePath}: An unknown error occurred.`;
104
- }
105
- }
106
-
107
- async function processShellCommand(command: string): Promise<string> {
108
- try {
109
- const { stdout, stderr, code } = await executeCommand(command, {
110
- shell: true,
111
- });
112
- if (code === 0) {
113
- return stdout;
114
- }
115
- return `Error executing command: ${command}\n${stderr}`;
116
- } catch (error) {
117
- if (error instanceof Error) {
118
- return `Error executing command ${command}: ${error.message}`;
119
- }
120
- return `Error executing command ${command}: An unknown error occurred.`;
121
- }
122
- }
123
-
124
- // Returns the formatted string or an error message string
125
- async function processUrlCommand(
126
- context: CommandContext,
127
- ): Promise<ReadUrlResult & { source: string }> {
128
- const { match } = context;
129
- const urlPath = match;
130
- try {
131
- return Object.assign(await readUrl(urlPath), { source: urlPath });
132
- } catch (error) {
133
- if (error instanceof Error) {
134
- return {
135
- contentType: "text/plain",
136
- data: `Url: ${urlPath} Status: Error fetching URL: ${error.message}`,
137
- source: urlPath,
138
- };
139
- }
140
- // Fallback for unknown error types
141
- return {
142
- contentType: "text/plain",
143
- data: `Url: ${urlPath} Status: Error fetching URL: An unknown error occurred.`,
144
- source: urlPath,
145
- };
146
- }
147
- }
148
-
149
- export async function processPrompt(
150
- message: string,
151
- { baseDir, model }: { baseDir: string; model: ModelMetadata },
152
- ): Promise<{ message: string; context: ContextItem[] }> {
153
- const fileRegex = /@([^\s@]+(?:\.[\w\d]+))/g;
154
- const urlRegex = /@(https?:\/\/[^\s]+)/g;
155
- const shellRegex = /!`([^`]+)`/g;
156
-
157
- // Collect all matches for files and urls
158
- const fileMatches = Array.from(message.matchAll(fileRegex));
159
- const urlMatches = Array.from(message.matchAll(urlRegex));
160
- const shellMatches = Array.from(message.matchAll(shellRegex));
161
-
162
- const mentionProcessingPromises: Promise<
163
- string | (ReadUrlResult & { source: string })
164
- >[] = [];
165
-
166
- // Process file references - collect promises
167
- for (const match of fileMatches) {
168
- const firstMatch = match[1];
169
- if (firstMatch) {
170
- const context = {
171
- model,
172
- baseDir,
173
- match: firstMatch,
174
- };
175
- mentionProcessingPromises.push(processFileCommand(context));
176
- }
177
- }
178
-
179
- // Process url references - collect promises
180
- for (const match of urlMatches) {
181
- const firstMatch = match[1];
182
- if (firstMatch) {
183
- const context = {
184
- model,
185
- baseDir, // baseDir is not used by processUrlCommand but kept for consistency
186
- match: firstMatch,
187
- };
188
- mentionProcessingPromises.push(processUrlCommand(context));
189
- }
190
- }
191
-
192
- let processedMessage = message;
193
- // Process shell commands
194
- for (const match of shellMatches) {
195
- const command = match[1];
196
- if (command) {
197
- const output = await processShellCommand(command);
198
- processedMessage = processedMessage.replace(match[0], output);
199
- }
200
- }
201
-
202
- // Wait for all mentions to be processed
203
- const mentionResults = await Promise.all(mentionProcessingPromises);
204
-
205
- const context: ContextItem[] = [];
206
-
207
- for (const mention of mentionResults) {
208
- if (isString(mention)) {
209
- context.push(mention);
210
- } else if (mention.data.startsWith("data")) {
211
- context.push({
212
- type: "image",
213
- mediaType: mention.contentType,
214
- image: mention.data,
215
- });
216
- } else {
217
- context.push(
218
- formatUrl(mention.source, mention.data.trim(), model.promptFormat),
219
- );
220
- }
221
- }
222
-
223
- return {
224
- message: processedMessage,
225
- context,
226
- };
227
- }