@travisennis/acai 0.0.1

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 (439) hide show
  1. package/.acai/acai.json +9 -0
  2. package/.acai/prompts/add-openrouter-model.md +13 -0
  3. package/.acai/prompts/project-status.md +4 -0
  4. package/.acai/prompts/update-architecture-document.md +9 -0
  5. package/.acai/rules/learned-rules.md +9 -0
  6. package/.ai/docs/available-tools.txt +3 -0
  7. package/.ai/docs/cognitive_complexity_refactoring_progress.md +65 -0
  8. package/.ai/docs/deleted_tools.md +168 -0
  9. package/.ai/docs/deleted_tools_88ced9ef.md +56 -0
  10. package/.ai/docs/image-pasting.md +46 -0
  11. package/.ai/docs/initialize-app.md +117 -0
  12. package/.ai/docs/issue-4-plan.md +44 -0
  13. package/.ai/docs/marked-renderer-debug.md +15 -0
  14. package/.ai/docs/marked-renderer-refactor-plan.md +64 -0
  15. package/.ai/docs/memory-use-cases.md +55 -0
  16. package/.ai/docs/prompt-consistency.md +31 -0
  17. package/.ai/docs/refactoring-tools.md +98 -0
  18. package/.ai/docs/system-prompt-update.md +174 -0
  19. package/.ai/docs/system_prompt.txt +210 -0
  20. package/.ai/docs/tasks.md +49 -0
  21. package/.ai/plan.md +131 -0
  22. package/.ai/prompt.md +1 -0
  23. package/.ai/scripts/fetch_models.js +27 -0
  24. package/.ai/scripts/generateSystemPrompt.ts +15 -0
  25. package/.ai/scripts/list-tools.mjs +4 -0
  26. package/.ai/scripts/p5_geometric_shapes.js +149 -0
  27. package/.husky/commit-msg +1 -0
  28. package/.husky/pre-commit +3 -0
  29. package/.husky/pre-push +1 -0
  30. package/.ignore +4 -0
  31. package/AGENTS.md +25 -0
  32. package/ARCHITECTURE.md +304 -0
  33. package/LICENSE +21 -0
  34. package/README.md +392 -0
  35. package/TODO.md +2 -0
  36. package/biome.json +61 -0
  37. package/commitlint.config.js +3 -0
  38. package/dist/cli.d.ts +19 -0
  39. package/dist/cli.js +116 -0
  40. package/dist/commands/application-log-command.d.ts +2 -0
  41. package/dist/commands/application-log-command.js +43 -0
  42. package/dist/commands/clear-command.d.ts +2 -0
  43. package/dist/commands/clear-command.js +12 -0
  44. package/dist/commands/compact-command.d.ts +2 -0
  45. package/dist/commands/compact-command.js +51 -0
  46. package/dist/commands/copy-command.d.ts +2 -0
  47. package/dist/commands/copy-command.js +51 -0
  48. package/dist/commands/edit-command.d.ts +2 -0
  49. package/dist/commands/edit-command.js +53 -0
  50. package/dist/commands/edit-prompt-command.d.ts +2 -0
  51. package/dist/commands/edit-prompt-command.js +25 -0
  52. package/dist/commands/exit-command.d.ts +2 -0
  53. package/dist/commands/exit-command.js +14 -0
  54. package/dist/commands/files-command.d.ts +2 -0
  55. package/dist/commands/files-command.js +63 -0
  56. package/dist/commands/generate-rules-command.d.ts +2 -0
  57. package/dist/commands/generate-rules-command.js +61 -0
  58. package/dist/commands/help-command.d.ts +2 -0
  59. package/dist/commands/help-command.js +19 -0
  60. package/dist/commands/init-command.d.ts +2 -0
  61. package/dist/commands/init-command.js +40 -0
  62. package/dist/commands/last-log-command.d.ts +2 -0
  63. package/dist/commands/last-log-command.js +76 -0
  64. package/dist/commands/manager.d.ts +22 -0
  65. package/dist/commands/manager.js +123 -0
  66. package/dist/commands/model-command.d.ts +2 -0
  67. package/dist/commands/model-command.js +84 -0
  68. package/dist/commands/paste-command.d.ts +2 -0
  69. package/dist/commands/paste-command.js +40 -0
  70. package/dist/commands/prompt-command.d.ts +2 -0
  71. package/dist/commands/prompt-command.js +111 -0
  72. package/dist/commands/reset-command.d.ts +2 -0
  73. package/dist/commands/reset-command.js +16 -0
  74. package/dist/commands/rules-command.d.ts +2 -0
  75. package/dist/commands/rules-command.js +68 -0
  76. package/dist/commands/save-command.d.ts +2 -0
  77. package/dist/commands/save-command.js +14 -0
  78. package/dist/commands/types.d.ts +26 -0
  79. package/dist/commands/types.js +1 -0
  80. package/dist/commands/usage-command.d.ts +2 -0
  81. package/dist/commands/usage-command.js +21 -0
  82. package/dist/config.d.ts +60 -0
  83. package/dist/config.js +193 -0
  84. package/dist/conversation-analyzer.d.ts +10 -0
  85. package/dist/conversation-analyzer.js +88 -0
  86. package/dist/dedent.d.ts +3 -0
  87. package/dist/dedent.js +38 -0
  88. package/dist/formatting.d.ts +17 -0
  89. package/dist/formatting.js +103 -0
  90. package/dist/index.d.ts +18 -0
  91. package/dist/index.js +213 -0
  92. package/dist/logger.d.ts +2 -0
  93. package/dist/logger.js +24 -0
  94. package/dist/mentions.d.ts +9 -0
  95. package/dist/mentions.js +182 -0
  96. package/dist/messages.d.ts +69 -0
  97. package/dist/messages.js +261 -0
  98. package/dist/middleware/audit-message.d.ts +5 -0
  99. package/dist/middleware/audit-message.js +95 -0
  100. package/dist/middleware/index.d.ts +2 -0
  101. package/dist/middleware/index.js +2 -0
  102. package/dist/middleware/rate-limit.d.ts +4 -0
  103. package/dist/middleware/rate-limit.js +17 -0
  104. package/dist/models/ai-config.d.ts +12 -0
  105. package/dist/models/ai-config.js +87 -0
  106. package/dist/models/anthropic-provider.d.ts +25 -0
  107. package/dist/models/anthropic-provider.js +184 -0
  108. package/dist/models/deepseek-provider.d.ts +20 -0
  109. package/dist/models/deepseek-provider.js +42 -0
  110. package/dist/models/google-provider.d.ts +19 -0
  111. package/dist/models/google-provider.js +56 -0
  112. package/dist/models/manager.d.ts +15 -0
  113. package/dist/models/manager.js +48 -0
  114. package/dist/models/openai-provider.d.ts +22 -0
  115. package/dist/models/openai-provider.js +70 -0
  116. package/dist/models/openrouter-provider.d.ts +36 -0
  117. package/dist/models/openrouter-provider.js +276 -0
  118. package/dist/models/providers.d.ts +33 -0
  119. package/dist/models/providers.js +116 -0
  120. package/dist/models/xai-provider.d.ts +20 -0
  121. package/dist/models/xai-provider.js +47 -0
  122. package/dist/parsing.d.ts +2 -0
  123. package/dist/parsing.js +18 -0
  124. package/dist/prompts/manager.d.ts +19 -0
  125. package/dist/prompts/manager.js +71 -0
  126. package/dist/prompts.d.ts +4 -0
  127. package/dist/prompts.js +158 -0
  128. package/dist/repl-prompt.d.ts +14 -0
  129. package/dist/repl-prompt.js +147 -0
  130. package/dist/repl.d.ts +27 -0
  131. package/dist/repl.js +431 -0
  132. package/dist/source/cli.d.ts +19 -0
  133. package/dist/source/cli.js +116 -0
  134. package/dist/source/commands/application-log-command.d.ts +2 -0
  135. package/dist/source/commands/application-log-command.js +43 -0
  136. package/dist/source/commands/clear-command.d.ts +2 -0
  137. package/dist/source/commands/clear-command.js +12 -0
  138. package/dist/source/commands/compact-command.d.ts +2 -0
  139. package/dist/source/commands/compact-command.js +51 -0
  140. package/dist/source/commands/copy-command.d.ts +2 -0
  141. package/dist/source/commands/copy-command.js +51 -0
  142. package/dist/source/commands/edit-command.d.ts +2 -0
  143. package/dist/source/commands/edit-command.js +53 -0
  144. package/dist/source/commands/edit-prompt-command.d.ts +2 -0
  145. package/dist/source/commands/edit-prompt-command.js +25 -0
  146. package/dist/source/commands/exit-command.d.ts +2 -0
  147. package/dist/source/commands/exit-command.js +14 -0
  148. package/dist/source/commands/files-command.d.ts +2 -0
  149. package/dist/source/commands/files-command.js +63 -0
  150. package/dist/source/commands/generate-rules-command.d.ts +2 -0
  151. package/dist/source/commands/generate-rules-command.js +61 -0
  152. package/dist/source/commands/help-command.d.ts +2 -0
  153. package/dist/source/commands/help-command.js +19 -0
  154. package/dist/source/commands/init-command.d.ts +2 -0
  155. package/dist/source/commands/init-command.js +40 -0
  156. package/dist/source/commands/last-log-command.d.ts +2 -0
  157. package/dist/source/commands/last-log-command.js +76 -0
  158. package/dist/source/commands/manager.d.ts +22 -0
  159. package/dist/source/commands/manager.js +123 -0
  160. package/dist/source/commands/model-command.d.ts +2 -0
  161. package/dist/source/commands/model-command.js +84 -0
  162. package/dist/source/commands/paste-command.d.ts +2 -0
  163. package/dist/source/commands/paste-command.js +40 -0
  164. package/dist/source/commands/prompt-command.d.ts +2 -0
  165. package/dist/source/commands/prompt-command.js +111 -0
  166. package/dist/source/commands/reset-command.d.ts +2 -0
  167. package/dist/source/commands/reset-command.js +16 -0
  168. package/dist/source/commands/rules-command.d.ts +2 -0
  169. package/dist/source/commands/rules-command.js +68 -0
  170. package/dist/source/commands/save-command.d.ts +2 -0
  171. package/dist/source/commands/save-command.js +14 -0
  172. package/dist/source/commands/types.d.ts +26 -0
  173. package/dist/source/commands/types.js +1 -0
  174. package/dist/source/commands/usage-command.d.ts +2 -0
  175. package/dist/source/commands/usage-command.js +21 -0
  176. package/dist/source/config.d.ts +60 -0
  177. package/dist/source/config.js +193 -0
  178. package/dist/source/conversation-analyzer.d.ts +10 -0
  179. package/dist/source/conversation-analyzer.js +88 -0
  180. package/dist/source/dedent.d.ts +3 -0
  181. package/dist/source/dedent.js +38 -0
  182. package/dist/source/formatting.d.ts +17 -0
  183. package/dist/source/formatting.js +103 -0
  184. package/dist/source/index.d.ts +18 -0
  185. package/dist/source/index.js +213 -0
  186. package/dist/source/logger.d.ts +2 -0
  187. package/dist/source/logger.js +24 -0
  188. package/dist/source/mentions.d.ts +9 -0
  189. package/dist/source/mentions.js +182 -0
  190. package/dist/source/messages.d.ts +69 -0
  191. package/dist/source/messages.js +261 -0
  192. package/dist/source/middleware/audit-message.d.ts +5 -0
  193. package/dist/source/middleware/audit-message.js +95 -0
  194. package/dist/source/middleware/index.d.ts +2 -0
  195. package/dist/source/middleware/index.js +2 -0
  196. package/dist/source/middleware/rate-limit.d.ts +4 -0
  197. package/dist/source/middleware/rate-limit.js +17 -0
  198. package/dist/source/models/ai-config.d.ts +12 -0
  199. package/dist/source/models/ai-config.js +87 -0
  200. package/dist/source/models/anthropic-provider.d.ts +25 -0
  201. package/dist/source/models/anthropic-provider.js +184 -0
  202. package/dist/source/models/deepseek-provider.d.ts +20 -0
  203. package/dist/source/models/deepseek-provider.js +42 -0
  204. package/dist/source/models/google-provider.d.ts +19 -0
  205. package/dist/source/models/google-provider.js +56 -0
  206. package/dist/source/models/manager.d.ts +15 -0
  207. package/dist/source/models/manager.js +48 -0
  208. package/dist/source/models/openai-provider.d.ts +22 -0
  209. package/dist/source/models/openai-provider.js +70 -0
  210. package/dist/source/models/openrouter-provider.d.ts +36 -0
  211. package/dist/source/models/openrouter-provider.js +276 -0
  212. package/dist/source/models/providers.d.ts +33 -0
  213. package/dist/source/models/providers.js +116 -0
  214. package/dist/source/models/xai-provider.d.ts +20 -0
  215. package/dist/source/models/xai-provider.js +47 -0
  216. package/dist/source/parsing.d.ts +2 -0
  217. package/dist/source/parsing.js +18 -0
  218. package/dist/source/prompts/manager.d.ts +19 -0
  219. package/dist/source/prompts/manager.js +71 -0
  220. package/dist/source/prompts.d.ts +4 -0
  221. package/dist/source/prompts.js +158 -0
  222. package/dist/source/repl-prompt.d.ts +14 -0
  223. package/dist/source/repl-prompt.js +147 -0
  224. package/dist/source/repl.d.ts +27 -0
  225. package/dist/source/repl.js +431 -0
  226. package/dist/source/terminal/formatting.d.ts +37 -0
  227. package/dist/source/terminal/formatting.js +106 -0
  228. package/dist/source/terminal/index.d.ts +94 -0
  229. package/dist/source/terminal/index.js +420 -0
  230. package/dist/source/terminal/markdown-utils.d.ts +2 -0
  231. package/dist/source/terminal/markdown-utils.js +81 -0
  232. package/dist/source/terminal/markdown.d.ts +1 -0
  233. package/dist/source/terminal/markdown.js +111 -0
  234. package/dist/source/terminal/types.d.ts +71 -0
  235. package/dist/source/terminal/types.js +1 -0
  236. package/dist/source/terminal-output.d.ts +8 -0
  237. package/dist/source/terminal-output.js +213 -0
  238. package/dist/source/terminal-output.test.d.ts +8 -0
  239. package/dist/source/terminal-output.test.js +213 -0
  240. package/dist/source/token-tracker.d.ts +14 -0
  241. package/dist/source/token-tracker.js +53 -0
  242. package/dist/source/token-utils.d.ts +7 -0
  243. package/dist/source/token-utils.js +13 -0
  244. package/dist/source/tools/agent.d.ts +17 -0
  245. package/dist/source/tools/agent.js +87 -0
  246. package/dist/source/tools/bash.d.ts +19 -0
  247. package/dist/source/tools/bash.js +294 -0
  248. package/dist/source/tools/code-interpreter.d.ts +12 -0
  249. package/dist/source/tools/code-interpreter.js +131 -0
  250. package/dist/source/tools/command-validation.d.ts +8 -0
  251. package/dist/source/tools/command-validation.js +69 -0
  252. package/dist/source/tools/delete-file.d.ts +12 -0
  253. package/dist/source/tools/delete-file.js +56 -0
  254. package/dist/source/tools/directory-tree.d.ts +12 -0
  255. package/dist/source/tools/directory-tree.js +38 -0
  256. package/dist/source/tools/edit-file.d.ts +19 -0
  257. package/dist/source/tools/edit-file.js +107 -0
  258. package/dist/source/tools/filesystem-utils.d.ts +22 -0
  259. package/dist/source/tools/filesystem-utils.js +191 -0
  260. package/dist/source/tools/git-utils.d.ts +14 -0
  261. package/dist/source/tools/git-utils.js +64 -0
  262. package/dist/source/tools/grep.d.ts +17 -0
  263. package/dist/source/tools/grep.js +138 -0
  264. package/dist/source/tools/index.d.ts +161 -0
  265. package/dist/source/tools/index.js +209 -0
  266. package/dist/source/tools/memory-read.d.ts +13 -0
  267. package/dist/source/tools/memory-read.js +135 -0
  268. package/dist/source/tools/memory-write.d.ts +12 -0
  269. package/dist/source/tools/memory-write.js +83 -0
  270. package/dist/source/tools/move-file.d.ts +13 -0
  271. package/dist/source/tools/move-file.js +44 -0
  272. package/dist/source/tools/read-file.d.ts +17 -0
  273. package/dist/source/tools/read-file.js +86 -0
  274. package/dist/source/tools/read-multiple-files.d.ts +14 -0
  275. package/dist/source/tools/read-multiple-files.js +55 -0
  276. package/dist/source/tools/save-file.d.ts +17 -0
  277. package/dist/source/tools/save-file.js +98 -0
  278. package/dist/source/tools/think.d.ts +11 -0
  279. package/dist/source/tools/think.js +45 -0
  280. package/dist/source/tools/types.d.ts +29 -0
  281. package/dist/source/tools/types.js +14 -0
  282. package/dist/source/tools/web-fetch.d.ts +47 -0
  283. package/dist/source/tools/web-fetch.js +246 -0
  284. package/dist/source/tools/web-search.d.ts +13 -0
  285. package/dist/source/tools/web-search.js +80 -0
  286. package/dist/source/utils/process.d.ts +36 -0
  287. package/dist/source/utils/process.js +75 -0
  288. package/dist/source/version.d.ts +1 -0
  289. package/dist/source/version.js +21 -0
  290. package/dist/terminal/formatting.d.ts +37 -0
  291. package/dist/terminal/formatting.js +106 -0
  292. package/dist/terminal/index.d.ts +94 -0
  293. package/dist/terminal/index.js +420 -0
  294. package/dist/terminal/markdown-utils.d.ts +2 -0
  295. package/dist/terminal/markdown-utils.js +81 -0
  296. package/dist/terminal/markdown.d.ts +1 -0
  297. package/dist/terminal/markdown.js +111 -0
  298. package/dist/terminal/types.d.ts +71 -0
  299. package/dist/terminal/types.js +1 -0
  300. package/dist/terminal-output.d.ts +8 -0
  301. package/dist/terminal-output.js +213 -0
  302. package/dist/token-tracker.d.ts +14 -0
  303. package/dist/token-tracker.js +53 -0
  304. package/dist/token-utils.d.ts +7 -0
  305. package/dist/token-utils.js +13 -0
  306. package/dist/tools/agent.d.ts +17 -0
  307. package/dist/tools/agent.js +87 -0
  308. package/dist/tools/bash.d.ts +19 -0
  309. package/dist/tools/bash.js +294 -0
  310. package/dist/tools/code-interpreter.d.ts +12 -0
  311. package/dist/tools/code-interpreter.js +131 -0
  312. package/dist/tools/command-validation.d.ts +8 -0
  313. package/dist/tools/command-validation.js +69 -0
  314. package/dist/tools/delete-file.d.ts +12 -0
  315. package/dist/tools/delete-file.js +56 -0
  316. package/dist/tools/directory-tree.d.ts +12 -0
  317. package/dist/tools/directory-tree.js +38 -0
  318. package/dist/tools/edit-file.d.ts +19 -0
  319. package/dist/tools/edit-file.js +107 -0
  320. package/dist/tools/filesystem-utils.d.ts +22 -0
  321. package/dist/tools/filesystem-utils.js +191 -0
  322. package/dist/tools/git-utils.d.ts +14 -0
  323. package/dist/tools/git-utils.js +64 -0
  324. package/dist/tools/grep.d.ts +17 -0
  325. package/dist/tools/grep.js +138 -0
  326. package/dist/tools/index.d.ts +161 -0
  327. package/dist/tools/index.js +209 -0
  328. package/dist/tools/memory-read.d.ts +13 -0
  329. package/dist/tools/memory-read.js +135 -0
  330. package/dist/tools/memory-write.d.ts +12 -0
  331. package/dist/tools/memory-write.js +83 -0
  332. package/dist/tools/move-file.d.ts +13 -0
  333. package/dist/tools/move-file.js +44 -0
  334. package/dist/tools/read-file.d.ts +17 -0
  335. package/dist/tools/read-file.js +86 -0
  336. package/dist/tools/read-multiple-files.d.ts +14 -0
  337. package/dist/tools/read-multiple-files.js +55 -0
  338. package/dist/tools/save-file.d.ts +17 -0
  339. package/dist/tools/save-file.js +98 -0
  340. package/dist/tools/think.d.ts +11 -0
  341. package/dist/tools/think.js +45 -0
  342. package/dist/tools/types.d.ts +29 -0
  343. package/dist/tools/types.js +14 -0
  344. package/dist/tools/web-fetch.d.ts +47 -0
  345. package/dist/tools/web-fetch.js +246 -0
  346. package/dist/tools/web-search.d.ts +13 -0
  347. package/dist/tools/web-search.js +80 -0
  348. package/dist/utils/process.d.ts +36 -0
  349. package/dist/utils/process.js +75 -0
  350. package/dist/version.d.ts +1 -0
  351. package/dist/version.js +21 -0
  352. package/knip.json +5 -0
  353. package/package.json +83 -0
  354. package/source/cli.ts +172 -0
  355. package/source/commands/application-log-command.ts +53 -0
  356. package/source/commands/clear-command.ts +14 -0
  357. package/source/commands/compact-command.ts +64 -0
  358. package/source/commands/copy-command.ts +55 -0
  359. package/source/commands/edit-command.ts +63 -0
  360. package/source/commands/edit-prompt-command.ts +31 -0
  361. package/source/commands/exit-command.ts +18 -0
  362. package/source/commands/files-command.ts +85 -0
  363. package/source/commands/generate-rules-command.ts +82 -0
  364. package/source/commands/help-command.ts +27 -0
  365. package/source/commands/init-command.ts +48 -0
  366. package/source/commands/last-log-command.ts +88 -0
  367. package/source/commands/manager.ts +151 -0
  368. package/source/commands/model-command.ts +123 -0
  369. package/source/commands/paste-command.ts +62 -0
  370. package/source/commands/prompt-command.ts +150 -0
  371. package/source/commands/reset-command.ts +22 -0
  372. package/source/commands/rules-command.ts +76 -0
  373. package/source/commands/save-command.ts +20 -0
  374. package/source/commands/types.ts +28 -0
  375. package/source/commands/usage-command.ts +26 -0
  376. package/source/config.ts +223 -0
  377. package/source/conversation-analyzer.ts +115 -0
  378. package/source/dedent.ts +53 -0
  379. package/source/formatting.ts +132 -0
  380. package/source/index.ts +240 -0
  381. package/source/logger.ts +29 -0
  382. package/source/mentions.ts +227 -0
  383. package/source/messages.ts +360 -0
  384. package/source/middleware/audit-message.ts +133 -0
  385. package/source/middleware/index.ts +2 -0
  386. package/source/middleware/rate-limit.ts +24 -0
  387. package/source/models/ai-config.ts +109 -0
  388. package/source/models/anthropic-provider.ts +199 -0
  389. package/source/models/deepseek-provider.ts +53 -0
  390. package/source/models/google-provider.ts +68 -0
  391. package/source/models/manager.ts +84 -0
  392. package/source/models/openai-provider.ts +81 -0
  393. package/source/models/openrouter-provider.ts +288 -0
  394. package/source/models/providers.ts +197 -0
  395. package/source/models/xai-provider.ts +59 -0
  396. package/source/parsing.ts +20 -0
  397. package/source/prompts/manager.ts +90 -0
  398. package/source/prompts.ts +172 -0
  399. package/source/repl-prompt.ts +196 -0
  400. package/source/repl.ts +572 -0
  401. package/source/terminal/formatting.ts +121 -0
  402. package/source/terminal/index.ts +518 -0
  403. package/source/terminal/markdown-utils.ts +89 -0
  404. package/source/terminal/markdown.ts +155 -0
  405. package/source/terminal/types.ts +84 -0
  406. package/source/terminal-output.test.ts +266 -0
  407. package/source/token-tracker.ts +78 -0
  408. package/source/token-utils.ts +17 -0
  409. package/source/tools/agent.ts +107 -0
  410. package/source/tools/bash.ts +367 -0
  411. package/source/tools/code-interpreter.ts +172 -0
  412. package/source/tools/command-validation.ts +81 -0
  413. package/source/tools/delete-file.ts +71 -0
  414. package/source/tools/directory-tree.ts +54 -0
  415. package/source/tools/edit-file.ts +155 -0
  416. package/source/tools/filesystem-utils.ts +265 -0
  417. package/source/tools/git-utils.ts +70 -0
  418. package/source/tools/grep.ts +184 -0
  419. package/source/tools/index.ts +278 -0
  420. package/source/tools/memory-read.ts +174 -0
  421. package/source/tools/memory-write.ts +105 -0
  422. package/source/tools/move-file.ts +59 -0
  423. package/source/tools/read-file.ts +129 -0
  424. package/source/tools/read-multiple-files.ts +80 -0
  425. package/source/tools/save-file.ts +147 -0
  426. package/source/tools/think.ts +51 -0
  427. package/source/tools/types.ts +58 -0
  428. package/source/tools/web-fetch.ts +327 -0
  429. package/source/tools/web-search.ts +101 -0
  430. package/source/utils/process.ts +121 -0
  431. package/source/version.ts +21 -0
  432. package/test/commands/copy-command.test.ts +69 -0
  433. package/test/config.test.ts +200 -0
  434. package/test/terminal/markdown-utils.test.ts +124 -0
  435. package/test/tools/bash-tool.test.ts +58 -0
  436. package/test/tools/code-interpreter.test.ts +91 -0
  437. package/test/tools/command-validation.test.ts +48 -0
  438. package/tsconfig.build.json +9 -0
  439. package/tsconfig.json +30 -0
@@ -0,0 +1,240 @@
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();
@@ -0,0 +1,29 @@
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
+ );
@@ -0,0 +1,227 @@
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
+ }