@gguf/coder 0.3.0 → 0.3.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/.editorconfig +16 -0
- package/.env.example +63 -0
- package/.gitattributes +1 -0
- package/.semgrepignore +19 -0
- package/coder-dummy-file.ts +52 -0
- package/coder.config.example.json +59 -0
- package/coder.config.json +13 -0
- package/color_picker.html +36 -0
- package/package.json +2 -14
- package/scripts/extract-changelog.js +73 -0
- package/scripts/fetch-models.js +143 -0
- package/scripts/test.sh +40 -0
- package/scripts/update-homebrew-formula.sh +125 -0
- package/scripts/update-nix-version.sh +157 -0
- package/source/ai-sdk-client/AISDKClient.spec.ts +117 -0
- package/source/ai-sdk-client/AISDKClient.ts +155 -0
- package/source/ai-sdk-client/chat/chat-handler.spec.ts +121 -0
- package/source/ai-sdk-client/chat/chat-handler.ts +276 -0
- package/source/ai-sdk-client/chat/streaming-handler.spec.ts +173 -0
- package/source/ai-sdk-client/chat/streaming-handler.ts +110 -0
- package/source/ai-sdk-client/chat/tool-processor.spec.ts +92 -0
- package/source/ai-sdk-client/chat/tool-processor.ts +70 -0
- package/source/ai-sdk-client/converters/message-converter.spec.ts +220 -0
- package/source/ai-sdk-client/converters/message-converter.ts +113 -0
- package/source/ai-sdk-client/converters/tool-converter.spec.ts +90 -0
- package/source/ai-sdk-client/converters/tool-converter.ts +46 -0
- package/source/ai-sdk-client/error-handling/error-extractor.spec.ts +55 -0
- package/source/ai-sdk-client/error-handling/error-extractor.ts +15 -0
- package/source/ai-sdk-client/error-handling/error-parser.spec.ts +169 -0
- package/source/ai-sdk-client/error-handling/error-parser.ts +161 -0
- package/source/ai-sdk-client/index.ts +7 -0
- package/source/ai-sdk-client/providers/provider-factory.spec.ts +71 -0
- package/source/ai-sdk-client/providers/provider-factory.ts +41 -0
- package/source/ai-sdk-client/types.ts +9 -0
- package/source/ai-sdk-client-empty-message.spec.ts +141 -0
- package/source/ai-sdk-client-error-handling.spec.ts +186 -0
- package/source/ai-sdk-client-maxretries.spec.ts +114 -0
- package/source/ai-sdk-client-preparestep.spec.ts +279 -0
- package/source/app/App.spec.tsx +32 -0
- package/source/app/App.tsx +480 -0
- package/source/app/components/AppContainer.spec.tsx +96 -0
- package/source/app/components/AppContainer.tsx +56 -0
- package/source/app/components/ChatInterface.spec.tsx +163 -0
- package/source/app/components/ChatInterface.tsx +144 -0
- package/source/app/components/ModalSelectors.spec.tsx +141 -0
- package/source/app/components/ModalSelectors.tsx +135 -0
- package/source/app/helpers.spec.ts +97 -0
- package/source/app/helpers.ts +63 -0
- package/source/app/index.ts +4 -0
- package/source/app/types.ts +39 -0
- package/source/app/utils/appUtils.ts +294 -0
- package/source/app/utils/conversationState.ts +310 -0
- package/source/app.spec.tsx +244 -0
- package/source/cli.spec.ts +73 -0
- package/source/cli.tsx +51 -0
- package/source/client-factory.spec.ts +48 -0
- package/source/client-factory.ts +178 -0
- package/source/command-parser.spec.ts +127 -0
- package/source/command-parser.ts +36 -0
- package/source/commands/checkpoint.spec.tsx +277 -0
- package/source/commands/checkpoint.tsx +366 -0
- package/source/commands/clear.tsx +22 -0
- package/source/commands/custom-commands.tsx +121 -0
- package/source/commands/exit.ts +21 -0
- package/source/commands/export.spec.tsx +131 -0
- package/source/commands/export.tsx +79 -0
- package/source/commands/help.tsx +120 -0
- package/source/commands/index.ts +17 -0
- package/source/commands/init.tsx +339 -0
- package/source/commands/lsp-command.spec.tsx +281 -0
- package/source/commands/lsp.tsx +120 -0
- package/source/commands/mcp-command.spec.tsx +313 -0
- package/source/commands/mcp.tsx +162 -0
- package/source/commands/model-database.spec.tsx +758 -0
- package/source/commands/model-database.tsx +418 -0
- package/source/commands/model.ts +12 -0
- package/source/commands/provider.ts +12 -0
- package/source/commands/setup-config.tsx +16 -0
- package/source/commands/simple-commands.spec.tsx +175 -0
- package/source/commands/status.ts +12 -0
- package/source/commands/theme.ts +12 -0
- package/source/commands/update.spec.tsx +261 -0
- package/source/commands/update.tsx +201 -0
- package/source/commands/usage.spec.tsx +495 -0
- package/source/commands/usage.tsx +100 -0
- package/source/commands.spec.ts +436 -0
- package/source/commands.ts +83 -0
- package/source/components/assistant-message.spec.tsx +796 -0
- package/source/components/assistant-message.tsx +34 -0
- package/source/components/bash-execution-indicator.tsx +21 -0
- package/source/components/cancelling-indicator.tsx +16 -0
- package/source/components/chat-queue.spec.tsx +83 -0
- package/source/components/chat-queue.tsx +36 -0
- package/source/components/checkpoint-display.spec.tsx +219 -0
- package/source/components/checkpoint-display.tsx +126 -0
- package/source/components/checkpoint-selector.spec.tsx +173 -0
- package/source/components/checkpoint-selector.tsx +173 -0
- package/source/components/development-mode-indicator.spec.tsx +268 -0
- package/source/components/development-mode-indicator.tsx +38 -0
- package/source/components/message-box.spec.tsx +427 -0
- package/source/components/message-box.tsx +87 -0
- package/source/components/model-selector.tsx +132 -0
- package/source/components/provider-selector.tsx +75 -0
- package/source/components/random-spinner.tsx +19 -0
- package/source/components/security-disclaimer.tsx +73 -0
- package/source/components/status-connection-display.spec.tsx +133 -0
- package/source/components/status.tsx +267 -0
- package/source/components/theme-selector.tsx +126 -0
- package/source/components/tool-confirmation.tsx +190 -0
- package/source/components/tool-execution-indicator.tsx +33 -0
- package/source/components/tool-message.tsx +85 -0
- package/source/components/ui/titled-box.spec.tsx +207 -0
- package/source/components/ui/titled-box.tsx +57 -0
- package/source/components/usage/progress-bar.spec.tsx +398 -0
- package/source/components/usage/progress-bar.tsx +30 -0
- package/source/components/usage/usage-display.spec.tsx +780 -0
- package/source/components/usage/usage-display.tsx +291 -0
- package/source/components/user-input.spec.tsx +327 -0
- package/source/components/user-input.tsx +533 -0
- package/source/components/user-message.spec.tsx +230 -0
- package/source/components/user-message.tsx +84 -0
- package/source/components/welcome-message.tsx +76 -0
- package/source/config/env-substitution.ts +65 -0
- package/source/config/index.spec.ts +171 -0
- package/source/config/index.ts +154 -0
- package/source/config/paths.spec.ts +241 -0
- package/source/config/paths.ts +55 -0
- package/source/config/preferences.ts +51 -0
- package/source/config/themes.ts +315 -0
- package/source/constants.ts +130 -0
- package/source/context/mode-context.spec.ts +79 -0
- package/source/context/mode-context.ts +24 -0
- package/source/custom-commands/executor.spec.ts +142 -0
- package/source/custom-commands/executor.ts +64 -0
- package/source/custom-commands/loader.spec.ts +314 -0
- package/source/custom-commands/loader.ts +153 -0
- package/source/custom-commands/parser.ts +196 -0
- package/source/hooks/chat-handler/conversation/conversation-loop.spec.ts +39 -0
- package/source/hooks/chat-handler/conversation/conversation-loop.tsx +511 -0
- package/source/hooks/chat-handler/conversation/tool-executor.spec.ts +50 -0
- package/source/hooks/chat-handler/conversation/tool-executor.tsx +109 -0
- package/source/hooks/chat-handler/index.ts +12 -0
- package/source/hooks/chat-handler/state/streaming-state.spec.ts +26 -0
- package/source/hooks/chat-handler/state/streaming-state.ts +19 -0
- package/source/hooks/chat-handler/types.ts +38 -0
- package/source/hooks/chat-handler/useChatHandler.spec.tsx +321 -0
- package/source/hooks/chat-handler/useChatHandler.tsx +194 -0
- package/source/hooks/chat-handler/utils/context-checker.spec.ts +60 -0
- package/source/hooks/chat-handler/utils/context-checker.tsx +73 -0
- package/source/hooks/chat-handler/utils/message-helpers.spec.ts +42 -0
- package/source/hooks/chat-handler/utils/message-helpers.tsx +36 -0
- package/source/hooks/chat-handler/utils/tool-filters.spec.ts +109 -0
- package/source/hooks/chat-handler/utils/tool-filters.ts +64 -0
- package/source/hooks/useAppHandlers.tsx +291 -0
- package/source/hooks/useAppInitialization.tsx +422 -0
- package/source/hooks/useAppState.tsx +311 -0
- package/source/hooks/useDirectoryTrust.tsx +98 -0
- package/source/hooks/useInputState.ts +414 -0
- package/source/hooks/useModeHandlers.tsx +302 -0
- package/source/hooks/useNonInteractiveMode.ts +140 -0
- package/source/hooks/useTerminalWidth.tsx +81 -0
- package/source/hooks/useTheme.ts +18 -0
- package/source/hooks/useToolHandler.tsx +349 -0
- package/source/hooks/useUIState.ts +61 -0
- package/source/init/agents-template-generator.ts +421 -0
- package/source/init/existing-rules-extractor.ts +319 -0
- package/source/init/file-scanner.spec.ts +227 -0
- package/source/init/file-scanner.ts +238 -0
- package/source/init/framework-detector.ts +382 -0
- package/source/init/language-detector.ts +269 -0
- package/source/init/project-analyzer.spec.ts +231 -0
- package/source/init/project-analyzer.ts +458 -0
- package/source/lsp/index.ts +31 -0
- package/source/lsp/lsp-client.spec.ts +508 -0
- package/source/lsp/lsp-client.ts +487 -0
- package/source/lsp/lsp-manager.spec.ts +477 -0
- package/source/lsp/lsp-manager.ts +419 -0
- package/source/lsp/protocol.spec.ts +502 -0
- package/source/lsp/protocol.ts +360 -0
- package/source/lsp/server-discovery.spec.ts +654 -0
- package/source/lsp/server-discovery.ts +515 -0
- package/source/markdown-parser/html-entities.spec.ts +88 -0
- package/source/markdown-parser/html-entities.ts +45 -0
- package/source/markdown-parser/index.spec.ts +281 -0
- package/source/markdown-parser/index.ts +126 -0
- package/source/markdown-parser/table-parser.spec.ts +133 -0
- package/source/markdown-parser/table-parser.ts +114 -0
- package/source/markdown-parser/utils.spec.ts +70 -0
- package/source/markdown-parser/utils.ts +13 -0
- package/source/mcp/mcp-client.spec.ts +81 -0
- package/source/mcp/mcp-client.ts +625 -0
- package/source/mcp/transport-factory.spec.ts +406 -0
- package/source/mcp/transport-factory.ts +312 -0
- package/source/message-handler.ts +67 -0
- package/source/model-database/database-engine.spec.ts +494 -0
- package/source/model-database/database-engine.ts +50 -0
- package/source/model-database/model-database.spec.ts +363 -0
- package/source/model-database/model-database.ts +91 -0
- package/source/model-database/model-engine.spec.ts +447 -0
- package/source/model-database/model-engine.ts +65 -0
- package/source/model-database/model-fetcher.spec.ts +583 -0
- package/source/model-database/model-fetcher.ts +330 -0
- package/source/models/index.ts +1 -0
- package/source/models/models-cache.spec.ts +214 -0
- package/source/models/models-cache.ts +78 -0
- package/source/models/models-dev-client.spec.ts +379 -0
- package/source/models/models-dev-client.ts +329 -0
- package/source/models/models-types.ts +68 -0
- package/source/prompt-history.ts +155 -0
- package/source/security/command-injection.spec.ts +240 -0
- package/source/services/checkpoint-manager.spec.ts +523 -0
- package/source/services/checkpoint-manager.ts +466 -0
- package/source/services/file-snapshot.spec.ts +569 -0
- package/source/services/file-snapshot.ts +220 -0
- package/source/test-utils/render-with-theme.tsx +48 -0
- package/source/tokenization/index.ts +1 -0
- package/source/tokenization/tokenizer-factory.spec.ts +170 -0
- package/source/tokenization/tokenizer-factory.ts +125 -0
- package/source/tokenization/tokenizers/anthropic-tokenizer.spec.ts +200 -0
- package/source/tokenization/tokenizers/anthropic-tokenizer.ts +43 -0
- package/source/tokenization/tokenizers/fallback-tokenizer.spec.ts +236 -0
- package/source/tokenization/tokenizers/fallback-tokenizer.ts +26 -0
- package/source/tokenization/tokenizers/llama-tokenizer.spec.ts +224 -0
- package/source/tokenization/tokenizers/llama-tokenizer.ts +41 -0
- package/source/tokenization/tokenizers/openai-tokenizer.spec.ts +184 -0
- package/source/tokenization/tokenizers/openai-tokenizer.ts +57 -0
- package/source/tool-calling/index.ts +5 -0
- package/source/tool-calling/json-parser.spec.ts +639 -0
- package/source/tool-calling/json-parser.ts +247 -0
- package/source/tool-calling/tool-parser.spec.ts +395 -0
- package/source/tool-calling/tool-parser.ts +120 -0
- package/source/tool-calling/xml-parser.spec.ts +662 -0
- package/source/tool-calling/xml-parser.ts +289 -0
- package/source/tools/execute-bash.spec.tsx +353 -0
- package/source/tools/execute-bash.tsx +219 -0
- package/source/tools/execute-function.spec.ts +130 -0
- package/source/tools/fetch-url.spec.tsx +342 -0
- package/source/tools/fetch-url.tsx +172 -0
- package/source/tools/find-files.spec.tsx +924 -0
- package/source/tools/find-files.tsx +293 -0
- package/source/tools/index.ts +102 -0
- package/source/tools/lsp-get-diagnostics.tsx +192 -0
- package/source/tools/needs-approval.spec.ts +282 -0
- package/source/tools/read-file.spec.tsx +801 -0
- package/source/tools/read-file.tsx +387 -0
- package/source/tools/search-file-contents.spec.tsx +1273 -0
- package/source/tools/search-file-contents.tsx +293 -0
- package/source/tools/string-replace.spec.tsx +730 -0
- package/source/tools/string-replace.tsx +548 -0
- package/source/tools/tool-manager.ts +210 -0
- package/source/tools/tool-registry.spec.ts +415 -0
- package/source/tools/tool-registry.ts +228 -0
- package/source/tools/web-search.tsx +223 -0
- package/source/tools/write-file.spec.tsx +559 -0
- package/source/tools/write-file.tsx +228 -0
- package/source/types/app.ts +37 -0
- package/source/types/checkpoint.ts +48 -0
- package/source/types/commands.ts +46 -0
- package/source/types/components.ts +27 -0
- package/source/types/config.ts +103 -0
- package/source/types/core-connection-status.spec.ts +67 -0
- package/source/types/core.ts +181 -0
- package/source/types/hooks.ts +50 -0
- package/source/types/index.ts +12 -0
- package/source/types/markdown-parser.ts +11 -0
- package/source/types/mcp.ts +52 -0
- package/source/types/system.ts +16 -0
- package/source/types/tokenization.ts +41 -0
- package/source/types/ui.ts +40 -0
- package/source/types/usage.ts +58 -0
- package/source/types/utils.ts +16 -0
- package/source/usage/calculator.spec.ts +385 -0
- package/source/usage/calculator.ts +104 -0
- package/source/usage/storage.spec.ts +703 -0
- package/source/usage/storage.ts +238 -0
- package/source/usage/tracker.spec.ts +456 -0
- package/source/usage/tracker.ts +102 -0
- package/source/utils/atomic-deletion.spec.ts +194 -0
- package/source/utils/atomic-deletion.ts +127 -0
- package/source/utils/bounded-map.spec.ts +300 -0
- package/source/utils/bounded-map.ts +193 -0
- package/source/utils/checkpoint-utils.spec.ts +222 -0
- package/source/utils/checkpoint-utils.ts +92 -0
- package/source/utils/error-formatter.spec.ts +169 -0
- package/source/utils/error-formatter.ts +194 -0
- package/source/utils/file-autocomplete.spec.ts +173 -0
- package/source/utils/file-autocomplete.ts +196 -0
- package/source/utils/file-cache.spec.ts +309 -0
- package/source/utils/file-cache.ts +195 -0
- package/source/utils/file-content-loader.spec.ts +180 -0
- package/source/utils/file-content-loader.ts +179 -0
- package/source/utils/file-mention-handler.spec.ts +261 -0
- package/source/utils/file-mention-handler.ts +84 -0
- package/source/utils/file-mention-parser.spec.ts +182 -0
- package/source/utils/file-mention-parser.ts +170 -0
- package/source/utils/fuzzy-matching.spec.ts +149 -0
- package/source/utils/fuzzy-matching.ts +146 -0
- package/source/utils/indentation-normalizer.spec.ts +216 -0
- package/source/utils/indentation-normalizer.ts +76 -0
- package/source/utils/installation-detector.spec.ts +178 -0
- package/source/utils/installation-detector.ts +153 -0
- package/source/utils/logging/config.spec.ts +311 -0
- package/source/utils/logging/config.ts +210 -0
- package/source/utils/logging/console-facade.spec.ts +184 -0
- package/source/utils/logging/console-facade.ts +384 -0
- package/source/utils/logging/correlation.spec.ts +679 -0
- package/source/utils/logging/correlation.ts +474 -0
- package/source/utils/logging/formatters.spec.ts +464 -0
- package/source/utils/logging/formatters.ts +207 -0
- package/source/utils/logging/health-monitor/alerts/alert-manager.spec.ts +93 -0
- package/source/utils/logging/health-monitor/alerts/alert-manager.ts +79 -0
- package/source/utils/logging/health-monitor/checks/configuration-check.spec.ts +56 -0
- package/source/utils/logging/health-monitor/checks/configuration-check.ts +43 -0
- package/source/utils/logging/health-monitor/checks/logging-check.spec.ts +56 -0
- package/source/utils/logging/health-monitor/checks/logging-check.ts +58 -0
- package/source/utils/logging/health-monitor/checks/memory-check.spec.ts +100 -0
- package/source/utils/logging/health-monitor/checks/memory-check.ts +78 -0
- package/source/utils/logging/health-monitor/checks/performance-check.spec.ts +56 -0
- package/source/utils/logging/health-monitor/checks/performance-check.ts +56 -0
- package/source/utils/logging/health-monitor/checks/request-check.spec.ts +56 -0
- package/source/utils/logging/health-monitor/checks/request-check.ts +76 -0
- package/source/utils/logging/health-monitor/core/health-check-runner.spec.ts +70 -0
- package/source/utils/logging/health-monitor/core/health-check-runner.ts +138 -0
- package/source/utils/logging/health-monitor/core/health-monitor.spec.ts +58 -0
- package/source/utils/logging/health-monitor/core/health-monitor.ts +344 -0
- package/source/utils/logging/health-monitor/core/scoring.spec.ts +65 -0
- package/source/utils/logging/health-monitor/core/scoring.ts +91 -0
- package/source/utils/logging/health-monitor/index.ts +15 -0
- package/source/utils/logging/health-monitor/instances.ts +48 -0
- package/source/utils/logging/health-monitor/middleware/http-middleware.spec.ts +141 -0
- package/source/utils/logging/health-monitor/middleware/http-middleware.ts +75 -0
- package/source/utils/logging/health-monitor/types.ts +126 -0
- package/source/utils/logging/index.spec.ts +284 -0
- package/source/utils/logging/index.ts +236 -0
- package/source/utils/logging/integration.spec.ts +441 -0
- package/source/utils/logging/log-method-factory.spec.ts +573 -0
- package/source/utils/logging/log-method-factory.ts +233 -0
- package/source/utils/logging/log-query/aggregation/aggregator.spec.ts +277 -0
- package/source/utils/logging/log-query/aggregation/aggregator.ts +159 -0
- package/source/utils/logging/log-query/aggregation/facet-generator.spec.ts +159 -0
- package/source/utils/logging/log-query/aggregation/facet-generator.ts +47 -0
- package/source/utils/logging/log-query/index.ts +23 -0
- package/source/utils/logging/log-query/query/filter-predicates.spec.ts +247 -0
- package/source/utils/logging/log-query/query/filter-predicates.ts +154 -0
- package/source/utils/logging/log-query/query/query-builder.spec.ts +182 -0
- package/source/utils/logging/log-query/query/query-builder.ts +151 -0
- package/source/utils/logging/log-query/query/query-engine.spec.ts +214 -0
- package/source/utils/logging/log-query/query/query-engine.ts +45 -0
- package/source/utils/logging/log-query/storage/circular-buffer.spec.ts +143 -0
- package/source/utils/logging/log-query/storage/circular-buffer.ts +75 -0
- package/source/utils/logging/log-query/storage/index-manager.spec.ts +150 -0
- package/source/utils/logging/log-query/storage/index-manager.ts +71 -0
- package/source/utils/logging/log-query/storage/log-storage.spec.ts +257 -0
- package/source/utils/logging/log-query/storage/log-storage.ts +80 -0
- package/source/utils/logging/log-query/types.ts +163 -0
- package/source/utils/logging/log-query/utils/helpers.spec.ts +263 -0
- package/source/utils/logging/log-query/utils/helpers.ts +72 -0
- package/source/utils/logging/log-query/utils/sorting.spec.ts +182 -0
- package/source/utils/logging/log-query/utils/sorting.ts +61 -0
- package/source/utils/logging/logger-provider.spec.ts +262 -0
- package/source/utils/logging/logger-provider.ts +362 -0
- package/source/utils/logging/performance.spec.ts +209 -0
- package/source/utils/logging/performance.ts +757 -0
- package/source/utils/logging/pino-logger.spec.ts +425 -0
- package/source/utils/logging/pino-logger.ts +514 -0
- package/source/utils/logging/redaction.spec.ts +490 -0
- package/source/utils/logging/redaction.ts +267 -0
- package/source/utils/logging/request-tracker.spec.ts +1198 -0
- package/source/utils/logging/request-tracker.ts +803 -0
- package/source/utils/logging/transports.spec.ts +505 -0
- package/source/utils/logging/transports.ts +305 -0
- package/source/utils/logging/types.ts +216 -0
- package/source/utils/message-builder.spec.ts +179 -0
- package/source/utils/message-builder.ts +101 -0
- package/source/utils/message-queue.tsx +486 -0
- package/source/utils/paste-detection.spec.ts +69 -0
- package/source/utils/paste-detection.ts +124 -0
- package/source/utils/paste-roundtrip.spec.ts +442 -0
- package/source/utils/paste-utils.spec.ts +128 -0
- package/source/utils/paste-utils.ts +52 -0
- package/source/utils/programming-language-helper.spec.ts +74 -0
- package/source/utils/programming-language-helper.ts +32 -0
- package/source/utils/prompt-assembly.spec.ts +221 -0
- package/source/utils/prompt-processor.ts +173 -0
- package/source/utils/tool-args-parser.spec.ts +136 -0
- package/source/utils/tool-args-parser.ts +54 -0
- package/source/utils/tool-cancellation.spec.ts +230 -0
- package/source/utils/tool-cancellation.ts +28 -0
- package/source/utils/tool-result-display.spec.tsx +469 -0
- package/source/utils/tool-result-display.tsx +90 -0
- package/source/utils/update-checker.spec.ts +383 -0
- package/source/utils/update-checker.ts +183 -0
- package/source/wizard/config-wizard.spec.tsx +103 -0
- package/source/wizard/config-wizard.tsx +382 -0
- package/source/wizard/steps/location-step.spec.tsx +186 -0
- package/source/wizard/steps/location-step.tsx +147 -0
- package/source/wizard/steps/mcp-step.spec.tsx +607 -0
- package/source/wizard/steps/mcp-step.tsx +632 -0
- package/source/wizard/steps/provider-step.spec.tsx +342 -0
- package/source/wizard/steps/provider-step.tsx +957 -0
- package/source/wizard/steps/summary-step.spec.tsx +749 -0
- package/source/wizard/steps/summary-step.tsx +228 -0
- package/source/wizard/templates/mcp-templates.spec.ts +613 -0
- package/source/wizard/templates/mcp-templates.ts +570 -0
- package/source/wizard/templates/provider-templates.spec.ts +152 -0
- package/source/wizard/templates/provider-templates.ts +485 -0
- package/source/wizard/utils/fetch-cloud-models.spec.ts +428 -0
- package/source/wizard/utils/fetch-cloud-models.ts +223 -0
- package/source/wizard/utils/fetch-local-models.spec.ts +297 -0
- package/source/wizard/utils/fetch-local-models.ts +192 -0
- package/source/wizard/validation-array.spec.ts +264 -0
- package/source/wizard/validation.spec.ts +373 -0
- package/source/wizard/validation.ts +232 -0
- package/source/app/prompts/main-prompt.md +0 -122
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import {render} from 'ink-testing-library';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import {themes} from '../config/themes';
|
|
5
|
+
import {ThemeContext} from '../hooks/useTheme';
|
|
6
|
+
import UserMessage from './user-message';
|
|
7
|
+
|
|
8
|
+
console.log(`\nuser-message.spec.tsx – ${React.version}`);
|
|
9
|
+
|
|
10
|
+
// Mock ThemeProvider for testing
|
|
11
|
+
const MockThemeProvider = ({children}: {children: React.ReactNode}) => {
|
|
12
|
+
const mockTheme = {
|
|
13
|
+
currentTheme: 'tokyo-night' as const,
|
|
14
|
+
colors: themes['tokyo-night'].colors,
|
|
15
|
+
setCurrentTheme: () => {},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<ThemeContext.Provider value={mockTheme}>{children}</ThemeContext.Provider>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Component Rendering Tests
|
|
25
|
+
// ============================================================================
|
|
26
|
+
|
|
27
|
+
test('UserMessage renders with basic message', t => {
|
|
28
|
+
const {lastFrame} = render(
|
|
29
|
+
<MockThemeProvider>
|
|
30
|
+
<UserMessage message="Hello world" />
|
|
31
|
+
</MockThemeProvider>,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const output = lastFrame();
|
|
35
|
+
t.truthy(output);
|
|
36
|
+
t.regex(output!, /You:/);
|
|
37
|
+
t.regex(output!, /Hello world/);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('UserMessage renders without file placeholders', t => {
|
|
41
|
+
const {lastFrame} = render(
|
|
42
|
+
<MockThemeProvider>
|
|
43
|
+
<UserMessage message="This is a normal message" />
|
|
44
|
+
</MockThemeProvider>,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const output = lastFrame();
|
|
48
|
+
t.truthy(output);
|
|
49
|
+
t.regex(output!, /This is a normal message/);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('UserMessage renders with file placeholder', t => {
|
|
53
|
+
const {lastFrame} = render(
|
|
54
|
+
<MockThemeProvider>
|
|
55
|
+
<UserMessage message="Check [@src/app.tsx] for details" />
|
|
56
|
+
</MockThemeProvider>,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const output = lastFrame();
|
|
60
|
+
t.truthy(output);
|
|
61
|
+
t.regex(output!, /\[@src\/app\.tsx\]/);
|
|
62
|
+
t.regex(output!, /Check/);
|
|
63
|
+
t.regex(output!, /for details/);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('UserMessage renders with file placeholder with line range', t => {
|
|
67
|
+
const {lastFrame} = render(
|
|
68
|
+
<MockThemeProvider>
|
|
69
|
+
<UserMessage message="Look at [@file.ts:10-20] please" />
|
|
70
|
+
</MockThemeProvider>,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const output = lastFrame();
|
|
74
|
+
t.truthy(output);
|
|
75
|
+
t.regex(output!, /\[@file\.ts:10-20\]/);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('UserMessage renders with file placeholder with single line', t => {
|
|
79
|
+
const {lastFrame} = render(
|
|
80
|
+
<MockThemeProvider>
|
|
81
|
+
<UserMessage message="Check [@utils.ts:42] specifically" />
|
|
82
|
+
</MockThemeProvider>,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const output = lastFrame();
|
|
86
|
+
t.truthy(output);
|
|
87
|
+
t.regex(output!, /\[@utils\.ts:42\]/);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('UserMessage renders with multiple file placeholders', t => {
|
|
91
|
+
const {lastFrame} = render(
|
|
92
|
+
<MockThemeProvider>
|
|
93
|
+
<UserMessage message="Compare [@src/app.tsx] with [@src/index.tsx]" />
|
|
94
|
+
</MockThemeProvider>,
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const output = lastFrame();
|
|
98
|
+
t.truthy(output);
|
|
99
|
+
t.regex(output!, /\[@src\/app\.tsx\]/);
|
|
100
|
+
t.regex(output!, /\[@src\/index\.tsx\]/);
|
|
101
|
+
t.regex(output!, /Compare/);
|
|
102
|
+
t.regex(output!, /with/);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('UserMessage renders multi-line message', t => {
|
|
106
|
+
const {lastFrame} = render(
|
|
107
|
+
<MockThemeProvider>
|
|
108
|
+
<UserMessage message="Line 1\nLine 2\nLine 3" />
|
|
109
|
+
</MockThemeProvider>,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const output = lastFrame();
|
|
113
|
+
t.truthy(output);
|
|
114
|
+
t.regex(output!, /Line 1/);
|
|
115
|
+
t.regex(output!, /Line 2/);
|
|
116
|
+
t.regex(output!, /Line 3/);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('UserMessage renders multi-line message with file placeholders', t => {
|
|
120
|
+
const {lastFrame} = render(
|
|
121
|
+
<MockThemeProvider>
|
|
122
|
+
<UserMessage message="Check these files:\n[@src/app.tsx]\n[@src/utils.ts]" />
|
|
123
|
+
</MockThemeProvider>,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const output = lastFrame();
|
|
127
|
+
t.truthy(output);
|
|
128
|
+
t.regex(output!, /Check these files:/);
|
|
129
|
+
t.regex(output!, /\[@src\/app\.tsx\]/);
|
|
130
|
+
t.regex(output!, /\[@src\/utils\.ts\]/);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('UserMessage renders file placeholder at start of message', t => {
|
|
134
|
+
const {lastFrame} = render(
|
|
135
|
+
<MockThemeProvider>
|
|
136
|
+
<UserMessage message="[@package.json] shows dependencies" />
|
|
137
|
+
</MockThemeProvider>,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const output = lastFrame();
|
|
141
|
+
t.truthy(output);
|
|
142
|
+
t.regex(output!, /\[@package\.json\]/);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('UserMessage renders file placeholder at end of message', t => {
|
|
146
|
+
const {lastFrame} = render(
|
|
147
|
+
<MockThemeProvider>
|
|
148
|
+
<UserMessage message="Check the config in [@tsconfig.json]" />
|
|
149
|
+
</MockThemeProvider>,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const output = lastFrame();
|
|
153
|
+
t.truthy(output);
|
|
154
|
+
t.regex(output!, /\[@tsconfig\.json\]/);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('UserMessage renders with empty message', t => {
|
|
158
|
+
const {lastFrame} = render(
|
|
159
|
+
<MockThemeProvider>
|
|
160
|
+
<UserMessage message="" />
|
|
161
|
+
</MockThemeProvider>,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const output = lastFrame();
|
|
165
|
+
t.truthy(output);
|
|
166
|
+
t.regex(output!, /You:/);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('UserMessage handles file placeholder with special characters in path', t => {
|
|
170
|
+
const {lastFrame} = render(
|
|
171
|
+
<MockThemeProvider>
|
|
172
|
+
<UserMessage message="Check [@src/my-file.spec.ts:100-200]" />
|
|
173
|
+
</MockThemeProvider>,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const output = lastFrame();
|
|
177
|
+
t.truthy(output);
|
|
178
|
+
t.regex(output!, /\[@src\/my-file\.spec\.ts:100-200\]/);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('UserMessage handles multiple placeholders on same line', t => {
|
|
182
|
+
const {lastFrame} = render(
|
|
183
|
+
<MockThemeProvider>
|
|
184
|
+
<UserMessage message="Compare [@a.ts] and [@b.ts] and [@c.ts]" />
|
|
185
|
+
</MockThemeProvider>,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const output = lastFrame();
|
|
189
|
+
t.truthy(output);
|
|
190
|
+
t.regex(output!, /\[@a\.ts\]/);
|
|
191
|
+
t.regex(output!, /\[@b\.ts\]/);
|
|
192
|
+
t.regex(output!, /\[@c\.ts\]/);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test('UserMessage does not render @ symbols that are not placeholders', t => {
|
|
196
|
+
const {lastFrame} = render(
|
|
197
|
+
<MockThemeProvider>
|
|
198
|
+
<UserMessage message="Email me at user@example.com" />
|
|
199
|
+
</MockThemeProvider>,
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
const output = lastFrame();
|
|
203
|
+
t.truthy(output);
|
|
204
|
+
t.regex(output!, /user@example\.com/);
|
|
205
|
+
// Should NOT have placeholder styling since it's not in [@...] format
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('UserMessage renders paragraphs with spacing', t => {
|
|
209
|
+
const {lastFrame} = render(
|
|
210
|
+
<MockThemeProvider>
|
|
211
|
+
<UserMessage message="First paragraph\n\nSecond paragraph\n\nThird paragraph" />
|
|
212
|
+
</MockThemeProvider>,
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const output = lastFrame();
|
|
216
|
+
t.truthy(output);
|
|
217
|
+
t.regex(output!, /First paragraph/);
|
|
218
|
+
t.regex(output!, /Second paragraph/);
|
|
219
|
+
t.regex(output!, /Third paragraph/);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test('UserMessage renders without crashing', t => {
|
|
223
|
+
const {lastFrame} = render(
|
|
224
|
+
<MockThemeProvider>
|
|
225
|
+
<UserMessage message="Test" />
|
|
226
|
+
</MockThemeProvider>,
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
t.truthy(lastFrame());
|
|
230
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {useTheme} from '@/hooks/useTheme';
|
|
2
|
+
import type {UserMessageProps} from '@/types/index';
|
|
3
|
+
import {Box, Text} from 'ink';
|
|
4
|
+
import {memo} from 'react';
|
|
5
|
+
|
|
6
|
+
// Parse a line and return segments with file placeholders highlighted
|
|
7
|
+
function parseLineWithPlaceholders(line: string) {
|
|
8
|
+
const segments: Array<{text: string; isPlaceholder: boolean}> = [];
|
|
9
|
+
const filePattern = /\[@[^\]]+\]/g;
|
|
10
|
+
let lastIndex = 0;
|
|
11
|
+
let match;
|
|
12
|
+
|
|
13
|
+
while ((match = filePattern.exec(line)) !== null) {
|
|
14
|
+
// Add text before the placeholder
|
|
15
|
+
if (match.index > lastIndex) {
|
|
16
|
+
segments.push({
|
|
17
|
+
text: line.slice(lastIndex, match.index),
|
|
18
|
+
isPlaceholder: false,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Add the placeholder
|
|
23
|
+
segments.push({
|
|
24
|
+
text: match[0],
|
|
25
|
+
isPlaceholder: true,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
lastIndex = match.index + match[0].length;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Add remaining text
|
|
32
|
+
if (lastIndex < line.length) {
|
|
33
|
+
segments.push({
|
|
34
|
+
text: line.slice(lastIndex),
|
|
35
|
+
isPlaceholder: false,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return segments;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default memo(function UserMessage({message}: UserMessageProps) {
|
|
43
|
+
const {colors} = useTheme();
|
|
44
|
+
|
|
45
|
+
const lines = message.split('\n');
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Box flexDirection="column" marginBottom={1}>
|
|
49
|
+
<Box>
|
|
50
|
+
<Text color={colors.secondary} bold>
|
|
51
|
+
You:
|
|
52
|
+
</Text>
|
|
53
|
+
</Box>
|
|
54
|
+
<Box flexDirection="column">
|
|
55
|
+
{lines.map((line, lineIndex) => {
|
|
56
|
+
// Skip empty lines - they create paragraph spacing via marginBottom
|
|
57
|
+
if (line.trim() === '') {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const segments = parseLineWithPlaceholders(line);
|
|
62
|
+
const isEndOfParagraph =
|
|
63
|
+
lineIndex + 1 < lines.length && lines[lineIndex + 1].trim() === '';
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<Box key={lineIndex} marginBottom={isEndOfParagraph ? 1 : 0}>
|
|
67
|
+
<Text>
|
|
68
|
+
{segments.map((segment, segIndex) => (
|
|
69
|
+
<Text
|
|
70
|
+
key={segIndex}
|
|
71
|
+
color={segment.isPlaceholder ? colors.info : colors.white}
|
|
72
|
+
bold={segment.isPlaceholder}
|
|
73
|
+
>
|
|
74
|
+
{segment.text}
|
|
75
|
+
</Text>
|
|
76
|
+
))}
|
|
77
|
+
</Text>
|
|
78
|
+
</Box>
|
|
79
|
+
);
|
|
80
|
+
})}
|
|
81
|
+
</Box>
|
|
82
|
+
</Box>
|
|
83
|
+
);
|
|
84
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {Box, Text} from 'ink';
|
|
2
|
+
import {memo} from 'react';
|
|
3
|
+
|
|
4
|
+
import {TitledBox} from '@/components/ui/titled-box';
|
|
5
|
+
import {useResponsiveTerminal} from '@/hooks/useTerminalWidth';
|
|
6
|
+
import {useTheme} from '@/hooks/useTheme';
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import {fileURLToPath} from 'url';
|
|
11
|
+
import BigText from 'ink-big-text';
|
|
12
|
+
import Gradient from 'ink-gradient';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = path.dirname(__filename);
|
|
16
|
+
|
|
17
|
+
// Read package.json once at module load time to avoid repeated file reads
|
|
18
|
+
const packageJson = JSON.parse(
|
|
19
|
+
fs.readFileSync(path.join(__dirname, '../../package.json'), 'utf8'),
|
|
20
|
+
) as {version: string};
|
|
21
|
+
|
|
22
|
+
export default memo(function WelcomeMessage() {
|
|
23
|
+
const {boxWidth, isNarrow, isNormal} = useResponsiveTerminal();
|
|
24
|
+
const {colors} = useTheme();
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
{/* Narrow terminal: simple text without boxes */}
|
|
29
|
+
{isNarrow ? (
|
|
30
|
+
<>
|
|
31
|
+
<Gradient colors={[colors.primary, colors.tool]}>
|
|
32
|
+
<BigText text="coder" font="tiny" />
|
|
33
|
+
</Gradient>
|
|
34
|
+
<Box
|
|
35
|
+
flexDirection="column"
|
|
36
|
+
marginBottom={1}
|
|
37
|
+
borderStyle="round"
|
|
38
|
+
borderColor={colors.primary}
|
|
39
|
+
paddingY={1}
|
|
40
|
+
paddingX={2}
|
|
41
|
+
>
|
|
42
|
+
<Box marginBottom={1}>
|
|
43
|
+
<Text color={colors.primary} bold>
|
|
44
|
+
✻ Version {packageJson.version}
|
|
45
|
+
</Text>
|
|
46
|
+
</Box>
|
|
47
|
+
<Text color={colors.white}>Tips:</Text>
|
|
48
|
+
<Text color={colors.secondary}>• Use natural language</Text>
|
|
49
|
+
<Text color={colors.secondary}>• /help for commands</Text>
|
|
50
|
+
<Text color={colors.secondary}>• Ctrl+C to quit</Text>
|
|
51
|
+
</Box>
|
|
52
|
+
</>
|
|
53
|
+
) : (
|
|
54
|
+
/* Normal/Wide terminal: full version with TitledBox */
|
|
55
|
+
<>
|
|
56
|
+
<Gradient colors={[colors.primary, colors.tool]}>
|
|
57
|
+
<BigText text="coder" font="tiny" />
|
|
58
|
+
</Gradient>
|
|
59
|
+
<TitledBox
|
|
60
|
+
title={packageJson.version}
|
|
61
|
+
width={boxWidth}
|
|
62
|
+
borderColor={colors.primary}
|
|
63
|
+
paddingX={2}
|
|
64
|
+
paddingY={1}
|
|
65
|
+
flexDirection="column"
|
|
66
|
+
marginBottom={1}
|
|
67
|
+
>
|
|
68
|
+
<Box>
|
|
69
|
+
<Text color={colors.white}>🎊✨ Happy New Year 2026!🎉 /help for help</Text>
|
|
70
|
+
</Box>
|
|
71
|
+
</TitledBox>
|
|
72
|
+
</>
|
|
73
|
+
)}
|
|
74
|
+
</>
|
|
75
|
+
);
|
|
76
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {logError} from '@/utils/message-queue';
|
|
2
|
+
|
|
3
|
+
// Expand environment variable references in a string
|
|
4
|
+
function expandEnvVar(str: string): string {
|
|
5
|
+
if (typeof str !== 'string') {
|
|
6
|
+
return str;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const regex = /\$\{([A-Z_][A-Z0-9_]*)(?::-(.*?))?\}|\$([A-Z_][A-Z0-9_]*)/g;
|
|
10
|
+
|
|
11
|
+
return str.replace(
|
|
12
|
+
regex,
|
|
13
|
+
(
|
|
14
|
+
_match: string,
|
|
15
|
+
bracedVarName: string | undefined,
|
|
16
|
+
defaultValue: string | undefined,
|
|
17
|
+
unbracedVarName: string | undefined,
|
|
18
|
+
) => {
|
|
19
|
+
const varName = bracedVarName || unbracedVarName;
|
|
20
|
+
if (!varName) return '';
|
|
21
|
+
|
|
22
|
+
const envValue = process.env[varName];
|
|
23
|
+
|
|
24
|
+
if (envValue !== undefined) {
|
|
25
|
+
return envValue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (defaultValue !== undefined) {
|
|
29
|
+
return defaultValue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
logError(
|
|
33
|
+
`Environment variable ${varName} not found in config, using empty string`,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return '';
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Recursively substitute environment variables in objects, arrays, and strings
|
|
42
|
+
export function substituteEnvVars<T>(value: T): T {
|
|
43
|
+
if (value === null || value === undefined) {
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (typeof value === 'string') {
|
|
48
|
+
return expandEnvVar(value) as T;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (Array.isArray(value)) {
|
|
52
|
+
return value.map((item: unknown) => substituteEnvVars(item)) as T;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (typeof value === 'object') {
|
|
56
|
+
const result: Record<string, unknown> = {};
|
|
57
|
+
for (const [key, val] of Object.entries(value)) {
|
|
58
|
+
result[key] = substituteEnvVars(val);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return result as T;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import {existsSync, mkdirSync, readFileSync, rmSync, writeFileSync} from 'fs';
|
|
2
|
+
import {tmpdir} from 'os';
|
|
3
|
+
import {join} from 'path';
|
|
4
|
+
import test from 'ava';
|
|
5
|
+
import {confDirMap, getClosestConfigFile, reloadAppConfig} from './index';
|
|
6
|
+
|
|
7
|
+
console.log(`\nindex.spec.ts`);
|
|
8
|
+
|
|
9
|
+
// Create a temporary test directory
|
|
10
|
+
const testDir = join(tmpdir(), `coder-test-${Date.now()}`);
|
|
11
|
+
|
|
12
|
+
test.before(() => {
|
|
13
|
+
// Create test directory
|
|
14
|
+
mkdirSync(testDir, {recursive: true});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test.after.always(() => {
|
|
18
|
+
// Clean up test directory
|
|
19
|
+
if (existsSync(testDir)) {
|
|
20
|
+
rmSync(testDir, {recursive: true, force: true});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('getClosestConfigFile creates default config if none exists', t => {
|
|
25
|
+
const fileName = 'test-config.json';
|
|
26
|
+
const configPath = getClosestConfigFile(fileName);
|
|
27
|
+
|
|
28
|
+
t.true(existsSync(configPath), 'Config file should be created');
|
|
29
|
+
t.true(configPath.includes(fileName), 'Config path should include filename');
|
|
30
|
+
|
|
31
|
+
// Clean up
|
|
32
|
+
if (existsSync(configPath)) {
|
|
33
|
+
rmSync(configPath, {force: true});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('getClosestConfigFile prefers cwd config over home config', t => {
|
|
38
|
+
const fileName = 'test-priority.json';
|
|
39
|
+
const cwdConfig = join(process.cwd(), fileName);
|
|
40
|
+
|
|
41
|
+
// Create a config in cwd
|
|
42
|
+
writeFileSync(cwdConfig, JSON.stringify({test: 'cwd'}), 'utf-8');
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const configPath = getClosestConfigFile(fileName);
|
|
46
|
+
t.is(configPath, cwdConfig, 'Should prefer cwd config');
|
|
47
|
+
t.is(confDirMap[fileName], cwdConfig, 'Should store cwd path in map');
|
|
48
|
+
|
|
49
|
+
// Verify it returns the cwd config content
|
|
50
|
+
const content = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
51
|
+
t.deepEqual(content, {test: 'cwd'});
|
|
52
|
+
} finally {
|
|
53
|
+
// Clean up
|
|
54
|
+
if (existsSync(cwdConfig)) {
|
|
55
|
+
rmSync(cwdConfig, {force: true});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('confDirMap stores config file locations', t => {
|
|
61
|
+
const fileName = 'test-map.json';
|
|
62
|
+
|
|
63
|
+
// Clear any existing entry
|
|
64
|
+
delete confDirMap[fileName];
|
|
65
|
+
|
|
66
|
+
const configPath = getClosestConfigFile(fileName);
|
|
67
|
+
|
|
68
|
+
t.true(fileName in confDirMap, 'Config map should have entry');
|
|
69
|
+
t.is(
|
|
70
|
+
confDirMap[fileName],
|
|
71
|
+
configPath,
|
|
72
|
+
'Config map should store correct path',
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Clean up
|
|
76
|
+
if (existsSync(configPath)) {
|
|
77
|
+
rmSync(configPath, {force: true});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('getClosestConfigFile handles missing config directory gracefully', t => {
|
|
82
|
+
const fileName = 'new-config.json';
|
|
83
|
+
|
|
84
|
+
// This should create the config directory and file
|
|
85
|
+
t.notThrows(() => {
|
|
86
|
+
const configPath = getClosestConfigFile(fileName);
|
|
87
|
+
t.true(existsSync(configPath), 'Should create config file');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Clean up
|
|
91
|
+
const configPath = confDirMap[fileName];
|
|
92
|
+
if (configPath && existsSync(configPath)) {
|
|
93
|
+
rmSync(configPath, {force: true});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('reloadAppConfig can be called without errors', t => {
|
|
98
|
+
// This test ensures reloadAppConfig doesn't throw
|
|
99
|
+
t.notThrows(() => {
|
|
100
|
+
reloadAppConfig();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('default config file contains valid JSON', t => {
|
|
105
|
+
const fileName = 'test-default.json';
|
|
106
|
+
const configPath = getClosestConfigFile(fileName);
|
|
107
|
+
|
|
108
|
+
// Read and parse the created config
|
|
109
|
+
const content = readFileSync(configPath, 'utf-8');
|
|
110
|
+
|
|
111
|
+
t.notThrows(() => {
|
|
112
|
+
JSON.parse(content);
|
|
113
|
+
}, 'Default config should be valid JSON');
|
|
114
|
+
|
|
115
|
+
// Clean up
|
|
116
|
+
if (existsSync(configPath)) {
|
|
117
|
+
rmSync(configPath, {force: true});
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('promptPath points to main-prompt.md', async t => {
|
|
122
|
+
// Dynamic import to get the promptPath
|
|
123
|
+
const {promptPath} = await import('./index.js');
|
|
124
|
+
|
|
125
|
+
t.true(
|
|
126
|
+
promptPath.includes('main-prompt.md'),
|
|
127
|
+
'promptPath should point to main-prompt.md',
|
|
128
|
+
);
|
|
129
|
+
t.true(
|
|
130
|
+
promptPath.includes('source/app/prompts'),
|
|
131
|
+
'promptPath should include source/app/prompts directory',
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('loadAppConfig handles malformed JSON gracefully', async t => {
|
|
136
|
+
const fileName = 'malformed-config.json';
|
|
137
|
+
const configPath = getClosestConfigFile(fileName);
|
|
138
|
+
|
|
139
|
+
// Write malformed JSON to the config file
|
|
140
|
+
writeFileSync(configPath, '{ "coder": { "providers": [ }, "mcpServers": [ ] }', 'utf-8');
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
// This should not throw, but should log a warning
|
|
144
|
+
const {reloadAppConfig} = await import('./index.js');
|
|
145
|
+
reloadAppConfig();
|
|
146
|
+
t.pass('Should handle malformed JSON without throwing');
|
|
147
|
+
} finally {
|
|
148
|
+
// Clean up
|
|
149
|
+
if (existsSync(configPath)) {
|
|
150
|
+
rmSync(configPath, {force: true});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('loadAppConfig handles missing file gracefully', async t => {
|
|
156
|
+
// This test ensures that when the config file is missing,
|
|
157
|
+
// the function falls back to defaults without throwing
|
|
158
|
+
const originalCwd = process.cwd();
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
// Change to a directory where the config file doesn't exist
|
|
162
|
+
process.chdir(testDir);
|
|
163
|
+
|
|
164
|
+
const {reloadAppConfig} = await import('./index.js');
|
|
165
|
+
reloadAppConfig();
|
|
166
|
+
t.pass('Should handle missing config file without throwing');
|
|
167
|
+
} finally {
|
|
168
|
+
// Restore original directory
|
|
169
|
+
process.chdir(originalCwd);
|
|
170
|
+
}
|
|
171
|
+
});
|