@travisennis/acai 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. package/README.md +186 -17
  2. package/bin/acai-wrapper.js +26 -0
  3. package/dist/agent/index.d.ts +15 -2
  4. package/dist/agent/index.d.ts.map +1 -1
  5. package/dist/agent/index.js +202 -174
  6. package/dist/api/exa/index.js +1 -1
  7. package/dist/cli.d.ts +2 -1
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +40 -7
  10. package/dist/commands/add-directory-command.d.ts +1 -1
  11. package/dist/commands/add-directory-command.d.ts.map +1 -1
  12. package/dist/commands/add-directory-command.js +1 -32
  13. package/dist/commands/application-log-command.d.ts +1 -1
  14. package/dist/commands/application-log-command.d.ts.map +1 -1
  15. package/dist/commands/application-log-command.js +2 -38
  16. package/dist/commands/clear-command.d.ts +1 -1
  17. package/dist/commands/clear-command.d.ts.map +1 -1
  18. package/dist/commands/clear-command.js +1 -5
  19. package/dist/commands/compact-command.d.ts.map +1 -1
  20. package/dist/commands/compact-command.js +0 -9
  21. package/dist/commands/context-command.d.ts +1 -1
  22. package/dist/commands/context-command.d.ts.map +1 -1
  23. package/dist/commands/context-command.js +13 -72
  24. package/dist/commands/copy-command.d.ts.map +1 -1
  25. package/dist/commands/copy-command.js +0 -19
  26. package/dist/commands/edit-command.d.ts +1 -1
  27. package/dist/commands/edit-command.d.ts.map +1 -1
  28. package/dist/commands/edit-command.js +3 -49
  29. package/dist/commands/edit-prompt-command.d.ts +1 -1
  30. package/dist/commands/edit-prompt-command.d.ts.map +1 -1
  31. package/dist/commands/edit-prompt-command.js +1 -26
  32. package/dist/commands/exit-command.d.ts +1 -4
  33. package/dist/commands/exit-command.d.ts.map +1 -1
  34. package/dist/commands/exit-command.js +2 -18
  35. package/dist/commands/files-command.d.ts +1 -1
  36. package/dist/commands/files-command.d.ts.map +1 -1
  37. package/dist/commands/files-command.js +1 -54
  38. package/dist/commands/generate-rules-command.d.ts +1 -1
  39. package/dist/commands/generate-rules-command.d.ts.map +1 -1
  40. package/dist/commands/generate-rules-command.js +18 -60
  41. package/dist/commands/handoff-command.d.ts.map +1 -1
  42. package/dist/commands/handoff-command.js +0 -11
  43. package/dist/commands/health-command.d.ts +1 -1
  44. package/dist/commands/health-command.d.ts.map +1 -1
  45. package/dist/commands/health-command.js +8 -103
  46. package/dist/commands/help-command.d.ts +1 -1
  47. package/dist/commands/help-command.d.ts.map +1 -1
  48. package/dist/commands/help-command.js +6 -14
  49. package/dist/commands/history-command.d.ts +1 -1
  50. package/dist/commands/history-command.d.ts.map +1 -1
  51. package/dist/commands/history-command.js +30 -106
  52. package/dist/commands/init-command.d.ts +1 -1
  53. package/dist/commands/init-command.d.ts.map +1 -1
  54. package/dist/commands/init-command.js +4 -23
  55. package/dist/commands/last-log-command.d.ts +1 -1
  56. package/dist/commands/last-log-command.d.ts.map +1 -1
  57. package/dist/commands/last-log-command.js +1 -28
  58. package/dist/commands/list-directories-command.d.ts +1 -1
  59. package/dist/commands/list-directories-command.d.ts.map +1 -1
  60. package/dist/commands/list-directories-command.js +1 -14
  61. package/dist/commands/list-tools-command.d.ts.map +1 -1
  62. package/dist/commands/list-tools-command.js +55 -78
  63. package/dist/commands/manager.d.ts +1 -8
  64. package/dist/commands/manager.d.ts.map +1 -1
  65. package/dist/commands/manager.js +7 -42
  66. package/dist/commands/model-command.d.ts +0 -22
  67. package/dist/commands/model-command.d.ts.map +1 -1
  68. package/dist/commands/model-command.js +5 -126
  69. package/dist/commands/paste-command.d.ts +1 -1
  70. package/dist/commands/paste-command.d.ts.map +1 -1
  71. package/dist/commands/paste-command.js +1 -79
  72. package/dist/commands/pickup-command.d.ts.map +1 -1
  73. package/dist/commands/pickup-command.js +3 -55
  74. package/dist/commands/prompt-command.d.ts +19 -1
  75. package/dist/commands/prompt-command.d.ts.map +1 -1
  76. package/dist/commands/prompt-command.js +172 -194
  77. package/dist/commands/remove-directory-command.d.ts +1 -1
  78. package/dist/commands/remove-directory-command.d.ts.map +1 -1
  79. package/dist/commands/remove-directory-command.js +1 -33
  80. package/dist/commands/reset-command.d.ts +1 -1
  81. package/dist/commands/reset-command.d.ts.map +1 -1
  82. package/dist/commands/reset-command.js +3 -11
  83. package/dist/commands/rules-command.d.ts +1 -1
  84. package/dist/commands/rules-command.d.ts.map +1 -1
  85. package/dist/commands/rules-command.js +1 -63
  86. package/dist/commands/save-command.d.ts +1 -1
  87. package/dist/commands/save-command.d.ts.map +1 -1
  88. package/dist/commands/save-command.js +1 -8
  89. package/dist/commands/shell-command.d.ts.map +1 -1
  90. package/dist/commands/shell-command.js +1 -48
  91. package/dist/commands/types.d.ts +0 -3
  92. package/dist/commands/types.d.ts.map +1 -1
  93. package/dist/commands/usage-command.d.ts +1 -1
  94. package/dist/commands/usage-command.d.ts.map +1 -1
  95. package/dist/commands/usage-command.js +5 -16
  96. package/dist/config.d.ts +17 -6
  97. package/dist/config.d.ts.map +1 -1
  98. package/dist/config.js +86 -53
  99. package/dist/execution/index.d.ts +17 -2
  100. package/dist/execution/index.d.ts.map +1 -1
  101. package/dist/execution/index.js +62 -20
  102. package/dist/formatting.d.ts +19 -0
  103. package/dist/formatting.d.ts.map +1 -1
  104. package/dist/formatting.js +54 -0
  105. package/dist/index.d.ts +1 -1
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +212 -153
  108. package/dist/messages.d.ts +3 -0
  109. package/dist/messages.d.ts.map +1 -1
  110. package/dist/messages.js +67 -3
  111. package/dist/models/anthropic-provider.d.ts.map +1 -1
  112. package/dist/models/anthropic-provider.js +0 -7
  113. package/dist/models/deepseek-provider.d.ts.map +1 -1
  114. package/dist/models/deepseek-provider.js +0 -2
  115. package/dist/models/google-provider.d.ts.map +1 -1
  116. package/dist/models/google-provider.js +0 -3
  117. package/dist/models/groq-provider.d.ts.map +1 -1
  118. package/dist/models/groq-provider.js +0 -1
  119. package/dist/models/openai-provider.d.ts.map +1 -1
  120. package/dist/models/openai-provider.js +0 -4
  121. package/dist/models/openrouter-provider.d.ts +10 -9
  122. package/dist/models/openrouter-provider.d.ts.map +1 -1
  123. package/dist/models/openrouter-provider.js +82 -88
  124. package/dist/models/providers.d.ts +4 -14
  125. package/dist/models/providers.d.ts.map +1 -1
  126. package/dist/models/providers.js +1 -57
  127. package/dist/models/xai-provider.d.ts.map +1 -1
  128. package/dist/models/xai-provider.js +0 -2
  129. package/dist/prompts.d.ts +9 -4
  130. package/dist/prompts.d.ts.map +1 -1
  131. package/dist/prompts.js +427 -99
  132. package/dist/repl/project-status-line.d.ts +1 -0
  133. package/dist/repl/project-status-line.d.ts.map +1 -1
  134. package/dist/repl/project-status-line.js +57 -27
  135. package/dist/repl-new.d.ts +0 -2
  136. package/dist/repl-new.d.ts.map +1 -1
  137. package/dist/repl-new.js +34 -54
  138. package/dist/skills.d.ts +20 -0
  139. package/dist/skills.d.ts.map +1 -0
  140. package/dist/skills.js +192 -0
  141. package/dist/terminal/control.d.ts +55 -0
  142. package/dist/terminal/control.d.ts.map +1 -0
  143. package/dist/terminal/control.js +109 -0
  144. package/dist/terminal/default-theme.d.ts +1 -1
  145. package/dist/terminal/default-theme.d.ts.map +1 -1
  146. package/dist/terminal/default-theme.js +24 -28
  147. package/dist/terminal/formatting.d.ts +23 -25
  148. package/dist/terminal/formatting.d.ts.map +1 -1
  149. package/dist/terminal/formatting.js +35 -52
  150. package/dist/terminal/highlight/index.d.ts.map +1 -1
  151. package/dist/terminal/highlight/index.js +3 -6
  152. package/dist/terminal/highlight/theme.d.ts.map +1 -1
  153. package/dist/terminal/highlight/theme.js +2 -6
  154. package/dist/terminal/index.d.ts +2 -101
  155. package/dist/terminal/index.d.ts.map +1 -1
  156. package/dist/terminal/index.js +2 -464
  157. package/dist/terminal/markdown.js +7 -5
  158. package/dist/terminal/strip-ansi.js +4 -4
  159. package/dist/terminal/table/cell.d.ts +114 -0
  160. package/dist/terminal/table/cell.d.ts.map +1 -0
  161. package/dist/terminal/table/cell.js +407 -0
  162. package/dist/terminal/table/debug.d.ts +15 -0
  163. package/dist/terminal/table/debug.d.ts.map +1 -0
  164. package/dist/terminal/table/debug.js +32 -0
  165. package/dist/terminal/table/index.d.ts +3 -0
  166. package/dist/terminal/table/index.d.ts.map +1 -0
  167. package/dist/terminal/table/index.js +2 -0
  168. package/dist/terminal/table/layout-manager.d.ts +27 -0
  169. package/dist/terminal/table/layout-manager.d.ts.map +1 -0
  170. package/dist/terminal/table/layout-manager.js +257 -0
  171. package/dist/terminal/table/table.d.ts +9 -0
  172. package/dist/terminal/table/table.d.ts.map +1 -0
  173. package/dist/terminal/table/table.js +97 -0
  174. package/dist/terminal/table/utils.d.ts +63 -0
  175. package/dist/terminal/table/utils.d.ts.map +1 -0
  176. package/dist/terminal/table/utils.js +326 -0
  177. package/dist/tokens/threshold.d.ts +6 -21
  178. package/dist/tokens/threshold.d.ts.map +1 -1
  179. package/dist/tokens/threshold.js +13 -31
  180. package/dist/tools/advanced-edit-file.d.ts.map +1 -1
  181. package/dist/tools/advanced-edit-file.js +5 -1
  182. package/dist/tools/agent.d.ts.map +1 -1
  183. package/dist/tools/agent.js +19 -5
  184. package/dist/tools/bash.d.ts +3 -1
  185. package/dist/tools/bash.d.ts.map +1 -1
  186. package/dist/tools/bash.js +204 -42
  187. package/dist/tools/batch.d.ts +34 -0
  188. package/dist/tools/batch.d.ts.map +1 -0
  189. package/dist/tools/batch.js +174 -0
  190. package/dist/tools/code-interpreter.d.ts.map +1 -1
  191. package/dist/tools/code-interpreter.js +25 -9
  192. package/dist/tools/delete-file.d.ts.map +1 -1
  193. package/dist/tools/delete-file.js +9 -2
  194. package/dist/tools/directory-tree.d.ts +0 -6
  195. package/dist/tools/directory-tree.d.ts.map +1 -1
  196. package/dist/tools/directory-tree.js +29 -18
  197. package/dist/tools/dynamic-tool-loader.d.ts +0 -4
  198. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  199. package/dist/tools/dynamic-tool-loader.js +2 -2
  200. package/dist/tools/edit-file.d.ts.map +1 -1
  201. package/dist/tools/edit-file.js +16 -3
  202. package/dist/tools/glob.d.ts.map +1 -1
  203. package/dist/tools/glob.js +24 -13
  204. package/dist/tools/grep.d.ts.map +1 -1
  205. package/dist/tools/grep.js +40 -25
  206. package/dist/tools/index.d.ts +17 -3
  207. package/dist/tools/index.d.ts.map +1 -1
  208. package/dist/tools/index.js +43 -1
  209. package/dist/tools/llm-edit-fixer.d.ts +0 -1
  210. package/dist/tools/llm-edit-fixer.d.ts.map +1 -1
  211. package/dist/tools/llm-edit-fixer.js +14 -28
  212. package/dist/tools/move-file.d.ts.map +1 -1
  213. package/dist/tools/move-file.js +8 -1
  214. package/dist/tools/read-file.d.ts.map +1 -1
  215. package/dist/tools/read-file.js +32 -23
  216. package/dist/tools/read-multiple-files.d.ts.map +1 -1
  217. package/dist/tools/read-multiple-files.js +102 -45
  218. package/dist/tools/save-file.d.ts +4 -4
  219. package/dist/tools/save-file.d.ts.map +1 -1
  220. package/dist/tools/save-file.js +20 -2
  221. package/dist/tools/think.d.ts.map +1 -1
  222. package/dist/tools/think.js +7 -1
  223. package/dist/tools/types.d.ts +5 -1
  224. package/dist/tools/types.d.ts.map +1 -1
  225. package/dist/tools/web-fetch.js +1 -1
  226. package/dist/tools/web-search.d.ts.map +1 -1
  227. package/dist/tools/web-search.js +24 -9
  228. package/dist/tui/components/assistant-message.js +1 -1
  229. package/dist/tui/components/box.d.ts +20 -0
  230. package/dist/tui/components/box.d.ts.map +1 -0
  231. package/dist/tui/components/box.js +81 -0
  232. package/dist/tui/components/editor.d.ts +60 -5
  233. package/dist/tui/components/editor.d.ts.map +1 -1
  234. package/dist/tui/components/editor.js +577 -115
  235. package/dist/tui/components/footer.d.ts +0 -12
  236. package/dist/tui/components/footer.d.ts.map +1 -1
  237. package/dist/tui/components/footer.js +19 -7
  238. package/dist/tui/components/header.d.ts +21 -0
  239. package/dist/tui/components/header.d.ts.map +1 -0
  240. package/dist/tui/components/header.js +63 -0
  241. package/dist/tui/components/loader.d.ts +5 -1
  242. package/dist/tui/components/loader.d.ts.map +1 -1
  243. package/dist/tui/components/loader.js +2 -2
  244. package/dist/tui/components/markdown.d.ts +26 -23
  245. package/dist/tui/components/markdown.d.ts.map +1 -1
  246. package/dist/tui/components/markdown.js +107 -54
  247. package/dist/tui/components/modal.d.ts +0 -11
  248. package/dist/tui/components/modal.d.ts.map +1 -1
  249. package/dist/tui/components/modal.js +0 -29
  250. package/dist/tui/components/progress-bar.d.ts +19 -0
  251. package/dist/tui/components/progress-bar.d.ts.map +1 -0
  252. package/dist/tui/components/progress-bar.js +78 -0
  253. package/dist/tui/components/prompt-status.d.ts +2 -1
  254. package/dist/tui/components/prompt-status.d.ts.map +1 -1
  255. package/dist/tui/components/prompt-status.js +7 -2
  256. package/dist/tui/components/select-list.d.ts +27 -1
  257. package/dist/tui/components/select-list.d.ts.map +1 -1
  258. package/dist/tui/components/select-list.js +93 -29
  259. package/dist/tui/components/spacer.d.ts +1 -1
  260. package/dist/tui/components/spacer.d.ts.map +1 -1
  261. package/dist/tui/components/spacer.js +2 -2
  262. package/dist/tui/components/table.d.ts +27 -0
  263. package/dist/tui/components/table.d.ts.map +1 -0
  264. package/dist/tui/components/table.js +125 -0
  265. package/dist/tui/components/thinking-block.d.ts.map +1 -1
  266. package/dist/tui/components/thinking-block.js +4 -1
  267. package/dist/tui/components/tool-execution.d.ts +8 -4
  268. package/dist/tui/components/tool-execution.d.ts.map +1 -1
  269. package/dist/tui/components/tool-execution.js +88 -80
  270. package/dist/tui/components/user-message.d.ts.map +1 -1
  271. package/dist/tui/components/user-message.js +6 -4
  272. package/dist/tui/index.d.ts +9 -5
  273. package/dist/tui/index.d.ts.map +1 -1
  274. package/dist/tui/index.js +5 -1
  275. package/dist/tui/terminal.d.ts +2 -1
  276. package/dist/tui/terminal.d.ts.map +1 -1
  277. package/dist/tui/terminal.js +28 -38
  278. package/dist/tui/tui.d.ts +2 -0
  279. package/dist/tui/tui.d.ts.map +1 -1
  280. package/dist/tui/tui.js +53 -33
  281. package/dist/tui/utils.d.ts +5 -0
  282. package/dist/tui/utils.d.ts.map +1 -1
  283. package/dist/tui/utils.js +81 -1
  284. package/dist/{tools/bash-utils.d.ts → utils/bash.d.ts} +3 -3
  285. package/dist/utils/bash.d.ts.map +1 -0
  286. package/dist/{tools/bash-utils.js → utils/bash.js} +22 -11
  287. package/dist/utils/{filesystem.d.ts → filesystem/operations.d.ts} +1 -1
  288. package/dist/utils/filesystem/operations.d.ts.map +1 -0
  289. package/dist/{tools/filesystem-utils.d.ts → utils/filesystem/security.d.ts} +3 -2
  290. package/dist/utils/filesystem/security.d.ts.map +1 -0
  291. package/dist/{tools/filesystem-utils.js → utils/filesystem/security.js} +62 -4
  292. package/dist/utils/funcs.d.ts +6 -0
  293. package/dist/utils/funcs.d.ts.map +1 -0
  294. package/dist/utils/funcs.js +6 -0
  295. package/dist/{tools/git-utils.d.ts → utils/git.d.ts} +1 -1
  296. package/dist/utils/git.d.ts.map +1 -0
  297. package/dist/{tools/git-utils.js → utils/git.js} +0 -6
  298. package/dist/utils/glob.js +1 -1
  299. package/dist/utils/{zod-utils.d.ts → zod.d.ts} +1 -1
  300. package/dist/utils/zod.d.ts.map +1 -0
  301. package/package.json +17 -17
  302. package/dist/agent/manual-loop.d.ts +0 -41
  303. package/dist/agent/manual-loop.d.ts.map +0 -1
  304. package/dist/agent/manual-loop.js +0 -278
  305. package/dist/repl/display-tool-messages.d.ts +0 -4
  306. package/dist/repl/display-tool-messages.d.ts.map +0 -1
  307. package/dist/repl/display-tool-messages.js +0 -58
  308. package/dist/repl/display-tool-use.d.ts +0 -14
  309. package/dist/repl/display-tool-use.d.ts.map +0 -1
  310. package/dist/repl/display-tool-use.js +0 -63
  311. package/dist/repl/get-prompt-header.d.ts +0 -8
  312. package/dist/repl/get-prompt-header.d.ts.map +0 -1
  313. package/dist/repl/get-prompt-header.js +0 -9
  314. package/dist/repl/prompt.d.ts +0 -21
  315. package/dist/repl/prompt.d.ts.map +0 -1
  316. package/dist/repl/prompt.js +0 -244
  317. package/dist/repl.d.ts +0 -29
  318. package/dist/repl.d.ts.map +0 -1
  319. package/dist/repl.js +0 -218
  320. package/dist/terminal/checkbox-prompt.d.ts +0 -36
  321. package/dist/terminal/checkbox-prompt.d.ts.map +0 -1
  322. package/dist/terminal/checkbox-prompt.js +0 -368
  323. package/dist/terminal/editor-prompt.d.ts +0 -10
  324. package/dist/terminal/editor-prompt.d.ts.map +0 -1
  325. package/dist/terminal/editor-prompt.js +0 -61
  326. package/dist/terminal/errors.d.ts +0 -19
  327. package/dist/terminal/errors.d.ts.map +0 -1
  328. package/dist/terminal/errors.js +0 -37
  329. package/dist/terminal/input-prompt.d.ts +0 -17
  330. package/dist/terminal/input-prompt.d.ts.map +0 -1
  331. package/dist/terminal/input-prompt.js +0 -181
  332. package/dist/terminal/search-prompt.d.ts +0 -20
  333. package/dist/terminal/search-prompt.d.ts.map +0 -1
  334. package/dist/terminal/search-prompt.js +0 -280
  335. package/dist/terminal/types.d.ts +0 -35
  336. package/dist/terminal/types.d.ts.map +0 -1
  337. package/dist/terminal/types.js +0 -1
  338. package/dist/tools/bash-utils.d.ts.map +0 -1
  339. package/dist/tools/filesystem-utils.d.ts.map +0 -1
  340. package/dist/tools/git-utils.d.ts.map +0 -1
  341. package/dist/utils/filesystem.d.ts.map +0 -1
  342. package/dist/utils/zod-utils.d.ts.map +0 -1
  343. /package/dist/utils/{filesystem.js → filesystem/operations.js} +0 -0
  344. /package/dist/utils/{zod-utils.js → zod.js} +0 -0
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env node
2
+ import os from "node:os";
3
+ import path from "node:path";
2
4
  import { text } from "node:stream/consumers";
3
5
  import { parseArgs } from "node:util";
4
6
  import { asyncTry } from "@travisennis/stdlib/try";
@@ -6,25 +8,30 @@ import { isDefined } from "@travisennis/stdlib/typeguards";
6
8
  import { Agent } from "./agent/index.js";
7
9
  import { Cli } from "./cli.js";
8
10
  import { CommandManager } from "./commands/manager.js";
9
- import { config } from "./config.js";
11
+ import { config, } from "./config.js";
10
12
  import { logger } from "./logger.js";
11
13
  import { MessageHistory } from "./messages.js";
12
14
  import { ModelManager } from "./models/manager.js";
13
15
  import { isSupportedModel } from "./models/providers.js";
14
16
  import { PromptManager } from "./prompts/manager.js";
15
17
  import { systemPrompt } from "./prompts.js";
16
- import { Repl } from "./repl.js";
17
18
  import { NewRepl } from "./repl-new.js";
18
- import { initTerminal } from "./terminal/index.js";
19
+ import { setTerminalTitle } from "./terminal/formatting.js";
19
20
  import { select } from "./terminal/select-prompt.js";
20
21
  import { TokenCounter } from "./tokens/counter.js";
21
22
  import { TokenTracker } from "./tokens/tracker.js";
22
- import { initAgents, initTools } from "./tools/index.js";
23
+ import { initAgents, initTools, } from "./tools/index.js";
23
24
  import { getPackageVersion } from "./version.js";
24
25
  // Create workspace context from CLI arguments
25
26
  export function createWorkspaceContext(addDirArgs = []) {
26
27
  const primaryDir = process.cwd();
27
- const allowedDirs = [primaryDir, ...addDirArgs];
28
+ const allowedDirs = [
29
+ primaryDir,
30
+ "/tmp",
31
+ config.getAccessibleLogDir(),
32
+ path.join(os.homedir(), ".acai"),
33
+ ...addDirArgs,
34
+ ];
28
35
  // Remove duplicates while preserving order
29
36
  const uniqueDirs = allowedDirs.filter((dir, index, array) => array.indexOf(dir) === index);
30
37
  return {
@@ -42,7 +49,8 @@ Options
42
49
  --continue Load the most recent conversation
43
50
  --resume Select a recent conversation to resume
44
51
  --add-dir Add additional working directory (can be used multiple times)
45
- --new-repl
52
+ --no-skills Disable skills discovery and loading
53
+
46
54
  --help, -h Show help
47
55
  --version, -v Show version
48
56
 
@@ -58,7 +66,7 @@ const parsed = parseArgs({
58
66
  continue: { type: "boolean", default: false },
59
67
  resume: { type: "boolean", default: false },
60
68
  "add-dir": { type: "string", multiple: true },
61
- "new-repl": { type: "boolean" },
69
+ "no-skills": { type: "boolean", default: false },
62
70
  help: { type: "boolean", short: "h" },
63
71
  version: { type: "boolean", short: "v" },
64
72
  },
@@ -76,8 +84,56 @@ const workspace = createWorkspaceContext(flags["add-dir"]);
76
84
  export function handleError(error) {
77
85
  logger.error({ error: error }, error.message);
78
86
  }
79
- async function main() {
80
- const appConfig = await config.ensureAppConfig("acai");
87
+ // Configuration constants
88
+ const DEFAULT_HISTORY_LIMIT = 10;
89
+ const CONTINUE_HISTORY_LIMIT = 1;
90
+ // Helper functions for main()
91
+ async function initializeAppState(appConfig, initialPromptInput, stdInPrompt, hasContinueOrResume) {
92
+ const appDir = config.app;
93
+ // Parallelize independent async operations
94
+ const [messageHistoryDir, modelManager] = await Promise.all([
95
+ appDir.ensurePath("message-history"),
96
+ initializeModelManager(appDir),
97
+ ]);
98
+ // Initialize synchronous components
99
+ const tokenTracker = new TokenTracker();
100
+ const tokenCounter = new TokenCounter();
101
+ // Initialize dependent components
102
+ const messageHistory = await initializeMessageHistory(messageHistoryDir, modelManager, tokenTracker);
103
+ // Handle conversation history loading
104
+ await handleConversationHistory(messageHistory, messageHistoryDir, hasContinueOrResume);
105
+ // Setup prompt manager
106
+ const promptManager = new PromptManager(tokenCounter);
107
+ if (!hasContinueOrResume && isDefined(initialPromptInput)) {
108
+ promptManager.set(initialPromptInput);
109
+ }
110
+ if (stdInPrompt) {
111
+ promptManager.addContext(stdInPrompt);
112
+ }
113
+ const promptHistory = [];
114
+ const commands = new CommandManager({
115
+ promptManager,
116
+ modelManager,
117
+ messageHistory,
118
+ tokenTracker,
119
+ config,
120
+ tokenCounter,
121
+ promptHistory,
122
+ workspace,
123
+ });
124
+ await commands.initializeCommmands();
125
+ return {
126
+ appConfig,
127
+ modelManager,
128
+ tokenTracker,
129
+ tokenCounter,
130
+ messageHistory,
131
+ promptManager,
132
+ promptHistory,
133
+ commands,
134
+ };
135
+ }
136
+ async function handleEarlyExits() {
81
137
  if (flags.version === true) {
82
138
  console.info(getPackageVersion());
83
139
  process.exit(0);
@@ -86,21 +142,21 @@ async function main() {
86
142
  console.info(helpText);
87
143
  process.exit(0);
88
144
  }
89
- const appDir = config.app;
90
- const messageHistoryDir = await appDir.ensurePath("message-history");
91
- // --- Argument Validation ---
145
+ return false;
146
+ }
147
+ function validateCliArguments() {
92
148
  if (flags.continue === true && flags.resume === true) {
93
149
  console.error("Cannot use --continue and --resume flags together.");
94
150
  process.exit(1);
95
151
  }
152
+ }
153
+ async function determineInitialPrompt() {
96
154
  const hasContinueOrResume = flags.continue === true || flags.resume === true;
97
- // --- Determine Initial Prompt (potential conflict) ---
98
155
  const positionalPrompt = input.at(0);
99
156
  let stdInPrompt;
100
157
  // Check if there's data available on stdin
101
158
  if (!process.stdin.isTTY) {
102
159
  try {
103
- // Non-TTY stdin means data is being piped in
104
160
  stdInPrompt = await text(process.stdin);
105
161
  }
106
162
  catch (error) {
@@ -116,8 +172,9 @@ async function main() {
116
172
  console.error("Cannot use --continue or --resume with an initial prompt.");
117
173
  process.exit(1);
118
174
  }
119
- const terminal = initTerminal();
120
- terminal.setTitle(`acai: ${workspace.primaryDir}`);
175
+ return { initialPromptInput, stdInPrompt, hasContinueOrResume };
176
+ }
177
+ async function initializeModelManager(appDir) {
121
178
  const chosenModel = isSupportedModel(flags.model)
122
179
  ? flags.model
123
180
  : "openrouter:glm-4.6";
@@ -126,37 +183,40 @@ async function main() {
126
183
  });
127
184
  modelManager.setModel("repl", chosenModel);
128
185
  modelManager.setModel("cli", chosenModel);
129
- modelManager.setModel("title-conversation", "openrouter:gemini-flash25");
130
- modelManager.setModel("conversation-summarizer", "openrouter:gemini-flash25");
131
- modelManager.setModel("tool-repair", "openai:gpt-4.1");
132
- modelManager.setModel("conversation-analyzer", "openrouter:gemini-flash25");
186
+ modelManager.setModel("title-conversation", chosenModel);
187
+ modelManager.setModel("conversation-summarizer", chosenModel);
188
+ modelManager.setModel("tool-repair", chosenModel);
189
+ modelManager.setModel("conversation-analyzer", chosenModel);
133
190
  modelManager.setModel("init-project", chosenModel);
134
- modelManager.setModel("task-agent", "openrouter:gpt-5-mini");
191
+ modelManager.setModel("task-agent", chosenModel);
135
192
  modelManager.setModel("handoff-agent", chosenModel);
136
- modelManager.setModel("edit-fix", "openrouter:gemini-flash25");
137
- const tokenTracker = new TokenTracker();
138
- const tokenCounter = new TokenCounter();
193
+ modelManager.setModel("edit-fix", chosenModel);
194
+ return modelManager;
195
+ }
196
+ async function initializeMessageHistory(messageHistoryDir, modelManager, tokenTracker) {
139
197
  const messageHistory = new MessageHistory({
140
198
  stateDir: messageHistoryDir,
141
199
  modelManager,
142
200
  tokenTracker,
143
201
  });
144
- messageHistory.on("update-title", (title) => terminal.setTitle(title));
202
+ messageHistory.on("update-title", (title) => setTerminalTitle(title));
203
+ return messageHistory;
204
+ }
205
+ async function handleConversationHistory(messageHistory, messageHistoryDir, _hasContinueOrResume) {
145
206
  if (flags.continue === true) {
146
- const histories = await MessageHistory.load(messageHistoryDir, 1);
207
+ const histories = await MessageHistory.load(messageHistoryDir, CONTINUE_HISTORY_LIMIT);
147
208
  const latestHistory = histories.at(0);
148
209
  if (latestHistory) {
149
210
  messageHistory.restore(latestHistory);
150
211
  console.info(`Resuming conversation: ${latestHistory.title}`);
151
- // Set terminal title after restoring
152
- terminal.setTitle(latestHistory.title || `acai: ${process.cwd()}`);
212
+ setTerminalTitle(latestHistory.title || `acai: ${process.cwd()}`);
153
213
  }
154
214
  else {
155
215
  logger.info("No previous conversation found to continue.");
156
216
  }
157
217
  }
158
218
  else if (flags.resume === true) {
159
- const histories = await MessageHistory.load(messageHistoryDir, 10);
219
+ const histories = await MessageHistory.load(messageHistoryDir, DEFAULT_HISTORY_LIMIT);
160
220
  if (histories.length > 0) {
161
221
  try {
162
222
  const choice = await select({
@@ -171,23 +231,19 @@ async function main() {
171
231
  if (selectedHistory) {
172
232
  messageHistory.restore(selectedHistory);
173
233
  logger.info(`Resuming conversation: ${selectedHistory.title}`);
174
- // Set terminal title after restoring
175
- terminal.setTitle(selectedHistory.title || `acai: ${process.cwd()}`);
234
+ setTerminalTitle(selectedHistory.title || `acai: ${process.cwd()}`);
176
235
  }
177
236
  else {
178
- // This case should theoretically not happen if choice is valid
179
237
  logger.error("Selected history index out of bounds.");
180
238
  }
181
239
  }
182
240
  catch (error) {
183
- // Handle Ctrl-C cancellation
184
241
  if (error instanceof Error &&
185
242
  "isCanceled" in error &&
186
243
  error.isCanceled === true) {
187
244
  logger.info("Resume selection cancelled.");
188
245
  }
189
246
  else {
190
- // Re-throw other errors
191
247
  throw error;
192
248
  }
193
249
  }
@@ -196,131 +252,134 @@ async function main() {
196
252
  logger.info("No previous conversations found to resume.");
197
253
  }
198
254
  }
199
- // --- Setup Prompt Manager (only if not continuing/resuming) ---
200
- const promptManager = new PromptManager(tokenCounter);
201
- if (!hasContinueOrResume && isDefined(initialPromptInput)) {
202
- promptManager.set(initialPromptInput);
203
- }
204
- if (stdInPrompt) {
205
- promptManager.addContext(stdInPrompt);
206
- }
207
- const promptHistory = [];
208
- const commands = new CommandManager({
209
- promptManager,
210
- modelManager,
211
- terminal,
212
- messageHistory,
213
- tokenTracker,
214
- config,
215
- tokenCounter,
216
- promptHistory,
255
+ }
256
+ async function runCliMode(state) {
257
+ const skillsEnabled = !flags["no-skills"] && (await config.getSkillsEnabled());
258
+ const cliProcess = new Cli({
259
+ promptManager: state.promptManager,
260
+ messageHistory: state.messageHistory,
261
+ modelManager: state.modelManager,
262
+ tokenTracker: state.tokenTracker,
263
+ tokenCounter: state.tokenCounter,
217
264
  workspace,
265
+ skillsEnabled,
218
266
  });
219
- await commands.initializeCommmands();
220
- if (isDefined(initialPromptInput)) {
221
- const cliProcess = new Cli({
222
- promptManager,
223
- config: appConfig,
224
- messageHistory,
225
- modelManager,
226
- tokenTracker,
227
- tokenCounter,
228
- workspace,
229
- });
230
- return (await asyncTry(cliProcess.run())).recover(handleError);
231
- }
267
+ (await asyncTry(cliProcess.run())).recover(handleError);
268
+ }
269
+ async function runReplMode(state) {
232
270
  const agent = new Agent({
233
- messageHistory,
234
- modelManager,
235
- tokenTracker,
271
+ messageHistory: state.messageHistory,
272
+ modelManager: state.modelManager,
273
+ tokenTracker: state.tokenTracker,
236
274
  });
237
- if (flags["new-repl"]) {
238
- const repl = new NewRepl({
239
- agent,
240
- promptManager,
241
- terminal,
242
- config: appConfig,
243
- messageHistory,
244
- modelManager,
245
- tokenTracker,
246
- commands,
247
- tokenCounter,
248
- promptHistory,
249
- workspace,
250
- });
251
- // Initialize TUI
252
- await repl.init();
253
- messageHistory.on("clear-history", () => {
254
- logger.info("Resetting agent state.");
255
- agent.resetState();
256
- repl.rerender();
257
- });
258
- // Set interrupt callback
259
- repl.setInterruptCallback(() => {
260
- agent.abort();
261
- });
262
- // Render any existing messages (from --continue mode)
263
- // repl.renderInitialMessages(agent.state);
264
- // Initialize tools once outside the loop - all models support tool calling
265
- const coreTools = await initTools({
266
- tokenCounter,
267
- workspace,
268
- modelManager,
269
- tokenTracker,
270
- });
271
- const agentTools = await initAgents({
272
- terminal,
273
- modelManager,
274
- tokenTracker,
275
- tokenCounter,
276
- workspace,
277
- });
278
- const completeToolDefs = {
279
- ...coreTools.toolDefs,
280
- ...agentTools.toolDefs,
281
- };
282
- const tools = {
283
- toolDefs: completeToolDefs,
284
- executors: new Map([...coreTools.executors, ...agentTools.executors]),
285
- };
286
- // Interactive loop
287
- while (true) {
288
- const userInput = await repl.getUserInput();
289
- // Process the message - agent.prompt will add user message and trigger state updates
290
- try {
291
- const results = agent.run({
292
- systemPrompt: await systemPrompt(),
293
- input: userInput,
294
- toolDefs: tools.toolDefs,
295
- executors: tools.executors,
296
- abortSignal: agent.abortSignal,
297
- });
298
- for await (const result of results) {
299
- repl.handle(result, agent.state);
300
- }
301
- messageHistory.save();
302
- }
303
- catch (_error) {
304
- // Display error in the TUI by adding an error message to the chat
305
- // repl.showError((error as Error).message || "Unknown error occurred");
306
- }
275
+ const repl = new NewRepl({
276
+ agent,
277
+ promptManager: state.promptManager,
278
+ config: state.appConfig,
279
+ messageHistory: state.messageHistory,
280
+ modelManager: state.modelManager,
281
+ tokenTracker: state.tokenTracker,
282
+ commands: state.commands,
283
+ tokenCounter: state.tokenCounter,
284
+ promptHistory: state.promptHistory,
285
+ workspace,
286
+ });
287
+ // Initialize TUI
288
+ await repl.init();
289
+ state.messageHistory.on("clear-history", () => {
290
+ logger.info("Resetting agent state.");
291
+ agent.resetState();
292
+ repl.rerender();
293
+ });
294
+ // Set interrupt callback
295
+ repl.setInterruptCallback(() => {
296
+ try {
297
+ state.messageHistory.save();
307
298
  }
308
- }
309
- const repl = new Repl({
310
- promptManager,
311
- terminal,
312
- config: appConfig,
313
- messageHistory,
314
- modelManager,
315
- tokenTracker,
316
- commands,
317
- tokenCounter,
318
- promptHistory,
299
+ catch (error) {
300
+ // Log but don't throw - we still want to abort the agent
301
+ logger.warn({ error }, "Failed to save message history on interrupt");
302
+ }
303
+ agent.abort();
304
+ });
305
+ // Initialize tools
306
+ const coreTools = await initTools({
307
+ tokenCounter: state.tokenCounter,
319
308
  workspace,
320
- showLastMessage: hasContinueOrResume
321
- ? !!(messageHistory.get() && messageHistory.get().length > 0)
322
- : false,
309
+ modelManager: state.modelManager,
310
+ tokenTracker: state.tokenTracker,
323
311
  });
324
- return (await asyncTry(repl.run())).recover(handleError);
312
+ const agentTools = await initAgents({
313
+ modelManager: state.modelManager,
314
+ tokenTracker: state.tokenTracker,
315
+ tokenCounter: state.tokenCounter,
316
+ workspace,
317
+ });
318
+ const completeToolDefs = {
319
+ ...coreTools.toolDefs,
320
+ ...agentTools.toolDefs,
321
+ };
322
+ const tools = {
323
+ toolDefs: completeToolDefs,
324
+ executors: new Map([...coreTools.executors, ...agentTools.executors]),
325
+ };
326
+ // Interactive loop
327
+ while (true) {
328
+ const userInput = await repl.getUserInput();
329
+ const projectConfig = await config.getConfig();
330
+ const activeTools = projectConfig.tools.activeTools;
331
+ const skillsEnabled = !flags["no-skills"] && (projectConfig.skills?.enabled ?? true);
332
+ try {
333
+ const results = agent.run({
334
+ systemPrompt: await systemPrompt({
335
+ type: projectConfig.systemPromptType,
336
+ activeTools,
337
+ allowedDirs: workspace.allowedDirs,
338
+ skillsEnabled,
339
+ }),
340
+ input: userInput,
341
+ toolDefs: tools.toolDefs,
342
+ activeTools,
343
+ executors: tools.executors,
344
+ abortSignal: agent.abortSignal,
345
+ });
346
+ for await (const result of results) {
347
+ repl.handle(result, agent.state);
348
+ }
349
+ state.messageHistory.save();
350
+ }
351
+ catch (_error) {
352
+ // Display error in the TUI by adding an error message to the chat
353
+ // repl.showError((error as Error).message || "Unknown error occurred");
354
+ }
355
+ }
356
+ }
357
+ async function main() {
358
+ try {
359
+ const appConfig = await config.ensureDefaultConfig("acai");
360
+ // Note: SIGINT/SIGTERM handlers are set up by CLI and REPL components
361
+ // as needed. We don't set a global handler here to avoid conflicts.
362
+ // Handle early exits
363
+ if (await handleEarlyExits())
364
+ return;
365
+ // Validate CLI arguments
366
+ validateCliArguments();
367
+ // Determine initial prompt
368
+ const { initialPromptInput, stdInPrompt, hasContinueOrResume } = await determineInitialPrompt();
369
+ // Initialize application state
370
+ const state = await initializeAppState(appConfig, initialPromptInput, stdInPrompt, hasContinueOrResume);
371
+ // Set terminal title after all validation is complete
372
+ setTerminalTitle(`acai: ${workspace.primaryDir}`);
373
+ // Handle CLI mode if initial prompt provided
374
+ if (isDefined(initialPromptInput)) {
375
+ return await runCliMode(state);
376
+ }
377
+ // Setup REPL mode
378
+ return await runReplMode(state);
379
+ }
380
+ catch (error) {
381
+ handleError(error);
382
+ process.exit(1);
383
+ }
325
384
  }
326
385
  main();
@@ -31,6 +31,7 @@ export declare class MessageHistory extends EventEmitter<MessageHistoryEvents> {
31
31
  private createdAt;
32
32
  private updatedAt;
33
33
  private stateDir;
34
+ private contextWindow;
34
35
  private modelManager;
35
36
  private tokenTracker;
36
37
  constructor({ stateDir, modelManager, tokenTracker, }: {
@@ -42,6 +43,8 @@ export declare class MessageHistory extends EventEmitter<MessageHistoryEvents> {
42
43
  private validMessage;
43
44
  get(): ModelMessage[];
44
45
  clear(): void;
46
+ setContextWindow(contextWindow: number): void;
47
+ getContextWindow(): number;
45
48
  appendUserMessage(msg: string): void;
46
49
  appendUserMessage(msg: UserModelMessage): void;
47
50
  appendAssistantMessage(msg: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../source/messages.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,aAAa,CAAC;AAIvC,OAAO,EACL,KAAK,qBAAqB,EAE1B,KAAK,SAAS,EAAE,kBAAkB;AAClC,KAAK,YAAY,EAEjB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,IAAI,CAAC;AACZ,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,SAAS,CAAC;AAExD,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,sBAAsB,EAAE,EACtC,MAAM,CAAC,EAAE,MAAM,GACd,gBAAgB,CAuBlB;AAcD;;;GAGG;AACH,KAAK,eAAe,GAAG,qBAAqB,GAAG,gBAAgB,CAAC;AAEhE,KAAK,mBAAmB,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B,CAAC;AAUF,UAAU,oBAAoB;IAC5B,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC;IACzB,eAAe,EAAE,EAAE,CAAC;CACrB;AAED,qBAAa,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IACpE,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAe;gBAEvB,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,GACb,EAAE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,YAAY,CAAC;QAC3B,YAAY,EAAE,YAAY,CAAC;KAC5B;IAaD,MAAM,CAAC,OAAO,EAAE,MAAM;IAStB,OAAO,CAAC,YAAY;IAoBpB,GAAG;IAIH,KAAK;IAKL,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IACpC,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI;IAmB9C,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IACzC,sBAAsB,CAAC,GAAG,EAAE,qBAAqB,GAAG,IAAI;IAOxD,kBAAkB,CAAC,kBAAkB,EAAE,gBAAgB,EAAE;IAKzD,sBAAsB,CAAC,gBAAgB,EAAE,eAAe,EAAE;IAO1D,OAAO;IAID,IAAI;YAoBI,aAAa;IA6B3B,mBAAmB,IAAI,gBAAgB,GAAG,SAAS;IAOnD,kBAAkB,IAAI,gBAAgB,GAAG,SAAS;IAOlD;;;OAGG;IACH,cAAc,IAAI,MAAM,GAAG,IAAI;WA2ClB,IAAI,CACf,QAAQ,EAAE,MAAM,EAChB,KAAK,SAAK,GACT,OAAO,CAAC,mBAAmB,EAAE,CAAC;IA6EjC,OAAO,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI;CAajD"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../source/messages.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,aAAa,CAAC;AAYvC,OAAO,EACL,KAAK,qBAAqB,EAE1B,KAAK,SAAS,EAAE,kBAAkB;AAClC,KAAK,YAAY,EAEjB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,IAAI,CAAC;AAEZ,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,SAAS,CAAC;AAExD,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,sBAAsB,EAAE,EACtC,MAAM,CAAC,EAAE,MAAM,GACd,gBAAgB,CAuBlB;AAcD;;;GAGG;AACH,KAAK,eAAe,GAAG,qBAAqB,GAAG,gBAAgB,CAAC;AAEhE,KAAK,mBAAmB,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B,CAAC;AAUF,UAAU,oBAAoB;IAC5B,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC;IACzB,eAAe,EAAE,EAAE,CAAC;CACrB;AAED,qBAAa,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IACpE,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAe;gBAEvB,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,GACb,EAAE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,YAAY,CAAC;QAC3B,YAAY,EAAE,YAAY,CAAC;KAC5B;IAcD,MAAM,CAAC,OAAO,EAAE,MAAM;IAStB,OAAO,CAAC,YAAY;IAoBpB,GAAG;IAIH,KAAK;IAML,gBAAgB,CAAC,aAAa,EAAE,MAAM;IAOtC,gBAAgB;IAIhB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IACpC,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI;IAmB9C,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IACzC,sBAAsB,CAAC,GAAG,EAAE,qBAAqB,GAAG,IAAI;IAOxD,kBAAkB,CAAC,kBAAkB,EAAE,gBAAgB,EAAE;IAKzD,sBAAsB,CAAC,gBAAgB,EAAE,eAAe,EAAE;IAO1D,OAAO;IAID,IAAI;YA+DI,aAAa;IA6B3B,mBAAmB,IAAI,gBAAgB,GAAG,SAAS;IAOnD,kBAAkB,IAAI,gBAAgB,GAAG,SAAS;IAOlD;;;OAGG;IACH,cAAc,IAAI,MAAM,GAAG,IAAI;WA2ClB,IAAI,CACf,QAAQ,EAAE,MAAM,EAChB,KAAK,SAAK,GACT,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAiGjC,OAAO,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI;CAajD"}
package/dist/messages.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import EventEmitter from "node:events";
3
- import { readdir, readFile, stat, writeFile } from "node:fs/promises";
3
+ import { mkdir, readdir, readFile, rename, stat, unlink, writeFile, } from "node:fs/promises";
4
4
  import { basename, join } from "node:path";
5
5
  import { isString } from "@travisennis/stdlib/typeguards";
6
6
  import { generateText, } from "ai";
7
+ import { logger } from "./logger.js";
7
8
  export function createUserMessage(contentItems, prompt) {
8
9
  const messageParts = [];
9
10
  // Process content items (images and pre-defined texts)
@@ -45,6 +46,7 @@ export class MessageHistory extends EventEmitter {
45
46
  createdAt;
46
47
  updatedAt;
47
48
  stateDir;
49
+ contextWindow;
48
50
  modelManager;
49
51
  tokenTracker;
50
52
  constructor({ stateDir, modelManager, tokenTracker, }) {
@@ -56,6 +58,7 @@ export class MessageHistory extends EventEmitter {
56
58
  this.createdAt = new Date();
57
59
  this.updatedAt = new Date();
58
60
  this.stateDir = stateDir;
61
+ this.contextWindow = 0;
59
62
  this.modelManager = modelManager;
60
63
  this.tokenTracker = tokenTracker;
61
64
  }
@@ -87,8 +90,18 @@ export class MessageHistory extends EventEmitter {
87
90
  }
88
91
  clear() {
89
92
  this.history.length = 0;
93
+ this.contextWindow = 0;
90
94
  this.emit("clear-history");
91
95
  }
96
+ setContextWindow(contextWindow) {
97
+ if (contextWindow < 0) {
98
+ throw new Error("Context window cannot be negative");
99
+ }
100
+ this.contextWindow = contextWindow;
101
+ }
102
+ getContextWindow() {
103
+ return this.contextWindow;
104
+ }
92
105
  appendUserMessage(msg) {
93
106
  const now = new Date();
94
107
  const msgObj = isString(msg) ? createUserMessage([], msg) : msg;
@@ -126,6 +139,14 @@ export class MessageHistory extends EventEmitter {
126
139
  const msgHistoryDir = this.stateDir;
127
140
  const fileName = `message-history-${this.sessionId}.json`;
128
141
  const filePath = join(msgHistoryDir, fileName);
142
+ const tempFilePath = `${filePath}.tmp`;
143
+ // Validate data before writing
144
+ if (!this.sessionId || this.sessionId.trim() === "") {
145
+ throw new Error("Cannot save: sessionId is empty");
146
+ }
147
+ if (!Array.isArray(this.history)) {
148
+ throw new Error("Cannot save: history is not an array");
149
+ }
129
150
  const project = basename(process.cwd());
130
151
  const output = {
131
152
  project,
@@ -136,7 +157,35 @@ export class MessageHistory extends EventEmitter {
136
157
  updatedAt: this.updatedAt,
137
158
  messages: this.history,
138
159
  };
139
- await writeFile(filePath, JSON.stringify(output, null, 2));
160
+ try {
161
+ // Ensure directory exists
162
+ await mkdir(msgHistoryDir, { recursive: true });
163
+ // Write to temporary file first
164
+ await writeFile(tempFilePath, JSON.stringify(output, null, 2));
165
+ // Atomically rename to final file
166
+ await rename(tempFilePath, filePath);
167
+ logger.info(`Message history saved to ${filePath}`);
168
+ }
169
+ catch (error) {
170
+ // Clean up temp file if it exists
171
+ try {
172
+ await unlink(tempFilePath);
173
+ }
174
+ catch (_cleanupError) {
175
+ // Ignore cleanup errors
176
+ }
177
+ // Check if it's an ENOENT error from rename (temp file doesn't exist)
178
+ if (error instanceof Error &&
179
+ "code" in error &&
180
+ error.code === "ENOENT") {
181
+ logger.warn(`Temp file missing during save for ${filePath}, write may have been interrupted`);
182
+ }
183
+ else {
184
+ logger.error(error, `Failed to save message history to ${filePath}:`);
185
+ // Don't throw - just log. This is called from interrupt handlers
186
+ // and we don't want to crash the program on save failure.
187
+ }
188
+ }
140
189
  }
141
190
  async generateTitle(message) {
142
191
  // Skip title generation if message is empty
@@ -232,7 +281,17 @@ export class MessageHistory extends EventEmitter {
232
281
  const fileReadPromises = sortedFiles.map(async (fileName) => {
233
282
  const filePath = join(stateDir, fileName);
234
283
  try {
284
+ // Check file stats first to avoid reading empty files
285
+ const stats = await stat(filePath);
286
+ if (stats.size === 0) {
287
+ // Silently skip empty files - they're likely from interrupted saves
288
+ return null;
289
+ }
235
290
  const content = await readFile(filePath, "utf-8");
291
+ // Skip files that only contain whitespace
292
+ if (content.trim().length === 0) {
293
+ return null;
294
+ }
236
295
  const parsed = JSON.parse(content);
237
296
  const result = parsed;
238
297
  // Basic validation - ensure messages array exists
@@ -244,7 +303,12 @@ export class MessageHistory extends EventEmitter {
244
303
  }
245
304
  }
246
305
  catch (error) {
247
- console.error(`Error reading or parsing file ${filePath}:`, error);
306
+ // Only log unexpected errors, not empty/malformed JSON files
307
+ // which are common from interrupted saves
308
+ if (!(error instanceof SyntaxError) ||
309
+ !error.message.includes("Unexpected end of JSON input")) {
310
+ console.error(`Error reading or parsing file ${filePath}:`, error);
311
+ }
248
312
  }
249
313
  return null; // Return null for failed reads/parses
250
314
  });
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic-provider.d.ts","sourceRoot":"","sources":["../../source/models/anthropic-provider.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,QAAA,MAAM,eAAe;;;;;;;;CAuBX,CAAC;AAEX,KAAK,SAAS,GAAG,aAAa,MAAM,OAAO,eAAe,EAAE,CAAC;AAE7D,eAAO,MAAM,mBAAmB,EAAE,SAAS,EAE1C,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;;;;CAK7B,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE;KAClC,CAAC,IAAI,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC;CA6F3C,CAAC"}
1
+ {"version":3,"file":"anthropic-provider.d.ts","sourceRoot":"","sources":["../../source/models/anthropic-provider.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,QAAA,MAAM,eAAe;;;;;;;;CAuBX,CAAC;AAEX,KAAK,SAAS,GAAG,aAAa,MAAM,OAAO,eAAe,EAAE,CAAC;AAE7D,eAAO,MAAM,mBAAmB,EAAE,SAAS,EAE1C,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;;;;CAK7B,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE;KAClC,CAAC,IAAI,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC;CAsF3C,CAAC"}