@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,283 @@
1
+ /**
2
+ * Tests for probeTool security validations
3
+ * @module tests/unit/probeTool-security
4
+ */
5
+
6
+ import { jest, describe, test, expect, beforeEach, afterEach } from '@jest/globals';
7
+ import { listFilesTool, searchFilesTool } from '../../src/agent/probeTool.js';
8
+ import path from 'path';
9
+ import { promises as fsPromises } from 'fs';
10
+ import os from 'os';
11
+
12
+ describe('ProbeTool Security', () => {
13
+ let testWorkspace;
14
+ let outsideDir;
15
+
16
+ beforeEach(async () => {
17
+ // Create a temporary workspace directory
18
+ testWorkspace = path.join(os.tmpdir(), `probe-test-${Date.now()}`);
19
+ await fsPromises.mkdir(testWorkspace, { recursive: true });
20
+
21
+ // Create a test file inside the workspace
22
+ await fsPromises.writeFile(
23
+ path.join(testWorkspace, 'test-file.txt'),
24
+ 'test content'
25
+ );
26
+
27
+ // Create a directory outside the workspace
28
+ outsideDir = path.join(os.tmpdir(), `probe-outside-${Date.now()}`);
29
+ await fsPromises.mkdir(outsideDir, { recursive: true });
30
+ await fsPromises.writeFile(
31
+ path.join(outsideDir, 'outside-file.txt'),
32
+ 'outside content'
33
+ );
34
+ });
35
+
36
+ afterEach(async () => {
37
+ // Clean up test directories
38
+ try {
39
+ await fsPromises.rm(testWorkspace, { recursive: true, force: true });
40
+ await fsPromises.rm(outsideDir, { recursive: true, force: true });
41
+ } catch (error) {
42
+ // Ignore cleanup errors
43
+ }
44
+ });
45
+
46
+ describe('listFilesTool Security', () => {
47
+ test('should allow access to workspace directory', async () => {
48
+ const result = await listFilesTool.execute({
49
+ directory: '.',
50
+ workingDirectory: testWorkspace
51
+ });
52
+
53
+ expect(result).toContain('test-file.txt');
54
+ });
55
+
56
+ test('should allow access to subdirectories within workspace using relative paths', async () => {
57
+ // Create a subdirectory
58
+ const subdir = path.join(testWorkspace, 'subdir');
59
+ await fsPromises.mkdir(subdir);
60
+ await fsPromises.writeFile(path.join(subdir, 'sub-file.txt'), 'sub content');
61
+
62
+ const result = await listFilesTool.execute({
63
+ directory: 'subdir',
64
+ workingDirectory: testWorkspace
65
+ });
66
+
67
+ expect(result).toContain('sub-file.txt');
68
+ });
69
+
70
+ test('should reject absolute path outside workspace', async () => {
71
+ await expect(async () => {
72
+ await listFilesTool.execute({
73
+ directory: outsideDir,
74
+ workingDirectory: testWorkspace
75
+ });
76
+ }).rejects.toThrow(/Path traversal attempt detected/);
77
+ });
78
+
79
+ test('should reject path traversal using ../..', async () => {
80
+ await expect(async () => {
81
+ await listFilesTool.execute({
82
+ directory: '../../../',
83
+ workingDirectory: testWorkspace
84
+ });
85
+ }).rejects.toThrow(/Path traversal attempt detected/);
86
+ });
87
+
88
+ test('should reject absolute path to system directories', async () => {
89
+ await expect(async () => {
90
+ await listFilesTool.execute({
91
+ directory: '/etc',
92
+ workingDirectory: testWorkspace
93
+ });
94
+ }).rejects.toThrow(/Path traversal attempt detected/);
95
+ });
96
+
97
+ test('should reject absolute path to home directory', async () => {
98
+ const homeDir = os.homedir();
99
+ await expect(async () => {
100
+ await listFilesTool.execute({
101
+ directory: homeDir,
102
+ workingDirectory: testWorkspace
103
+ });
104
+ }).rejects.toThrow(/Path traversal attempt detected/);
105
+ });
106
+
107
+ test('should allow access to workspace root using absolute path', async () => {
108
+ const result = await listFilesTool.execute({
109
+ directory: testWorkspace,
110
+ workingDirectory: testWorkspace
111
+ });
112
+
113
+ expect(result).toContain('test-file.txt');
114
+ });
115
+
116
+ test('should allow access to subdirectory using absolute path within workspace', async () => {
117
+ // Create a subdirectory
118
+ const subdir = path.join(testWorkspace, 'subdir');
119
+ await fsPromises.mkdir(subdir);
120
+ await fsPromises.writeFile(path.join(subdir, 'sub-file.txt'), 'sub content');
121
+
122
+ const result = await listFilesTool.execute({
123
+ directory: subdir,
124
+ workingDirectory: testWorkspace
125
+ });
126
+
127
+ expect(result).toContain('sub-file.txt');
128
+ });
129
+ });
130
+
131
+ describe('searchFilesTool Security', () => {
132
+ test('should allow searching in workspace directory', async () => {
133
+ const result = await searchFilesTool.execute({
134
+ pattern: '*.txt',
135
+ directory: '.',
136
+ workingDirectory: testWorkspace
137
+ });
138
+
139
+ expect(result).toContain('test-file.txt');
140
+ });
141
+
142
+ test('should allow searching in subdirectories within workspace using relative paths', async () => {
143
+ // Create a subdirectory
144
+ const subdir = path.join(testWorkspace, 'subdir');
145
+ await fsPromises.mkdir(subdir);
146
+ await fsPromises.writeFile(path.join(subdir, 'sub-file.txt'), 'sub content');
147
+
148
+ const result = await searchFilesTool.execute({
149
+ pattern: '*.txt',
150
+ directory: 'subdir',
151
+ workingDirectory: testWorkspace
152
+ });
153
+
154
+ expect(result).toContain('sub-file.txt');
155
+ });
156
+
157
+ test('should reject absolute path outside workspace', async () => {
158
+ await expect(async () => {
159
+ await searchFilesTool.execute({
160
+ pattern: '*.txt',
161
+ directory: outsideDir,
162
+ workingDirectory: testWorkspace
163
+ });
164
+ }).rejects.toThrow(/Path traversal attempt detected/);
165
+ });
166
+
167
+ test('should reject path traversal using ../..', async () => {
168
+ await expect(async () => {
169
+ await searchFilesTool.execute({
170
+ pattern: '*.txt',
171
+ directory: '../../../',
172
+ workingDirectory: testWorkspace
173
+ });
174
+ }).rejects.toThrow(/Path traversal attempt detected/);
175
+ });
176
+
177
+ test('should reject absolute path to system directories', async () => {
178
+ await expect(async () => {
179
+ await searchFilesTool.execute({
180
+ pattern: '*.txt',
181
+ directory: '/etc',
182
+ workingDirectory: testWorkspace
183
+ });
184
+ }).rejects.toThrow(/Path traversal attempt detected/);
185
+ });
186
+
187
+ test('should reject absolute path to home directory', async () => {
188
+ const homeDir = os.homedir();
189
+ await expect(async () => {
190
+ await searchFilesTool.execute({
191
+ pattern: '*.txt',
192
+ directory: homeDir,
193
+ workingDirectory: testWorkspace
194
+ });
195
+ }).rejects.toThrow(/Path traversal attempt detected/);
196
+ });
197
+
198
+ test('should allow searching workspace root using absolute path', async () => {
199
+ const result = await searchFilesTool.execute({
200
+ pattern: '*.txt',
201
+ directory: testWorkspace,
202
+ workingDirectory: testWorkspace
203
+ });
204
+
205
+ expect(result).toContain('test-file.txt');
206
+ });
207
+
208
+ test('should allow searching subdirectory using absolute path within workspace', async () => {
209
+ // Create a subdirectory
210
+ const subdir = path.join(testWorkspace, 'subdir');
211
+ await fsPromises.mkdir(subdir);
212
+ await fsPromises.writeFile(path.join(subdir, 'sub-file.txt'), 'sub content');
213
+
214
+ const result = await searchFilesTool.execute({
215
+ pattern: '*.txt',
216
+ directory: subdir,
217
+ workingDirectory: testWorkspace
218
+ });
219
+
220
+ expect(result).toContain('sub-file.txt');
221
+ });
222
+ });
223
+
224
+ describe('Dependency Path Bypass', () => {
225
+ test('should allow /dep/ prefix paths to bypass workspace restrictions', async () => {
226
+ // This should not throw a "Path traversal" error even though it's outside workspace
227
+ // It may throw other errors (e.g., directory not found), but not security errors
228
+ try {
229
+ await listFilesTool.execute({
230
+ directory: '/dep/go/fmt',
231
+ workingDirectory: testWorkspace
232
+ });
233
+ } catch (error) {
234
+ expect(error.message).not.toMatch(/Path traversal attempt detected/);
235
+ }
236
+ });
237
+
238
+ test('should allow go: prefix paths to bypass workspace restrictions', async () => {
239
+ try {
240
+ await listFilesTool.execute({
241
+ directory: 'go:fmt',
242
+ workingDirectory: testWorkspace
243
+ });
244
+ } catch (error) {
245
+ expect(error.message).not.toMatch(/Path traversal attempt detected/);
246
+ }
247
+ });
248
+
249
+ test('should allow js: prefix paths to bypass workspace restrictions', async () => {
250
+ try {
251
+ await listFilesTool.execute({
252
+ directory: 'js:express',
253
+ workingDirectory: testWorkspace
254
+ });
255
+ } catch (error) {
256
+ expect(error.message).not.toMatch(/Path traversal attempt detected/);
257
+ }
258
+ });
259
+
260
+ test('should allow rust: prefix paths to bypass workspace restrictions', async () => {
261
+ try {
262
+ await listFilesTool.execute({
263
+ directory: 'rust:serde',
264
+ workingDirectory: testWorkspace
265
+ });
266
+ } catch (error) {
267
+ expect(error.message).not.toMatch(/Path traversal attempt detected/);
268
+ }
269
+ });
270
+
271
+ test('should allow /dep/ prefix in searchFilesTool', async () => {
272
+ try {
273
+ await searchFilesTool.execute({
274
+ pattern: '*.go',
275
+ directory: '/dep/go/fmt',
276
+ workingDirectory: testWorkspace
277
+ });
278
+ } catch (error) {
279
+ expect(error.message).not.toMatch(/Path traversal attempt detected/);
280
+ }
281
+ });
282
+ });
283
+ });
@@ -0,0 +1,418 @@
1
+ import { jest, describe, test, expect, beforeEach, afterEach } from '@jest/globals';
2
+
3
+ // Mock all the heavy dependencies that ProbeAgent uses
4
+ jest.mock('@ai-sdk/anthropic', () => ({}));
5
+ jest.mock('@ai-sdk/openai', () => ({}));
6
+ jest.mock('@ai-sdk/google', () => ({}));
7
+ jest.mock('@ai-sdk/amazon-bedrock', () => ({}));
8
+ jest.mock('ai', () => ({
9
+ generateText: jest.fn(),
10
+ streamText: jest.fn(),
11
+ tool: jest.fn((config) => ({
12
+ name: config.name,
13
+ description: config.description,
14
+ inputSchema: config.inputSchema,
15
+ execute: config.execute
16
+ }))
17
+ }));
18
+
19
+ import { ProbeAgent } from '../../src/agent/ProbeAgent.js';
20
+ import { writeFileSync, unlinkSync, existsSync, mkdirSync, rmSync } from 'fs';
21
+ import { join } from 'path';
22
+
23
+ describe('ReadImage Tool', () => {
24
+ let testDir;
25
+ let agent;
26
+ let testImagePath;
27
+
28
+ beforeEach(() => {
29
+ // Create a test directory structure
30
+ testDir = join(process.cwd(), 'test-readimage-temp');
31
+ if (!existsSync(testDir)) {
32
+ mkdirSync(testDir, { recursive: true });
33
+ }
34
+
35
+ // Create a simple 1x1 PNG image
36
+ const simplePng = Buffer.from([
37
+ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
38
+ 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
39
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
40
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4,
41
+ 0x89, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x44, 0x41,
42
+ 0x54, 0x78, 0x9C, 0x62, 0x00, 0x02, 0x00, 0x00,
43
+ 0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00,
44
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
45
+ 0x42, 0x60, 0x82
46
+ ]);
47
+
48
+ testImagePath = join(testDir, 'test-screenshot.png');
49
+ writeFileSync(testImagePath, simplePng);
50
+
51
+ // Initialize agent with the test directory
52
+ agent = new ProbeAgent({
53
+ debug: false,
54
+ path: testDir
55
+ });
56
+ });
57
+
58
+ afterEach(() => {
59
+ // Cleanup
60
+ if (existsSync(testDir)) {
61
+ rmSync(testDir, { recursive: true, force: true });
62
+ }
63
+ });
64
+
65
+ describe('Tool availability', () => {
66
+ test('readImage tool should be available in toolImplementations', () => {
67
+ expect(agent.toolImplementations).toHaveProperty('readImage');
68
+ expect(agent.toolImplementations.readImage).toHaveProperty('execute');
69
+ expect(typeof agent.toolImplementations.readImage.execute).toBe('function');
70
+ });
71
+
72
+ test('readImage tool should be in allowed tools by default', () => {
73
+ expect(agent.allowedTools.isEnabled('readImage')).toBe(true);
74
+ });
75
+ });
76
+
77
+ describe('Tool execution', () => {
78
+ test('should successfully load image when given valid path', async () => {
79
+ const result = await agent.toolImplementations.readImage.execute({
80
+ path: testImagePath
81
+ });
82
+
83
+ expect(result).toContain('Image loaded successfully');
84
+ expect(result).toContain(testImagePath);
85
+
86
+ // Verify image was actually loaded into pendingImages
87
+ expect(agent.pendingImages.has(testImagePath)).toBe(true);
88
+
89
+ // Verify it can be retrieved
90
+ const loadedImages = agent.getCurrentImages();
91
+ expect(loadedImages.length).toBeGreaterThan(0);
92
+ expect(loadedImages[0]).toMatch(/^data:image\/png;base64,/);
93
+ });
94
+
95
+ test('should throw error when path parameter is missing', async () => {
96
+ await expect(
97
+ agent.toolImplementations.readImage.execute({})
98
+ ).rejects.toThrow('Image path is required');
99
+ });
100
+
101
+ test('should throw error when image file does not exist', async () => {
102
+ const nonExistentPath = join(testDir, 'nonexistent.png');
103
+
104
+ await expect(
105
+ agent.toolImplementations.readImage.execute({
106
+ path: nonExistentPath
107
+ })
108
+ ).rejects.toThrow();
109
+ });
110
+
111
+ test('should handle relative paths correctly', async () => {
112
+ // Create image in a subdirectory
113
+ const subDir = join(testDir, 'images');
114
+ mkdirSync(subDir, { recursive: true });
115
+
116
+ const simplePng = Buffer.from([
117
+ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
118
+ 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
119
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
120
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4,
121
+ 0x89, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x44, 0x41,
122
+ 0x54, 0x78, 0x9C, 0x62, 0x00, 0x02, 0x00, 0x00,
123
+ 0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00,
124
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
125
+ 0x42, 0x60, 0x82
126
+ ]);
127
+
128
+ const imagePath = join(subDir, 'relative.png');
129
+ writeFileSync(imagePath, simplePng);
130
+
131
+ const result = await agent.toolImplementations.readImage.execute({
132
+ path: imagePath
133
+ });
134
+
135
+ expect(result).toContain('Image loaded successfully');
136
+ expect(agent.pendingImages.has(imagePath)).toBe(true);
137
+ });
138
+
139
+ test('should support multiple image formats', async () => {
140
+ const formats = ['test.png', 'test.jpg', 'test.jpeg', 'test.webp', 'test.bmp'];
141
+
142
+ // Create a simple PNG for all tests (format validation happens elsewhere)
143
+ const simplePng = Buffer.from([
144
+ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
145
+ 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
146
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
147
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4,
148
+ 0x89, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x44, 0x41,
149
+ 0x54, 0x78, 0x9C, 0x62, 0x00, 0x02, 0x00, 0x00,
150
+ 0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00,
151
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
152
+ 0x42, 0x60, 0x82
153
+ ]);
154
+
155
+ for (const filename of formats) {
156
+ const imagePath = join(testDir, filename);
157
+ writeFileSync(imagePath, simplePng);
158
+
159
+ const result = await agent.toolImplementations.readImage.execute({
160
+ path: imagePath
161
+ });
162
+
163
+ expect(result).toContain('Image loaded successfully');
164
+ expect(agent.pendingImages.has(imagePath)).toBe(true);
165
+ }
166
+ });
167
+
168
+ test('should not load the same image twice', async () => {
169
+ // Load image first time
170
+ await agent.toolImplementations.readImage.execute({
171
+ path: testImagePath
172
+ });
173
+
174
+ const imagesAfterFirst = agent.getCurrentImages().length;
175
+
176
+ // Load same image again
177
+ await agent.toolImplementations.readImage.execute({
178
+ path: testImagePath
179
+ });
180
+
181
+ const imagesAfterSecond = agent.getCurrentImages().length;
182
+
183
+ // Should still have same number of images (no duplicate)
184
+ expect(imagesAfterSecond).toBe(imagesAfterFirst);
185
+ });
186
+ });
187
+
188
+ describe('Security', () => {
189
+ test('should respect allowed folders security', async () => {
190
+ // Create agent with restricted allowed folders
191
+ const restrictedAgent = new ProbeAgent({
192
+ debug: false,
193
+ path: testDir,
194
+ allowedFolders: [testDir] // Only allow test directory
195
+ });
196
+
197
+ // Try to load image outside allowed folder
198
+ const outsidePath = '/tmp/malicious.png';
199
+
200
+ await expect(
201
+ restrictedAgent.toolImplementations.readImage.execute({
202
+ path: outsidePath
203
+ })
204
+ ).rejects.toThrow();
205
+ });
206
+
207
+ test('should validate file size limits', async () => {
208
+ // The loadImageIfValid method should enforce MAX_IMAGE_FILE_SIZE (20MB)
209
+ // This test verifies the tool respects that limit
210
+ const result = await agent.toolImplementations.readImage.execute({
211
+ path: testImagePath
212
+ });
213
+
214
+ expect(result).toContain('Image loaded successfully');
215
+ });
216
+
217
+ test('should prevent path traversal attacks with .. sequences', async () => {
218
+ const restrictedAgent = new ProbeAgent({
219
+ debug: false,
220
+ path: testDir,
221
+ allowedFolders: [testDir]
222
+ });
223
+
224
+ // Try path traversal attack
225
+ const traversalPath = join(testDir, '..', '..', 'etc', 'passwd');
226
+
227
+ await expect(
228
+ restrictedAgent.toolImplementations.readImage.execute({
229
+ path: traversalPath
230
+ })
231
+ ).rejects.toThrow();
232
+ });
233
+
234
+ test('should prevent path traversal in extension extraction', async () => {
235
+ // This tests that basename is used to extract extension safely
236
+ const restrictedAgent = new ProbeAgent({
237
+ debug: false,
238
+ path: testDir,
239
+ allowedFolders: [testDir]
240
+ });
241
+
242
+ // Path designed to look like valid extension but contains traversal
243
+ const maliciousPath = 'malicious.png/../../../etc/passwd';
244
+
245
+ await expect(
246
+ restrictedAgent.toolImplementations.readImage.execute({
247
+ path: maliciousPath
248
+ })
249
+ ).rejects.toThrow();
250
+ });
251
+
252
+ test('should handle normalized path prefix attacks', async () => {
253
+ // Test that /allowed/path doesn't match /allowed/pathsuffix
254
+ const restrictedAgent = new ProbeAgent({
255
+ debug: false,
256
+ path: testDir,
257
+ allowedFolders: [testDir]
258
+ });
259
+
260
+ // Create a sibling directory name that starts with testDir name
261
+ const siblingPath = testDir + '-sibling/image.png';
262
+
263
+ await expect(
264
+ restrictedAgent.toolImplementations.readImage.execute({
265
+ path: siblingPath
266
+ })
267
+ ).rejects.toThrow();
268
+ });
269
+
270
+ test('should reject invalid extensions even without apiType set', async () => {
271
+ // Test that extension validation happens regardless of apiType
272
+ const agentWithoutApiType = new ProbeAgent({
273
+ debug: false,
274
+ path: testDir
275
+ });
276
+ // Ensure apiType is not set
277
+ agentWithoutApiType.apiType = null;
278
+
279
+ // Try to load a file with invalid extension
280
+ await expect(
281
+ agentWithoutApiType.toolImplementations.readImage.execute({
282
+ path: join(testDir, 'malicious.exe')
283
+ })
284
+ ).rejects.toThrow(/Invalid or unsupported image extension/);
285
+ });
286
+
287
+ test('should reject path traversal disguised as valid extension', async () => {
288
+ const restrictedAgent = new ProbeAgent({
289
+ debug: false,
290
+ path: testDir,
291
+ allowedFolders: [testDir]
292
+ });
293
+
294
+ // Path that looks like it has a valid extension but is actually traversal
295
+ // basename('malicious.png/../../../etc/passwd') = 'passwd'
296
+ // extension of 'passwd' = 'passwd' (not in allowed list)
297
+ await expect(
298
+ restrictedAgent.toolImplementations.readImage.execute({
299
+ path: 'malicious.png/../../../etc/passwd'
300
+ })
301
+ ).rejects.toThrow(/Invalid or unsupported image extension/);
302
+ });
303
+ });
304
+
305
+ describe('Provider-specific format restrictions (GitHub issue #305)', () => {
306
+ test('should reject SVG files when using Google provider', async () => {
307
+ // Create an agent with Google provider
308
+ // Note: We need to manually set apiType since mocks prevent normal initialization
309
+ const googleAgent = new ProbeAgent({
310
+ debug: false,
311
+ path: testDir
312
+ });
313
+ googleAgent.apiType = 'google'; // Simulate Google provider
314
+
315
+ // Create a simple SVG file
316
+ const svgContent = '<svg xmlns="http://www.w3.org/2000/svg"><rect width="1" height="1"/></svg>';
317
+ const svgPath = join(testDir, 'test.svg');
318
+ writeFileSync(svgPath, svgContent);
319
+
320
+ // Attempting to read SVG should throw error
321
+ await expect(
322
+ googleAgent.toolImplementations.readImage.execute({
323
+ path: svgPath
324
+ })
325
+ ).rejects.toThrow(/not supported by the current AI provider/);
326
+ });
327
+
328
+ test('should allow SVG files when using Anthropic provider', async () => {
329
+ // Create an agent with Anthropic provider
330
+ // Note: We need to manually set apiType since mocks prevent normal initialization
331
+ const anthropicAgent = new ProbeAgent({
332
+ debug: false,
333
+ path: testDir
334
+ });
335
+ anthropicAgent.apiType = 'anthropic'; // Simulate Anthropic provider
336
+
337
+ // Create a simple SVG file
338
+ const svgContent = '<svg xmlns="http://www.w3.org/2000/svg"><rect width="1" height="1"/></svg>';
339
+ const svgPath = join(testDir, 'test-anthropic.svg');
340
+ writeFileSync(svgPath, svgContent);
341
+
342
+ // Attempting to read SVG should succeed
343
+ const result = await anthropicAgent.toolImplementations.readImage.execute({
344
+ path: svgPath
345
+ });
346
+
347
+ expect(result).toContain('Image loaded successfully');
348
+ });
349
+
350
+ test('loadImageIfValid should load SVG (provider filtering handled by readImage tool)', async () => {
351
+ // Note: loadImageIfValid is a low-level method that only checks general format support.
352
+ // Provider-specific filtering (e.g., SVG not supported by Google Gemini) is handled
353
+ // by the readImage tool which provides explicit error messages.
354
+ const agent = new ProbeAgent({
355
+ debug: false,
356
+ path: testDir
357
+ });
358
+
359
+ const svgContent = '<svg xmlns="http://www.w3.org/2000/svg"><rect width="1" height="1"/></svg>';
360
+ const svgPath = join(testDir, 'test-load.svg');
361
+ writeFileSync(svgPath, svgContent);
362
+
363
+ // loadImageIfValid should succeed - it doesn't do provider-specific filtering
364
+ const result = await agent.loadImageIfValid(svgPath);
365
+ expect(result).toBe(true);
366
+ });
367
+ });
368
+
369
+ describe('Integration with message flow', () => {
370
+ test('loaded images should be available in getCurrentImages', async () => {
371
+ agent.clearLoadedImages();
372
+
373
+ await agent.toolImplementations.readImage.execute({
374
+ path: testImagePath
375
+ });
376
+
377
+ const images = agent.getCurrentImages();
378
+ expect(images.length).toBe(1);
379
+ expect(images[0]).toMatch(/^data:image\/png;base64,/);
380
+ });
381
+
382
+ test('should work alongside processImageReferences method (for explicit image processing)', async () => {
383
+ // Note: Automatic image processing after tool results was removed in GitHub issue #305
384
+ // The processImageReferences method still exists for explicit use when needed
385
+
386
+ // Clear any existing images
387
+ agent.clearLoadedImages();
388
+
389
+ // Manually call processImageReferences (this is no longer called automatically)
390
+ const toolResultWithImage = `Found the file at ${testImagePath}`;
391
+ await agent.processImageReferences(toolResultWithImage);
392
+
393
+ const imagesFromProcessing = agent.getCurrentImages().length;
394
+
395
+ // Now explicitly read another image using readImage tool
396
+ const anotherImage = join(testDir, 'another.png');
397
+ const simplePng = Buffer.from([
398
+ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
399
+ 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
400
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
401
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4,
402
+ 0x89, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x44, 0x41,
403
+ 0x54, 0x78, 0x9C, 0x62, 0x00, 0x02, 0x00, 0x00,
404
+ 0x05, 0x00, 0x01, 0x0D, 0x0A, 0x2D, 0xB4, 0x00,
405
+ 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
406
+ 0x42, 0x60, 0x82
407
+ ]);
408
+ writeFileSync(anotherImage, simplePng);
409
+
410
+ await agent.toolImplementations.readImage.execute({
411
+ path: anotherImage
412
+ });
413
+
414
+ const totalImages = agent.getCurrentImages().length;
415
+ expect(totalImages).toBeGreaterThan(imagesFromProcessing);
416
+ });
417
+ });
418
+ });