@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,200 @@
1
+ import assert from "node:assert/strict";
2
+ import fs from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test from "node:test";
6
+
7
+ import { ConfigManager, DirectoryProvider } from "../source/config.ts";
8
+
9
+ // Helper to create and cleanup a temp directory
10
+ async function withTempDir<T>(fn: (dir: string) => Promise<T>) {
11
+ const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "acai-test-"));
12
+ try {
13
+ return await fn(tmp);
14
+ } finally {
15
+ // best-effort cleanup
16
+ try {
17
+ await fs.rm(tmp, { recursive: true, force: true });
18
+ } catch {}
19
+ }
20
+ }
21
+
22
+ test("DirectoryProvider.ensurePath async and sync create directories", async () => {
23
+ await withTempDir(async (tmp) => {
24
+ const base = path.join(tmp, "base");
25
+ const dp = new DirectoryProvider(base);
26
+
27
+ const asyncDir = await dp.ensurePath("async-sub");
28
+ const stat = await fs.stat(asyncDir);
29
+ assert(stat.isDirectory(), "async-created path should be a directory");
30
+
31
+ const syncDir = dp.ensurePathSync("sync-sub");
32
+ const stat2 = await fs.stat(syncDir);
33
+ assert(stat2.isDirectory(), "sync-created path should be a directory");
34
+ });
35
+ });
36
+
37
+ test("ConfigManager.ensureAppConfig creates default app config in HOME", async () => {
38
+ await withTempDir(async (tmpHome) => {
39
+ const oldHome = process.env.HOME;
40
+ try {
41
+ process.env.HOME = tmpHome;
42
+
43
+ const mgr = new ConfigManager();
44
+ const cfg = await mgr.ensureAppConfig("acai");
45
+
46
+ // Defaults expected
47
+ assert.equal((cfg as Record<string, unknown>).notify, true);
48
+ assert.equal(
49
+ ((cfg as Record<string, unknown>).tools as Record<string, unknown>)
50
+ .maxTokens as number,
51
+ 30000,
52
+ );
53
+
54
+ const configPath = path.join(tmpHome, ".acai", "acai.json");
55
+ const data = JSON.parse(await fs.readFile(configPath, "utf8"));
56
+ assert.equal(data.notify, true);
57
+ assert.equal(data.tools.maxTokens, 30000);
58
+ } finally {
59
+ if (oldHome !== undefined) process.env.HOME = oldHome;
60
+ }
61
+ });
62
+ });
63
+
64
+ test("writeProjectLearnedRulesFile creates project rules file inside .acai", async () => {
65
+ await withTempDir(async (tmpProject) => {
66
+ const oldCwd = process.cwd();
67
+ try {
68
+ process.chdir(tmpProject);
69
+ const mgr = new ConfigManager();
70
+
71
+ await mgr.writeProjectLearnedRulesFile("# rules\nhello");
72
+
73
+ const target = path.join(
74
+ tmpProject,
75
+ ".acai",
76
+ "rules",
77
+ "learned-rules.md",
78
+ );
79
+ const content = await fs.readFile(target, "utf8");
80
+ assert(content.includes("hello"));
81
+
82
+ // readProjectLearnedRulesFile should return the same content
83
+ const read = await mgr.readProjectLearnedRulesFile();
84
+ assert(read.includes("hello"));
85
+ } finally {
86
+ process.chdir(oldCwd);
87
+ }
88
+ });
89
+ });
90
+
91
+ test("writeCachedLearnedRulesFile and readCachedLearnedRulesFile in HOME", async () => {
92
+ await withTempDir(async (tmpHome) => {
93
+ const oldHome = process.env.HOME;
94
+ try {
95
+ process.env.HOME = tmpHome;
96
+ const mgr = new ConfigManager();
97
+
98
+ await mgr.writeCachedLearnedRulesFile("cached rules\nabc");
99
+ const content = await mgr.readCachedLearnedRulesFile();
100
+ assert(content.includes("abc"));
101
+
102
+ // Removing file should cause read to return empty string
103
+ const filePath = path.join(tmpHome, ".acai", "rules", "learned-rules.md");
104
+ await fs.rm(filePath);
105
+ const missing = await mgr.readCachedLearnedRulesFile();
106
+ assert.equal(missing, "");
107
+ } finally {
108
+ if (oldHome !== undefined) process.env.HOME = oldHome;
109
+ }
110
+ });
111
+ });
112
+
113
+ test("readAppConfig returns {} for missing and throws for malformed", async () => {
114
+ await withTempDir(async (tmpHome) => {
115
+ const oldHome = process.env.HOME;
116
+ try {
117
+ process.env.HOME = tmpHome;
118
+ const mgr = new ConfigManager();
119
+
120
+ const missing = await mgr.readAppConfig("nonexistent");
121
+ assert.deepEqual(missing, {});
122
+
123
+ // Create malformed JSON
124
+ const cfgDir = path.join(tmpHome, ".acai");
125
+ await fs.mkdir(cfgDir, { recursive: true });
126
+ const cfgPath = path.join(cfgDir, "bad.json");
127
+ await fs.writeFile(cfgPath, "{ invalid json", "utf8");
128
+
129
+ let threw = false;
130
+ try {
131
+ await mgr.readAppConfig("bad");
132
+ } catch (_e) {
133
+ threw = true;
134
+ }
135
+ assert.equal(threw, true, "readAppConfig should throw on malformed JSON");
136
+ } finally {
137
+ if (oldHome !== undefined) process.env.HOME = oldHome;
138
+ }
139
+ });
140
+ });
141
+
142
+ test("readProjectConfig merges app and project configs with project precedence", async () => {
143
+ await withTempDir(async (tmpHome) => {
144
+ const oldHome = process.env.HOME;
145
+ const oldCwd = process.cwd();
146
+ try {
147
+ process.env.HOME = tmpHome;
148
+ const projectDir = path.join(tmpHome, "proj");
149
+ await fs.mkdir(projectDir, { recursive: true });
150
+ process.chdir(projectDir);
151
+
152
+ // write app config in HOME
153
+ const appCfgDir = path.join(tmpHome, ".acai");
154
+ await fs.mkdir(appCfgDir, { recursive: true });
155
+ const appCfg = { tools: { maxTokens: 100 }, notify: true };
156
+ await fs.writeFile(
157
+ path.join(appCfgDir, "acai.json"),
158
+ JSON.stringify(appCfg),
159
+ "utf8",
160
+ );
161
+
162
+ // write project config overriding tools.maxTokens and notify
163
+ const projCfgDir = path.join(projectDir, ".acai");
164
+ await fs.mkdir(path.join(projCfgDir), { recursive: true });
165
+ const projCfg = { tools: { maxTokens: 50 }, notify: false };
166
+ await fs.writeFile(
167
+ path.join(projCfgDir, "acai.json"),
168
+ JSON.stringify(projCfg),
169
+ "utf8",
170
+ );
171
+
172
+ const mgr = new ConfigManager();
173
+ const merged = await mgr.readProjectConfig();
174
+ assert.equal(merged.tools.maxTokens, 50);
175
+ assert.equal(merged.notify, false);
176
+ } finally {
177
+ if (oldHome !== undefined) process.env.HOME = oldHome;
178
+ process.chdir(oldCwd);
179
+ }
180
+ });
181
+ });
182
+
183
+ test("readAgentsFile and writeAgentsFile operate in CWD", async () => {
184
+ await withTempDir(async (tmpCwd) => {
185
+ const oldCwd = process.cwd();
186
+ try {
187
+ process.chdir(tmpCwd);
188
+ const mgr = new ConfigManager();
189
+
190
+ const initial = await mgr.readAgentsFile();
191
+ assert.equal(initial, "");
192
+
193
+ await mgr.writeAgentsFile("# Agents\nagent1");
194
+ const content = await mgr.readAgentsFile();
195
+ assert(content.includes("agent1"));
196
+ } finally {
197
+ process.chdir(oldCwd);
198
+ }
199
+ });
200
+ });
@@ -0,0 +1,124 @@
1
+ import { strict as assert } from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import {
4
+ getListNumber,
5
+ isMarkdown,
6
+ } from "../../source/terminal/markdown-utils.ts";
7
+
8
+ describe("isMarkdown", () => {
9
+ it("should return true for markdown headings", () => {
10
+ assert.strictEqual(isMarkdown("# Heading 1"), true);
11
+ assert.strictEqual(isMarkdown("## Heading 2"), true);
12
+ assert.strictEqual(isMarkdown("### Heading 3"), true);
13
+ assert.strictEqual(isMarkdown("#### Heading 4"), true);
14
+ assert.strictEqual(isMarkdown("##### Heading 5"), true);
15
+ assert.strictEqual(isMarkdown("###### Heading 6"), true);
16
+ });
17
+
18
+ it("should return true for markdown bold text", () => {
19
+ assert.strictEqual(isMarkdown("**bold text**"), true);
20
+ assert.strictEqual(isMarkdown("__bold text__"), true);
21
+ });
22
+
23
+ it("should return true for markdown italic text", () => {
24
+ assert.strictEqual(isMarkdown("*italic text*"), true);
25
+ assert.strictEqual(isMarkdown("_italic text_"), true);
26
+ });
27
+
28
+ it("should return true for markdown code blocks", () => {
29
+ assert.strictEqual(isMarkdown("`code`"), true);
30
+ assert.strictEqual(isMarkdown("```code block```"), true);
31
+ });
32
+
33
+ it("should return true for markdown links", () => {
34
+ assert.strictEqual(isMarkdown("(alt text](url)"), true);
35
+ });
36
+
37
+ it("should return true for markdown blockquotes", () => {
38
+ assert.strictEqual(isMarkdown("> blockquote"), true);
39
+ });
40
+
41
+ it("should return true for markdown unordered lists", () => {
42
+ assert.strictEqual(isMarkdown("- list item"), true);
43
+ assert.strictEqual(isMarkdown("* list item"), true);
44
+ assert.strictEqual(isMarkdown("+ list item"), true);
45
+ });
46
+
47
+ it("should return true for markdown ordered lists", () => {
48
+ assert.strictEqual(isMarkdown("1. list item"), true);
49
+ });
50
+
51
+ it("should return true for markdown horizontal rules", () => {
52
+ assert.strictEqual(isMarkdown("---"), true);
53
+ });
54
+
55
+ it("should return true for markdown images", () => {
56
+ assert.strictEqual(isMarkdown("![alt text](url)"), true);
57
+ });
58
+
59
+ it("should return false for plain text", () => {
60
+ assert.strictEqual(isMarkdown("This is plain text."), false);
61
+ });
62
+
63
+ it("should return false for an empty string", () => {
64
+ assert.strictEqual(isMarkdown(""), false);
65
+ });
66
+
67
+ it("should return true for mixed markdown content", () => {
68
+ assert.strictEqual(
69
+ isMarkdown("# Heading\nSome *italic* and **bold** text."),
70
+ true,
71
+ );
72
+ });
73
+ });
74
+
75
+ describe("getListNumber", () => {
76
+ it("should return arabic numerals for depth 0", () => {
77
+ assert.strictEqual(getListNumber(0, 1), "1");
78
+ assert.strictEqual(getListNumber(0, 10), "10");
79
+ assert.strictEqual(getListNumber(0, 0), "0"); // Though practically, list numbers start from 1
80
+ });
81
+
82
+ it("should return arabic numerals for depth 1", () => {
83
+ assert.strictEqual(getListNumber(1, 1), "1");
84
+ assert.strictEqual(getListNumber(1, 5), "5");
85
+ });
86
+
87
+ it("should return lowercase letters for depth 2", () => {
88
+ assert.strictEqual(getListNumber(2, 1), "a");
89
+ assert.strictEqual(getListNumber(2, 26), "z");
90
+ assert.strictEqual(getListNumber(2, 27), "aa");
91
+ assert.strictEqual(getListNumber(2, 0), "");
92
+ });
93
+
94
+ it("should return lowercase Roman numerals for depth 3", () => {
95
+ assert.strictEqual(getListNumber(3, 1), "i");
96
+ assert.strictEqual(getListNumber(3, 4), "iv");
97
+ assert.strictEqual(getListNumber(3, 9), "ix");
98
+ assert.strictEqual(getListNumber(3, 10), "x");
99
+ assert.strictEqual(getListNumber(3, 40), "xl");
100
+ assert.strictEqual(getListNumber(3, 0), "");
101
+ });
102
+
103
+ it("should return arabic numerals for depth greater than 3 (default case)", () => {
104
+ assert.strictEqual(getListNumber(4, 1), "1");
105
+ assert.strictEqual(getListNumber(10, 5), "5");
106
+ });
107
+
108
+ it("should handle various numbers for depth 1 list (arabic)", () => {
109
+ assert.strictEqual(getListNumber(1, 123), "123");
110
+ });
111
+
112
+ it("should handle various numbers for depth 2 list (letters)", () => {
113
+ assert.strictEqual(getListNumber(2, 52), "az");
114
+ assert.strictEqual(getListNumber(2, 702), "zz");
115
+ assert.strictEqual(getListNumber(2, 703), "aaa");
116
+ });
117
+
118
+ it("should handle various numbers for depth 3 list (roman)", () => {
119
+ assert.strictEqual(getListNumber(3, 49), "xlix");
120
+ assert.strictEqual(getListNumber(3, 99), "xcix");
121
+ assert.strictEqual(getListNumber(3, 499), "cdxcix");
122
+ assert.strictEqual(getListNumber(3, 1994), "mcmxciv");
123
+ });
124
+ });
@@ -0,0 +1,58 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import { config } from "../../source/config.ts";
4
+ import { createBashTool } from "../../source/tools/bash.ts";
5
+
6
+ // Minimal token counter mock
7
+ const tokenCounter = { count: (s: string) => s.length } as const;
8
+
9
+ await config.readProjectConfig();
10
+
11
+ const baseDir = process.cwd();
12
+
13
+ describe("bash tool path validation for git message flags", () => {
14
+ const { bash } = createBashTool({
15
+ baseDir,
16
+ tokenCounter,
17
+ autoAcceptAll: true,
18
+ });
19
+
20
+ async function run(command: string) {
21
+ const toolImpl = bash as unknown as {
22
+ execute: (
23
+ args: { command: string; cwd: string; timeout: number },
24
+ meta: { toolCallId: string },
25
+ ) => Promise<string>;
26
+ };
27
+ const result = await toolImpl.execute(
28
+ { command, cwd: baseDir, timeout: 1000 },
29
+ { toolCallId: "t1" },
30
+ );
31
+ return String(result);
32
+ }
33
+
34
+ it("allows commit messages with /copy", async () => {
35
+ const res = await run('echo ok && git commit -m "docs: mention /copy"');
36
+ assert.ok(!res.includes("references path outside"));
37
+ });
38
+
39
+ it("allows URLs in messages", async () => {
40
+ const res = await run('git commit -m "URL https://example.com/p/a/t/h"');
41
+ assert.ok(!res.includes("references path outside"));
42
+ });
43
+
44
+ it("rejects absolute path in git add", async () => {
45
+ const res = await run("git add /etc/hosts");
46
+ assert.ok(res.includes("references path outside"));
47
+ });
48
+
49
+ it("rejects commit -F with file outside", async () => {
50
+ const res = await run("git commit -F /tmp/message.txt");
51
+ assert.ok(res.includes("references path outside"));
52
+ });
53
+
54
+ it("handles multiple -m flags", async () => {
55
+ const res = await run('git commit -m "first /copy" -m "second /path"');
56
+ assert.ok(!res.includes("references path outside"));
57
+ });
58
+ });
@@ -0,0 +1,91 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import {
4
+ CodeInterpreterTool,
5
+ createCodeInterpreterTool,
6
+ } from "../../source/tools/code-interpreter.ts";
7
+
8
+ // Helper to run the tool easily
9
+ async function runTool(input: {
10
+ code: string;
11
+ timeoutSeconds?: number;
12
+ }): Promise<{ ok: boolean; value: unknown }> {
13
+ const events: Array<{ event: string; data: unknown }> = [];
14
+ const { [CodeInterpreterTool.name]: tool } = createCodeInterpreterTool({
15
+ sendData: async (msg) => {
16
+ events.push({ event: msg.event, data: msg.data });
17
+ },
18
+ });
19
+
20
+ const output = await tool.execute(
21
+ input as never,
22
+ { toolCallId: "t1" } as never,
23
+ );
24
+ if (typeof output === "string" && output.startsWith("{")) {
25
+ return { ok: true, value: JSON.parse(output) };
26
+ }
27
+ return { ok: false, value: output };
28
+ }
29
+
30
+ describe("code-interpreter tool", () => {
31
+ it("executes simple console.log", async () => {
32
+ const res = await runTool({ code: "console.log('ok');" });
33
+ assert.equal(res.ok, true);
34
+ const v = res.value as { stdout: string; stderr: string; exitCode: number };
35
+ assert.equal(v.exitCode, 0);
36
+ assert.equal(v.stdout.trim(), "ok");
37
+ // Ignore stderr in this test due to environment-specific Node warnings.
38
+ assert.equal(typeof v.stderr, "string");
39
+ });
40
+
41
+ it("enforces timeout", async () => {
42
+ const res = await runTool({ code: "for(;;){}", timeoutSeconds: 1 });
43
+ assert.equal(res.ok, false);
44
+ assert.equal(res.value, "Script timed out");
45
+ });
46
+
47
+ it("allows fs within cwd", async () => {
48
+ const code = `
49
+ import { writeFileSync, readFileSync, rmSync } from 'node:fs';
50
+ writeFileSync('tmp_test_file.txt', 'hello', { encoding: 'utf8' });
51
+ const s = readFileSync('tmp_test_file.txt', { encoding: 'utf8' });
52
+ console.log(s);
53
+ rmSync('tmp_test_file.txt', { force: true });
54
+ `;
55
+ const res = await runTool({ code });
56
+ assert.equal(res.ok, true);
57
+ const v = res.value as { stdout: string };
58
+ assert.equal(v.stdout.trim(), "hello");
59
+ });
60
+
61
+ it("denies fs outside cwd", async () => {
62
+ const code = `
63
+ import { writeFileSync } from 'node:fs';
64
+ import { resolve } from 'node:path';
65
+ writeFileSync(resolve('..', 'should_not_write.txt'), 'x', { encoding: 'utf8' });
66
+ console.log('done');
67
+ `;
68
+ const res = await runTool({ code });
69
+ assert.equal(res.ok, false);
70
+ assert.match(String(res.value), /Process exited with code|permission/i);
71
+ });
72
+
73
+ it("denies child_process", async () => {
74
+ const code = `
75
+ import { spawnSync } from 'node:child_process';
76
+ const r = spawnSync('node', ['-v']);
77
+ console.log(String(r.stdout || ''));
78
+ `;
79
+ const res = await runTool({ code });
80
+ assert.equal(res.ok, false);
81
+ });
82
+
83
+ it("denies network", async () => {
84
+ const code = `
85
+ import https from 'node:https';
86
+ https.get('https://example.com', (res) => { console.log('status', res.statusCode); }).on('error', (e) => { console.error(String(e)); });
87
+ `;
88
+ const res = await runTool({ code });
89
+ assert.equal(res.ok, false);
90
+ });
91
+ });
@@ -0,0 +1,48 @@
1
+ import assert from "node:assert";
2
+ import { describe, it } from "node:test";
3
+ import { CommandValidation } from "../../source/tools/command-validation.ts";
4
+
5
+ describe("CommandValidation", () => {
6
+ const allowedCommands = ["ls", "pwd", "echo", "grep", "sleep"];
7
+ const validator = new CommandValidation(allowedCommands);
8
+
9
+ describe("Valid Commands", () => {
10
+ it("allows ls && pwd", () => {
11
+ assert.strictEqual(validator.isValid("ls && pwd"), true);
12
+ });
13
+
14
+ it("allows echo 'hi' || ls", () => {
15
+ assert.strictEqual(validator.isValid("echo 'hi' || ls"), true);
16
+ });
17
+
18
+ it("allows ls; pwd", () => {
19
+ assert.strictEqual(validator.isValid("ls; pwd"), true);
20
+ });
21
+
22
+ it("allows ls | grep .ts", () => {
23
+ assert.strictEqual(validator.isValid("ls | grep .ts"), true);
24
+ });
25
+
26
+ it("allows sleep 1 &", () => {
27
+ assert.strictEqual(validator.isValid("sleep 1 &"), true);
28
+ });
29
+ });
30
+
31
+ describe("Invalid Commands", () => {
32
+ it("blocks ls > file (unsafe operator)", () => {
33
+ assert.strictEqual(validator.isValid("ls > file"), false);
34
+ });
35
+
36
+ it("blocks echo $(date) (unsafe operator)", () => {
37
+ assert.strictEqual(validator.isValid("echo $(date)"), false);
38
+ });
39
+
40
+ it("blocks rm -rf / (disallowed command)", () => {
41
+ assert.strictEqual(validator.isValid("rm -rf /"), false);
42
+ });
43
+
44
+ it("blocks empty command", () => {
45
+ assert.strictEqual(validator.isValid(""), false);
46
+ });
47
+ });
48
+ });
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": ["test", "**/*.test.ts"],
4
+ "compilerOptions": {
5
+ "rootDir": "source",
6
+ "outDir": "dist"
7
+ }
8
+ }
9
+
package/tsconfig.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "./dist",
4
+ "target": "ESNext",
5
+ "module": "ESNext",
6
+ "declaration": true,
7
+ "composite": true,
8
+ "moduleResolution": "Bundler",
9
+ "strict": true,
10
+ "allowUnusedLabels": false,
11
+ "allowUnreachableCode": false,
12
+ "exactOptionalPropertyTypes": false,
13
+ "noFallthroughCasesInSwitch": true,
14
+ "noImplicitOverride": true,
15
+ "noImplicitReturns": true,
16
+ "noPropertyAccessFromIndexSignature": true,
17
+ "noUncheckedIndexedAccess": true,
18
+ "noUnusedLocals": true,
19
+ "noUnusedParameters": true,
20
+ "isolatedModules": true,
21
+ "checkJs": true,
22
+ "skipLibCheck": true,
23
+ "rewriteRelativeImportExtensions": true,
24
+ "types": ["node"],
25
+ "lib": ["ESNext"]
26
+ },
27
+ "include": ["source/**/*.ts"],
28
+ "$schema": "https://json.schemastore.org/tsconfig",
29
+ "_version": "2.0.0"
30
+ }