@travisennis/acai 0.0.12 → 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 (237) hide show
  1. package/README.md +3 -2
  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 -1
  9. package/dist/commands/manager.d.ts.map +1 -1
  10. package/dist/commands/manager.js +0 -18
  11. package/dist/commands/share/html-renderer.d.ts.map +1 -1
  12. package/dist/commands/share/html-renderer.js +54 -48
  13. package/dist/commands/tools/index.js +39 -38
  14. package/dist/config/index.d.ts +0 -2
  15. package/dist/config/index.d.ts.map +1 -1
  16. package/dist/config/index.js +2 -6
  17. package/dist/index.d.ts +14 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +94 -76
  20. package/dist/models/manager.d.ts +1 -10
  21. package/dist/models/manager.d.ts.map +1 -1
  22. package/dist/models/manager.js +2 -2
  23. package/dist/models/opencode-go-provider.d.ts +4 -4
  24. package/dist/models/opencode-go-provider.d.ts.map +1 -1
  25. package/dist/models/opencode-go-provider.js +29 -35
  26. package/dist/models/providers.d.ts +1 -1
  27. package/dist/models/providers.d.ts.map +1 -1
  28. package/dist/prompts/system-prompt.d.ts +0 -2
  29. package/dist/prompts/system-prompt.d.ts.map +1 -1
  30. package/dist/prompts/system-prompt.js +6 -10
  31. package/dist/repl/index.d.ts +27 -11
  32. package/dist/repl/index.d.ts.map +1 -1
  33. package/dist/repl/index.js +238 -254
  34. package/dist/skills/index.d.ts +12 -2
  35. package/dist/skills/index.d.ts.map +1 -1
  36. package/dist/skills/index.js +123 -73
  37. package/dist/terminal/control.d.ts +1 -21
  38. package/dist/terminal/control.d.ts.map +1 -1
  39. package/dist/terminal/control.js +1 -32
  40. package/dist/terminal/formatting.d.ts +0 -33
  41. package/dist/terminal/formatting.d.ts.map +1 -1
  42. package/dist/terminal/formatting.js +0 -91
  43. package/dist/terminal/highlight/theme.d.ts +0 -37
  44. package/dist/terminal/highlight/theme.d.ts.map +1 -1
  45. package/dist/terminal/highlight/theme.js +1 -79
  46. package/dist/terminal/keys.d.ts +0 -97
  47. package/dist/terminal/keys.d.ts.map +1 -1
  48. package/dist/terminal/keys.js +0 -194
  49. package/dist/terminal/select-prompt.d.ts.map +1 -1
  50. package/dist/terminal/select-prompt.js +65 -51
  51. package/dist/terminal/style.d.ts +1 -1
  52. package/dist/terminal/style.d.ts.map +1 -1
  53. package/dist/terminal/supports-color.d.ts.map +1 -1
  54. package/dist/terminal/supports-color.js +38 -20
  55. package/dist/terminal/supports-hyperlinks.d.ts +3 -0
  56. package/dist/terminal/supports-hyperlinks.d.ts.map +1 -1
  57. package/dist/terminal/supports-hyperlinks.js +72 -31
  58. package/dist/terminal/table/layout-manager.d.ts +0 -20
  59. package/dist/terminal/table/layout-manager.d.ts.map +1 -1
  60. package/dist/terminal/table/layout-manager.js +68 -44
  61. package/dist/terminal/table/utils.d.ts +0 -1
  62. package/dist/terminal/table/utils.d.ts.map +1 -1
  63. package/dist/terminal/table/utils.js +2 -4
  64. package/dist/tools/apply-patch.d.ts +5 -3
  65. package/dist/tools/apply-patch.d.ts.map +1 -1
  66. package/dist/tools/apply-patch.js +154 -123
  67. package/dist/tools/bash.d.ts.map +1 -1
  68. package/dist/tools/bash.js +11 -8
  69. package/dist/tools/dynamic-tool-loader.d.ts +6 -1
  70. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  71. package/dist/tools/dynamic-tool-loader.js +154 -135
  72. package/dist/tools/index.d.ts +3 -133
  73. package/dist/tools/index.d.ts.map +1 -1
  74. package/dist/tools/index.js +0 -20
  75. package/dist/tools/read-file.d.ts.map +1 -1
  76. package/dist/tools/read-file.js +32 -13
  77. package/dist/tools/skill.d.ts.map +1 -1
  78. package/dist/tools/skill.js +20 -13
  79. package/dist/tools/web-fetch.d.ts +2 -6
  80. package/dist/tools/web-fetch.d.ts.map +1 -1
  81. package/dist/tools/web-fetch.js +59 -36
  82. package/dist/tools/web-search.d.ts +0 -4
  83. package/dist/tools/web-search.d.ts.map +1 -1
  84. package/dist/tools/web-search.js +40 -32
  85. package/dist/tui/autocomplete/utils.d.ts +0 -15
  86. package/dist/tui/autocomplete/utils.d.ts.map +1 -1
  87. package/dist/tui/autocomplete/utils.js +0 -85
  88. package/dist/tui/autocomplete.d.ts +1 -1
  89. package/dist/tui/autocomplete.d.ts.map +1 -1
  90. package/dist/tui/autocomplete.js +1 -1
  91. package/dist/tui/components/editor.d.ts +12 -0
  92. package/dist/tui/components/editor.d.ts.map +1 -1
  93. package/dist/tui/components/editor.js +181 -195
  94. package/dist/tui/components/input.d.ts +4 -0
  95. package/dist/tui/components/input.d.ts.map +1 -1
  96. package/dist/tui/components/input.js +33 -31
  97. package/dist/tui/components/markdown.d.ts +30 -0
  98. package/dist/tui/components/markdown.d.ts.map +1 -1
  99. package/dist/tui/components/markdown.js +274 -242
  100. package/dist/tui/components/modal.d.ts.map +1 -1
  101. package/dist/tui/components/modal.js +11 -11
  102. package/dist/tui/components/select-list.d.ts +5 -0
  103. package/dist/tui/components/select-list.d.ts.map +1 -1
  104. package/dist/tui/components/select-list.js +69 -98
  105. package/dist/tui/components/table.d.ts +6 -0
  106. package/dist/tui/components/table.d.ts.map +1 -1
  107. package/dist/tui/components/table.js +61 -52
  108. package/dist/tui/index.d.ts +1 -8
  109. package/dist/tui/index.d.ts.map +1 -1
  110. package/dist/tui/index.js +0 -8
  111. package/dist/tui/tui.d.ts +9 -0
  112. package/dist/tui/tui.d.ts.map +1 -1
  113. package/dist/tui/tui.js +78 -48
  114. package/dist/tui/utils.d.ts +7 -0
  115. package/dist/tui/utils.d.ts.map +1 -1
  116. package/dist/tui/utils.js +117 -53
  117. package/dist/utils/bash.d.ts.map +1 -1
  118. package/dist/utils/bash.js +121 -104
  119. package/dist/utils/command-protection.d.ts +3 -2
  120. package/dist/utils/command-protection.d.ts.map +1 -1
  121. package/dist/utils/command-protection.js +42 -33
  122. package/dist/utils/filesystem/operations.d.ts +0 -15
  123. package/dist/utils/filesystem/operations.d.ts.map +1 -1
  124. package/dist/utils/filesystem/operations.js +1 -38
  125. package/dist/utils/filesystem/security.d.ts.map +1 -1
  126. package/dist/utils/filesystem/security.js +22 -15
  127. package/dist/utils/filetype-detection.d.ts +0 -1
  128. package/dist/utils/filetype-detection.d.ts.map +1 -1
  129. package/dist/utils/filetype-detection.js +0 -12
  130. package/dist/utils/formatting.d.ts +0 -30
  131. package/dist/utils/formatting.d.ts.map +1 -1
  132. package/dist/utils/formatting.js +0 -44
  133. package/dist/utils/git.d.ts +4 -6
  134. package/dist/utils/git.d.ts.map +1 -1
  135. package/dist/utils/git.js +36 -46
  136. package/dist/utils/ignore.d.ts +1 -1
  137. package/dist/utils/ignore.d.ts.map +1 -1
  138. package/dist/utils/ignore.js +1 -1
  139. package/dist/utils/process.d.ts.map +1 -1
  140. package/dist/utils/process.js +77 -79
  141. package/dist/utils/yaml.d.ts +0 -1
  142. package/dist/utils/yaml.d.ts.map +1 -1
  143. package/dist/utils/yaml.js +80 -89
  144. package/dist/utils/zod.d.ts +0 -3
  145. package/dist/utils/zod.d.ts.map +1 -1
  146. package/dist/utils/zod.js +0 -7
  147. package/package.json +25 -24
  148. package/dist/agent/sub-agent.d.ts +0 -23
  149. package/dist/agent/sub-agent.d.ts.map +0 -1
  150. package/dist/agent/sub-agent.js +0 -109
  151. package/dist/commands/add-directory/index.d.ts +0 -3
  152. package/dist/commands/add-directory/index.d.ts.map +0 -1
  153. package/dist/commands/add-directory/index.js +0 -50
  154. package/dist/commands/add-directory/utils.d.ts +0 -3
  155. package/dist/commands/add-directory/utils.d.ts.map +0 -1
  156. package/dist/commands/add-directory/utils.js +0 -15
  157. package/dist/commands/clear/index.d.ts +0 -3
  158. package/dist/commands/clear/index.d.ts.map +0 -1
  159. package/dist/commands/clear/index.js +0 -13
  160. package/dist/commands/generate-rules/index.d.ts +0 -3
  161. package/dist/commands/generate-rules/index.d.ts.map +0 -1
  162. package/dist/commands/generate-rules/index.js +0 -206
  163. package/dist/commands/generate-rules/service.d.ts +0 -22
  164. package/dist/commands/generate-rules/service.d.ts.map +0 -1
  165. package/dist/commands/generate-rules/service.js +0 -103
  166. package/dist/commands/generate-rules/utils.d.ts +0 -5
  167. package/dist/commands/generate-rules/utils.d.ts.map +0 -1
  168. package/dist/commands/generate-rules/utils.js +0 -25
  169. package/dist/commands/handoff/index.d.ts +0 -3
  170. package/dist/commands/handoff/index.d.ts.map +0 -1
  171. package/dist/commands/handoff/index.js +0 -97
  172. package/dist/commands/handoff/utils.d.ts +0 -4
  173. package/dist/commands/handoff/utils.d.ts.map +0 -1
  174. package/dist/commands/handoff/utils.js +0 -123
  175. package/dist/commands/list-directories/index.d.ts +0 -3
  176. package/dist/commands/list-directories/index.d.ts.map +0 -1
  177. package/dist/commands/list-directories/index.js +0 -35
  178. package/dist/commands/pickup/index.d.ts +0 -3
  179. package/dist/commands/pickup/index.d.ts.map +0 -1
  180. package/dist/commands/pickup/index.js +0 -141
  181. package/dist/commands/pickup/types.d.ts +0 -6
  182. package/dist/commands/pickup/types.d.ts.map +0 -1
  183. package/dist/commands/pickup/types.js +0 -1
  184. package/dist/commands/pickup/utils.d.ts +0 -7
  185. package/dist/commands/pickup/utils.d.ts.map +0 -1
  186. package/dist/commands/pickup/utils.js +0 -56
  187. package/dist/commands/remove-directory/index.d.ts +0 -3
  188. package/dist/commands/remove-directory/index.d.ts.map +0 -1
  189. package/dist/commands/remove-directory/index.js +0 -55
  190. package/dist/commands/review/index.d.ts +0 -3
  191. package/dist/commands/review/index.d.ts.map +0 -1
  192. package/dist/commands/review/index.js +0 -12
  193. package/dist/commands/review/review-panel.d.ts +0 -3
  194. package/dist/commands/review/review-panel.d.ts.map +0 -1
  195. package/dist/commands/review/review-panel.js +0 -186
  196. package/dist/commands/review/utils.d.ts +0 -18
  197. package/dist/commands/review/utils.d.ts.map +0 -1
  198. package/dist/commands/review/utils.js +0 -146
  199. package/dist/commands/shell/index.d.ts +0 -3
  200. package/dist/commands/shell/index.d.ts.map +0 -1
  201. package/dist/commands/shell/index.js +0 -96
  202. package/dist/subagents/index.d.ts +0 -16
  203. package/dist/subagents/index.d.ts.map +0 -1
  204. package/dist/subagents/index.js +0 -231
  205. package/dist/terminal/index.d.ts +0 -9
  206. package/dist/terminal/index.d.ts.map +0 -1
  207. package/dist/terminal/index.js +0 -8
  208. package/dist/tools/agent.d.ts +0 -27
  209. package/dist/tools/agent.d.ts.map +0 -1
  210. package/dist/tools/agent.js +0 -81
  211. package/dist/tools/directory-tree.d.ts +0 -28
  212. package/dist/tools/directory-tree.d.ts.map +0 -1
  213. package/dist/tools/directory-tree.js +0 -154
  214. package/dist/tools/glob.d.ts +0 -35
  215. package/dist/tools/glob.d.ts.map +0 -1
  216. package/dist/tools/glob.js +0 -167
  217. package/dist/tools/grep.d.ts +0 -100
  218. package/dist/tools/grep.d.ts.map +0 -1
  219. package/dist/tools/grep.js +0 -608
  220. package/dist/tools/ls.d.ts +0 -26
  221. package/dist/tools/ls.d.ts.map +0 -1
  222. package/dist/tools/ls.js +0 -83
  223. package/dist/tui/components/header.d.ts +0 -21
  224. package/dist/tui/components/header.d.ts.map +0 -1
  225. package/dist/tui/components/header.js +0 -63
  226. package/dist/utils/bash/parse.d.ts +0 -19
  227. package/dist/utils/bash/parse.d.ts.map +0 -1
  228. package/dist/utils/bash/parse.js +0 -223
  229. package/dist/utils/bash/quote.d.ts +0 -6
  230. package/dist/utils/bash/quote.d.ts.map +0 -1
  231. package/dist/utils/bash/quote.js +0 -23
  232. package/dist/utils/generators.d.ts +0 -3
  233. package/dist/utils/generators.d.ts.map +0 -1
  234. package/dist/utils/generators.js +0 -25
  235. package/dist/utils/glob.d.ts +0 -52
  236. package/dist/utils/glob.d.ts.map +0 -1
  237. package/dist/utils/glob.js +0 -376
@@ -1,206 +0,0 @@
1
- import { getTerminalSize, isArrowDown, isArrowUp, isEnter, isEscape, isShiftTab, isTab, } from "../../terminal/control.js";
2
- import style from "../../terminal/style.js";
3
- import { Container, Input, Spacer, Text, } from "../../tui/index.js";
4
- import { logger } from "../../utils/logger.js";
5
- import { generateRulesFromSession } from "./service.js";
6
- import { hideRuleSelector } from "./utils.js";
7
- export const generateRulesCommand = ({ sessionManager, modelManager, tokenTracker, config, workspace, }) => {
8
- return {
9
- command: "/generate-rules",
10
- description: "Analyzes the current conversation to generate and save new interaction rules, then displays them.",
11
- getSubCommands: () => Promise.resolve([]),
12
- async handle(_args, { tui, container, inputContainer, editor, }) {
13
- if (sessionManager.isEmpty()) {
14
- container.addChild(new Text(style.yellow("Cannot generate rules from an empty conversation."), 1, 0));
15
- tui.requestRender();
16
- editor.setText("");
17
- return "continue";
18
- }
19
- container.addChild(new Text("Analyzing conversation to generate rules...", 0, 1));
20
- tui.requestRender();
21
- try {
22
- const { rules: newRules } = await generateRulesFromSession({
23
- modelManager,
24
- messages: sessionManager.get(),
25
- tokenTracker,
26
- config,
27
- workspace,
28
- });
29
- if (newRules == null || newRules.length === 0) {
30
- container.addChild(new Text(style.yellow("No new generalizable rules were identified."), 2, 0));
31
- tui.requestRender();
32
- editor.setText("");
33
- return "continue";
34
- }
35
- const ruleSelector = new RuleSelectorComponent(newRules, async (selectedRules) => {
36
- if (selectedRules.length === 0) {
37
- container.addChild(new Text(style.yellow("No rules selected to save."), 2, 0));
38
- }
39
- else {
40
- try {
41
- const existingRules = await config.readLearnedRulesFile();
42
- const rulesToAdd = selectedRules.join("\n");
43
- const updatedRules = existingRules.endsWith("\n") || existingRules.length === 0
44
- ? `${existingRules}${rulesToAdd}`
45
- : `${existingRules}\n${rulesToAdd}`;
46
- await config.writeLearnedRulesFile(updatedRules);
47
- container.addChild(new Text(style.green("Selected rules saved to learned rules."), 2, 0));
48
- container.addChild(new Text(style.dim("Saved rules:"), 3, 0));
49
- selectedRules.forEach((rule, index) => {
50
- container.addChild(new Text(`- ${rule}`, 4 + index, 0));
51
- });
52
- }
53
- catch (error) {
54
- container.addChild(new Text(style.red(`Failed to save rules: ${error}`), 2, 0));
55
- }
56
- }
57
- hideRuleSelector(inputContainer, editor, tui);
58
- tui.requestRender();
59
- }, () => {
60
- hideRuleSelector(inputContainer, editor, tui);
61
- tui.requestRender();
62
- });
63
- inputContainer.clear();
64
- inputContainer.addChild(ruleSelector);
65
- tui.setFocus(ruleSelector);
66
- tui.requestRender();
67
- return "continue";
68
- }
69
- catch (error) {
70
- const errorMessage = error instanceof Error ? error.message : String(error);
71
- container.addChild(new Text(style.red(`Error generating rules: ${errorMessage}`), 0, 1));
72
- logger.error(error, "Error during rule generation:");
73
- tui.requestRender();
74
- editor.setText("");
75
- return "continue";
76
- }
77
- },
78
- };
79
- };
80
- class RuleSelectorComponent extends Container {
81
- searchInput;
82
- listContainer;
83
- allRules = [];
84
- filteredRules = [];
85
- selectedIndex = 0;
86
- selectedRules = new Set();
87
- onSelectCallback;
88
- onCancelCallback;
89
- constructor(rules, onSelect, onCancel) {
90
- super();
91
- this.onSelectCallback = onSelect;
92
- this.onCancelCallback = onCancel;
93
- this.allRules = rules;
94
- this.filteredRules = rules;
95
- const { columns } = getTerminalSize();
96
- this.addChild(new Text(style.blue("─".repeat(columns)), 0, 0));
97
- this.addChild(new Spacer(1));
98
- this.searchInput = new Input();
99
- this.searchInput.onSubmit = () => {
100
- this.toggleSelection(this.selectedIndex);
101
- };
102
- this.addChild(this.searchInput);
103
- this.addChild(new Spacer(1));
104
- this.listContainer = new Container();
105
- this.addChild(this.listContainer);
106
- this.addChild(new Spacer(1));
107
- this.addChild(new Text(style.dim("Space: toggle selection, Enter: confirm, Escape: cancel"), 0, 0));
108
- this.addChild(new Spacer(1));
109
- this.addChild(new Text(style.blue("─".repeat(columns)), 0, 0));
110
- this.updateList();
111
- }
112
- filterRules(query) {
113
- if (!query.trim()) {
114
- this.filteredRules = this.allRules;
115
- }
116
- else {
117
- const searchTokens = query
118
- .toLowerCase()
119
- .split(/\s+/)
120
- .filter((t) => t);
121
- this.filteredRules = this.allRules.filter((rule) => {
122
- const searchText = rule.toLowerCase();
123
- return searchTokens.every((token) => searchText.includes(token));
124
- });
125
- }
126
- this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredRules.length - 1));
127
- this.updateList();
128
- }
129
- updateList() {
130
- this.listContainer.clear();
131
- const maxVisible = 10;
132
- const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(maxVisible / 2), this.filteredRules.length - maxVisible));
133
- const endIndex = Math.min(startIndex + maxVisible, this.filteredRules.length);
134
- for (let i = startIndex; i < endIndex; i++) {
135
- const rule = this.filteredRules[i];
136
- if (!rule)
137
- continue;
138
- const isSelected = i === this.selectedIndex;
139
- const isChecked = this.selectedRules.has(i);
140
- let line = "";
141
- if (isSelected) {
142
- const prefix = style.blue("→ ");
143
- const checkbox = isChecked ? style.green("[✓] ") : "[ ] ";
144
- const ruleText = rule;
145
- line = `${prefix + checkbox + style.blue(ruleText)}`;
146
- }
147
- else {
148
- const checkbox = isChecked ? style.green("[✓] ") : "[ ] ";
149
- const ruleText = ` ${rule}`;
150
- line = `${checkbox + ruleText}`;
151
- }
152
- this.listContainer.addChild(new Text(line, 0, 0));
153
- }
154
- if (startIndex > 0 || endIndex < this.filteredRules.length) {
155
- const scrollInfo = style.gray(` (${this.selectedIndex + 1}/${this.filteredRules.length})`);
156
- this.listContainer.addChild(new Text(scrollInfo, 0, 0));
157
- }
158
- if (this.filteredRules.length === 0) {
159
- this.listContainer.addChild(new Text(style.gray(" No matching rules"), 0, 0));
160
- }
161
- }
162
- wantsNavigationKeys() {
163
- return true;
164
- }
165
- handleInput(keyData) {
166
- if (isArrowUp(keyData) || isShiftTab(keyData)) {
167
- this.selectedIndex = Math.max(0, this.selectedIndex - 1);
168
- this.updateList();
169
- }
170
- else if (isArrowDown(keyData) || isTab(keyData)) {
171
- this.selectedIndex = Math.min(this.filteredRules.length - 1, this.selectedIndex + 1);
172
- this.updateList();
173
- }
174
- else if (keyData === " ") {
175
- this.toggleSelection(this.selectedIndex);
176
- }
177
- else if (isEnter(keyData)) {
178
- this.handleConfirm();
179
- }
180
- else if (isEscape(keyData)) {
181
- this.onCancelCallback();
182
- }
183
- else {
184
- this.searchInput.handleInput(keyData);
185
- this.filterRules(this.searchInput.getValue());
186
- }
187
- }
188
- toggleSelection(index) {
189
- if (this.selectedRules.has(index)) {
190
- this.selectedRules.delete(index);
191
- }
192
- else {
193
- this.selectedRules.add(index);
194
- }
195
- this.updateList();
196
- }
197
- handleConfirm() {
198
- const selectedRuleTexts = Array.from(this.selectedRules)
199
- .map((index) => this.filteredRules[index])
200
- .filter((rule) => rule !== undefined);
201
- this.onSelectCallback(selectedRuleTexts);
202
- }
203
- getSearchInput() {
204
- return this.searchInput;
205
- }
206
- }
@@ -1,22 +0,0 @@
1
- import { type ModelMessage } from "ai";
2
- import type { ConfigManager } from "../../config/index.ts";
3
- import type { WorkspaceContext } from "../../index.ts";
4
- import type { ModelManager } from "../../models/manager.ts";
5
- import type { TokenTracker } from "../../tokens/tracker.ts";
6
- interface GenerateRulesOptions {
7
- modelManager: ModelManager;
8
- messages: ModelMessage[];
9
- tokenTracker: TokenTracker;
10
- config: ConfigManager;
11
- workspace: WorkspaceContext;
12
- }
13
- interface GenerateRulesResult {
14
- rules: string[];
15
- }
16
- /**
17
- * Analyzes conversation and generates rules without UI interaction.
18
- * Returns the list of generated rules.
19
- */
20
- export declare function generateRulesFromSession(options: GenerateRulesOptions): Promise<GenerateRulesResult>;
21
- export {};
22
- //# sourceMappingURL=service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../source/commands/generate-rules/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,IAAI,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,UAAU,oBAAoB;IAC5B,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,YAAY,EAAE,YAAY,CAAC;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,gBAAgB,CAAC;CAC7B;AAED,UAAU,mBAAmB;IAC3B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CA6D9B"}
@@ -1,103 +0,0 @@
1
- import { generateText } from "ai";
2
- import { systemPrompt } from "../../prompts/system-prompt.js";
3
- import { createUserMessage } from "../../sessions/manager.js";
4
- /**
5
- * Analyzes conversation and generates rules without UI interaction.
6
- * Returns the list of generated rules.
7
- */
8
- export async function generateRulesFromSession(options) {
9
- const { modelManager, messages, tokenTracker, config, workspace } = options;
10
- // Read existing learned rules to avoid duplicates
11
- const existingRules = await config.readLearnedRulesFile();
12
- // Add analysis prompt to messages (clone to avoid side effects)
13
- const analysisMessages = [...messages];
14
- analysisMessages.push(createUserMessage([
15
- `Analyze this conversation and identify ONLY rules that are broadly applicable to FUTURE, UNRELATED tasks.
16
-
17
- **Critical: Most conversations will NOT yield useful generalizable rules.** Only extract a rule if it represents a genuine, reusable principle that would help the agent in completely different contexts.
18
-
19
- **Key Requirements:**
20
- - A rule must be *universally* applicable, not just to this project or similar tasks
21
- - If you're uncertain whether a rule is broadly applicable, DO NOT include it
22
- - Rules about specific files, functions, or variables are NEVER acceptable
23
- - Return an EMPTY list if no broadly applicable rules can be inferred
24
- - Return *only* the Markdown list of rules, with no preamble or explanation
25
-
26
- <existing-rules>
27
- ${existingRules}
28
- </existing-rules>`,
29
- ]));
30
- const systemPromptText = await createAnalysisSystemPrompt(config, workspace);
31
- const { text, usage } = await generateText({
32
- model: modelManager.getModel("conversation-analyzer"),
33
- maxOutputTokens: 8192,
34
- system: systemPromptText,
35
- messages: analysisMessages,
36
- });
37
- tokenTracker.trackUsage("conversation-analyzer", usage);
38
- const potentialRulesText = text.trim();
39
- if (!potentialRulesText || potentialRulesText.length === 0) {
40
- return { rules: [] };
41
- }
42
- const potentialRulesList = potentialRulesText
43
- .split("\n")
44
- .map((rule) => rule.trim())
45
- .filter((rule) => rule.length > 0);
46
- if (potentialRulesList.length === 0) {
47
- return { rules: [] };
48
- }
49
- // Update learned rules file to avoid duplicates in future analysis
50
- const updatedRules = existingRules.endsWith("\n") || existingRules.length === 0
51
- ? `${existingRules}${potentialRulesList.join("\n")}`
52
- : `${existingRules}\n${potentialRulesList.join("\n")}`;
53
- await config.writeLearnedRulesFile(updatedRules);
54
- return { rules: potentialRulesList };
55
- }
56
- async function createAnalysisSystemPrompt(configManager, workspace) {
57
- const projectConfig = await configManager.getConfig();
58
- const sysResult = await systemPrompt({
59
- activeTools: projectConfig.tools.activeTools,
60
- includeRules: true,
61
- allowedDirs: workspace.allowedDirs,
62
- logsPath: projectConfig.logs?.path,
63
- });
64
- const sys = sysResult.prompt;
65
- return `You are an expert analyst reviewing conversations between a coding agent and a software engineer.
66
-
67
- **YOUR PRIMARY DIRECTIVE: Be extremely conservative. Most conversations do NOT contain useful generalizable rules.** Your job is to identify ONLY those rare, genuinely universal principles that would help the agent in completely unrelated future tasks.
68
-
69
- **Your Task:**
70
- 1. Analyze the conversation provided.
71
- 2. Identify corrections or redirections that reveal principles TRUE ACROSS ALMOST ANY CONTEXT.
72
- 3. For each correction, ask yourself: "Would this principle be useful if I were working on a completely different project, with different files, different languages, and different requirements?" If not, DO NOT create a rule.
73
- 4. List only rules that pass this high bar in Markdown bullet points. No preamble.
74
-
75
- **RULES ABOUT RULES:**
76
- - When in doubt, EXCLUDE. It is better to generate no rules than to generate specific ones.
77
- - If a rule references any specific file name, function name, variable name, or project-specific detail, it is INVALID.
78
- - If a rule is specific to a particular language, framework, or tool without broader applicability, it is INVALID.
79
- - If the user simply clarified requirements (not corrected a flawed approach), it is NOT a rule-worthy correction.
80
-
81
- **Valid General Rule Examples:**
82
- <examples>
83
- - Always ask for clarification if the user's request is ambiguous.
84
- - Never make assumptions about file paths without confirmation.
85
- - Always follow the user's explicitly stated formatting preferences.
86
- - Never provide incomplete code snippets without indicating they are partial.
87
- - Always check for potential null or undefined values before accessing properties.
88
- </examples>
89
-
90
- **INVALID Examples (Do NOT generate these):**
91
- <bad-examples>
92
- - Always use 'const' instead of 'let' for variables (too specific - depends on mutability needs)
93
- - Never forget to pass the 'config' object to functions (specific to this codebase)
94
- - Always add a try-catch block around API calls (too specific - depends on error handling strategy)
95
- - Always run tests after making changes (task-specific workflow, not a general principle)
96
- - Never modify the .env file (project-specific)
97
- </bad-examples>
98
-
99
- This is the original system prompt the agent operated under:
100
- <systemPrompt>
101
- ${sys}
102
- </systemPrompt>`;
103
- }
@@ -1,5 +0,0 @@
1
- import type { Container, Editor, TUI } from "../../tui/index.ts";
2
- export declare function hideRuleSelector(editorContainer: Container, editor: Editor, tui: TUI): void;
3
- export declare function parseRulesText(text: string): string[];
4
- export declare function formatRulesForStorage(existingRules: string, newRules: string[]): string;
5
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../source/commands/generate-rules/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAEjE,wBAAgB,gBAAgB,CAC9B,eAAe,EAAE,SAAS,EAC1B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,GAAG,GACP,IAAI,CAIN;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAUrD;AAED,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAAE,GACjB,MAAM,CAUR"}
@@ -1,25 +0,0 @@
1
- export function hideRuleSelector(editorContainer, editor, tui) {
2
- editorContainer.clear();
3
- editorContainer.addChild(editor);
4
- tui.setFocus(editor);
5
- }
6
- export function parseRulesText(text) {
7
- const trimmed = text.trim();
8
- if (!trimmed || trimmed.length === 0) {
9
- return [];
10
- }
11
- return trimmed
12
- .split("\n")
13
- .map((rule) => rule.trim())
14
- .filter((rule) => rule.length > 0);
15
- }
16
- export function formatRulesForStorage(existingRules, newRules) {
17
- if (newRules.length === 0) {
18
- return existingRules;
19
- }
20
- const rulesToAdd = newRules.join("\n");
21
- if (existingRules.endsWith("\n") || existingRules.length === 0) {
22
- return `${existingRules}${rulesToAdd}`;
23
- }
24
- return `${existingRules}\n${rulesToAdd}`;
25
- }
@@ -1,3 +0,0 @@
1
- import type { CommandOptions, ReplCommand } from "../types.ts";
2
- export declare const handoffCommand: (options: CommandOptions) => ReplCommand;
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/commands/handoff/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/D,eAAO,MAAM,cAAc,GAAI,SAAS,cAAc,KAAG,WA2DxD,CAAC"}
@@ -1,97 +0,0 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
2
- import { generateText } from "ai";
3
- import { AiConfig } from "../../models/ai-config.js";
4
- import style from "../../terminal/style.js";
5
- import { Spacer, Text } from "../../tui/index.js";
6
- import { generateHandoffFilename, generateHandoffSlug, handoffPrompt, } from "./utils.js";
7
- export const handoffCommand = (options) => {
8
- return {
9
- command: "/handoff",
10
- description: "Creates a detailed handoff plan of the conversation for continuing the work in a new session. Usage: /handoff <the purpose of the handoff>",
11
- getSubCommands: () => Promise.resolve([]),
12
- async handle(args, { tui, container, editor, }) {
13
- const purpose = args.join(" ").trim();
14
- if (!purpose) {
15
- container.addChild(new Text(style.red("Please provide a purpose for the handoff. Usage: /handoff <the purpose of the handoff>"), 1, 0));
16
- tui.requestRender();
17
- editor.setText("");
18
- return "continue";
19
- }
20
- container.addChild(new Spacer(1));
21
- container.addChild(new Text(`Creating handoff document for purpose: ${style.blue(purpose)}`, 1, 0));
22
- tui.requestRender();
23
- const filename = await createHandoffDocument(options, purpose);
24
- container.addChild(new Text(style.green(`Handoff document created: ${filename}`), 2, 0));
25
- container.addChild(new Text(`Use /pickup ${filename.replace(".md", "")} to continue this work.`, 3, 0));
26
- tui.requestRender();
27
- editor.setText("");
28
- return "continue";
29
- },
30
- };
31
- };
32
- async function createHandoffDocument({ modelManager, tokenTracker, sessionManager }, purpose) {
33
- const app = "handoff-agent";
34
- const model = modelManager.getModel(app);
35
- const modelConfig = modelManager.getModelMetadata(app);
36
- const messages = sessionManager.get();
37
- const conversationText = messages
38
- .map((msg) => {
39
- let content = "";
40
- if (Array.isArray(msg.content)) {
41
- content = msg.content
42
- .filter((part) => part.type === "text")
43
- .map((part) => part.text)
44
- .join("\n");
45
- }
46
- else if (typeof msg.content === "string") {
47
- content = msg.content;
48
- }
49
- return `${msg.role}: ${content}`;
50
- })
51
- .filter((text) => text?.trim())
52
- .join("\n\n");
53
- const fullPrompt = `${handoffPrompt(purpose)}\n\n## Conversation History\n\n${conversationText}`;
54
- const aiConfig = new AiConfig({
55
- modelMetadata: modelConfig,
56
- prompt: fullPrompt,
57
- });
58
- let result;
59
- try {
60
- result = await generateText({
61
- model,
62
- maxOutputTokens: aiConfig.maxOutputTokens(),
63
- system: "You are a helpful AI assistant tasked with creating detailed handoff summaries for coding agents. Focus on technical accuracy and completeness so that another agent can seamlessly continue the work.",
64
- prompt: fullPrompt,
65
- temperature: aiConfig.temperature(),
66
- topP: aiConfig.topP(),
67
- providerOptions: aiConfig.providerOptions(),
68
- });
69
- }
70
- catch (error) {
71
- console.error(`Error generating handoff text: ${error}`);
72
- throw new Error(`Failed to generate handoff summary: ${error.message}`);
73
- }
74
- const { text, usage } = result;
75
- tokenTracker.trackUsage(app, usage);
76
- if (!text || text.trim().length === 0) {
77
- throw new Error("AI returned empty response");
78
- }
79
- const slug = generateHandoffSlug(purpose);
80
- const filename = generateHandoffFilename(slug);
81
- const handoffsDir = ".acai/handoffs";
82
- const filepath = `${handoffsDir}/${filename}`;
83
- const handoffDocument = `${text}
84
-
85
- ---
86
- *Generated on ${new Date().toISOString()} for purpose: ${purpose}*
87
- *This handoff file can be used to continue the work using the /pickup command*`;
88
- try {
89
- await mkdir(handoffsDir, { recursive: true });
90
- await writeFile(filepath, handoffDocument, "utf-8");
91
- return filename;
92
- }
93
- catch (error) {
94
- console.error(`Failed to save handoff file: ${error}`);
95
- throw new Error(`Failed to save handoff file: ${error.message}`);
96
- }
97
- }
@@ -1,4 +0,0 @@
1
- export declare const handoffPrompt: (purpose: string) => string;
2
- export declare const generateHandoffSlug: (purpose: string, maxLength?: number) => string;
3
- export declare const generateHandoffFilename: (slug: string) => string;
4
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../source/commands/handoff/utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,KAAG,MAqG/C,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,MAAM,EACf,kBAAc,KACb,MAmBF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,KAAG,MAItD,CAAC"}
@@ -1,123 +0,0 @@
1
- export const handoffPrompt = (purpose) => {
2
- return `Creates a detailed handoff plan of the conversation for continuing the work in a new session.
3
-
4
- The user specified purpose:
5
-
6
- <purpose>${purpose}</purpose>
7
-
8
- You are creating a summary specifically so that it can be continued by another agent. For this to work you MUST have a purpose. If no specified purpose was provided in the \`<purpose>...</purpose>\` tag you must STOP IMMEDIATELY and ask the user what the purpose is.
9
-
10
- Do not continue before asking for the purpose as you will otherwise not understand the instructions and do not assume a purpose!
11
-
12
- ## Goal
13
-
14
- Your task is to create a detailed summary of the conversation so far, paying close attention to the user's explicit purpose for the next steps.
15
- This handoff plan should be thorough in capturing technical details, code patterns, and architectural decisions that will be essential for continuing development work without losing context.
16
-
17
- ## Process
18
-
19
- Before providing your final plan, wrap your analysis in <analysis> tags to organize your thoughts and ensure you've covered all necessary points. In your analysis process:
20
-
21
- 1. Chronologically analyze each message and section of the conversation. For each section thoroughly identify:
22
- - The user's explicit requests and intents
23
- - Your approach to addressing the user's requests
24
- - Key decisions, technical concepts and code patterns
25
- - Specific details like file names, full code snippets, function signatures, file edits, etc
26
- 2. Double-check for technical accuracy and completeness, addressing each required element thoroughly.
27
-
28
- Your plan should include the following sections:
29
-
30
- 1. **Primary Request and Intent**: Capture all of the user's explicit requests and intents in detail
31
- 2. **Key Technical Concepts**: List all important technical concepts, technologies, and frameworks discussed.
32
- 3. **Files and Code Sections**: Enumerate specific files and code sections examined, modified, or created. Pay special attention to the most recent messages and include full code snippets where applicable and include a summary of why this file read or edit is important.
33
- 4. **Problem Solving**: Document problems solved and any ongoing troubleshooting efforts.
34
- 5. **Pending Tasks**: Outline any pending tasks that you have explicitly been asked to work on.
35
- 6. **Current Work**: Describe in detail precisely what was being worked on immediately before this handoff request, paying special attention to the most recent messages from both user and assistant. Include file names and code snippets where applicable.
36
- 7. **Optional Next Step**: List the next step that you will take that is related to the most recent work you were doing. IMPORTANT: ensure that this step is DIRECTLY in line with the user's explicit requests, and the task you were working on immediately before this handoff request. If your last task was concluded, then only list next steps if they are explicitly in line with the users request. Do not start on tangential requests without confirming with the user first.
37
-
38
- Additionally create a "slug" for this handoff. The "slug" is how we will refer to it later in a few places. Examples:
39
-
40
- * current-user-api-handler
41
- * implement-auth
42
- * fix-issue-42
43
-
44
- Together with the slug create a "Readable Summary". Examples:
45
-
46
- * Implement Currnet User API Handler
47
- * Implement Authentication
48
- * Fix Issue #42
49
-
50
- ## Output Structure
51
-
52
- Here's an example of how your output should be structured:
53
-
54
- \`\`\` markdown
55
- # Readable Summary
56
-
57
- <analysis>
58
- [Your thought process, ensuring all points are covered thoroughly and accurately]
59
- </analysis>
60
-
61
- <plan>
62
- # Session Handoff Plan
63
-
64
- ## 1. Primary Request and Intent
65
- [Detailed description of all user requests and intents]
66
-
67
- ## 2. Key Technical Concepts
68
- - [Concept 1]
69
- - [Concept 2]
70
- - [...]
71
-
72
- ## 3. Files and Code Sections
73
- ### [File Name 1]
74
- - **Why important**: [Summary of why this file is important]
75
- - **Changes made**: [Summary of the changes made to this file, if any]
76
- - **Code snippet**:
77
- \`\`\` language
78
- [Important Code Snippet]
79
- \`\`\`
80
-
81
- ### [File Name 2]
82
- - **Code snippet**:
83
- \`\`\` language
84
- [Important Code Snippet]
85
- \`\`\`
86
-
87
- [...]
88
-
89
- ## 4. Problem Solving
90
- [Description of solved problems and ongoing troubleshooting]
91
-
92
- ## 5. Next Step
93
- [Required next step to take, directly aligned with user's explicit handoff purpose]
94
- </plan>
95
- \`\`\`
96
-
97
- ## Final Step
98
-
99
- Provide your complete handoff summary with all the sections above. The system will save it to a file automatically.
100
-
101
- Make sure to include both the slug and readable summary in your response as described.`;
102
- };
103
- export const generateHandoffSlug = (purpose, maxLength = 20) => {
104
- let slug = purpose
105
- .toLowerCase()
106
- .replace(/[^a-z0-9\s-]/g, "")
107
- .replace(/\s+/g, "-")
108
- .replace(/-+/g, "-")
109
- .trim();
110
- // Remove leading and trailing hyphens
111
- slug = slug.replace(/^-+|-+$/g, "");
112
- // Apply maxLength after trimming hyphens
113
- slug = slug.slice(0, maxLength);
114
- if (!slug) {
115
- slug = "session";
116
- }
117
- return slug;
118
- };
119
- export const generateHandoffFilename = (slug) => {
120
- const now = new Date();
121
- const timestamp = now.toISOString().split("T")[0];
122
- return `${timestamp}-${slug}.md`;
123
- };
@@ -1,3 +0,0 @@
1
- import type { CommandOptions, ReplCommand } from "../types.ts";
2
- export declare const listDirectoriesCommand: ({ workspace, }: CommandOptions) => ReplCommand;
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/commands/list-directories/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/D,eAAO,MAAM,sBAAsB,GAAI,gBAEpC,cAAc,KAAG,WAkDnB,CAAC"}
@@ -1,35 +0,0 @@
1
- import { Modal, Container as ModalContainer, ModalText, } from "../../tui/index.js";
2
- export const listDirectoriesCommand = ({ workspace, }) => {
3
- return {
4
- command: "/list-directories",
5
- description: "List all allowed working directories",
6
- getSubCommands: async () => {
7
- return [];
8
- },
9
- async handle(_args, { tui, editor }) {
10
- // Build modal content
11
- const modalContent = new ModalContainer();
12
- modalContent.addChild(new ModalText("Current working directories:", 0, 1));
13
- if (workspace.allowedDirs.length === 0) {
14
- modalContent.addChild(new ModalText("No directories configured. Using current directory only.", 0, 1));
15
- }
16
- else {
17
- // Add each directory as a separate line
18
- workspace.allowedDirs.forEach((dir) => {
19
- const isPrimary = dir === workspace.primaryDir;
20
- const prefix = isPrimary ? "● " : " ";
21
- const indicator = isPrimary ? " (primary)" : "";
22
- modalContent.addChild(new ModalText(`${prefix}${dir}${indicator}`, 0, 0));
23
- });
24
- }
25
- // Create and show modal
26
- const modal = new Modal("Working Directories", modalContent, true, () => {
27
- // Modal closed callback
28
- editor.setText("");
29
- tui.requestRender();
30
- });
31
- tui.showModal(modal);
32
- return "continue";
33
- },
34
- };
35
- };
@@ -1,3 +0,0 @@
1
- import type { CommandOptions, ReplCommand } from "../types.ts";
2
- export declare const pickupCommand: (options: CommandOptions) => ReplCommand;
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/commands/pickup/index.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ/D,eAAO,MAAM,aAAa,GAAI,SAAS,cAAc,KAAG,WA0DvD,CAAC"}