@travisennis/acai 0.0.8 → 0.0.10
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 +48 -729
- package/bin/acai +52 -0
- package/dist/agent/index.d.ts +12 -2
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +378 -168
- package/dist/agent/sub-agent.d.ts +23 -0
- package/dist/agent/sub-agent.d.ts.map +1 -0
- package/dist/agent/sub-agent.js +109 -0
- package/dist/cli/index.d.ts +26 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/{cli.js → cli/index.js} +84 -76
- package/dist/cli/stdin.d.ts +9 -0
- package/dist/cli/stdin.d.ts.map +1 -0
- package/dist/cli/stdin.js +37 -0
- package/dist/commands/copy/index.js +2 -2
- package/dist/commands/copy/utils.d.ts.map +1 -1
- package/dist/commands/copy/utils.js +15 -13
- package/dist/commands/generate-rules/index.d.ts +1 -1
- package/dist/commands/generate-rules/index.d.ts.map +1 -1
- package/dist/commands/generate-rules/index.js +16 -100
- package/dist/commands/generate-rules/service.d.ts +21 -0
- package/dist/commands/generate-rules/service.d.ts.map +1 -0
- package/dist/commands/generate-rules/service.js +103 -0
- package/dist/commands/handoff/index.js +2 -2
- package/dist/commands/health/index.js +1 -1
- package/dist/commands/health/utils.d.ts.map +1 -1
- package/dist/commands/health/utils.js +6 -0
- package/dist/commands/history/index.d.ts +1 -1
- package/dist/commands/history/index.d.ts.map +1 -1
- package/dist/commands/history/index.js +17 -18
- package/dist/commands/history/types.d.ts +38 -0
- package/dist/commands/history/types.d.ts.map +1 -1
- package/dist/commands/history/utils.d.ts.map +1 -1
- package/dist/commands/history/utils.js +63 -58
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +3 -8
- package/dist/commands/init-project/index.d.ts.map +1 -1
- package/dist/commands/init-project/index.js +3 -3
- package/dist/commands/init-project/utils.d.ts.map +1 -1
- package/dist/commands/init-project/utils.js +10 -2
- package/dist/commands/list-tools/index.d.ts.map +1 -1
- package/dist/commands/list-tools/index.js +7 -31
- package/dist/commands/manager.d.ts +2 -2
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +57 -33
- package/dist/commands/model/index.d.ts.map +1 -1
- package/dist/commands/model/index.js +20 -151
- package/dist/commands/model/model-panel.d.ts +4 -0
- package/dist/commands/model/model-panel.d.ts.map +1 -0
- package/dist/commands/model/model-panel.js +144 -0
- package/dist/commands/paste/index.d.ts.map +1 -1
- package/dist/commands/paste/index.js +59 -62
- package/dist/commands/paste/utils.d.ts.map +1 -1
- package/dist/commands/paste/utils.js +88 -58
- package/dist/commands/pickup/index.d.ts.map +1 -1
- package/dist/commands/pickup/index.js +6 -3
- package/dist/commands/pickup/utils.js +3 -3
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +33 -50
- package/dist/commands/review/index.d.ts.map +1 -1
- package/dist/commands/review/index.js +3 -117
- package/dist/commands/review/review-panel.d.ts +3 -0
- package/dist/commands/review/review-panel.d.ts.map +1 -0
- package/dist/commands/review/review-panel.js +186 -0
- package/dist/commands/review/utils.d.ts +9 -0
- package/dist/commands/review/utils.d.ts.map +1 -1
- package/dist/commands/review/utils.js +127 -68
- package/dist/commands/session/index.d.ts +1 -1
- package/dist/commands/session/index.d.ts.map +1 -1
- package/dist/commands/session/index.js +134 -112
- package/dist/commands/session/types.d.ts +7 -0
- package/dist/commands/session/types.d.ts.map +1 -1
- package/dist/commands/share/html-renderer.d.ts +25 -0
- package/dist/commands/share/html-renderer.d.ts.map +1 -0
- package/dist/commands/share/html-renderer.js +384 -0
- package/dist/commands/share/index.d.ts +3 -0
- package/dist/commands/share/index.d.ts.map +1 -0
- package/dist/commands/share/index.js +122 -0
- package/dist/commands/shell/index.d.ts.map +1 -1
- package/dist/commands/shell/index.js +16 -1
- package/dist/commands/types.d.ts +2 -2
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/{config.d.ts → config/index.d.ts} +20 -9
- package/dist/config/index.d.ts.map +1 -0
- package/dist/{config.js → config/index.js} +43 -42
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +75 -55
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +170 -127
- package/dist/middleware/cache.d.ts.map +1 -1
- package/dist/middleware/cache.js +18 -36
- package/dist/models/ai-config.d.ts +1 -0
- package/dist/models/ai-config.d.ts.map +1 -1
- package/dist/models/ai-config.js +4 -3
- package/dist/models/anthropic-provider.d.ts +2 -5
- package/dist/models/anthropic-provider.d.ts.map +1 -1
- package/dist/models/anthropic-provider.js +3 -70
- package/dist/models/deepseek-provider.d.ts +1 -0
- package/dist/models/deepseek-provider.d.ts.map +1 -1
- package/dist/models/google-provider.d.ts +2 -3
- package/dist/models/google-provider.d.ts.map +1 -1
- package/dist/models/google-provider.js +0 -26
- package/dist/models/groq-provider.d.ts +1 -0
- package/dist/models/groq-provider.d.ts.map +1 -1
- package/dist/models/manager.d.ts +13 -2
- package/dist/models/manager.d.ts.map +1 -1
- package/dist/models/manager.js +20 -8
- package/dist/models/openai-provider.d.ts +5 -5
- package/dist/models/openai-provider.d.ts.map +1 -1
- package/dist/models/openai-provider.js +27 -40
- package/dist/models/opencode-zen-provider.d.ts +8 -3
- package/dist/models/opencode-zen-provider.d.ts.map +1 -1
- package/dist/models/opencode-zen-provider.js +68 -11
- package/dist/models/openrouter-provider.d.ts +24 -30
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +92 -177
- package/dist/models/providers.d.ts +1 -1
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/xai-provider.d.ts +4 -3
- package/dist/models/xai-provider.d.ts.map +1 -1
- package/dist/models/xai-provider.js +18 -18
- package/dist/modes/manager.d.ts +23 -0
- package/dist/modes/manager.d.ts.map +1 -0
- package/dist/modes/manager.js +77 -0
- package/dist/modes/prompts.d.ts +2 -0
- package/dist/modes/prompts.d.ts.map +1 -0
- package/dist/modes/prompts.js +143 -0
- package/dist/prompts/mentions.d.ts +11 -0
- package/dist/prompts/mentions.d.ts.map +1 -0
- package/dist/{mentions.js → prompts/mentions.js} +21 -80
- package/dist/prompts/system-prompt.d.ts +26 -0
- package/dist/prompts/system-prompt.d.ts.map +1 -0
- package/dist/{prompts.js → prompts/system-prompt.js} +50 -22
- package/dist/repl/index.d.ts +174 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/{repl-new.js → repl/index.js} +399 -76
- package/dist/repl/project-status.d.ts +1 -0
- package/dist/repl/project-status.d.ts.map +1 -1
- package/dist/repl/project-status.js +4 -1
- package/dist/sessions/manager.d.ts +93 -1
- package/dist/sessions/manager.d.ts.map +1 -1
- package/dist/sessions/manager.js +264 -9
- package/dist/sessions/summary.d.ts +4 -0
- package/dist/sessions/summary.d.ts.map +1 -0
- package/dist/sessions/summary.js +30 -0
- package/dist/{skills.d.ts → skills/index.d.ts} +14 -2
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +294 -0
- package/dist/subagents/index.d.ts +15 -0
- package/dist/subagents/index.d.ts.map +1 -0
- package/dist/subagents/index.js +231 -0
- package/dist/terminal/control.d.ts +1 -1
- package/dist/terminal/control.d.ts.map +1 -1
- package/dist/terminal/control.js +30 -9
- package/dist/terminal/east-asian-width.d.ts.map +1 -1
- package/dist/terminal/east-asian-width.js +404 -351
- package/dist/terminal/keys.d.ts +17 -0
- package/dist/terminal/keys.d.ts.map +1 -1
- package/dist/terminal/keys.js +37 -0
- package/dist/terminal/select-prompt.d.ts.map +1 -1
- package/dist/terminal/select-prompt.js +24 -12
- package/dist/terminal/string-width.d.ts.map +1 -1
- package/dist/terminal/string-width.js +25 -27
- package/dist/terminal/style.d.ts.map +1 -1
- package/dist/terminal/style.js +4 -7
- package/dist/terminal/supports-color.d.ts.map +1 -1
- package/dist/terminal/supports-color.js +41 -27
- package/dist/terminal/table/cell.d.ts +12 -0
- package/dist/terminal/table/cell.d.ts.map +1 -1
- package/dist/terminal/table/cell.js +40 -25
- package/dist/terminal/table/layout-manager.d.ts.map +1 -1
- package/dist/terminal/table/layout-manager.js +100 -68
- package/dist/terminal/table/utils.d.ts.map +1 -1
- package/dist/terminal/table/utils.js +17 -10
- package/dist/terminal/wrap-ansi.d.ts.map +1 -1
- package/dist/terminal/wrap-ansi.js +172 -103
- package/dist/tokens/tracker.d.ts +1 -0
- package/dist/tokens/tracker.d.ts.map +1 -1
- package/dist/tokens/tracker.js +3 -0
- package/dist/tools/agent.d.ts +27 -0
- package/dist/tools/agent.d.ts.map +1 -0
- package/dist/tools/agent.js +81 -0
- package/dist/tools/bash.d.ts +4 -3
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +343 -121
- package/dist/tools/code-search.d.ts +41 -0
- package/dist/tools/code-search.d.ts.map +1 -0
- package/dist/tools/code-search.js +195 -0
- package/dist/tools/directory-tree.d.ts +3 -3
- package/dist/tools/directory-tree.d.ts.map +1 -1
- package/dist/tools/directory-tree.js +8 -5
- package/dist/tools/dynamic-tool-loader.d.ts +2 -5
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +20 -4
- package/dist/tools/edit-file.d.ts +7 -7
- package/dist/tools/edit-file.d.ts.map +1 -1
- package/dist/tools/edit-file.js +164 -66
- package/dist/tools/glob.d.ts +6 -6
- package/dist/tools/glob.d.ts.map +1 -1
- package/dist/tools/glob.js +95 -55
- package/dist/tools/grep.d.ts +15 -12
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +300 -192
- package/dist/tools/index.d.ts +143 -5
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +39 -24
- package/dist/tools/ls.d.ts +2 -2
- package/dist/tools/ls.d.ts.map +1 -1
- package/dist/tools/ls.js +7 -5
- package/dist/tools/read-file.d.ts +3 -3
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +74 -34
- package/dist/tools/save-file.d.ts +3 -3
- package/dist/tools/save-file.d.ts.map +1 -1
- package/dist/tools/save-file.js +11 -11
- package/dist/tools/skill.d.ts +23 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +65 -0
- package/dist/tools/think.d.ts.map +1 -1
- package/dist/tools/think.js +2 -9
- package/dist/tools/utils.d.ts +2 -0
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +12 -0
- package/dist/tools/web-fetch.d.ts +62 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +429 -0
- package/dist/tools/web-search.d.ts +62 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +226 -0
- package/dist/tui/autocomplete/attachment-provider.d.ts +3 -6
- package/dist/tui/autocomplete/attachment-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/attachment-provider.js +25 -78
- package/dist/tui/autocomplete/base-provider.d.ts +1 -0
- package/dist/tui/autocomplete/base-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/combined-provider.d.ts +1 -4
- package/dist/tui/autocomplete/combined-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/combined-provider.js +3 -17
- package/dist/tui/autocomplete/command-provider.d.ts +1 -0
- package/dist/tui/autocomplete/command-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/command-provider.js +3 -0
- package/dist/tui/autocomplete/file-search-provider.d.ts +2 -1
- package/dist/tui/autocomplete/file-search-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/file-search-provider.js +36 -16
- package/dist/tui/autocomplete/skill-provider.d.ts +17 -0
- package/dist/tui/autocomplete/skill-provider.d.ts.map +1 -0
- package/dist/tui/autocomplete/skill-provider.js +49 -0
- package/dist/tui/autocomplete.d.ts +2 -2
- package/dist/tui/autocomplete.d.ts.map +1 -1
- package/dist/tui/autocomplete.js +3 -5
- package/dist/tui/components/assistant-message.d.ts.map +1 -1
- package/dist/tui/components/assistant-message.js +0 -4
- package/dist/tui/components/editor.d.ts +21 -2
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +228 -236
- package/dist/tui/components/footer.d.ts +6 -4
- package/dist/tui/components/footer.d.ts.map +1 -1
- package/dist/tui/components/footer.js +49 -25
- package/dist/tui/components/markdown.d.ts +8 -5
- package/dist/tui/components/markdown.d.ts.map +1 -1
- package/dist/tui/components/markdown.js +57 -39
- package/dist/tui/components/modal.d.ts.map +1 -1
- package/dist/tui/components/modal.js +35 -33
- package/dist/tui/components/notification.d.ts +13 -2
- package/dist/tui/components/notification.d.ts.map +1 -1
- package/dist/tui/components/notification.js +37 -2
- package/dist/tui/components/progress-bar.js +1 -1
- package/dist/tui/components/select-list.d.ts +1 -0
- package/dist/tui/components/select-list.d.ts.map +1 -1
- package/dist/tui/components/select-list.js +14 -11
- package/dist/tui/components/text.d.ts +16 -0
- package/dist/tui/components/text.d.ts.map +1 -1
- package/dist/tui/components/text.js +72 -57
- package/dist/tui/components/thinking-block.d.ts +9 -0
- package/dist/tui/components/thinking-block.d.ts.map +1 -1
- package/dist/tui/components/thinking-block.js +43 -11
- package/dist/tui/components/tool-execution.d.ts +5 -1
- package/dist/tui/components/tool-execution.d.ts.map +1 -1
- package/dist/tui/components/tool-execution.js +19 -10
- package/dist/tui/components/user-message.d.ts.map +1 -1
- package/dist/tui/components/user-message.js +0 -3
- package/dist/tui/components/welcome.js +2 -2
- package/dist/tui/editor-launcher.d.ts +13 -0
- package/dist/tui/editor-launcher.d.ts.map +1 -0
- package/dist/tui/editor-launcher.js +39 -0
- package/dist/tui/index.d.ts +3 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +1 -0
- package/dist/tui/terminal.d.ts +27 -0
- package/dist/tui/terminal.d.ts.map +1 -1
- package/dist/tui/terminal.js +144 -15
- package/dist/tui/tui.d.ts +43 -0
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +172 -41
- package/dist/utils/bash/parse.d.ts +19 -0
- package/dist/utils/bash/parse.d.ts.map +1 -0
- package/dist/utils/bash/parse.js +223 -0
- package/dist/utils/bash/quote.d.ts +6 -0
- package/dist/utils/bash/quote.d.ts.map +1 -0
- package/dist/utils/bash/quote.js +23 -0
- package/dist/utils/bash.d.ts.map +1 -1
- package/dist/utils/bash.js +211 -126
- package/dist/utils/command-protection.d.ts +28 -0
- package/dist/utils/command-protection.d.ts.map +1 -0
- package/dist/utils/command-protection.js +324 -0
- package/dist/utils/dedent.d.ts.map +1 -0
- package/dist/utils/env-expand.d.ts +2 -0
- package/dist/utils/env-expand.d.ts.map +1 -0
- package/dist/utils/env-expand.js +8 -0
- package/dist/utils/filesystem/path-display.d.ts +11 -0
- package/dist/utils/filesystem/path-display.d.ts.map +1 -0
- package/dist/utils/filesystem/path-display.js +32 -0
- package/dist/utils/filesystem/security.d.ts +2 -2
- package/dist/utils/filesystem/security.d.ts.map +1 -1
- package/dist/utils/filesystem/security.js +32 -31
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/{formatting.js → utils/formatting.js} +1 -1
- package/dist/utils/git.d.ts +4 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +30 -0
- package/dist/utils/glob.d.ts +1 -1
- package/dist/utils/glob.d.ts.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/{logger.js → utils/logger.js} +1 -1
- package/dist/utils/parsing.d.ts.map +1 -0
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +90 -37
- package/dist/utils/templates.d.ts +2 -0
- package/dist/utils/templates.d.ts.map +1 -0
- package/dist/utils/templates.js +24 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/{version.js → utils/version.js} +1 -1
- package/package.json +34 -25
- package/dist/cli.d.ts +0 -23
- package/dist/cli.d.ts.map +0 -1
- package/dist/commands/exit/index.d.ts +0 -10
- package/dist/commands/exit/index.d.ts.map +0 -1
- package/dist/commands/exit/index.js +0 -21
- package/dist/commands/exit/types.d.ts +0 -8
- package/dist/commands/exit/types.d.ts.map +0 -1
- package/dist/commands/exit/types.js +0 -1
- package/dist/commands/exit/utils.d.ts +0 -2
- package/dist/commands/exit/utils.d.ts.map +0 -1
- package/dist/commands/exit/utils.js +0 -13
- package/dist/commands/prompt/index.d.ts +0 -5
- package/dist/commands/prompt/index.d.ts.map +0 -1
- package/dist/commands/prompt/index.js +0 -126
- package/dist/commands/prompt/types.d.ts +0 -15
- package/dist/commands/prompt/types.d.ts.map +0 -1
- package/dist/commands/prompt/types.js +0 -1
- package/dist/commands/prompt/utils.d.ts +0 -12
- package/dist/commands/prompt/utils.d.ts.map +0 -1
- package/dist/commands/prompt/utils.js +0 -107
- package/dist/commands/reset/index.d.ts +0 -3
- package/dist/commands/reset/index.d.ts.map +0 -1
- package/dist/commands/reset/index.js +0 -25
- package/dist/commands/reset/types.d.ts +0 -1
- package/dist/commands/reset/types.d.ts.map +0 -1
- package/dist/commands/reset/types.js +0 -3
- package/dist/commands/save/index.d.ts +0 -3
- package/dist/commands/save/index.d.ts.map +0 -1
- package/dist/commands/save/index.js +0 -19
- package/dist/config.d.ts.map +0 -1
- package/dist/dedent.d.ts.map +0 -1
- package/dist/formatting.d.ts.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/mentions.d.ts +0 -14
- package/dist/mentions.d.ts.map +0 -1
- package/dist/parsing.d.ts.map +0 -1
- package/dist/prompts.d.ts +0 -10
- package/dist/prompts.d.ts.map +0 -1
- package/dist/repl-new.d.ts +0 -62
- package/dist/repl-new.d.ts.map +0 -1
- package/dist/skills.d.ts.map +0 -1
- package/dist/skills.js +0 -233
- package/dist/tui/autocomplete/path-provider.d.ts +0 -21
- package/dist/tui/autocomplete/path-provider.d.ts.map +0 -1
- package/dist/tui/autocomplete/path-provider.js +0 -164
- package/dist/version.d.ts.map +0 -1
- /package/dist/{dedent.d.ts → utils/dedent.d.ts} +0 -0
- /package/dist/{dedent.js → utils/dedent.js} +0 -0
- /package/dist/{formatting.d.ts → utils/formatting.d.ts} +0 -0
- /package/dist/{logger.d.ts → utils/logger.d.ts} +0 -0
- /package/dist/{parsing.d.ts → utils/parsing.d.ts} +0 -0
- /package/dist/{parsing.js → utils/parsing.js} +0 -0
- /package/dist/{version.d.ts → utils/version.d.ts} +0 -0
|
@@ -1,16 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
1
|
+
import { generateRulesFromSession } from "../commands/generate-rules/service.js";
|
|
2
|
+
import { showModelSelector } from "../commands/model/model-panel.js";
|
|
3
|
+
import { showReviewPanel } from "../commands/review/review-panel.js";
|
|
4
|
+
import { ModeManager } from "../modes/manager.js";
|
|
5
|
+
import { processPrompt } from "../prompts/mentions.js";
|
|
6
|
+
import { createUserMessage } from "../sessions/manager.js";
|
|
7
|
+
import { loadSkills } from "../skills/index.js";
|
|
8
|
+
import { alert, setTerminalTitle, startProgress, stopProgress, } from "../terminal/control.js";
|
|
9
|
+
import style from "../terminal/style.js";
|
|
10
|
+
import { AttachmentProvider, CombinedProvider, CommandProvider, FileSearchProvider, SkillProvider, } from "../tui/autocomplete.js";
|
|
11
|
+
import { AssistantMessageComponent } from "../tui/components/assistant-message.js";
|
|
12
|
+
import { FooterComponent } from "../tui/components/footer.js";
|
|
13
|
+
import { ThinkingBlockComponent } from "../tui/components/thinking-block.js";
|
|
14
|
+
import { ToolExecutionComponent } from "../tui/components/tool-execution.js";
|
|
15
|
+
import { Welcome } from "../tui/components/welcome.js";
|
|
16
|
+
import { launchEditor } from "../tui/editor-launcher.js";
|
|
17
|
+
import { Container, Editor, Loader, NotificationComponent, ProcessTerminal, Spacer, Text, TUI, UserMessageComponent, } from "../tui/index.js";
|
|
18
|
+
import { logger } from "../utils/logger.js";
|
|
19
|
+
import { getProjectStatus } from "./project-status.js";
|
|
20
|
+
/**
|
|
21
|
+
* Interactive Read-Eval-Print Loop that provides the primary user interface
|
|
22
|
+
* for the AI assistant CLI. Manages the TUI layout, handles keyboard shortcuts,
|
|
23
|
+
* processes agent events for streaming responses, and coordinates session lifecycle.
|
|
24
|
+
*/
|
|
25
|
+
export class Repl {
|
|
13
26
|
options;
|
|
27
|
+
terminal;
|
|
14
28
|
tui;
|
|
15
29
|
welcome;
|
|
16
30
|
editor;
|
|
@@ -32,9 +46,20 @@ export class NewRepl {
|
|
|
32
46
|
streamingComponent = null;
|
|
33
47
|
// thinking block tracking
|
|
34
48
|
thinkingBlockComponent = null;
|
|
49
|
+
// Track all verbose-aware components for re-rendering on toggle
|
|
50
|
+
allThinkingBlocks = [];
|
|
51
|
+
allToolExecutions = [];
|
|
52
|
+
// verbose mode state
|
|
53
|
+
verboseMode = false;
|
|
54
|
+
// mode manager
|
|
55
|
+
modeManager;
|
|
56
|
+
// ProjectConfig - initialized in init()
|
|
57
|
+
config;
|
|
58
|
+
/** Creates a new Repl instance, initializing the TUI layout and components. */
|
|
35
59
|
constructor(options) {
|
|
36
60
|
this.options = options;
|
|
37
|
-
this.
|
|
61
|
+
this.terminal = new ProcessTerminal(options.terminalOptions);
|
|
62
|
+
this.tui = new TUI(this.terminal);
|
|
38
63
|
this.welcome = new Welcome({ type: "simple" });
|
|
39
64
|
this.editor = new Editor({
|
|
40
65
|
borderColor: style.gray,
|
|
@@ -42,7 +67,7 @@ export class NewRepl {
|
|
|
42
67
|
this.chatContainer = new Container();
|
|
43
68
|
this.statusContainer = new Container();
|
|
44
69
|
this.editorContainer = new Container(); // Container to hold editor or selector
|
|
45
|
-
this.footer = new FooterComponent(options.modelManager, {
|
|
70
|
+
this.footer = new FooterComponent(options.modelManager, options.tokenTracker, {
|
|
46
71
|
projectStatus: {
|
|
47
72
|
path: "",
|
|
48
73
|
isGitRepository: false,
|
|
@@ -52,24 +77,43 @@ export class NewRepl {
|
|
|
52
77
|
},
|
|
53
78
|
currentContextWindow: 0,
|
|
54
79
|
contextWindow: options.modelManager.getModelMetadata("repl").contextWindow,
|
|
55
|
-
usage: this.options.tokenTracker.getUsageByApp("repl"),
|
|
56
80
|
});
|
|
57
81
|
this.editorContainer.addChild(this.editor); // Start with editor
|
|
58
82
|
this.editor.onRenderRequested = () => this.tui.requestRender();
|
|
83
|
+
this.editor.onExternalEditor = async (content) => {
|
|
84
|
+
return launchEditor({
|
|
85
|
+
initialContent: content,
|
|
86
|
+
postfix: ".md",
|
|
87
|
+
terminal: this.terminal,
|
|
88
|
+
});
|
|
89
|
+
};
|
|
59
90
|
this.isInitialized = false;
|
|
60
91
|
this.pendingTools = new Map();
|
|
61
92
|
this.tools = options.tools;
|
|
62
|
-
this.
|
|
93
|
+
this.modeManager = new ModeManager();
|
|
94
|
+
this.notification = new NotificationComponent("", { r: 52, g: 53, b: 65 }, style.yellow, 1, () => this.tui.requestRender());
|
|
63
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Initializes the REPL by setting up autocomplete,
|
|
98
|
+
* keyboard handlers, and the TUI component tree.
|
|
99
|
+
*/
|
|
64
100
|
async init() {
|
|
65
101
|
if (this.isInitialized) {
|
|
102
|
+
this.notification.setMessage("initialized");
|
|
66
103
|
return;
|
|
67
104
|
}
|
|
68
|
-
// Setup autocomplete for file paths
|
|
69
|
-
const
|
|
70
|
-
const
|
|
105
|
+
// Setup autocomplete for file paths, slash commands, and skills
|
|
106
|
+
const skills = await loadSkills();
|
|
107
|
+
const commandsList = await this.options.commands.getCompletions();
|
|
108
|
+
const autocompleteProvider = new CombinedProvider([
|
|
109
|
+
new CommandProvider(commandsList),
|
|
110
|
+
new AttachmentProvider(),
|
|
111
|
+
new FileSearchProvider(),
|
|
112
|
+
new SkillProvider(skills.getModelInvocable()),
|
|
113
|
+
]);
|
|
71
114
|
this.editor.setAutocompleteProvider(autocompleteProvider);
|
|
72
|
-
const { promptManager, modelManager,
|
|
115
|
+
const { promptManager, modelManager, sessionManager, commands, promptHistory, configManager, } = this.options;
|
|
116
|
+
this.config = await configManager.getConfig();
|
|
73
117
|
// Listen for session title updates
|
|
74
118
|
// messageHistory.on("update-title", (title: string) => {
|
|
75
119
|
// this.footer.setTitle(title);
|
|
@@ -80,16 +124,45 @@ export class NewRepl {
|
|
|
80
124
|
projectStatus: await getProjectStatus(),
|
|
81
125
|
currentContextWindow: 0,
|
|
82
126
|
contextWindow: modelConfig.contextWindow,
|
|
83
|
-
|
|
127
|
+
currentMode: this.modeManager.getDisplayName(),
|
|
84
128
|
});
|
|
85
129
|
this.tui.onCtrlC = () => {
|
|
86
130
|
this.handleCtrlC();
|
|
87
131
|
};
|
|
132
|
+
this.tui.onCtrlD = () => {
|
|
133
|
+
this.handleCtrlD();
|
|
134
|
+
};
|
|
135
|
+
this.tui.onCtrlO = () => {
|
|
136
|
+
this.handleCtrlO();
|
|
137
|
+
};
|
|
138
|
+
this.tui.onCtrlN = () => {
|
|
139
|
+
void this.handleCtrlN();
|
|
140
|
+
};
|
|
141
|
+
this.tui.onCtrlR = () => {
|
|
142
|
+
void showReviewPanel(this.tui, this.chatContainer, this.editorContainer, this.editor);
|
|
143
|
+
};
|
|
144
|
+
this.tui.onCtrlM = () => {
|
|
145
|
+
void this.handleCtrlM();
|
|
146
|
+
};
|
|
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
|
+
// Set callback for session reconstruction (used by /history command)
|
|
158
|
+
this.tui.onReconstructSession = () => this.rerender();
|
|
88
159
|
this.tui.addChild(this.welcome);
|
|
89
160
|
// Initialize footer with current title if one exists
|
|
90
161
|
// this.footer.setTitle(messageHistory.getTitle());
|
|
91
162
|
this.tui.addChild(this.chatContainer);
|
|
92
163
|
this.tui.addChild(this.statusContainer);
|
|
164
|
+
// Everything below here is fixed to the bottom of the terminal
|
|
165
|
+
this.tui.setFixedFooterStart();
|
|
93
166
|
this.tui.addChild(new Spacer(1));
|
|
94
167
|
this.tui.addChild(this.editorContainer); // Use container that can hold editor or selector
|
|
95
168
|
this.tui.addChild(this.footer);
|
|
@@ -112,38 +185,20 @@ export class NewRepl {
|
|
|
112
185
|
inputContainer: this.editorContainer,
|
|
113
186
|
editor: this.editor,
|
|
114
187
|
});
|
|
115
|
-
if (commandResult.break) {
|
|
116
|
-
this.stop(true);
|
|
117
|
-
process.exit(0);
|
|
118
|
-
}
|
|
119
188
|
if (commandResult.continue) {
|
|
120
189
|
this.editor.setText("");
|
|
121
190
|
this.tui.requestRender();
|
|
122
191
|
return;
|
|
123
192
|
}
|
|
124
193
|
if (!promptManager.isPending()) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
promptManager.addContext(context);
|
|
132
|
-
}
|
|
133
|
-
promptManager.set(processedPrompt.message);
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
if (error instanceof PromptError) {
|
|
137
|
-
this.chatContainer.addChild(new Text(style.red(`Prompt processing failed: ${error.message}`), 1, 1));
|
|
138
|
-
if (error.cause &&
|
|
139
|
-
typeof error.cause === "object" &&
|
|
140
|
-
"command" in error.cause &&
|
|
141
|
-
typeof error.cause.command === "string") {
|
|
142
|
-
this.chatContainer.addChild(new Text(style.red(`Command: ${error.cause.command}`, 1, 1)));
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
throw error; // Re-throw other errors
|
|
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);
|
|
146
200
|
}
|
|
201
|
+
promptManager.set(processedPrompt.message);
|
|
147
202
|
}
|
|
148
203
|
else {
|
|
149
204
|
promptHistory.push(promptManager.get());
|
|
@@ -153,11 +208,34 @@ export class NewRepl {
|
|
|
153
208
|
const hasAddedContext = promptManager.hasContext();
|
|
154
209
|
if (hasAddedContext) {
|
|
155
210
|
const contextTokenCount = promptManager.getContextTokenCount();
|
|
156
|
-
this.
|
|
211
|
+
this.addComponentWithSpacing(new Text(style.green(`Context will be added to prompt. (${contextTokenCount} tokens)`)));
|
|
157
212
|
}
|
|
158
213
|
const userPrompt = promptManager.get();
|
|
159
214
|
const userMsg = promptManager.getUserMessage();
|
|
160
|
-
|
|
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 });
|
|
237
|
+
this.editor.setText("");
|
|
238
|
+
this.tui.requestRender();
|
|
161
239
|
if (this.onInputCallback) {
|
|
162
240
|
this.onInputCallback(userPrompt);
|
|
163
241
|
}
|
|
@@ -167,18 +245,25 @@ export class NewRepl {
|
|
|
167
245
|
this.tui.start();
|
|
168
246
|
this.isInitialized = true;
|
|
169
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* Handles an agent event by updating the TUI accordingly.
|
|
250
|
+
* Processes events such as streaming messages, tool calls, thinking blocks,
|
|
251
|
+
* and agent lifecycle transitions (start, stop, error).
|
|
252
|
+
*/
|
|
170
253
|
async handle(event, state) {
|
|
171
254
|
if (!this.isInitialized) {
|
|
172
255
|
await this.init();
|
|
173
256
|
}
|
|
174
257
|
// Update footer with current stats
|
|
175
258
|
// this.footer.updateState(state);
|
|
259
|
+
// Use cached project status for all events to avoid blocking on git
|
|
260
|
+
// subprocess calls; refresh asynchronously at agent-stop
|
|
176
261
|
this.footer.setState({
|
|
177
|
-
projectStatus:
|
|
178
|
-
currentContextWindow: this.options.
|
|
262
|
+
projectStatus: this.footer.getProjectStatus(),
|
|
263
|
+
currentContextWindow: this.options.sessionManager.getLastTurnContextWindow(),
|
|
179
264
|
contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
|
|
180
265
|
agentState: state,
|
|
181
|
-
|
|
266
|
+
currentMode: this.modeManager.getDisplayName(),
|
|
182
267
|
});
|
|
183
268
|
const eventType = event.type;
|
|
184
269
|
switch (eventType) {
|
|
@@ -209,19 +294,13 @@ export class NewRepl {
|
|
|
209
294
|
// Create assistant component for streaming
|
|
210
295
|
const assistantMessageComponent = new AssistantMessageComponent();
|
|
211
296
|
this.streamingComponent = assistantMessageComponent;
|
|
212
|
-
this.
|
|
297
|
+
this.addComponentWithSpacing(assistantMessageComponent);
|
|
213
298
|
this.streamingComponent.updateContent(event);
|
|
214
299
|
this.tui.requestRender();
|
|
215
300
|
}
|
|
216
301
|
break;
|
|
217
302
|
case "message":
|
|
218
|
-
if (event.role === "
|
|
219
|
-
// Show user message immediately and clear editor
|
|
220
|
-
this.addMessageToChat(event);
|
|
221
|
-
this.editor.setText("");
|
|
222
|
-
this.tui.requestRender();
|
|
223
|
-
}
|
|
224
|
-
else if (event.role === "assistant") {
|
|
303
|
+
if (event.role === "assistant") {
|
|
225
304
|
// Update streaming component
|
|
226
305
|
if (this.streamingComponent && event.role === "assistant") {
|
|
227
306
|
this.streamingComponent.updateContent(event);
|
|
@@ -243,9 +322,12 @@ export class NewRepl {
|
|
|
243
322
|
}
|
|
244
323
|
else {
|
|
245
324
|
// Create tool component for new tool call
|
|
246
|
-
const newComponent = new ToolExecutionComponent(event.events
|
|
325
|
+
const newComponent = new ToolExecutionComponent(event.events, {
|
|
326
|
+
verboseMode: this.verboseMode,
|
|
327
|
+
});
|
|
247
328
|
this.pendingTools.set(event.toolCallId, newComponent);
|
|
248
|
-
this.
|
|
329
|
+
this.allToolExecutions.push(newComponent);
|
|
330
|
+
this.addComponentWithSpacing(newComponent);
|
|
249
331
|
}
|
|
250
332
|
this.tui.requestRender();
|
|
251
333
|
break;
|
|
@@ -267,10 +349,30 @@ export class NewRepl {
|
|
|
267
349
|
}
|
|
268
350
|
this.pendingTools.clear();
|
|
269
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
|
+
});
|
|
270
367
|
this.tui.requestRender();
|
|
271
368
|
break;
|
|
272
369
|
case "agent-error":
|
|
273
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
|
+
}
|
|
274
376
|
// Stop loading animation
|
|
275
377
|
if (this.loadingAnimation) {
|
|
276
378
|
this.loadingAnimation.stop();
|
|
@@ -286,9 +388,12 @@ export class NewRepl {
|
|
|
286
388
|
this.tui.requestRender();
|
|
287
389
|
break;
|
|
288
390
|
case "thinking-start": {
|
|
289
|
-
const component = new ThinkingBlockComponent(
|
|
391
|
+
const component = new ThinkingBlockComponent(undefined, {
|
|
392
|
+
verboseMode: this.verboseMode,
|
|
393
|
+
});
|
|
290
394
|
this.thinkingBlockComponent = component;
|
|
291
|
-
this.
|
|
395
|
+
this.allThinkingBlocks.push(component);
|
|
396
|
+
this.addComponentWithSpacing(component);
|
|
292
397
|
this.thinkingBlockComponent.updateContent(event);
|
|
293
398
|
this.tui.requestRender();
|
|
294
399
|
break;
|
|
@@ -301,7 +406,7 @@ export class NewRepl {
|
|
|
301
406
|
break;
|
|
302
407
|
case "thinking-end":
|
|
303
408
|
if (this.thinkingBlockComponent) {
|
|
304
|
-
this.thinkingBlockComponent.
|
|
409
|
+
this.thinkingBlockComponent.endThinking();
|
|
305
410
|
this.thinkingBlockComponent = null;
|
|
306
411
|
this.tui.requestRender();
|
|
307
412
|
}
|
|
@@ -310,16 +415,26 @@ export class NewRepl {
|
|
|
310
415
|
eventType;
|
|
311
416
|
}
|
|
312
417
|
}
|
|
418
|
+
/** Adds a user message component to the chat container. */
|
|
313
419
|
addMessageToChat(message) {
|
|
314
420
|
if (message.role === "user") {
|
|
315
421
|
// Extract text content from content blocks
|
|
316
422
|
const textContent = message.content;
|
|
317
423
|
if (textContent) {
|
|
318
424
|
const userComponent = new UserMessageComponent(textContent);
|
|
319
|
-
this.
|
|
425
|
+
this.addComponentWithSpacing(userComponent);
|
|
320
426
|
}
|
|
321
427
|
}
|
|
322
428
|
}
|
|
429
|
+
/**
|
|
430
|
+
* Adds a component to the chat container with spacing.
|
|
431
|
+
* Adds a Spacer(1) before every component (including the first).
|
|
432
|
+
*/
|
|
433
|
+
addComponentWithSpacing(component) {
|
|
434
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
435
|
+
this.chatContainer.addChild(component);
|
|
436
|
+
}
|
|
437
|
+
/** Returns a promise that resolves with the user's next input submission. */
|
|
323
438
|
async getUserInput() {
|
|
324
439
|
return new Promise((resolve) => {
|
|
325
440
|
this.onInputCallback = (text) => {
|
|
@@ -328,33 +443,75 @@ export class NewRepl {
|
|
|
328
443
|
};
|
|
329
444
|
});
|
|
330
445
|
}
|
|
446
|
+
/** Clears the editor input and triggers a re-render. */
|
|
331
447
|
clearEditor() {
|
|
332
448
|
this.editor.setText("");
|
|
333
449
|
this.tui.requestRender();
|
|
334
450
|
}
|
|
451
|
+
/**
|
|
452
|
+
* Sets the callback invoked when the user presses
|
|
453
|
+
* Escape to interrupt the agent.
|
|
454
|
+
*/
|
|
335
455
|
setInterruptCallback(callback) {
|
|
336
456
|
this.onInterruptCallback = callback;
|
|
337
457
|
}
|
|
458
|
+
/** Sets the callback invoked on exit, receiving the current session ID. */
|
|
338
459
|
setExitCallback(callback) {
|
|
339
460
|
this.onExitCallback = callback;
|
|
340
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* Re-renders the entire session by restoring mode state,
|
|
464
|
+
* replaying token usage, and reconstructing the chat
|
|
465
|
+
* display.
|
|
466
|
+
*/
|
|
341
467
|
async rerender() {
|
|
468
|
+
const modeState = this.options.sessionManager.getMetadata("modeState");
|
|
469
|
+
if (modeState && typeof modeState === "object" && "mode" in modeState) {
|
|
470
|
+
this.modeManager.fromJson(modeState);
|
|
471
|
+
}
|
|
472
|
+
// When resuming a session, populate tokenTracker with historical usage
|
|
473
|
+
// so the footer displays the correct total session usage
|
|
474
|
+
const totalUsage = this.options.sessionManager.getTotalTokenUsage();
|
|
475
|
+
if (totalUsage.inputTokens > 0 || totalUsage.outputTokens > 0) {
|
|
476
|
+
this.options.tokenTracker.trackUsage("repl", {
|
|
477
|
+
inputTokens: totalUsage.inputTokens,
|
|
478
|
+
outputTokens: totalUsage.outputTokens,
|
|
479
|
+
totalTokens: totalUsage.totalTokens,
|
|
480
|
+
inputTokenDetails: {
|
|
481
|
+
noCacheTokens: totalUsage.inputTokens - totalUsage.cachedInputTokens,
|
|
482
|
+
cacheReadTokens: totalUsage.cachedInputTokens,
|
|
483
|
+
cacheWriteTokens: 0,
|
|
484
|
+
},
|
|
485
|
+
outputTokenDetails: {
|
|
486
|
+
textTokens: totalUsage.outputTokens,
|
|
487
|
+
reasoningTokens: totalUsage.reasoningTokens,
|
|
488
|
+
},
|
|
489
|
+
});
|
|
490
|
+
}
|
|
342
491
|
this.footer.setState({
|
|
343
492
|
projectStatus: await getProjectStatus(),
|
|
344
|
-
currentContextWindow: this.options.
|
|
493
|
+
currentContextWindow: this.options.sessionManager.getLastTurnContextWindow(),
|
|
345
494
|
contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
|
|
346
|
-
|
|
495
|
+
currentMode: this.modeManager.getDisplayName(),
|
|
347
496
|
});
|
|
348
497
|
// Reconstruct entire session display from messages
|
|
349
498
|
this.reconstructSession();
|
|
499
|
+
this.tui.scrollToBottom();
|
|
350
500
|
this.tui.requestRender();
|
|
351
501
|
}
|
|
502
|
+
/**
|
|
503
|
+
* Rebuilds the chat container from the full session
|
|
504
|
+
* message history, including user messages, assistant
|
|
505
|
+
* responses, and tool executions.
|
|
506
|
+
*/
|
|
352
507
|
reconstructSession() {
|
|
353
508
|
// Clear existing display
|
|
354
509
|
this.pendingTools.clear();
|
|
510
|
+
this.allThinkingBlocks = [];
|
|
511
|
+
this.allToolExecutions = [];
|
|
355
512
|
this.chatContainer.clear();
|
|
356
513
|
// Get session messages
|
|
357
|
-
const messages = this.options.
|
|
514
|
+
const messages = this.options.sessionManager.get();
|
|
358
515
|
// First pass: collect all tool results
|
|
359
516
|
const toolResults = new Map();
|
|
360
517
|
for (const message of messages) {
|
|
@@ -385,7 +542,7 @@ export class NewRepl {
|
|
|
385
542
|
const textContent = this.extractUserMessageText(message);
|
|
386
543
|
if (textContent) {
|
|
387
544
|
const userComponent = new UserMessageComponent(textContent);
|
|
388
|
-
this.
|
|
545
|
+
this.addComponentWithSpacing(userComponent);
|
|
389
546
|
}
|
|
390
547
|
}
|
|
391
548
|
else if (message.role === "assistant") {
|
|
@@ -397,15 +554,22 @@ export class NewRepl {
|
|
|
397
554
|
const toolCallId = toolCallContent.toolCallId;
|
|
398
555
|
const events = this.createToolEvents(toolCallContent);
|
|
399
556
|
if (events.length > 0) {
|
|
400
|
-
const component = new ToolExecutionComponent(events
|
|
557
|
+
const component = new ToolExecutionComponent(events, {
|
|
558
|
+
verboseMode: this.verboseMode,
|
|
559
|
+
});
|
|
401
560
|
this.pendingTools.set(toolCallId, component);
|
|
402
|
-
this.
|
|
561
|
+
this.allToolExecutions.push(component);
|
|
562
|
+
this.addComponentWithSpacing(component);
|
|
403
563
|
}
|
|
404
564
|
}
|
|
405
565
|
}
|
|
406
566
|
// Tool messages are handled through their associated assistant message
|
|
407
567
|
}
|
|
408
568
|
}
|
|
569
|
+
/**
|
|
570
|
+
* Extracts the text content from a user message,
|
|
571
|
+
* handling both string and array content formats.
|
|
572
|
+
*/
|
|
409
573
|
extractUserMessageText(message) {
|
|
410
574
|
if (typeof message.content === "string") {
|
|
411
575
|
return message.content;
|
|
@@ -418,6 +582,10 @@ export class NewRepl {
|
|
|
418
582
|
}
|
|
419
583
|
return null;
|
|
420
584
|
}
|
|
585
|
+
/**
|
|
586
|
+
* Renders an assistant message into the chat container,
|
|
587
|
+
* including reasoning/thinking blocks and text content.
|
|
588
|
+
*/
|
|
421
589
|
renderAssistantMessage(message) {
|
|
422
590
|
if (typeof message.content === "string") {
|
|
423
591
|
if (message.content.trim()) {
|
|
@@ -427,10 +595,25 @@ export class NewRepl {
|
|
|
427
595
|
role: "assistant",
|
|
428
596
|
content: message.content,
|
|
429
597
|
});
|
|
430
|
-
this.
|
|
598
|
+
this.addComponentWithSpacing(assistantComponent);
|
|
431
599
|
}
|
|
432
600
|
}
|
|
433
601
|
else if (Array.isArray(message.content)) {
|
|
602
|
+
const reasoningParts = message.content
|
|
603
|
+
.filter((part) => part.type === "reasoning" &&
|
|
604
|
+
typeof part.text === "string" &&
|
|
605
|
+
part.text.trim().length > 0)
|
|
606
|
+
.map((part) => part.text)
|
|
607
|
+
.join("\n");
|
|
608
|
+
if (reasoningParts.trim()) {
|
|
609
|
+
const thinkingComponent = new ThinkingBlockComponent(undefined, {
|
|
610
|
+
verboseMode: this.verboseMode,
|
|
611
|
+
});
|
|
612
|
+
thinkingComponent.updateContent({ content: reasoningParts });
|
|
613
|
+
thinkingComponent.endThinking();
|
|
614
|
+
this.allThinkingBlocks.push(thinkingComponent);
|
|
615
|
+
this.addComponentWithSpacing(thinkingComponent);
|
|
616
|
+
}
|
|
434
617
|
const textParts = message.content
|
|
435
618
|
.filter((part) => part.type === "text" && part.text?.trim() !== undefined)
|
|
436
619
|
.map((part) => part.text)
|
|
@@ -442,10 +625,15 @@ export class NewRepl {
|
|
|
442
625
|
role: "assistant",
|
|
443
626
|
content: textParts,
|
|
444
627
|
});
|
|
445
|
-
this.
|
|
628
|
+
this.addComponentWithSpacing(assistantComponent);
|
|
446
629
|
}
|
|
447
630
|
}
|
|
448
631
|
}
|
|
632
|
+
/**
|
|
633
|
+
* Extracts tool call content parts from an assistant
|
|
634
|
+
* message, matching them with their corresponding
|
|
635
|
+
* tool results.
|
|
636
|
+
*/
|
|
449
637
|
extractToolCallsFromAssistant(message, toolResults) {
|
|
450
638
|
const toolCallContents = [];
|
|
451
639
|
if (typeof message.content === "string") {
|
|
@@ -470,6 +658,11 @@ export class NewRepl {
|
|
|
470
658
|
}
|
|
471
659
|
return toolCallContents;
|
|
472
660
|
}
|
|
661
|
+
/**
|
|
662
|
+
* Creates start and end/error ToolEvent pairs from a
|
|
663
|
+
* resolved tool call, using the tool's display function
|
|
664
|
+
* when available.
|
|
665
|
+
*/
|
|
473
666
|
createToolEvents(toolCallContent) {
|
|
474
667
|
const events = [];
|
|
475
668
|
// tool-call-start: use the tool's display function
|
|
@@ -498,6 +691,88 @@ export class NewRepl {
|
|
|
498
691
|
});
|
|
499
692
|
return events;
|
|
500
693
|
}
|
|
694
|
+
/**
|
|
695
|
+
* Toggles verbose mode on/off, updating all thinking
|
|
696
|
+
* block and tool execution components.
|
|
697
|
+
*/
|
|
698
|
+
handleCtrlO() {
|
|
699
|
+
this.verboseMode = !this.verboseMode;
|
|
700
|
+
const modeText = this.verboseMode ? "ON" : "OFF";
|
|
701
|
+
this.notification.setMessage(`Verbose mode: ${modeText}`);
|
|
702
|
+
// Update all verbose-aware components to reflect new verbose mode
|
|
703
|
+
for (const component of this.allThinkingBlocks) {
|
|
704
|
+
component.setVerboseMode(this.verboseMode);
|
|
705
|
+
}
|
|
706
|
+
for (const component of this.allToolExecutions) {
|
|
707
|
+
component.setVerboseMode(this.verboseMode);
|
|
708
|
+
}
|
|
709
|
+
this.tui.requestRender();
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Starts a new session by saving the current one,
|
|
713
|
+
* resetting mode/tokens/UI, and clearing the chat.
|
|
714
|
+
*/
|
|
715
|
+
async handleCtrlN() {
|
|
716
|
+
if (!this.options.sessionManager.isEmpty()) {
|
|
717
|
+
// Auto-generate rules before starting new session if enabled
|
|
718
|
+
// Run in background - don't block new session from starting
|
|
719
|
+
this.maybeGenerateRules().catch((err) => logger.debug({ err }, "Background rule generation failed"));
|
|
720
|
+
this.options.sessionManager.setMetadata("modeState", this.modeManager.toJson());
|
|
721
|
+
if (!this.options.noSession) {
|
|
722
|
+
await this.options.sessionManager.save();
|
|
723
|
+
}
|
|
724
|
+
this.options.sessionManager.create(this.options.modelManager.getModel("repl").modelId);
|
|
725
|
+
}
|
|
726
|
+
this.config = await this.options.configManager.getConfig();
|
|
727
|
+
this.modeManager.reset();
|
|
728
|
+
this.options.sessionManager.clearTransientMessages();
|
|
729
|
+
this.options.tokenTracker.reset();
|
|
730
|
+
setTerminalTitle(`acai: ${process.cwd()}`);
|
|
731
|
+
this.chatContainer.clear();
|
|
732
|
+
this.editor.setText("");
|
|
733
|
+
// Reset footer state to clear usage/cost/steps/tools/time
|
|
734
|
+
const footer = this.tui.children.find((child) => child.constructor.name === "FooterComponent");
|
|
735
|
+
if (footer) {
|
|
736
|
+
footer.resetState();
|
|
737
|
+
}
|
|
738
|
+
this.footer.setState({
|
|
739
|
+
projectStatus: this.footer.getProjectStatus(),
|
|
740
|
+
currentContextWindow: 0,
|
|
741
|
+
contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
|
|
742
|
+
currentMode: this.modeManager.getDisplayName(),
|
|
743
|
+
});
|
|
744
|
+
this.tui.requestRender();
|
|
745
|
+
}
|
|
746
|
+
handleCtrlM() {
|
|
747
|
+
showModelSelector(this.tui, this.editorContainer, this.editor, this.options.modelManager);
|
|
748
|
+
}
|
|
749
|
+
/** Handles Ctrl+D to exit the REPL when the editor is empty. */
|
|
750
|
+
handleCtrlD() {
|
|
751
|
+
// Only exit if the editor is empty
|
|
752
|
+
if (this.editor.getText().trim() !== "") {
|
|
753
|
+
// Editor has content, do nothing
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
// Editor is empty - proceed with exit
|
|
757
|
+
// Clear any pending notification timer
|
|
758
|
+
if (this.exitNotificationTimer) {
|
|
759
|
+
clearTimeout(this.exitNotificationTimer);
|
|
760
|
+
this.exitNotificationTimer = undefined;
|
|
761
|
+
}
|
|
762
|
+
this.notification.setMessage("");
|
|
763
|
+
this.tui.requestRender();
|
|
764
|
+
this.options.sessionManager.setMetadata("modeState", this.modeManager.toJson());
|
|
765
|
+
if (!this.options.noSession) {
|
|
766
|
+
void this.options.sessionManager.save();
|
|
767
|
+
}
|
|
768
|
+
this.stop(true);
|
|
769
|
+
process.exit(0);
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Handles Ctrl+C with double-press-to-exit logic.
|
|
773
|
+
* First press clears the editor; second press within
|
|
774
|
+
* 1 second exits.
|
|
775
|
+
*/
|
|
501
776
|
handleCtrlC() {
|
|
502
777
|
// Handle Ctrl+C double-press logic
|
|
503
778
|
const now = Date.now();
|
|
@@ -512,14 +787,17 @@ export class NewRepl {
|
|
|
512
787
|
}
|
|
513
788
|
this.notification.setMessage("");
|
|
514
789
|
this.tui.requestRender();
|
|
515
|
-
|
|
790
|
+
this.options.sessionManager.setMetadata("modeState", this.modeManager.toJson());
|
|
791
|
+
if (!this.options.noSession) {
|
|
792
|
+
void this.options.sessionManager.save();
|
|
793
|
+
}
|
|
516
794
|
this.stop(true);
|
|
517
795
|
process.exit(0);
|
|
518
796
|
}
|
|
519
797
|
else {
|
|
520
798
|
// First Ctrl+C - clear the editor and show notification
|
|
521
799
|
this.clearEditor();
|
|
522
|
-
this.notification.setMessage("Press Ctrl+C again to exit");
|
|
800
|
+
this.notification.setMessage("Press Ctrl+C again to exit", 1000);
|
|
523
801
|
this.tui.requestRender();
|
|
524
802
|
this.lastSigintTime = now;
|
|
525
803
|
// Clear notification after threshold if no second Ctrl+C
|
|
@@ -535,6 +813,10 @@ export class NewRepl {
|
|
|
535
813
|
}, DoublePressThreshold);
|
|
536
814
|
}
|
|
537
815
|
}
|
|
816
|
+
/**
|
|
817
|
+
* Stops the REPL, cleaning up timers, animations,
|
|
818
|
+
* and the TUI. Optionally triggers the exit callback.
|
|
819
|
+
*/
|
|
538
820
|
stop(showExitMessage = false) {
|
|
539
821
|
this.notification.setMessage("");
|
|
540
822
|
// Clear any pending notification timer
|
|
@@ -543,7 +825,11 @@ export class NewRepl {
|
|
|
543
825
|
this.exitNotificationTimer = undefined;
|
|
544
826
|
}
|
|
545
827
|
if (showExitMessage && this.onExitCallback) {
|
|
546
|
-
this.onExitCallback(this.options.
|
|
828
|
+
const result = this.onExitCallback(this.options.sessionManager.getSessionId());
|
|
829
|
+
// Await if the callback is async
|
|
830
|
+
if (result instanceof Promise) {
|
|
831
|
+
void result;
|
|
832
|
+
}
|
|
547
833
|
}
|
|
548
834
|
if (this.loadingAnimation) {
|
|
549
835
|
this.loadingAnimation.stop();
|
|
@@ -554,4 +840,41 @@ export class NewRepl {
|
|
|
554
840
|
this.isInitialized = false;
|
|
555
841
|
}
|
|
556
842
|
}
|
|
843
|
+
/**
|
|
844
|
+
* Generates rules automatically if autoGenerateRules is enabled
|
|
845
|
+
* and the session has messages.
|
|
846
|
+
*/
|
|
847
|
+
async maybeGenerateRules() {
|
|
848
|
+
try {
|
|
849
|
+
const config = this.config;
|
|
850
|
+
if (!config.autoGenerateRules) {
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
if (this.options.sessionManager.isEmpty()) {
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
const { rules } = await generateRulesFromSession({
|
|
857
|
+
modelManager: this.options.modelManager,
|
|
858
|
+
messages: this.options.sessionManager.get(),
|
|
859
|
+
tokenTracker: this.options.tokenTracker,
|
|
860
|
+
config: this.options.configManager,
|
|
861
|
+
workspace: this.options.workspace,
|
|
862
|
+
});
|
|
863
|
+
if (rules.length > 0) {
|
|
864
|
+
this.notification.setMessage(`Auto-generated ${rules.length} rule(s) saved`);
|
|
865
|
+
this.tui.requestRender();
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
catch (error) {
|
|
869
|
+
// Don't fail the session transition on rule generation errors
|
|
870
|
+
logger.debug({ error }, "Auto rule generation failed");
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Triggers rule generation for use before exit.
|
|
875
|
+
* Returns a promise that resolves when rules are generated.
|
|
876
|
+
*/
|
|
877
|
+
async triggerRuleGeneration() {
|
|
878
|
+
await this.maybeGenerateRules();
|
|
879
|
+
}
|
|
557
880
|
}
|