@travisennis/acai 0.0.9 → 0.0.11
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 +51 -760
- 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 +380 -199
- 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 -77
- package/dist/{stdin.d.ts → cli/stdin.d.ts} +2 -1
- package/dist/cli/stdin.d.ts.map +1 -0
- package/dist/{stdin.js → cli/stdin.js} +11 -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 -101
- package/dist/commands/generate-rules/service.d.ts +22 -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 +3 -2
- 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 +2 -1
- 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 +55 -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 +15 -1
- 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 +124 -135
- 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 +148 -141
- 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 +2 -5
- package/dist/models/openai-provider.d.ts.map +1 -1
- package/dist/models/openai-provider.js +0 -52
- package/dist/models/opencode-go-provider.d.ts +25 -0
- package/dist/models/opencode-go-provider.d.ts.map +1 -0
- package/dist/models/opencode-go-provider.js +78 -0
- package/dist/models/opencode-zen-provider.d.ts +7 -3
- package/dist/models/opencode-zen-provider.d.ts.map +1 -1
- package/dist/models/opencode-zen-provider.js +49 -10
- package/dist/models/openrouter-provider.d.ts +27 -31
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +121 -180
- package/dist/models/providers.d.ts +3 -3
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/providers.js +6 -0
- 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 +24 -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 +142 -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} +55 -85
- package/dist/{prompts.d.ts → prompts/system-prompt.d.ts} +7 -2
- package/dist/prompts/system-prompt.d.ts.map +1 -0
- package/dist/{prompts.js → prompts/system-prompt.js} +31 -16
- 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} +397 -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 +92 -0
- package/dist/sessions/manager.d.ts.map +1 -1
- package/dist/sessions/manager.js +262 -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/index.d.ts +29 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +294 -0
- package/dist/subagents/index.d.ts +16 -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 +3 -3
- 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 +1 -1
- 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 +174 -105
- 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/apply-patch.d.ts +62 -0
- package/dist/tools/apply-patch.d.ts.map +1 -0
- package/dist/tools/apply-patch.js +377 -0
- package/dist/tools/bash.d.ts +4 -3
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +349 -141
- 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 +3 -6
- 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 +292 -85
- package/dist/tools/glob.d.ts +6 -6
- package/dist/tools/glob.d.ts.map +1 -1
- package/dist/tools/glob.js +110 -63
- package/dist/tools/grep.d.ts +15 -12
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +315 -193
- package/dist/tools/index.d.ts +114 -9
- 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 +4 -6
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +84 -39
- 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 +36 -31
- 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 +50 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +446 -0
- package/dist/tools/web-search.d.ts +44 -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 +37 -17
- 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/utils.d.ts +2 -1
- package/dist/tui/autocomplete/utils.d.ts.map +1 -1
- package/dist/tui/autocomplete/utils.js +25 -23
- 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 +18 -3
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +211 -237
- 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 +10 -7
- 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 +36 -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.d.ts +2 -1
- package/dist/tui/components/welcome.d.ts.map +1 -1
- package/dist/tui/components/welcome.js +2 -2
- package/dist/tui/editor-launcher.d.ts +3 -2
- package/dist/tui/editor-launcher.d.ts.map +1 -1
- package/dist/tui/index.d.ts +0 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/terminal.d.ts.map +1 -1
- package/dist/tui/terminal.js +10 -2
- package/dist/tui/tui.d.ts +43 -0
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +166 -41
- package/dist/tui/utils.d.ts +1 -5
- package/dist/tui/utils.d.ts.map +1 -1
- package/dist/tui/utils.js +271 -44
- 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 +28 -30
- 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 +35 -26
- package/dist/cli.d.ts +0 -23
- package/dist/cli.d.ts.map +0 -1
- package/dist/commands/add-directory/types.d.ts +0 -6
- package/dist/commands/add-directory/types.d.ts.map +0 -1
- package/dist/commands/add-directory/types.js +0 -1
- package/dist/commands/copy/types.d.ts +0 -3
- package/dist/commands/copy/types.d.ts.map +0 -1
- package/dist/commands/copy/types.js +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 -122
- 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/review/types.d.ts +0 -12
- package/dist/commands/review/types.d.ts.map +0 -1
- package/dist/commands/review/types.js +0 -1
- 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.map +0 -1
- package/dist/repl-new.d.ts +0 -65
- package/dist/repl-new.d.ts.map +0 -1
- package/dist/skills.d.ts +0 -16
- package/dist/skills.d.ts.map +0 -1
- package/dist/skills.js +0 -233
- package/dist/stdin.d.ts.map +0 -1
- 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/utils/iterables.d.ts +0 -2
- package/dist/utils/iterables.d.ts.map +0 -1
- package/dist/utils/iterables.js +0 -6
- 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,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
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 {
|
|
14
26
|
options;
|
|
15
27
|
terminal;
|
|
16
28
|
tui;
|
|
@@ -34,6 +46,16 @@ export class NewRepl {
|
|
|
34
46
|
streamingComponent = null;
|
|
35
47
|
// thinking block tracking
|
|
36
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. */
|
|
37
59
|
constructor(options) {
|
|
38
60
|
this.options = options;
|
|
39
61
|
this.terminal = new ProcessTerminal(options.terminalOptions);
|
|
@@ -45,7 +67,7 @@ export class NewRepl {
|
|
|
45
67
|
this.chatContainer = new Container();
|
|
46
68
|
this.statusContainer = new Container();
|
|
47
69
|
this.editorContainer = new Container(); // Container to hold editor or selector
|
|
48
|
-
this.footer = new FooterComponent(options.modelManager, {
|
|
70
|
+
this.footer = new FooterComponent(options.modelManager, options.tokenTracker, {
|
|
49
71
|
projectStatus: {
|
|
50
72
|
path: "",
|
|
51
73
|
isGitRepository: false,
|
|
@@ -55,7 +77,6 @@ export class NewRepl {
|
|
|
55
77
|
},
|
|
56
78
|
currentContextWindow: 0,
|
|
57
79
|
contextWindow: options.modelManager.getModelMetadata("repl").contextWindow,
|
|
58
|
-
usage: this.options.tokenTracker.getUsageByApp("repl"),
|
|
59
80
|
});
|
|
60
81
|
this.editorContainer.addChild(this.editor); // Start with editor
|
|
61
82
|
this.editor.onRenderRequested = () => this.tui.requestRender();
|
|
@@ -69,17 +90,30 @@ export class NewRepl {
|
|
|
69
90
|
this.isInitialized = false;
|
|
70
91
|
this.pendingTools = new Map();
|
|
71
92
|
this.tools = options.tools;
|
|
72
|
-
this.
|
|
93
|
+
this.modeManager = new ModeManager();
|
|
94
|
+
this.notification = new NotificationComponent("", { r: 52, g: 53, b: 65 }, style.yellow, 1, () => this.tui.requestRender());
|
|
73
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Initializes the REPL by setting up autocomplete,
|
|
98
|
+
* keyboard handlers, and the TUI component tree.
|
|
99
|
+
*/
|
|
74
100
|
async init() {
|
|
75
101
|
if (this.isInitialized) {
|
|
102
|
+
this.notification.setMessage("initialized");
|
|
76
103
|
return;
|
|
77
104
|
}
|
|
78
|
-
// Setup autocomplete for file paths
|
|
79
|
-
const
|
|
80
|
-
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
|
+
]);
|
|
81
114
|
this.editor.setAutocompleteProvider(autocompleteProvider);
|
|
82
|
-
const { promptManager, modelManager,
|
|
115
|
+
const { promptManager, modelManager, sessionManager, commands, promptHistory, configManager, } = this.options;
|
|
116
|
+
this.config = await configManager.getConfig();
|
|
83
117
|
// Listen for session title updates
|
|
84
118
|
// messageHistory.on("update-title", (title: string) => {
|
|
85
119
|
// this.footer.setTitle(title);
|
|
@@ -90,16 +124,45 @@ export class NewRepl {
|
|
|
90
124
|
projectStatus: await getProjectStatus(),
|
|
91
125
|
currentContextWindow: 0,
|
|
92
126
|
contextWindow: modelConfig.contextWindow,
|
|
93
|
-
|
|
127
|
+
currentMode: this.modeManager.getDisplayName(),
|
|
94
128
|
});
|
|
95
129
|
this.tui.onCtrlC = () => {
|
|
96
130
|
this.handleCtrlC();
|
|
97
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();
|
|
98
159
|
this.tui.addChild(this.welcome);
|
|
99
160
|
// Initialize footer with current title if one exists
|
|
100
161
|
// this.footer.setTitle(messageHistory.getTitle());
|
|
101
162
|
this.tui.addChild(this.chatContainer);
|
|
102
163
|
this.tui.addChild(this.statusContainer);
|
|
164
|
+
// Everything below here is fixed to the bottom of the terminal
|
|
165
|
+
this.tui.setFixedFooterStart();
|
|
103
166
|
this.tui.addChild(new Spacer(1));
|
|
104
167
|
this.tui.addChild(this.editorContainer); // Use container that can hold editor or selector
|
|
105
168
|
this.tui.addChild(this.footer);
|
|
@@ -122,38 +185,20 @@ export class NewRepl {
|
|
|
122
185
|
inputContainer: this.editorContainer,
|
|
123
186
|
editor: this.editor,
|
|
124
187
|
});
|
|
125
|
-
if (commandResult.break) {
|
|
126
|
-
this.stop(true);
|
|
127
|
-
process.exit(0);
|
|
128
|
-
}
|
|
129
188
|
if (commandResult.continue) {
|
|
130
189
|
this.editor.setText("");
|
|
131
190
|
this.tui.requestRender();
|
|
132
191
|
return;
|
|
133
192
|
}
|
|
134
193
|
if (!promptManager.isPending()) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
promptManager.addContext(context);
|
|
142
|
-
}
|
|
143
|
-
promptManager.set(processedPrompt.message);
|
|
144
|
-
}
|
|
145
|
-
catch (error) {
|
|
146
|
-
if (error instanceof PromptError) {
|
|
147
|
-
this.chatContainer.addChild(new Text(style.red(`Prompt processing failed: ${error.message}`), 1, 1));
|
|
148
|
-
if (error.cause &&
|
|
149
|
-
typeof error.cause === "object" &&
|
|
150
|
-
"command" in error.cause &&
|
|
151
|
-
typeof error.cause.command === "string") {
|
|
152
|
-
this.chatContainer.addChild(new Text(style.red(`Command: ${error.cause.command}`, 1, 1)));
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
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);
|
|
156
200
|
}
|
|
201
|
+
promptManager.set(processedPrompt.message);
|
|
157
202
|
}
|
|
158
203
|
else {
|
|
159
204
|
promptHistory.push(promptManager.get());
|
|
@@ -163,11 +208,34 @@ export class NewRepl {
|
|
|
163
208
|
const hasAddedContext = promptManager.hasContext();
|
|
164
209
|
if (hasAddedContext) {
|
|
165
210
|
const contextTokenCount = promptManager.getContextTokenCount();
|
|
166
|
-
this.
|
|
211
|
+
this.addComponentWithSpacing(new Text(style.green(`Context will be added to prompt. (${contextTokenCount} tokens)`)));
|
|
167
212
|
}
|
|
168
213
|
const userPrompt = promptManager.get();
|
|
169
214
|
const userMsg = promptManager.getUserMessage();
|
|
170
|
-
|
|
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();
|
|
171
239
|
if (this.onInputCallback) {
|
|
172
240
|
this.onInputCallback(userPrompt);
|
|
173
241
|
}
|
|
@@ -177,18 +245,25 @@ export class NewRepl {
|
|
|
177
245
|
this.tui.start();
|
|
178
246
|
this.isInitialized = true;
|
|
179
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
|
+
*/
|
|
180
253
|
async handle(event, state) {
|
|
181
254
|
if (!this.isInitialized) {
|
|
182
255
|
await this.init();
|
|
183
256
|
}
|
|
184
257
|
// Update footer with current stats
|
|
185
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
|
|
186
261
|
this.footer.setState({
|
|
187
|
-
projectStatus:
|
|
188
|
-
currentContextWindow: this.options.
|
|
262
|
+
projectStatus: this.footer.getProjectStatus(),
|
|
263
|
+
currentContextWindow: this.options.sessionManager.getLastTurnContextWindow(),
|
|
189
264
|
contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
|
|
190
265
|
agentState: state,
|
|
191
|
-
|
|
266
|
+
currentMode: this.modeManager.getDisplayName(),
|
|
192
267
|
});
|
|
193
268
|
const eventType = event.type;
|
|
194
269
|
switch (eventType) {
|
|
@@ -219,19 +294,13 @@ export class NewRepl {
|
|
|
219
294
|
// Create assistant component for streaming
|
|
220
295
|
const assistantMessageComponent = new AssistantMessageComponent();
|
|
221
296
|
this.streamingComponent = assistantMessageComponent;
|
|
222
|
-
this.
|
|
297
|
+
this.addComponentWithSpacing(assistantMessageComponent);
|
|
223
298
|
this.streamingComponent.updateContent(event);
|
|
224
299
|
this.tui.requestRender();
|
|
225
300
|
}
|
|
226
301
|
break;
|
|
227
302
|
case "message":
|
|
228
|
-
if (event.role === "
|
|
229
|
-
// Show user message immediately and clear editor
|
|
230
|
-
this.addMessageToChat(event);
|
|
231
|
-
this.editor.setText("");
|
|
232
|
-
this.tui.requestRender();
|
|
233
|
-
}
|
|
234
|
-
else if (event.role === "assistant") {
|
|
303
|
+
if (event.role === "assistant") {
|
|
235
304
|
// Update streaming component
|
|
236
305
|
if (this.streamingComponent && event.role === "assistant") {
|
|
237
306
|
this.streamingComponent.updateContent(event);
|
|
@@ -253,9 +322,12 @@ export class NewRepl {
|
|
|
253
322
|
}
|
|
254
323
|
else {
|
|
255
324
|
// Create tool component for new tool call
|
|
256
|
-
const newComponent = new ToolExecutionComponent(event.events
|
|
325
|
+
const newComponent = new ToolExecutionComponent(event.events, {
|
|
326
|
+
verboseMode: this.verboseMode,
|
|
327
|
+
});
|
|
257
328
|
this.pendingTools.set(event.toolCallId, newComponent);
|
|
258
|
-
this.
|
|
329
|
+
this.allToolExecutions.push(newComponent);
|
|
330
|
+
this.addComponentWithSpacing(newComponent);
|
|
259
331
|
}
|
|
260
332
|
this.tui.requestRender();
|
|
261
333
|
break;
|
|
@@ -277,10 +349,30 @@ export class NewRepl {
|
|
|
277
349
|
}
|
|
278
350
|
this.pendingTools.clear();
|
|
279
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
|
+
});
|
|
280
367
|
this.tui.requestRender();
|
|
281
368
|
break;
|
|
282
369
|
case "agent-error":
|
|
283
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
|
+
}
|
|
284
376
|
// Stop loading animation
|
|
285
377
|
if (this.loadingAnimation) {
|
|
286
378
|
this.loadingAnimation.stop();
|
|
@@ -296,9 +388,20 @@ export class NewRepl {
|
|
|
296
388
|
this.tui.requestRender();
|
|
297
389
|
break;
|
|
298
390
|
case "thinking-start": {
|
|
299
|
-
const component = new ThinkingBlockComponent(
|
|
391
|
+
const component = new ThinkingBlockComponent(undefined, {
|
|
392
|
+
verboseMode: this.verboseMode,
|
|
393
|
+
});
|
|
300
394
|
this.thinkingBlockComponent = component;
|
|
301
|
-
this.
|
|
395
|
+
this.allThinkingBlocks.push(component);
|
|
396
|
+
// If a streaming message component already exists (text came before thinking),
|
|
397
|
+
// insert the thinking block BEFORE it to ensure correct visual order
|
|
398
|
+
if (this.streamingComponent) {
|
|
399
|
+
this.chatContainer.insertChildBefore(this.streamingComponent, component);
|
|
400
|
+
this.chatContainer.insertChildBefore(this.streamingComponent, new Spacer(1));
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
this.addComponentWithSpacing(component);
|
|
404
|
+
}
|
|
302
405
|
this.thinkingBlockComponent.updateContent(event);
|
|
303
406
|
this.tui.requestRender();
|
|
304
407
|
break;
|
|
@@ -311,7 +414,7 @@ export class NewRepl {
|
|
|
311
414
|
break;
|
|
312
415
|
case "thinking-end":
|
|
313
416
|
if (this.thinkingBlockComponent) {
|
|
314
|
-
this.thinkingBlockComponent.
|
|
417
|
+
this.thinkingBlockComponent.endThinking();
|
|
315
418
|
this.thinkingBlockComponent = null;
|
|
316
419
|
this.tui.requestRender();
|
|
317
420
|
}
|
|
@@ -320,16 +423,26 @@ export class NewRepl {
|
|
|
320
423
|
eventType;
|
|
321
424
|
}
|
|
322
425
|
}
|
|
426
|
+
/** Adds a user message component to the chat container. */
|
|
323
427
|
addMessageToChat(message) {
|
|
324
428
|
if (message.role === "user") {
|
|
325
429
|
// Extract text content from content blocks
|
|
326
430
|
const textContent = message.content;
|
|
327
431
|
if (textContent) {
|
|
328
432
|
const userComponent = new UserMessageComponent(textContent);
|
|
329
|
-
this.
|
|
433
|
+
this.addComponentWithSpacing(userComponent);
|
|
330
434
|
}
|
|
331
435
|
}
|
|
332
436
|
}
|
|
437
|
+
/**
|
|
438
|
+
* Adds a component to the chat container with spacing.
|
|
439
|
+
* Adds a Spacer(1) before every component (including the first).
|
|
440
|
+
*/
|
|
441
|
+
addComponentWithSpacing(component) {
|
|
442
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
443
|
+
this.chatContainer.addChild(component);
|
|
444
|
+
}
|
|
445
|
+
/** Returns a promise that resolves with the user's next input submission. */
|
|
333
446
|
async getUserInput() {
|
|
334
447
|
return new Promise((resolve) => {
|
|
335
448
|
this.onInputCallback = (text) => {
|
|
@@ -338,33 +451,75 @@ export class NewRepl {
|
|
|
338
451
|
};
|
|
339
452
|
});
|
|
340
453
|
}
|
|
454
|
+
/** Clears the editor input and triggers a re-render. */
|
|
341
455
|
clearEditor() {
|
|
342
456
|
this.editor.setText("");
|
|
343
457
|
this.tui.requestRender();
|
|
344
458
|
}
|
|
459
|
+
/**
|
|
460
|
+
* Sets the callback invoked when the user presses
|
|
461
|
+
* Escape to interrupt the agent.
|
|
462
|
+
*/
|
|
345
463
|
setInterruptCallback(callback) {
|
|
346
464
|
this.onInterruptCallback = callback;
|
|
347
465
|
}
|
|
466
|
+
/** Sets the callback invoked on exit, receiving the current session ID. */
|
|
348
467
|
setExitCallback(callback) {
|
|
349
468
|
this.onExitCallback = callback;
|
|
350
469
|
}
|
|
470
|
+
/**
|
|
471
|
+
* Re-renders the entire session by restoring mode state,
|
|
472
|
+
* replaying token usage, and reconstructing the chat
|
|
473
|
+
* display.
|
|
474
|
+
*/
|
|
351
475
|
async rerender() {
|
|
476
|
+
const modeState = this.options.sessionManager.getMetadata("modeState");
|
|
477
|
+
if (modeState && typeof modeState === "object" && "mode" in modeState) {
|
|
478
|
+
this.modeManager.fromJson(modeState);
|
|
479
|
+
}
|
|
480
|
+
// When resuming a session, populate tokenTracker with historical usage
|
|
481
|
+
// so the footer displays the correct total session usage
|
|
482
|
+
const totalUsage = this.options.sessionManager.getTotalTokenUsage();
|
|
483
|
+
if (totalUsage.inputTokens > 0 || totalUsage.outputTokens > 0) {
|
|
484
|
+
this.options.tokenTracker.trackUsage("repl", {
|
|
485
|
+
inputTokens: totalUsage.inputTokens,
|
|
486
|
+
outputTokens: totalUsage.outputTokens,
|
|
487
|
+
totalTokens: totalUsage.totalTokens,
|
|
488
|
+
inputTokenDetails: {
|
|
489
|
+
noCacheTokens: totalUsage.inputTokens - totalUsage.cachedInputTokens,
|
|
490
|
+
cacheReadTokens: totalUsage.cachedInputTokens,
|
|
491
|
+
cacheWriteTokens: 0,
|
|
492
|
+
},
|
|
493
|
+
outputTokenDetails: {
|
|
494
|
+
textTokens: totalUsage.outputTokens,
|
|
495
|
+
reasoningTokens: totalUsage.reasoningTokens,
|
|
496
|
+
},
|
|
497
|
+
});
|
|
498
|
+
}
|
|
352
499
|
this.footer.setState({
|
|
353
500
|
projectStatus: await getProjectStatus(),
|
|
354
|
-
currentContextWindow: this.options.
|
|
501
|
+
currentContextWindow: this.options.sessionManager.getLastTurnContextWindow(),
|
|
355
502
|
contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
|
|
356
|
-
|
|
503
|
+
currentMode: this.modeManager.getDisplayName(),
|
|
357
504
|
});
|
|
358
505
|
// Reconstruct entire session display from messages
|
|
359
506
|
this.reconstructSession();
|
|
507
|
+
this.tui.scrollToBottom();
|
|
360
508
|
this.tui.requestRender();
|
|
361
509
|
}
|
|
510
|
+
/**
|
|
511
|
+
* Rebuilds the chat container from the full session
|
|
512
|
+
* message history, including user messages, assistant
|
|
513
|
+
* responses, and tool executions.
|
|
514
|
+
*/
|
|
362
515
|
reconstructSession() {
|
|
363
516
|
// Clear existing display
|
|
364
517
|
this.pendingTools.clear();
|
|
518
|
+
this.allThinkingBlocks = [];
|
|
519
|
+
this.allToolExecutions = [];
|
|
365
520
|
this.chatContainer.clear();
|
|
366
521
|
// Get session messages
|
|
367
|
-
const messages = this.options.
|
|
522
|
+
const messages = this.options.sessionManager.get();
|
|
368
523
|
// First pass: collect all tool results
|
|
369
524
|
const toolResults = new Map();
|
|
370
525
|
for (const message of messages) {
|
|
@@ -395,7 +550,7 @@ export class NewRepl {
|
|
|
395
550
|
const textContent = this.extractUserMessageText(message);
|
|
396
551
|
if (textContent) {
|
|
397
552
|
const userComponent = new UserMessageComponent(textContent);
|
|
398
|
-
this.
|
|
553
|
+
this.addComponentWithSpacing(userComponent);
|
|
399
554
|
}
|
|
400
555
|
}
|
|
401
556
|
else if (message.role === "assistant") {
|
|
@@ -407,15 +562,22 @@ export class NewRepl {
|
|
|
407
562
|
const toolCallId = toolCallContent.toolCallId;
|
|
408
563
|
const events = this.createToolEvents(toolCallContent);
|
|
409
564
|
if (events.length > 0) {
|
|
410
|
-
const component = new ToolExecutionComponent(events
|
|
565
|
+
const component = new ToolExecutionComponent(events, {
|
|
566
|
+
verboseMode: this.verboseMode,
|
|
567
|
+
});
|
|
411
568
|
this.pendingTools.set(toolCallId, component);
|
|
412
|
-
this.
|
|
569
|
+
this.allToolExecutions.push(component);
|
|
570
|
+
this.addComponentWithSpacing(component);
|
|
413
571
|
}
|
|
414
572
|
}
|
|
415
573
|
}
|
|
416
574
|
// Tool messages are handled through their associated assistant message
|
|
417
575
|
}
|
|
418
576
|
}
|
|
577
|
+
/**
|
|
578
|
+
* Extracts the text content from a user message,
|
|
579
|
+
* handling both string and array content formats.
|
|
580
|
+
*/
|
|
419
581
|
extractUserMessageText(message) {
|
|
420
582
|
if (typeof message.content === "string") {
|
|
421
583
|
return message.content;
|
|
@@ -428,6 +590,10 @@ export class NewRepl {
|
|
|
428
590
|
}
|
|
429
591
|
return null;
|
|
430
592
|
}
|
|
593
|
+
/**
|
|
594
|
+
* Renders an assistant message into the chat container,
|
|
595
|
+
* including reasoning/thinking blocks and text content.
|
|
596
|
+
*/
|
|
431
597
|
renderAssistantMessage(message) {
|
|
432
598
|
if (typeof message.content === "string") {
|
|
433
599
|
if (message.content.trim()) {
|
|
@@ -437,10 +603,25 @@ export class NewRepl {
|
|
|
437
603
|
role: "assistant",
|
|
438
604
|
content: message.content,
|
|
439
605
|
});
|
|
440
|
-
this.
|
|
606
|
+
this.addComponentWithSpacing(assistantComponent);
|
|
441
607
|
}
|
|
442
608
|
}
|
|
443
609
|
else if (Array.isArray(message.content)) {
|
|
610
|
+
const reasoningParts = message.content
|
|
611
|
+
.filter((part) => part.type === "reasoning" &&
|
|
612
|
+
typeof part.text === "string" &&
|
|
613
|
+
part.text.trim().length > 0)
|
|
614
|
+
.map((part) => part.text)
|
|
615
|
+
.join("\n");
|
|
616
|
+
if (reasoningParts.trim()) {
|
|
617
|
+
const thinkingComponent = new ThinkingBlockComponent(undefined, {
|
|
618
|
+
verboseMode: this.verboseMode,
|
|
619
|
+
});
|
|
620
|
+
thinkingComponent.updateContent({ content: reasoningParts });
|
|
621
|
+
thinkingComponent.endThinking();
|
|
622
|
+
this.allThinkingBlocks.push(thinkingComponent);
|
|
623
|
+
this.addComponentWithSpacing(thinkingComponent);
|
|
624
|
+
}
|
|
444
625
|
const textParts = message.content
|
|
445
626
|
.filter((part) => part.type === "text" && part.text?.trim() !== undefined)
|
|
446
627
|
.map((part) => part.text)
|
|
@@ -452,10 +633,15 @@ export class NewRepl {
|
|
|
452
633
|
role: "assistant",
|
|
453
634
|
content: textParts,
|
|
454
635
|
});
|
|
455
|
-
this.
|
|
636
|
+
this.addComponentWithSpacing(assistantComponent);
|
|
456
637
|
}
|
|
457
638
|
}
|
|
458
639
|
}
|
|
640
|
+
/**
|
|
641
|
+
* Extracts tool call content parts from an assistant
|
|
642
|
+
* message, matching them with their corresponding
|
|
643
|
+
* tool results.
|
|
644
|
+
*/
|
|
459
645
|
extractToolCallsFromAssistant(message, toolResults) {
|
|
460
646
|
const toolCallContents = [];
|
|
461
647
|
if (typeof message.content === "string") {
|
|
@@ -480,6 +666,11 @@ export class NewRepl {
|
|
|
480
666
|
}
|
|
481
667
|
return toolCallContents;
|
|
482
668
|
}
|
|
669
|
+
/**
|
|
670
|
+
* Creates start and end/error ToolEvent pairs from a
|
|
671
|
+
* resolved tool call, using the tool's display function
|
|
672
|
+
* when available.
|
|
673
|
+
*/
|
|
483
674
|
createToolEvents(toolCallContent) {
|
|
484
675
|
const events = [];
|
|
485
676
|
// tool-call-start: use the tool's display function
|
|
@@ -508,6 +699,88 @@ export class NewRepl {
|
|
|
508
699
|
});
|
|
509
700
|
return events;
|
|
510
701
|
}
|
|
702
|
+
/**
|
|
703
|
+
* Toggles verbose mode on/off, updating all thinking
|
|
704
|
+
* block and tool execution components.
|
|
705
|
+
*/
|
|
706
|
+
handleCtrlO() {
|
|
707
|
+
this.verboseMode = !this.verboseMode;
|
|
708
|
+
const modeText = this.verboseMode ? "ON" : "OFF";
|
|
709
|
+
this.notification.setMessage(`Verbose mode: ${modeText}`);
|
|
710
|
+
// Update all verbose-aware components to reflect new verbose mode
|
|
711
|
+
for (const component of this.allThinkingBlocks) {
|
|
712
|
+
component.setVerboseMode(this.verboseMode);
|
|
713
|
+
}
|
|
714
|
+
for (const component of this.allToolExecutions) {
|
|
715
|
+
component.setVerboseMode(this.verboseMode);
|
|
716
|
+
}
|
|
717
|
+
this.tui.requestRender();
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Starts a new session by saving the current one,
|
|
721
|
+
* resetting mode/tokens/UI, and clearing the chat.
|
|
722
|
+
*/
|
|
723
|
+
async handleCtrlN() {
|
|
724
|
+
if (!this.options.sessionManager.isEmpty()) {
|
|
725
|
+
// Auto-generate rules before starting new session if enabled
|
|
726
|
+
// Run in background - don't block new session from starting
|
|
727
|
+
this.maybeGenerateRules().catch((err) => logger.debug({ err }, "Background rule generation failed"));
|
|
728
|
+
this.options.sessionManager.setMetadata("modeState", this.modeManager.toJson());
|
|
729
|
+
if (!this.options.noSession) {
|
|
730
|
+
await this.options.sessionManager.save();
|
|
731
|
+
}
|
|
732
|
+
this.options.sessionManager.create(this.options.modelManager.getModel("repl").modelId);
|
|
733
|
+
}
|
|
734
|
+
this.config = await this.options.configManager.getConfig();
|
|
735
|
+
this.modeManager.reset();
|
|
736
|
+
this.options.sessionManager.clearTransientMessages();
|
|
737
|
+
this.options.tokenTracker.reset();
|
|
738
|
+
setTerminalTitle(`acai: ${process.cwd()}`);
|
|
739
|
+
this.chatContainer.clear();
|
|
740
|
+
this.editor.setText("");
|
|
741
|
+
// Reset footer state to clear usage/cost/steps/tools/time
|
|
742
|
+
const footer = this.tui.children.find((child) => child.constructor.name === "FooterComponent");
|
|
743
|
+
if (footer) {
|
|
744
|
+
footer.resetState();
|
|
745
|
+
}
|
|
746
|
+
this.footer.setState({
|
|
747
|
+
projectStatus: this.footer.getProjectStatus(),
|
|
748
|
+
currentContextWindow: 0,
|
|
749
|
+
contextWindow: this.options.modelManager.getModelMetadata("repl").contextWindow,
|
|
750
|
+
currentMode: this.modeManager.getDisplayName(),
|
|
751
|
+
});
|
|
752
|
+
this.tui.requestRender();
|
|
753
|
+
}
|
|
754
|
+
handleCtrlM() {
|
|
755
|
+
showModelSelector(this.tui, this.editorContainer, this.editor, this.options.modelManager);
|
|
756
|
+
}
|
|
757
|
+
/** Handles Ctrl+D to exit the REPL when the editor is empty. */
|
|
758
|
+
handleCtrlD() {
|
|
759
|
+
// Only exit if the editor is empty
|
|
760
|
+
if (this.editor.getText().trim() !== "") {
|
|
761
|
+
// Editor has content, do nothing
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
// Editor is empty - proceed with exit
|
|
765
|
+
// Clear any pending notification timer
|
|
766
|
+
if (this.exitNotificationTimer) {
|
|
767
|
+
clearTimeout(this.exitNotificationTimer);
|
|
768
|
+
this.exitNotificationTimer = undefined;
|
|
769
|
+
}
|
|
770
|
+
this.notification.setMessage("");
|
|
771
|
+
this.tui.requestRender();
|
|
772
|
+
this.options.sessionManager.setMetadata("modeState", this.modeManager.toJson());
|
|
773
|
+
if (!this.options.noSession) {
|
|
774
|
+
void this.options.sessionManager.save();
|
|
775
|
+
}
|
|
776
|
+
this.stop(true);
|
|
777
|
+
process.exit(0);
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Handles Ctrl+C with double-press-to-exit logic.
|
|
781
|
+
* First press clears the editor; second press within
|
|
782
|
+
* 1 second exits.
|
|
783
|
+
*/
|
|
511
784
|
handleCtrlC() {
|
|
512
785
|
// Handle Ctrl+C double-press logic
|
|
513
786
|
const now = Date.now();
|
|
@@ -522,14 +795,17 @@ export class NewRepl {
|
|
|
522
795
|
}
|
|
523
796
|
this.notification.setMessage("");
|
|
524
797
|
this.tui.requestRender();
|
|
525
|
-
|
|
798
|
+
this.options.sessionManager.setMetadata("modeState", this.modeManager.toJson());
|
|
799
|
+
if (!this.options.noSession) {
|
|
800
|
+
void this.options.sessionManager.save();
|
|
801
|
+
}
|
|
526
802
|
this.stop(true);
|
|
527
803
|
process.exit(0);
|
|
528
804
|
}
|
|
529
805
|
else {
|
|
530
806
|
// First Ctrl+C - clear the editor and show notification
|
|
531
807
|
this.clearEditor();
|
|
532
|
-
this.notification.setMessage("Press Ctrl+C again to exit");
|
|
808
|
+
this.notification.setMessage("Press Ctrl+C again to exit", 1000);
|
|
533
809
|
this.tui.requestRender();
|
|
534
810
|
this.lastSigintTime = now;
|
|
535
811
|
// Clear notification after threshold if no second Ctrl+C
|
|
@@ -545,6 +821,10 @@ export class NewRepl {
|
|
|
545
821
|
}, DoublePressThreshold);
|
|
546
822
|
}
|
|
547
823
|
}
|
|
824
|
+
/**
|
|
825
|
+
* Stops the REPL, cleaning up timers, animations,
|
|
826
|
+
* and the TUI. Optionally triggers the exit callback.
|
|
827
|
+
*/
|
|
548
828
|
stop(showExitMessage = false) {
|
|
549
829
|
this.notification.setMessage("");
|
|
550
830
|
// Clear any pending notification timer
|
|
@@ -553,7 +833,11 @@ export class NewRepl {
|
|
|
553
833
|
this.exitNotificationTimer = undefined;
|
|
554
834
|
}
|
|
555
835
|
if (showExitMessage && this.onExitCallback) {
|
|
556
|
-
this.onExitCallback(this.options.
|
|
836
|
+
const result = this.onExitCallback(this.options.sessionManager.getSessionId());
|
|
837
|
+
// Await if the callback is async
|
|
838
|
+
if (result instanceof Promise) {
|
|
839
|
+
void result;
|
|
840
|
+
}
|
|
557
841
|
}
|
|
558
842
|
if (this.loadingAnimation) {
|
|
559
843
|
this.loadingAnimation.stop();
|
|
@@ -564,4 +848,41 @@ export class NewRepl {
|
|
|
564
848
|
this.isInitialized = false;
|
|
565
849
|
}
|
|
566
850
|
}
|
|
851
|
+
/**
|
|
852
|
+
* Generates rules automatically if autoGenerateRules is enabled
|
|
853
|
+
* and the session has messages.
|
|
854
|
+
*/
|
|
855
|
+
async maybeGenerateRules() {
|
|
856
|
+
try {
|
|
857
|
+
const config = this.config;
|
|
858
|
+
if (!config.autoGenerateRules) {
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
if (this.options.sessionManager.isEmpty()) {
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
const { rules } = await generateRulesFromSession({
|
|
865
|
+
modelManager: this.options.modelManager,
|
|
866
|
+
messages: this.options.sessionManager.get(),
|
|
867
|
+
tokenTracker: this.options.tokenTracker,
|
|
868
|
+
config: this.options.configManager,
|
|
869
|
+
workspace: this.options.workspace,
|
|
870
|
+
});
|
|
871
|
+
if (rules.length > 0) {
|
|
872
|
+
this.notification.setMessage(`Auto-generated ${rules.length} rule(s) saved`);
|
|
873
|
+
this.tui.requestRender();
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
catch (error) {
|
|
877
|
+
// Don't fail the session transition on rule generation errors
|
|
878
|
+
logger.debug({ error }, "Auto rule generation failed");
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Triggers rule generation for use before exit.
|
|
883
|
+
* Returns a promise that resolves when rules are generated.
|
|
884
|
+
*/
|
|
885
|
+
async triggerRuleGeneration() {
|
|
886
|
+
await this.maybeGenerateRules();
|
|
887
|
+
}
|
|
567
888
|
}
|