@travisennis/acai 0.0.1
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/.acai/acai.json +9 -0
- package/.acai/prompts/add-openrouter-model.md +13 -0
- package/.acai/prompts/project-status.md +4 -0
- package/.acai/prompts/update-architecture-document.md +9 -0
- package/.acai/rules/learned-rules.md +9 -0
- package/.ai/docs/available-tools.txt +3 -0
- package/.ai/docs/cognitive_complexity_refactoring_progress.md +65 -0
- package/.ai/docs/deleted_tools.md +168 -0
- package/.ai/docs/deleted_tools_88ced9ef.md +56 -0
- package/.ai/docs/image-pasting.md +46 -0
- package/.ai/docs/initialize-app.md +117 -0
- package/.ai/docs/issue-4-plan.md +44 -0
- package/.ai/docs/marked-renderer-debug.md +15 -0
- package/.ai/docs/marked-renderer-refactor-plan.md +64 -0
- package/.ai/docs/memory-use-cases.md +55 -0
- package/.ai/docs/prompt-consistency.md +31 -0
- package/.ai/docs/refactoring-tools.md +98 -0
- package/.ai/docs/system-prompt-update.md +174 -0
- package/.ai/docs/system_prompt.txt +210 -0
- package/.ai/docs/tasks.md +49 -0
- package/.ai/plan.md +131 -0
- package/.ai/prompt.md +1 -0
- package/.ai/scripts/fetch_models.js +27 -0
- package/.ai/scripts/generateSystemPrompt.ts +15 -0
- package/.ai/scripts/list-tools.mjs +4 -0
- package/.ai/scripts/p5_geometric_shapes.js +149 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +3 -0
- package/.husky/pre-push +1 -0
- package/.ignore +4 -0
- package/AGENTS.md +25 -0
- package/ARCHITECTURE.md +304 -0
- package/LICENSE +21 -0
- package/README.md +392 -0
- package/TODO.md +2 -0
- package/biome.json +61 -0
- package/commitlint.config.js +3 -0
- package/dist/cli.d.ts +19 -0
- package/dist/cli.js +116 -0
- package/dist/commands/application-log-command.d.ts +2 -0
- package/dist/commands/application-log-command.js +43 -0
- package/dist/commands/clear-command.d.ts +2 -0
- package/dist/commands/clear-command.js +12 -0
- package/dist/commands/compact-command.d.ts +2 -0
- package/dist/commands/compact-command.js +51 -0
- package/dist/commands/copy-command.d.ts +2 -0
- package/dist/commands/copy-command.js +51 -0
- package/dist/commands/edit-command.d.ts +2 -0
- package/dist/commands/edit-command.js +53 -0
- package/dist/commands/edit-prompt-command.d.ts +2 -0
- package/dist/commands/edit-prompt-command.js +25 -0
- package/dist/commands/exit-command.d.ts +2 -0
- package/dist/commands/exit-command.js +14 -0
- package/dist/commands/files-command.d.ts +2 -0
- package/dist/commands/files-command.js +63 -0
- package/dist/commands/generate-rules-command.d.ts +2 -0
- package/dist/commands/generate-rules-command.js +61 -0
- package/dist/commands/help-command.d.ts +2 -0
- package/dist/commands/help-command.js +19 -0
- package/dist/commands/init-command.d.ts +2 -0
- package/dist/commands/init-command.js +40 -0
- package/dist/commands/last-log-command.d.ts +2 -0
- package/dist/commands/last-log-command.js +76 -0
- package/dist/commands/manager.d.ts +22 -0
- package/dist/commands/manager.js +123 -0
- package/dist/commands/model-command.d.ts +2 -0
- package/dist/commands/model-command.js +84 -0
- package/dist/commands/paste-command.d.ts +2 -0
- package/dist/commands/paste-command.js +40 -0
- package/dist/commands/prompt-command.d.ts +2 -0
- package/dist/commands/prompt-command.js +111 -0
- package/dist/commands/reset-command.d.ts +2 -0
- package/dist/commands/reset-command.js +16 -0
- package/dist/commands/rules-command.d.ts +2 -0
- package/dist/commands/rules-command.js +68 -0
- package/dist/commands/save-command.d.ts +2 -0
- package/dist/commands/save-command.js +14 -0
- package/dist/commands/types.d.ts +26 -0
- package/dist/commands/types.js +1 -0
- package/dist/commands/usage-command.d.ts +2 -0
- package/dist/commands/usage-command.js +21 -0
- package/dist/config.d.ts +60 -0
- package/dist/config.js +193 -0
- package/dist/conversation-analyzer.d.ts +10 -0
- package/dist/conversation-analyzer.js +88 -0
- package/dist/dedent.d.ts +3 -0
- package/dist/dedent.js +38 -0
- package/dist/formatting.d.ts +17 -0
- package/dist/formatting.js +103 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +213 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +24 -0
- package/dist/mentions.d.ts +9 -0
- package/dist/mentions.js +182 -0
- package/dist/messages.d.ts +69 -0
- package/dist/messages.js +261 -0
- package/dist/middleware/audit-message.d.ts +5 -0
- package/dist/middleware/audit-message.js +95 -0
- package/dist/middleware/index.d.ts +2 -0
- package/dist/middleware/index.js +2 -0
- package/dist/middleware/rate-limit.d.ts +4 -0
- package/dist/middleware/rate-limit.js +17 -0
- package/dist/models/ai-config.d.ts +12 -0
- package/dist/models/ai-config.js +87 -0
- package/dist/models/anthropic-provider.d.ts +25 -0
- package/dist/models/anthropic-provider.js +184 -0
- package/dist/models/deepseek-provider.d.ts +20 -0
- package/dist/models/deepseek-provider.js +42 -0
- package/dist/models/google-provider.d.ts +19 -0
- package/dist/models/google-provider.js +56 -0
- package/dist/models/manager.d.ts +15 -0
- package/dist/models/manager.js +48 -0
- package/dist/models/openai-provider.d.ts +22 -0
- package/dist/models/openai-provider.js +70 -0
- package/dist/models/openrouter-provider.d.ts +36 -0
- package/dist/models/openrouter-provider.js +276 -0
- package/dist/models/providers.d.ts +33 -0
- package/dist/models/providers.js +116 -0
- package/dist/models/xai-provider.d.ts +20 -0
- package/dist/models/xai-provider.js +47 -0
- package/dist/parsing.d.ts +2 -0
- package/dist/parsing.js +18 -0
- package/dist/prompts/manager.d.ts +19 -0
- package/dist/prompts/manager.js +71 -0
- package/dist/prompts.d.ts +4 -0
- package/dist/prompts.js +158 -0
- package/dist/repl-prompt.d.ts +14 -0
- package/dist/repl-prompt.js +147 -0
- package/dist/repl.d.ts +27 -0
- package/dist/repl.js +431 -0
- package/dist/source/cli.d.ts +19 -0
- package/dist/source/cli.js +116 -0
- package/dist/source/commands/application-log-command.d.ts +2 -0
- package/dist/source/commands/application-log-command.js +43 -0
- package/dist/source/commands/clear-command.d.ts +2 -0
- package/dist/source/commands/clear-command.js +12 -0
- package/dist/source/commands/compact-command.d.ts +2 -0
- package/dist/source/commands/compact-command.js +51 -0
- package/dist/source/commands/copy-command.d.ts +2 -0
- package/dist/source/commands/copy-command.js +51 -0
- package/dist/source/commands/edit-command.d.ts +2 -0
- package/dist/source/commands/edit-command.js +53 -0
- package/dist/source/commands/edit-prompt-command.d.ts +2 -0
- package/dist/source/commands/edit-prompt-command.js +25 -0
- package/dist/source/commands/exit-command.d.ts +2 -0
- package/dist/source/commands/exit-command.js +14 -0
- package/dist/source/commands/files-command.d.ts +2 -0
- package/dist/source/commands/files-command.js +63 -0
- package/dist/source/commands/generate-rules-command.d.ts +2 -0
- package/dist/source/commands/generate-rules-command.js +61 -0
- package/dist/source/commands/help-command.d.ts +2 -0
- package/dist/source/commands/help-command.js +19 -0
- package/dist/source/commands/init-command.d.ts +2 -0
- package/dist/source/commands/init-command.js +40 -0
- package/dist/source/commands/last-log-command.d.ts +2 -0
- package/dist/source/commands/last-log-command.js +76 -0
- package/dist/source/commands/manager.d.ts +22 -0
- package/dist/source/commands/manager.js +123 -0
- package/dist/source/commands/model-command.d.ts +2 -0
- package/dist/source/commands/model-command.js +84 -0
- package/dist/source/commands/paste-command.d.ts +2 -0
- package/dist/source/commands/paste-command.js +40 -0
- package/dist/source/commands/prompt-command.d.ts +2 -0
- package/dist/source/commands/prompt-command.js +111 -0
- package/dist/source/commands/reset-command.d.ts +2 -0
- package/dist/source/commands/reset-command.js +16 -0
- package/dist/source/commands/rules-command.d.ts +2 -0
- package/dist/source/commands/rules-command.js +68 -0
- package/dist/source/commands/save-command.d.ts +2 -0
- package/dist/source/commands/save-command.js +14 -0
- package/dist/source/commands/types.d.ts +26 -0
- package/dist/source/commands/types.js +1 -0
- package/dist/source/commands/usage-command.d.ts +2 -0
- package/dist/source/commands/usage-command.js +21 -0
- package/dist/source/config.d.ts +60 -0
- package/dist/source/config.js +193 -0
- package/dist/source/conversation-analyzer.d.ts +10 -0
- package/dist/source/conversation-analyzer.js +88 -0
- package/dist/source/dedent.d.ts +3 -0
- package/dist/source/dedent.js +38 -0
- package/dist/source/formatting.d.ts +17 -0
- package/dist/source/formatting.js +103 -0
- package/dist/source/index.d.ts +18 -0
- package/dist/source/index.js +213 -0
- package/dist/source/logger.d.ts +2 -0
- package/dist/source/logger.js +24 -0
- package/dist/source/mentions.d.ts +9 -0
- package/dist/source/mentions.js +182 -0
- package/dist/source/messages.d.ts +69 -0
- package/dist/source/messages.js +261 -0
- package/dist/source/middleware/audit-message.d.ts +5 -0
- package/dist/source/middleware/audit-message.js +95 -0
- package/dist/source/middleware/index.d.ts +2 -0
- package/dist/source/middleware/index.js +2 -0
- package/dist/source/middleware/rate-limit.d.ts +4 -0
- package/dist/source/middleware/rate-limit.js +17 -0
- package/dist/source/models/ai-config.d.ts +12 -0
- package/dist/source/models/ai-config.js +87 -0
- package/dist/source/models/anthropic-provider.d.ts +25 -0
- package/dist/source/models/anthropic-provider.js +184 -0
- package/dist/source/models/deepseek-provider.d.ts +20 -0
- package/dist/source/models/deepseek-provider.js +42 -0
- package/dist/source/models/google-provider.d.ts +19 -0
- package/dist/source/models/google-provider.js +56 -0
- package/dist/source/models/manager.d.ts +15 -0
- package/dist/source/models/manager.js +48 -0
- package/dist/source/models/openai-provider.d.ts +22 -0
- package/dist/source/models/openai-provider.js +70 -0
- package/dist/source/models/openrouter-provider.d.ts +36 -0
- package/dist/source/models/openrouter-provider.js +276 -0
- package/dist/source/models/providers.d.ts +33 -0
- package/dist/source/models/providers.js +116 -0
- package/dist/source/models/xai-provider.d.ts +20 -0
- package/dist/source/models/xai-provider.js +47 -0
- package/dist/source/parsing.d.ts +2 -0
- package/dist/source/parsing.js +18 -0
- package/dist/source/prompts/manager.d.ts +19 -0
- package/dist/source/prompts/manager.js +71 -0
- package/dist/source/prompts.d.ts +4 -0
- package/dist/source/prompts.js +158 -0
- package/dist/source/repl-prompt.d.ts +14 -0
- package/dist/source/repl-prompt.js +147 -0
- package/dist/source/repl.d.ts +27 -0
- package/dist/source/repl.js +431 -0
- package/dist/source/terminal/formatting.d.ts +37 -0
- package/dist/source/terminal/formatting.js +106 -0
- package/dist/source/terminal/index.d.ts +94 -0
- package/dist/source/terminal/index.js +420 -0
- package/dist/source/terminal/markdown-utils.d.ts +2 -0
- package/dist/source/terminal/markdown-utils.js +81 -0
- package/dist/source/terminal/markdown.d.ts +1 -0
- package/dist/source/terminal/markdown.js +111 -0
- package/dist/source/terminal/types.d.ts +71 -0
- package/dist/source/terminal/types.js +1 -0
- package/dist/source/terminal-output.d.ts +8 -0
- package/dist/source/terminal-output.js +213 -0
- package/dist/source/terminal-output.test.d.ts +8 -0
- package/dist/source/terminal-output.test.js +213 -0
- package/dist/source/token-tracker.d.ts +14 -0
- package/dist/source/token-tracker.js +53 -0
- package/dist/source/token-utils.d.ts +7 -0
- package/dist/source/token-utils.js +13 -0
- package/dist/source/tools/agent.d.ts +17 -0
- package/dist/source/tools/agent.js +87 -0
- package/dist/source/tools/bash.d.ts +19 -0
- package/dist/source/tools/bash.js +294 -0
- package/dist/source/tools/code-interpreter.d.ts +12 -0
- package/dist/source/tools/code-interpreter.js +131 -0
- package/dist/source/tools/command-validation.d.ts +8 -0
- package/dist/source/tools/command-validation.js +69 -0
- package/dist/source/tools/delete-file.d.ts +12 -0
- package/dist/source/tools/delete-file.js +56 -0
- package/dist/source/tools/directory-tree.d.ts +12 -0
- package/dist/source/tools/directory-tree.js +38 -0
- package/dist/source/tools/edit-file.d.ts +19 -0
- package/dist/source/tools/edit-file.js +107 -0
- package/dist/source/tools/filesystem-utils.d.ts +22 -0
- package/dist/source/tools/filesystem-utils.js +191 -0
- package/dist/source/tools/git-utils.d.ts +14 -0
- package/dist/source/tools/git-utils.js +64 -0
- package/dist/source/tools/grep.d.ts +17 -0
- package/dist/source/tools/grep.js +138 -0
- package/dist/source/tools/index.d.ts +161 -0
- package/dist/source/tools/index.js +209 -0
- package/dist/source/tools/memory-read.d.ts +13 -0
- package/dist/source/tools/memory-read.js +135 -0
- package/dist/source/tools/memory-write.d.ts +12 -0
- package/dist/source/tools/memory-write.js +83 -0
- package/dist/source/tools/move-file.d.ts +13 -0
- package/dist/source/tools/move-file.js +44 -0
- package/dist/source/tools/read-file.d.ts +17 -0
- package/dist/source/tools/read-file.js +86 -0
- package/dist/source/tools/read-multiple-files.d.ts +14 -0
- package/dist/source/tools/read-multiple-files.js +55 -0
- package/dist/source/tools/save-file.d.ts +17 -0
- package/dist/source/tools/save-file.js +98 -0
- package/dist/source/tools/think.d.ts +11 -0
- package/dist/source/tools/think.js +45 -0
- package/dist/source/tools/types.d.ts +29 -0
- package/dist/source/tools/types.js +14 -0
- package/dist/source/tools/web-fetch.d.ts +47 -0
- package/dist/source/tools/web-fetch.js +246 -0
- package/dist/source/tools/web-search.d.ts +13 -0
- package/dist/source/tools/web-search.js +80 -0
- package/dist/source/utils/process.d.ts +36 -0
- package/dist/source/utils/process.js +75 -0
- package/dist/source/version.d.ts +1 -0
- package/dist/source/version.js +21 -0
- package/dist/terminal/formatting.d.ts +37 -0
- package/dist/terminal/formatting.js +106 -0
- package/dist/terminal/index.d.ts +94 -0
- package/dist/terminal/index.js +420 -0
- package/dist/terminal/markdown-utils.d.ts +2 -0
- package/dist/terminal/markdown-utils.js +81 -0
- package/dist/terminal/markdown.d.ts +1 -0
- package/dist/terminal/markdown.js +111 -0
- package/dist/terminal/types.d.ts +71 -0
- package/dist/terminal/types.js +1 -0
- package/dist/terminal-output.d.ts +8 -0
- package/dist/terminal-output.js +213 -0
- package/dist/token-tracker.d.ts +14 -0
- package/dist/token-tracker.js +53 -0
- package/dist/token-utils.d.ts +7 -0
- package/dist/token-utils.js +13 -0
- package/dist/tools/agent.d.ts +17 -0
- package/dist/tools/agent.js +87 -0
- package/dist/tools/bash.d.ts +19 -0
- package/dist/tools/bash.js +294 -0
- package/dist/tools/code-interpreter.d.ts +12 -0
- package/dist/tools/code-interpreter.js +131 -0
- package/dist/tools/command-validation.d.ts +8 -0
- package/dist/tools/command-validation.js +69 -0
- package/dist/tools/delete-file.d.ts +12 -0
- package/dist/tools/delete-file.js +56 -0
- package/dist/tools/directory-tree.d.ts +12 -0
- package/dist/tools/directory-tree.js +38 -0
- package/dist/tools/edit-file.d.ts +19 -0
- package/dist/tools/edit-file.js +107 -0
- package/dist/tools/filesystem-utils.d.ts +22 -0
- package/dist/tools/filesystem-utils.js +191 -0
- package/dist/tools/git-utils.d.ts +14 -0
- package/dist/tools/git-utils.js +64 -0
- package/dist/tools/grep.d.ts +17 -0
- package/dist/tools/grep.js +138 -0
- package/dist/tools/index.d.ts +161 -0
- package/dist/tools/index.js +209 -0
- package/dist/tools/memory-read.d.ts +13 -0
- package/dist/tools/memory-read.js +135 -0
- package/dist/tools/memory-write.d.ts +12 -0
- package/dist/tools/memory-write.js +83 -0
- package/dist/tools/move-file.d.ts +13 -0
- package/dist/tools/move-file.js +44 -0
- package/dist/tools/read-file.d.ts +17 -0
- package/dist/tools/read-file.js +86 -0
- package/dist/tools/read-multiple-files.d.ts +14 -0
- package/dist/tools/read-multiple-files.js +55 -0
- package/dist/tools/save-file.d.ts +17 -0
- package/dist/tools/save-file.js +98 -0
- package/dist/tools/think.d.ts +11 -0
- package/dist/tools/think.js +45 -0
- package/dist/tools/types.d.ts +29 -0
- package/dist/tools/types.js +14 -0
- package/dist/tools/web-fetch.d.ts +47 -0
- package/dist/tools/web-fetch.js +246 -0
- package/dist/tools/web-search.d.ts +13 -0
- package/dist/tools/web-search.js +80 -0
- package/dist/utils/process.d.ts +36 -0
- package/dist/utils/process.js +75 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +21 -0
- package/knip.json +5 -0
- package/package.json +83 -0
- package/source/cli.ts +172 -0
- package/source/commands/application-log-command.ts +53 -0
- package/source/commands/clear-command.ts +14 -0
- package/source/commands/compact-command.ts +64 -0
- package/source/commands/copy-command.ts +55 -0
- package/source/commands/edit-command.ts +63 -0
- package/source/commands/edit-prompt-command.ts +31 -0
- package/source/commands/exit-command.ts +18 -0
- package/source/commands/files-command.ts +85 -0
- package/source/commands/generate-rules-command.ts +82 -0
- package/source/commands/help-command.ts +27 -0
- package/source/commands/init-command.ts +48 -0
- package/source/commands/last-log-command.ts +88 -0
- package/source/commands/manager.ts +151 -0
- package/source/commands/model-command.ts +123 -0
- package/source/commands/paste-command.ts +62 -0
- package/source/commands/prompt-command.ts +150 -0
- package/source/commands/reset-command.ts +22 -0
- package/source/commands/rules-command.ts +76 -0
- package/source/commands/save-command.ts +20 -0
- package/source/commands/types.ts +28 -0
- package/source/commands/usage-command.ts +26 -0
- package/source/config.ts +223 -0
- package/source/conversation-analyzer.ts +115 -0
- package/source/dedent.ts +53 -0
- package/source/formatting.ts +132 -0
- package/source/index.ts +240 -0
- package/source/logger.ts +29 -0
- package/source/mentions.ts +227 -0
- package/source/messages.ts +360 -0
- package/source/middleware/audit-message.ts +133 -0
- package/source/middleware/index.ts +2 -0
- package/source/middleware/rate-limit.ts +24 -0
- package/source/models/ai-config.ts +109 -0
- package/source/models/anthropic-provider.ts +199 -0
- package/source/models/deepseek-provider.ts +53 -0
- package/source/models/google-provider.ts +68 -0
- package/source/models/manager.ts +84 -0
- package/source/models/openai-provider.ts +81 -0
- package/source/models/openrouter-provider.ts +288 -0
- package/source/models/providers.ts +197 -0
- package/source/models/xai-provider.ts +59 -0
- package/source/parsing.ts +20 -0
- package/source/prompts/manager.ts +90 -0
- package/source/prompts.ts +172 -0
- package/source/repl-prompt.ts +196 -0
- package/source/repl.ts +572 -0
- package/source/terminal/formatting.ts +121 -0
- package/source/terminal/index.ts +518 -0
- package/source/terminal/markdown-utils.ts +89 -0
- package/source/terminal/markdown.ts +155 -0
- package/source/terminal/types.ts +84 -0
- package/source/terminal-output.test.ts +266 -0
- package/source/token-tracker.ts +78 -0
- package/source/token-utils.ts +17 -0
- package/source/tools/agent.ts +107 -0
- package/source/tools/bash.ts +367 -0
- package/source/tools/code-interpreter.ts +172 -0
- package/source/tools/command-validation.ts +81 -0
- package/source/tools/delete-file.ts +71 -0
- package/source/tools/directory-tree.ts +54 -0
- package/source/tools/edit-file.ts +155 -0
- package/source/tools/filesystem-utils.ts +265 -0
- package/source/tools/git-utils.ts +70 -0
- package/source/tools/grep.ts +184 -0
- package/source/tools/index.ts +278 -0
- package/source/tools/memory-read.ts +174 -0
- package/source/tools/memory-write.ts +105 -0
- package/source/tools/move-file.ts +59 -0
- package/source/tools/read-file.ts +129 -0
- package/source/tools/read-multiple-files.ts +80 -0
- package/source/tools/save-file.ts +147 -0
- package/source/tools/think.ts +51 -0
- package/source/tools/types.ts +58 -0
- package/source/tools/web-fetch.ts +327 -0
- package/source/tools/web-search.ts +101 -0
- package/source/utils/process.ts +121 -0
- package/source/version.ts +21 -0
- package/test/commands/copy-command.test.ts +69 -0
- package/test/config.test.ts +200 -0
- package/test/terminal/markdown-utils.test.ts +124 -0
- package/test/tools/bash-tool.test.ts +58 -0
- package/test/tools/code-interpreter.test.ts +91 -0
- package/test/tools/command-validation.test.ts +48 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { isNumber, isRecord } from "@travisennis/stdlib/typeguards";
|
|
2
|
+
import { generateObject, NoSuchToolError, stepCountIs, streamText, } from "ai";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { config as configManager } from "./config.js";
|
|
5
|
+
import { logger } from "./logger.js";
|
|
6
|
+
import { processPrompt } from "./mentions.js";
|
|
7
|
+
import { AiConfig } from "./models/ai-config.js";
|
|
8
|
+
import { systemPrompt } from "./prompts.js";
|
|
9
|
+
import { ReplPrompt } from "./repl-prompt.js";
|
|
10
|
+
import { isMarkdown } from "./terminal/markdown-utils.js";
|
|
11
|
+
import { getCurrentBranch, getDiffStat, hasUncommittedChanges, inGitDirectory, } from "./tools/git-utils.js"; // Modified import
|
|
12
|
+
import { initAgents, initTools } from "./tools/index.js";
|
|
13
|
+
export class Repl {
|
|
14
|
+
options;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
}
|
|
18
|
+
async run() {
|
|
19
|
+
const { config, promptManager, terminal, modelManager, tokenTracker, messageHistory, commands, tokenCounter, toolEvents, autoAcceptAll, } = this.options;
|
|
20
|
+
logger.info(config, "Config:");
|
|
21
|
+
terminal.displayWelcome();
|
|
22
|
+
const promptHistory = [];
|
|
23
|
+
let currentContextWindow = 0;
|
|
24
|
+
messageHistory.on("clear-history", () => {
|
|
25
|
+
currentContextWindow = 0;
|
|
26
|
+
});
|
|
27
|
+
let prevCb = null;
|
|
28
|
+
while (true) {
|
|
29
|
+
const abortController = new AbortController();
|
|
30
|
+
const { signal } = abortController;
|
|
31
|
+
const cb = () => {
|
|
32
|
+
abortController.abort();
|
|
33
|
+
};
|
|
34
|
+
if (prevCb) {
|
|
35
|
+
process.removeListener("SIGINT", prevCb);
|
|
36
|
+
}
|
|
37
|
+
// Handle Ctrl+C (SIGINT)
|
|
38
|
+
process.on("SIGINT", cb);
|
|
39
|
+
prevCb = cb;
|
|
40
|
+
const langModel = modelManager.getModel("repl");
|
|
41
|
+
const modelConfig = modelManager.getModelMetadata("repl");
|
|
42
|
+
const currentDir = process.cwd().split("/").pop() || process.cwd();
|
|
43
|
+
const branch = await getCurrentBranch();
|
|
44
|
+
let branchDisplay = "";
|
|
45
|
+
if (branch) {
|
|
46
|
+
const hasChanges = await hasUncommittedChanges();
|
|
47
|
+
const asterisk = hasChanges ? "*" : "";
|
|
48
|
+
branchDisplay = ` ${chalk.gray(branch + asterisk)}`;
|
|
49
|
+
}
|
|
50
|
+
terminal.hr();
|
|
51
|
+
terminal.writeln(`${chalk.blue(currentDir)}${branchDisplay}`);
|
|
52
|
+
terminal.writeln(chalk.dim(langModel.modelId));
|
|
53
|
+
terminal.displayProgressBar(currentContextWindow, modelConfig.contextWindow);
|
|
54
|
+
if (!promptManager.isPending()) {
|
|
55
|
+
// For interactive input
|
|
56
|
+
const prompt = new ReplPrompt({ commands, history: promptHistory });
|
|
57
|
+
const userInput = await prompt.input();
|
|
58
|
+
prompt.close();
|
|
59
|
+
// see if the userInput contains a command
|
|
60
|
+
const commandResult = await commands.handle({ userInput });
|
|
61
|
+
if (commandResult.break) {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
if (commandResult.continue) {
|
|
65
|
+
terminal.lineBreak();
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (!userInput.trim()) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
// if there is no pending prompt then use the user's input. otherwise, the prompt was loaded from a command
|
|
72
|
+
if (!promptManager.isPending()) {
|
|
73
|
+
const processedPrompt = await processPrompt(userInput, {
|
|
74
|
+
baseDir: process.cwd(),
|
|
75
|
+
model: modelConfig,
|
|
76
|
+
});
|
|
77
|
+
for (const context of processedPrompt.context) {
|
|
78
|
+
promptManager.addContext(context);
|
|
79
|
+
}
|
|
80
|
+
promptManager.set(processedPrompt.message);
|
|
81
|
+
}
|
|
82
|
+
terminal.lineBreak();
|
|
83
|
+
}
|
|
84
|
+
// flag to see if the user prompt has added context
|
|
85
|
+
const hasAddedContext = promptManager.hasContext();
|
|
86
|
+
if (hasAddedContext) {
|
|
87
|
+
terminal.info("Context will be added to prompt.");
|
|
88
|
+
terminal.lineBreak();
|
|
89
|
+
}
|
|
90
|
+
const userPrompt = promptManager.get();
|
|
91
|
+
const userMsg = promptManager.getUserMessage();
|
|
92
|
+
messageHistory.appendUserMessage(userMsg);
|
|
93
|
+
const finalSystemPrompt = await systemPrompt({
|
|
94
|
+
supportsToolCalling: modelConfig.supportsToolCalling,
|
|
95
|
+
});
|
|
96
|
+
const aiConfig = new AiConfig({
|
|
97
|
+
modelMetadata: modelConfig,
|
|
98
|
+
prompt: userPrompt,
|
|
99
|
+
});
|
|
100
|
+
const maxTokens = aiConfig.getMaxTokens();
|
|
101
|
+
const tools = modelConfig.supportsToolCalling
|
|
102
|
+
? {
|
|
103
|
+
...(await initTools({
|
|
104
|
+
terminal,
|
|
105
|
+
tokenCounter,
|
|
106
|
+
autoAcceptAll,
|
|
107
|
+
events: toolEvents,
|
|
108
|
+
})),
|
|
109
|
+
...(await initAgents({
|
|
110
|
+
terminal,
|
|
111
|
+
modelManager,
|
|
112
|
+
tokenTracker,
|
|
113
|
+
tokenCounter,
|
|
114
|
+
events: toolEvents,
|
|
115
|
+
})),
|
|
116
|
+
}
|
|
117
|
+
: undefined;
|
|
118
|
+
try {
|
|
119
|
+
const result = streamText({
|
|
120
|
+
model: langModel,
|
|
121
|
+
maxOutputTokens: maxTokens,
|
|
122
|
+
messages: [
|
|
123
|
+
{
|
|
124
|
+
role: "system",
|
|
125
|
+
content: finalSystemPrompt,
|
|
126
|
+
providerOptions: {
|
|
127
|
+
anthropic: { cacheControl: { type: "ephemeral" } },
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
...messageHistory.get(),
|
|
131
|
+
],
|
|
132
|
+
temperature: modelConfig.defaultTemperature,
|
|
133
|
+
stopWhen: stepCountIs(60),
|
|
134
|
+
maxRetries: 2,
|
|
135
|
+
providerOptions: aiConfig.getProviderOptions(),
|
|
136
|
+
tools,
|
|
137
|
+
// biome-ignore lint/style/useNamingConvention: third-party controlled
|
|
138
|
+
experimental_repairToolCall: modelConfig.supportsToolCalling
|
|
139
|
+
? toolCallRepair(modelManager, terminal)
|
|
140
|
+
: undefined,
|
|
141
|
+
abortSignal: signal,
|
|
142
|
+
onFinish: async (result) => {
|
|
143
|
+
logger.debug("onFinish called");
|
|
144
|
+
if (result.response.messages.length > 0) {
|
|
145
|
+
messageHistory.appendResponseMessages(result.response.messages);
|
|
146
|
+
}
|
|
147
|
+
terminal.hr();
|
|
148
|
+
// Notify if configured in project config (acai.json)
|
|
149
|
+
const projectConfig = await configManager.readProjectConfig();
|
|
150
|
+
if (projectConfig.notify) {
|
|
151
|
+
terminal.alert();
|
|
152
|
+
}
|
|
153
|
+
// Create a more visual representation of steps/tool usage
|
|
154
|
+
this.displayToolUse(result, terminal);
|
|
155
|
+
if (await inGitDirectory()) {
|
|
156
|
+
// Added check
|
|
157
|
+
const stats = await getDiffStat();
|
|
158
|
+
terminal.writeln(`${chalk.dim("Files changed:")} ${chalk.yellow(stats.filesChanged)} ` +
|
|
159
|
+
`${chalk.green(`+${stats.insertions}`)} ` + // Insertions first (green)
|
|
160
|
+
`${chalk.red(`-${stats.deletions}`)}`);
|
|
161
|
+
}
|
|
162
|
+
const total = result.totalUsage ??
|
|
163
|
+
result.usage;
|
|
164
|
+
const outgoingTokens = isNumber(total.inputTokens)
|
|
165
|
+
? total.inputTokens
|
|
166
|
+
: 0;
|
|
167
|
+
const incomingTokens = isNumber(total.outputTokens)
|
|
168
|
+
? total.outputTokens
|
|
169
|
+
: 0;
|
|
170
|
+
const tokenSummary = `Tokens: ↑ ${outgoingTokens} ↓ ${incomingTokens}`;
|
|
171
|
+
terminal.writeln(chalk.dim(tokenSummary));
|
|
172
|
+
// Track aggregate usage across all steps when available
|
|
173
|
+
tokenTracker.trackUsage("repl", total);
|
|
174
|
+
// Derive current context window from final step usage
|
|
175
|
+
const finalTotalTokens = result.usage.totalTokens;
|
|
176
|
+
if (isNumber(finalTotalTokens)) {
|
|
177
|
+
currentContextWindow = finalTotalTokens ?? 0;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// Fallback: find the stopped step
|
|
181
|
+
for (const step of result.steps) {
|
|
182
|
+
if (step.finishReason === "stop") {
|
|
183
|
+
const usage = step.usage;
|
|
184
|
+
currentContextWindow = Number.isNaN(usage.totalTokens)
|
|
185
|
+
? 0
|
|
186
|
+
: (usage.totalTokens ?? 0);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// comment out auto-summarization for now. it's been causing issues.
|
|
191
|
+
// if (currentContextWindow > 70000) {
|
|
192
|
+
// logger.info(
|
|
193
|
+
// `Condensing history from ${currentContextWindow} to 0`,
|
|
194
|
+
// );
|
|
195
|
+
// await messageHistory.summarizeAndReset();
|
|
196
|
+
// }
|
|
197
|
+
terminal.hr();
|
|
198
|
+
},
|
|
199
|
+
onError: ({ error }) => {
|
|
200
|
+
logger.error(error, // Log the full error object
|
|
201
|
+
"Error on REPL streamText");
|
|
202
|
+
terminal.error(error.message.length > 100
|
|
203
|
+
? `${error.message.slice(0, 100)}...`
|
|
204
|
+
: error.message);
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
let accumulatedText = "";
|
|
208
|
+
let lastType = null;
|
|
209
|
+
for await (const chunk of result.fullStream) {
|
|
210
|
+
// Handle text-related chunks (reasoning or text-delta)
|
|
211
|
+
if (chunk.type === "reasoning-delta" || chunk.type === "text-delta") {
|
|
212
|
+
if (chunk.type === "reasoning-delta") {
|
|
213
|
+
if (lastType !== "reasoning") {
|
|
214
|
+
terminal.writeln(chalk.dim("<think>"));
|
|
215
|
+
}
|
|
216
|
+
terminal.write(chalk.dim(chunk.text)); // Stream reasoning directly
|
|
217
|
+
lastType = "reasoning";
|
|
218
|
+
}
|
|
219
|
+
else if (chunk.type === "text-delta") {
|
|
220
|
+
if (lastType === "reasoning") {
|
|
221
|
+
// Finishing reasoning: Print </think>
|
|
222
|
+
terminal.writeln(chalk.dim("\n</think>\n"));
|
|
223
|
+
}
|
|
224
|
+
accumulatedText += chunk.text;
|
|
225
|
+
lastType = "text";
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else if (chunk.type === "tool-result") {
|
|
229
|
+
const messages = toolEvents.get(chunk.toolCallId);
|
|
230
|
+
if (messages) {
|
|
231
|
+
displayToolMessages(messages, terminal);
|
|
232
|
+
toolEvents.delete(chunk.toolCallId);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
logger.warn(`No tool events found for ${chunk.toolCallId}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
// Close thinking tags when moving from reasoning to any other chunk type
|
|
240
|
+
if (lastType === "reasoning") {
|
|
241
|
+
terminal.write(chalk.dim("\n</think>\n\n"));
|
|
242
|
+
}
|
|
243
|
+
// if there is accumulatedText, display it
|
|
244
|
+
if (accumulatedText) {
|
|
245
|
+
terminal.writeln(`${chalk.blue.bold("●")} Response:`);
|
|
246
|
+
terminal.display(accumulatedText, true);
|
|
247
|
+
terminal.lineBreak();
|
|
248
|
+
}
|
|
249
|
+
accumulatedText = "";
|
|
250
|
+
lastType = null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Ensure the final closing tag for reasoning is written if it was the last type
|
|
254
|
+
if (lastType === "reasoning") {
|
|
255
|
+
terminal.write(chalk.gray("\n</think>\n\n"));
|
|
256
|
+
}
|
|
257
|
+
// if there is accumulatedText, display it
|
|
258
|
+
if (accumulatedText) {
|
|
259
|
+
terminal.writeln(`${chalk.green.bold("●")} Response:`);
|
|
260
|
+
terminal.display(accumulatedText, true);
|
|
261
|
+
terminal.lineBreak();
|
|
262
|
+
}
|
|
263
|
+
terminal.lineBreak(); // Add a final newline for clarity
|
|
264
|
+
await result.consumeStream();
|
|
265
|
+
}
|
|
266
|
+
catch (e) {
|
|
267
|
+
if (isRecord(e) && isRecord(e["data"]) && "error" in e["data"]) {
|
|
268
|
+
terminal.error(e["data"]["error"].message);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
terminal.error(e.message.length > 100
|
|
272
|
+
? `${e.message.slice(0, 100)}...`
|
|
273
|
+
: e.message);
|
|
274
|
+
}
|
|
275
|
+
terminal.lineBreak();
|
|
276
|
+
if (e instanceof Error) {
|
|
277
|
+
logger.error(e);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
logger.error(JSON.stringify(e, null, 2));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
displayToolUse(result, terminal) {
|
|
286
|
+
const toolsCalled = [];
|
|
287
|
+
const toolColors = new Map();
|
|
288
|
+
const chalkColors = [
|
|
289
|
+
"red",
|
|
290
|
+
"green",
|
|
291
|
+
"yellow",
|
|
292
|
+
"blue",
|
|
293
|
+
"magenta",
|
|
294
|
+
"cyan",
|
|
295
|
+
"white",
|
|
296
|
+
"gray",
|
|
297
|
+
"redBright",
|
|
298
|
+
"greenBright",
|
|
299
|
+
"yellowBright",
|
|
300
|
+
"blueBright",
|
|
301
|
+
"magentaBright",
|
|
302
|
+
"cyanBright",
|
|
303
|
+
"whiteBright",
|
|
304
|
+
"blackBright",
|
|
305
|
+
];
|
|
306
|
+
terminal.writeln(chalk.dim(`Steps: ${result.steps.length}`));
|
|
307
|
+
for (const step of result.steps) {
|
|
308
|
+
let currentToolCalls = [];
|
|
309
|
+
if (step.toolResults.length > 0) {
|
|
310
|
+
currentToolCalls = step.toolResults;
|
|
311
|
+
}
|
|
312
|
+
else if (step.toolCalls.length > 0) {
|
|
313
|
+
currentToolCalls = step.toolCalls;
|
|
314
|
+
}
|
|
315
|
+
for (const toolCallOrResult of currentToolCalls) {
|
|
316
|
+
const toolName = toolCallOrResult.toolName;
|
|
317
|
+
if (!toolColors.has(toolName)) {
|
|
318
|
+
const availableColors = chalkColors.filter((color) => !Array.from(toolColors.values()).some((c) => c === chalk[color]));
|
|
319
|
+
const color = availableColors.length > 0
|
|
320
|
+
? (availableColors[Math.floor(Math.random() * availableColors.length)] ?? "white")
|
|
321
|
+
: "white";
|
|
322
|
+
toolColors.set(toolName, chalk[color]);
|
|
323
|
+
}
|
|
324
|
+
toolsCalled.push(toolName);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (toolsCalled.length > 0) {
|
|
328
|
+
terminal.writeln(chalk.dim("Tools:"));
|
|
329
|
+
for (const toolCalled of toolsCalled) {
|
|
330
|
+
const colorFn = toolColors.get(toolCalled) ?? chalk.white;
|
|
331
|
+
terminal.write(`${colorFn("██")} `);
|
|
332
|
+
}
|
|
333
|
+
terminal.lineBreak();
|
|
334
|
+
const uniqueTools = new Set(toolsCalled);
|
|
335
|
+
for (const [index, toolCalled] of Array.from(uniqueTools).entries()) {
|
|
336
|
+
const colorFn = toolColors.get(toolCalled) ?? chalk.white;
|
|
337
|
+
terminal.write(colorFn(toolCalled));
|
|
338
|
+
if (index < new Set(toolsCalled).size - 1) {
|
|
339
|
+
terminal.write(" - ");
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
terminal.lineBreak();
|
|
343
|
+
terminal.lineBreak();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function displayToolMessages(messages, terminal) {
|
|
348
|
+
const isError = messages[messages.length - 1]?.event === "tool-error";
|
|
349
|
+
const indicator = isError ? chalk.red.bold("●") : chalk.blue.bold("●");
|
|
350
|
+
const initMessage = messages.find((m) => m.event === "tool-init")?.data ?? "Tool Execution";
|
|
351
|
+
terminal.write(`${indicator} `); // Write indicator without newline (sync)
|
|
352
|
+
terminal.display(initMessage); // Display initial message (async)
|
|
353
|
+
for (const msg of messages) {
|
|
354
|
+
switch (msg.event) {
|
|
355
|
+
case "tool-update":
|
|
356
|
+
_handleToolUpdateMessage(msg.data, terminal);
|
|
357
|
+
break;
|
|
358
|
+
case "tool-completion":
|
|
359
|
+
_handleToolCompletionMessage(msg.data, terminal);
|
|
360
|
+
break;
|
|
361
|
+
case "tool-error":
|
|
362
|
+
_handleToolErrorMessage(msg.data, terminal);
|
|
363
|
+
break;
|
|
364
|
+
// 'tool-init' is handled before the loop, so no case needed here.
|
|
365
|
+
default:
|
|
366
|
+
// Optional: Log an unexpected event type for debugging, or do nothing.
|
|
367
|
+
logger.debug(`Unhandled tool message event: ${msg.event}`);
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
terminal.lineBreak();
|
|
372
|
+
}
|
|
373
|
+
// Helper function to handle tool update messages
|
|
374
|
+
function _handleToolUpdateMessage(data, terminal) {
|
|
375
|
+
if (data.secondary && data.secondary.length > 0) {
|
|
376
|
+
const content = data.secondary.join("\n");
|
|
377
|
+
if (content.trim().length !== 0) {
|
|
378
|
+
terminal.display(`└── ${data.primary}`);
|
|
379
|
+
terminal.hr();
|
|
380
|
+
if (isMarkdown(content)) {
|
|
381
|
+
terminal.display(content, true);
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
terminal.write(chalk.green(content));
|
|
385
|
+
terminal.lineBreak();
|
|
386
|
+
}
|
|
387
|
+
terminal.hr();
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
terminal.display(`└── ${data.primary}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// Helper function to handle tool completion messages
|
|
395
|
+
function _handleToolCompletionMessage(data, terminal) {
|
|
396
|
+
terminal.display(`└── ${data}`);
|
|
397
|
+
}
|
|
398
|
+
// Helper function to handle tool error messages
|
|
399
|
+
function _handleToolErrorMessage(data, terminal) {
|
|
400
|
+
terminal.write("└── ");
|
|
401
|
+
terminal.error(data);
|
|
402
|
+
}
|
|
403
|
+
const toolCallRepair = (modelManager, terminal) => {
|
|
404
|
+
const fn = async ({ toolCall, tools, inputSchema, error, }) => {
|
|
405
|
+
if (NoSuchToolError.isInstance(error)) {
|
|
406
|
+
return null; // do not attempt to fix invalid tool names
|
|
407
|
+
}
|
|
408
|
+
terminal.warn(`Attempting to repair tool call: ${toolCall.toolName}.`);
|
|
409
|
+
terminal.lineBreak();
|
|
410
|
+
const tool = tools[toolCall.toolName];
|
|
411
|
+
try {
|
|
412
|
+
const { object: repairedArgs } = await generateObject({
|
|
413
|
+
model: modelManager.getModel("tool-repair"),
|
|
414
|
+
schema: tool.inputSchema,
|
|
415
|
+
prompt: [
|
|
416
|
+
`The model tried to call the tool "${toolCall.toolName}" with the following arguments:`,
|
|
417
|
+
JSON.stringify(toolCall.input),
|
|
418
|
+
"The tool accepts the following schema:",
|
|
419
|
+
JSON.stringify(inputSchema(toolCall)),
|
|
420
|
+
"Please fix the arguments.",
|
|
421
|
+
].join("\n"),
|
|
422
|
+
});
|
|
423
|
+
return { ...toolCall, args: JSON.stringify(repairedArgs) };
|
|
424
|
+
}
|
|
425
|
+
catch (err) {
|
|
426
|
+
logger.error(err, `Failed to repair tool call: ${toolCall.toolName}.`);
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
return fn;
|
|
431
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Formatting Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides functions for formatting and displaying text in the terminal.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Clear the terminal screen
|
|
8
|
+
*/
|
|
9
|
+
export declare function clearScreen(): void;
|
|
10
|
+
/**
|
|
11
|
+
* Clear the terminal screen including scrollback buffer
|
|
12
|
+
*
|
|
13
|
+
* Unlike clearScreen, this function:
|
|
14
|
+
* 1. Clears the entire screen (\x1b[2J)
|
|
15
|
+
* 2. Clears the scrollback buffer (\x1b[3J)
|
|
16
|
+
* 3. Moves cursor to home position (\x1b[H)
|
|
17
|
+
* 4. Returns a Promise that resolves when the write operation completes
|
|
18
|
+
*
|
|
19
|
+
* @returns Promise that resolves when the terminal has been cleared
|
|
20
|
+
*/
|
|
21
|
+
export declare function clearTerminal(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Sets the terminal title
|
|
24
|
+
*/
|
|
25
|
+
export declare function setTerminalTitle(title: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* Get the terminal size (rows and columns)
|
|
28
|
+
*/
|
|
29
|
+
export declare function getTerminalSize(): {
|
|
30
|
+
rows: number;
|
|
31
|
+
columns: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Word wrap text to the specified width
|
|
35
|
+
*/
|
|
36
|
+
export declare function wordWrap(text: string, width: number): string;
|
|
37
|
+
export declare const link: (text: string, url: string) => string;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Formatting Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides functions for formatting and displaying text in the terminal.
|
|
5
|
+
*/
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
/**
|
|
8
|
+
* Clear the terminal screen
|
|
9
|
+
*/
|
|
10
|
+
export function clearScreen() {
|
|
11
|
+
// Clear screen and move cursor to top-left
|
|
12
|
+
process.stdout.write("\x1b[2J\x1b[0f");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Clear the terminal screen including scrollback buffer
|
|
16
|
+
*
|
|
17
|
+
* Unlike clearScreen, this function:
|
|
18
|
+
* 1. Clears the entire screen (\x1b[2J)
|
|
19
|
+
* 2. Clears the scrollback buffer (\x1b[3J)
|
|
20
|
+
* 3. Moves cursor to home position (\x1b[H)
|
|
21
|
+
* 4. Returns a Promise that resolves when the write operation completes
|
|
22
|
+
*
|
|
23
|
+
* @returns Promise that resolves when the terminal has been cleared
|
|
24
|
+
*/
|
|
25
|
+
export function clearTerminal() {
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
process.stdout.write("\x1b[2J\x1b[3J\x1b[H", () => {
|
|
28
|
+
resolve();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Sets the terminal title
|
|
34
|
+
*/
|
|
35
|
+
export function setTerminalTitle(title) {
|
|
36
|
+
if (process.platform === "win32") {
|
|
37
|
+
process.title = title ? `✳✳ ${title}` : title;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
process.stdout.write(`\x1b]0;${title ? `✳✳ ${title}` : ""}\x07`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the terminal size (rows and columns)
|
|
45
|
+
*/
|
|
46
|
+
export function getTerminalSize() {
|
|
47
|
+
// Default to a reasonable size if we can't determine the actual size
|
|
48
|
+
const defaultSize = { rows: 24, columns: 80 };
|
|
49
|
+
try {
|
|
50
|
+
if (process.stdout.isTTY) {
|
|
51
|
+
return {
|
|
52
|
+
rows: process.stdout.rows || defaultSize.rows,
|
|
53
|
+
columns: process.stdout.columns || defaultSize.columns,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (_error) {
|
|
58
|
+
// Ignore errors
|
|
59
|
+
}
|
|
60
|
+
return defaultSize;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Word wrap text to the specified width
|
|
64
|
+
*/
|
|
65
|
+
export function wordWrap(text, width) {
|
|
66
|
+
const lines = text.split("\n");
|
|
67
|
+
return lines.map((line) => wrapLine(line, width)).join("\n");
|
|
68
|
+
}
|
|
69
|
+
function wrapLine(line, width) {
|
|
70
|
+
// If the line is a code block or already shorter than the width, leave it as is
|
|
71
|
+
if (line.trim().startsWith("┃") || line.length <= width) {
|
|
72
|
+
return line;
|
|
73
|
+
}
|
|
74
|
+
// Word wrap the line
|
|
75
|
+
const words = line.split(" ");
|
|
76
|
+
const wrappedLines = [];
|
|
77
|
+
let currentLine = "";
|
|
78
|
+
for (const word of words) {
|
|
79
|
+
// If adding this word would exceed the width
|
|
80
|
+
if (currentLine.length + word.length + 1 > width) {
|
|
81
|
+
// Add the current line to wrapped lines if it's not empty
|
|
82
|
+
if (currentLine) {
|
|
83
|
+
wrappedLines.push(currentLine);
|
|
84
|
+
currentLine = word;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// If the current line is empty, it means the word itself is longer than the width
|
|
88
|
+
wrappedLines.push(word);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Add the word to the current line
|
|
93
|
+
currentLine = currentLine ? `${currentLine} ${word}` : word;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Add the last line if it's not empty
|
|
97
|
+
if (currentLine) {
|
|
98
|
+
wrappedLines.push(currentLine);
|
|
99
|
+
}
|
|
100
|
+
return wrappedLines.join("\n");
|
|
101
|
+
}
|
|
102
|
+
// const ESC = "\u001B[";
|
|
103
|
+
const OSC = "\u001B]";
|
|
104
|
+
const BEL = "\u0007";
|
|
105
|
+
const SEP = ";";
|
|
106
|
+
export const link = (text, url) => chalk.underline.blue([OSC, "8", SEP, SEP, url, BEL, text, OSC, "8", SEP, SEP, BEL].join(""));
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Interface Module
|
|
3
|
+
*
|
|
4
|
+
* Provides a user interface for interacting with Claude Code in the terminal.
|
|
5
|
+
* Handles input/output, formatting, and display.
|
|
6
|
+
*/
|
|
7
|
+
import { type ChalkInstance } from "chalk";
|
|
8
|
+
import type { SpinnerInstance, TerminalConfig } from "./types.ts";
|
|
9
|
+
/**
|
|
10
|
+
* Initialize the terminal interface
|
|
11
|
+
*/
|
|
12
|
+
export declare function initTerminal(config?: Partial<TerminalConfig>): Terminal;
|
|
13
|
+
/**
|
|
14
|
+
* Terminal class for handling user interaction
|
|
15
|
+
*/
|
|
16
|
+
export declare class Terminal {
|
|
17
|
+
private config;
|
|
18
|
+
private activeSpinners;
|
|
19
|
+
private terminalWidth;
|
|
20
|
+
private terminalHeight;
|
|
21
|
+
private isInteractive;
|
|
22
|
+
constructor(config: TerminalConfig);
|
|
23
|
+
/**
|
|
24
|
+
* Detect terminal capabilities
|
|
25
|
+
*/
|
|
26
|
+
detectCapabilities(): void;
|
|
27
|
+
setTitle(title: string): void;
|
|
28
|
+
getLogo(): string;
|
|
29
|
+
/**
|
|
30
|
+
* Display the welcome message
|
|
31
|
+
*/
|
|
32
|
+
displayWelcome(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Clear the terminal screen
|
|
35
|
+
*/
|
|
36
|
+
clear(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Display formatted content
|
|
39
|
+
*/
|
|
40
|
+
display(content: string, wrap?: boolean): void;
|
|
41
|
+
/**
|
|
42
|
+
* Display a message with emphasis
|
|
43
|
+
*/
|
|
44
|
+
emphasize(message: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Display an informational message
|
|
47
|
+
*/
|
|
48
|
+
info(message: string): void;
|
|
49
|
+
/**
|
|
50
|
+
* Display a success message
|
|
51
|
+
*/
|
|
52
|
+
success(message: string): void;
|
|
53
|
+
/**
|
|
54
|
+
* Display a warning message
|
|
55
|
+
*/
|
|
56
|
+
warn(message: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Display an error message
|
|
59
|
+
*/
|
|
60
|
+
error(message: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Emits an alert.
|
|
63
|
+
*/
|
|
64
|
+
alert(): void;
|
|
65
|
+
write(input: string): void;
|
|
66
|
+
writeln(input: string): void;
|
|
67
|
+
lineBreak(): void;
|
|
68
|
+
header(header: string, chalkFn?: ChalkInstance): void;
|
|
69
|
+
box(header: string, content: string): Promise<void>;
|
|
70
|
+
hr(chalkFn?: ChalkInstance): void;
|
|
71
|
+
/**
|
|
72
|
+
* Create a clickable link in the terminal if supported
|
|
73
|
+
*/
|
|
74
|
+
link(text: string, url: string): string;
|
|
75
|
+
/**
|
|
76
|
+
* Display a table of data
|
|
77
|
+
*/
|
|
78
|
+
table(data: [string, string | number][], options?: {
|
|
79
|
+
header?: string[];
|
|
80
|
+
colWidths?: number[];
|
|
81
|
+
}): void;
|
|
82
|
+
/**
|
|
83
|
+
* Create a spinner for showing progress
|
|
84
|
+
*/
|
|
85
|
+
spinner(text: string, id?: string): SpinnerInstance;
|
|
86
|
+
/**
|
|
87
|
+
* Displays a horizontal progress bar in the console.
|
|
88
|
+
* @param current The current value.
|
|
89
|
+
* @param total The target value.
|
|
90
|
+
*/
|
|
91
|
+
displayProgressBar(current: number, total: number): void;
|
|
92
|
+
private formatMarkdown;
|
|
93
|
+
}
|
|
94
|
+
export * from "./types.ts";
|