@vybestack/llxprt-code-core 0.1.15 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -2
- package/dist/src/code_assist/converter.d.ts +2 -1
- package/dist/src/code_assist/converter.js +2 -1
- package/dist/src/code_assist/converter.js.map +1 -1
- package/dist/src/code_assist/converter.test.js +13 -10
- package/dist/src/code_assist/converter.test.js.map +1 -1
- package/dist/src/code_assist/server.d.ts +2 -2
- package/dist/src/code_assist/server.js +4 -4
- package/dist/src/code_assist/server.js.map +1 -1
- package/dist/src/code_assist/server.test.js +9 -9
- package/dist/src/code_assist/server.test.js.map +1 -1
- package/dist/src/code_assist/setup.js +1 -1
- package/dist/src/code_assist/setup.js.map +1 -1
- package/dist/src/code_assist/setup.test.js +2 -2
- package/dist/src/code_assist/setup.test.js.map +1 -1
- package/dist/src/config/config.d.ts +22 -4
- package/dist/src/config/config.js +58 -10
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +28 -0
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/flashFallback.test.js +11 -1
- package/dist/src/config/flashFallback.test.js.map +1 -1
- package/dist/src/config/models.js.map +1 -1
- package/dist/src/config/profileManager.d.ts +42 -0
- package/dist/src/config/profileManager.js +114 -0
- package/dist/src/config/profileManager.js.map +1 -0
- package/dist/src/core/client.d.ts +11 -1
- package/dist/src/core/client.js +86 -30
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.d.ts +1 -1
- package/dist/src/core/client.test.js +95 -28
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +2 -2
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/coreToolScheduler.js +39 -15
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/coreToolScheduler.test.js +14 -17
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/geminiChat.js +34 -2
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +2 -2
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.js +11 -3
- package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.test.js +5 -2
- package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
- package/dist/src/core/prompts-async.test.d.ts +6 -0
- package/dist/src/core/prompts-async.test.js +115 -0
- package/dist/src/core/prompts-async.test.js.map +1 -0
- package/dist/src/core/prompts.d.ts +8 -1
- package/dist/src/core/prompts.js +97 -377
- package/dist/src/core/prompts.js.map +1 -1
- package/dist/src/core/prompts.test.js +46 -192
- package/dist/src/core/prompts.test.js.map +1 -1
- package/dist/src/core/tokenLimits.d.ts +1 -1
- package/dist/src/core/tokenLimits.js +5 -1
- package/dist/src/core/tokenLimits.js.map +1 -1
- package/dist/src/core/turn.d.ts +3 -0
- package/dist/src/core/turn.js +3 -0
- package/dist/src/core/turn.js.map +1 -1
- package/dist/src/ide/detect-ide.d.ts +10 -0
- package/dist/src/ide/detect-ide.js +24 -0
- package/dist/src/ide/detect-ide.js.map +1 -0
- package/dist/src/ide/ide-client.d.ts +11 -1
- package/dist/src/ide/ide-client.js +37 -1
- package/dist/src/ide/ide-client.js.map +1 -1
- package/dist/src/ide/ide-installer.d.ts +15 -0
- package/dist/src/ide/ide-installer.js +111 -0
- package/dist/src/ide/ide-installer.js.map +1 -0
- package/dist/src/ide/ide-installer.test.d.ts +6 -0
- package/dist/src/ide/ide-installer.test.js +78 -0
- package/dist/src/ide/ide-installer.test.js.map +1 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/oauth-provider.js +3 -3
- package/dist/src/mcp/oauth-provider.js.map +1 -1
- package/dist/src/mcp/oauth-provider.test.js +9 -8
- package/dist/src/mcp/oauth-provider.test.js.map +1 -1
- package/dist/src/parsers/TextToolCallParser.d.ts +1 -0
- package/dist/src/parsers/TextToolCallParser.js +45 -3
- package/dist/src/parsers/TextToolCallParser.js.map +1 -1
- package/dist/src/parsers/TextToolCallParser.multibyte.test.d.ts +1 -0
- package/dist/src/parsers/TextToolCallParser.multibyte.test.js +42 -0
- package/dist/src/parsers/TextToolCallParser.multibyte.test.js.map +1 -0
- package/dist/src/prompt-config/TemplateEngine.d.ts +35 -0
- package/dist/src/prompt-config/TemplateEngine.js +149 -0
- package/dist/src/prompt-config/TemplateEngine.js.map +1 -0
- package/dist/src/prompt-config/TemplateEngine.test.d.ts +1 -0
- package/dist/src/prompt-config/TemplateEngine.test.js +494 -0
- package/dist/src/prompt-config/TemplateEngine.test.js.map +1 -0
- package/dist/src/prompt-config/defaults/compression.md +58 -0
- package/dist/src/prompt-config/defaults/core-defaults.d.ts +5 -0
- package/dist/src/prompt-config/defaults/core-defaults.js +332 -0
- package/dist/src/prompt-config/defaults/core-defaults.js.map +1 -0
- package/dist/src/prompt-config/defaults/core.md +267 -0
- package/dist/src/prompt-config/defaults/env/git-repository.md +15 -0
- package/dist/src/prompt-config/defaults/env/ide-mode.md +3 -0
- package/dist/src/prompt-config/defaults/env/macos-seatbelt.md +3 -0
- package/dist/src/prompt-config/defaults/env/outside-of-sandbox.md +3 -0
- package/dist/src/prompt-config/defaults/env/sandbox.md +3 -0
- package/dist/src/prompt-config/defaults/index.d.ts +14 -0
- package/dist/src/prompt-config/defaults/index.js +21 -0
- package/dist/src/prompt-config/defaults/index.js.map +1 -0
- package/dist/src/prompt-config/defaults/provider-defaults.d.ts +5 -0
- package/dist/src/prompt-config/defaults/provider-defaults.js +26 -0
- package/dist/src/prompt-config/defaults/provider-defaults.js.map +1 -0
- package/dist/src/prompt-config/defaults/providers/gemini/models/gemini-2.5-flash/core.md +10 -0
- package/dist/src/prompt-config/defaults/service-defaults.d.ts +5 -0
- package/dist/src/prompt-config/defaults/service-defaults.js +52 -0
- package/dist/src/prompt-config/defaults/service-defaults.js.map +1 -0
- package/dist/src/prompt-config/defaults/tool-defaults.d.ts +5 -0
- package/dist/src/prompt-config/defaults/tool-defaults.js +81 -0
- package/dist/src/prompt-config/defaults/tool-defaults.js.map +1 -0
- package/dist/src/prompt-config/defaults/tools/edit.md +2 -0
- package/dist/src/prompt-config/defaults/tools/glob.md +2 -0
- package/dist/src/prompt-config/defaults/tools/grep.md +2 -0
- package/dist/src/prompt-config/defaults/tools/ls.md +1 -0
- package/dist/src/prompt-config/defaults/tools/memory.md +1 -0
- package/dist/src/prompt-config/defaults/tools/read-file.md +4 -0
- package/dist/src/prompt-config/defaults/tools/read-many-files.md +2 -0
- package/dist/src/prompt-config/defaults/tools/shell.md +5 -0
- package/dist/src/prompt-config/defaults/tools/todo-read.md +3 -0
- package/dist/src/prompt-config/defaults/tools/todo-write.md +50 -0
- package/dist/src/prompt-config/defaults/tools/web-fetch.md +3 -0
- package/dist/src/prompt-config/defaults/tools/web-search.md +3 -0
- package/dist/src/prompt-config/defaults/tools/write-file.md +4 -0
- package/dist/src/prompt-config/index.d.ts +16 -0
- package/dist/src/prompt-config/index.js +11 -0
- package/dist/src/prompt-config/index.js.map +1 -0
- package/dist/src/prompt-config/prompt-cache.d.ts +72 -0
- package/dist/src/prompt-config/prompt-cache.js +271 -0
- package/dist/src/prompt-config/prompt-cache.js.map +1 -0
- package/dist/src/prompt-config/prompt-cache.test.d.ts +6 -0
- package/dist/src/prompt-config/prompt-cache.test.js +437 -0
- package/dist/src/prompt-config/prompt-cache.test.js.map +1 -0
- package/dist/src/prompt-config/prompt-installer.d.ts +118 -0
- package/dist/src/prompt-config/prompt-installer.js +723 -0
- package/dist/src/prompt-config/prompt-installer.js.map +1 -0
- package/dist/src/prompt-config/prompt-installer.test.d.ts +7 -0
- package/dist/src/prompt-config/prompt-installer.test.js +503 -0
- package/dist/src/prompt-config/prompt-installer.test.js.map +1 -0
- package/dist/src/prompt-config/prompt-loader.d.ts +49 -0
- package/dist/src/prompt-config/prompt-loader.js +331 -0
- package/dist/src/prompt-config/prompt-loader.js.map +1 -0
- package/dist/src/prompt-config/prompt-loader.test.d.ts +5 -0
- package/dist/src/prompt-config/prompt-loader.test.js +413 -0
- package/dist/src/prompt-config/prompt-loader.test.js.map +1 -0
- package/dist/src/prompt-config/prompt-resolver.d.ts +74 -0
- package/dist/src/prompt-config/prompt-resolver.js +600 -0
- package/dist/src/prompt-config/prompt-resolver.js.map +1 -0
- package/dist/src/prompt-config/prompt-resolver.test.d.ts +1 -0
- package/dist/src/prompt-config/prompt-resolver.test.js +529 -0
- package/dist/src/prompt-config/prompt-resolver.test.js.map +1 -0
- package/dist/src/prompt-config/prompt-service.d.ts +108 -0
- package/dist/src/prompt-config/prompt-service.js +435 -0
- package/dist/src/prompt-config/prompt-service.js.map +1 -0
- package/dist/src/prompt-config/prompt-service.test.d.ts +1 -0
- package/dist/src/prompt-config/prompt-service.test.js +811 -0
- package/dist/src/prompt-config/prompt-service.test.js.map +1 -0
- package/dist/src/prompt-config/types.d.ts +30 -0
- package/dist/src/prompt-config/types.js +10 -0
- package/dist/src/prompt-config/types.js.map +1 -0
- package/dist/src/providers/IProvider.d.ts +10 -0
- package/dist/src/providers/anthropic/AnthropicProvider.d.ts +14 -1
- package/dist/src/providers/anthropic/AnthropicProvider.js +28 -2
- package/dist/src/providers/anthropic/AnthropicProvider.js.map +1 -1
- package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.d.ts +1 -0
- package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.js +48 -0
- package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.js.map +1 -0
- package/dist/src/providers/anthropic/AnthropicProvider.test.js +2 -1
- package/dist/src/providers/anthropic/AnthropicProvider.test.js.map +1 -1
- package/dist/src/providers/gemini/GeminiProvider.d.ts +11 -2
- package/dist/src/providers/gemini/GeminiProvider.integration.test.js +1 -1
- package/dist/src/providers/gemini/GeminiProvider.js +34 -9
- package/dist/src/providers/gemini/GeminiProvider.js.map +1 -1
- package/dist/src/providers/openai/OpenAIProvider.d.ts +11 -0
- package/dist/src/providers/openai/OpenAIProvider.js +100 -31
- package/dist/src/providers/openai/OpenAIProvider.js.map +1 -1
- package/dist/src/providers/openai/OpenAIProvider.responses.test.js +27 -3
- package/dist/src/providers/openai/OpenAIProvider.responses.test.js.map +1 -1
- package/dist/src/providers/openai/OpenAIProvider.shouldUseResponses.test.js +2 -1
- package/dist/src/providers/openai/OpenAIProvider.shouldUseResponses.test.js.map +1 -1
- package/dist/src/providers/openai/OpenAIProvider.test.js +307 -7
- package/dist/src/providers/openai/OpenAIProvider.test.js.map +1 -1
- package/dist/src/providers/openai/buildResponsesRequest.js +19 -2
- package/dist/src/providers/openai/buildResponsesRequest.js.map +1 -1
- package/dist/src/providers/test-utils/providerTestConfig.d.ts +21 -0
- package/dist/src/providers/test-utils/providerTestConfig.js +23 -0
- package/dist/src/providers/test-utils/providerTestConfig.js.map +1 -0
- package/dist/src/providers/types/IProviderConfig.d.ts +6 -0
- package/dist/src/services/loopDetectionService.d.ts +9 -0
- package/dist/src/services/loopDetectionService.js +44 -12
- package/dist/src/services/loopDetectionService.js.map +1 -1
- package/dist/src/services/shellExecutionService.d.ts +1 -37
- package/dist/src/services/shellExecutionService.js +24 -55
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/{providers/IProviderConfig.js → services/shellExecutionService.multibyte.test.d.ts} +0 -1
- package/dist/src/services/shellExecutionService.multibyte.test.js +72 -0
- package/dist/src/services/shellExecutionService.multibyte.test.js.map +1 -0
- package/dist/src/services/shellExecutionService.test.js +11 -5
- package/dist/src/services/shellExecutionService.test.js.map +1 -1
- package/dist/src/services/shellExecutionService.windows.multibyte.test.d.ts +6 -0
- package/dist/src/services/shellExecutionService.windows.multibyte.test.js +98 -0
- package/dist/src/services/shellExecutionService.windows.multibyte.test.js.map +1 -0
- package/dist/src/services/shellExecutionService.windows.test.d.ts +6 -0
- package/dist/src/services/shellExecutionService.windows.test.js +79 -0
- package/dist/src/services/shellExecutionService.windows.test.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +3 -2
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +22 -3
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +4 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +12 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/constants.d.ts +1 -1
- package/dist/src/telemetry/constants.js +1 -1
- package/dist/src/telemetry/constants.js.map +1 -1
- package/dist/src/telemetry/file-exporters.d.ts +2 -2
- package/dist/src/telemetry/file-exporters.js +47 -20
- package/dist/src/telemetry/file-exporters.js.map +1 -1
- package/dist/src/telemetry/loggers.d.ts +2 -2
- package/dist/src/telemetry/loggers.js +13 -6
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.circular.js +2 -0
- package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +8 -3
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/sdk.d.ts +1 -1
- package/dist/src/telemetry/sdk.js +71 -73
- package/dist/src/telemetry/sdk.js.map +1 -1
- package/dist/src/telemetry/telemetry.test.js +7 -5
- package/dist/src/telemetry/telemetry.test.js.map +1 -1
- package/dist/src/telemetry/types.d.ts +12 -4
- package/dist/src/telemetry/types.js +18 -4
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.test.js +3 -0
- package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
- package/dist/src/test-utils/mockWorkspaceContext.d.ts +13 -0
- package/dist/src/test-utils/mockWorkspaceContext.js +24 -0
- package/dist/src/test-utils/mockWorkspaceContext.js.map +1 -0
- package/dist/src/tools/edit.js +27 -3
- package/dist/src/tools/edit.js.map +1 -1
- package/dist/src/tools/edit.test.js +104 -1
- package/dist/src/tools/edit.test.js.map +1 -1
- package/dist/src/tools/glob.js +53 -17
- package/dist/src/tools/glob.js.map +1 -1
- package/dist/src/tools/glob.test.js +25 -2
- package/dist/src/tools/glob.test.js.map +1 -1
- package/dist/src/tools/grep.d.ts +1 -1
- package/dist/src/tools/grep.js +81 -29
- package/dist/src/tools/grep.js.map +1 -1
- package/dist/src/tools/grep.test.js +72 -5
- package/dist/src/tools/grep.test.js.map +1 -1
- package/dist/src/tools/ls.js +4 -3
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/ls.test.d.ts +6 -0
- package/dist/src/tools/ls.test.js +356 -0
- package/dist/src/tools/ls.test.js.map +1 -0
- package/dist/src/tools/mcp-client.js +8 -3
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +34 -0
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/memoryTool.d.ts +17 -2
- package/dist/src/tools/memoryTool.js +130 -13
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/memoryTool.test.js +88 -3
- package/dist/src/tools/memoryTool.test.js.map +1 -1
- package/dist/src/tools/read-file.js +8 -6
- package/dist/src/tools/read-file.js.map +1 -1
- package/dist/src/tools/read-file.test.js +30 -2
- package/dist/src/tools/read-file.test.js.map +1 -1
- package/dist/src/tools/read-many-files.js +22 -12
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/read-many-files.test.js +35 -2
- package/dist/src/tools/read-many-files.test.js.map +1 -1
- package/dist/src/tools/shell.js +16 -0
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.multibyte.test.d.ts +6 -0
- package/dist/src/tools/shell.multibyte.test.js +74 -0
- package/dist/src/tools/shell.multibyte.test.js.map +1 -0
- package/dist/src/tools/shell.test.js +33 -1
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/tool-error.d.ts +22 -0
- package/dist/src/tools/tool-error.js +27 -0
- package/dist/src/tools/tool-error.js.map +1 -0
- package/dist/src/tools/tool-registry.test.js +8 -0
- package/dist/src/tools/tool-registry.test.js.map +1 -1
- package/dist/src/tools/tools.d.ts +8 -0
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/write-file.js +5 -3
- package/dist/src/tools/write-file.js.map +1 -1
- package/dist/src/tools/write-file.test.js +36 -2
- package/dist/src/tools/write-file.test.js.map +1 -1
- package/dist/src/types/modelParams.d.ts +62 -0
- package/dist/src/types/modelParams.js +7 -0
- package/dist/src/types/modelParams.js.map +1 -0
- package/dist/src/utils/bfsFileSearch.test.js +4 -2
- package/dist/src/utils/bfsFileSearch.test.js.map +1 -1
- package/dist/src/utils/editCorrector.js +2 -2
- package/dist/src/utils/editCorrector.js.map +1 -1
- package/dist/src/utils/editor.d.ts +1 -1
- package/dist/src/utils/editor.js +9 -0
- package/dist/src/utils/editor.js.map +1 -1
- package/dist/src/utils/editor.test.js +21 -1
- package/dist/src/utils/editor.test.js.map +1 -1
- package/dist/src/utils/fileUtils.js +12 -1
- package/dist/src/utils/fileUtils.js.map +1 -1
- package/dist/src/utils/fileUtils.test.js +29 -1
- package/dist/src/utils/fileUtils.test.js.map +1 -1
- package/dist/src/utils/flashFallback.integration.test.js +8 -0
- package/dist/src/utils/flashFallback.integration.test.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.d.ts +1 -1
- package/dist/src/utils/memoryDiscovery.js +61 -73
- package/dist/src/utils/memoryDiscovery.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.test.js +4 -3
- package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
- package/dist/src/utils/memoryImportProcessor.d.ts +19 -12
- package/dist/src/utils/memoryImportProcessor.js +241 -82
- package/dist/src/utils/memoryImportProcessor.js.map +1 -1
- package/dist/src/utils/memoryImportProcessor.test.js +595 -50
- package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
- package/dist/src/utils/nextSpeakerChecker.js +10 -25
- package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
- package/dist/src/utils/nextSpeakerChecker.test.js +6 -2
- package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
- package/dist/src/utils/sanitization.d.ts +20 -0
- package/dist/src/utils/sanitization.js +66 -0
- package/dist/src/utils/sanitization.js.map +1 -0
- package/dist/src/utils/sanitization.test.d.ts +6 -0
- package/dist/src/utils/sanitization.test.js +81 -0
- package/dist/src/utils/sanitization.test.js.map +1 -0
- package/dist/src/utils/secure-browser-launcher.d.ts +23 -0
- package/dist/src/utils/secure-browser-launcher.js +164 -0
- package/dist/src/utils/secure-browser-launcher.js.map +1 -0
- package/dist/src/utils/secure-browser-launcher.test.d.ts +6 -0
- package/dist/src/utils/secure-browser-launcher.test.js +149 -0
- package/dist/src/utils/secure-browser-launcher.test.js.map +1 -0
- package/dist/src/utils/summarizer.js +2 -2
- package/dist/src/utils/summarizer.js.map +1 -1
- package/dist/src/utils/unicodeUtils.d.ts +44 -0
- package/dist/src/utils/unicodeUtils.js +93 -0
- package/dist/src/utils/unicodeUtils.js.map +1 -0
- package/dist/src/utils/unicodeUtils.test.d.ts +6 -0
- package/dist/src/utils/unicodeUtils.test.js +120 -0
- package/dist/src/utils/unicodeUtils.test.js.map +1 -0
- package/dist/src/utils/workspaceContext.d.ts +47 -0
- package/dist/src/utils/workspaceContext.js +106 -0
- package/dist/src/utils/workspaceContext.js.map +1 -0
- package/dist/src/utils/workspaceContext.test.d.ts +6 -0
- package/dist/src/utils/workspaceContext.test.js +209 -0
- package/dist/src/utils/workspaceContext.test.js.map +1 -0
- package/package.json +2 -1
- package/dist/src/providers/IProviderConfig.d.ts +0 -31
- package/dist/src/providers/IProviderConfig.js.map +0 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
7
|
+
import { openBrowserSecurely } from './secure-browser-launcher.js';
|
|
8
|
+
// Create mock function using vi.hoisted
|
|
9
|
+
const mockExecFile = vi.hoisted(() => vi.fn());
|
|
10
|
+
// Mock modules
|
|
11
|
+
vi.mock('node:child_process');
|
|
12
|
+
vi.mock('node:util', () => ({
|
|
13
|
+
promisify: () => mockExecFile,
|
|
14
|
+
}));
|
|
15
|
+
describe('secure-browser-launcher', () => {
|
|
16
|
+
let originalPlatform;
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
vi.clearAllMocks();
|
|
19
|
+
mockExecFile.mockResolvedValue({ stdout: '', stderr: '' });
|
|
20
|
+
originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
|
|
21
|
+
});
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
if (originalPlatform) {
|
|
24
|
+
Object.defineProperty(process, 'platform', originalPlatform);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
function setPlatform(platform) {
|
|
28
|
+
Object.defineProperty(process, 'platform', {
|
|
29
|
+
value: platform,
|
|
30
|
+
configurable: true,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
describe('URL validation', () => {
|
|
34
|
+
it('should allow valid HTTP URLs', async () => {
|
|
35
|
+
setPlatform('darwin');
|
|
36
|
+
await openBrowserSecurely('http://example.com');
|
|
37
|
+
expect(mockExecFile).toHaveBeenCalledWith('open', ['http://example.com'], expect.any(Object));
|
|
38
|
+
});
|
|
39
|
+
it('should allow valid HTTPS URLs', async () => {
|
|
40
|
+
setPlatform('darwin');
|
|
41
|
+
await openBrowserSecurely('https://example.com');
|
|
42
|
+
expect(mockExecFile).toHaveBeenCalledWith('open', ['https://example.com'], expect.any(Object));
|
|
43
|
+
});
|
|
44
|
+
it('should reject non-HTTP(S) protocols', async () => {
|
|
45
|
+
await expect(openBrowserSecurely('file:///etc/passwd')).rejects.toThrow('Unsafe protocol');
|
|
46
|
+
await expect(openBrowserSecurely('javascript:alert(1)')).rejects.toThrow('Unsafe protocol');
|
|
47
|
+
await expect(openBrowserSecurely('ftp://example.com')).rejects.toThrow('Unsafe protocol');
|
|
48
|
+
});
|
|
49
|
+
it('should reject invalid URLs', async () => {
|
|
50
|
+
await expect(openBrowserSecurely('not-a-url')).rejects.toThrow('Invalid URL');
|
|
51
|
+
await expect(openBrowserSecurely('')).rejects.toThrow('Invalid URL');
|
|
52
|
+
});
|
|
53
|
+
it('should reject URLs with control characters', async () => {
|
|
54
|
+
await expect(openBrowserSecurely('http://example.com\nmalicious-command')).rejects.toThrow('invalid characters');
|
|
55
|
+
await expect(openBrowserSecurely('http://example.com\rmalicious-command')).rejects.toThrow('invalid characters');
|
|
56
|
+
await expect(openBrowserSecurely('http://example.com\x00')).rejects.toThrow('invalid characters');
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe('Command injection prevention', () => {
|
|
60
|
+
it('should prevent PowerShell command injection on Windows', async () => {
|
|
61
|
+
setPlatform('win32');
|
|
62
|
+
// The POC from the vulnerability report
|
|
63
|
+
const maliciousUrl = "http://127.0.0.1:8080/?param=example#$(Invoke-Expression([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('Y2FsYy5leGU='))))";
|
|
64
|
+
await openBrowserSecurely(maliciousUrl);
|
|
65
|
+
// Verify that execFile was called (not exec) and the URL is passed safely
|
|
66
|
+
expect(mockExecFile).toHaveBeenCalledWith('powershell.exe', [
|
|
67
|
+
'-NoProfile',
|
|
68
|
+
'-NonInteractive',
|
|
69
|
+
'-WindowStyle',
|
|
70
|
+
'Hidden',
|
|
71
|
+
'-Command',
|
|
72
|
+
`Start-Process '${maliciousUrl.replace(/'/g, "''")}'`,
|
|
73
|
+
], expect.any(Object));
|
|
74
|
+
});
|
|
75
|
+
it('should handle URLs with special shell characters safely', async () => {
|
|
76
|
+
setPlatform('darwin');
|
|
77
|
+
const urlsWithSpecialChars = [
|
|
78
|
+
'http://example.com/path?param=value&other=$value',
|
|
79
|
+
'http://example.com/path#fragment;command',
|
|
80
|
+
'http://example.com/$(whoami)',
|
|
81
|
+
'http://example.com/`command`',
|
|
82
|
+
'http://example.com/|pipe',
|
|
83
|
+
'http://example.com/>redirect',
|
|
84
|
+
];
|
|
85
|
+
for (const url of urlsWithSpecialChars) {
|
|
86
|
+
await openBrowserSecurely(url);
|
|
87
|
+
// Verify the URL is passed as an argument, not interpreted by shell
|
|
88
|
+
expect(mockExecFile).toHaveBeenCalledWith('open', [url], expect.any(Object));
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
it('should properly escape single quotes in URLs on Windows', async () => {
|
|
92
|
+
setPlatform('win32');
|
|
93
|
+
const urlWithSingleQuotes = "http://example.com/path?name=O'Brien&test='value'";
|
|
94
|
+
await openBrowserSecurely(urlWithSingleQuotes);
|
|
95
|
+
// Verify that single quotes are escaped by doubling them
|
|
96
|
+
expect(mockExecFile).toHaveBeenCalledWith('powershell.exe', [
|
|
97
|
+
'-NoProfile',
|
|
98
|
+
'-NonInteractive',
|
|
99
|
+
'-WindowStyle',
|
|
100
|
+
'Hidden',
|
|
101
|
+
'-Command',
|
|
102
|
+
`Start-Process 'http://example.com/path?name=O''Brien&test=''value'''`,
|
|
103
|
+
], expect.any(Object));
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('Platform-specific behavior', () => {
|
|
107
|
+
it('should use correct command on macOS', async () => {
|
|
108
|
+
setPlatform('darwin');
|
|
109
|
+
await openBrowserSecurely('https://example.com');
|
|
110
|
+
expect(mockExecFile).toHaveBeenCalledWith('open', ['https://example.com'], expect.any(Object));
|
|
111
|
+
});
|
|
112
|
+
it('should use PowerShell on Windows', async () => {
|
|
113
|
+
setPlatform('win32');
|
|
114
|
+
await openBrowserSecurely('https://example.com');
|
|
115
|
+
expect(mockExecFile).toHaveBeenCalledWith('powershell.exe', expect.arrayContaining([
|
|
116
|
+
'-Command',
|
|
117
|
+
`Start-Process 'https://example.com'`,
|
|
118
|
+
]), expect.any(Object));
|
|
119
|
+
});
|
|
120
|
+
it('should use xdg-open on Linux', async () => {
|
|
121
|
+
setPlatform('linux');
|
|
122
|
+
await openBrowserSecurely('https://example.com');
|
|
123
|
+
expect(mockExecFile).toHaveBeenCalledWith('xdg-open', ['https://example.com'], expect.any(Object));
|
|
124
|
+
});
|
|
125
|
+
it('should throw on unsupported platforms', async () => {
|
|
126
|
+
setPlatform('aix');
|
|
127
|
+
await expect(openBrowserSecurely('https://example.com')).rejects.toThrow('Unsupported platform');
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
describe('Error handling', () => {
|
|
131
|
+
it('should handle browser launch failures gracefully', async () => {
|
|
132
|
+
setPlatform('darwin');
|
|
133
|
+
mockExecFile.mockRejectedValueOnce(new Error('Command not found'));
|
|
134
|
+
await expect(openBrowserSecurely('https://example.com')).rejects.toThrow('Failed to open browser');
|
|
135
|
+
});
|
|
136
|
+
it('should try fallback browsers on Linux', async () => {
|
|
137
|
+
setPlatform('linux');
|
|
138
|
+
// First call to xdg-open fails
|
|
139
|
+
mockExecFile.mockRejectedValueOnce(new Error('Command not found'));
|
|
140
|
+
// Second call to gnome-open succeeds
|
|
141
|
+
mockExecFile.mockResolvedValueOnce({ stdout: '', stderr: '' });
|
|
142
|
+
await openBrowserSecurely('https://example.com');
|
|
143
|
+
expect(mockExecFile).toHaveBeenCalledTimes(2);
|
|
144
|
+
expect(mockExecFile).toHaveBeenNthCalledWith(1, 'xdg-open', ['https://example.com'], expect.any(Object));
|
|
145
|
+
expect(mockExecFile).toHaveBeenNthCalledWith(2, 'gnome-open', ['https://example.com'], expect.any(Object));
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=secure-browser-launcher.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secure-browser-launcher.test.js","sourceRoot":"","sources":["../../../src/utils/secure-browser-launcher.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { DEFAULT_GEMINI_FLASH_LITE_MODEL } from '../config/models.js';
|
|
7
7
|
import { getResponseText, partToString } from './partUtils.js';
|
|
8
8
|
/**
|
|
9
9
|
* The default summarizer for tool results.
|
|
@@ -40,7 +40,7 @@ export async function summarizeToolOutput(textToSummarize, geminiClient, abortSi
|
|
|
40
40
|
maxOutputTokens,
|
|
41
41
|
};
|
|
42
42
|
try {
|
|
43
|
-
const parsedResponse = (await geminiClient.generateContent(contents, toolOutputSummarizerConfig, abortSignal,
|
|
43
|
+
const parsedResponse = (await geminiClient.generateContent(contents, toolOutputSummarizerConfig, abortSignal, DEFAULT_GEMINI_FLASH_LITE_MODEL));
|
|
44
44
|
return getResponseText(parsedResponse) || textToSummarize;
|
|
45
45
|
}
|
|
46
46
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarizer.js","sourceRoot":"","sources":["../../../src/utils/summarizer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"summarizer.js","sourceRoot":"","sources":["../../../src/utils/summarizer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAc/D;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAe,CAC3C,MAAkB,EAClB,aAA2B,EAC3B,YAAyB,EACzB,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAExD,MAAM,4BAA4B,GAAG;;;;;;;;;;;;CAYpC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAe,CAAC,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,CAC7E,mBAAmB,CACjB,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,EAC/B,YAAY,EACZ,WAAW,CACZ,CAAC;AAEJ,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,eAAuB,EACvB,YAA0B,EAC1B,WAAwB,EACxB,kBAA0B,IAAI;IAE9B,8GAA8G;IAC9G,wFAAwF;IACxF,IAAI,CAAC,eAAe,IAAI,eAAe,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QACjE,OAAO,eAAe,CAAC;IACzB,CAAC;IACD,MAAM,MAAM,GAAG,4BAA4B,CAAC,OAAO,CACjD,mBAAmB,EACnB,MAAM,CAAC,eAAe,CAAC,CACxB,CAAC,OAAO,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC;IAEhD,MAAM,QAAQ,GAAc,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1E,MAAM,0BAA0B,GAA0B;QACxD,eAAe;KAChB,CAAC;IACF,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,CAAC,MAAM,YAAY,CAAC,eAAe,CACxD,QAAQ,EACR,0BAA0B,EAC1B,WAAW,EACX,+BAA+B,CAChC,CAAuC,CAAC;QACzC,OAAO,eAAe,CAAC,cAAc,CAAC,IAAI,eAAe,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,KAAK,CAAC,CAAC;QACzD,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Vybestack LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Sanitizes Unicode strings by handling replacement characters and ensuring
|
|
8
|
+
* proper UTF-8 encoding for API transmission.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Removes or replaces Unicode replacement characters (U+FFFD) from a string.
|
|
12
|
+
* These characters often appear when there are encoding/decoding errors.
|
|
13
|
+
*
|
|
14
|
+
* @param text The text to sanitize
|
|
15
|
+
* @param replacement What to replace U+FFFD with (default: '?')
|
|
16
|
+
* @returns The sanitized text
|
|
17
|
+
*/
|
|
18
|
+
export declare function sanitizeUnicodeReplacements(text: string, replacement?: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Checks if a string contains Unicode replacement characters (U+FFFD).
|
|
21
|
+
*
|
|
22
|
+
* @param text The text to check
|
|
23
|
+
* @returns True if the text contains replacement characters
|
|
24
|
+
*/
|
|
25
|
+
export declare function hasUnicodeReplacements(text: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Ensures a string is safe for JSON serialization and API transmission.
|
|
28
|
+
* This handles various edge cases including:
|
|
29
|
+
* - Unicode replacement characters
|
|
30
|
+
* - Control characters
|
|
31
|
+
* - Invalid surrogate pairs
|
|
32
|
+
*
|
|
33
|
+
* @param text The text to make safe
|
|
34
|
+
* @returns The sanitized text
|
|
35
|
+
*/
|
|
36
|
+
export declare function ensureJsonSafe(text: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Attempts to detect and fix common cp932 (Shift-JIS) decoding issues.
|
|
39
|
+
* This is specifically for Windows Japanese locale users.
|
|
40
|
+
*
|
|
41
|
+
* @param text The text that may have cp932 encoding issues
|
|
42
|
+
* @returns The cleaned text
|
|
43
|
+
*/
|
|
44
|
+
export declare function cleanCp932Artifacts(text: string): string;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Vybestack LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Sanitizes Unicode strings by handling replacement characters and ensuring
|
|
8
|
+
* proper UTF-8 encoding for API transmission.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Removes or replaces Unicode replacement characters (U+FFFD) from a string.
|
|
12
|
+
* These characters often appear when there are encoding/decoding errors.
|
|
13
|
+
*
|
|
14
|
+
* @param text The text to sanitize
|
|
15
|
+
* @param replacement What to replace U+FFFD with (default: '?')
|
|
16
|
+
* @returns The sanitized text
|
|
17
|
+
*/
|
|
18
|
+
export function sanitizeUnicodeReplacements(text, replacement = '?') {
|
|
19
|
+
// U+FFFD is the Unicode replacement character
|
|
20
|
+
return text.replace(/\uFFFD/g, replacement);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Checks if a string contains Unicode replacement characters (U+FFFD).
|
|
24
|
+
*
|
|
25
|
+
* @param text The text to check
|
|
26
|
+
* @returns True if the text contains replacement characters
|
|
27
|
+
*/
|
|
28
|
+
export function hasUnicodeReplacements(text) {
|
|
29
|
+
return /\uFFFD/.test(text);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Ensures a string is safe for JSON serialization and API transmission.
|
|
33
|
+
* This handles various edge cases including:
|
|
34
|
+
* - Unicode replacement characters
|
|
35
|
+
* - Control characters
|
|
36
|
+
* - Invalid surrogate pairs
|
|
37
|
+
*
|
|
38
|
+
* @param text The text to make safe
|
|
39
|
+
* @returns The sanitized text
|
|
40
|
+
*/
|
|
41
|
+
export function ensureJsonSafe(text) {
|
|
42
|
+
// First, handle replacement characters
|
|
43
|
+
let safe = sanitizeUnicodeReplacements(text);
|
|
44
|
+
// Remove control characters except common ones (tab, newline, carriage return)
|
|
45
|
+
let result = '';
|
|
46
|
+
for (let i = 0; i < safe.length; i++) {
|
|
47
|
+
const char = safe[i];
|
|
48
|
+
const code = safe.charCodeAt(i);
|
|
49
|
+
// Keep tab (0x09), newline (0x0A), and carriage return (0x0D)
|
|
50
|
+
if (code === 0x09 || code === 0x0a || code === 0x0d) {
|
|
51
|
+
result += char;
|
|
52
|
+
}
|
|
53
|
+
// Skip other control characters
|
|
54
|
+
else if ((code >= 0x00 && code <= 0x1f) || code === 0x7f) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
// Keep all other characters
|
|
58
|
+
else {
|
|
59
|
+
result += char;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
safe = result;
|
|
63
|
+
// Ensure valid UTF-16 surrogate pairs
|
|
64
|
+
// This regex matches unpaired surrogates
|
|
65
|
+
safe = safe.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, '?');
|
|
66
|
+
return safe;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Attempts to detect and fix common cp932 (Shift-JIS) decoding issues.
|
|
70
|
+
* This is specifically for Windows Japanese locale users.
|
|
71
|
+
*
|
|
72
|
+
* @param text The text that may have cp932 encoding issues
|
|
73
|
+
* @returns The cleaned text
|
|
74
|
+
*/
|
|
75
|
+
export function cleanCp932Artifacts(text) {
|
|
76
|
+
// Common cp932 decoding artifacts when incorrectly decoded as UTF-8
|
|
77
|
+
const commonArtifacts = {
|
|
78
|
+
'髮「': '陰',
|
|
79
|
+
邨ア: '結',
|
|
80
|
+
繧ウ: 'コ',
|
|
81
|
+
繝シ: 'ー',
|
|
82
|
+
'繝。': 'メ',
|
|
83
|
+
繝ウ: 'ン',
|
|
84
|
+
繝医: 'ト',
|
|
85
|
+
// Add more common patterns as discovered
|
|
86
|
+
};
|
|
87
|
+
let cleaned = text;
|
|
88
|
+
for (const [artifact, replacement] of Object.entries(commonArtifacts)) {
|
|
89
|
+
cleaned = cleaned.replace(new RegExp(artifact, 'g'), replacement);
|
|
90
|
+
}
|
|
91
|
+
return cleaned;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=unicodeUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unicodeUtils.js","sourceRoot":"","sources":["../../../src/utils/unicodeUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CACzC,IAAY,EACZ,cAAsB,GAAG;IAEzB,8CAA8C;IAC9C,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,uCAAuC;IACvC,IAAI,IAAI,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAC;IAE7C,+EAA+E;IAC/E,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAEhC,8DAA8D;QAC9D,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YACpD,MAAM,IAAI,IAAI,CAAC;QACjB,CAAC;QACD,gCAAgC;aAC3B,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YACzD,SAAS;QACX,CAAC;QACD,4BAA4B;aACvB,CAAC;YACJ,MAAM,IAAI,IAAI,CAAC;QACjB,CAAC;IACH,CAAC;IACD,IAAI,GAAG,MAAM,CAAC;IAEd,sCAAsC;IACtC,yCAAyC;IACzC,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,yEAAyE,EACzE,GAAG,CACJ,CAAC;IAEF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,oEAAoE;IACpE,MAAM,eAAe,GAA8B;QACjD,IAAI,EAAE,GAAG;QACT,EAAE,EAAE,GAAG;QACP,EAAE,EAAE,GAAG;QACP,EAAE,EAAE,GAAG;QACP,IAAI,EAAE,GAAG;QACT,EAAE,EAAE,GAAG;QACP,EAAE,EAAE,GAAG;QACP,yCAAyC;KAC1C,CAAC;IAEF,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,KAAK,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;QACtE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,WAAW,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Vybestack LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import { sanitizeUnicodeReplacements, hasUnicodeReplacements, ensureJsonSafe, cleanCp932Artifacts, } from './unicodeUtils.js';
|
|
8
|
+
describe('Unicode utilities regression tests', () => {
|
|
9
|
+
describe('sanitizeUnicodeReplacements', () => {
|
|
10
|
+
it('should remove Unicode replacement characters', () => {
|
|
11
|
+
const input = 'Hello\uFFFDWorld\uFFFD!';
|
|
12
|
+
const result = sanitizeUnicodeReplacements(input);
|
|
13
|
+
expect(result).toBe('Hello?World?!');
|
|
14
|
+
expect(result).not.toContain('\uFFFD');
|
|
15
|
+
});
|
|
16
|
+
it('should use custom replacement when specified', () => {
|
|
17
|
+
const input = 'Data\uFFFDCorrupted';
|
|
18
|
+
const result = sanitizeUnicodeReplacements(input, '[INVALID]');
|
|
19
|
+
expect(result).toBe('Data[INVALID]Corrupted');
|
|
20
|
+
});
|
|
21
|
+
it('should handle multiple consecutive replacement characters', () => {
|
|
22
|
+
const input = 'Test\uFFFD\uFFFD\uFFFDEnd';
|
|
23
|
+
const result = sanitizeUnicodeReplacements(input);
|
|
24
|
+
expect(result).toBe('Test???End');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe('hasUnicodeReplacements', () => {
|
|
28
|
+
it('should detect Unicode replacement characters', () => {
|
|
29
|
+
expect(hasUnicodeReplacements('Normal text')).toBe(false);
|
|
30
|
+
expect(hasUnicodeReplacements('Text with \uFFFD')).toBe(true);
|
|
31
|
+
expect(hasUnicodeReplacements('\uFFFD')).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe('ensureJsonSafe', () => {
|
|
35
|
+
it('should remove control characters except tab, newline, and carriage return', () => {
|
|
36
|
+
const input = 'Text\x00with\x01control\x02chars\nkeep\ttabs\r';
|
|
37
|
+
const result = ensureJsonSafe(input);
|
|
38
|
+
expect(result).toBe('Textwithcontrolchars\nkeep\ttabs\r');
|
|
39
|
+
expect(result).toContain('\n');
|
|
40
|
+
expect(result).toContain('\t');
|
|
41
|
+
expect(result).toContain('\r');
|
|
42
|
+
expect(result).not.toContain('\x00');
|
|
43
|
+
expect(result).not.toContain('\x01');
|
|
44
|
+
expect(result).not.toContain('\x02');
|
|
45
|
+
});
|
|
46
|
+
it('should handle Unicode replacement characters', () => {
|
|
47
|
+
const input = 'JSON\uFFFDSafe';
|
|
48
|
+
const result = ensureJsonSafe(input);
|
|
49
|
+
expect(result).toBe('JSON?Safe');
|
|
50
|
+
});
|
|
51
|
+
it('should fix invalid surrogate pairs', () => {
|
|
52
|
+
// Unpaired high surrogate
|
|
53
|
+
const input1 = 'Test\uD800End';
|
|
54
|
+
const result1 = ensureJsonSafe(input1);
|
|
55
|
+
expect(result1).toBe('Test?End');
|
|
56
|
+
// Unpaired low surrogate
|
|
57
|
+
const input2 = 'Test\uDC00End';
|
|
58
|
+
const result2 = ensureJsonSafe(input2);
|
|
59
|
+
expect(result2).toBe('Test?End');
|
|
60
|
+
// Valid surrogate pair (should be preserved)
|
|
61
|
+
const input3 = 'Test\uD83D\uDE00End'; // 😀
|
|
62
|
+
const result3 = ensureJsonSafe(input3);
|
|
63
|
+
expect(result3).toBe('Test😀End');
|
|
64
|
+
});
|
|
65
|
+
it('should handle mixed issues in one string', () => {
|
|
66
|
+
const input = 'Mixed\x00\uFFFD\uD800issues\x7F';
|
|
67
|
+
const result = ensureJsonSafe(input);
|
|
68
|
+
expect(result).toBe('Mixed??issues');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('cleanCp932Artifacts', () => {
|
|
72
|
+
it('should clean common cp932 decoding artifacts', () => {
|
|
73
|
+
const input = '髮「繧ウ繝シ繝。繝ウ繝医';
|
|
74
|
+
const result = cleanCp932Artifacts(input);
|
|
75
|
+
expect(result).toBe('陰コーメント');
|
|
76
|
+
});
|
|
77
|
+
it('should handle multiple artifacts in one string', () => {
|
|
78
|
+
const input = '邨ア髮「';
|
|
79
|
+
const result = cleanCp932Artifacts(input);
|
|
80
|
+
expect(result).toBe('結陰');
|
|
81
|
+
});
|
|
82
|
+
it('should leave non-artifact text unchanged', () => {
|
|
83
|
+
const input = 'Normal Japanese text: こんにちは';
|
|
84
|
+
const result = cleanCp932Artifacts(input);
|
|
85
|
+
expect(result).toBe(input);
|
|
86
|
+
});
|
|
87
|
+
it('should handle mixed artifact and normal text', () => {
|
|
88
|
+
const input = 'Before 髮「 after 繧ウ end';
|
|
89
|
+
const result = cleanCp932Artifacts(input);
|
|
90
|
+
expect(result).toBe('Before 陰 after コ end');
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe('Real-world scenarios', () => {
|
|
94
|
+
it('should handle API key with encoding issues', () => {
|
|
95
|
+
// Simulate an API key read from a file with encoding issues
|
|
96
|
+
const apiKey = 'sk-1234567890abcdef\uFFFDghijklmnop\x00';
|
|
97
|
+
const cleaned = ensureJsonSafe(apiKey);
|
|
98
|
+
expect(cleaned).toBe('sk-1234567890abcdef?ghijklmnop');
|
|
99
|
+
expect(cleaned).not.toContain('\uFFFD');
|
|
100
|
+
expect(cleaned).not.toContain('\x00');
|
|
101
|
+
});
|
|
102
|
+
it('should handle shell output with cp932 artifacts', () => {
|
|
103
|
+
// Simulate garbled Japanese error message from Windows shell
|
|
104
|
+
// Using artifacts we have mappings for
|
|
105
|
+
const shellOutput = 'Error: 繧ウ繝シ繝。繝ウ繝医′髮「';
|
|
106
|
+
const cleaned = cleanCp932Artifacts(shellOutput);
|
|
107
|
+
// Should clean to: "Error: コーメントが陰"
|
|
108
|
+
expect(cleaned).not.toBe(shellOutput);
|
|
109
|
+
expect(cleaned).toContain('コーメント');
|
|
110
|
+
});
|
|
111
|
+
it('should make API request content safe', () => {
|
|
112
|
+
const userInput = 'User message with\uFFFDencoding issues\x00and control chars';
|
|
113
|
+
const safe = ensureJsonSafe(userInput);
|
|
114
|
+
// Should be safe to JSON stringify
|
|
115
|
+
expect(() => JSON.stringify({ content: safe })).not.toThrow();
|
|
116
|
+
expect(safe).toBe('User message with?encoding issuesand control chars');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
//# sourceMappingURL=unicodeUtils.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unicodeUtils.test.js","sourceRoot":"","sources":["../../../src/utils/unicodeUtils.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* WorkspaceContext manages multiple workspace directories and validates paths
|
|
8
|
+
* against them. This allows the CLI to operate on files from multiple directories
|
|
9
|
+
* in a single session.
|
|
10
|
+
*/
|
|
11
|
+
export declare class WorkspaceContext {
|
|
12
|
+
private directories;
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new WorkspaceContext with the given initial directory and optional additional directories.
|
|
15
|
+
* @param initialDirectory The initial working directory (usually cwd)
|
|
16
|
+
* @param additionalDirectories Optional array of additional directories to include
|
|
17
|
+
*/
|
|
18
|
+
constructor(initialDirectory: string, additionalDirectories?: string[]);
|
|
19
|
+
/**
|
|
20
|
+
* Adds a directory to the workspace.
|
|
21
|
+
* @param directory The directory path to add (can be relative or absolute)
|
|
22
|
+
* @param basePath Optional base path for resolving relative paths (defaults to cwd)
|
|
23
|
+
*/
|
|
24
|
+
addDirectory(directory: string, basePath?: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Internal method to add a directory with validation.
|
|
27
|
+
*/
|
|
28
|
+
private addDirectoryInternal;
|
|
29
|
+
/**
|
|
30
|
+
* Gets a copy of all workspace directories.
|
|
31
|
+
* @returns Array of absolute directory paths
|
|
32
|
+
*/
|
|
33
|
+
getDirectories(): readonly string[];
|
|
34
|
+
/**
|
|
35
|
+
* Checks if a given path is within any of the workspace directories.
|
|
36
|
+
* @param pathToCheck The path to validate
|
|
37
|
+
* @returns True if the path is within the workspace, false otherwise
|
|
38
|
+
*/
|
|
39
|
+
isPathWithinWorkspace(pathToCheck: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Checks if a path is within a given root directory.
|
|
42
|
+
* @param pathToCheck The absolute path to check
|
|
43
|
+
* @param rootDirectory The absolute root directory
|
|
44
|
+
* @returns True if the path is within the root directory, false otherwise
|
|
45
|
+
*/
|
|
46
|
+
private isPathWithinRoot;
|
|
47
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
/**
|
|
9
|
+
* WorkspaceContext manages multiple workspace directories and validates paths
|
|
10
|
+
* against them. This allows the CLI to operate on files from multiple directories
|
|
11
|
+
* in a single session.
|
|
12
|
+
*/
|
|
13
|
+
export class WorkspaceContext {
|
|
14
|
+
directories;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new WorkspaceContext with the given initial directory and optional additional directories.
|
|
17
|
+
* @param initialDirectory The initial working directory (usually cwd)
|
|
18
|
+
* @param additionalDirectories Optional array of additional directories to include
|
|
19
|
+
*/
|
|
20
|
+
constructor(initialDirectory, additionalDirectories = []) {
|
|
21
|
+
this.directories = new Set();
|
|
22
|
+
this.addDirectoryInternal(initialDirectory);
|
|
23
|
+
for (const dir of additionalDirectories) {
|
|
24
|
+
this.addDirectoryInternal(dir);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Adds a directory to the workspace.
|
|
29
|
+
* @param directory The directory path to add (can be relative or absolute)
|
|
30
|
+
* @param basePath Optional base path for resolving relative paths (defaults to cwd)
|
|
31
|
+
*/
|
|
32
|
+
addDirectory(directory, basePath = process.cwd()) {
|
|
33
|
+
this.addDirectoryInternal(directory, basePath);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Internal method to add a directory with validation.
|
|
37
|
+
*/
|
|
38
|
+
addDirectoryInternal(directory, basePath = process.cwd()) {
|
|
39
|
+
const absolutePath = path.isAbsolute(directory)
|
|
40
|
+
? directory
|
|
41
|
+
: path.resolve(basePath, directory);
|
|
42
|
+
if (!fs.existsSync(absolutePath)) {
|
|
43
|
+
throw new Error(`Directory does not exist: ${absolutePath}`);
|
|
44
|
+
}
|
|
45
|
+
const stats = fs.statSync(absolutePath);
|
|
46
|
+
if (!stats.isDirectory()) {
|
|
47
|
+
throw new Error(`Path is not a directory: ${absolutePath}`);
|
|
48
|
+
}
|
|
49
|
+
let realPath;
|
|
50
|
+
try {
|
|
51
|
+
realPath = fs.realpathSync(absolutePath);
|
|
52
|
+
}
|
|
53
|
+
catch (_error) {
|
|
54
|
+
throw new Error(`Failed to resolve path: ${absolutePath}`);
|
|
55
|
+
}
|
|
56
|
+
this.directories.add(realPath);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Gets a copy of all workspace directories.
|
|
60
|
+
* @returns Array of absolute directory paths
|
|
61
|
+
*/
|
|
62
|
+
getDirectories() {
|
|
63
|
+
return Array.from(this.directories);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Checks if a given path is within any of the workspace directories.
|
|
67
|
+
* @param pathToCheck The path to validate
|
|
68
|
+
* @returns True if the path is within the workspace, false otherwise
|
|
69
|
+
*/
|
|
70
|
+
isPathWithinWorkspace(pathToCheck) {
|
|
71
|
+
try {
|
|
72
|
+
const absolutePath = path.resolve(pathToCheck);
|
|
73
|
+
let resolvedPath = absolutePath;
|
|
74
|
+
if (fs.existsSync(absolutePath)) {
|
|
75
|
+
try {
|
|
76
|
+
resolvedPath = fs.realpathSync(absolutePath);
|
|
77
|
+
}
|
|
78
|
+
catch (_error) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
for (const dir of this.directories) {
|
|
83
|
+
if (this.isPathWithinRoot(resolvedPath, dir)) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
catch (_error) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Checks if a path is within a given root directory.
|
|
95
|
+
* @param pathToCheck The absolute path to check
|
|
96
|
+
* @param rootDirectory The absolute root directory
|
|
97
|
+
* @returns True if the path is within the root directory, false otherwise
|
|
98
|
+
*/
|
|
99
|
+
isPathWithinRoot(pathToCheck, rootDirectory) {
|
|
100
|
+
const relative = path.relative(rootDirectory, pathToCheck);
|
|
101
|
+
return (!relative.startsWith(`..${path.sep}`) &&
|
|
102
|
+
relative !== '..' &&
|
|
103
|
+
!path.isAbsolute(relative));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=workspaceContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaceContext.js","sourceRoot":"","sources":["../../../src/utils/workspaceContext.ts"],"names":[],"mappings":"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"}
|