@travisennis/acai 0.0.5 → 0.0.6
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.
- package/README.md +4 -2
- package/dist/agent/index.d.ts +119 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +406 -0
- package/dist/agent/manual-loop.d.ts +41 -0
- package/dist/agent/manual-loop.d.ts.map +1 -0
- package/dist/agent/manual-loop.js +278 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +27 -33
- package/dist/commands/add-directory-command.d.ts +3 -0
- package/dist/commands/add-directory-command.d.ts.map +1 -0
- package/dist/commands/add-directory-command.js +85 -0
- package/dist/commands/application-log-command.d.ts.map +1 -1
- package/dist/commands/application-log-command.js +34 -0
- package/dist/commands/clear-command.d.ts.map +1 -1
- package/dist/commands/clear-command.js +8 -0
- package/dist/commands/compact-command.d.ts.map +1 -1
- package/dist/commands/compact-command.js +15 -2
- package/dist/commands/context-command.d.ts +3 -0
- package/dist/commands/context-command.d.ts.map +1 -0
- package/dist/commands/context-command.js +183 -0
- package/dist/commands/copy-command.d.ts.map +1 -1
- package/dist/commands/copy-command.js +28 -0
- package/dist/commands/edit-command.d.ts.map +1 -1
- package/dist/commands/edit-command.js +33 -0
- package/dist/commands/edit-prompt-command.d.ts.map +1 -1
- package/dist/commands/edit-prompt-command.js +28 -0
- package/dist/commands/exit-command.d.ts.map +1 -1
- package/dist/commands/exit-command.js +20 -0
- package/dist/commands/files-command.d.ts.map +1 -1
- package/dist/commands/files-command.js +57 -0
- package/dist/commands/generate-rules-command.d.ts.map +1 -1
- package/dist/commands/generate-rules-command.js +311 -1
- package/dist/commands/handoff-command.d.ts +3 -0
- package/dist/commands/handoff-command.d.ts.map +1 -0
- package/dist/commands/handoff-command.js +202 -0
- package/dist/commands/health-command.d.ts.map +1 -1
- package/dist/commands/health-command.js +119 -2
- package/dist/commands/help-command.d.ts.map +1 -1
- package/dist/commands/help-command.js +28 -0
- package/dist/commands/history-command.d.ts +3 -0
- package/dist/commands/history-command.d.ts.map +1 -0
- package/dist/commands/history-command.js +534 -0
- package/dist/commands/init-command.d.ts +1 -1
- package/dist/commands/init-command.d.ts.map +1 -1
- package/dist/commands/init-command.js +55 -18
- package/dist/commands/last-log-command.d.ts.map +1 -1
- package/dist/commands/last-log-command.js +27 -0
- package/dist/commands/list-directories-command.d.ts +3 -0
- package/dist/commands/list-directories-command.d.ts.map +1 -0
- package/dist/commands/list-directories-command.js +48 -0
- package/dist/commands/list-tools-command.d.ts.map +1 -1
- package/dist/commands/list-tools-command.js +66 -3
- package/dist/commands/manager.d.ts +15 -3
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +86 -26
- package/dist/commands/model-command.d.ts +22 -0
- package/dist/commands/model-command.d.ts.map +1 -1
- package/dist/commands/model-command.js +256 -0
- package/dist/commands/paste-command.d.ts.map +1 -1
- package/dist/commands/paste-command.js +92 -0
- package/dist/commands/pickup-command.d.ts +3 -0
- package/dist/commands/pickup-command.d.ts.map +1 -0
- package/dist/commands/pickup-command.js +161 -0
- package/dist/commands/prompt-command.d.ts +1 -1
- package/dist/commands/prompt-command.d.ts.map +1 -1
- package/dist/commands/prompt-command.js +117 -2
- package/dist/commands/remove-directory-command.d.ts +3 -0
- package/dist/commands/remove-directory-command.d.ts.map +1 -0
- package/dist/commands/remove-directory-command.js +87 -0
- package/dist/commands/reset-command.d.ts +1 -1
- package/dist/commands/reset-command.d.ts.map +1 -1
- package/dist/commands/reset-command.js +13 -2
- package/dist/commands/rules-command.d.ts.map +1 -1
- package/dist/commands/rules-command.js +65 -0
- package/dist/commands/save-command.d.ts.map +1 -1
- package/dist/commands/save-command.js +12 -0
- package/dist/commands/shell-command.d.ts.map +1 -1
- package/dist/commands/shell-command.js +68 -0
- package/dist/commands/types.d.ts +9 -4
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/usage-command.d.ts.map +1 -1
- package/dist/commands/usage-command.js +22 -0
- package/dist/config.d.ts +6 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +23 -29
- package/dist/formatting.d.ts +108 -0
- package/dist/formatting.d.ts.map +1 -1
- package/dist/formatting.js +147 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +140 -38
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +47 -18
- package/dist/mentions.d.ts +2 -1
- package/dist/mentions.d.ts.map +1 -1
- package/dist/mentions.js +16 -1
- package/dist/messages.d.ts +8 -0
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +56 -19
- package/dist/middleware/cache.d.ts +3 -0
- package/dist/middleware/cache.d.ts.map +1 -0
- package/dist/middleware/cache.js +53 -0
- package/dist/middleware/index.d.ts +1 -0
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +1 -0
- package/dist/models/ai-config.d.ts +4 -2
- package/dist/models/ai-config.d.ts.map +1 -1
- package/dist/models/ai-config.js +12 -2
- package/dist/models/anthropic-provider.d.ts.map +1 -1
- package/dist/models/anthropic-provider.js +3 -60
- package/dist/models/manager.d.ts +2 -1
- package/dist/models/manager.d.ts.map +1 -1
- package/dist/models/manager.js +26 -2
- package/dist/models/openrouter-provider.d.ts +7 -14
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +114 -169
- package/dist/models/providers.d.ts +1 -1
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/prompts.d.ts +1 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +53 -4
- package/dist/repl/display-tool-messages.d.ts +1 -1
- package/dist/repl/display-tool-messages.d.ts.map +1 -1
- package/dist/repl/display-tool-messages.js +47 -44
- package/dist/repl/get-prompt-header.d.ts.map +1 -1
- package/dist/repl/get-prompt-header.js +1 -30
- package/dist/repl/project-status-line.d.ts +2 -0
- package/dist/repl/project-status-line.d.ts.map +1 -0
- package/dist/repl/project-status-line.js +31 -0
- package/dist/repl/prompt.d.ts +21 -0
- package/dist/repl/prompt.d.ts.map +1 -0
- package/dist/{repl-prompt.js → repl/prompt.js} +119 -22
- package/dist/repl/tool-call-repair.d.ts.map +1 -1
- package/dist/repl/tool-call-repair.js +8 -4
- package/dist/repl-new.d.ts +53 -0
- package/dist/repl-new.d.ts.map +1 -0
- package/dist/repl-new.js +374 -0
- package/dist/repl.d.ts +3 -5
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +74 -166
- package/dist/terminal/checkbox-prompt.d.ts.map +1 -1
- package/dist/terminal/checkbox-prompt.js +10 -4
- package/dist/terminal/index.d.ts +7 -0
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +94 -0
- package/dist/terminal/input-prompt.d.ts +2 -1
- package/dist/terminal/input-prompt.d.ts.map +1 -1
- package/dist/terminal/markdown.js +3 -0
- package/dist/terminal/search-prompt.d.ts.map +1 -1
- package/dist/terminal/search-prompt.js +11 -10
- package/dist/terminal/select-prompt.d.ts +2 -2
- package/dist/terminal/select-prompt.d.ts.map +1 -1
- package/dist/terminal/select-prompt.js +47 -39
- package/dist/tokens/threshold.d.ts +35 -0
- package/dist/tokens/threshold.d.ts.map +1 -0
- package/dist/tokens/threshold.js +85 -0
- package/dist/tools/advanced-edit-file.d.ts +69 -0
- package/dist/tools/advanced-edit-file.d.ts.map +1 -0
- package/dist/tools/advanced-edit-file.js +281 -0
- package/dist/tools/agent.d.ts +16 -5
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/agent.js +71 -58
- package/dist/tools/bash-utils.d.ts +1 -1
- package/dist/tools/bash-utils.d.ts.map +1 -1
- package/dist/tools/bash-utils.js +14 -6
- package/dist/tools/bash.d.ts +21 -12
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +88 -135
- package/dist/tools/code-interpreter.d.ts +21 -9
- package/dist/tools/code-interpreter.d.ts.map +1 -1
- package/dist/tools/code-interpreter.js +138 -137
- package/dist/tools/delete-file.d.ts +17 -10
- package/dist/tools/delete-file.d.ts.map +1 -1
- package/dist/tools/delete-file.js +51 -95
- package/dist/tools/directory-tree.d.ts +17 -6
- package/dist/tools/directory-tree.d.ts.map +1 -1
- package/dist/tools/directory-tree.js +47 -49
- package/dist/tools/dynamic-tool-loader.d.ts +18 -8
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +121 -129
- package/dist/tools/dynamic-tool-parser.d.ts +1 -0
- package/dist/tools/dynamic-tool-parser.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-parser.js +1 -0
- package/dist/tools/edit-file.d.ts +35 -15
- package/dist/tools/edit-file.d.ts.map +1 -1
- package/dist/tools/edit-file.js +112 -112
- package/dist/tools/filesystem-utils.d.ts +2 -1
- package/dist/tools/filesystem-utils.d.ts.map +1 -1
- package/dist/tools/filesystem-utils.js +31 -17
- package/dist/tools/glob.d.ts +36 -0
- package/dist/tools/glob.d.ts.map +1 -0
- package/dist/tools/glob.js +143 -0
- package/dist/tools/grep.d.ts +73 -12
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +413 -168
- package/dist/tools/index.d.ts +204 -124
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +242 -135
- package/dist/tools/llm-edit-fixer.d.ts +25 -0
- package/dist/tools/llm-edit-fixer.d.ts.map +1 -0
- package/dist/tools/llm-edit-fixer.js +150 -0
- package/dist/tools/move-file.d.ts +19 -7
- package/dist/tools/move-file.d.ts.map +1 -1
- package/dist/tools/move-file.js +40 -33
- package/dist/tools/read-file.d.ts +47 -9
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +74 -69
- package/dist/tools/read-multiple-files.d.ts +17 -6
- package/dist/tools/read-multiple-files.d.ts.map +1 -1
- package/dist/tools/read-multiple-files.js +76 -73
- package/dist/tools/save-file.d.ts +45 -12
- package/dist/tools/save-file.d.ts.map +1 -1
- package/dist/tools/save-file.js +58 -101
- package/dist/tools/think.d.ts +15 -7
- package/dist/tools/think.d.ts.map +1 -1
- package/dist/tools/think.js +30 -22
- package/dist/tools/types.d.ts +4 -10
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js +9 -0
- package/dist/tools/utils.d.ts +14 -0
- package/dist/tools/utils.d.ts.map +1 -0
- package/dist/tools/utils.js +16 -0
- package/dist/tools/web-fetch.d.ts +11 -4
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +39 -38
- package/dist/tools/web-search.d.ts +15 -6
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +50 -32
- package/dist/tui/autocomplete.d.ts +44 -0
- package/dist/tui/autocomplete.d.ts.map +1 -0
- package/dist/tui/autocomplete.js +466 -0
- package/dist/tui/components/assistant-message.d.ts +18 -0
- package/dist/tui/components/assistant-message.d.ts.map +1 -0
- package/dist/tui/components/assistant-message.js +29 -0
- package/dist/tui/components/editor.d.ts +51 -0
- package/dist/tui/components/editor.d.ts.map +1 -0
- package/dist/tui/components/editor.js +758 -0
- package/dist/tui/components/footer.d.ts +24 -0
- package/dist/tui/components/footer.d.ts.map +1 -0
- package/dist/tui/components/footer.js +197 -0
- package/dist/tui/components/input.d.ts +14 -0
- package/dist/tui/components/input.d.ts.map +1 -0
- package/dist/tui/components/input.js +122 -0
- package/dist/tui/components/loader.d.ts +19 -0
- package/dist/tui/components/loader.d.ts.map +1 -0
- package/dist/tui/components/loader.js +45 -0
- package/dist/tui/components/markdown.d.ts +103 -0
- package/dist/tui/components/markdown.d.ts.map +1 -0
- package/dist/tui/components/markdown.js +533 -0
- package/dist/tui/components/modal.d.ts +40 -0
- package/dist/tui/components/modal.d.ts.map +1 -0
- package/dist/tui/components/modal.js +292 -0
- package/dist/tui/components/prompt-status.d.ts +16 -0
- package/dist/tui/components/prompt-status.d.ts.map +1 -0
- package/dist/tui/components/prompt-status.js +21 -0
- package/dist/tui/components/select-list.d.ts +22 -0
- package/dist/tui/components/select-list.d.ts.map +1 -0
- package/dist/tui/components/select-list.js +143 -0
- package/dist/tui/components/spacer.d.ts +16 -0
- package/dist/tui/components/spacer.d.ts.map +1 -0
- package/dist/tui/components/spacer.js +27 -0
- package/dist/tui/components/text.d.ts +26 -0
- package/dist/tui/components/text.d.ts.map +1 -0
- package/dist/tui/components/text.js +143 -0
- package/dist/tui/components/thinking-block.d.ts +14 -0
- package/dist/tui/components/thinking-block.d.ts.map +1 -0
- package/dist/tui/components/thinking-block.js +30 -0
- package/dist/tui/components/tool-execution.d.ts +17 -0
- package/dist/tui/components/tool-execution.d.ts.map +1 -0
- package/dist/tui/components/tool-execution.js +153 -0
- package/dist/tui/components/user-message.d.ts +9 -0
- package/dist/tui/components/user-message.d.ts.map +1 -0
- package/dist/tui/components/user-message.js +21 -0
- package/dist/tui/components/welcome.d.ts +6 -0
- package/dist/tui/components/welcome.d.ts.map +1 -0
- package/dist/tui/components/welcome.js +30 -0
- package/dist/tui/index.d.ts +14 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +18 -0
- package/dist/tui/terminal.d.ts +37 -0
- package/dist/tui/terminal.d.ts.map +1 -0
- package/dist/tui/terminal.js +104 -0
- package/dist/tui/tui.d.ts +67 -0
- package/dist/tui/tui.d.ts.map +1 -0
- package/dist/tui/tui.js +184 -0
- package/dist/tui/utils.d.ts +19 -0
- package/dist/tui/utils.d.ts.map +1 -0
- package/dist/tui/utils.js +31 -0
- package/dist/utils/generators.d.ts +3 -0
- package/dist/utils/generators.d.ts.map +1 -0
- package/dist/utils/generators.js +25 -0
- package/dist/utils/iterables.d.ts +2 -0
- package/dist/utils/iterables.d.ts.map +1 -0
- package/dist/utils/iterables.js +6 -0
- package/package.json +16 -16
- package/dist/conversation-analyzer.d.ts +0 -11
- package/dist/conversation-analyzer.d.ts.map +0 -1
- package/dist/conversation-analyzer.js +0 -88
- package/dist/repl-prompt.d.ts +0 -15
- package/dist/repl-prompt.d.ts.map +0 -1
- package/dist/tokens/manage-output.d.ts +0 -34
- package/dist/tokens/manage-output.d.ts.map +0 -1
- package/dist/tokens/manage-output.js +0 -44
- package/dist/tool-executor.d.ts +0 -28
- package/dist/tool-executor.d.ts.map +0 -1
- package/dist/tool-executor.js +0 -74
- package/dist/tools/file-editing-utils.d.ts +0 -2
- package/dist/tools/file-editing-utils.d.ts.map +0 -1
- package/dist/tools/file-editing-utils.js +0 -135
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import { writeFile } from "node:fs/promises";
|
|
2
|
+
import { generateText } from "ai";
|
|
3
|
+
import { MessageHistory } from "../messages.js";
|
|
4
|
+
import { getTerminalSize } from "../terminal/formatting.js";
|
|
5
|
+
import { select } from "../terminal/select-prompt.js";
|
|
6
|
+
import style from "../terminal/style.js";
|
|
7
|
+
import { Container, Input, Spacer, Text } from "../tui/index.js";
|
|
8
|
+
async function exportConversation(history, terminal) {
|
|
9
|
+
const sanitizedTitle = history.title
|
|
10
|
+
.replace(/[^a-zA-Z0-9\s-_]/g, "")
|
|
11
|
+
.replace(/\s+/g, "-")
|
|
12
|
+
.toLowerCase();
|
|
13
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, -5);
|
|
14
|
+
const filename = `${sanitizedTitle}_${timestamp}.md`;
|
|
15
|
+
const markdownContent = generateMarkdown(history);
|
|
16
|
+
try {
|
|
17
|
+
await writeFile(filename, markdownContent);
|
|
18
|
+
terminal.info(`Conversation exported to: ${filename}`);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
terminal.error(`Failed to export conversation: ${error}`);
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function generateMarkdown(history) {
|
|
26
|
+
const lines = [];
|
|
27
|
+
// Header
|
|
28
|
+
lines.push(`# ${history.title}`);
|
|
29
|
+
lines.push("");
|
|
30
|
+
lines.push("## Conversation Metadata");
|
|
31
|
+
lines.push(`- **Session ID**: ${history.sessionId}`);
|
|
32
|
+
lines.push(`- **Model**: ${history.modelId}`);
|
|
33
|
+
lines.push(`- **Created**: ${history.createdAt.toISOString()}`);
|
|
34
|
+
lines.push(`- **Last Updated**: ${history.updatedAt.toISOString()}`);
|
|
35
|
+
lines.push(`- **Total Messages**: ${history.messages.length}`);
|
|
36
|
+
lines.push("");
|
|
37
|
+
// Messages
|
|
38
|
+
lines.push("## Conversation History");
|
|
39
|
+
lines.push("");
|
|
40
|
+
history.messages.forEach((message, index) => {
|
|
41
|
+
const role = message.role.toUpperCase();
|
|
42
|
+
lines.push(`### ${role} (Message ${index + 1})`);
|
|
43
|
+
lines.push("");
|
|
44
|
+
if (Array.isArray(message.content)) {
|
|
45
|
+
message.content.forEach((part) => {
|
|
46
|
+
if (part.type === "text" && part.text?.trim()) {
|
|
47
|
+
lines.push(part.text);
|
|
48
|
+
lines.push("");
|
|
49
|
+
}
|
|
50
|
+
else if (part.type === "tool-call") {
|
|
51
|
+
lines.push(`**Tool Call**: ${part.toolName}`);
|
|
52
|
+
lines.push(`**Call ID**: ${part.toolCallId}`);
|
|
53
|
+
lines.push("**Input**:");
|
|
54
|
+
lines.push("```json");
|
|
55
|
+
lines.push(JSON.stringify(part.input, null, 2));
|
|
56
|
+
lines.push("```");
|
|
57
|
+
lines.push("");
|
|
58
|
+
}
|
|
59
|
+
else if (part.type === "tool-result") {
|
|
60
|
+
lines.push(`**Tool Result**: ${part.toolName}`);
|
|
61
|
+
lines.push(`**Call ID**: ${part.toolCallId}`);
|
|
62
|
+
lines.push("**Output**:");
|
|
63
|
+
if (typeof part.output === "object" &&
|
|
64
|
+
part.output !== null &&
|
|
65
|
+
"type" in part.output &&
|
|
66
|
+
part.output.type === "text" &&
|
|
67
|
+
"text" in part.output) {
|
|
68
|
+
lines.push("```");
|
|
69
|
+
lines.push(String(part.output.text));
|
|
70
|
+
lines.push("```");
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
lines.push("```json");
|
|
74
|
+
lines.push(JSON.stringify(part.output, null, 2));
|
|
75
|
+
lines.push("```");
|
|
76
|
+
}
|
|
77
|
+
lines.push("");
|
|
78
|
+
}
|
|
79
|
+
else if (part.type === "tool-error") {
|
|
80
|
+
lines.push(`**Tool Error**: ${part.toolName}`);
|
|
81
|
+
lines.push(`**Call ID**: ${part.toolCallId}`);
|
|
82
|
+
lines.push("**Error**:");
|
|
83
|
+
lines.push("```");
|
|
84
|
+
lines.push(String(part.output));
|
|
85
|
+
lines.push("```");
|
|
86
|
+
lines.push("");
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
else if (typeof message.content === "string" && message.content.trim()) {
|
|
91
|
+
lines.push(message.content);
|
|
92
|
+
lines.push("");
|
|
93
|
+
}
|
|
94
|
+
lines.push("---");
|
|
95
|
+
lines.push("");
|
|
96
|
+
});
|
|
97
|
+
return lines.join("\n");
|
|
98
|
+
}
|
|
99
|
+
async function summarizeConversation(history, terminal, modelManager, tokenTracker) {
|
|
100
|
+
const systemPrompt = `You are an expert at summarizing conversations between a coding assistant and a user. Your task is to provide a clear, concise summary of the conversation that captures:
|
|
101
|
+
|
|
102
|
+
1. The main topic and objectives
|
|
103
|
+
2. Key decisions and solutions discussed
|
|
104
|
+
3. Tools and techniques used
|
|
105
|
+
4. Overall outcome or current status
|
|
106
|
+
|
|
107
|
+
Keep the summary focused and informative, around 3-5 paragraphs. Use plain text without markdown formatting.`;
|
|
108
|
+
const conversationText = history.messages
|
|
109
|
+
.map((message) => {
|
|
110
|
+
const role = message.role.toUpperCase();
|
|
111
|
+
let content = "";
|
|
112
|
+
if (Array.isArray(message.content)) {
|
|
113
|
+
content = message.content
|
|
114
|
+
.filter((part) => part.type === "text" && part.text?.trim())
|
|
115
|
+
.map((part) => part.text)
|
|
116
|
+
.join("\n");
|
|
117
|
+
}
|
|
118
|
+
else if (typeof message.content === "string") {
|
|
119
|
+
content = message.content;
|
|
120
|
+
}
|
|
121
|
+
return `${role}: ${content}`;
|
|
122
|
+
})
|
|
123
|
+
.filter((text) => text?.trim())
|
|
124
|
+
.join("\n\n");
|
|
125
|
+
try {
|
|
126
|
+
const { text, usage } = await generateText({
|
|
127
|
+
model: modelManager.getModel("conversation-summarizer"),
|
|
128
|
+
system: systemPrompt,
|
|
129
|
+
prompt: `Please summarize this conversation:\n\n${conversationText}`,
|
|
130
|
+
});
|
|
131
|
+
tokenTracker.trackUsage("conversation-summarizer", usage);
|
|
132
|
+
terminal.writeln(`Summary of "${history.title}":`);
|
|
133
|
+
terminal.lineBreak();
|
|
134
|
+
terminal.display(text);
|
|
135
|
+
terminal.lineBreak();
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
terminal.error(`Failed to generate summary: ${error}`);
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export const historyCommand = ({ messageHistory, terminal, config, modelManager, tokenTracker, }) => {
|
|
143
|
+
return {
|
|
144
|
+
command: "/history",
|
|
145
|
+
description: "Browse and manage previous conversations.",
|
|
146
|
+
getSubCommands: () => Promise.resolve([]),
|
|
147
|
+
execute: async () => {
|
|
148
|
+
const appDir = config.app;
|
|
149
|
+
const messageHistoryDir = await appDir.ensurePath("message-history");
|
|
150
|
+
// Load all histories (use a large number to get all)
|
|
151
|
+
const histories = await MessageHistory.load(messageHistoryDir, 1000);
|
|
152
|
+
if (histories.length === 0) {
|
|
153
|
+
terminal.info("No previous conversations found.");
|
|
154
|
+
return "continue";
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
// Step 1: Select conversation
|
|
158
|
+
const conversationChoice = await select({
|
|
159
|
+
message: "Select a conversation:",
|
|
160
|
+
choices: histories.map((h, index) => ({
|
|
161
|
+
name: `${index + 1}: ${h.title} (${h.updatedAt.toLocaleString()})`,
|
|
162
|
+
value: index,
|
|
163
|
+
description: `${h.messages.length} messages`,
|
|
164
|
+
})),
|
|
165
|
+
pageSize: 15,
|
|
166
|
+
});
|
|
167
|
+
const selectedHistory = histories.at(conversationChoice);
|
|
168
|
+
if (!selectedHistory) {
|
|
169
|
+
terminal.error("Selected history index out of bounds.");
|
|
170
|
+
return "continue";
|
|
171
|
+
}
|
|
172
|
+
// Step 2: Select action
|
|
173
|
+
const actionChoice = await select({
|
|
174
|
+
message: `What would you like to do with "${selectedHistory.title}"?`,
|
|
175
|
+
choices: [
|
|
176
|
+
{
|
|
177
|
+
name: "Resume - Continue this conversation",
|
|
178
|
+
value: "resume",
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: "Export - Save as markdown file",
|
|
182
|
+
value: "export",
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "Summarize - Generate AI summary of conversation",
|
|
186
|
+
value: "summarize",
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
pageSize: 5,
|
|
190
|
+
});
|
|
191
|
+
switch (actionChoice) {
|
|
192
|
+
case "resume":
|
|
193
|
+
messageHistory.restore(selectedHistory);
|
|
194
|
+
terminal.info(`Resuming conversation: ${selectedHistory.title}`);
|
|
195
|
+
terminal.setTitle(selectedHistory.title || `acai: ${process.cwd()}`);
|
|
196
|
+
break;
|
|
197
|
+
case "export":
|
|
198
|
+
await exportConversation(selectedHistory, terminal);
|
|
199
|
+
break;
|
|
200
|
+
case "summarize":
|
|
201
|
+
await summarizeConversation(selectedHistory, terminal, modelManager, tokenTracker);
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
// Handle Ctrl-C cancellation
|
|
207
|
+
if (error instanceof Error &&
|
|
208
|
+
"isCanceled" in error &&
|
|
209
|
+
error.isCanceled === true) {
|
|
210
|
+
terminal.info("Operation cancelled.");
|
|
211
|
+
return "continue";
|
|
212
|
+
}
|
|
213
|
+
// Re-throw other errors
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
return "continue";
|
|
217
|
+
},
|
|
218
|
+
async handle(_args, { tui, container, inputContainer, editor, }) {
|
|
219
|
+
const appDir = config.app;
|
|
220
|
+
const messageHistoryDir = await appDir.ensurePath("message-history");
|
|
221
|
+
// Load all histories (use a large number to get all)
|
|
222
|
+
const histories = await MessageHistory.load(messageHistoryDir, 1000);
|
|
223
|
+
if (histories.length === 0) {
|
|
224
|
+
container.addChild(new Text(style.yellow("No previous conversations found."), 0, 1));
|
|
225
|
+
tui.requestRender();
|
|
226
|
+
editor.setText("");
|
|
227
|
+
return "continue";
|
|
228
|
+
}
|
|
229
|
+
// Create conversation selector
|
|
230
|
+
const conversationSelector = new ConversationSelectorComponent(histories, async (conversation) => {
|
|
231
|
+
// Handle conversation selection
|
|
232
|
+
const actionSelector = new ActionSelectorComponent(conversation, async (action) => {
|
|
233
|
+
// Handle action selection
|
|
234
|
+
switch (action) {
|
|
235
|
+
case "resume":
|
|
236
|
+
messageHistory.restore(conversation);
|
|
237
|
+
container.addChild(new Text(style.green(`Resuming conversation: ${conversation.title}`), 0, 1));
|
|
238
|
+
terminal.setTitle(conversation.title || `acai: ${process.cwd()}`);
|
|
239
|
+
break;
|
|
240
|
+
case "export":
|
|
241
|
+
try {
|
|
242
|
+
await exportConversation(conversation, terminal);
|
|
243
|
+
container.addChild(new Text(style.green("Conversation exported successfully"), 1, 0));
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
container.addChild(new Text(style.red(`Failed to export conversation: ${error}`), 1, 0));
|
|
247
|
+
}
|
|
248
|
+
break;
|
|
249
|
+
case "summarize":
|
|
250
|
+
try {
|
|
251
|
+
await summarizeConversation(conversation, terminal, modelManager, tokenTracker);
|
|
252
|
+
container.addChild(new Text(style.green("Conversation summarized"), 0, 1));
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
container.addChild(new Text(style.red(`Failed to summarize conversation: ${error}`), 1, 0));
|
|
256
|
+
}
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
// Hide selectors and show editor again
|
|
260
|
+
hideHistorySelectors(inputContainer, editor, tui);
|
|
261
|
+
tui.requestRender();
|
|
262
|
+
}, () => {
|
|
263
|
+
// Cancel action selection - go back to conversation selection
|
|
264
|
+
hideHistorySelectors(inputContainer, editor, tui);
|
|
265
|
+
inputContainer.addChild(conversationSelector);
|
|
266
|
+
tui.setFocus(conversationSelector);
|
|
267
|
+
tui.requestRender();
|
|
268
|
+
});
|
|
269
|
+
// Replace conversation selector with action selector
|
|
270
|
+
inputContainer.clear();
|
|
271
|
+
inputContainer.addChild(actionSelector);
|
|
272
|
+
tui.setFocus(actionSelector);
|
|
273
|
+
tui.requestRender();
|
|
274
|
+
}, () => {
|
|
275
|
+
// Cancel conversation selection - just hide selector
|
|
276
|
+
hideHistorySelectors(inputContainer, editor, tui);
|
|
277
|
+
tui.requestRender();
|
|
278
|
+
});
|
|
279
|
+
// Replace editor with conversation selector
|
|
280
|
+
inputContainer.clear();
|
|
281
|
+
inputContainer.addChild(conversationSelector);
|
|
282
|
+
tui.setFocus(conversationSelector);
|
|
283
|
+
tui.requestRender();
|
|
284
|
+
return "continue";
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
function hideHistorySelectors(editorContainer, editor, tui) {
|
|
289
|
+
// Replace selector with editor in the container
|
|
290
|
+
editorContainer.clear();
|
|
291
|
+
editorContainer.addChild(editor);
|
|
292
|
+
tui.setFocus(editor);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Component that renders a conversation selector with search
|
|
296
|
+
*/
|
|
297
|
+
class ConversationSelectorComponent extends Container {
|
|
298
|
+
searchInput;
|
|
299
|
+
listContainer;
|
|
300
|
+
allConversations = [];
|
|
301
|
+
filteredConversations = [];
|
|
302
|
+
selectedIndex = 0;
|
|
303
|
+
onSelectCallback;
|
|
304
|
+
onCancelCallback;
|
|
305
|
+
constructor(conversations, onSelect, onCancel) {
|
|
306
|
+
super();
|
|
307
|
+
this.onSelectCallback = onSelect;
|
|
308
|
+
this.onCancelCallback = onCancel;
|
|
309
|
+
// Load all conversations
|
|
310
|
+
this.allConversations = conversations;
|
|
311
|
+
this.filteredConversations = conversations;
|
|
312
|
+
const { columns } = getTerminalSize();
|
|
313
|
+
// Add top border
|
|
314
|
+
this.addChild(new Text(style.blue("─".repeat(columns)), 0, 0));
|
|
315
|
+
this.addChild(new Spacer(1));
|
|
316
|
+
// Create search input
|
|
317
|
+
this.searchInput = new Input();
|
|
318
|
+
// Note: setPlaceholder not available on Input component
|
|
319
|
+
this.searchInput.onSubmit = () => {
|
|
320
|
+
// Enter on search input selects the first filtered item
|
|
321
|
+
if (this.filteredConversations[this.selectedIndex]) {
|
|
322
|
+
this.handleSelect(this.filteredConversations[this.selectedIndex]);
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
this.addChild(this.searchInput);
|
|
326
|
+
this.addChild(new Spacer(1));
|
|
327
|
+
// Create list container
|
|
328
|
+
this.listContainer = new Container();
|
|
329
|
+
this.addChild(this.listContainer);
|
|
330
|
+
this.addChild(new Spacer(1));
|
|
331
|
+
// Add bottom border
|
|
332
|
+
this.addChild(new Text(style.blue("─".repeat(columns)), 0, 0));
|
|
333
|
+
// Initial render
|
|
334
|
+
this.updateList();
|
|
335
|
+
}
|
|
336
|
+
filterConversations(query) {
|
|
337
|
+
if (!query.trim()) {
|
|
338
|
+
this.filteredConversations = this.allConversations;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
const searchTokens = query
|
|
342
|
+
.toLowerCase()
|
|
343
|
+
.split(/\s+/)
|
|
344
|
+
.filter((t) => t);
|
|
345
|
+
this.filteredConversations = this.allConversations.filter((conversation) => {
|
|
346
|
+
const searchText = `${conversation.title} ${conversation.sessionId}`.toLowerCase();
|
|
347
|
+
return searchTokens.every((token) => searchText.includes(token));
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredConversations.length - 1));
|
|
351
|
+
this.updateList();
|
|
352
|
+
}
|
|
353
|
+
updateList() {
|
|
354
|
+
this.listContainer.clear();
|
|
355
|
+
const maxVisible = 10;
|
|
356
|
+
const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(maxVisible / 2), this.filteredConversations.length - maxVisible));
|
|
357
|
+
const endIndex = Math.min(startIndex + maxVisible, this.filteredConversations.length);
|
|
358
|
+
// Show visible slice of filtered conversations
|
|
359
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
360
|
+
const conversation = this.filteredConversations[i];
|
|
361
|
+
if (!conversation)
|
|
362
|
+
continue;
|
|
363
|
+
const isSelected = i === this.selectedIndex;
|
|
364
|
+
let line = "";
|
|
365
|
+
if (isSelected) {
|
|
366
|
+
const prefix = style.blue("→ ");
|
|
367
|
+
const title = conversation.title;
|
|
368
|
+
const date = conversation.updatedAt.toLocaleString();
|
|
369
|
+
const messages = conversation.messages.length;
|
|
370
|
+
line = `${prefix + style.blue(title)} ${style.gray(`(${date}) - ${messages} messages`)}`;
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
const title = ` ${conversation.title}`;
|
|
374
|
+
const date = conversation.updatedAt.toLocaleString();
|
|
375
|
+
const messages = conversation.messages.length;
|
|
376
|
+
line = `${title} ${style.gray(`(${date}) - ${messages} messages`)}`;
|
|
377
|
+
}
|
|
378
|
+
this.listContainer.addChild(new Text(line, 0, 0));
|
|
379
|
+
}
|
|
380
|
+
// Add scroll indicator if needed
|
|
381
|
+
if (startIndex > 0 || endIndex < this.filteredConversations.length) {
|
|
382
|
+
const scrollInfo = style.gray(` (${this.selectedIndex + 1}/${this.filteredConversations.length})`);
|
|
383
|
+
this.listContainer.addChild(new Text(scrollInfo, 0, 0));
|
|
384
|
+
}
|
|
385
|
+
// Show "no results" if empty
|
|
386
|
+
if (this.filteredConversations.length === 0) {
|
|
387
|
+
this.listContainer.addChild(new Text(style.gray(" No matching conversations"), 0, 0));
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
handleInput(keyData) {
|
|
391
|
+
// Up arrow
|
|
392
|
+
if (keyData === "\x1b[A") {
|
|
393
|
+
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
394
|
+
this.updateList();
|
|
395
|
+
}
|
|
396
|
+
// Down arrow
|
|
397
|
+
else if (keyData === "\x1b[B") {
|
|
398
|
+
this.selectedIndex = Math.min(this.filteredConversations.length - 1, this.selectedIndex + 1);
|
|
399
|
+
this.updateList();
|
|
400
|
+
}
|
|
401
|
+
// Enter
|
|
402
|
+
else if (keyData === "\r") {
|
|
403
|
+
const selectedConversation = this.filteredConversations[this.selectedIndex];
|
|
404
|
+
if (selectedConversation) {
|
|
405
|
+
this.handleSelect(selectedConversation);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
// Escape
|
|
409
|
+
else if (keyData === "\x1b") {
|
|
410
|
+
this.onCancelCallback();
|
|
411
|
+
}
|
|
412
|
+
// Pass everything else to search input
|
|
413
|
+
else {
|
|
414
|
+
this.searchInput.handleInput(keyData);
|
|
415
|
+
this.filterConversations(this.searchInput.getValue());
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
handleSelect(conversation) {
|
|
419
|
+
this.onSelectCallback(conversation);
|
|
420
|
+
}
|
|
421
|
+
getSearchInput() {
|
|
422
|
+
return this.searchInput;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Component that renders an action selector for a conversation
|
|
427
|
+
*/
|
|
428
|
+
class ActionSelectorComponent extends Container {
|
|
429
|
+
selectedIndex = 0;
|
|
430
|
+
conversationTitle;
|
|
431
|
+
onSelectCallback;
|
|
432
|
+
onCancelCallback;
|
|
433
|
+
constructor(conversation, onSelect, onCancel) {
|
|
434
|
+
super();
|
|
435
|
+
this.conversationTitle = conversation.title;
|
|
436
|
+
this.onSelectCallback = onSelect;
|
|
437
|
+
this.onCancelCallback = onCancel;
|
|
438
|
+
const { columns } = getTerminalSize();
|
|
439
|
+
// Add top border
|
|
440
|
+
this.addChild(new Text(style.blue("─".repeat(columns)), 0, 0));
|
|
441
|
+
this.addChild(new Spacer(1));
|
|
442
|
+
// Show conversation title
|
|
443
|
+
this.addChild(new Text(`Selected: ${conversation.title}`, 0, 0));
|
|
444
|
+
this.addChild(new Spacer(1));
|
|
445
|
+
// Create action list
|
|
446
|
+
this.addChild(new Text("Choose an action:", 0, 0));
|
|
447
|
+
this.addChild(new Spacer(1));
|
|
448
|
+
const actions = [
|
|
449
|
+
{ name: "Resume - Continue this conversation", value: "resume" },
|
|
450
|
+
{ name: "Export - Save as markdown file", value: "export" },
|
|
451
|
+
{
|
|
452
|
+
name: "Summarize - Generate AI summary of conversation",
|
|
453
|
+
value: "summarize",
|
|
454
|
+
},
|
|
455
|
+
];
|
|
456
|
+
actions.forEach((action, index) => {
|
|
457
|
+
const isSelected = index === this.selectedIndex;
|
|
458
|
+
let line = "";
|
|
459
|
+
if (isSelected) {
|
|
460
|
+
line = `${style.blue("→ ") + style.blue(action.name)}`;
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
line = ` ${action.name}`;
|
|
464
|
+
}
|
|
465
|
+
this.addChild(new Text(line, 0, 0));
|
|
466
|
+
});
|
|
467
|
+
this.addChild(new Spacer(1));
|
|
468
|
+
// Add bottom border
|
|
469
|
+
this.addChild(new Text(style.blue("─".repeat(columns)), 0, 0));
|
|
470
|
+
}
|
|
471
|
+
handleInput(keyData) {
|
|
472
|
+
// Up arrow
|
|
473
|
+
if (keyData === "\x1b[A") {
|
|
474
|
+
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
475
|
+
this.updateList();
|
|
476
|
+
}
|
|
477
|
+
// Down arrow
|
|
478
|
+
else if (keyData === "\x1b[B") {
|
|
479
|
+
this.selectedIndex = Math.min(2, this.selectedIndex + 1);
|
|
480
|
+
this.updateList();
|
|
481
|
+
}
|
|
482
|
+
// Enter
|
|
483
|
+
else if (keyData === "\r") {
|
|
484
|
+
const actions = ["resume", "export", "summarize"];
|
|
485
|
+
const selectedAction = actions[this.selectedIndex];
|
|
486
|
+
if (selectedAction) {
|
|
487
|
+
this.handleSelect(selectedAction);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
// Escape
|
|
491
|
+
else if (keyData === "\x1b") {
|
|
492
|
+
this.onCancelCallback();
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
updateList() {
|
|
496
|
+
// Clear and rebuild the action list
|
|
497
|
+
this.clear();
|
|
498
|
+
const { columns } = getTerminalSize();
|
|
499
|
+
// Add top border
|
|
500
|
+
this.addChild(new Text(style.blue("─".repeat(columns)), 0, 0));
|
|
501
|
+
this.addChild(new Spacer(1));
|
|
502
|
+
// Show conversation title
|
|
503
|
+
this.addChild(new Text(`Selected: ${this.conversationTitle}`, 0, 0));
|
|
504
|
+
this.addChild(new Spacer(1));
|
|
505
|
+
// Create action list
|
|
506
|
+
this.addChild(new Text("Choose an action:", 0, 0));
|
|
507
|
+
this.addChild(new Spacer(1));
|
|
508
|
+
const actions = [
|
|
509
|
+
{ name: "Resume - Continue this conversation", value: "resume" },
|
|
510
|
+
{ name: "Export - Save as markdown file", value: "export" },
|
|
511
|
+
{
|
|
512
|
+
name: "Summarize - Generate AI summary of conversation",
|
|
513
|
+
value: "summarize",
|
|
514
|
+
},
|
|
515
|
+
];
|
|
516
|
+
actions.forEach((action, index) => {
|
|
517
|
+
const isSelected = index === this.selectedIndex;
|
|
518
|
+
let line = "";
|
|
519
|
+
if (isSelected) {
|
|
520
|
+
line = `${style.blue("→ ") + style.blue(action.name)}`;
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
line = ` ${action.name}`;
|
|
524
|
+
}
|
|
525
|
+
this.addChild(new Text(line, 0, 0));
|
|
526
|
+
});
|
|
527
|
+
this.addChild(new Spacer(1));
|
|
528
|
+
// Add bottom border
|
|
529
|
+
this.addChild(new Text(style.blue("─".repeat(columns)), 0, 0));
|
|
530
|
+
}
|
|
531
|
+
handleSelect(action) {
|
|
532
|
+
this.onSelectCallback(action);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { CommandOptions, ReplCommand } from "./types.ts";
|
|
2
|
-
export declare const initCommand: ({ terminal, modelManager, tokenCounter,
|
|
2
|
+
export declare const initCommand: ({ terminal, modelManager, tokenCounter, workspace, }: CommandOptions) => ReplCommand;
|
|
3
3
|
//# sourceMappingURL=init-command.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-command.d.ts","sourceRoot":"","sources":["../../source/commands/init-command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init-command.d.ts","sourceRoot":"","sources":["../../source/commands/init-command.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAqB9D,eAAO,MAAM,WAAW,GAAI,sDAKzB,cAAc,KAAG,WAyEnB,CAAC"}
|
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
import { platform } from "node:os";
|
|
2
2
|
import { stepCountIs, streamText } from "ai";
|
|
3
|
+
import style from "../terminal/style.js";
|
|
3
4
|
import { inGitDirectory } from "../tools/git-utils.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
5
|
+
import { initCliTools } from "../tools/index.js";
|
|
6
|
+
import { Markdown, Spacer, Text } from "../tui/index.js";
|
|
7
|
+
const initPrompt = `Please analyze this codebase and create a AGENTS.md file containing:
|
|
8
|
+
1. An overview of the project including how the project is structured and the tech stack used.
|
|
9
|
+
2. Build/lint/test commands - especially for running a single test
|
|
10
|
+
3. Directions on how to run the app
|
|
11
|
+
4. Custom tools defined in ./.acai/tools
|
|
12
|
+
3. Code style guidelines including imports, formatting, types, naming conventions, error handling, etc.
|
|
13
|
+
4. Commit format (does the repository use Conventional Commits?)
|
|
14
|
+
5. Branch strategy
|
|
15
|
+
6. PR requirements
|
|
16
|
+
|
|
17
|
+
The file you create will be given to agentic coding agents (such as yourself) that operate in this repository. Make it about 50 lines long.
|
|
18
|
+
|
|
19
|
+
If there's already a AGENTS.md, improve it.
|
|
20
|
+
If there are Cursor rules (in .cursor/rules/ or .cursorrules), Copilot rules (in .github/copilot-instructions.md or .github/instructions/), or Windsurf rules (in .windsurf/rules), make sure to include them.
|
|
21
|
+
|
|
22
|
+
Your current working directory is ${process.cwd()}
|
|
23
|
+
Is directory a git repo: ${(await inGitDirectory()) ? "Yes" : "No"}
|
|
24
|
+
Platform: ${platform()}`;
|
|
25
|
+
export const initCommand = ({ terminal, modelManager, tokenCounter, workspace, }) => {
|
|
6
26
|
return {
|
|
7
27
|
command: "/init",
|
|
8
28
|
description: "Creates the AGENTS.md file.",
|
|
@@ -11,29 +31,46 @@ export const initCommand = ({ terminal, modelManager, tokenCounter, toolEvents,
|
|
|
11
31
|
const result = streamText({
|
|
12
32
|
model: modelManager.getModel("init-project"),
|
|
13
33
|
temperature: 0.5,
|
|
14
|
-
prompt:
|
|
15
|
-
1. Build/lint/test commands - especially for running a single test
|
|
16
|
-
2. Code style guidelines including imports, formatting, types, naming conventions, error handling, etc.
|
|
17
|
-
|
|
18
|
-
The file you create will be given to agentic coding agents (such as yourself) that operate in this repository. Make it about 20 lines long.
|
|
19
|
-
|
|
20
|
-
If there's already a AGENTS.md, improve it.
|
|
21
|
-
If there are Cursor rules (in .cursor/rules/ or .cursorrules), Copilot rules (in .github/copilot-instructions.md), or Windsurf rules (in .windsurf/rules), make sure to include them.
|
|
22
|
-
|
|
23
|
-
Your current working directory is ${process.cwd()}
|
|
24
|
-
Is directory a git repo: ${(await inGitDirectory()) ? "Yes" : "No"}
|
|
25
|
-
Platform: ${platform()}`,
|
|
34
|
+
prompt: initPrompt,
|
|
26
35
|
stopWhen: stepCountIs(40),
|
|
27
|
-
tools: await
|
|
28
|
-
terminal,
|
|
36
|
+
tools: (await initCliTools({
|
|
29
37
|
tokenCounter,
|
|
30
|
-
|
|
31
|
-
}),
|
|
38
|
+
workspace,
|
|
39
|
+
})).toolDefs,
|
|
32
40
|
});
|
|
33
41
|
for await (const text of result.textStream) {
|
|
34
42
|
terminal.write(text);
|
|
35
43
|
}
|
|
36
44
|
return "continue";
|
|
37
45
|
},
|
|
46
|
+
async handle(_args, { tui, container, editor, }) {
|
|
47
|
+
container.addChild(new Text("Initializing project and creating AGENTS.md...", 1, 1));
|
|
48
|
+
tui.requestRender();
|
|
49
|
+
const result = streamText({
|
|
50
|
+
model: modelManager.getModel("init-project"),
|
|
51
|
+
temperature: 0.5,
|
|
52
|
+
prompt: initPrompt,
|
|
53
|
+
stopWhen: stepCountIs(40),
|
|
54
|
+
tools: (await initCliTools({
|
|
55
|
+
tokenCounter,
|
|
56
|
+
workspace,
|
|
57
|
+
})).toolDefs,
|
|
58
|
+
});
|
|
59
|
+
container.addChild(new Spacer(1));
|
|
60
|
+
let output = "";
|
|
61
|
+
const t = new Markdown(output, undefined, undefined, undefined, 1, 0);
|
|
62
|
+
container.addChild(t);
|
|
63
|
+
for await (const text of result.textStream) {
|
|
64
|
+
output += text;
|
|
65
|
+
// Update the display with the latest output
|
|
66
|
+
t.setText(output);
|
|
67
|
+
tui.requestRender();
|
|
68
|
+
}
|
|
69
|
+
container.addChild(new Spacer(1));
|
|
70
|
+
container.addChild(new Text(style.green("AGENTS.md file created successfully"), 1, 0));
|
|
71
|
+
tui.requestRender();
|
|
72
|
+
editor.setText("");
|
|
73
|
+
return "continue";
|
|
74
|
+
},
|
|
38
75
|
};
|
|
39
76
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"last-log-command.d.ts","sourceRoot":"","sources":["../../source/commands/last-log-command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"last-log-command.d.ts","sourceRoot":"","sources":["../../source/commands/last-log-command.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAyC9D,eAAO,MAAM,cAAc,GAAI,cAAc,cAAc,KAAG,WA8F7D,CAAC"}
|
|
@@ -3,6 +3,7 @@ import { join } from "node:path";
|
|
|
3
3
|
import { config } from "../config.js";
|
|
4
4
|
import { editor } from "../terminal/editor-prompt.js";
|
|
5
5
|
import style from "../terminal/style.js";
|
|
6
|
+
import { Text } from "../tui/index.js";
|
|
6
7
|
import { glob } from "../utils/glob.js";
|
|
7
8
|
const isoDateRegex = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)/;
|
|
8
9
|
// Function to find the most recent log file
|
|
@@ -67,5 +68,31 @@ export const lastLogCommand = ({ terminal }) => {
|
|
|
67
68
|
return "continue";
|
|
68
69
|
}
|
|
69
70
|
},
|
|
71
|
+
async handle(_args, { tui, container, editor, }) {
|
|
72
|
+
const logDir = config.app.ensurePathSync("audit");
|
|
73
|
+
const mostRecentLog = await findMostRecentLog(logDir);
|
|
74
|
+
if (!mostRecentLog) {
|
|
75
|
+
container.addChild(new Text(style.red(`No REPL audit logs found in '${logDir}'.`), 0, 1));
|
|
76
|
+
tui.requestRender();
|
|
77
|
+
editor.setText("");
|
|
78
|
+
return "continue";
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const content = await readFile(mostRecentLog, { encoding: "utf8" });
|
|
82
|
+
// For TUI mode, we'll just display a message since we can't use the editor prompt
|
|
83
|
+
container.addChild(new Text(`Viewing most recent log: ${style.blue(mostRecentLog)}`, 1, 0));
|
|
84
|
+
container.addChild(new Text(`Content length: ${content.length} characters`, 2, 0));
|
|
85
|
+
container.addChild(new Text(style.dim("Note: Full log viewing not available in TUI mode"), 3, 0));
|
|
86
|
+
tui.requestRender();
|
|
87
|
+
editor.setText("");
|
|
88
|
+
return "continue";
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
container.addChild(new Text(style.red(`Error reading log file ${mostRecentLog}: ${error}`), 1, 0));
|
|
92
|
+
tui.requestRender();
|
|
93
|
+
editor.setText("");
|
|
94
|
+
return "continue";
|
|
95
|
+
}
|
|
96
|
+
},
|
|
70
97
|
};
|
|
71
98
|
};
|