@crownpeak/dqm-react-component-dev-mcp 1.2.0
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 +138 -0
- package/data/.env.example +22 -0
- package/data/.gitattributes +47 -0
- package/data/.glfrc.json +7 -0
- package/data/.husky/pre-commit +5 -0
- package/data/.nvmrc +1 -0
- package/data/CHANGELOG.md +75 -0
- package/data/CODE_OF_CONDUCT.md +129 -0
- package/data/CONTRIBUTING.md +203 -0
- package/data/DOCS-STRUCTURE.md +307 -0
- package/data/I18N.md +292 -0
- package/data/LICENSE +22 -0
- package/data/README.md +315 -0
- package/data/SECURITY.md +125 -0
- package/data/WIKI-DEPLOYMENT.md +348 -0
- package/data/docs/AI-FEATURES.md +610 -0
- package/data/docs/API-REFERENCE.md +1022 -0
- package/data/docs/AUTHENTICATION.md +301 -0
- package/data/docs/BACKEND-API.md +468 -0
- package/data/docs/DEVELOPMENT.md +375 -0
- package/data/docs/EXAMPLES.md +622 -0
- package/data/docs/MCP-SERVER.md +307 -0
- package/data/docs/MIGRATION-GUIDE.md +367 -0
- package/data/docs/NPM-PUBLISH.md +193 -0
- package/data/docs/QUICKSTART.md +206 -0
- package/data/docs/REDIS-SETUP.md +162 -0
- package/data/docs/SERVER.md +228 -0
- package/data/docs/TROUBLESHOOTING.md +657 -0
- package/data/docs/WIDGET-GUIDE.md +638 -0
- package/data/docs/WIKI-HOME.md +58 -0
- package/data/docs/WIKI-SIDEBAR.md +39 -0
- package/data/package.json +171 -0
- package/data/playwright.config.ts +64 -0
- package/data/probe/.cargo/config.toml +10 -0
- package/data/probe/.claude/commands/performance-review.md +15 -0
- package/data/probe/.clinerules +288 -0
- package/data/probe/.dockerignore +57 -0
- package/data/probe/.githooks/post-commit +11 -0
- package/data/probe/.githooks/pre-commit +99 -0
- package/data/probe/.githooks/pre-commit-vow +9 -0
- package/data/probe/.prompts/engineer.md +41 -0
- package/data/probe/.roomodes +28 -0
- package/data/probe/.windsurfrules +0 -0
- package/data/probe/BASH_TOOL_SUMMARY.md +148 -0
- package/data/probe/BENCHMARKING.md +256 -0
- package/data/probe/CLAUDE.md +226 -0
- package/data/probe/CODE_OF_CONDUCT.md +128 -0
- package/data/probe/CONTRIBUTING.md +193 -0
- package/data/probe/Cargo.toml +120 -0
- package/data/probe/Cross.toml +10 -0
- package/data/probe/DOCKER-README.md +224 -0
- package/data/probe/Dockerfile +32 -0
- package/data/probe/ENHANCED_DEBUG_TELEMETRY.md +188 -0
- package/data/probe/LICENSE +201 -0
- package/data/probe/Makefile +210 -0
- package/data/probe/README.md +824 -0
- package/data/probe/SECURITY.md +67 -0
- package/data/probe/WINDOWS-GUIDE.md +294 -0
- package/data/probe/benches/parsing_benchmarks.rs +370 -0
- package/data/probe/benches/search_benchmarks.rs +599 -0
- package/data/probe/benches/simd_benchmarks.rs +372 -0
- package/data/probe/benches/timing_benchmarks.rs +287 -0
- package/data/probe/build-windows.bat +229 -0
- package/data/probe/codex-config/config.toml +6 -0
- package/data/probe/docs/PERFORMANCE_OPTIMIZATION.md +161 -0
- package/data/probe/examples/cache_demo.rs +46 -0
- package/data/probe/examples/chat/.dockerignore +37 -0
- package/data/probe/examples/chat/ChatSessionManager.js +295 -0
- package/data/probe/examples/chat/Dockerfile +98 -0
- package/data/probe/examples/chat/LICENSE +201 -0
- package/data/probe/examples/chat/LOCAL_IMAGE_SUPPORT.md +195 -0
- package/data/probe/examples/chat/MCP_INTEGRATION.md +400 -0
- package/data/probe/examples/chat/README.md +338 -0
- package/data/probe/examples/chat/TRACING.md +226 -0
- package/data/probe/examples/chat/appTracer.js +968 -0
- package/data/probe/examples/chat/auth.js +76 -0
- package/data/probe/examples/chat/bin/probe-chat.js +13 -0
- package/data/probe/examples/chat/build.js +104 -0
- package/data/probe/examples/chat/cancelRequest.js +84 -0
- package/data/probe/examples/chat/demo-agentic-image-flow.js +88 -0
- package/data/probe/examples/chat/demo-local-images.js +128 -0
- package/data/probe/examples/chat/fileSpanExporter.js +181 -0
- package/data/probe/examples/chat/implement/README.md +228 -0
- package/data/probe/examples/chat/implement/backends/AiderBackend.js +750 -0
- package/data/probe/examples/chat/implement/backends/BaseBackend.js +276 -0
- package/data/probe/examples/chat/implement/backends/ClaudeCodeBackend.js +767 -0
- package/data/probe/examples/chat/implement/backends/MockBackend.js +237 -0
- package/data/probe/examples/chat/implement/backends/registry.js +85 -0
- package/data/probe/examples/chat/implement/core/BackendManager.js +567 -0
- package/data/probe/examples/chat/implement/core/ImplementTool.js +354 -0
- package/data/probe/examples/chat/implement/core/config.js +428 -0
- package/data/probe/examples/chat/implement/core/timeouts.js +58 -0
- package/data/probe/examples/chat/implement/core/utils.js +496 -0
- package/data/probe/examples/chat/implement/types/BackendTypes.js +126 -0
- package/data/probe/examples/chat/index.js +669 -0
- package/data/probe/examples/chat/mcpServer.js +341 -0
- package/data/probe/examples/chat/npm/LICENSE +15 -0
- package/data/probe/examples/chat/npm/README.md +168 -0
- package/data/probe/examples/chat/npm/bin/probe-chat.js +156 -0
- package/data/probe/examples/chat/npm/index.js +259 -0
- package/data/probe/examples/chat/npm/package.json +54 -0
- package/data/probe/examples/chat/package.json +102 -0
- package/data/probe/examples/chat/probeChat.js +456 -0
- package/data/probe/examples/chat/probeTool.js +491 -0
- package/data/probe/examples/chat/storage/JsonChatStorage.js +476 -0
- package/data/probe/examples/chat/telemetry.js +281 -0
- package/data/probe/examples/chat/test/integration/chatFlows.test.js +320 -0
- package/data/probe/examples/chat/test/integration/toolCalling.test.js +471 -0
- package/data/probe/examples/chat/test/mocks/mockLLMProvider.js +269 -0
- package/data/probe/examples/chat/test/test-backends.js +90 -0
- package/data/probe/examples/chat/test/testUtils.js +530 -0
- package/data/probe/examples/chat/test/unit/backendTimeout.test.js +161 -0
- package/data/probe/examples/chat/test/unit/packageFiles.test.js +120 -0
- package/data/probe/examples/chat/test/verify-tests.js +118 -0
- package/data/probe/examples/chat/test-agentic-image-loading.js +294 -0
- package/data/probe/examples/chat/test-ai-sdk-telemetry.js +204 -0
- package/data/probe/examples/chat/test-chat-tracing.js +38 -0
- package/data/probe/examples/chat/test-direct-function.js +49 -0
- package/data/probe/examples/chat/test-file-size-validation.js +103 -0
- package/data/probe/examples/chat/test-full-mcp-integration.js +258 -0
- package/data/probe/examples/chat/test-github-context.txt +12 -0
- package/data/probe/examples/chat/test-hierarchy.js +203 -0
- package/data/probe/examples/chat/test-image-spans.js +37 -0
- package/data/probe/examples/chat/test-local-image-reading.js +176 -0
- package/data/probe/examples/chat/test-mcp-integration.js +136 -0
- package/data/probe/examples/chat/test-mcp-probe-server.js +161 -0
- package/data/probe/examples/chat/test-mcp-with-ai.js +279 -0
- package/data/probe/examples/chat/test-multiple-allowed-dirs.js +111 -0
- package/data/probe/examples/chat/test-probe-mcp-server.js +110 -0
- package/data/probe/examples/chat/test-security-validation.js +145 -0
- package/data/probe/examples/chat/test-simple-tracing.js +32 -0
- package/data/probe/examples/chat/test-trace-verification.js +235 -0
- package/data/probe/examples/chat/test-tracing.js +114 -0
- package/data/probe/examples/chat/tokenCounter.js +419 -0
- package/data/probe/examples/chat/tokenUsageDisplay.js +134 -0
- package/data/probe/examples/chat/webServer.js +1103 -0
- package/data/probe/examples/reranker/Cargo.toml +33 -0
- package/data/probe/examples/reranker/DEBUG_OUTPUT_ANALYSIS.md +71 -0
- package/data/probe/examples/reranker/MODELS.md +66 -0
- package/data/probe/examples/reranker/MODEL_COMPARISON.md +60 -0
- package/data/probe/examples/reranker/MULTI_MODEL_ANALYSIS.md +176 -0
- package/data/probe/examples/reranker/PERFORMANCE_SUMMARY.md +156 -0
- package/data/probe/examples/reranker/README.md +347 -0
- package/data/probe/examples/reranker/RUST_BERT_COMPARISON.md +82 -0
- package/data/probe/examples/reranker/TOKENIZATION_GUIDE.md +120 -0
- package/data/probe/examples/reranker/check_rust_tokenizer.py +108 -0
- package/data/probe/examples/reranker/convert_to_torchscript.py +109 -0
- package/data/probe/examples/reranker/debug_scoring.py +189 -0
- package/data/probe/examples/reranker/debug_tokenization.py +154 -0
- package/data/probe/examples/reranker/download_models.sh +73 -0
- package/data/probe/examples/reranker/requirements.txt +13 -0
- package/data/probe/examples/reranker/run_comprehensive_benchmark.sh +83 -0
- package/data/probe/examples/reranker/rust_bert_test/Cargo.toml +12 -0
- package/data/probe/examples/reranker/rust_bert_test/README.md +54 -0
- package/data/probe/examples/reranker/simple_test.py +50 -0
- package/data/probe/examples/reranker/test_all_models.sh +63 -0
- package/data/probe/examples/reranker/test_bert_results.sh +44 -0
- package/data/probe/examples/reranker/test_cross_encoder.py +334 -0
- package/data/probe/examples/reranker/test_cross_encoder.sh +80 -0
- package/data/probe/examples/reranker/test_exact_comparison.py +151 -0
- package/data/probe/examples/reranker/test_parallel_performance.sh +56 -0
- package/data/probe/examples/reranker/test_scores.py +132 -0
- package/data/probe/install.ps1 +508 -0
- package/data/probe/install.sh +460 -0
- package/data/probe/npm/CLONE_METHOD_EXAMPLES.md +596 -0
- package/data/probe/npm/CONTEXT_COMPACTION.md +303 -0
- package/data/probe/npm/DELEGATE_TOOL_README.md +166 -0
- package/data/probe/npm/MAID_INTEGRATION.md +313 -0
- package/data/probe/npm/MCP_INTEGRATION_SUMMARY.md +241 -0
- package/data/probe/npm/README.md +824 -0
- package/data/probe/npm/bin/.gitignore +7 -0
- package/data/probe/npm/bin/.gitkeep +0 -0
- package/data/probe/npm/bin/README.md +12 -0
- package/data/probe/npm/bin/probe +167 -0
- package/data/probe/npm/docs/CLAUDE_CODE_INTEGRATION.md +414 -0
- package/data/probe/npm/docs/CODEX_INTEGRATION.md +502 -0
- package/data/probe/npm/docs/EDIT_CREATE_TOOLS.md +233 -0
- package/data/probe/npm/docs/RETRY_AND_FALLBACK.md +674 -0
- package/data/probe/npm/example-usage.js +335 -0
- package/data/probe/npm/examples/multi-engine-demo.js +117 -0
- package/data/probe/npm/examples/probe-agent-cli.js +113 -0
- package/data/probe/npm/examples/test-agent-edit.js +114 -0
- package/data/probe/npm/examples/test-edit-create.js +120 -0
- package/data/probe/npm/examples/test-edit-direct.js +114 -0
- package/data/probe/npm/index.d.ts +744 -0
- package/data/probe/npm/jest.config.js +52 -0
- package/data/probe/npm/package.json +117 -0
- package/data/probe/npm/scripts/build-agent.cjs +75 -0
- package/data/probe/npm/scripts/build-cjs.js +124 -0
- package/data/probe/npm/scripts/build-mcp.cjs +36 -0
- package/data/probe/npm/scripts/postinstall.js +216 -0
- package/data/probe/npm/test-codex-e2e.js +78 -0
- package/data/probe/npm/test-download-lock.js +109 -0
- package/data/probe/npm/test-grep-security.js +94 -0
- package/data/probe/npm/test-grep-simplified.js +63 -0
- package/data/probe/npm/test-grep.js +51 -0
- package/data/probe/npm/tests/README.md +96 -0
- package/data/probe/npm/tests/agent-compact-history.test.js +174 -0
- package/data/probe/npm/tests/allow-tests-default.test.js +151 -0
- package/data/probe/npm/tests/contextCompactor.test.js +498 -0
- package/data/probe/npm/tests/delegate-config.test.js +353 -0
- package/data/probe/npm/tests/delegate-integration.test.js +348 -0
- package/data/probe/npm/tests/extractor-integration.test.js +162 -0
- package/data/probe/npm/tests/extractor.test.js +317 -0
- package/data/probe/npm/tests/fixtures/sampleDiagrams.js +267 -0
- package/data/probe/npm/tests/integration/claude-code-auto-fallback.spec.js +148 -0
- package/data/probe/npm/tests/integration/claude-code-multi-step.spec.js +127 -0
- package/data/probe/npm/tests/integration/claude-code-tool-events.spec.js +163 -0
- package/data/probe/npm/tests/integration/codex-auto-fallback.spec.js +191 -0
- package/data/probe/npm/tests/integration/codex-tool-events.spec.js +147 -0
- package/data/probe/npm/tests/integration/examplesChatMcp.test.js +402 -0
- package/data/probe/npm/tests/integration/mcpDotenvSupport.test.js +174 -0
- package/data/probe/npm/tests/integration/mcpErrorHandling.test.js +566 -0
- package/data/probe/npm/tests/integration/mcpRobustness.test.js +564 -0
- package/data/probe/npm/tests/integration/mcpStdoutPurity.test.js +355 -0
- package/data/probe/npm/tests/integration/probeAgentMcp.test.js +398 -0
- package/data/probe/npm/tests/integration/retryFallback.test.js +368 -0
- package/data/probe/npm/tests/integration/schema-in-initial-message.test.js +318 -0
- package/data/probe/npm/tests/integration/schema-validation-loop-prevention.test.js +244 -0
- package/data/probe/npm/tests/integration/schemaRetryLogic.test.js +94 -0
- package/data/probe/npm/tests/integration/validationFlow.test.js +329 -0
- package/data/probe/npm/tests/manual/test-codex-basic.js +110 -0
- package/data/probe/npm/tests/mcp/mcpClientManager.test.js +614 -0
- package/data/probe/npm/tests/mcp/mcpConfig.test.js +359 -0
- package/data/probe/npm/tests/mcp/mcpXmlBridge.test.js +436 -0
- package/data/probe/npm/tests/mcp/mockMcpServer.js +510 -0
- package/data/probe/npm/tests/mcp-strict-syntax.test.js +319 -0
- package/data/probe/npm/tests/mermaidQuoteEscaping.test.js +214 -0
- package/data/probe/npm/tests/nestedQuoteFix.test.js +40 -0
- package/data/probe/npm/tests/setup.js +46 -0
- package/data/probe/npm/tests/unit/allowed-tools.test.js +513 -0
- package/data/probe/npm/tests/unit/attempt-completion-closing-tag-in-content.test.js +188 -0
- package/data/probe/npm/tests/unit/attemptCompletionJsonFix.test.js +238 -0
- package/data/probe/npm/tests/unit/attemptCompletionJsonIssue.test.js +128 -0
- package/data/probe/npm/tests/unit/backtickAutoFix.test.js +35 -0
- package/data/probe/npm/tests/unit/bash-probe-agent-integration.test.js +389 -0
- package/data/probe/npm/tests/unit/bash-simple-commands.test.js +324 -0
- package/data/probe/npm/tests/unit/bash-tool-comprehensive.test.js +371 -0
- package/data/probe/npm/tests/unit/bash-tool-integration.test.js +310 -0
- package/data/probe/npm/tests/unit/bash-tool.test.js +341 -0
- package/data/probe/npm/tests/unit/completion-prompt.test.js +379 -0
- package/data/probe/npm/tests/unit/cwd-path-options.test.js +287 -0
- package/data/probe/npm/tests/unit/delegate-limits.test.js +422 -0
- package/data/probe/npm/tests/unit/direct-content-attempt-completion.test.js +235 -0
- package/data/probe/npm/tests/unit/edit-create-tools.test.js +609 -0
- package/data/probe/npm/tests/unit/enhancedMermaidValidation.test.js +577 -0
- package/data/probe/npm/tests/unit/extract-content.test.js +83 -0
- package/data/probe/npm/tests/unit/extract-multiple-targets.test.js +89 -0
- package/data/probe/npm/tests/unit/fallbackManager.test.js +442 -0
- package/data/probe/npm/tests/unit/githubCompatibilityValidation.test.js +258 -0
- package/data/probe/npm/tests/unit/imageConfig.test.js +149 -0
- package/data/probe/npm/tests/unit/imagePathResolution.test.js +345 -0
- package/data/probe/npm/tests/unit/json-fixing-agent.test.js +238 -0
- package/data/probe/npm/tests/unit/json-validation-enhanced-errors.test.js +199 -0
- package/data/probe/npm/tests/unit/jsonValidationInfiniteLoopFix.test.js +228 -0
- package/data/probe/npm/tests/unit/maidIntegration.test.js +139 -0
- package/data/probe/npm/tests/unit/maxIterationsWarning.test.js +195 -0
- package/data/probe/npm/tests/unit/mermaidEdgeLabelFix.test.js +161 -0
- package/data/probe/npm/tests/unit/mermaidHtmlEntities.test.js +76 -0
- package/data/probe/npm/tests/unit/mermaidInfiniteLoopFix.test.js +64 -0
- package/data/probe/npm/tests/unit/mermaidValidation.test.js +723 -0
- package/data/probe/npm/tests/unit/mermaidValidationVisorExample.test.js +309 -0
- package/data/probe/npm/tests/unit/probe-agent-clone-realistic.test.js +643 -0
- package/data/probe/npm/tests/unit/probe-agent-clone.test.js +476 -0
- package/data/probe/npm/tests/unit/probe-agent-delegate.test.js +400 -0
- package/data/probe/npm/tests/unit/probe-agent-model-option.test.js +118 -0
- package/data/probe/npm/tests/unit/probeTool-security.test.js +283 -0
- package/data/probe/npm/tests/unit/readImageTool.test.js +418 -0
- package/data/probe/npm/tests/unit/retryManager.test.js +317 -0
- package/data/probe/npm/tests/unit/schema-aware-reminders.test.js +288 -0
- package/data/probe/npm/tests/unit/schemaDefinitionDetection.test.js +115 -0
- package/data/probe/npm/tests/unit/schemaUtils.test.js +1268 -0
- package/data/probe/npm/tests/unit/simpleTelemetry.test.js +282 -0
- package/data/probe/npm/tests/unit/simplified-attempt-completion.test.js +274 -0
- package/data/probe/npm/tests/unit/single-quote-json-bug.test.js +231 -0
- package/data/probe/npm/tests/unit/subgraphAutoFix.test.js +110 -0
- package/data/probe/npm/tests/unit/system-prompt.test.js +32 -0
- package/data/probe/npm/tests/unit/types-probe-agent-options.test.js +42 -0
- package/data/probe/npm/tests/unit/xmlParsing.test.js +720 -0
- package/data/probe/npm/tsconfig.json +21 -0
- package/data/probe/result1.txt +19 -0
- package/data/probe/result2.txt +26 -0
- package/data/probe/scripts/benchmark.sh +270 -0
- package/data/probe/scripts/cache_memory_analysis.rs +844 -0
- package/data/probe/scripts/claude-hook-wrapper.sh +56 -0
- package/data/probe/site/.env.example +10 -0
- package/data/probe/site/DEPLOYMENT.md +86 -0
- package/data/probe/site/README.md +183 -0
- package/data/probe/site/adding-languages.md +135 -0
- package/data/probe/site/ai-chat.md +427 -0
- package/data/probe/site/ai-integration.md +1488 -0
- package/data/probe/site/blog/agentic-flow-custom-xml-protocol.md +407 -0
- package/data/probe/site/blog/index.md +118 -0
- package/data/probe/site/blog/v0.6.0-release.md +426 -0
- package/data/probe/site/blog.md +8 -0
- package/data/probe/site/changelog.md +200 -0
- package/data/probe/site/cli-mode.md +437 -0
- package/data/probe/site/code-extraction.md +436 -0
- package/data/probe/site/contributing/README.md +9 -0
- package/data/probe/site/contributing/documentation-cross-references.md +215 -0
- package/data/probe/site/contributing/documentation-maintenance.md +275 -0
- package/data/probe/site/contributing/documentation-structure.md +75 -0
- package/data/probe/site/documentation-cross-references.md +215 -0
- package/data/probe/site/documentation-guide.md +132 -0
- package/data/probe/site/documentation-maintenance.md +275 -0
- package/data/probe/site/features.md +147 -0
- package/data/probe/site/how-it-works.md +118 -0
- package/data/probe/site/index.md +175 -0
- package/data/probe/site/index.md.bak +133 -0
- package/data/probe/site/installation.md +235 -0
- package/data/probe/site/integrations/docker.md +248 -0
- package/data/probe/site/integrations/github-actions.md +413 -0
- package/data/probe/site/language-support-overview.md +168 -0
- package/data/probe/site/mcp-integration.md +587 -0
- package/data/probe/site/mcp-server.md +304 -0
- package/data/probe/site/navigation-structure.md +76 -0
- package/data/probe/site/nodejs-sdk.md +798 -0
- package/data/probe/site/output-formats.md +625 -0
- package/data/probe/site/package.json +21 -0
- package/data/probe/site/public/_headers +28 -0
- package/data/probe/site/public/_redirects +11 -0
- package/data/probe/site/quick-start.md +289 -0
- package/data/probe/site/search-functionality.md +291 -0
- package/data/probe/site/search-reference.md +291 -0
- package/data/probe/site/supported-languages.md +215 -0
- package/data/probe/site/use-cases/README.md +8 -0
- package/data/probe/site/use-cases/advanced-cli.md +253 -0
- package/data/probe/site/use-cases/ai-code-editors.md +239 -0
- package/data/probe/site/use-cases/building-ai-tools.md +529 -0
- package/data/probe/site/use-cases/cli-ai-workflows.md +285 -0
- package/data/probe/site/use-cases/deploying-probe-web-interface.md +255 -0
- package/data/probe/site/use-cases/integrating-probe-into-ai-code-editors.md +161 -0
- package/data/probe/site/use-cases/nodejs-sdk.md +596 -0
- package/data/probe/site/use-cases/team-chat.md +350 -0
- package/data/probe/site/web-interface.md +434 -0
- package/data/probe/site/wrangler.toml +9 -0
- package/data/probe/test-api-key.sh +1 -0
- package/data/probe/test-probe-implementation/hello.js +7 -0
- package/data/probe/test_cases/demonstrate_early_termination_issues.sh +176 -0
- package/data/probe/test_cases/early_termination_issues.rs +533 -0
- package/data/probe/test_data/test_nested_struct.go +26 -0
- package/data/probe/tests/README.md +286 -0
- package/data/probe/tests/README_search_determinism_tests.md +116 -0
- package/data/probe/tests/adjacent_comment_test.rs +152 -0
- package/data/probe/tests/apostrophe_handling_tests.rs +132 -0
- package/data/probe/tests/block_filtering_with_ast_tests.rs +669 -0
- package/data/probe/tests/block_merging_tests.rs +396 -0
- package/data/probe/tests/c_outline_format_tests.rs +2179 -0
- package/data/probe/tests/cache_invalidation_issues.rs.disabled +682 -0
- package/data/probe/tests/cache_order_tests.rs +147 -0
- package/data/probe/tests/cache_query_scoping_tests.rs +221 -0
- package/data/probe/tests/cli_tests.rs +680 -0
- package/data/probe/tests/comment_context_integration_test.rs +240 -0
- package/data/probe/tests/common.rs +33 -0
- package/data/probe/tests/complex_block_merging_tests.rs +599 -0
- package/data/probe/tests/complex_query_block_filtering_tests.rs +422 -0
- package/data/probe/tests/control_flow_closing_braces_test.rs +91 -0
- package/data/probe/tests/cpp_outline_format_tests.rs +1507 -0
- package/data/probe/tests/csharp_outline_format_tests.rs +941 -0
- package/data/probe/tests/elastic_query_integration_tests.rs +922 -0
- package/data/probe/tests/extract_command_tests.rs +1848 -0
- package/data/probe/tests/extract_deduplication_tests.rs +146 -0
- package/data/probe/tests/extract_input_file_tests.rs +84 -0
- package/data/probe/tests/extract_prompt_tests.rs +102 -0
- package/data/probe/tests/filename_search_tests.rs +96 -0
- package/data/probe/tests/fixtures/user/AssemblyInfo.cs +3 -0
- package/data/probe/tests/github_extract_tests.rs +234 -0
- package/data/probe/tests/go_comment_test.rs +253 -0
- package/data/probe/tests/go_outline_format_tests.rs +2587 -0
- package/data/probe/tests/go_path_resolver_tests.rs +96 -0
- package/data/probe/tests/html_outline_format_tests.rs +637 -0
- package/data/probe/tests/integration_tests.rs +837 -0
- package/data/probe/tests/ip_whitelist_test.rs +148 -0
- package/data/probe/tests/java_outline_format_tests.rs +1611 -0
- package/data/probe/tests/javascript_extract_tests.rs +315 -0
- package/data/probe/tests/javascript_outline_format_tests.rs +1464 -0
- package/data/probe/tests/json_format_tests.rs +436 -0
- package/data/probe/tests/json_schema_validation_tests.rs +450 -0
- package/data/probe/tests/lib_usage.rs +60 -0
- package/data/probe/tests/line_comment_context_extension_test.rs +459 -0
- package/data/probe/tests/line_map_cache_tests.rs +114 -0
- package/data/probe/tests/markdown_integration_tests.rs +190 -0
- package/data/probe/tests/mocks/test_ip_whitelist.go +11 -0
- package/data/probe/tests/mocks/test_object.js +27 -0
- package/data/probe/tests/mocks/test_struct.go +50 -0
- package/data/probe/tests/multi_keyword_pattern_tests.rs +464 -0
- package/data/probe/tests/multi_language_syntax_integration_tests.rs +218 -0
- package/data/probe/tests/multiple_capture_groups_tests.rs +169 -0
- package/data/probe/tests/negative_compound_word_tests.rs +246 -0
- package/data/probe/tests/nested_symbol_extraction_tests.rs +99 -0
- package/data/probe/tests/outline_cross_file_interference_test.rs +335 -0
- package/data/probe/tests/outline_keyword_preservation_test.rs +67 -0
- package/data/probe/tests/output_format_edge_cases_tests.rs +693 -0
- package/data/probe/tests/parallel_extraction_tests.rs +178 -0
- package/data/probe/tests/parallel_search_tests.rs +355 -0
- package/data/probe/tests/path_resolver_tests.rs +698 -0
- package/data/probe/tests/php_outline_format_extended_tests.rs +928 -0
- package/data/probe/tests/php_outline_format_tests.rs +768 -0
- package/data/probe/tests/property_tests.proptest-regressions +9 -0
- package/data/probe/tests/property_tests.rs +118 -0
- package/data/probe/tests/python_outline_format_tests.rs +1538 -0
- package/data/probe/tests/query_command_json_tests.rs +438 -0
- package/data/probe/tests/query_command_tests.rs +232 -0
- package/data/probe/tests/query_command_xml_tests.rs +569 -0
- package/data/probe/tests/quoted_term_with_negative_keyword_tests.rs +216 -0
- package/data/probe/tests/required_terms_filename_tests.rs +116 -0
- package/data/probe/tests/ruby_outline_format_tests.rs +1011 -0
- package/data/probe/tests/rust_line_comment_context_test.rs +151 -0
- package/data/probe/tests/rust_outline_format_enhanced_tests.rs +725 -0
- package/data/probe/tests/rust_outline_format_tests.rs +843 -0
- package/data/probe/tests/schemas/xml_output_schema.xsd +38 -0
- package/data/probe/tests/search_determinism_tests.rs +451 -0
- package/data/probe/tests/search_hints_tests.rs +253 -0
- package/data/probe/tests/special_character_escaping_tests.rs +417 -0
- package/data/probe/tests/stemming_compound_word_filtering_tests.rs +535 -0
- package/data/probe/tests/strict_elastic_syntax_tests.rs +404 -0
- package/data/probe/tests/swift_outline_format_tests.rs +3319 -0
- package/data/probe/tests/symbols_tests.rs +166 -0
- package/data/probe/tests/test_file.rs +45 -0
- package/data/probe/tests/test_tokenize.rs +28 -0
- package/data/probe/tests/timeout_tests.rs +82 -0
- package/data/probe/tests/tokenization_tests.rs +195 -0
- package/data/probe/tests/tokenized_block_filtering_tests.rs +174 -0
- package/data/probe/tests/typescript_extract_tests.rs +214 -0
- package/data/probe/tests/typescript_outline_format_tests.rs +2188 -0
- package/data/probe/tests/xml_format_tests.rs +568 -0
- package/data/probe/tests/xml_schema_validation_tests.rs +497 -0
- package/data/scripts/postinstall.mjs +9 -0
- package/data/scripts/set-version.js +0 -0
- package/data/scripts/wiki-build.sh +111 -0
- package/data/scripts/wiki-deploy.sh +73 -0
- package/data/serve.json +12 -0
- package/data/test/demo-dynamic.html +134 -0
- package/data/test/demo-esm.html +105 -0
- package/data/test/demo-iife.html +78 -0
- package/data/tsconfig.json +7 -0
- package/data/vite.server.ts +483 -0
- package/data/vitest.config.ts +40 -0
- package/data/wiki/Home.md +58 -0
- package/data/wiki/_Sidebar.md +39 -0
- package/docs-mcp.config.json +20 -0
- package/package.json +56 -0
- package/src/config.js +111 -0
- package/src/index.js +395 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for probeTool security validations
|
|
3
|
+
* @module tests/unit/probeTool-security
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { jest, describe, test, expect, beforeEach, afterEach } from '@jest/globals';
|
|
7
|
+
import { listFilesTool, searchFilesTool } from '../../src/agent/probeTool.js';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { promises as fsPromises } from 'fs';
|
|
10
|
+
import os from 'os';
|
|
11
|
+
|
|
12
|
+
describe('ProbeTool Security', () => {
|
|
13
|
+
let testWorkspace;
|
|
14
|
+
let outsideDir;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
// Create a temporary workspace directory
|
|
18
|
+
testWorkspace = path.join(os.tmpdir(), `probe-test-${Date.now()}`);
|
|
19
|
+
await fsPromises.mkdir(testWorkspace, { recursive: true });
|
|
20
|
+
|
|
21
|
+
// Create a test file inside the workspace
|
|
22
|
+
await fsPromises.writeFile(
|
|
23
|
+
path.join(testWorkspace, 'test-file.txt'),
|
|
24
|
+
'test content'
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// Create a directory outside the workspace
|
|
28
|
+
outsideDir = path.join(os.tmpdir(), `probe-outside-${Date.now()}`);
|
|
29
|
+
await fsPromises.mkdir(outsideDir, { recursive: true });
|
|
30
|
+
await fsPromises.writeFile(
|
|
31
|
+
path.join(outsideDir, 'outside-file.txt'),
|
|
32
|
+
'outside content'
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
afterEach(async () => {
|
|
37
|
+
// Clean up test directories
|
|
38
|
+
try {
|
|
39
|
+
await fsPromises.rm(testWorkspace, { recursive: true, force: true });
|
|
40
|
+
await fsPromises.rm(outsideDir, { recursive: true, force: true });
|
|
41
|
+
} catch (error) {
|
|
42
|
+
// Ignore cleanup errors
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('listFilesTool Security', () => {
|
|
47
|
+
test('should allow access to workspace directory', async () => {
|
|
48
|
+
const result = await listFilesTool.execute({
|
|
49
|
+
directory: '.',
|
|
50
|
+
workingDirectory: testWorkspace
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(result).toContain('test-file.txt');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('should allow access to subdirectories within workspace using relative paths', async () => {
|
|
57
|
+
// Create a subdirectory
|
|
58
|
+
const subdir = path.join(testWorkspace, 'subdir');
|
|
59
|
+
await fsPromises.mkdir(subdir);
|
|
60
|
+
await fsPromises.writeFile(path.join(subdir, 'sub-file.txt'), 'sub content');
|
|
61
|
+
|
|
62
|
+
const result = await listFilesTool.execute({
|
|
63
|
+
directory: 'subdir',
|
|
64
|
+
workingDirectory: testWorkspace
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(result).toContain('sub-file.txt');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('should reject absolute path outside workspace', async () => {
|
|
71
|
+
await expect(async () => {
|
|
72
|
+
await listFilesTool.execute({
|
|
73
|
+
directory: outsideDir,
|
|
74
|
+
workingDirectory: testWorkspace
|
|
75
|
+
});
|
|
76
|
+
}).rejects.toThrow(/Path traversal attempt detected/);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('should reject path traversal using ../..', async () => {
|
|
80
|
+
await expect(async () => {
|
|
81
|
+
await listFilesTool.execute({
|
|
82
|
+
directory: '../../../',
|
|
83
|
+
workingDirectory: testWorkspace
|
|
84
|
+
});
|
|
85
|
+
}).rejects.toThrow(/Path traversal attempt detected/);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('should reject absolute path to system directories', async () => {
|
|
89
|
+
await expect(async () => {
|
|
90
|
+
await listFilesTool.execute({
|
|
91
|
+
directory: '/etc',
|
|
92
|
+
workingDirectory: testWorkspace
|
|
93
|
+
});
|
|
94
|
+
}).rejects.toThrow(/Path traversal attempt detected/);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('should reject absolute path to home directory', async () => {
|
|
98
|
+
const homeDir = os.homedir();
|
|
99
|
+
await expect(async () => {
|
|
100
|
+
await listFilesTool.execute({
|
|
101
|
+
directory: homeDir,
|
|
102
|
+
workingDirectory: testWorkspace
|
|
103
|
+
});
|
|
104
|
+
}).rejects.toThrow(/Path traversal attempt detected/);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('should allow access to workspace root using absolute path', async () => {
|
|
108
|
+
const result = await listFilesTool.execute({
|
|
109
|
+
directory: testWorkspace,
|
|
110
|
+
workingDirectory: testWorkspace
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
expect(result).toContain('test-file.txt');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('should allow access to subdirectory using absolute path within workspace', async () => {
|
|
117
|
+
// Create a subdirectory
|
|
118
|
+
const subdir = path.join(testWorkspace, 'subdir');
|
|
119
|
+
await fsPromises.mkdir(subdir);
|
|
120
|
+
await fsPromises.writeFile(path.join(subdir, 'sub-file.txt'), 'sub content');
|
|
121
|
+
|
|
122
|
+
const result = await listFilesTool.execute({
|
|
123
|
+
directory: subdir,
|
|
124
|
+
workingDirectory: testWorkspace
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(result).toContain('sub-file.txt');
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('searchFilesTool Security', () => {
|
|
132
|
+
test('should allow searching in workspace directory', async () => {
|
|
133
|
+
const result = await searchFilesTool.execute({
|
|
134
|
+
pattern: '*.txt',
|
|
135
|
+
directory: '.',
|
|
136
|
+
workingDirectory: testWorkspace
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
expect(result).toContain('test-file.txt');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('should allow searching in subdirectories within workspace using relative paths', async () => {
|
|
143
|
+
// Create a subdirectory
|
|
144
|
+
const subdir = path.join(testWorkspace, 'subdir');
|
|
145
|
+
await fsPromises.mkdir(subdir);
|
|
146
|
+
await fsPromises.writeFile(path.join(subdir, 'sub-file.txt'), 'sub content');
|
|
147
|
+
|
|
148
|
+
const result = await searchFilesTool.execute({
|
|
149
|
+
pattern: '*.txt',
|
|
150
|
+
directory: 'subdir',
|
|
151
|
+
workingDirectory: testWorkspace
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
expect(result).toContain('sub-file.txt');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('should reject absolute path outside workspace', async () => {
|
|
158
|
+
await expect(async () => {
|
|
159
|
+
await searchFilesTool.execute({
|
|
160
|
+
pattern: '*.txt',
|
|
161
|
+
directory: outsideDir,
|
|
162
|
+
workingDirectory: testWorkspace
|
|
163
|
+
});
|
|
164
|
+
}).rejects.toThrow(/Path traversal attempt detected/);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('should reject path traversal using ../..', async () => {
|
|
168
|
+
await expect(async () => {
|
|
169
|
+
await searchFilesTool.execute({
|
|
170
|
+
pattern: '*.txt',
|
|
171
|
+
directory: '../../../',
|
|
172
|
+
workingDirectory: testWorkspace
|
|
173
|
+
});
|
|
174
|
+
}).rejects.toThrow(/Path traversal attempt detected/);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test('should reject absolute path to system directories', async () => {
|
|
178
|
+
await expect(async () => {
|
|
179
|
+
await searchFilesTool.execute({
|
|
180
|
+
pattern: '*.txt',
|
|
181
|
+
directory: '/etc',
|
|
182
|
+
workingDirectory: testWorkspace
|
|
183
|
+
});
|
|
184
|
+
}).rejects.toThrow(/Path traversal attempt detected/);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test('should reject absolute path to home directory', async () => {
|
|
188
|
+
const homeDir = os.homedir();
|
|
189
|
+
await expect(async () => {
|
|
190
|
+
await searchFilesTool.execute({
|
|
191
|
+
pattern: '*.txt',
|
|
192
|
+
directory: homeDir,
|
|
193
|
+
workingDirectory: testWorkspace
|
|
194
|
+
});
|
|
195
|
+
}).rejects.toThrow(/Path traversal attempt detected/);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test('should allow searching workspace root using absolute path', async () => {
|
|
199
|
+
const result = await searchFilesTool.execute({
|
|
200
|
+
pattern: '*.txt',
|
|
201
|
+
directory: testWorkspace,
|
|
202
|
+
workingDirectory: testWorkspace
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
expect(result).toContain('test-file.txt');
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('should allow searching subdirectory using absolute path within workspace', async () => {
|
|
209
|
+
// Create a subdirectory
|
|
210
|
+
const subdir = path.join(testWorkspace, 'subdir');
|
|
211
|
+
await fsPromises.mkdir(subdir);
|
|
212
|
+
await fsPromises.writeFile(path.join(subdir, 'sub-file.txt'), 'sub content');
|
|
213
|
+
|
|
214
|
+
const result = await searchFilesTool.execute({
|
|
215
|
+
pattern: '*.txt',
|
|
216
|
+
directory: subdir,
|
|
217
|
+
workingDirectory: testWorkspace
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
expect(result).toContain('sub-file.txt');
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe('Dependency Path Bypass', () => {
|
|
225
|
+
test('should allow /dep/ prefix paths to bypass workspace restrictions', async () => {
|
|
226
|
+
// This should not throw a "Path traversal" error even though it's outside workspace
|
|
227
|
+
// It may throw other errors (e.g., directory not found), but not security errors
|
|
228
|
+
try {
|
|
229
|
+
await listFilesTool.execute({
|
|
230
|
+
directory: '/dep/go/fmt',
|
|
231
|
+
workingDirectory: testWorkspace
|
|
232
|
+
});
|
|
233
|
+
} catch (error) {
|
|
234
|
+
expect(error.message).not.toMatch(/Path traversal attempt detected/);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test('should allow go: prefix paths to bypass workspace restrictions', async () => {
|
|
239
|
+
try {
|
|
240
|
+
await listFilesTool.execute({
|
|
241
|
+
directory: 'go:fmt',
|
|
242
|
+
workingDirectory: testWorkspace
|
|
243
|
+
});
|
|
244
|
+
} catch (error) {
|
|
245
|
+
expect(error.message).not.toMatch(/Path traversal attempt detected/);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test('should allow js: prefix paths to bypass workspace restrictions', async () => {
|
|
250
|
+
try {
|
|
251
|
+
await listFilesTool.execute({
|
|
252
|
+
directory: 'js:express',
|
|
253
|
+
workingDirectory: testWorkspace
|
|
254
|
+
});
|
|
255
|
+
} catch (error) {
|
|
256
|
+
expect(error.message).not.toMatch(/Path traversal attempt detected/);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test('should allow rust: prefix paths to bypass workspace restrictions', async () => {
|
|
261
|
+
try {
|
|
262
|
+
await listFilesTool.execute({
|
|
263
|
+
directory: 'rust:serde',
|
|
264
|
+
workingDirectory: testWorkspace
|
|
265
|
+
});
|
|
266
|
+
} catch (error) {
|
|
267
|
+
expect(error.message).not.toMatch(/Path traversal attempt detected/);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test('should allow /dep/ prefix in searchFilesTool', async () => {
|
|
272
|
+
try {
|
|
273
|
+
await searchFilesTool.execute({
|
|
274
|
+
pattern: '*.go',
|
|
275
|
+
directory: '/dep/go/fmt',
|
|
276
|
+
workingDirectory: testWorkspace
|
|
277
|
+
});
|
|
278
|
+
} catch (error) {
|
|
279
|
+
expect(error.message).not.toMatch(/Path traversal attempt detected/);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
});
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { jest, describe, test, expect, beforeEach, afterEach } from '@jest/globals';
|
|
2
|
+
|
|
3
|
+
// Mock all the heavy dependencies that ProbeAgent uses
|
|
4
|
+
jest.mock('@ai-sdk/anthropic', () => ({}));
|
|
5
|
+
jest.mock('@ai-sdk/openai', () => ({}));
|
|
6
|
+
jest.mock('@ai-sdk/google', () => ({}));
|
|
7
|
+
jest.mock('@ai-sdk/amazon-bedrock', () => ({}));
|
|
8
|
+
jest.mock('ai', () => ({
|
|
9
|
+
generateText: jest.fn(),
|
|
10
|
+
streamText: jest.fn(),
|
|
11
|
+
tool: jest.fn((config) => ({
|
|
12
|
+
name: config.name,
|
|
13
|
+
description: config.description,
|
|
14
|
+
inputSchema: config.inputSchema,
|
|
15
|
+
execute: config.execute
|
|
16
|
+
}))
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
import { ProbeAgent } from '../../src/agent/ProbeAgent.js';
|
|
20
|
+
import { writeFileSync, unlinkSync, existsSync, mkdirSync, rmSync } from 'fs';
|
|
21
|
+
import { join } from 'path';
|
|
22
|
+
|
|
23
|
+
describe('ReadImage Tool', () => {
|
|
24
|
+
let testDir;
|
|
25
|
+
let agent;
|
|
26
|
+
let testImagePath;
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
// Create a test directory structure
|
|
30
|
+
testDir = join(process.cwd(), 'test-readimage-temp');
|
|
31
|
+
if (!existsSync(testDir)) {
|
|
32
|
+
mkdirSync(testDir, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Create a simple 1x1 PNG image
|
|
36
|
+
const simplePng = Buffer.from([
|
|
37
|
+
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
|
|
38
|
+
0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
|
|
39
|
+
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
|
|
40
|
+
0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4,
|
|
41
|
+
0x89, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x44, 0x41,
|
|
42
|
+
0x54, 0x78, 0x9C, 0x62, 0x00, 0x02, 0x00, 0x00,
|
|
43
|
+
0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00,
|
|
44
|
+
0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
|
|
45
|
+
0x42, 0x60, 0x82
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
testImagePath = join(testDir, 'test-screenshot.png');
|
|
49
|
+
writeFileSync(testImagePath, simplePng);
|
|
50
|
+
|
|
51
|
+
// Initialize agent with the test directory
|
|
52
|
+
agent = new ProbeAgent({
|
|
53
|
+
debug: false,
|
|
54
|
+
path: testDir
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
// Cleanup
|
|
60
|
+
if (existsSync(testDir)) {
|
|
61
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('Tool availability', () => {
|
|
66
|
+
test('readImage tool should be available in toolImplementations', () => {
|
|
67
|
+
expect(agent.toolImplementations).toHaveProperty('readImage');
|
|
68
|
+
expect(agent.toolImplementations.readImage).toHaveProperty('execute');
|
|
69
|
+
expect(typeof agent.toolImplementations.readImage.execute).toBe('function');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('readImage tool should be in allowed tools by default', () => {
|
|
73
|
+
expect(agent.allowedTools.isEnabled('readImage')).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('Tool execution', () => {
|
|
78
|
+
test('should successfully load image when given valid path', async () => {
|
|
79
|
+
const result = await agent.toolImplementations.readImage.execute({
|
|
80
|
+
path: testImagePath
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(result).toContain('Image loaded successfully');
|
|
84
|
+
expect(result).toContain(testImagePath);
|
|
85
|
+
|
|
86
|
+
// Verify image was actually loaded into pendingImages
|
|
87
|
+
expect(agent.pendingImages.has(testImagePath)).toBe(true);
|
|
88
|
+
|
|
89
|
+
// Verify it can be retrieved
|
|
90
|
+
const loadedImages = agent.getCurrentImages();
|
|
91
|
+
expect(loadedImages.length).toBeGreaterThan(0);
|
|
92
|
+
expect(loadedImages[0]).toMatch(/^data:image\/png;base64,/);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('should throw error when path parameter is missing', async () => {
|
|
96
|
+
await expect(
|
|
97
|
+
agent.toolImplementations.readImage.execute({})
|
|
98
|
+
).rejects.toThrow('Image path is required');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('should throw error when image file does not exist', async () => {
|
|
102
|
+
const nonExistentPath = join(testDir, 'nonexistent.png');
|
|
103
|
+
|
|
104
|
+
await expect(
|
|
105
|
+
agent.toolImplementations.readImage.execute({
|
|
106
|
+
path: nonExistentPath
|
|
107
|
+
})
|
|
108
|
+
).rejects.toThrow();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('should handle relative paths correctly', async () => {
|
|
112
|
+
// Create image in a subdirectory
|
|
113
|
+
const subDir = join(testDir, 'images');
|
|
114
|
+
mkdirSync(subDir, { recursive: true });
|
|
115
|
+
|
|
116
|
+
const simplePng = Buffer.from([
|
|
117
|
+
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
|
|
118
|
+
0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
|
|
119
|
+
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
|
|
120
|
+
0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4,
|
|
121
|
+
0x89, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x44, 0x41,
|
|
122
|
+
0x54, 0x78, 0x9C, 0x62, 0x00, 0x02, 0x00, 0x00,
|
|
123
|
+
0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00,
|
|
124
|
+
0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
|
|
125
|
+
0x42, 0x60, 0x82
|
|
126
|
+
]);
|
|
127
|
+
|
|
128
|
+
const imagePath = join(subDir, 'relative.png');
|
|
129
|
+
writeFileSync(imagePath, simplePng);
|
|
130
|
+
|
|
131
|
+
const result = await agent.toolImplementations.readImage.execute({
|
|
132
|
+
path: imagePath
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(result).toContain('Image loaded successfully');
|
|
136
|
+
expect(agent.pendingImages.has(imagePath)).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('should support multiple image formats', async () => {
|
|
140
|
+
const formats = ['test.png', 'test.jpg', 'test.jpeg', 'test.webp', 'test.bmp'];
|
|
141
|
+
|
|
142
|
+
// Create a simple PNG for all tests (format validation happens elsewhere)
|
|
143
|
+
const simplePng = Buffer.from([
|
|
144
|
+
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
|
|
145
|
+
0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
|
|
146
|
+
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
|
|
147
|
+
0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4,
|
|
148
|
+
0x89, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x44, 0x41,
|
|
149
|
+
0x54, 0x78, 0x9C, 0x62, 0x00, 0x02, 0x00, 0x00,
|
|
150
|
+
0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00,
|
|
151
|
+
0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
|
|
152
|
+
0x42, 0x60, 0x82
|
|
153
|
+
]);
|
|
154
|
+
|
|
155
|
+
for (const filename of formats) {
|
|
156
|
+
const imagePath = join(testDir, filename);
|
|
157
|
+
writeFileSync(imagePath, simplePng);
|
|
158
|
+
|
|
159
|
+
const result = await agent.toolImplementations.readImage.execute({
|
|
160
|
+
path: imagePath
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
expect(result).toContain('Image loaded successfully');
|
|
164
|
+
expect(agent.pendingImages.has(imagePath)).toBe(true);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test('should not load the same image twice', async () => {
|
|
169
|
+
// Load image first time
|
|
170
|
+
await agent.toolImplementations.readImage.execute({
|
|
171
|
+
path: testImagePath
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const imagesAfterFirst = agent.getCurrentImages().length;
|
|
175
|
+
|
|
176
|
+
// Load same image again
|
|
177
|
+
await agent.toolImplementations.readImage.execute({
|
|
178
|
+
path: testImagePath
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const imagesAfterSecond = agent.getCurrentImages().length;
|
|
182
|
+
|
|
183
|
+
// Should still have same number of images (no duplicate)
|
|
184
|
+
expect(imagesAfterSecond).toBe(imagesAfterFirst);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe('Security', () => {
|
|
189
|
+
test('should respect allowed folders security', async () => {
|
|
190
|
+
// Create agent with restricted allowed folders
|
|
191
|
+
const restrictedAgent = new ProbeAgent({
|
|
192
|
+
debug: false,
|
|
193
|
+
path: testDir,
|
|
194
|
+
allowedFolders: [testDir] // Only allow test directory
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Try to load image outside allowed folder
|
|
198
|
+
const outsidePath = '/tmp/malicious.png';
|
|
199
|
+
|
|
200
|
+
await expect(
|
|
201
|
+
restrictedAgent.toolImplementations.readImage.execute({
|
|
202
|
+
path: outsidePath
|
|
203
|
+
})
|
|
204
|
+
).rejects.toThrow();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('should validate file size limits', async () => {
|
|
208
|
+
// The loadImageIfValid method should enforce MAX_IMAGE_FILE_SIZE (20MB)
|
|
209
|
+
// This test verifies the tool respects that limit
|
|
210
|
+
const result = await agent.toolImplementations.readImage.execute({
|
|
211
|
+
path: testImagePath
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
expect(result).toContain('Image loaded successfully');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test('should prevent path traversal attacks with .. sequences', async () => {
|
|
218
|
+
const restrictedAgent = new ProbeAgent({
|
|
219
|
+
debug: false,
|
|
220
|
+
path: testDir,
|
|
221
|
+
allowedFolders: [testDir]
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Try path traversal attack
|
|
225
|
+
const traversalPath = join(testDir, '..', '..', 'etc', 'passwd');
|
|
226
|
+
|
|
227
|
+
await expect(
|
|
228
|
+
restrictedAgent.toolImplementations.readImage.execute({
|
|
229
|
+
path: traversalPath
|
|
230
|
+
})
|
|
231
|
+
).rejects.toThrow();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('should prevent path traversal in extension extraction', async () => {
|
|
235
|
+
// This tests that basename is used to extract extension safely
|
|
236
|
+
const restrictedAgent = new ProbeAgent({
|
|
237
|
+
debug: false,
|
|
238
|
+
path: testDir,
|
|
239
|
+
allowedFolders: [testDir]
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Path designed to look like valid extension but contains traversal
|
|
243
|
+
const maliciousPath = 'malicious.png/../../../etc/passwd';
|
|
244
|
+
|
|
245
|
+
await expect(
|
|
246
|
+
restrictedAgent.toolImplementations.readImage.execute({
|
|
247
|
+
path: maliciousPath
|
|
248
|
+
})
|
|
249
|
+
).rejects.toThrow();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test('should handle normalized path prefix attacks', async () => {
|
|
253
|
+
// Test that /allowed/path doesn't match /allowed/pathsuffix
|
|
254
|
+
const restrictedAgent = new ProbeAgent({
|
|
255
|
+
debug: false,
|
|
256
|
+
path: testDir,
|
|
257
|
+
allowedFolders: [testDir]
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Create a sibling directory name that starts with testDir name
|
|
261
|
+
const siblingPath = testDir + '-sibling/image.png';
|
|
262
|
+
|
|
263
|
+
await expect(
|
|
264
|
+
restrictedAgent.toolImplementations.readImage.execute({
|
|
265
|
+
path: siblingPath
|
|
266
|
+
})
|
|
267
|
+
).rejects.toThrow();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test('should reject invalid extensions even without apiType set', async () => {
|
|
271
|
+
// Test that extension validation happens regardless of apiType
|
|
272
|
+
const agentWithoutApiType = new ProbeAgent({
|
|
273
|
+
debug: false,
|
|
274
|
+
path: testDir
|
|
275
|
+
});
|
|
276
|
+
// Ensure apiType is not set
|
|
277
|
+
agentWithoutApiType.apiType = null;
|
|
278
|
+
|
|
279
|
+
// Try to load a file with invalid extension
|
|
280
|
+
await expect(
|
|
281
|
+
agentWithoutApiType.toolImplementations.readImage.execute({
|
|
282
|
+
path: join(testDir, 'malicious.exe')
|
|
283
|
+
})
|
|
284
|
+
).rejects.toThrow(/Invalid or unsupported image extension/);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test('should reject path traversal disguised as valid extension', async () => {
|
|
288
|
+
const restrictedAgent = new ProbeAgent({
|
|
289
|
+
debug: false,
|
|
290
|
+
path: testDir,
|
|
291
|
+
allowedFolders: [testDir]
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// Path that looks like it has a valid extension but is actually traversal
|
|
295
|
+
// basename('malicious.png/../../../etc/passwd') = 'passwd'
|
|
296
|
+
// extension of 'passwd' = 'passwd' (not in allowed list)
|
|
297
|
+
await expect(
|
|
298
|
+
restrictedAgent.toolImplementations.readImage.execute({
|
|
299
|
+
path: 'malicious.png/../../../etc/passwd'
|
|
300
|
+
})
|
|
301
|
+
).rejects.toThrow(/Invalid or unsupported image extension/);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
describe('Provider-specific format restrictions (GitHub issue #305)', () => {
|
|
306
|
+
test('should reject SVG files when using Google provider', async () => {
|
|
307
|
+
// Create an agent with Google provider
|
|
308
|
+
// Note: We need to manually set apiType since mocks prevent normal initialization
|
|
309
|
+
const googleAgent = new ProbeAgent({
|
|
310
|
+
debug: false,
|
|
311
|
+
path: testDir
|
|
312
|
+
});
|
|
313
|
+
googleAgent.apiType = 'google'; // Simulate Google provider
|
|
314
|
+
|
|
315
|
+
// Create a simple SVG file
|
|
316
|
+
const svgContent = '<svg xmlns="http://www.w3.org/2000/svg"><rect width="1" height="1"/></svg>';
|
|
317
|
+
const svgPath = join(testDir, 'test.svg');
|
|
318
|
+
writeFileSync(svgPath, svgContent);
|
|
319
|
+
|
|
320
|
+
// Attempting to read SVG should throw error
|
|
321
|
+
await expect(
|
|
322
|
+
googleAgent.toolImplementations.readImage.execute({
|
|
323
|
+
path: svgPath
|
|
324
|
+
})
|
|
325
|
+
).rejects.toThrow(/not supported by the current AI provider/);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test('should allow SVG files when using Anthropic provider', async () => {
|
|
329
|
+
// Create an agent with Anthropic provider
|
|
330
|
+
// Note: We need to manually set apiType since mocks prevent normal initialization
|
|
331
|
+
const anthropicAgent = new ProbeAgent({
|
|
332
|
+
debug: false,
|
|
333
|
+
path: testDir
|
|
334
|
+
});
|
|
335
|
+
anthropicAgent.apiType = 'anthropic'; // Simulate Anthropic provider
|
|
336
|
+
|
|
337
|
+
// Create a simple SVG file
|
|
338
|
+
const svgContent = '<svg xmlns="http://www.w3.org/2000/svg"><rect width="1" height="1"/></svg>';
|
|
339
|
+
const svgPath = join(testDir, 'test-anthropic.svg');
|
|
340
|
+
writeFileSync(svgPath, svgContent);
|
|
341
|
+
|
|
342
|
+
// Attempting to read SVG should succeed
|
|
343
|
+
const result = await anthropicAgent.toolImplementations.readImage.execute({
|
|
344
|
+
path: svgPath
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
expect(result).toContain('Image loaded successfully');
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
test('loadImageIfValid should load SVG (provider filtering handled by readImage tool)', async () => {
|
|
351
|
+
// Note: loadImageIfValid is a low-level method that only checks general format support.
|
|
352
|
+
// Provider-specific filtering (e.g., SVG not supported by Google Gemini) is handled
|
|
353
|
+
// by the readImage tool which provides explicit error messages.
|
|
354
|
+
const agent = new ProbeAgent({
|
|
355
|
+
debug: false,
|
|
356
|
+
path: testDir
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
const svgContent = '<svg xmlns="http://www.w3.org/2000/svg"><rect width="1" height="1"/></svg>';
|
|
360
|
+
const svgPath = join(testDir, 'test-load.svg');
|
|
361
|
+
writeFileSync(svgPath, svgContent);
|
|
362
|
+
|
|
363
|
+
// loadImageIfValid should succeed - it doesn't do provider-specific filtering
|
|
364
|
+
const result = await agent.loadImageIfValid(svgPath);
|
|
365
|
+
expect(result).toBe(true);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
describe('Integration with message flow', () => {
|
|
370
|
+
test('loaded images should be available in getCurrentImages', async () => {
|
|
371
|
+
agent.clearLoadedImages();
|
|
372
|
+
|
|
373
|
+
await agent.toolImplementations.readImage.execute({
|
|
374
|
+
path: testImagePath
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
const images = agent.getCurrentImages();
|
|
378
|
+
expect(images.length).toBe(1);
|
|
379
|
+
expect(images[0]).toMatch(/^data:image\/png;base64,/);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
test('should work alongside processImageReferences method (for explicit image processing)', async () => {
|
|
383
|
+
// Note: Automatic image processing after tool results was removed in GitHub issue #305
|
|
384
|
+
// The processImageReferences method still exists for explicit use when needed
|
|
385
|
+
|
|
386
|
+
// Clear any existing images
|
|
387
|
+
agent.clearLoadedImages();
|
|
388
|
+
|
|
389
|
+
// Manually call processImageReferences (this is no longer called automatically)
|
|
390
|
+
const toolResultWithImage = `Found the file at ${testImagePath}`;
|
|
391
|
+
await agent.processImageReferences(toolResultWithImage);
|
|
392
|
+
|
|
393
|
+
const imagesFromProcessing = agent.getCurrentImages().length;
|
|
394
|
+
|
|
395
|
+
// Now explicitly read another image using readImage tool
|
|
396
|
+
const anotherImage = join(testDir, 'another.png');
|
|
397
|
+
const simplePng = Buffer.from([
|
|
398
|
+
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
|
|
399
|
+
0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
|
|
400
|
+
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
|
|
401
|
+
0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4,
|
|
402
|
+
0x89, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x44, 0x41,
|
|
403
|
+
0x54, 0x78, 0x9C, 0x62, 0x00, 0x02, 0x00, 0x00,
|
|
404
|
+
0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00,
|
|
405
|
+
0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
|
|
406
|
+
0x42, 0x60, 0x82
|
|
407
|
+
]);
|
|
408
|
+
writeFileSync(anotherImage, simplePng);
|
|
409
|
+
|
|
410
|
+
await agent.toolImplementations.readImage.execute({
|
|
411
|
+
path: anotherImage
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
const totalImages = agent.getCurrentImages().length;
|
|
415
|
+
expect(totalImages).toBeGreaterThan(imagesFromProcessing);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
});
|