@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,767 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code SDK backend implementation
|
|
3
|
+
* @module ClaudeCodeBackend
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import BaseBackend from './BaseBackend.js';
|
|
7
|
+
import { BackendError, ErrorTypes, ProgressTracker, FileChangeParser, TokenEstimator } from '../core/utils.js';
|
|
8
|
+
import { exec, spawn } from 'child_process';
|
|
9
|
+
import { promisify } from 'util';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { TIMEOUTS, getDefaultTimeoutMs } from '../core/timeouts.js';
|
|
12
|
+
|
|
13
|
+
const execPromise = promisify(exec);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Claude Code SDK implementation backend
|
|
17
|
+
* @class
|
|
18
|
+
* @extends BaseBackend
|
|
19
|
+
*/
|
|
20
|
+
class ClaudeCodeBackend extends BaseBackend {
|
|
21
|
+
constructor() {
|
|
22
|
+
super('claude-code', '1.0.0');
|
|
23
|
+
this.config = null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @override
|
|
28
|
+
*/
|
|
29
|
+
async initialize(config) {
|
|
30
|
+
this.config = {
|
|
31
|
+
apiKey: config.apiKey || process.env.ANTHROPIC_API_KEY,
|
|
32
|
+
model: config.model || 'claude-3-5-sonnet-20241022',
|
|
33
|
+
baseUrl: config.baseUrl,
|
|
34
|
+
timeout: config.timeout || getDefaultTimeoutMs(), // Use centralized default (20 minutes)
|
|
35
|
+
maxTokens: config.maxTokens || 8000,
|
|
36
|
+
temperature: config.temperature || 0.3,
|
|
37
|
+
systemPrompt: config.systemPrompt,
|
|
38
|
+
tools: config.tools || ['edit', 'search', 'bash'],
|
|
39
|
+
maxTurns: config.maxTurns || 100,
|
|
40
|
+
...config
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
// Claude Code backend only uses CLI interface
|
|
45
|
+
this.log('debug', 'Using Claude Code CLI interface');
|
|
46
|
+
|
|
47
|
+
// Validate configuration
|
|
48
|
+
await this.validateConfiguration();
|
|
49
|
+
|
|
50
|
+
// Test connection/availability
|
|
51
|
+
const available = await this.isAvailable();
|
|
52
|
+
if (!available) {
|
|
53
|
+
throw new Error('Claude Code is not available');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.initialized = true;
|
|
57
|
+
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw new BackendError(
|
|
60
|
+
`Failed to initialize Claude Code backend: ${error.message}`,
|
|
61
|
+
ErrorTypes.INITIALIZATION_FAILED,
|
|
62
|
+
'CLAUDE_CODE_INIT_FAILED',
|
|
63
|
+
{ originalError: error }
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @override
|
|
70
|
+
*/
|
|
71
|
+
async isAvailable() {
|
|
72
|
+
if (!this.config.apiKey) {
|
|
73
|
+
this.log('warn', 'No API key configured');
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
let claudeCommand = null;
|
|
79
|
+
|
|
80
|
+
// Method 1: Try direct execution with claude --version
|
|
81
|
+
try {
|
|
82
|
+
await execPromise('claude --version', { timeout: TIMEOUTS.VERSION_CHECK });
|
|
83
|
+
claudeCommand = 'claude';
|
|
84
|
+
this.log('debug', 'Claude found in PATH via direct execution');
|
|
85
|
+
} catch (directError) {
|
|
86
|
+
this.log('debug', 'Claude not directly executable from PATH', { error: directError.message });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Method 2: Check npm global installation and find the binary
|
|
90
|
+
if (!claudeCommand) {
|
|
91
|
+
try {
|
|
92
|
+
const { stdout } = await execPromise('npm list -g @anthropic-ai/claude-code --depth=0', { timeout: TIMEOUTS.VERSION_CHECK });
|
|
93
|
+
if (stdout.includes('@anthropic-ai/claude-code')) {
|
|
94
|
+
// Get npm global bin directory
|
|
95
|
+
const { stdout: binPath } = await execPromise('npm bin -g', { timeout: TIMEOUTS.VERSION_CHECK });
|
|
96
|
+
const npmBinDir = binPath.trim();
|
|
97
|
+
|
|
98
|
+
// Build the claude command path
|
|
99
|
+
const isWindows = process.platform === 'win32';
|
|
100
|
+
const claudeBinary = isWindows ? 'claude.cmd' : 'claude';
|
|
101
|
+
const claudePath = path.join(npmBinDir, claudeBinary);
|
|
102
|
+
|
|
103
|
+
// Test if we can execute it
|
|
104
|
+
try {
|
|
105
|
+
await execPromise(`"${claudePath}" --version`, { timeout: TIMEOUTS.VERSION_CHECK });
|
|
106
|
+
claudeCommand = claudePath;
|
|
107
|
+
|
|
108
|
+
// Update PATH for this process to include npm global bin
|
|
109
|
+
const pathSeparator = isWindows ? ';' : ':';
|
|
110
|
+
process.env.PATH = `${npmBinDir}${pathSeparator}${process.env.PATH}`;
|
|
111
|
+
|
|
112
|
+
this.log('debug', `Claude found at ${claudePath}, added ${npmBinDir} to PATH`);
|
|
113
|
+
} catch (execError) {
|
|
114
|
+
this.log('debug', `Failed to execute claude at ${claudePath}`, { error: execError.message });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} catch (npmError) {
|
|
118
|
+
this.log('debug', 'Failed to check npm global packages', { error: npmError.message });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Method 3: Try WSL on Windows
|
|
123
|
+
if (!claudeCommand && process.platform === 'win32') {
|
|
124
|
+
try {
|
|
125
|
+
// Check if WSL is available and claude is installed there
|
|
126
|
+
const { stdout: wslCheck } = await execPromise('wsl --list', { timeout: TIMEOUTS.WSL_CHECK });
|
|
127
|
+
if (wslCheck) {
|
|
128
|
+
this.log('debug', 'WSL detected, checking for claude in WSL');
|
|
129
|
+
try {
|
|
130
|
+
// Try to run claude through WSL
|
|
131
|
+
await execPromise('wsl claude --version', { timeout: TIMEOUTS.VERSION_CHECK });
|
|
132
|
+
claudeCommand = 'wsl claude';
|
|
133
|
+
this.log('debug', 'Claude found in WSL');
|
|
134
|
+
} catch (wslClaudeError) {
|
|
135
|
+
this.log('debug', 'Claude not found in WSL', { error: wslClaudeError.message });
|
|
136
|
+
|
|
137
|
+
// Try common WSL paths
|
|
138
|
+
const wslPaths = [
|
|
139
|
+
'wsl /usr/local/bin/claude',
|
|
140
|
+
'wsl ~/.npm-global/bin/claude',
|
|
141
|
+
'wsl ~/.local/bin/claude',
|
|
142
|
+
'wsl ~/node_modules/.bin/claude'
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
for (const wslPath of wslPaths) {
|
|
146
|
+
try {
|
|
147
|
+
await execPromise(`${wslPath} --version`, { timeout: TIMEOUTS.WSL_CHECK });
|
|
148
|
+
claudeCommand = wslPath;
|
|
149
|
+
this.log('debug', `Claude found in WSL at: ${wslPath}`);
|
|
150
|
+
break;
|
|
151
|
+
} catch (e) {
|
|
152
|
+
// Continue searching
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
} catch (wslError) {
|
|
158
|
+
this.log('debug', 'WSL not available or accessible', { error: wslError.message });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Method 4: Try to find claude in common locations
|
|
163
|
+
if (!claudeCommand) {
|
|
164
|
+
const isWindows = process.platform === 'win32';
|
|
165
|
+
const homeDir = process.env[isWindows ? 'USERPROFILE' : 'HOME'];
|
|
166
|
+
const claudeBinary = isWindows ? 'claude.cmd' : 'claude';
|
|
167
|
+
|
|
168
|
+
// Common npm global locations
|
|
169
|
+
const commonPaths = [
|
|
170
|
+
// Windows paths
|
|
171
|
+
isWindows && path.join(process.env.APPDATA || '', 'npm', claudeBinary),
|
|
172
|
+
isWindows && path.join('C:', 'Program Files', 'nodejs', claudeBinary),
|
|
173
|
+
// Unix-like paths
|
|
174
|
+
!isWindows && path.join('/usr/local/bin', claudeBinary),
|
|
175
|
+
!isWindows && path.join(homeDir, '.npm-global', 'bin', claudeBinary),
|
|
176
|
+
!isWindows && path.join(homeDir, '.local', 'bin', claudeBinary),
|
|
177
|
+
// Cross-platform home directory paths
|
|
178
|
+
path.join(homeDir, 'node_modules', '.bin', claudeBinary),
|
|
179
|
+
].filter(Boolean);
|
|
180
|
+
|
|
181
|
+
for (const claudePath of commonPaths) {
|
|
182
|
+
try {
|
|
183
|
+
await execPromise(`"${claudePath}" --version`, { timeout: TIMEOUTS.WSL_CHECK });
|
|
184
|
+
claudeCommand = claudePath;
|
|
185
|
+
this.log('debug', `Claude found at ${claudePath}`);
|
|
186
|
+
break;
|
|
187
|
+
} catch (e) {
|
|
188
|
+
// Continue searching
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (!claudeCommand) {
|
|
194
|
+
this.log('warn', 'Claude Code CLI not found. Please install with: npm install -g @anthropic-ai/claude-code (or in WSL on Windows)');
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Store the command for later use
|
|
199
|
+
this.claudeCommand = claudeCommand;
|
|
200
|
+
|
|
201
|
+
// Just verify the API key exists (non-empty)
|
|
202
|
+
// Don't validate format as it can vary
|
|
203
|
+
if (!this.config.apiKey || this.config.apiKey.trim() === '') {
|
|
204
|
+
this.log('warn', 'API key is not configured');
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return true;
|
|
209
|
+
} catch (error) {
|
|
210
|
+
this.log('debug', 'Availability check failed', { error: error.message });
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @override
|
|
217
|
+
*/
|
|
218
|
+
getRequiredDependencies() {
|
|
219
|
+
return [
|
|
220
|
+
{
|
|
221
|
+
name: 'claude-code',
|
|
222
|
+
type: 'cli',
|
|
223
|
+
installCommand: 'npm install -g @anthropic-ai/claude-code',
|
|
224
|
+
description: 'Claude Code CLI tool'
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: 'ANTHROPIC_API_KEY',
|
|
228
|
+
type: 'environment',
|
|
229
|
+
description: 'Anthropic API key for Claude Code'
|
|
230
|
+
}
|
|
231
|
+
];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @override
|
|
236
|
+
*/
|
|
237
|
+
getCapabilities() {
|
|
238
|
+
return {
|
|
239
|
+
supportsLanguages: ['javascript', 'typescript', 'python', 'rust', 'go', 'java', 'c++', 'c#', 'ruby', 'php', 'swift'],
|
|
240
|
+
supportsStreaming: true,
|
|
241
|
+
supportsRollback: false,
|
|
242
|
+
supportsDirectFileEdit: true,
|
|
243
|
+
supportsPlanGeneration: true,
|
|
244
|
+
supportsTestGeneration: true,
|
|
245
|
+
maxConcurrentSessions: 5
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @override
|
|
251
|
+
*/
|
|
252
|
+
getDescription() {
|
|
253
|
+
return 'Claude Code CLI - Advanced AI coding assistant powered by Claude';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* @override
|
|
258
|
+
*/
|
|
259
|
+
async execute(request) {
|
|
260
|
+
this.checkInitialized();
|
|
261
|
+
|
|
262
|
+
const validation = this.validateRequest(request);
|
|
263
|
+
if (!validation.valid) {
|
|
264
|
+
throw new BackendError(
|
|
265
|
+
`Invalid request: ${validation.errors.join(', ')}`,
|
|
266
|
+
ErrorTypes.VALIDATION_ERROR,
|
|
267
|
+
'INVALID_REQUEST'
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const sessionInfo = this.createSessionInfo(request.sessionId);
|
|
272
|
+
const progressTracker = new ProgressTracker(request.sessionId, request.callbacks?.onProgress);
|
|
273
|
+
|
|
274
|
+
this.activeSessions.set(request.sessionId, sessionInfo);
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
progressTracker.startStep('prepare', 'Preparing Claude Code execution');
|
|
278
|
+
|
|
279
|
+
// Build the prompt
|
|
280
|
+
const prompt = this.buildPrompt(request);
|
|
281
|
+
const workingDir = request.context?.workingDirectory || process.cwd();
|
|
282
|
+
|
|
283
|
+
this.updateSessionStatus(request.sessionId, {
|
|
284
|
+
status: 'running',
|
|
285
|
+
progress: 25,
|
|
286
|
+
message: 'Claude Code is processing your request'
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
progressTracker.endStep();
|
|
290
|
+
progressTracker.startStep('execute', 'Executing with Claude Code');
|
|
291
|
+
|
|
292
|
+
// Always use CLI interface
|
|
293
|
+
const result = await this.executeWithCLI(prompt, workingDir, request, sessionInfo, progressTracker);
|
|
294
|
+
|
|
295
|
+
progressTracker.endStep();
|
|
296
|
+
|
|
297
|
+
this.updateSessionStatus(request.sessionId, {
|
|
298
|
+
status: 'completed',
|
|
299
|
+
progress: 100,
|
|
300
|
+
message: 'Implementation completed successfully'
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
return result;
|
|
304
|
+
|
|
305
|
+
} catch (error) {
|
|
306
|
+
this.updateSessionStatus(request.sessionId, {
|
|
307
|
+
status: 'failed',
|
|
308
|
+
message: error.message
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
if (error instanceof BackendError) {
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
throw new BackendError(
|
|
316
|
+
`Claude Code execution failed: ${error.message}`,
|
|
317
|
+
ErrorTypes.EXECUTION_FAILED,
|
|
318
|
+
'CLAUDE_CODE_EXECUTION_FAILED',
|
|
319
|
+
{ originalError: error, sessionId: request.sessionId }
|
|
320
|
+
);
|
|
321
|
+
} finally {
|
|
322
|
+
this.activeSessions.delete(request.sessionId);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Validate configuration
|
|
328
|
+
* @private
|
|
329
|
+
*/
|
|
330
|
+
async validateConfiguration() {
|
|
331
|
+
if (!this.config.apiKey) {
|
|
332
|
+
throw new Error('API key is required. Set ANTHROPIC_API_KEY environment variable or provide apiKey in config');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// No format validation - API key formats can vary
|
|
336
|
+
// Model validation removed - model names change frequently
|
|
337
|
+
|
|
338
|
+
// Tools validation not needed since we always use --dangerously-skip-permissions
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Build prompt for Claude Code
|
|
343
|
+
* @param {import('../types/BackendTypes').ImplementRequest} request - Implementation request
|
|
344
|
+
* @returns {string} Formatted prompt
|
|
345
|
+
* @private
|
|
346
|
+
*/
|
|
347
|
+
buildPrompt(request) {
|
|
348
|
+
let prompt = '';
|
|
349
|
+
|
|
350
|
+
// Add context if provided
|
|
351
|
+
if (request.context?.additionalContext) {
|
|
352
|
+
prompt += `Context:\n${request.context.additionalContext}\n\n`;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Add main task
|
|
356
|
+
prompt += `Task:\n${request.task}\n`;
|
|
357
|
+
|
|
358
|
+
// Add constraints
|
|
359
|
+
if (request.context?.allowedFiles && request.context.allowedFiles.length > 0) {
|
|
360
|
+
prompt += `\nOnly modify these files: ${request.context.allowedFiles.join(', ')}\n`;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (request.context?.language) {
|
|
364
|
+
prompt += `\nPrimary language: ${request.context.language}\n`;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Add options
|
|
368
|
+
if (request.options?.generateTests) {
|
|
369
|
+
prompt += '\nAlso generate appropriate tests for the implemented functionality.\n';
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (request.options?.dryRun) {
|
|
373
|
+
prompt += '\nThis is a dry run - describe what changes would be made without actually implementing them.\n';
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return prompt.trim();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Build system prompt for Claude Code
|
|
381
|
+
* @param {import('../types/BackendTypes').ImplementRequest} request - Implementation request
|
|
382
|
+
* @returns {string} System prompt
|
|
383
|
+
* @private
|
|
384
|
+
*/
|
|
385
|
+
buildSystemPrompt(request) {
|
|
386
|
+
if (this.config.systemPrompt) {
|
|
387
|
+
return this.config.systemPrompt;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return `You are an expert software developer assistant using Claude Code. Your task is to implement code changes based on user requirements.
|
|
391
|
+
|
|
392
|
+
Key guidelines:
|
|
393
|
+
- Follow best practices for the detected programming language
|
|
394
|
+
- Write clean, maintainable, and well-documented code
|
|
395
|
+
- Include error handling where appropriate
|
|
396
|
+
- Consider edge cases and potential issues
|
|
397
|
+
- Generate tests when requested or when it would be beneficial
|
|
398
|
+
- Make minimal, focused changes that achieve the requested functionality
|
|
399
|
+
- Preserve existing code style and conventions
|
|
400
|
+
|
|
401
|
+
Working directory: ${request.context?.workingDirectory || process.cwd()}
|
|
402
|
+
${request.context?.allowedFiles ? `Allowed files: ${request.context.allowedFiles.join(', ')}` : ''}
|
|
403
|
+
${request.context?.language ? `Primary language: ${request.context.language}` : ''}`;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Execute using CLI interface
|
|
409
|
+
* @private
|
|
410
|
+
*/
|
|
411
|
+
async executeWithCLI(prompt, workingDir, request, sessionInfo, progressTracker) {
|
|
412
|
+
const startTime = Date.now();
|
|
413
|
+
|
|
414
|
+
// Build Claude Code CLI arguments securely
|
|
415
|
+
const args = this.buildSecureCommandArgs(request);
|
|
416
|
+
|
|
417
|
+
// Add the prompt using -p flag (multiline strings are handled safely by spawn)
|
|
418
|
+
const validatedPrompt = this.validatePrompt(prompt);
|
|
419
|
+
args.unshift('-p', validatedPrompt);
|
|
420
|
+
|
|
421
|
+
this.log('debug', 'Executing Claude Code CLI', {
|
|
422
|
+
command: 'claude',
|
|
423
|
+
args: args.slice(0, 5), // Log first few args only for security
|
|
424
|
+
workingDir
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// Always log command info to stderr for debugging (visible in all modes)
|
|
428
|
+
console.error(`[INFO] Claude Code execution details:`);
|
|
429
|
+
console.error(`[INFO] Working directory: ${workingDir}`);
|
|
430
|
+
console.error(`[INFO] Environment: ANTHROPIC_API_KEY=${this.config.apiKey ? '***set***' : '***not set***'}`);
|
|
431
|
+
console.error(`[INFO] Prompt length: ${validatedPrompt.length} characters`);
|
|
432
|
+
|
|
433
|
+
return new Promise(async (resolve, reject) => {
|
|
434
|
+
// Use spawn instead of exec for better security
|
|
435
|
+
// Use the command we found during isAvailable() check
|
|
436
|
+
let claudeCommand = this.claudeCommand || 'claude';
|
|
437
|
+
|
|
438
|
+
// If we don't have a stored command, try to find it again
|
|
439
|
+
if (!this.claudeCommand) {
|
|
440
|
+
try {
|
|
441
|
+
// Try direct execution first
|
|
442
|
+
await execPromise('claude --version', { timeout: TIMEOUTS.PATH_CHECK });
|
|
443
|
+
claudeCommand = 'claude';
|
|
444
|
+
} catch (e) {
|
|
445
|
+
const isWindows = process.platform === 'win32';
|
|
446
|
+
|
|
447
|
+
// Try WSL on Windows
|
|
448
|
+
if (isWindows) {
|
|
449
|
+
try {
|
|
450
|
+
await execPromise('wsl claude --version', { timeout: TIMEOUTS.WSL_CHECK });
|
|
451
|
+
claudeCommand = 'wsl claude';
|
|
452
|
+
this.log('debug', 'Using claude from WSL');
|
|
453
|
+
} catch (wslError) {
|
|
454
|
+
// Continue to npm global check
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Try to find it in npm global bin
|
|
459
|
+
if (claudeCommand === 'claude') {
|
|
460
|
+
try {
|
|
461
|
+
const { stdout: binPath } = await execPromise('npm bin -g', { timeout: TIMEOUTS.PATH_CHECK });
|
|
462
|
+
const claudeBinary = isWindows ? 'claude.cmd' : 'claude';
|
|
463
|
+
const potentialClaudePath = path.join(binPath.trim(), claudeBinary);
|
|
464
|
+
|
|
465
|
+
// Test if we can execute it
|
|
466
|
+
await execPromise(`"${potentialClaudePath}" --version`, { timeout: TIMEOUTS.PATH_CHECK });
|
|
467
|
+
claudeCommand = potentialClaudePath;
|
|
468
|
+
this.log('debug', `Using claude from npm global: ${claudeCommand}`);
|
|
469
|
+
} catch (npmError) {
|
|
470
|
+
// Fall back to 'claude' and let it fail with a clear error
|
|
471
|
+
this.log('warn', 'Could not find claude in npm global bin or WSL, attempting direct execution');
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Special handling for WSL commands
|
|
478
|
+
let spawnCommand = claudeCommand;
|
|
479
|
+
let spawnArgs = args;
|
|
480
|
+
|
|
481
|
+
if (claudeCommand.startsWith('wsl ')) {
|
|
482
|
+
// Split WSL command properly
|
|
483
|
+
const wslParts = claudeCommand.split(' ');
|
|
484
|
+
spawnCommand = wslParts[0]; // 'wsl'
|
|
485
|
+
spawnArgs = [...wslParts.slice(1), ...args]; // claude path + original args
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Log the exact spawn command to stderr (always visible)
|
|
489
|
+
console.error(`[INFO] Executing command: ${spawnCommand} ${spawnArgs.join(' ')}`);
|
|
490
|
+
console.error(`[INFO] Shell mode: ${process.platform === 'win32'}`);
|
|
491
|
+
|
|
492
|
+
const child = spawn(spawnCommand, spawnArgs, {
|
|
493
|
+
cwd: workingDir,
|
|
494
|
+
env: this.buildSecureEnvironment(),
|
|
495
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
496
|
+
shell: process.platform === 'win32' // Use shell on Windows for .cmd files
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
sessionInfo.childProcess = child;
|
|
500
|
+
sessionInfo.cancel = () => {
|
|
501
|
+
if (child && !child.killed) {
|
|
502
|
+
child.kill('SIGTERM');
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
let output = '';
|
|
507
|
+
let errorOutput = '';
|
|
508
|
+
|
|
509
|
+
// No need to send prompt to stdin - it's passed via -p argument
|
|
510
|
+
if (child.stdin) {
|
|
511
|
+
child.stdin.end();
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Handle stdout
|
|
515
|
+
if (child.stdout) {
|
|
516
|
+
child.stdout.on('data', (data) => {
|
|
517
|
+
const chunk = data.toString();
|
|
518
|
+
output += chunk;
|
|
519
|
+
|
|
520
|
+
// Stream to stderr for visibility
|
|
521
|
+
process.stderr.write(chunk);
|
|
522
|
+
|
|
523
|
+
// Report progress
|
|
524
|
+
progressTracker.reportMessage(chunk.trim(), 'stdout');
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Handle stderr
|
|
529
|
+
if (child.stderr) {
|
|
530
|
+
child.stderr.on('data', (data) => {
|
|
531
|
+
const chunk = data.toString();
|
|
532
|
+
errorOutput += chunk;
|
|
533
|
+
|
|
534
|
+
// Stream to stderr
|
|
535
|
+
process.stderr.write(chunk);
|
|
536
|
+
|
|
537
|
+
// Check for errors
|
|
538
|
+
if (chunk.toLowerCase().includes('error')) {
|
|
539
|
+
progressTracker.reportMessage(chunk.trim(), 'stderr');
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Handle completion
|
|
545
|
+
child.on('close', (code) => {
|
|
546
|
+
const executionTime = Date.now() - startTime;
|
|
547
|
+
|
|
548
|
+
// Clear timeout
|
|
549
|
+
clearTimeout(timeoutId);
|
|
550
|
+
|
|
551
|
+
if (code === 0) {
|
|
552
|
+
// Parse changes from output
|
|
553
|
+
const changes = FileChangeParser.parseChanges(output, workingDir);
|
|
554
|
+
|
|
555
|
+
resolve({
|
|
556
|
+
success: true,
|
|
557
|
+
sessionId: request.sessionId,
|
|
558
|
+
output,
|
|
559
|
+
changes,
|
|
560
|
+
metrics: {
|
|
561
|
+
executionTime,
|
|
562
|
+
tokensUsed: TokenEstimator.estimate(prompt + output),
|
|
563
|
+
filesModified: changes.length,
|
|
564
|
+
linesChanged: 0,
|
|
565
|
+
exitCode: code
|
|
566
|
+
},
|
|
567
|
+
metadata: {
|
|
568
|
+
command: 'claude',
|
|
569
|
+
args: args.slice(0, 5), // Limited args for security
|
|
570
|
+
model: this.config.model
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
} else {
|
|
574
|
+
// Log full error details to stderr
|
|
575
|
+
console.error(`[ERROR] Claude Code CLI failed with exit code: ${code}`);
|
|
576
|
+
console.error(`[ERROR] Full command: ${claudeCommand} ${args.join(' ')}`);
|
|
577
|
+
console.error(`[ERROR] Working directory: ${workingDir}`);
|
|
578
|
+
console.error(`[ERROR] Full stdout output:`);
|
|
579
|
+
console.error(output || '(no stdout)');
|
|
580
|
+
console.error(`[ERROR] Full stderr output:`);
|
|
581
|
+
console.error(errorOutput || '(no stderr)');
|
|
582
|
+
console.error(`[ERROR] Execution time: ${Date.now() - startTime}ms`);
|
|
583
|
+
|
|
584
|
+
reject(new BackendError(
|
|
585
|
+
`Claude Code CLI exited with code ${code}`,
|
|
586
|
+
ErrorTypes.EXECUTION_FAILED,
|
|
587
|
+
'CLI_EXECUTION_FAILED',
|
|
588
|
+
{
|
|
589
|
+
exitCode: code,
|
|
590
|
+
stdout: output.substring(0, 1000),
|
|
591
|
+
stderr: errorOutput.substring(0, 1000)
|
|
592
|
+
}
|
|
593
|
+
));
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
// Handle errors
|
|
598
|
+
child.on('error', (error) => {
|
|
599
|
+
// Clear timeout
|
|
600
|
+
clearTimeout(timeoutId);
|
|
601
|
+
|
|
602
|
+
// Log full error details to stderr
|
|
603
|
+
console.error(`[ERROR] Failed to spawn Claude Code CLI process:`);
|
|
604
|
+
console.error(`[ERROR] Command: ${spawnCommand}`);
|
|
605
|
+
console.error(`[ERROR] Args: ${spawnArgs.join(' ')}`);
|
|
606
|
+
console.error(`[ERROR] Working directory: ${workingDir}`);
|
|
607
|
+
console.error(`[ERROR] Error message: ${error.message}`);
|
|
608
|
+
console.error(`[ERROR] Error code: ${error.code || 'unknown'}`);
|
|
609
|
+
console.error(`[ERROR] Error signal: ${error.signal || 'none'}`);
|
|
610
|
+
console.error(`[ERROR] Full error:`, error);
|
|
611
|
+
|
|
612
|
+
reject(new BackendError(
|
|
613
|
+
`Failed to execute Claude Code CLI: ${error.message}`,
|
|
614
|
+
ErrorTypes.EXECUTION_FAILED,
|
|
615
|
+
'CLI_SPAWN_FAILED',
|
|
616
|
+
{ originalError: error }
|
|
617
|
+
));
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
// Set timeout
|
|
621
|
+
const timeout = request.options?.timeout || this.config.timeout;
|
|
622
|
+
const timeoutId = setTimeout(() => {
|
|
623
|
+
if (!child.killed) {
|
|
624
|
+
// Log timeout details to stderr
|
|
625
|
+
console.error(`[ERROR] Claude Code CLI timed out after ${timeout}ms`);
|
|
626
|
+
console.error(`[ERROR] Command: ${spawnCommand} ${spawnArgs.join(' ')}`);
|
|
627
|
+
console.error(`[ERROR] Working directory: ${workingDir}`);
|
|
628
|
+
console.error(`[ERROR] Partial stdout output:`);
|
|
629
|
+
console.error(output || '(no stdout)');
|
|
630
|
+
console.error(`[ERROR] Partial stderr output:`);
|
|
631
|
+
console.error(errorOutput || '(no stderr)');
|
|
632
|
+
|
|
633
|
+
child.kill('SIGTERM');
|
|
634
|
+
reject(new BackendError(
|
|
635
|
+
`Claude Code execution timed out after ${timeout}ms`,
|
|
636
|
+
ErrorTypes.TIMEOUT,
|
|
637
|
+
'CLAUDE_CODE_TIMEOUT',
|
|
638
|
+
{ timeout }
|
|
639
|
+
));
|
|
640
|
+
}
|
|
641
|
+
}, timeout);
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Build secure command arguments
|
|
648
|
+
* @param {import('../types/BackendTypes').ImplementRequest} request - Implementation request
|
|
649
|
+
* @returns {Array<string>} Secure command arguments
|
|
650
|
+
* @private
|
|
651
|
+
*/
|
|
652
|
+
buildSecureCommandArgs(request) {
|
|
653
|
+
const args = [];
|
|
654
|
+
|
|
655
|
+
// Add max turns with validation
|
|
656
|
+
const maxTurns = this.validateMaxTurns(request.options?.maxTurns || this.config.maxTurns);
|
|
657
|
+
if (process.env.DEBUG) {
|
|
658
|
+
this.log('debug', 'Max turns check', {
|
|
659
|
+
requestMaxTurns: request.options?.maxTurns,
|
|
660
|
+
configMaxTurns: this.config.maxTurns,
|
|
661
|
+
validatedMaxTurns: maxTurns
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
args.push('--max-turns', maxTurns.toString());
|
|
665
|
+
|
|
666
|
+
// Model and temperature are not supported by Claude CLI
|
|
667
|
+
// Claude CLI uses default model and temperature settings
|
|
668
|
+
|
|
669
|
+
// Always use --dangerously-skip-permissions to avoid tool permission complexity
|
|
670
|
+
args.push('--dangerously-skip-permissions');
|
|
671
|
+
|
|
672
|
+
if (process.env.DEBUG) {
|
|
673
|
+
this.log('debug', 'Final args constructed', { args });
|
|
674
|
+
}
|
|
675
|
+
return args;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Build secure environment variables
|
|
680
|
+
* @returns {Object} Secure environment variables
|
|
681
|
+
* @private
|
|
682
|
+
*/
|
|
683
|
+
buildSecureEnvironment() {
|
|
684
|
+
const env = { ...process.env };
|
|
685
|
+
|
|
686
|
+
if (this.config.apiKey && this.isValidApiKey(this.config.apiKey)) {
|
|
687
|
+
env.ANTHROPIC_API_KEY = this.config.apiKey;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
return env;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Validate API key format
|
|
695
|
+
* @param {string} apiKey - API key to validate
|
|
696
|
+
* @returns {boolean} True if valid format
|
|
697
|
+
* @private
|
|
698
|
+
*/
|
|
699
|
+
isValidApiKey(apiKey) {
|
|
700
|
+
// Just check if it's a non-empty string
|
|
701
|
+
// API key formats can vary between providers and versions
|
|
702
|
+
return apiKey && typeof apiKey === 'string' && apiKey.trim().length > 0;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Validate max turns value
|
|
708
|
+
* @param {number} maxTurns - Max turns to validate
|
|
709
|
+
* @returns {number} Validated max turns value
|
|
710
|
+
* @private
|
|
711
|
+
*/
|
|
712
|
+
validateMaxTurns(maxTurns) {
|
|
713
|
+
if (typeof maxTurns !== 'number' || isNaN(maxTurns) || maxTurns < 1) {
|
|
714
|
+
return 100; // Default value
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
return Math.min(Math.max(Math.floor(maxTurns), 1), 1000); // Clamp between 1 and 1000
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Validate prompt content
|
|
723
|
+
* @param {string} prompt - Prompt to validate
|
|
724
|
+
* @returns {string} Validated prompt
|
|
725
|
+
* @private
|
|
726
|
+
*/
|
|
727
|
+
validatePrompt(prompt) {
|
|
728
|
+
if (!prompt || typeof prompt !== 'string') {
|
|
729
|
+
throw new BackendError(
|
|
730
|
+
'Invalid prompt content',
|
|
731
|
+
ErrorTypes.VALIDATION_ERROR,
|
|
732
|
+
'INVALID_PROMPT'
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
const maxPromptLength = 100000; // 100KB limit for prompts
|
|
737
|
+
|
|
738
|
+
if (prompt.length > maxPromptLength) {
|
|
739
|
+
throw new BackendError(
|
|
740
|
+
`Prompt too long (${prompt.length} chars, max: ${maxPromptLength})`,
|
|
741
|
+
ErrorTypes.VALIDATION_ERROR,
|
|
742
|
+
'PROMPT_TOO_LONG'
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// Check for control characters that could cause issues
|
|
747
|
+
if (this.containsControlCharacters(prompt)) {
|
|
748
|
+
this.log('warn', 'Prompt contains control characters, they will be filtered');
|
|
749
|
+
return prompt.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, ''); // Remove most control chars but keep newlines/tabs
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
return prompt;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Check if string contains problematic control characters
|
|
757
|
+
* @param {string} str - String to check
|
|
758
|
+
* @returns {boolean} True if contains control characters
|
|
759
|
+
* @private
|
|
760
|
+
*/
|
|
761
|
+
containsControlCharacters(str) {
|
|
762
|
+
// Check for control characters excluding newlines and tabs
|
|
763
|
+
return /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/.test(str);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
export default ClaudeCodeBackend;
|