@travisennis/acai 0.0.11 → 0.0.13

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 (292) hide show
  1. package/README.md +5 -5
  2. package/dist/agent/index.d.ts.map +1 -1
  3. package/dist/agent/index.js +2 -5
  4. package/dist/commands/history/types.d.ts +3 -2
  5. package/dist/commands/history/types.d.ts.map +1 -1
  6. package/dist/commands/init-project/utils.d.ts +0 -1
  7. package/dist/commands/init-project/utils.d.ts.map +1 -1
  8. package/dist/commands/init-project/utils.js +1 -12
  9. package/dist/commands/manager.d.ts.map +1 -1
  10. package/dist/commands/manager.js +6 -19
  11. package/dist/commands/resources/index.d.ts.map +1 -1
  12. package/dist/commands/resources/index.js +4 -1
  13. package/dist/commands/session/index.d.ts.map +1 -1
  14. package/dist/commands/session/index.js +6 -0
  15. package/dist/commands/session/types.d.ts +1 -0
  16. package/dist/commands/session/types.d.ts.map +1 -1
  17. package/dist/commands/share/html-renderer.d.ts.map +1 -1
  18. package/dist/commands/share/html-renderer.js +54 -48
  19. package/dist/commands/tools/index.d.ts +3 -0
  20. package/dist/commands/tools/index.d.ts.map +1 -0
  21. package/dist/commands/tools/index.js +191 -0
  22. package/dist/commands/tools/templates.d.ts +6 -0
  23. package/dist/commands/tools/templates.d.ts.map +1 -0
  24. package/dist/commands/tools/templates.js +97 -0
  25. package/dist/config/index.d.ts +5 -2
  26. package/dist/config/index.d.ts.map +1 -1
  27. package/dist/config/index.js +42 -6
  28. package/dist/index.d.ts +14 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +98 -68
  31. package/dist/models/anthropic-provider.d.ts +1 -1
  32. package/dist/models/deepseek-provider.d.ts +3 -3
  33. package/dist/models/deepseek-provider.js +17 -17
  34. package/dist/models/google-provider.d.ts +2 -4
  35. package/dist/models/google-provider.d.ts.map +1 -1
  36. package/dist/models/google-provider.js +2 -17
  37. package/dist/models/groq-provider.d.ts +2 -4
  38. package/dist/models/groq-provider.d.ts.map +1 -1
  39. package/dist/models/groq-provider.js +3 -21
  40. package/dist/models/manager.d.ts +1 -10
  41. package/dist/models/manager.d.ts.map +1 -1
  42. package/dist/models/manager.js +2 -2
  43. package/dist/models/opencode-go-provider.d.ts +11 -1
  44. package/dist/models/opencode-go-provider.d.ts.map +1 -1
  45. package/dist/models/opencode-go-provider.js +130 -0
  46. package/dist/models/opencode-zen-provider.d.ts +3 -3
  47. package/dist/models/opencode-zen-provider.d.ts.map +1 -1
  48. package/dist/models/opencode-zen-provider.js +26 -32
  49. package/dist/models/openrouter-provider.d.ts +4 -15
  50. package/dist/models/openrouter-provider.d.ts.map +1 -1
  51. package/dist/models/openrouter-provider.js +26 -169
  52. package/dist/models/providers.d.ts +1 -1
  53. package/dist/models/providers.d.ts.map +1 -1
  54. package/dist/models/xai-provider.d.ts +1 -2
  55. package/dist/models/xai-provider.d.ts.map +1 -1
  56. package/dist/models/xai-provider.js +0 -13
  57. package/dist/prompts/manager.d.ts.map +1 -1
  58. package/dist/prompts/manager.js +5 -1
  59. package/dist/prompts/system-prompt.d.ts +1 -2
  60. package/dist/prompts/system-prompt.d.ts.map +1 -1
  61. package/dist/prompts/system-prompt.js +26 -15
  62. package/dist/repl/index.d.ts +28 -13
  63. package/dist/repl/index.d.ts.map +1 -1
  64. package/dist/repl/index.js +242 -305
  65. package/dist/skills/activated-tracker.d.ts +11 -0
  66. package/dist/skills/activated-tracker.d.ts.map +1 -0
  67. package/dist/skills/activated-tracker.js +16 -0
  68. package/dist/skills/index.d.ts +12 -2
  69. package/dist/skills/index.d.ts.map +1 -1
  70. package/dist/skills/index.js +127 -71
  71. package/dist/terminal/control.d.ts +1 -21
  72. package/dist/terminal/control.d.ts.map +1 -1
  73. package/dist/terminal/control.js +1 -32
  74. package/dist/terminal/formatting.d.ts +0 -33
  75. package/dist/terminal/formatting.d.ts.map +1 -1
  76. package/dist/terminal/formatting.js +0 -91
  77. package/dist/terminal/highlight/theme.d.ts +0 -37
  78. package/dist/terminal/highlight/theme.d.ts.map +1 -1
  79. package/dist/terminal/highlight/theme.js +1 -79
  80. package/dist/terminal/keys.d.ts +0 -97
  81. package/dist/terminal/keys.d.ts.map +1 -1
  82. package/dist/terminal/keys.js +0 -194
  83. package/dist/terminal/select-prompt.d.ts.map +1 -1
  84. package/dist/terminal/select-prompt.js +65 -51
  85. package/dist/terminal/style.d.ts +1 -1
  86. package/dist/terminal/style.d.ts.map +1 -1
  87. package/dist/terminal/supports-color.d.ts.map +1 -1
  88. package/dist/terminal/supports-color.js +38 -20
  89. package/dist/terminal/supports-hyperlinks.d.ts +3 -0
  90. package/dist/terminal/supports-hyperlinks.d.ts.map +1 -1
  91. package/dist/terminal/supports-hyperlinks.js +72 -31
  92. package/dist/terminal/table/layout-manager.d.ts +0 -20
  93. package/dist/terminal/table/layout-manager.d.ts.map +1 -1
  94. package/dist/terminal/table/layout-manager.js +68 -44
  95. package/dist/terminal/table/utils.d.ts +0 -1
  96. package/dist/terminal/table/utils.d.ts.map +1 -1
  97. package/dist/terminal/table/utils.js +2 -4
  98. package/dist/tools/apply-patch.d.ts +5 -3
  99. package/dist/tools/apply-patch.d.ts.map +1 -1
  100. package/dist/tools/apply-patch.js +154 -123
  101. package/dist/tools/bash.d.ts +4 -4
  102. package/dist/tools/bash.d.ts.map +1 -1
  103. package/dist/tools/bash.js +27 -13
  104. package/dist/tools/dynamic-tool-loader.d.ts +17 -3
  105. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  106. package/dist/tools/dynamic-tool-loader.js +360 -81
  107. package/dist/tools/edit-file.d.ts +2 -2
  108. package/dist/tools/index.d.ts +27 -151
  109. package/dist/tools/index.d.ts.map +1 -1
  110. package/dist/tools/index.js +16 -21
  111. package/dist/tools/read-file.d.ts +8 -8
  112. package/dist/tools/read-file.d.ts.map +1 -1
  113. package/dist/tools/read-file.js +32 -13
  114. package/dist/tools/save-file.d.ts +4 -4
  115. package/dist/tools/skill.d.ts +2 -1
  116. package/dist/tools/skill.d.ts.map +1 -1
  117. package/dist/tools/skill.js +64 -14
  118. package/dist/tools/types.d.ts +8 -2
  119. package/dist/tools/types.d.ts.map +1 -1
  120. package/dist/tools/web-fetch.d.ts +8 -12
  121. package/dist/tools/web-fetch.d.ts.map +1 -1
  122. package/dist/tools/web-fetch.js +86 -44
  123. package/dist/tools/web-search.d.ts +4 -8
  124. package/dist/tools/web-search.d.ts.map +1 -1
  125. package/dist/tools/web-search.js +41 -33
  126. package/dist/tui/autocomplete/utils.d.ts +0 -15
  127. package/dist/tui/autocomplete/utils.d.ts.map +1 -1
  128. package/dist/tui/autocomplete/utils.js +0 -85
  129. package/dist/tui/autocomplete.d.ts +1 -1
  130. package/dist/tui/autocomplete.d.ts.map +1 -1
  131. package/dist/tui/autocomplete.js +1 -1
  132. package/dist/tui/components/editor.d.ts +12 -0
  133. package/dist/tui/components/editor.d.ts.map +1 -1
  134. package/dist/tui/components/editor.js +181 -195
  135. package/dist/tui/components/footer.d.ts +0 -2
  136. package/dist/tui/components/footer.d.ts.map +1 -1
  137. package/dist/tui/components/footer.js +1 -17
  138. package/dist/tui/components/input.d.ts +4 -0
  139. package/dist/tui/components/input.d.ts.map +1 -1
  140. package/dist/tui/components/input.js +33 -31
  141. package/dist/tui/components/markdown.d.ts +30 -0
  142. package/dist/tui/components/markdown.d.ts.map +1 -1
  143. package/dist/tui/components/markdown.js +274 -242
  144. package/dist/tui/components/modal.d.ts.map +1 -1
  145. package/dist/tui/components/modal.js +11 -11
  146. package/dist/tui/components/select-list.d.ts +5 -0
  147. package/dist/tui/components/select-list.d.ts.map +1 -1
  148. package/dist/tui/components/select-list.js +69 -98
  149. package/dist/tui/components/table.d.ts +6 -0
  150. package/dist/tui/components/table.d.ts.map +1 -1
  151. package/dist/tui/components/table.js +61 -52
  152. package/dist/tui/index.d.ts +1 -8
  153. package/dist/tui/index.d.ts.map +1 -1
  154. package/dist/tui/index.js +0 -8
  155. package/dist/tui/tui.d.ts +9 -0
  156. package/dist/tui/tui.d.ts.map +1 -1
  157. package/dist/tui/tui.js +78 -48
  158. package/dist/tui/utils.d.ts +7 -0
  159. package/dist/tui/utils.d.ts.map +1 -1
  160. package/dist/tui/utils.js +117 -53
  161. package/dist/utils/bash.d.ts.map +1 -1
  162. package/dist/utils/bash.js +121 -104
  163. package/dist/utils/binary-output.d.ts +32 -0
  164. package/dist/utils/binary-output.d.ts.map +1 -0
  165. package/dist/utils/binary-output.js +127 -0
  166. package/dist/utils/command-protection.d.ts +3 -2
  167. package/dist/utils/command-protection.d.ts.map +1 -1
  168. package/dist/utils/command-protection.js +121 -29
  169. package/dist/utils/filesystem/operations.d.ts +0 -15
  170. package/dist/utils/filesystem/operations.d.ts.map +1 -1
  171. package/dist/utils/filesystem/operations.js +1 -38
  172. package/dist/utils/filesystem/security.d.ts.map +1 -1
  173. package/dist/utils/filesystem/security.js +22 -15
  174. package/dist/utils/filetype-detection.d.ts +0 -1
  175. package/dist/utils/filetype-detection.d.ts.map +1 -1
  176. package/dist/utils/filetype-detection.js +0 -12
  177. package/dist/utils/formatting.d.ts +0 -30
  178. package/dist/utils/formatting.d.ts.map +1 -1
  179. package/dist/utils/formatting.js +0 -44
  180. package/dist/utils/git.d.ts +4 -6
  181. package/dist/utils/git.d.ts.map +1 -1
  182. package/dist/utils/git.js +36 -46
  183. package/dist/utils/ignore.d.ts +1 -1
  184. package/dist/utils/ignore.d.ts.map +1 -1
  185. package/dist/utils/ignore.js +1 -1
  186. package/dist/utils/parsing.d.ts +1 -1
  187. package/dist/utils/parsing.d.ts.map +1 -1
  188. package/dist/utils/process.d.ts.map +1 -1
  189. package/dist/utils/process.js +77 -79
  190. package/dist/utils/yaml.d.ts +0 -1
  191. package/dist/utils/yaml.d.ts.map +1 -1
  192. package/dist/utils/yaml.js +80 -89
  193. package/dist/utils/zod.d.ts +0 -3
  194. package/dist/utils/zod.d.ts.map +1 -1
  195. package/dist/utils/zod.js +0 -7
  196. package/package.json +32 -29
  197. package/dist/agent/sub-agent.d.ts +0 -23
  198. package/dist/agent/sub-agent.d.ts.map +0 -1
  199. package/dist/agent/sub-agent.js +0 -109
  200. package/dist/commands/add-directory/index.d.ts +0 -3
  201. package/dist/commands/add-directory/index.d.ts.map +0 -1
  202. package/dist/commands/add-directory/index.js +0 -50
  203. package/dist/commands/add-directory/utils.d.ts +0 -3
  204. package/dist/commands/add-directory/utils.d.ts.map +0 -1
  205. package/dist/commands/add-directory/utils.js +0 -15
  206. package/dist/commands/clear/index.d.ts +0 -3
  207. package/dist/commands/clear/index.d.ts.map +0 -1
  208. package/dist/commands/clear/index.js +0 -13
  209. package/dist/commands/generate-rules/index.d.ts +0 -3
  210. package/dist/commands/generate-rules/index.d.ts.map +0 -1
  211. package/dist/commands/generate-rules/index.js +0 -206
  212. package/dist/commands/generate-rules/service.d.ts +0 -22
  213. package/dist/commands/generate-rules/service.d.ts.map +0 -1
  214. package/dist/commands/generate-rules/service.js +0 -103
  215. package/dist/commands/generate-rules/utils.d.ts +0 -5
  216. package/dist/commands/generate-rules/utils.d.ts.map +0 -1
  217. package/dist/commands/generate-rules/utils.js +0 -25
  218. package/dist/commands/handoff/index.d.ts +0 -3
  219. package/dist/commands/handoff/index.d.ts.map +0 -1
  220. package/dist/commands/handoff/index.js +0 -97
  221. package/dist/commands/handoff/utils.d.ts +0 -4
  222. package/dist/commands/handoff/utils.d.ts.map +0 -1
  223. package/dist/commands/handoff/utils.js +0 -123
  224. package/dist/commands/list-directories/index.d.ts +0 -3
  225. package/dist/commands/list-directories/index.d.ts.map +0 -1
  226. package/dist/commands/list-directories/index.js +0 -35
  227. package/dist/commands/pickup/index.d.ts +0 -3
  228. package/dist/commands/pickup/index.d.ts.map +0 -1
  229. package/dist/commands/pickup/index.js +0 -141
  230. package/dist/commands/pickup/types.d.ts +0 -6
  231. package/dist/commands/pickup/types.d.ts.map +0 -1
  232. package/dist/commands/pickup/types.js +0 -1
  233. package/dist/commands/pickup/utils.d.ts +0 -7
  234. package/dist/commands/pickup/utils.d.ts.map +0 -1
  235. package/dist/commands/pickup/utils.js +0 -56
  236. package/dist/commands/remove-directory/index.d.ts +0 -3
  237. package/dist/commands/remove-directory/index.d.ts.map +0 -1
  238. package/dist/commands/remove-directory/index.js +0 -55
  239. package/dist/commands/review/index.d.ts +0 -3
  240. package/dist/commands/review/index.d.ts.map +0 -1
  241. package/dist/commands/review/index.js +0 -12
  242. package/dist/commands/review/review-panel.d.ts +0 -3
  243. package/dist/commands/review/review-panel.d.ts.map +0 -1
  244. package/dist/commands/review/review-panel.js +0 -186
  245. package/dist/commands/review/utils.d.ts +0 -18
  246. package/dist/commands/review/utils.d.ts.map +0 -1
  247. package/dist/commands/review/utils.js +0 -146
  248. package/dist/commands/shell/index.d.ts +0 -3
  249. package/dist/commands/shell/index.d.ts.map +0 -1
  250. package/dist/commands/shell/index.js +0 -96
  251. package/dist/modes/manager.d.ts +0 -24
  252. package/dist/modes/manager.d.ts.map +0 -1
  253. package/dist/modes/manager.js +0 -77
  254. package/dist/modes/prompts.d.ts +0 -2
  255. package/dist/modes/prompts.d.ts.map +0 -1
  256. package/dist/modes/prompts.js +0 -142
  257. package/dist/subagents/index.d.ts +0 -16
  258. package/dist/subagents/index.d.ts.map +0 -1
  259. package/dist/subagents/index.js +0 -231
  260. package/dist/terminal/index.d.ts +0 -9
  261. package/dist/terminal/index.d.ts.map +0 -1
  262. package/dist/terminal/index.js +0 -8
  263. package/dist/tools/agent.d.ts +0 -27
  264. package/dist/tools/agent.d.ts.map +0 -1
  265. package/dist/tools/agent.js +0 -81
  266. package/dist/tools/directory-tree.d.ts +0 -28
  267. package/dist/tools/directory-tree.d.ts.map +0 -1
  268. package/dist/tools/directory-tree.js +0 -152
  269. package/dist/tools/glob.d.ts +0 -35
  270. package/dist/tools/glob.d.ts.map +0 -1
  271. package/dist/tools/glob.js +0 -159
  272. package/dist/tools/grep.d.ts +0 -100
  273. package/dist/tools/grep.d.ts.map +0 -1
  274. package/dist/tools/grep.js +0 -601
  275. package/dist/tools/ls.d.ts +0 -26
  276. package/dist/tools/ls.d.ts.map +0 -1
  277. package/dist/tools/ls.js +0 -82
  278. package/dist/tui/components/header.d.ts +0 -21
  279. package/dist/tui/components/header.d.ts.map +0 -1
  280. package/dist/tui/components/header.js +0 -63
  281. package/dist/utils/bash/parse.d.ts +0 -19
  282. package/dist/utils/bash/parse.d.ts.map +0 -1
  283. package/dist/utils/bash/parse.js +0 -223
  284. package/dist/utils/bash/quote.d.ts +0 -6
  285. package/dist/utils/bash/quote.d.ts.map +0 -1
  286. package/dist/utils/bash/quote.js +0 -23
  287. package/dist/utils/generators.d.ts +0 -3
  288. package/dist/utils/generators.d.ts.map +0 -1
  289. package/dist/utils/generators.js +0 -25
  290. package/dist/utils/glob.d.ts +0 -52
  291. package/dist/utils/glob.d.ts.map +0 -1
  292. package/dist/utils/glob.js +0 -376
@@ -1,9 +1,6 @@
1
- import { generateRulesFromSession } from "../commands/generate-rules/service.js";
2
1
  import { showModelSelector } from "../commands/model/model-panel.js";
3
- import { showReviewPanel } from "../commands/review/review-panel.js";
4
- import { ModeManager } from "../modes/manager.js";
2
+ import { parseSkillsPath } from "../config/index.js";
5
3
  import { processPrompt } from "../prompts/mentions.js";
6
- import { createUserMessage } from "../sessions/manager.js";
7
4
  import { loadSkills } from "../skills/index.js";
8
5
  import { alert, setTerminalTitle, startProgress, stopProgress, } from "../terminal/control.js";
9
6
  import style from "../terminal/style.js";
@@ -51,10 +48,6 @@ export class Repl {
51
48
  allToolExecutions = [];
52
49
  // verbose mode state
53
50
  verboseMode = false;
54
- // mode manager
55
- modeManager;
56
- // ProjectConfig - initialized in init()
57
- config;
58
51
  /** Creates a new Repl instance, initializing the TUI layout and components. */
59
52
  constructor(options) {
60
53
  this.options = options;
@@ -90,7 +83,6 @@ export class Repl {
90
83
  this.isInitialized = false;
91
84
  this.pendingTools = new Map();
92
85
  this.tools = options.tools;
93
- this.modeManager = new ModeManager();
94
86
  this.notification = new NotificationComponent("", { r: 52, g: 53, b: 65 }, style.yellow, 1, () => this.tui.requestRender());
95
87
  }
96
88
  /**
@@ -103,7 +95,9 @@ export class Repl {
103
95
  return;
104
96
  }
105
97
  // Setup autocomplete for file paths, slash commands, and skills
106
- const skills = await loadSkills();
98
+ const appConfig = await this.options.configManager.getConfig();
99
+ const skillPaths = parseSkillsPath(appConfig.skills.path);
100
+ const skills = await loadSkills(skillPaths);
107
101
  const commandsList = await this.options.commands.getCompletions();
108
102
  const autocompleteProvider = new CombinedProvider([
109
103
  new CommandProvider(commandsList),
@@ -112,8 +106,7 @@ export class Repl {
112
106
  new SkillProvider(skills.getModelInvocable()),
113
107
  ]);
114
108
  this.editor.setAutocompleteProvider(autocompleteProvider);
115
- const { promptManager, modelManager, sessionManager, commands, promptHistory, configManager, } = this.options;
116
- this.config = await configManager.getConfig();
109
+ const { promptManager, modelManager, sessionManager, commands, promptHistory, } = this.options;
117
110
  // Listen for session title updates
118
111
  // messageHistory.on("update-title", (title: string) => {
119
112
  // this.footer.setTitle(title);
@@ -124,7 +117,6 @@ export class Repl {
124
117
  projectStatus: await getProjectStatus(),
125
118
  currentContextWindow: 0,
126
119
  contextWindow: modelConfig.contextWindow,
127
- currentMode: this.modeManager.getDisplayName(),
128
120
  });
129
121
  this.tui.onCtrlC = () => {
130
122
  this.handleCtrlC();
@@ -138,22 +130,9 @@ export class Repl {
138
130
  this.tui.onCtrlN = () => {
139
131
  void this.handleCtrlN();
140
132
  };
141
- this.tui.onCtrlR = () => {
142
- void showReviewPanel(this.tui, this.chatContainer, this.editorContainer, this.editor);
143
- };
144
133
  this.tui.onCtrlM = () => {
145
134
  void this.handleCtrlM();
146
135
  };
147
- this.tui.onShiftTab = () => {
148
- this.modeManager.cycleMode();
149
- this.footer.setState({
150
- projectStatus: this.footer.getProjectStatus(),
151
- currentContextWindow: this.options.sessionManager.getLastTurnContextWindow(),
152
- contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
153
- currentMode: this.modeManager.getDisplayName(),
154
- });
155
- this.tui.requestRender();
156
- };
157
136
  // Set callback for session reconstruction (used by /history command)
158
137
  this.tui.onReconstructSession = () => this.rerender();
159
138
  this.tui.addChild(this.welcome);
@@ -177,68 +156,48 @@ export class Repl {
177
156
  };
178
157
  // Create editor for input
179
158
  this.editor.onSubmit = async (text) => {
180
- if (text.trim()) {
181
- // see if the text contains a command
182
- const commandResult = await commands.handle({ userInput: text }, {
183
- tui: this.tui,
184
- container: this.chatContainer,
185
- inputContainer: this.editorContainer,
186
- editor: this.editor,
187
- });
188
- if (commandResult.continue) {
189
- this.editor.setText("");
190
- this.tui.requestRender();
191
- return;
192
- }
193
- if (!promptManager.isPending()) {
194
- const processedPrompt = await processPrompt(text, {
195
- baseDir: process.cwd(),
196
- model: modelConfig,
197
- });
198
- for (const context of processedPrompt.context) {
199
- promptManager.addContext(context);
200
- }
201
- promptManager.set(processedPrompt.message);
202
- }
203
- else {
204
- promptHistory.push(promptManager.get());
205
- this.editor.addToHistory(promptManager.get());
206
- }
207
- // flag to see if the user prompt has added context
208
- const hasAddedContext = promptManager.hasContext();
209
- if (hasAddedContext) {
210
- const contextTokenCount = promptManager.getContextTokenCount();
211
- this.addComponentWithSpacing(new Text(style.green(`Context will be added to prompt. (${contextTokenCount} tokens)`)));
212
- }
213
- const userPrompt = promptManager.get();
214
- const userMsg = promptManager.getUserMessage();
215
- if (!this.modeManager.isNormal()) {
216
- if (this.modeManager.isFirstMessage()) {
217
- const initialPrompt = this.modeManager.getInitialPrompt();
218
- if (initialPrompt) {
219
- const modeMessage = createUserMessage([], initialPrompt);
220
- sessionManager.appendUserMessage(modeMessage);
221
- }
222
- sessionManager.appendUserMessage(userMsg);
223
- this.modeManager.markFirstMessageSent();
224
- }
225
- else {
226
- sessionManager.appendUserMessage(userMsg);
227
- const reminderMessage = this.modeManager.getReminderMessage();
228
- if (reminderMessage) {
229
- sessionManager.setTransientMessages([reminderMessage]);
230
- }
231
- }
232
- }
233
- else {
234
- sessionManager.appendUserMessage(userMsg);
235
- }
236
- this.addMessageToChat({ role: "user", content: userPrompt });
159
+ if (!text.trim())
160
+ return;
161
+ // see if the text contains a command
162
+ const commandResult = await commands.handle({ userInput: text }, {
163
+ tui: this.tui,
164
+ container: this.chatContainer,
165
+ inputContainer: this.editorContainer,
166
+ editor: this.editor,
167
+ });
168
+ if (commandResult.continue) {
237
169
  this.editor.setText("");
238
170
  this.tui.requestRender();
239
- if (this.onInputCallback) {
240
- this.onInputCallback(userPrompt);
171
+ return;
172
+ }
173
+ if (!promptManager.isPending()) {
174
+ const processedPrompt = await processPrompt(text, {
175
+ baseDir: process.cwd(),
176
+ model: modelConfig,
177
+ });
178
+ for (const context of processedPrompt.context) {
179
+ promptManager.addContext(context);
241
180
  }
181
+ promptManager.set(processedPrompt.message);
182
+ }
183
+ else {
184
+ promptHistory.push(promptManager.get());
185
+ this.editor.addToHistory(promptManager.get());
186
+ }
187
+ // flag to see if the user prompt has added context
188
+ const hasAddedContext = promptManager.hasContext();
189
+ if (hasAddedContext) {
190
+ const contextTokenCount = promptManager.getContextTokenCount();
191
+ this.addComponentWithSpacing(new Text(style.green(`Context will be added to prompt. (${contextTokenCount} tokens)`)));
192
+ }
193
+ const userPrompt = promptManager.get();
194
+ const userMsg = promptManager.getUserMessage();
195
+ sessionManager.appendUserMessage(userMsg);
196
+ this.addMessageToChat({ role: "user", content: userPrompt });
197
+ this.editor.setText("");
198
+ this.tui.requestRender();
199
+ if (this.onInputCallback) {
200
+ this.onInputCallback(userPrompt);
242
201
  }
243
202
  };
244
203
  // Start
@@ -263,166 +222,173 @@ export class Repl {
263
222
  currentContextWindow: this.options.sessionManager.getLastTurnContextWindow(),
264
223
  contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
265
224
  agentState: state,
266
- currentMode: this.modeManager.getDisplayName(),
267
225
  });
268
226
  const eventType = event.type;
269
227
  switch (eventType) {
270
228
  case "agent-start":
271
- // start the terminal progress display
272
- startProgress();
273
- // disable the submit functionality of the editor
274
- this.editor.disableSubmit = true;
275
- // Stop old loader before clearing
276
- if (this.loadingAnimation) {
277
- this.loadingAnimation.stop();
278
- }
279
- this.statusContainer.clear();
280
- // Show loading animation
281
- this.loadingAnimation = new Loader(this.tui, "Working... (esc to interrupt)");
282
- this.statusContainer.addChild(this.loadingAnimation);
283
- this.tui.requestRender();
229
+ this.handleAgentStart();
284
230
  break;
285
231
  case "step-start":
286
- // this.tui.requestRender();
287
232
  break;
288
233
  case "step-stop":
289
- // this.pendingTools.clear();
290
- // this.tui.requestRender();
291
234
  break;
292
235
  case "message-start":
293
- if (event.role === "assistant") {
294
- // Create assistant component for streaming
295
- const assistantMessageComponent = new AssistantMessageComponent();
296
- this.streamingComponent = assistantMessageComponent;
297
- this.addComponentWithSpacing(assistantMessageComponent);
298
- this.streamingComponent.updateContent(event);
299
- this.tui.requestRender();
300
- }
236
+ this.handleMessageStart(event);
301
237
  break;
302
238
  case "message":
303
- if (event.role === "assistant") {
304
- // Update streaming component
305
- if (this.streamingComponent && event.role === "assistant") {
306
- this.streamingComponent.updateContent(event);
307
- this.tui.requestRender();
308
- }
309
- }
239
+ this.handleMessage(event);
310
240
  break;
311
241
  case "message-end":
312
- if (this.streamingComponent && event.role === "assistant") {
313
- this.streamingComponent.updateContent(event);
314
- this.streamingComponent = null;
315
- this.tui.requestRender();
316
- }
242
+ this.handleMessageEnd(event);
317
243
  break;
318
- case "tool-call-lifecycle": {
319
- const component = this.pendingTools.get(event.toolCallId);
320
- if (component) {
321
- component.update(event.events);
322
- }
323
- else {
324
- // Create tool component for new tool call
325
- const newComponent = new ToolExecutionComponent(event.events, {
326
- verboseMode: this.verboseMode,
327
- });
328
- this.pendingTools.set(event.toolCallId, newComponent);
329
- this.allToolExecutions.push(newComponent);
330
- this.addComponentWithSpacing(newComponent);
331
- }
332
- this.tui.requestRender();
244
+ case "tool-call-lifecycle":
245
+ this.handleToolCallLifecycle(event);
333
246
  break;
334
- }
335
247
  case "agent-stop":
336
- // stop the terminal progress display
337
- stopProgress();
338
- // send a terminal alert to indicate the agent is done
339
- await alert();
340
- // Stop loading animation
341
- if (this.loadingAnimation) {
342
- this.loadingAnimation.stop();
343
- this.loadingAnimation = null;
344
- this.statusContainer.clear();
345
- }
346
- // Clear streaming component reference
347
- if (this.streamingComponent) {
348
- this.streamingComponent = null;
349
- }
350
- this.pendingTools.clear();
351
- this.editor.disableSubmit = false;
352
- this.options.sessionManager.clearTransientMessages();
353
- this.options.sessionManager.setMetadata("modeState", this.modeManager.toJson());
354
- if (!this.options.noSession) {
355
- await this.options.sessionManager.save();
356
- }
357
- // Refresh project status now that agent may have modified files
358
- await getProjectStatus().then((ps) => {
359
- this.footer.setState({
360
- projectStatus: ps,
361
- currentContextWindow: this.options.sessionManager.getLastTurnContextWindow(),
362
- contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
363
- currentMode: this.modeManager.getDisplayName(),
364
- });
365
- this.tui.requestRender();
366
- });
367
- this.tui.requestRender();
248
+ await this.handleAgentStop();
368
249
  break;
369
250
  case "agent-error":
370
- logger.error(event, "agent-error");
371
- this.options.sessionManager.clearTransientMessages();
372
- this.options.sessionManager.setMetadata("modeState", this.modeManager.toJson());
373
- if (!this.options.noSession) {
374
- await this.options.sessionManager.save();
375
- }
376
- // Stop loading animation
377
- if (this.loadingAnimation) {
378
- this.loadingAnimation.stop();
379
- this.loadingAnimation = null;
380
- this.statusContainer.clear();
381
- }
382
- // Clear streaming component reference
383
- if (this.streamingComponent) {
384
- this.streamingComponent = null;
385
- }
386
- this.pendingTools.clear();
387
- this.editor.disableSubmit = false;
388
- this.tui.requestRender();
251
+ await this.handleAgentError(event);
389
252
  break;
390
- case "thinking-start": {
391
- const component = new ThinkingBlockComponent(undefined, {
392
- verboseMode: this.verboseMode,
393
- });
394
- this.thinkingBlockComponent = component;
395
- this.allThinkingBlocks.push(component);
396
- // If a streaming message component already exists (text came before thinking),
397
- // insert the thinking block BEFORE it to ensure correct visual order
398
- if (this.streamingComponent) {
399
- this.chatContainer.insertChildBefore(this.streamingComponent, component);
400
- this.chatContainer.insertChildBefore(this.streamingComponent, new Spacer(1));
401
- }
402
- else {
403
- this.addComponentWithSpacing(component);
404
- }
405
- this.thinkingBlockComponent.updateContent(event);
406
- this.tui.requestRender();
253
+ case "thinking-start":
254
+ this.handleThinkingStart(event);
407
255
  break;
408
- }
409
256
  case "thinking":
410
- if (this.thinkingBlockComponent) {
411
- this.thinkingBlockComponent.updateContent(event);
412
- this.tui.requestRender();
413
- }
257
+ this.handleThinking(event);
414
258
  break;
415
259
  case "thinking-end":
416
- if (this.thinkingBlockComponent) {
417
- this.thinkingBlockComponent.endThinking();
418
- this.thinkingBlockComponent = null;
419
- this.tui.requestRender();
420
- }
260
+ this.handleThinkingEnd();
421
261
  break;
422
262
  default:
423
263
  eventType;
424
264
  }
425
265
  }
266
+ handleAgentStart() {
267
+ startProgress();
268
+ this.editor.disableSubmit = true;
269
+ if (this.loadingAnimation) {
270
+ this.loadingAnimation.stop();
271
+ }
272
+ this.statusContainer.clear();
273
+ this.loadingAnimation = new Loader(this.tui, "Working... (esc to interrupt)");
274
+ this.statusContainer.addChild(this.loadingAnimation);
275
+ this.tui.requestRender();
276
+ }
277
+ handleMessageStart(event) {
278
+ if (event.type === "message-start" && event.role === "assistant") {
279
+ const assistantMessageComponent = new AssistantMessageComponent();
280
+ this.streamingComponent = assistantMessageComponent;
281
+ this.addComponentWithSpacing(assistantMessageComponent);
282
+ this.streamingComponent.updateContent(event);
283
+ this.tui.requestRender();
284
+ }
285
+ }
286
+ handleMessage(event) {
287
+ if (event.type === "message" && event.role === "assistant") {
288
+ if (this.streamingComponent) {
289
+ this.streamingComponent.updateContent(event);
290
+ this.tui.requestRender();
291
+ }
292
+ }
293
+ }
294
+ handleMessageEnd(event) {
295
+ if (event.type === "message-end" &&
296
+ this.streamingComponent &&
297
+ event.role === "assistant") {
298
+ this.streamingComponent.updateContent(event);
299
+ this.streamingComponent = null;
300
+ this.tui.requestRender();
301
+ }
302
+ }
303
+ handleToolCallLifecycle(event) {
304
+ const component = this.pendingTools.get(event.toolCallId);
305
+ if (component) {
306
+ component.update(event.events);
307
+ }
308
+ else {
309
+ const newComponent = new ToolExecutionComponent(event.events, {
310
+ verboseMode: this.verboseMode,
311
+ });
312
+ this.pendingTools.set(event.toolCallId, newComponent);
313
+ this.allToolExecutions.push(newComponent);
314
+ this.addComponentWithSpacing(newComponent);
315
+ }
316
+ this.tui.requestRender();
317
+ }
318
+ async handleAgentStop() {
319
+ stopProgress();
320
+ await alert();
321
+ if (this.loadingAnimation) {
322
+ this.loadingAnimation.stop();
323
+ this.loadingAnimation = null;
324
+ this.statusContainer.clear();
325
+ }
326
+ if (this.streamingComponent) {
327
+ this.streamingComponent = null;
328
+ }
329
+ this.pendingTools.clear();
330
+ this.editor.disableSubmit = false;
331
+ this.options.sessionManager.clearTransientMessages();
332
+ if (!this.options.noSession) {
333
+ await this.options.sessionManager.save();
334
+ }
335
+ await getProjectStatus().then((ps) => {
336
+ this.footer.setState({
337
+ projectStatus: ps,
338
+ currentContextWindow: this.options.sessionManager.getLastTurnContextWindow(),
339
+ contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
340
+ });
341
+ this.tui.requestRender();
342
+ });
343
+ this.tui.requestRender();
344
+ }
345
+ async handleAgentError(event) {
346
+ logger.error(event, "agent-error");
347
+ this.options.sessionManager.clearTransientMessages();
348
+ if (!this.options.noSession) {
349
+ await this.options.sessionManager.save();
350
+ }
351
+ if (this.loadingAnimation) {
352
+ this.loadingAnimation.stop();
353
+ this.loadingAnimation = null;
354
+ this.statusContainer.clear();
355
+ }
356
+ if (this.streamingComponent) {
357
+ this.streamingComponent = null;
358
+ }
359
+ this.pendingTools.clear();
360
+ this.editor.disableSubmit = false;
361
+ this.tui.requestRender();
362
+ }
363
+ handleThinkingStart(event) {
364
+ const component = new ThinkingBlockComponent(undefined, {
365
+ verboseMode: this.verboseMode,
366
+ });
367
+ this.thinkingBlockComponent = component;
368
+ this.allThinkingBlocks.push(component);
369
+ if (this.streamingComponent) {
370
+ this.chatContainer.insertChildBefore(this.streamingComponent, component);
371
+ this.chatContainer.insertChildBefore(this.streamingComponent, new Spacer(1));
372
+ }
373
+ else {
374
+ this.addComponentWithSpacing(component);
375
+ }
376
+ this.thinkingBlockComponent.updateContent({ content: event.content });
377
+ this.tui.requestRender();
378
+ }
379
+ handleThinking(event) {
380
+ if (this.thinkingBlockComponent) {
381
+ this.thinkingBlockComponent.updateContent(event);
382
+ this.tui.requestRender();
383
+ }
384
+ }
385
+ handleThinkingEnd() {
386
+ if (this.thinkingBlockComponent) {
387
+ this.thinkingBlockComponent.endThinking();
388
+ this.thinkingBlockComponent = null;
389
+ this.tui.requestRender();
390
+ }
391
+ }
426
392
  /** Adds a user message component to the chat container. */
427
393
  addMessageToChat(message) {
428
394
  if (message.role === "user") {
@@ -473,10 +439,6 @@ export class Repl {
473
439
  * display.
474
440
  */
475
441
  async rerender() {
476
- const modeState = this.options.sessionManager.getMetadata("modeState");
477
- if (modeState && typeof modeState === "object" && "mode" in modeState) {
478
- this.modeManager.fromJson(modeState);
479
- }
480
442
  // When resuming a session, populate tokenTracker with historical usage
481
443
  // so the footer displays the correct total session usage
482
444
  const totalUsage = this.options.sessionManager.getTotalTokenUsage();
@@ -500,7 +462,6 @@ export class Repl {
500
462
  projectStatus: await getProjectStatus(),
501
463
  currentContextWindow: this.options.sessionManager.getLastTurnContextWindow(),
502
464
  contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
503
- currentMode: this.modeManager.getDisplayName(),
504
465
  });
505
466
  // Reconstruct entire session display from messages
506
467
  this.reconstructSession();
@@ -520,7 +481,25 @@ export class Repl {
520
481
  this.chatContainer.clear();
521
482
  // Get session messages
522
483
  const messages = this.options.sessionManager.get();
523
- // First pass: collect all tool results
484
+ const toolResults = this.collectToolResults(messages);
485
+ // Render all messages in order
486
+ for (let i = 0; i < messages.length; i++) {
487
+ const message = messages[i];
488
+ if (message.role === "user") {
489
+ this.renderUserMessageFromSession(message);
490
+ }
491
+ else if (message.role === "assistant") {
492
+ this.renderAssistantMessage(message);
493
+ this.renderToolCallsForAssistantMessage(message, toolResults);
494
+ }
495
+ // Tool messages are handled through their associated assistant message
496
+ }
497
+ }
498
+ /**
499
+ * Collects all tool results from tool-role messages into a map
500
+ * keyed by tool call ID.
501
+ */
502
+ collectToolResults(messages) {
524
503
  const toolResults = new Map();
525
504
  for (const message of messages) {
526
505
  if (message.role !== "tool")
@@ -529,49 +508,53 @@ export class Repl {
529
508
  if (!Array.isArray(content))
530
509
  continue;
531
510
  for (const part of content) {
532
- if (part.type === "tool-result") {
533
- const output = part.output;
534
- const outputValue = output && typeof output === "object" && "value" in output
535
- ? String(output.value)
536
- : "";
537
- toolResults.set(part.toolCallId, {
538
- toolName: part.toolName,
539
- outputValue,
511
+ const toolPart = part;
512
+ if (toolPart.type === "tool-result") {
513
+ toolResults.set(toolPart.toolCallId ?? "", {
514
+ toolName: toolPart.toolName ?? "",
515
+ outputValue: this.extractToolOutputValue(toolPart.output),
540
516
  isError: false,
541
517
  });
542
518
  }
543
519
  }
544
520
  }
545
- // Second pass: render all messages in order
546
- for (let i = 0; i < messages.length; i++) {
547
- const message = messages[i];
548
- if (message.role === "user") {
549
- // Render user message
550
- const textContent = this.extractUserMessageText(message);
551
- if (textContent) {
552
- const userComponent = new UserMessageComponent(textContent);
553
- this.addComponentWithSpacing(userComponent);
554
- }
555
- }
556
- else if (message.role === "assistant") {
557
- // Render assistant message text parts
558
- this.renderAssistantMessage(message);
559
- // Collect and render tool calls for this assistant message
560
- const toolCallsForThisAssistant = this.extractToolCallsFromAssistant(message, toolResults);
561
- for (const toolCallContent of toolCallsForThisAssistant) {
562
- const toolCallId = toolCallContent.toolCallId;
563
- const events = this.createToolEvents(toolCallContent);
564
- if (events.length > 0) {
565
- const component = new ToolExecutionComponent(events, {
566
- verboseMode: this.verboseMode,
567
- });
568
- this.pendingTools.set(toolCallId, component);
569
- this.allToolExecutions.push(component);
570
- this.addComponentWithSpacing(component);
571
- }
572
- }
521
+ return toolResults;
522
+ }
523
+ /**
524
+ * Extracts the output value string from a tool result's output field.
525
+ */
526
+ extractToolOutputValue(output) {
527
+ if (output && typeof output === "object" && "value" in output) {
528
+ return String(output["value"]);
529
+ }
530
+ return "";
531
+ }
532
+ /**
533
+ * Renders a user message into the chat container.
534
+ */
535
+ renderUserMessageFromSession(message) {
536
+ const textContent = this.extractUserMessageText(message);
537
+ if (textContent) {
538
+ const userComponent = new UserMessageComponent(textContent);
539
+ this.addComponentWithSpacing(userComponent);
540
+ }
541
+ }
542
+ /**
543
+ * Renders tool call execution components for an assistant message.
544
+ */
545
+ renderToolCallsForAssistantMessage(message, toolResults) {
546
+ const toolCallsForThisAssistant = this.extractToolCallsFromAssistant(message, toolResults);
547
+ for (const toolCallContent of toolCallsForThisAssistant) {
548
+ const toolCallId = toolCallContent.toolCallId;
549
+ const events = this.createToolEvents(toolCallContent);
550
+ if (events.length > 0) {
551
+ const component = new ToolExecutionComponent(events, {
552
+ verboseMode: this.verboseMode,
553
+ });
554
+ this.pendingTools.set(toolCallId, component);
555
+ this.allToolExecutions.push(component);
556
+ this.addComponentWithSpacing(component);
573
557
  }
574
- // Tool messages are handled through their associated assistant message
575
558
  }
576
559
  }
577
560
  /**
@@ -722,17 +705,11 @@ export class Repl {
722
705
  */
723
706
  async handleCtrlN() {
724
707
  if (!this.options.sessionManager.isEmpty()) {
725
- // Auto-generate rules before starting new session if enabled
726
- // Run in background - don't block new session from starting
727
- this.maybeGenerateRules().catch((err) => logger.debug({ err }, "Background rule generation failed"));
728
- this.options.sessionManager.setMetadata("modeState", this.modeManager.toJson());
729
708
  if (!this.options.noSession) {
730
709
  await this.options.sessionManager.save();
731
710
  }
732
711
  this.options.sessionManager.create(this.options.modelManager.getModel("repl").modelId);
733
712
  }
734
- this.config = await this.options.configManager.getConfig();
735
- this.modeManager.reset();
736
713
  this.options.sessionManager.clearTransientMessages();
737
714
  this.options.tokenTracker.reset();
738
715
  setTerminalTitle(`acai: ${process.cwd()}`);
@@ -747,7 +724,6 @@ export class Repl {
747
724
  projectStatus: this.footer.getProjectStatus(),
748
725
  currentContextWindow: 0,
749
726
  contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
750
- currentMode: this.modeManager.getDisplayName(),
751
727
  });
752
728
  this.tui.requestRender();
753
729
  }
@@ -769,7 +745,6 @@ export class Repl {
769
745
  }
770
746
  this.notification.setMessage("");
771
747
  this.tui.requestRender();
772
- this.options.sessionManager.setMetadata("modeState", this.modeManager.toJson());
773
748
  if (!this.options.noSession) {
774
749
  void this.options.sessionManager.save();
775
750
  }
@@ -795,7 +770,6 @@ export class Repl {
795
770
  }
796
771
  this.notification.setMessage("");
797
772
  this.tui.requestRender();
798
- this.options.sessionManager.setMetadata("modeState", this.modeManager.toJson());
799
773
  if (!this.options.noSession) {
800
774
  void this.options.sessionManager.save();
801
775
  }
@@ -848,41 +822,4 @@ export class Repl {
848
822
  this.isInitialized = false;
849
823
  }
850
824
  }
851
- /**
852
- * Generates rules automatically if autoGenerateRules is enabled
853
- * and the session has messages.
854
- */
855
- async maybeGenerateRules() {
856
- try {
857
- const config = this.config;
858
- if (!config.autoGenerateRules) {
859
- return;
860
- }
861
- if (this.options.sessionManager.isEmpty()) {
862
- return;
863
- }
864
- const { rules } = await generateRulesFromSession({
865
- modelManager: this.options.modelManager,
866
- messages: this.options.sessionManager.get(),
867
- tokenTracker: this.options.tokenTracker,
868
- config: this.options.configManager,
869
- workspace: this.options.workspace,
870
- });
871
- if (rules.length > 0) {
872
- this.notification.setMessage(`Auto-generated ${rules.length} rule(s) saved`);
873
- this.tui.requestRender();
874
- }
875
- }
876
- catch (error) {
877
- // Don't fail the session transition on rule generation errors
878
- logger.debug({ error }, "Auto rule generation failed");
879
- }
880
- }
881
- /**
882
- * Triggers rule generation for use before exit.
883
- * Returns a promise that resolves when rules are generated.
884
- */
885
- async triggerRuleGeneration() {
886
- await this.maybeGenerateRules();
887
- }
888
825
  }