@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.
Files changed (444) hide show
  1. package/README.md +138 -0
  2. package/data/.env.example +22 -0
  3. package/data/.gitattributes +47 -0
  4. package/data/.glfrc.json +7 -0
  5. package/data/.husky/pre-commit +5 -0
  6. package/data/.nvmrc +1 -0
  7. package/data/CHANGELOG.md +75 -0
  8. package/data/CODE_OF_CONDUCT.md +129 -0
  9. package/data/CONTRIBUTING.md +203 -0
  10. package/data/DOCS-STRUCTURE.md +307 -0
  11. package/data/I18N.md +292 -0
  12. package/data/LICENSE +22 -0
  13. package/data/README.md +315 -0
  14. package/data/SECURITY.md +125 -0
  15. package/data/WIKI-DEPLOYMENT.md +348 -0
  16. package/data/docs/AI-FEATURES.md +610 -0
  17. package/data/docs/API-REFERENCE.md +1022 -0
  18. package/data/docs/AUTHENTICATION.md +301 -0
  19. package/data/docs/BACKEND-API.md +468 -0
  20. package/data/docs/DEVELOPMENT.md +375 -0
  21. package/data/docs/EXAMPLES.md +622 -0
  22. package/data/docs/MCP-SERVER.md +307 -0
  23. package/data/docs/MIGRATION-GUIDE.md +367 -0
  24. package/data/docs/NPM-PUBLISH.md +193 -0
  25. package/data/docs/QUICKSTART.md +206 -0
  26. package/data/docs/REDIS-SETUP.md +162 -0
  27. package/data/docs/SERVER.md +228 -0
  28. package/data/docs/TROUBLESHOOTING.md +657 -0
  29. package/data/docs/WIDGET-GUIDE.md +638 -0
  30. package/data/docs/WIKI-HOME.md +58 -0
  31. package/data/docs/WIKI-SIDEBAR.md +39 -0
  32. package/data/package.json +171 -0
  33. package/data/playwright.config.ts +64 -0
  34. package/data/probe/.cargo/config.toml +10 -0
  35. package/data/probe/.claude/commands/performance-review.md +15 -0
  36. package/data/probe/.clinerules +288 -0
  37. package/data/probe/.dockerignore +57 -0
  38. package/data/probe/.githooks/post-commit +11 -0
  39. package/data/probe/.githooks/pre-commit +99 -0
  40. package/data/probe/.githooks/pre-commit-vow +9 -0
  41. package/data/probe/.prompts/engineer.md +41 -0
  42. package/data/probe/.roomodes +28 -0
  43. package/data/probe/.windsurfrules +0 -0
  44. package/data/probe/BASH_TOOL_SUMMARY.md +148 -0
  45. package/data/probe/BENCHMARKING.md +256 -0
  46. package/data/probe/CLAUDE.md +226 -0
  47. package/data/probe/CODE_OF_CONDUCT.md +128 -0
  48. package/data/probe/CONTRIBUTING.md +193 -0
  49. package/data/probe/Cargo.toml +120 -0
  50. package/data/probe/Cross.toml +10 -0
  51. package/data/probe/DOCKER-README.md +224 -0
  52. package/data/probe/Dockerfile +32 -0
  53. package/data/probe/ENHANCED_DEBUG_TELEMETRY.md +188 -0
  54. package/data/probe/LICENSE +201 -0
  55. package/data/probe/Makefile +210 -0
  56. package/data/probe/README.md +824 -0
  57. package/data/probe/SECURITY.md +67 -0
  58. package/data/probe/WINDOWS-GUIDE.md +294 -0
  59. package/data/probe/benches/parsing_benchmarks.rs +370 -0
  60. package/data/probe/benches/search_benchmarks.rs +599 -0
  61. package/data/probe/benches/simd_benchmarks.rs +372 -0
  62. package/data/probe/benches/timing_benchmarks.rs +287 -0
  63. package/data/probe/build-windows.bat +229 -0
  64. package/data/probe/codex-config/config.toml +6 -0
  65. package/data/probe/docs/PERFORMANCE_OPTIMIZATION.md +161 -0
  66. package/data/probe/examples/cache_demo.rs +46 -0
  67. package/data/probe/examples/chat/.dockerignore +37 -0
  68. package/data/probe/examples/chat/ChatSessionManager.js +295 -0
  69. package/data/probe/examples/chat/Dockerfile +98 -0
  70. package/data/probe/examples/chat/LICENSE +201 -0
  71. package/data/probe/examples/chat/LOCAL_IMAGE_SUPPORT.md +195 -0
  72. package/data/probe/examples/chat/MCP_INTEGRATION.md +400 -0
  73. package/data/probe/examples/chat/README.md +338 -0
  74. package/data/probe/examples/chat/TRACING.md +226 -0
  75. package/data/probe/examples/chat/appTracer.js +968 -0
  76. package/data/probe/examples/chat/auth.js +76 -0
  77. package/data/probe/examples/chat/bin/probe-chat.js +13 -0
  78. package/data/probe/examples/chat/build.js +104 -0
  79. package/data/probe/examples/chat/cancelRequest.js +84 -0
  80. package/data/probe/examples/chat/demo-agentic-image-flow.js +88 -0
  81. package/data/probe/examples/chat/demo-local-images.js +128 -0
  82. package/data/probe/examples/chat/fileSpanExporter.js +181 -0
  83. package/data/probe/examples/chat/implement/README.md +228 -0
  84. package/data/probe/examples/chat/implement/backends/AiderBackend.js +750 -0
  85. package/data/probe/examples/chat/implement/backends/BaseBackend.js +276 -0
  86. package/data/probe/examples/chat/implement/backends/ClaudeCodeBackend.js +767 -0
  87. package/data/probe/examples/chat/implement/backends/MockBackend.js +237 -0
  88. package/data/probe/examples/chat/implement/backends/registry.js +85 -0
  89. package/data/probe/examples/chat/implement/core/BackendManager.js +567 -0
  90. package/data/probe/examples/chat/implement/core/ImplementTool.js +354 -0
  91. package/data/probe/examples/chat/implement/core/config.js +428 -0
  92. package/data/probe/examples/chat/implement/core/timeouts.js +58 -0
  93. package/data/probe/examples/chat/implement/core/utils.js +496 -0
  94. package/data/probe/examples/chat/implement/types/BackendTypes.js +126 -0
  95. package/data/probe/examples/chat/index.js +669 -0
  96. package/data/probe/examples/chat/mcpServer.js +341 -0
  97. package/data/probe/examples/chat/npm/LICENSE +15 -0
  98. package/data/probe/examples/chat/npm/README.md +168 -0
  99. package/data/probe/examples/chat/npm/bin/probe-chat.js +156 -0
  100. package/data/probe/examples/chat/npm/index.js +259 -0
  101. package/data/probe/examples/chat/npm/package.json +54 -0
  102. package/data/probe/examples/chat/package.json +102 -0
  103. package/data/probe/examples/chat/probeChat.js +456 -0
  104. package/data/probe/examples/chat/probeTool.js +491 -0
  105. package/data/probe/examples/chat/storage/JsonChatStorage.js +476 -0
  106. package/data/probe/examples/chat/telemetry.js +281 -0
  107. package/data/probe/examples/chat/test/integration/chatFlows.test.js +320 -0
  108. package/data/probe/examples/chat/test/integration/toolCalling.test.js +471 -0
  109. package/data/probe/examples/chat/test/mocks/mockLLMProvider.js +269 -0
  110. package/data/probe/examples/chat/test/test-backends.js +90 -0
  111. package/data/probe/examples/chat/test/testUtils.js +530 -0
  112. package/data/probe/examples/chat/test/unit/backendTimeout.test.js +161 -0
  113. package/data/probe/examples/chat/test/unit/packageFiles.test.js +120 -0
  114. package/data/probe/examples/chat/test/verify-tests.js +118 -0
  115. package/data/probe/examples/chat/test-agentic-image-loading.js +294 -0
  116. package/data/probe/examples/chat/test-ai-sdk-telemetry.js +204 -0
  117. package/data/probe/examples/chat/test-chat-tracing.js +38 -0
  118. package/data/probe/examples/chat/test-direct-function.js +49 -0
  119. package/data/probe/examples/chat/test-file-size-validation.js +103 -0
  120. package/data/probe/examples/chat/test-full-mcp-integration.js +258 -0
  121. package/data/probe/examples/chat/test-github-context.txt +12 -0
  122. package/data/probe/examples/chat/test-hierarchy.js +203 -0
  123. package/data/probe/examples/chat/test-image-spans.js +37 -0
  124. package/data/probe/examples/chat/test-local-image-reading.js +176 -0
  125. package/data/probe/examples/chat/test-mcp-integration.js +136 -0
  126. package/data/probe/examples/chat/test-mcp-probe-server.js +161 -0
  127. package/data/probe/examples/chat/test-mcp-with-ai.js +279 -0
  128. package/data/probe/examples/chat/test-multiple-allowed-dirs.js +111 -0
  129. package/data/probe/examples/chat/test-probe-mcp-server.js +110 -0
  130. package/data/probe/examples/chat/test-security-validation.js +145 -0
  131. package/data/probe/examples/chat/test-simple-tracing.js +32 -0
  132. package/data/probe/examples/chat/test-trace-verification.js +235 -0
  133. package/data/probe/examples/chat/test-tracing.js +114 -0
  134. package/data/probe/examples/chat/tokenCounter.js +419 -0
  135. package/data/probe/examples/chat/tokenUsageDisplay.js +134 -0
  136. package/data/probe/examples/chat/webServer.js +1103 -0
  137. package/data/probe/examples/reranker/Cargo.toml +33 -0
  138. package/data/probe/examples/reranker/DEBUG_OUTPUT_ANALYSIS.md +71 -0
  139. package/data/probe/examples/reranker/MODELS.md +66 -0
  140. package/data/probe/examples/reranker/MODEL_COMPARISON.md +60 -0
  141. package/data/probe/examples/reranker/MULTI_MODEL_ANALYSIS.md +176 -0
  142. package/data/probe/examples/reranker/PERFORMANCE_SUMMARY.md +156 -0
  143. package/data/probe/examples/reranker/README.md +347 -0
  144. package/data/probe/examples/reranker/RUST_BERT_COMPARISON.md +82 -0
  145. package/data/probe/examples/reranker/TOKENIZATION_GUIDE.md +120 -0
  146. package/data/probe/examples/reranker/check_rust_tokenizer.py +108 -0
  147. package/data/probe/examples/reranker/convert_to_torchscript.py +109 -0
  148. package/data/probe/examples/reranker/debug_scoring.py +189 -0
  149. package/data/probe/examples/reranker/debug_tokenization.py +154 -0
  150. package/data/probe/examples/reranker/download_models.sh +73 -0
  151. package/data/probe/examples/reranker/requirements.txt +13 -0
  152. package/data/probe/examples/reranker/run_comprehensive_benchmark.sh +83 -0
  153. package/data/probe/examples/reranker/rust_bert_test/Cargo.toml +12 -0
  154. package/data/probe/examples/reranker/rust_bert_test/README.md +54 -0
  155. package/data/probe/examples/reranker/simple_test.py +50 -0
  156. package/data/probe/examples/reranker/test_all_models.sh +63 -0
  157. package/data/probe/examples/reranker/test_bert_results.sh +44 -0
  158. package/data/probe/examples/reranker/test_cross_encoder.py +334 -0
  159. package/data/probe/examples/reranker/test_cross_encoder.sh +80 -0
  160. package/data/probe/examples/reranker/test_exact_comparison.py +151 -0
  161. package/data/probe/examples/reranker/test_parallel_performance.sh +56 -0
  162. package/data/probe/examples/reranker/test_scores.py +132 -0
  163. package/data/probe/install.ps1 +508 -0
  164. package/data/probe/install.sh +460 -0
  165. package/data/probe/npm/CLONE_METHOD_EXAMPLES.md +596 -0
  166. package/data/probe/npm/CONTEXT_COMPACTION.md +303 -0
  167. package/data/probe/npm/DELEGATE_TOOL_README.md +166 -0
  168. package/data/probe/npm/MAID_INTEGRATION.md +313 -0
  169. package/data/probe/npm/MCP_INTEGRATION_SUMMARY.md +241 -0
  170. package/data/probe/npm/README.md +824 -0
  171. package/data/probe/npm/bin/.gitignore +7 -0
  172. package/data/probe/npm/bin/.gitkeep +0 -0
  173. package/data/probe/npm/bin/README.md +12 -0
  174. package/data/probe/npm/bin/probe +167 -0
  175. package/data/probe/npm/docs/CLAUDE_CODE_INTEGRATION.md +414 -0
  176. package/data/probe/npm/docs/CODEX_INTEGRATION.md +502 -0
  177. package/data/probe/npm/docs/EDIT_CREATE_TOOLS.md +233 -0
  178. package/data/probe/npm/docs/RETRY_AND_FALLBACK.md +674 -0
  179. package/data/probe/npm/example-usage.js +335 -0
  180. package/data/probe/npm/examples/multi-engine-demo.js +117 -0
  181. package/data/probe/npm/examples/probe-agent-cli.js +113 -0
  182. package/data/probe/npm/examples/test-agent-edit.js +114 -0
  183. package/data/probe/npm/examples/test-edit-create.js +120 -0
  184. package/data/probe/npm/examples/test-edit-direct.js +114 -0
  185. package/data/probe/npm/index.d.ts +744 -0
  186. package/data/probe/npm/jest.config.js +52 -0
  187. package/data/probe/npm/package.json +117 -0
  188. package/data/probe/npm/scripts/build-agent.cjs +75 -0
  189. package/data/probe/npm/scripts/build-cjs.js +124 -0
  190. package/data/probe/npm/scripts/build-mcp.cjs +36 -0
  191. package/data/probe/npm/scripts/postinstall.js +216 -0
  192. package/data/probe/npm/test-codex-e2e.js +78 -0
  193. package/data/probe/npm/test-download-lock.js +109 -0
  194. package/data/probe/npm/test-grep-security.js +94 -0
  195. package/data/probe/npm/test-grep-simplified.js +63 -0
  196. package/data/probe/npm/test-grep.js +51 -0
  197. package/data/probe/npm/tests/README.md +96 -0
  198. package/data/probe/npm/tests/agent-compact-history.test.js +174 -0
  199. package/data/probe/npm/tests/allow-tests-default.test.js +151 -0
  200. package/data/probe/npm/tests/contextCompactor.test.js +498 -0
  201. package/data/probe/npm/tests/delegate-config.test.js +353 -0
  202. package/data/probe/npm/tests/delegate-integration.test.js +348 -0
  203. package/data/probe/npm/tests/extractor-integration.test.js +162 -0
  204. package/data/probe/npm/tests/extractor.test.js +317 -0
  205. package/data/probe/npm/tests/fixtures/sampleDiagrams.js +267 -0
  206. package/data/probe/npm/tests/integration/claude-code-auto-fallback.spec.js +148 -0
  207. package/data/probe/npm/tests/integration/claude-code-multi-step.spec.js +127 -0
  208. package/data/probe/npm/tests/integration/claude-code-tool-events.spec.js +163 -0
  209. package/data/probe/npm/tests/integration/codex-auto-fallback.spec.js +191 -0
  210. package/data/probe/npm/tests/integration/codex-tool-events.spec.js +147 -0
  211. package/data/probe/npm/tests/integration/examplesChatMcp.test.js +402 -0
  212. package/data/probe/npm/tests/integration/mcpDotenvSupport.test.js +174 -0
  213. package/data/probe/npm/tests/integration/mcpErrorHandling.test.js +566 -0
  214. package/data/probe/npm/tests/integration/mcpRobustness.test.js +564 -0
  215. package/data/probe/npm/tests/integration/mcpStdoutPurity.test.js +355 -0
  216. package/data/probe/npm/tests/integration/probeAgentMcp.test.js +398 -0
  217. package/data/probe/npm/tests/integration/retryFallback.test.js +368 -0
  218. package/data/probe/npm/tests/integration/schema-in-initial-message.test.js +318 -0
  219. package/data/probe/npm/tests/integration/schema-validation-loop-prevention.test.js +244 -0
  220. package/data/probe/npm/tests/integration/schemaRetryLogic.test.js +94 -0
  221. package/data/probe/npm/tests/integration/validationFlow.test.js +329 -0
  222. package/data/probe/npm/tests/manual/test-codex-basic.js +110 -0
  223. package/data/probe/npm/tests/mcp/mcpClientManager.test.js +614 -0
  224. package/data/probe/npm/tests/mcp/mcpConfig.test.js +359 -0
  225. package/data/probe/npm/tests/mcp/mcpXmlBridge.test.js +436 -0
  226. package/data/probe/npm/tests/mcp/mockMcpServer.js +510 -0
  227. package/data/probe/npm/tests/mcp-strict-syntax.test.js +319 -0
  228. package/data/probe/npm/tests/mermaidQuoteEscaping.test.js +214 -0
  229. package/data/probe/npm/tests/nestedQuoteFix.test.js +40 -0
  230. package/data/probe/npm/tests/setup.js +46 -0
  231. package/data/probe/npm/tests/unit/allowed-tools.test.js +513 -0
  232. package/data/probe/npm/tests/unit/attempt-completion-closing-tag-in-content.test.js +188 -0
  233. package/data/probe/npm/tests/unit/attemptCompletionJsonFix.test.js +238 -0
  234. package/data/probe/npm/tests/unit/attemptCompletionJsonIssue.test.js +128 -0
  235. package/data/probe/npm/tests/unit/backtickAutoFix.test.js +35 -0
  236. package/data/probe/npm/tests/unit/bash-probe-agent-integration.test.js +389 -0
  237. package/data/probe/npm/tests/unit/bash-simple-commands.test.js +324 -0
  238. package/data/probe/npm/tests/unit/bash-tool-comprehensive.test.js +371 -0
  239. package/data/probe/npm/tests/unit/bash-tool-integration.test.js +310 -0
  240. package/data/probe/npm/tests/unit/bash-tool.test.js +341 -0
  241. package/data/probe/npm/tests/unit/completion-prompt.test.js +379 -0
  242. package/data/probe/npm/tests/unit/cwd-path-options.test.js +287 -0
  243. package/data/probe/npm/tests/unit/delegate-limits.test.js +422 -0
  244. package/data/probe/npm/tests/unit/direct-content-attempt-completion.test.js +235 -0
  245. package/data/probe/npm/tests/unit/edit-create-tools.test.js +609 -0
  246. package/data/probe/npm/tests/unit/enhancedMermaidValidation.test.js +577 -0
  247. package/data/probe/npm/tests/unit/extract-content.test.js +83 -0
  248. package/data/probe/npm/tests/unit/extract-multiple-targets.test.js +89 -0
  249. package/data/probe/npm/tests/unit/fallbackManager.test.js +442 -0
  250. package/data/probe/npm/tests/unit/githubCompatibilityValidation.test.js +258 -0
  251. package/data/probe/npm/tests/unit/imageConfig.test.js +149 -0
  252. package/data/probe/npm/tests/unit/imagePathResolution.test.js +345 -0
  253. package/data/probe/npm/tests/unit/json-fixing-agent.test.js +238 -0
  254. package/data/probe/npm/tests/unit/json-validation-enhanced-errors.test.js +199 -0
  255. package/data/probe/npm/tests/unit/jsonValidationInfiniteLoopFix.test.js +228 -0
  256. package/data/probe/npm/tests/unit/maidIntegration.test.js +139 -0
  257. package/data/probe/npm/tests/unit/maxIterationsWarning.test.js +195 -0
  258. package/data/probe/npm/tests/unit/mermaidEdgeLabelFix.test.js +161 -0
  259. package/data/probe/npm/tests/unit/mermaidHtmlEntities.test.js +76 -0
  260. package/data/probe/npm/tests/unit/mermaidInfiniteLoopFix.test.js +64 -0
  261. package/data/probe/npm/tests/unit/mermaidValidation.test.js +723 -0
  262. package/data/probe/npm/tests/unit/mermaidValidationVisorExample.test.js +309 -0
  263. package/data/probe/npm/tests/unit/probe-agent-clone-realistic.test.js +643 -0
  264. package/data/probe/npm/tests/unit/probe-agent-clone.test.js +476 -0
  265. package/data/probe/npm/tests/unit/probe-agent-delegate.test.js +400 -0
  266. package/data/probe/npm/tests/unit/probe-agent-model-option.test.js +118 -0
  267. package/data/probe/npm/tests/unit/probeTool-security.test.js +283 -0
  268. package/data/probe/npm/tests/unit/readImageTool.test.js +418 -0
  269. package/data/probe/npm/tests/unit/retryManager.test.js +317 -0
  270. package/data/probe/npm/tests/unit/schema-aware-reminders.test.js +288 -0
  271. package/data/probe/npm/tests/unit/schemaDefinitionDetection.test.js +115 -0
  272. package/data/probe/npm/tests/unit/schemaUtils.test.js +1268 -0
  273. package/data/probe/npm/tests/unit/simpleTelemetry.test.js +282 -0
  274. package/data/probe/npm/tests/unit/simplified-attempt-completion.test.js +274 -0
  275. package/data/probe/npm/tests/unit/single-quote-json-bug.test.js +231 -0
  276. package/data/probe/npm/tests/unit/subgraphAutoFix.test.js +110 -0
  277. package/data/probe/npm/tests/unit/system-prompt.test.js +32 -0
  278. package/data/probe/npm/tests/unit/types-probe-agent-options.test.js +42 -0
  279. package/data/probe/npm/tests/unit/xmlParsing.test.js +720 -0
  280. package/data/probe/npm/tsconfig.json +21 -0
  281. package/data/probe/result1.txt +19 -0
  282. package/data/probe/result2.txt +26 -0
  283. package/data/probe/scripts/benchmark.sh +270 -0
  284. package/data/probe/scripts/cache_memory_analysis.rs +844 -0
  285. package/data/probe/scripts/claude-hook-wrapper.sh +56 -0
  286. package/data/probe/site/.env.example +10 -0
  287. package/data/probe/site/DEPLOYMENT.md +86 -0
  288. package/data/probe/site/README.md +183 -0
  289. package/data/probe/site/adding-languages.md +135 -0
  290. package/data/probe/site/ai-chat.md +427 -0
  291. package/data/probe/site/ai-integration.md +1488 -0
  292. package/data/probe/site/blog/agentic-flow-custom-xml-protocol.md +407 -0
  293. package/data/probe/site/blog/index.md +118 -0
  294. package/data/probe/site/blog/v0.6.0-release.md +426 -0
  295. package/data/probe/site/blog.md +8 -0
  296. package/data/probe/site/changelog.md +200 -0
  297. package/data/probe/site/cli-mode.md +437 -0
  298. package/data/probe/site/code-extraction.md +436 -0
  299. package/data/probe/site/contributing/README.md +9 -0
  300. package/data/probe/site/contributing/documentation-cross-references.md +215 -0
  301. package/data/probe/site/contributing/documentation-maintenance.md +275 -0
  302. package/data/probe/site/contributing/documentation-structure.md +75 -0
  303. package/data/probe/site/documentation-cross-references.md +215 -0
  304. package/data/probe/site/documentation-guide.md +132 -0
  305. package/data/probe/site/documentation-maintenance.md +275 -0
  306. package/data/probe/site/features.md +147 -0
  307. package/data/probe/site/how-it-works.md +118 -0
  308. package/data/probe/site/index.md +175 -0
  309. package/data/probe/site/index.md.bak +133 -0
  310. package/data/probe/site/installation.md +235 -0
  311. package/data/probe/site/integrations/docker.md +248 -0
  312. package/data/probe/site/integrations/github-actions.md +413 -0
  313. package/data/probe/site/language-support-overview.md +168 -0
  314. package/data/probe/site/mcp-integration.md +587 -0
  315. package/data/probe/site/mcp-server.md +304 -0
  316. package/data/probe/site/navigation-structure.md +76 -0
  317. package/data/probe/site/nodejs-sdk.md +798 -0
  318. package/data/probe/site/output-formats.md +625 -0
  319. package/data/probe/site/package.json +21 -0
  320. package/data/probe/site/public/_headers +28 -0
  321. package/data/probe/site/public/_redirects +11 -0
  322. package/data/probe/site/quick-start.md +289 -0
  323. package/data/probe/site/search-functionality.md +291 -0
  324. package/data/probe/site/search-reference.md +291 -0
  325. package/data/probe/site/supported-languages.md +215 -0
  326. package/data/probe/site/use-cases/README.md +8 -0
  327. package/data/probe/site/use-cases/advanced-cli.md +253 -0
  328. package/data/probe/site/use-cases/ai-code-editors.md +239 -0
  329. package/data/probe/site/use-cases/building-ai-tools.md +529 -0
  330. package/data/probe/site/use-cases/cli-ai-workflows.md +285 -0
  331. package/data/probe/site/use-cases/deploying-probe-web-interface.md +255 -0
  332. package/data/probe/site/use-cases/integrating-probe-into-ai-code-editors.md +161 -0
  333. package/data/probe/site/use-cases/nodejs-sdk.md +596 -0
  334. package/data/probe/site/use-cases/team-chat.md +350 -0
  335. package/data/probe/site/web-interface.md +434 -0
  336. package/data/probe/site/wrangler.toml +9 -0
  337. package/data/probe/test-api-key.sh +1 -0
  338. package/data/probe/test-probe-implementation/hello.js +7 -0
  339. package/data/probe/test_cases/demonstrate_early_termination_issues.sh +176 -0
  340. package/data/probe/test_cases/early_termination_issues.rs +533 -0
  341. package/data/probe/test_data/test_nested_struct.go +26 -0
  342. package/data/probe/tests/README.md +286 -0
  343. package/data/probe/tests/README_search_determinism_tests.md +116 -0
  344. package/data/probe/tests/adjacent_comment_test.rs +152 -0
  345. package/data/probe/tests/apostrophe_handling_tests.rs +132 -0
  346. package/data/probe/tests/block_filtering_with_ast_tests.rs +669 -0
  347. package/data/probe/tests/block_merging_tests.rs +396 -0
  348. package/data/probe/tests/c_outline_format_tests.rs +2179 -0
  349. package/data/probe/tests/cache_invalidation_issues.rs.disabled +682 -0
  350. package/data/probe/tests/cache_order_tests.rs +147 -0
  351. package/data/probe/tests/cache_query_scoping_tests.rs +221 -0
  352. package/data/probe/tests/cli_tests.rs +680 -0
  353. package/data/probe/tests/comment_context_integration_test.rs +240 -0
  354. package/data/probe/tests/common.rs +33 -0
  355. package/data/probe/tests/complex_block_merging_tests.rs +599 -0
  356. package/data/probe/tests/complex_query_block_filtering_tests.rs +422 -0
  357. package/data/probe/tests/control_flow_closing_braces_test.rs +91 -0
  358. package/data/probe/tests/cpp_outline_format_tests.rs +1507 -0
  359. package/data/probe/tests/csharp_outline_format_tests.rs +941 -0
  360. package/data/probe/tests/elastic_query_integration_tests.rs +922 -0
  361. package/data/probe/tests/extract_command_tests.rs +1848 -0
  362. package/data/probe/tests/extract_deduplication_tests.rs +146 -0
  363. package/data/probe/tests/extract_input_file_tests.rs +84 -0
  364. package/data/probe/tests/extract_prompt_tests.rs +102 -0
  365. package/data/probe/tests/filename_search_tests.rs +96 -0
  366. package/data/probe/tests/fixtures/user/AssemblyInfo.cs +3 -0
  367. package/data/probe/tests/github_extract_tests.rs +234 -0
  368. package/data/probe/tests/go_comment_test.rs +253 -0
  369. package/data/probe/tests/go_outline_format_tests.rs +2587 -0
  370. package/data/probe/tests/go_path_resolver_tests.rs +96 -0
  371. package/data/probe/tests/html_outline_format_tests.rs +637 -0
  372. package/data/probe/tests/integration_tests.rs +837 -0
  373. package/data/probe/tests/ip_whitelist_test.rs +148 -0
  374. package/data/probe/tests/java_outline_format_tests.rs +1611 -0
  375. package/data/probe/tests/javascript_extract_tests.rs +315 -0
  376. package/data/probe/tests/javascript_outline_format_tests.rs +1464 -0
  377. package/data/probe/tests/json_format_tests.rs +436 -0
  378. package/data/probe/tests/json_schema_validation_tests.rs +450 -0
  379. package/data/probe/tests/lib_usage.rs +60 -0
  380. package/data/probe/tests/line_comment_context_extension_test.rs +459 -0
  381. package/data/probe/tests/line_map_cache_tests.rs +114 -0
  382. package/data/probe/tests/markdown_integration_tests.rs +190 -0
  383. package/data/probe/tests/mocks/test_ip_whitelist.go +11 -0
  384. package/data/probe/tests/mocks/test_object.js +27 -0
  385. package/data/probe/tests/mocks/test_struct.go +50 -0
  386. package/data/probe/tests/multi_keyword_pattern_tests.rs +464 -0
  387. package/data/probe/tests/multi_language_syntax_integration_tests.rs +218 -0
  388. package/data/probe/tests/multiple_capture_groups_tests.rs +169 -0
  389. package/data/probe/tests/negative_compound_word_tests.rs +246 -0
  390. package/data/probe/tests/nested_symbol_extraction_tests.rs +99 -0
  391. package/data/probe/tests/outline_cross_file_interference_test.rs +335 -0
  392. package/data/probe/tests/outline_keyword_preservation_test.rs +67 -0
  393. package/data/probe/tests/output_format_edge_cases_tests.rs +693 -0
  394. package/data/probe/tests/parallel_extraction_tests.rs +178 -0
  395. package/data/probe/tests/parallel_search_tests.rs +355 -0
  396. package/data/probe/tests/path_resolver_tests.rs +698 -0
  397. package/data/probe/tests/php_outline_format_extended_tests.rs +928 -0
  398. package/data/probe/tests/php_outline_format_tests.rs +768 -0
  399. package/data/probe/tests/property_tests.proptest-regressions +9 -0
  400. package/data/probe/tests/property_tests.rs +118 -0
  401. package/data/probe/tests/python_outline_format_tests.rs +1538 -0
  402. package/data/probe/tests/query_command_json_tests.rs +438 -0
  403. package/data/probe/tests/query_command_tests.rs +232 -0
  404. package/data/probe/tests/query_command_xml_tests.rs +569 -0
  405. package/data/probe/tests/quoted_term_with_negative_keyword_tests.rs +216 -0
  406. package/data/probe/tests/required_terms_filename_tests.rs +116 -0
  407. package/data/probe/tests/ruby_outline_format_tests.rs +1011 -0
  408. package/data/probe/tests/rust_line_comment_context_test.rs +151 -0
  409. package/data/probe/tests/rust_outline_format_enhanced_tests.rs +725 -0
  410. package/data/probe/tests/rust_outline_format_tests.rs +843 -0
  411. package/data/probe/tests/schemas/xml_output_schema.xsd +38 -0
  412. package/data/probe/tests/search_determinism_tests.rs +451 -0
  413. package/data/probe/tests/search_hints_tests.rs +253 -0
  414. package/data/probe/tests/special_character_escaping_tests.rs +417 -0
  415. package/data/probe/tests/stemming_compound_word_filtering_tests.rs +535 -0
  416. package/data/probe/tests/strict_elastic_syntax_tests.rs +404 -0
  417. package/data/probe/tests/swift_outline_format_tests.rs +3319 -0
  418. package/data/probe/tests/symbols_tests.rs +166 -0
  419. package/data/probe/tests/test_file.rs +45 -0
  420. package/data/probe/tests/test_tokenize.rs +28 -0
  421. package/data/probe/tests/timeout_tests.rs +82 -0
  422. package/data/probe/tests/tokenization_tests.rs +195 -0
  423. package/data/probe/tests/tokenized_block_filtering_tests.rs +174 -0
  424. package/data/probe/tests/typescript_extract_tests.rs +214 -0
  425. package/data/probe/tests/typescript_outline_format_tests.rs +2188 -0
  426. package/data/probe/tests/xml_format_tests.rs +568 -0
  427. package/data/probe/tests/xml_schema_validation_tests.rs +497 -0
  428. package/data/scripts/postinstall.mjs +9 -0
  429. package/data/scripts/set-version.js +0 -0
  430. package/data/scripts/wiki-build.sh +111 -0
  431. package/data/scripts/wiki-deploy.sh +73 -0
  432. package/data/serve.json +12 -0
  433. package/data/test/demo-dynamic.html +134 -0
  434. package/data/test/demo-esm.html +105 -0
  435. package/data/test/demo-iife.html +78 -0
  436. package/data/tsconfig.json +7 -0
  437. package/data/vite.server.ts +483 -0
  438. package/data/vitest.config.ts +40 -0
  439. package/data/wiki/Home.md +58 -0
  440. package/data/wiki/_Sidebar.md +39 -0
  441. package/docs-mcp.config.json +20 -0
  442. package/package.json +56 -0
  443. package/src/config.js +111 -0
  444. package/src/index.js +395 -0
@@ -0,0 +1,750 @@
1
+ /**
2
+ * Aider backend implementation for code implementation tasks
3
+ * @module AiderBackend
4
+ */
5
+
6
+ import BaseBackend from './BaseBackend.js';
7
+ import { BackendError, ErrorTypes, ProgressTracker, FileChangeParser, TokenEstimator } from '../core/utils.js';
8
+ import { spawn, exec } from 'child_process';
9
+ import { promisify } from 'util';
10
+ import { promises as fsPromises } from 'fs';
11
+ import path from 'path';
12
+ import os from 'os';
13
+ import { TIMEOUTS, getDefaultTimeoutMs } from '../core/timeouts.js';
14
+
15
+ const execPromise = promisify(exec);
16
+
17
+ /**
18
+ * Aider implementation backend
19
+ * @class
20
+ * @extends BaseBackend
21
+ */
22
+ class AiderBackend extends BaseBackend {
23
+ constructor() {
24
+ super('aider', '1.0.0');
25
+ this.config = null;
26
+ this.aiderVersion = null;
27
+ }
28
+
29
+ /**
30
+ * @override
31
+ */
32
+ async initialize(config) {
33
+ this.config = {
34
+ command: 'aider',
35
+ timeout: getDefaultTimeoutMs(), // Use centralized default (20 minutes)
36
+ maxOutputSize: 10 * 1024 * 1024, // 10MB
37
+ additionalArgs: [],
38
+ environment: {},
39
+ autoCommit: false,
40
+ modelSelection: 'auto',
41
+ ...config
42
+ };
43
+
44
+ // Test aider availability
45
+ const available = await this.isAvailable();
46
+ if (!available) {
47
+ throw new BackendError(
48
+ 'Aider command not found or not accessible. Please install aider with: pip install aider-chat',
49
+ ErrorTypes.DEPENDENCY_MISSING,
50
+ 'AIDER_NOT_FOUND'
51
+ );
52
+ }
53
+
54
+ // Get aider version
55
+ try {
56
+ const { stdout } = await execPromise('aider --version', { timeout: TIMEOUTS.VERSION_CHECK });
57
+ this.aiderVersion = stdout.trim();
58
+ this.log('info', `Initialized with aider version: ${this.aiderVersion}`);
59
+ } catch (error) {
60
+ this.log('warn', 'Could not determine aider version', { error: error.message });
61
+ }
62
+
63
+ this.initialized = true;
64
+ }
65
+
66
+ /**
67
+ * @override
68
+ */
69
+ async isAvailable() {
70
+ try {
71
+ // Test if aider command exists
72
+ await execPromise('which aider', { timeout: TIMEOUTS.VERSION_CHECK });
73
+
74
+ // Check if API key is available
75
+ const hasApiKey = !!(
76
+ process.env.ANTHROPIC_API_KEY ||
77
+ process.env.OPENAI_API_KEY ||
78
+ process.env.GOOGLE_API_KEY ||
79
+ process.env.GEMINI_API_KEY
80
+ );
81
+
82
+ if (!hasApiKey) {
83
+ this.log('warn', 'No API key found. Aider requires ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY');
84
+ return false;
85
+ }
86
+
87
+ return true;
88
+ } catch (error) {
89
+ return false;
90
+ }
91
+ }
92
+
93
+ /**
94
+ * @override
95
+ */
96
+ getRequiredDependencies() {
97
+ return [
98
+ {
99
+ name: 'aider-chat',
100
+ type: 'pip',
101
+ version: '>=0.20.0',
102
+ installCommand: 'pip install aider-chat',
103
+ description: 'AI pair programming tool'
104
+ },
105
+ {
106
+ name: 'API Key',
107
+ type: 'environment',
108
+ description: 'One of: ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY, or GEMINI_API_KEY'
109
+ }
110
+ ];
111
+ }
112
+
113
+ /**
114
+ * @override
115
+ */
116
+ getCapabilities() {
117
+ return {
118
+ supportsLanguages: ['python', 'javascript', 'typescript', 'go', 'rust', 'java', 'cpp', 'c', 'csharp', 'ruby', 'php', 'swift'],
119
+ supportsStreaming: true,
120
+ supportsRollback: true,
121
+ supportsDirectFileEdit: true,
122
+ supportsPlanGeneration: false,
123
+ supportsTestGeneration: false,
124
+ maxConcurrentSessions: 3
125
+ };
126
+ }
127
+
128
+ /**
129
+ * @override
130
+ */
131
+ getDescription() {
132
+ return 'Aider - AI pair programming in your terminal';
133
+ }
134
+
135
+ /**
136
+ * @override
137
+ */
138
+ async execute(request) {
139
+ this.checkInitialized();
140
+
141
+ const validation = this.validateRequest(request);
142
+ if (!validation.valid) {
143
+ throw new BackendError(
144
+ `Invalid request: ${validation.errors.join(', ')}`,
145
+ ErrorTypes.VALIDATION_ERROR,
146
+ 'INVALID_REQUEST'
147
+ );
148
+ }
149
+
150
+ const sessionInfo = this.createSessionInfo(request.sessionId);
151
+ const progressTracker = new ProgressTracker(request.sessionId, request.callbacks?.onProgress);
152
+
153
+ this.activeSessions.set(request.sessionId, sessionInfo);
154
+
155
+ try {
156
+ progressTracker.startStep('prepare', 'Preparing aider execution');
157
+
158
+ // Create temporary file for task
159
+ const tempDir = os.tmpdir();
160
+ const tempFileName = `aider-task-${request.sessionId}-${Date.now()}.txt`;
161
+ const tempFilePath = path.join(tempDir, tempFileName);
162
+
163
+ await fsPromises.writeFile(tempFilePath, request.task, 'utf8');
164
+ sessionInfo.tempFile = tempFilePath;
165
+
166
+ this.log('debug', 'Created temporary task file', { path: tempFilePath });
167
+
168
+ progressTracker.endStep();
169
+ progressTracker.startStep('execute', 'Executing aider');
170
+
171
+ // Validate working directory
172
+ const workingDir = this.validateWorkingDirectory(request.context?.workingDirectory || process.cwd());
173
+
174
+ this.updateSessionStatus(request.sessionId, {
175
+ status: 'running',
176
+ progress: 25,
177
+ message: 'Aider is processing your request'
178
+ });
179
+
180
+ // Execute aider
181
+ const result = await this.executeCommand(workingDir, request, sessionInfo, progressTracker);
182
+
183
+ progressTracker.endStep();
184
+
185
+ // Clean up temp file
186
+ try {
187
+ await fsPromises.unlink(tempFilePath);
188
+ } catch (error) {
189
+ this.log('warn', 'Failed to clean up temp file', { path: tempFilePath, error: error.message });
190
+ }
191
+
192
+ this.updateSessionStatus(request.sessionId, {
193
+ status: 'completed',
194
+ progress: 100,
195
+ message: 'Implementation completed successfully'
196
+ });
197
+
198
+ return result;
199
+
200
+ } catch (error) {
201
+ // Clean up temp file on error
202
+ if (sessionInfo.tempFile) {
203
+ try {
204
+ await fsPromises.unlink(sessionInfo.tempFile);
205
+ } catch (cleanupError) {
206
+ this.log('warn', 'Failed to clean up temp file on error', { error: cleanupError.message });
207
+ }
208
+ }
209
+
210
+ this.updateSessionStatus(request.sessionId, {
211
+ status: 'failed',
212
+ message: error.message
213
+ });
214
+
215
+ if (error instanceof BackendError) {
216
+ throw error;
217
+ }
218
+
219
+ throw new BackendError(
220
+ `Aider execution failed: ${error.message}`,
221
+ ErrorTypes.EXECUTION_FAILED,
222
+ 'AIDER_EXECUTION_FAILED',
223
+ { originalError: error, sessionId: request.sessionId }
224
+ );
225
+ } finally {
226
+ this.activeSessions.delete(request.sessionId);
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Build aider command arguments
232
+ * @param {import('../types/BackendTypes').ImplementRequest} request - Implementation request
233
+ * @param {string} tempFilePath - Path to temporary file with task
234
+ * @returns {Array<string>} Command arguments array for secure execution
235
+ * @private
236
+ */
237
+ buildCommandArgs(request, tempFilePath) {
238
+ // Validate tempFilePath to prevent injection
239
+ if (!tempFilePath || typeof tempFilePath !== 'string') {
240
+ throw new BackendError(
241
+ 'Invalid temporary file path',
242
+ ErrorTypes.VALIDATION_ERROR,
243
+ 'INVALID_TEMP_FILE_PATH'
244
+ );
245
+ }
246
+
247
+ const args = [
248
+ '--yes',
249
+ '--no-check-update',
250
+ '--no-analytics',
251
+ '--message-file',
252
+ tempFilePath // Separate argument to prevent injection
253
+ ];
254
+
255
+ // Handle auto-commit option
256
+ if (!request.options?.autoCommit && !this.config.autoCommit) {
257
+ args.push('--no-auto-commits');
258
+ }
259
+
260
+ // Add model selection
261
+ const model = this.selectModel(request);
262
+ if (model) {
263
+ // Validate model name to prevent injection
264
+ if (this.isValidModelName(model)) {
265
+ args.push('--model');
266
+ args.push(model);
267
+ } else {
268
+ this.log('warn', `Invalid model name ignored: ${model}`);
269
+ }
270
+ }
271
+
272
+ // Add timeout if specified
273
+ if (request.options?.timeout || this.config.timeout) {
274
+ const timeoutSeconds = Math.floor((request.options?.timeout || this.config.timeout) / 1000);
275
+ // Note: aider doesn't have a built-in timeout, this would need to be handled at process level
276
+ }
277
+
278
+ // Add additional arguments from config with validation
279
+ if (this.config.additionalArgs && this.config.additionalArgs.length > 0) {
280
+ const validatedArgs = this.validateAdditionalArgs(this.config.additionalArgs);
281
+ args.push(...validatedArgs);
282
+ }
283
+
284
+ // Add any custom arguments from request with validation
285
+ if (request.options?.additionalArgs) {
286
+ const validatedArgs = this.validateAdditionalArgs(request.options.additionalArgs);
287
+ args.push(...validatedArgs);
288
+ }
289
+
290
+ return args;
291
+ }
292
+
293
+ /**
294
+ * Select the appropriate model based on configuration and environment
295
+ * @param {import('../types/BackendTypes').ImplementRequest} request - Implementation request
296
+ * @returns {string|null} Model identifier or null
297
+ * @private
298
+ */
299
+ selectModel(request) {
300
+ // Priority: request option > config > environment-based auto-selection
301
+ if (request.options?.model) {
302
+ return request.options.model;
303
+ }
304
+
305
+ if (this.config.model) {
306
+ return this.config.model;
307
+ }
308
+
309
+ if (this.config.modelSelection === 'auto') {
310
+ // Auto-select based on available API keys
311
+ const geminiApiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
312
+ const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
313
+ const openaiApiKey = process.env.OPENAI_API_KEY;
314
+
315
+ if (geminiApiKey) {
316
+ return 'gemini/gemini-2.5-pro';
317
+ } else if (anthropicApiKey) {
318
+ return 'claude-3-5-sonnet-20241022';
319
+ } else if (openaiApiKey) {
320
+ return 'gpt-4';
321
+ }
322
+ }
323
+
324
+ return null;
325
+ }
326
+
327
+ /**
328
+ * Validate model name to prevent command injection
329
+ * @param {string} model - Model name to validate
330
+ * @returns {boolean} True if valid, false otherwise
331
+ * @private
332
+ */
333
+ isValidModelName(model) {
334
+ // Just check if it's a non-empty string
335
+ // Model names change frequently and formats vary
336
+ return model && typeof model === 'string' && model.trim().length > 0;
337
+ }
338
+
339
+ /**
340
+ * Validate additional arguments to prevent command injection
341
+ * @param {Array<string>} args - Arguments to validate
342
+ * @returns {Array<string>} Validated arguments
343
+ * @private
344
+ */
345
+ validateAdditionalArgs(args) {
346
+ if (!Array.isArray(args)) {
347
+ this.log('warn', 'additionalArgs must be an array, ignoring');
348
+ return [];
349
+ }
350
+
351
+ const validatedArgs = [];
352
+ const maxArgLength = 500; // Reasonable limit for individual arguments
353
+
354
+ for (const arg of args) {
355
+ if (typeof arg !== 'string') {
356
+ this.log('warn', `Skipping non-string argument: ${typeof arg}`);
357
+ continue;
358
+ }
359
+
360
+ if (arg.length > maxArgLength) {
361
+ this.log('warn', `Skipping overly long argument (${arg.length} chars)`);
362
+ continue;
363
+ }
364
+
365
+ // Check for dangerous patterns
366
+ if (this.containsShellMetacharacters(arg)) {
367
+ this.log('warn', `Skipping argument with shell metacharacters: ${arg.substring(0, 50)}`);
368
+ continue;
369
+ }
370
+
371
+ // Validate common aider flags
372
+ if (this.isValidAiderArgument(arg)) {
373
+ validatedArgs.push(arg);
374
+ } else {
375
+ this.log('warn', `Skipping potentially unsafe argument: ${arg.substring(0, 50)}`);
376
+ }
377
+ }
378
+
379
+ return validatedArgs;
380
+ }
381
+
382
+ /**
383
+ * Check if string contains shell metacharacters
384
+ * @param {string} str - String to check
385
+ * @returns {boolean} True if contains metacharacters
386
+ * @private
387
+ */
388
+ containsShellMetacharacters(str) {
389
+ // Common shell metacharacters that could be used for injection
390
+ const shellMetacharacters = /[;&|`$(){}[\]<>*?'"\\]/;
391
+ const controlChars = /[\x00-\x1f\x7f]/; // Control characters
392
+
393
+ return shellMetacharacters.test(str) || controlChars.test(str);
394
+ }
395
+
396
+ /**
397
+ * Validate if argument is a known safe aider argument
398
+ * @param {string} arg - Argument to validate
399
+ * @returns {boolean} True if valid aider argument
400
+ * @private
401
+ */
402
+ isValidAiderArgument(arg) {
403
+ // Whitelist of known safe aider arguments
404
+ const safeAiderFlags = [
405
+ '--yes', '--no-check-update', '--no-analytics', '--no-auto-commits',
406
+ '--model', '--message-file', '--dry-run', '--map-tokens', '--show-model-warnings',
407
+ '--no-show-model-warnings', '--edit-format', '--architect', '--weak-model',
408
+ '--cache-prompts', '--no-cache-prompts', '--map-refresh', '--restore-chat-history',
409
+ '--encoding', '--config'
410
+ ];
411
+
412
+ // Check if it's a known flag
413
+ if (safeAiderFlags.includes(arg)) {
414
+ return true;
415
+ }
416
+
417
+ // Check if it's a flag with equals sign (like --model=value)
418
+ for (const flag of safeAiderFlags) {
419
+ if (arg.startsWith(flag + '=')) {
420
+ const value = arg.substring(flag.length + 1);
421
+ return !this.containsShellMetacharacters(value) && value.length <= 100;
422
+ }
423
+ }
424
+
425
+ // Allow simple values that don't look like flags if they're safe
426
+ if (!arg.startsWith('-') && !this.containsShellMetacharacters(arg) && arg.length <= 100) {
427
+ return true;
428
+ }
429
+
430
+ return false;
431
+ }
432
+
433
+ /**
434
+ * Validate command path to prevent command injection
435
+ * @param {string} command - Command to validate
436
+ * @returns {boolean} True if valid
437
+ * @private
438
+ */
439
+ isValidCommand(command) {
440
+ if (!command || typeof command !== 'string') {
441
+ return false;
442
+ }
443
+
444
+ // Only allow alphanumeric, hyphens, underscores, and forward slashes for paths
445
+ const validCommandPattern = /^[a-zA-Z0-9._/-]+$/;
446
+ const maxLength = 200; // Reasonable limit for command paths
447
+
448
+ return validCommandPattern.test(command) &&
449
+ command.length <= maxLength &&
450
+ !this.containsShellMetacharacters(command);
451
+ }
452
+
453
+ /**
454
+ * Validate working directory path
455
+ * @param {string} dir - Directory path to validate
456
+ * @returns {string} Validated directory path
457
+ * @private
458
+ */
459
+ validateWorkingDirectory(dir) {
460
+ if (!dir || typeof dir !== 'string') {
461
+ throw new BackendError(
462
+ 'Invalid working directory',
463
+ ErrorTypes.VALIDATION_ERROR,
464
+ 'INVALID_WORKING_DIRECTORY'
465
+ );
466
+ }
467
+
468
+ // Resolve path to prevent directory traversal
469
+ const resolvedPath = path.resolve(dir);
470
+
471
+ // Basic validation - ensure it doesn't contain obvious injection attempts
472
+ if (this.containsShellMetacharacters(resolvedPath)) {
473
+ throw new BackendError(
474
+ 'Working directory contains unsafe characters',
475
+ ErrorTypes.VALIDATION_ERROR,
476
+ 'UNSAFE_WORKING_DIRECTORY'
477
+ );
478
+ }
479
+
480
+ return resolvedPath;
481
+ }
482
+
483
+ /**
484
+ * Validate environment variables
485
+ * @param {Object} env - Environment variables to validate
486
+ * @returns {Object} Validated environment variables
487
+ * @private
488
+ */
489
+ validateEnvironment(env) {
490
+ if (!env || typeof env !== 'object') {
491
+ return {};
492
+ }
493
+
494
+ const validatedEnv = {};
495
+ const maxValueLength = 1000; // Reasonable limit for env values
496
+
497
+ for (const [key, value] of Object.entries(env)) {
498
+ // Validate key
499
+ if (typeof key !== 'string' || !/^[A-Z_][A-Z0-9_]*$/i.test(key)) {
500
+ this.log('warn', `Skipping invalid environment variable key: ${key}`);
501
+ continue;
502
+ }
503
+
504
+ // Validate value
505
+ if (typeof value !== 'string') {
506
+ this.log('warn', `Skipping non-string environment variable value for: ${key}`);
507
+ continue;
508
+ }
509
+
510
+ if (value.length > maxValueLength) {
511
+ this.log('warn', `Skipping overly long environment variable value for: ${key}`);
512
+ continue;
513
+ }
514
+
515
+ // Don't allow control characters in environment variables
516
+ if (/[\x00-\x1f\x7f]/.test(value)) {
517
+ this.log('warn', `Skipping environment variable with control characters: ${key}`);
518
+ continue;
519
+ }
520
+
521
+ validatedEnv[key] = value;
522
+ }
523
+
524
+ return validatedEnv;
525
+ }
526
+
527
+ /**
528
+ * Execute aider command
529
+ * @param {string} workingDir - Working directory
530
+ * @param {import('../types/BackendTypes').ImplementRequest} request - Implementation request
531
+ * @param {Object} sessionInfo - Session information
532
+ * @param {ProgressTracker} progressTracker - Progress tracker
533
+ * @returns {Promise<import('../types/BackendTypes').ImplementResult>}
534
+ * @private
535
+ */
536
+ async executeCommand(workingDir, request, sessionInfo, progressTracker) {
537
+ return new Promise((resolve, reject) => {
538
+ const startTime = Date.now();
539
+
540
+ // Build command arguments securely
541
+ const commandArgs = this.buildCommandArgs(request, sessionInfo.tempFile);
542
+ const commandPath = this.config.command || 'aider';
543
+
544
+ this.log('info', 'Executing aider command', {
545
+ command: commandPath,
546
+ args: commandArgs.slice(0, 5), // Log first few args only for security
547
+ workingDir
548
+ });
549
+
550
+ // Validate command exists and is safe
551
+ if (!this.isValidCommand(commandPath)) {
552
+ throw new BackendError(
553
+ 'Invalid or unsafe command path',
554
+ ErrorTypes.VALIDATION_ERROR,
555
+ 'INVALID_COMMAND_PATH'
556
+ );
557
+ }
558
+
559
+ // Spawn the process directly (no shell interpretation)
560
+ const childProcess = spawn(commandPath, commandArgs, {
561
+ cwd: workingDir,
562
+ env: { ...process.env, ...this.validateEnvironment(this.config.environment) }
563
+ });
564
+
565
+ sessionInfo.childProcess = childProcess;
566
+ sessionInfo.cancel = () => {
567
+ if (childProcess && !childProcess.killed) {
568
+ this.log('info', 'Cancelling aider process', { sessionId: request.sessionId });
569
+ childProcess.kill('SIGTERM');
570
+ setTimeout(() => {
571
+ if (!childProcess.killed) {
572
+ childProcess.kill('SIGKILL');
573
+ }
574
+ }, 5000);
575
+ }
576
+ };
577
+
578
+ let stdoutData = '';
579
+ let stderrData = '';
580
+ let outputSize = 0;
581
+ let lastProgressUpdate = Date.now();
582
+
583
+ // Handle stdout
584
+ childProcess.stdout.on('data', (data) => {
585
+ const output = data.toString();
586
+ outputSize += output.length;
587
+
588
+ // Check output size limit
589
+ if (outputSize > this.config.maxOutputSize) {
590
+ childProcess.kill('SIGTERM');
591
+ reject(new BackendError(
592
+ 'Output size exceeded maximum limit',
593
+ ErrorTypes.EXECUTION_FAILED,
594
+ 'OUTPUT_TOO_LARGE',
595
+ { limit: this.config.maxOutputSize, actual: outputSize }
596
+ ));
597
+ return;
598
+ }
599
+
600
+ stdoutData += output;
601
+
602
+ // Stream output to stderr for real-time visibility
603
+ process.stderr.write(output);
604
+
605
+ // Send progress updates (throttled)
606
+ const now = Date.now();
607
+ if (now - lastProgressUpdate > 1000) { // Update every second
608
+ progressTracker.reportMessage(output.trim(), 'stdout');
609
+ lastProgressUpdate = now;
610
+
611
+ // Update session progress
612
+ const elapsedSeconds = Math.floor((now - startTime) / 1000);
613
+ const estimatedProgress = Math.min(25 + (elapsedSeconds * 2), 90); // Cap at 90%
614
+ this.updateSessionStatus(request.sessionId, {
615
+ progress: estimatedProgress
616
+ });
617
+ }
618
+ });
619
+
620
+ // Handle stderr
621
+ childProcess.stderr.on('data', (data) => {
622
+ const output = data.toString();
623
+ stderrData += output;
624
+
625
+ // Stream to stderr
626
+ process.stderr.write(output);
627
+
628
+ // Report warnings
629
+ if (output.toLowerCase().includes('warning') || output.toLowerCase().includes('error')) {
630
+ progressTracker.reportMessage(output.trim(), 'stderr');
631
+ }
632
+ });
633
+
634
+ // Handle process completion
635
+ childProcess.on('close', (code) => {
636
+ const executionTime = Date.now() - startTime;
637
+
638
+ // Clear timeout
639
+ clearTimeout(timeoutId);
640
+
641
+ this.log('info', `Aider process exited`, {
642
+ code,
643
+ executionTime,
644
+ outputSize: stdoutData.length
645
+ });
646
+
647
+ // Parse file changes from output
648
+ const changes = FileChangeParser.parseChanges(stdoutData + stderrData, workingDir);
649
+ const diffStats = FileChangeParser.extractDiffStats(stdoutData + stderrData);
650
+
651
+ if (code === 0) {
652
+ // Check for errors in output even if exit code is 0
653
+ const combinedOutput = stdoutData + stderrData;
654
+ const hasAuthError = /AuthenticationError|Invalid API key|insufficient permissions|not able to authenticate/i.test(combinedOutput);
655
+ const hasOtherErrors = /Error:|Exception:|Failed:|fatal:/i.test(combinedOutput);
656
+ const hasChanges = changes.length > 0;
657
+
658
+ // Only consider it successful if:
659
+ // 1. No authentication/critical errors found in output
660
+ // 2. Either changes were made OR this was an informational command
661
+ const isActualSuccess = !hasAuthError && !hasOtherErrors && (hasChanges || !request.requiresChanges);
662
+
663
+ if (isActualSuccess) {
664
+ resolve({
665
+ success: true,
666
+ sessionId: request.sessionId,
667
+ output: stdoutData,
668
+ changes,
669
+ metrics: {
670
+ executionTime,
671
+ filesModified: changes.length,
672
+ linesChanged: diffStats.insertions + diffStats.deletions,
673
+ tokensUsed: TokenEstimator.estimate(request.task + stdoutData),
674
+ exitCode: code
675
+ },
676
+ metadata: {
677
+ command: commandPath,
678
+ args: commandArgs.slice(0, 5), // Limited args for security
679
+ workingDirectory: workingDir,
680
+ aiderVersion: this.aiderVersion
681
+ }
682
+ });
683
+ } else {
684
+ // Exit code 0 but actual failure detected
685
+ const errorType = hasAuthError ? 'AUTHENTICATION_ERROR' : 'EXECUTION_FAILED';
686
+ const errorMessage = hasAuthError
687
+ ? 'Authentication failed - check API key and permissions'
688
+ : `Aider completed but encountered errors: ${combinedOutput.substring(0, 200)}...`;
689
+
690
+ reject(new BackendError(
691
+ errorMessage,
692
+ hasAuthError ? ErrorTypes.AUTHENTICATION : ErrorTypes.EXECUTION_FAILED,
693
+ errorType,
694
+ {
695
+ exitCode: code,
696
+ hasChanges,
697
+ hasAuthError,
698
+ hasOtherErrors,
699
+ stdout: stdoutData.substring(0, 1000),
700
+ stderr: stderrData.substring(0, 1000)
701
+ }
702
+ ));
703
+ }
704
+ } else {
705
+ reject(new BackendError(
706
+ `Aider process exited with code ${code}`,
707
+ ErrorTypes.EXECUTION_FAILED,
708
+ 'AIDER_PROCESS_FAILED',
709
+ {
710
+ exitCode: code,
711
+ stdout: stdoutData.substring(0, 1000),
712
+ stderr: stderrData.substring(0, 1000)
713
+ }
714
+ ));
715
+ }
716
+ });
717
+
718
+ // Handle process errors
719
+ childProcess.on('error', (error) => {
720
+ // Clear timeout
721
+ clearTimeout(timeoutId);
722
+
723
+ this.log('error', 'Failed to spawn aider process', { error: error.message });
724
+ reject(new BackendError(
725
+ `Failed to spawn aider process: ${error.message}`,
726
+ ErrorTypes.EXECUTION_FAILED,
727
+ 'AIDER_SPAWN_FAILED',
728
+ { originalError: error }
729
+ ));
730
+ });
731
+
732
+ // Set timeout
733
+ const timeout = request.options?.timeout || this.config.timeout;
734
+ const timeoutId = setTimeout(() => {
735
+ if (!childProcess.killed) {
736
+ this.log('warn', 'Aider execution timed out', { timeout });
737
+ childProcess.kill('SIGTERM');
738
+ reject(new BackendError(
739
+ `Aider execution timed out after ${timeout}ms`,
740
+ ErrorTypes.TIMEOUT,
741
+ 'AIDER_TIMEOUT',
742
+ { timeout }
743
+ ));
744
+ }
745
+ }, timeout);
746
+ });
747
+ }
748
+ }
749
+
750
+ export default AiderBackend;