@crownpeak/dqm-react-component-dev-mcp 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -0
- package/data/.env.example +22 -0
- package/data/.gitattributes +47 -0
- package/data/.glfrc.json +7 -0
- package/data/.husky/pre-commit +5 -0
- package/data/.nvmrc +1 -0
- package/data/CHANGELOG.md +75 -0
- package/data/CODE_OF_CONDUCT.md +129 -0
- package/data/CONTRIBUTING.md +203 -0
- package/data/DOCS-STRUCTURE.md +307 -0
- package/data/I18N.md +292 -0
- package/data/LICENSE +22 -0
- package/data/README.md +315 -0
- package/data/SECURITY.md +125 -0
- package/data/WIKI-DEPLOYMENT.md +348 -0
- package/data/docs/AI-FEATURES.md +610 -0
- package/data/docs/API-REFERENCE.md +1022 -0
- package/data/docs/AUTHENTICATION.md +301 -0
- package/data/docs/BACKEND-API.md +468 -0
- package/data/docs/DEVELOPMENT.md +375 -0
- package/data/docs/EXAMPLES.md +622 -0
- package/data/docs/MCP-SERVER.md +307 -0
- package/data/docs/MIGRATION-GUIDE.md +367 -0
- package/data/docs/NPM-PUBLISH.md +193 -0
- package/data/docs/QUICKSTART.md +206 -0
- package/data/docs/REDIS-SETUP.md +162 -0
- package/data/docs/SERVER.md +228 -0
- package/data/docs/TROUBLESHOOTING.md +657 -0
- package/data/docs/WIDGET-GUIDE.md +638 -0
- package/data/docs/WIKI-HOME.md +58 -0
- package/data/docs/WIKI-SIDEBAR.md +39 -0
- package/data/package.json +171 -0
- package/data/playwright.config.ts +64 -0
- package/data/probe/.cargo/config.toml +10 -0
- package/data/probe/.claude/commands/performance-review.md +15 -0
- package/data/probe/.clinerules +288 -0
- package/data/probe/.dockerignore +57 -0
- package/data/probe/.githooks/post-commit +11 -0
- package/data/probe/.githooks/pre-commit +99 -0
- package/data/probe/.githooks/pre-commit-vow +9 -0
- package/data/probe/.prompts/engineer.md +41 -0
- package/data/probe/.roomodes +28 -0
- package/data/probe/.windsurfrules +0 -0
- package/data/probe/BASH_TOOL_SUMMARY.md +148 -0
- package/data/probe/BENCHMARKING.md +256 -0
- package/data/probe/CLAUDE.md +226 -0
- package/data/probe/CODE_OF_CONDUCT.md +128 -0
- package/data/probe/CONTRIBUTING.md +193 -0
- package/data/probe/Cargo.toml +120 -0
- package/data/probe/Cross.toml +10 -0
- package/data/probe/DOCKER-README.md +224 -0
- package/data/probe/Dockerfile +32 -0
- package/data/probe/ENHANCED_DEBUG_TELEMETRY.md +188 -0
- package/data/probe/LICENSE +201 -0
- package/data/probe/Makefile +210 -0
- package/data/probe/README.md +824 -0
- package/data/probe/SECURITY.md +67 -0
- package/data/probe/WINDOWS-GUIDE.md +294 -0
- package/data/probe/benches/parsing_benchmarks.rs +370 -0
- package/data/probe/benches/search_benchmarks.rs +599 -0
- package/data/probe/benches/simd_benchmarks.rs +372 -0
- package/data/probe/benches/timing_benchmarks.rs +287 -0
- package/data/probe/build-windows.bat +229 -0
- package/data/probe/codex-config/config.toml +6 -0
- package/data/probe/docs/PERFORMANCE_OPTIMIZATION.md +161 -0
- package/data/probe/examples/cache_demo.rs +46 -0
- package/data/probe/examples/chat/.dockerignore +37 -0
- package/data/probe/examples/chat/ChatSessionManager.js +295 -0
- package/data/probe/examples/chat/Dockerfile +98 -0
- package/data/probe/examples/chat/LICENSE +201 -0
- package/data/probe/examples/chat/LOCAL_IMAGE_SUPPORT.md +195 -0
- package/data/probe/examples/chat/MCP_INTEGRATION.md +400 -0
- package/data/probe/examples/chat/README.md +338 -0
- package/data/probe/examples/chat/TRACING.md +226 -0
- package/data/probe/examples/chat/appTracer.js +968 -0
- package/data/probe/examples/chat/auth.js +76 -0
- package/data/probe/examples/chat/bin/probe-chat.js +13 -0
- package/data/probe/examples/chat/build.js +104 -0
- package/data/probe/examples/chat/cancelRequest.js +84 -0
- package/data/probe/examples/chat/demo-agentic-image-flow.js +88 -0
- package/data/probe/examples/chat/demo-local-images.js +128 -0
- package/data/probe/examples/chat/fileSpanExporter.js +181 -0
- package/data/probe/examples/chat/implement/README.md +228 -0
- package/data/probe/examples/chat/implement/backends/AiderBackend.js +750 -0
- package/data/probe/examples/chat/implement/backends/BaseBackend.js +276 -0
- package/data/probe/examples/chat/implement/backends/ClaudeCodeBackend.js +767 -0
- package/data/probe/examples/chat/implement/backends/MockBackend.js +237 -0
- package/data/probe/examples/chat/implement/backends/registry.js +85 -0
- package/data/probe/examples/chat/implement/core/BackendManager.js +567 -0
- package/data/probe/examples/chat/implement/core/ImplementTool.js +354 -0
- package/data/probe/examples/chat/implement/core/config.js +428 -0
- package/data/probe/examples/chat/implement/core/timeouts.js +58 -0
- package/data/probe/examples/chat/implement/core/utils.js +496 -0
- package/data/probe/examples/chat/implement/types/BackendTypes.js +126 -0
- package/data/probe/examples/chat/index.js +669 -0
- package/data/probe/examples/chat/mcpServer.js +341 -0
- package/data/probe/examples/chat/npm/LICENSE +15 -0
- package/data/probe/examples/chat/npm/README.md +168 -0
- package/data/probe/examples/chat/npm/bin/probe-chat.js +156 -0
- package/data/probe/examples/chat/npm/index.js +259 -0
- package/data/probe/examples/chat/npm/package.json +54 -0
- package/data/probe/examples/chat/package.json +102 -0
- package/data/probe/examples/chat/probeChat.js +456 -0
- package/data/probe/examples/chat/probeTool.js +491 -0
- package/data/probe/examples/chat/storage/JsonChatStorage.js +476 -0
- package/data/probe/examples/chat/telemetry.js +281 -0
- package/data/probe/examples/chat/test/integration/chatFlows.test.js +320 -0
- package/data/probe/examples/chat/test/integration/toolCalling.test.js +471 -0
- package/data/probe/examples/chat/test/mocks/mockLLMProvider.js +269 -0
- package/data/probe/examples/chat/test/test-backends.js +90 -0
- package/data/probe/examples/chat/test/testUtils.js +530 -0
- package/data/probe/examples/chat/test/unit/backendTimeout.test.js +161 -0
- package/data/probe/examples/chat/test/unit/packageFiles.test.js +120 -0
- package/data/probe/examples/chat/test/verify-tests.js +118 -0
- package/data/probe/examples/chat/test-agentic-image-loading.js +294 -0
- package/data/probe/examples/chat/test-ai-sdk-telemetry.js +204 -0
- package/data/probe/examples/chat/test-chat-tracing.js +38 -0
- package/data/probe/examples/chat/test-direct-function.js +49 -0
- package/data/probe/examples/chat/test-file-size-validation.js +103 -0
- package/data/probe/examples/chat/test-full-mcp-integration.js +258 -0
- package/data/probe/examples/chat/test-github-context.txt +12 -0
- package/data/probe/examples/chat/test-hierarchy.js +203 -0
- package/data/probe/examples/chat/test-image-spans.js +37 -0
- package/data/probe/examples/chat/test-local-image-reading.js +176 -0
- package/data/probe/examples/chat/test-mcp-integration.js +136 -0
- package/data/probe/examples/chat/test-mcp-probe-server.js +161 -0
- package/data/probe/examples/chat/test-mcp-with-ai.js +279 -0
- package/data/probe/examples/chat/test-multiple-allowed-dirs.js +111 -0
- package/data/probe/examples/chat/test-probe-mcp-server.js +110 -0
- package/data/probe/examples/chat/test-security-validation.js +145 -0
- package/data/probe/examples/chat/test-simple-tracing.js +32 -0
- package/data/probe/examples/chat/test-trace-verification.js +235 -0
- package/data/probe/examples/chat/test-tracing.js +114 -0
- package/data/probe/examples/chat/tokenCounter.js +419 -0
- package/data/probe/examples/chat/tokenUsageDisplay.js +134 -0
- package/data/probe/examples/chat/webServer.js +1103 -0
- package/data/probe/examples/reranker/Cargo.toml +33 -0
- package/data/probe/examples/reranker/DEBUG_OUTPUT_ANALYSIS.md +71 -0
- package/data/probe/examples/reranker/MODELS.md +66 -0
- package/data/probe/examples/reranker/MODEL_COMPARISON.md +60 -0
- package/data/probe/examples/reranker/MULTI_MODEL_ANALYSIS.md +176 -0
- package/data/probe/examples/reranker/PERFORMANCE_SUMMARY.md +156 -0
- package/data/probe/examples/reranker/README.md +347 -0
- package/data/probe/examples/reranker/RUST_BERT_COMPARISON.md +82 -0
- package/data/probe/examples/reranker/TOKENIZATION_GUIDE.md +120 -0
- package/data/probe/examples/reranker/check_rust_tokenizer.py +108 -0
- package/data/probe/examples/reranker/convert_to_torchscript.py +109 -0
- package/data/probe/examples/reranker/debug_scoring.py +189 -0
- package/data/probe/examples/reranker/debug_tokenization.py +154 -0
- package/data/probe/examples/reranker/download_models.sh +73 -0
- package/data/probe/examples/reranker/requirements.txt +13 -0
- package/data/probe/examples/reranker/run_comprehensive_benchmark.sh +83 -0
- package/data/probe/examples/reranker/rust_bert_test/Cargo.toml +12 -0
- package/data/probe/examples/reranker/rust_bert_test/README.md +54 -0
- package/data/probe/examples/reranker/simple_test.py +50 -0
- package/data/probe/examples/reranker/test_all_models.sh +63 -0
- package/data/probe/examples/reranker/test_bert_results.sh +44 -0
- package/data/probe/examples/reranker/test_cross_encoder.py +334 -0
- package/data/probe/examples/reranker/test_cross_encoder.sh +80 -0
- package/data/probe/examples/reranker/test_exact_comparison.py +151 -0
- package/data/probe/examples/reranker/test_parallel_performance.sh +56 -0
- package/data/probe/examples/reranker/test_scores.py +132 -0
- package/data/probe/install.ps1 +508 -0
- package/data/probe/install.sh +460 -0
- package/data/probe/npm/CLONE_METHOD_EXAMPLES.md +596 -0
- package/data/probe/npm/CONTEXT_COMPACTION.md +303 -0
- package/data/probe/npm/DELEGATE_TOOL_README.md +166 -0
- package/data/probe/npm/MAID_INTEGRATION.md +313 -0
- package/data/probe/npm/MCP_INTEGRATION_SUMMARY.md +241 -0
- package/data/probe/npm/README.md +824 -0
- package/data/probe/npm/bin/.gitignore +7 -0
- package/data/probe/npm/bin/.gitkeep +0 -0
- package/data/probe/npm/bin/README.md +12 -0
- package/data/probe/npm/bin/probe +167 -0
- package/data/probe/npm/docs/CLAUDE_CODE_INTEGRATION.md +414 -0
- package/data/probe/npm/docs/CODEX_INTEGRATION.md +502 -0
- package/data/probe/npm/docs/EDIT_CREATE_TOOLS.md +233 -0
- package/data/probe/npm/docs/RETRY_AND_FALLBACK.md +674 -0
- package/data/probe/npm/example-usage.js +335 -0
- package/data/probe/npm/examples/multi-engine-demo.js +117 -0
- package/data/probe/npm/examples/probe-agent-cli.js +113 -0
- package/data/probe/npm/examples/test-agent-edit.js +114 -0
- package/data/probe/npm/examples/test-edit-create.js +120 -0
- package/data/probe/npm/examples/test-edit-direct.js +114 -0
- package/data/probe/npm/index.d.ts +744 -0
- package/data/probe/npm/jest.config.js +52 -0
- package/data/probe/npm/package.json +117 -0
- package/data/probe/npm/scripts/build-agent.cjs +75 -0
- package/data/probe/npm/scripts/build-cjs.js +124 -0
- package/data/probe/npm/scripts/build-mcp.cjs +36 -0
- package/data/probe/npm/scripts/postinstall.js +216 -0
- package/data/probe/npm/test-codex-e2e.js +78 -0
- package/data/probe/npm/test-download-lock.js +109 -0
- package/data/probe/npm/test-grep-security.js +94 -0
- package/data/probe/npm/test-grep-simplified.js +63 -0
- package/data/probe/npm/test-grep.js +51 -0
- package/data/probe/npm/tests/README.md +96 -0
- package/data/probe/npm/tests/agent-compact-history.test.js +174 -0
- package/data/probe/npm/tests/allow-tests-default.test.js +151 -0
- package/data/probe/npm/tests/contextCompactor.test.js +498 -0
- package/data/probe/npm/tests/delegate-config.test.js +353 -0
- package/data/probe/npm/tests/delegate-integration.test.js +348 -0
- package/data/probe/npm/tests/extractor-integration.test.js +162 -0
- package/data/probe/npm/tests/extractor.test.js +317 -0
- package/data/probe/npm/tests/fixtures/sampleDiagrams.js +267 -0
- package/data/probe/npm/tests/integration/claude-code-auto-fallback.spec.js +148 -0
- package/data/probe/npm/tests/integration/claude-code-multi-step.spec.js +127 -0
- package/data/probe/npm/tests/integration/claude-code-tool-events.spec.js +163 -0
- package/data/probe/npm/tests/integration/codex-auto-fallback.spec.js +191 -0
- package/data/probe/npm/tests/integration/codex-tool-events.spec.js +147 -0
- package/data/probe/npm/tests/integration/examplesChatMcp.test.js +402 -0
- package/data/probe/npm/tests/integration/mcpDotenvSupport.test.js +174 -0
- package/data/probe/npm/tests/integration/mcpErrorHandling.test.js +566 -0
- package/data/probe/npm/tests/integration/mcpRobustness.test.js +564 -0
- package/data/probe/npm/tests/integration/mcpStdoutPurity.test.js +355 -0
- package/data/probe/npm/tests/integration/probeAgentMcp.test.js +398 -0
- package/data/probe/npm/tests/integration/retryFallback.test.js +368 -0
- package/data/probe/npm/tests/integration/schema-in-initial-message.test.js +318 -0
- package/data/probe/npm/tests/integration/schema-validation-loop-prevention.test.js +244 -0
- package/data/probe/npm/tests/integration/schemaRetryLogic.test.js +94 -0
- package/data/probe/npm/tests/integration/validationFlow.test.js +329 -0
- package/data/probe/npm/tests/manual/test-codex-basic.js +110 -0
- package/data/probe/npm/tests/mcp/mcpClientManager.test.js +614 -0
- package/data/probe/npm/tests/mcp/mcpConfig.test.js +359 -0
- package/data/probe/npm/tests/mcp/mcpXmlBridge.test.js +436 -0
- package/data/probe/npm/tests/mcp/mockMcpServer.js +510 -0
- package/data/probe/npm/tests/mcp-strict-syntax.test.js +319 -0
- package/data/probe/npm/tests/mermaidQuoteEscaping.test.js +214 -0
- package/data/probe/npm/tests/nestedQuoteFix.test.js +40 -0
- package/data/probe/npm/tests/setup.js +46 -0
- package/data/probe/npm/tests/unit/allowed-tools.test.js +513 -0
- package/data/probe/npm/tests/unit/attempt-completion-closing-tag-in-content.test.js +188 -0
- package/data/probe/npm/tests/unit/attemptCompletionJsonFix.test.js +238 -0
- package/data/probe/npm/tests/unit/attemptCompletionJsonIssue.test.js +128 -0
- package/data/probe/npm/tests/unit/backtickAutoFix.test.js +35 -0
- package/data/probe/npm/tests/unit/bash-probe-agent-integration.test.js +389 -0
- package/data/probe/npm/tests/unit/bash-simple-commands.test.js +324 -0
- package/data/probe/npm/tests/unit/bash-tool-comprehensive.test.js +371 -0
- package/data/probe/npm/tests/unit/bash-tool-integration.test.js +310 -0
- package/data/probe/npm/tests/unit/bash-tool.test.js +341 -0
- package/data/probe/npm/tests/unit/completion-prompt.test.js +379 -0
- package/data/probe/npm/tests/unit/cwd-path-options.test.js +287 -0
- package/data/probe/npm/tests/unit/delegate-limits.test.js +422 -0
- package/data/probe/npm/tests/unit/direct-content-attempt-completion.test.js +235 -0
- package/data/probe/npm/tests/unit/edit-create-tools.test.js +609 -0
- package/data/probe/npm/tests/unit/enhancedMermaidValidation.test.js +577 -0
- package/data/probe/npm/tests/unit/extract-content.test.js +83 -0
- package/data/probe/npm/tests/unit/extract-multiple-targets.test.js +89 -0
- package/data/probe/npm/tests/unit/fallbackManager.test.js +442 -0
- package/data/probe/npm/tests/unit/githubCompatibilityValidation.test.js +258 -0
- package/data/probe/npm/tests/unit/imageConfig.test.js +149 -0
- package/data/probe/npm/tests/unit/imagePathResolution.test.js +345 -0
- package/data/probe/npm/tests/unit/json-fixing-agent.test.js +238 -0
- package/data/probe/npm/tests/unit/json-validation-enhanced-errors.test.js +199 -0
- package/data/probe/npm/tests/unit/jsonValidationInfiniteLoopFix.test.js +228 -0
- package/data/probe/npm/tests/unit/maidIntegration.test.js +139 -0
- package/data/probe/npm/tests/unit/maxIterationsWarning.test.js +195 -0
- package/data/probe/npm/tests/unit/mermaidEdgeLabelFix.test.js +161 -0
- package/data/probe/npm/tests/unit/mermaidHtmlEntities.test.js +76 -0
- package/data/probe/npm/tests/unit/mermaidInfiniteLoopFix.test.js +64 -0
- package/data/probe/npm/tests/unit/mermaidValidation.test.js +723 -0
- package/data/probe/npm/tests/unit/mermaidValidationVisorExample.test.js +309 -0
- package/data/probe/npm/tests/unit/probe-agent-clone-realistic.test.js +643 -0
- package/data/probe/npm/tests/unit/probe-agent-clone.test.js +476 -0
- package/data/probe/npm/tests/unit/probe-agent-delegate.test.js +400 -0
- package/data/probe/npm/tests/unit/probe-agent-model-option.test.js +118 -0
- package/data/probe/npm/tests/unit/probeTool-security.test.js +283 -0
- package/data/probe/npm/tests/unit/readImageTool.test.js +418 -0
- package/data/probe/npm/tests/unit/retryManager.test.js +317 -0
- package/data/probe/npm/tests/unit/schema-aware-reminders.test.js +288 -0
- package/data/probe/npm/tests/unit/schemaDefinitionDetection.test.js +115 -0
- package/data/probe/npm/tests/unit/schemaUtils.test.js +1268 -0
- package/data/probe/npm/tests/unit/simpleTelemetry.test.js +282 -0
- package/data/probe/npm/tests/unit/simplified-attempt-completion.test.js +274 -0
- package/data/probe/npm/tests/unit/single-quote-json-bug.test.js +231 -0
- package/data/probe/npm/tests/unit/subgraphAutoFix.test.js +110 -0
- package/data/probe/npm/tests/unit/system-prompt.test.js +32 -0
- package/data/probe/npm/tests/unit/types-probe-agent-options.test.js +42 -0
- package/data/probe/npm/tests/unit/xmlParsing.test.js +720 -0
- package/data/probe/npm/tsconfig.json +21 -0
- package/data/probe/result1.txt +19 -0
- package/data/probe/result2.txt +26 -0
- package/data/probe/scripts/benchmark.sh +270 -0
- package/data/probe/scripts/cache_memory_analysis.rs +844 -0
- package/data/probe/scripts/claude-hook-wrapper.sh +56 -0
- package/data/probe/site/.env.example +10 -0
- package/data/probe/site/DEPLOYMENT.md +86 -0
- package/data/probe/site/README.md +183 -0
- package/data/probe/site/adding-languages.md +135 -0
- package/data/probe/site/ai-chat.md +427 -0
- package/data/probe/site/ai-integration.md +1488 -0
- package/data/probe/site/blog/agentic-flow-custom-xml-protocol.md +407 -0
- package/data/probe/site/blog/index.md +118 -0
- package/data/probe/site/blog/v0.6.0-release.md +426 -0
- package/data/probe/site/blog.md +8 -0
- package/data/probe/site/changelog.md +200 -0
- package/data/probe/site/cli-mode.md +437 -0
- package/data/probe/site/code-extraction.md +436 -0
- package/data/probe/site/contributing/README.md +9 -0
- package/data/probe/site/contributing/documentation-cross-references.md +215 -0
- package/data/probe/site/contributing/documentation-maintenance.md +275 -0
- package/data/probe/site/contributing/documentation-structure.md +75 -0
- package/data/probe/site/documentation-cross-references.md +215 -0
- package/data/probe/site/documentation-guide.md +132 -0
- package/data/probe/site/documentation-maintenance.md +275 -0
- package/data/probe/site/features.md +147 -0
- package/data/probe/site/how-it-works.md +118 -0
- package/data/probe/site/index.md +175 -0
- package/data/probe/site/index.md.bak +133 -0
- package/data/probe/site/installation.md +235 -0
- package/data/probe/site/integrations/docker.md +248 -0
- package/data/probe/site/integrations/github-actions.md +413 -0
- package/data/probe/site/language-support-overview.md +168 -0
- package/data/probe/site/mcp-integration.md +587 -0
- package/data/probe/site/mcp-server.md +304 -0
- package/data/probe/site/navigation-structure.md +76 -0
- package/data/probe/site/nodejs-sdk.md +798 -0
- package/data/probe/site/output-formats.md +625 -0
- package/data/probe/site/package.json +21 -0
- package/data/probe/site/public/_headers +28 -0
- package/data/probe/site/public/_redirects +11 -0
- package/data/probe/site/quick-start.md +289 -0
- package/data/probe/site/search-functionality.md +291 -0
- package/data/probe/site/search-reference.md +291 -0
- package/data/probe/site/supported-languages.md +215 -0
- package/data/probe/site/use-cases/README.md +8 -0
- package/data/probe/site/use-cases/advanced-cli.md +253 -0
- package/data/probe/site/use-cases/ai-code-editors.md +239 -0
- package/data/probe/site/use-cases/building-ai-tools.md +529 -0
- package/data/probe/site/use-cases/cli-ai-workflows.md +285 -0
- package/data/probe/site/use-cases/deploying-probe-web-interface.md +255 -0
- package/data/probe/site/use-cases/integrating-probe-into-ai-code-editors.md +161 -0
- package/data/probe/site/use-cases/nodejs-sdk.md +596 -0
- package/data/probe/site/use-cases/team-chat.md +350 -0
- package/data/probe/site/web-interface.md +434 -0
- package/data/probe/site/wrangler.toml +9 -0
- package/data/probe/test-api-key.sh +1 -0
- package/data/probe/test-probe-implementation/hello.js +7 -0
- package/data/probe/test_cases/demonstrate_early_termination_issues.sh +176 -0
- package/data/probe/test_cases/early_termination_issues.rs +533 -0
- package/data/probe/test_data/test_nested_struct.go +26 -0
- package/data/probe/tests/README.md +286 -0
- package/data/probe/tests/README_search_determinism_tests.md +116 -0
- package/data/probe/tests/adjacent_comment_test.rs +152 -0
- package/data/probe/tests/apostrophe_handling_tests.rs +132 -0
- package/data/probe/tests/block_filtering_with_ast_tests.rs +669 -0
- package/data/probe/tests/block_merging_tests.rs +396 -0
- package/data/probe/tests/c_outline_format_tests.rs +2179 -0
- package/data/probe/tests/cache_invalidation_issues.rs.disabled +682 -0
- package/data/probe/tests/cache_order_tests.rs +147 -0
- package/data/probe/tests/cache_query_scoping_tests.rs +221 -0
- package/data/probe/tests/cli_tests.rs +680 -0
- package/data/probe/tests/comment_context_integration_test.rs +240 -0
- package/data/probe/tests/common.rs +33 -0
- package/data/probe/tests/complex_block_merging_tests.rs +599 -0
- package/data/probe/tests/complex_query_block_filtering_tests.rs +422 -0
- package/data/probe/tests/control_flow_closing_braces_test.rs +91 -0
- package/data/probe/tests/cpp_outline_format_tests.rs +1507 -0
- package/data/probe/tests/csharp_outline_format_tests.rs +941 -0
- package/data/probe/tests/elastic_query_integration_tests.rs +922 -0
- package/data/probe/tests/extract_command_tests.rs +1848 -0
- package/data/probe/tests/extract_deduplication_tests.rs +146 -0
- package/data/probe/tests/extract_input_file_tests.rs +84 -0
- package/data/probe/tests/extract_prompt_tests.rs +102 -0
- package/data/probe/tests/filename_search_tests.rs +96 -0
- package/data/probe/tests/fixtures/user/AssemblyInfo.cs +3 -0
- package/data/probe/tests/github_extract_tests.rs +234 -0
- package/data/probe/tests/go_comment_test.rs +253 -0
- package/data/probe/tests/go_outline_format_tests.rs +2587 -0
- package/data/probe/tests/go_path_resolver_tests.rs +96 -0
- package/data/probe/tests/html_outline_format_tests.rs +637 -0
- package/data/probe/tests/integration_tests.rs +837 -0
- package/data/probe/tests/ip_whitelist_test.rs +148 -0
- package/data/probe/tests/java_outline_format_tests.rs +1611 -0
- package/data/probe/tests/javascript_extract_tests.rs +315 -0
- package/data/probe/tests/javascript_outline_format_tests.rs +1464 -0
- package/data/probe/tests/json_format_tests.rs +436 -0
- package/data/probe/tests/json_schema_validation_tests.rs +450 -0
- package/data/probe/tests/lib_usage.rs +60 -0
- package/data/probe/tests/line_comment_context_extension_test.rs +459 -0
- package/data/probe/tests/line_map_cache_tests.rs +114 -0
- package/data/probe/tests/markdown_integration_tests.rs +190 -0
- package/data/probe/tests/mocks/test_ip_whitelist.go +11 -0
- package/data/probe/tests/mocks/test_object.js +27 -0
- package/data/probe/tests/mocks/test_struct.go +50 -0
- package/data/probe/tests/multi_keyword_pattern_tests.rs +464 -0
- package/data/probe/tests/multi_language_syntax_integration_tests.rs +218 -0
- package/data/probe/tests/multiple_capture_groups_tests.rs +169 -0
- package/data/probe/tests/negative_compound_word_tests.rs +246 -0
- package/data/probe/tests/nested_symbol_extraction_tests.rs +99 -0
- package/data/probe/tests/outline_cross_file_interference_test.rs +335 -0
- package/data/probe/tests/outline_keyword_preservation_test.rs +67 -0
- package/data/probe/tests/output_format_edge_cases_tests.rs +693 -0
- package/data/probe/tests/parallel_extraction_tests.rs +178 -0
- package/data/probe/tests/parallel_search_tests.rs +355 -0
- package/data/probe/tests/path_resolver_tests.rs +698 -0
- package/data/probe/tests/php_outline_format_extended_tests.rs +928 -0
- package/data/probe/tests/php_outline_format_tests.rs +768 -0
- package/data/probe/tests/property_tests.proptest-regressions +9 -0
- package/data/probe/tests/property_tests.rs +118 -0
- package/data/probe/tests/python_outline_format_tests.rs +1538 -0
- package/data/probe/tests/query_command_json_tests.rs +438 -0
- package/data/probe/tests/query_command_tests.rs +232 -0
- package/data/probe/tests/query_command_xml_tests.rs +569 -0
- package/data/probe/tests/quoted_term_with_negative_keyword_tests.rs +216 -0
- package/data/probe/tests/required_terms_filename_tests.rs +116 -0
- package/data/probe/tests/ruby_outline_format_tests.rs +1011 -0
- package/data/probe/tests/rust_line_comment_context_test.rs +151 -0
- package/data/probe/tests/rust_outline_format_enhanced_tests.rs +725 -0
- package/data/probe/tests/rust_outline_format_tests.rs +843 -0
- package/data/probe/tests/schemas/xml_output_schema.xsd +38 -0
- package/data/probe/tests/search_determinism_tests.rs +451 -0
- package/data/probe/tests/search_hints_tests.rs +253 -0
- package/data/probe/tests/special_character_escaping_tests.rs +417 -0
- package/data/probe/tests/stemming_compound_word_filtering_tests.rs +535 -0
- package/data/probe/tests/strict_elastic_syntax_tests.rs +404 -0
- package/data/probe/tests/swift_outline_format_tests.rs +3319 -0
- package/data/probe/tests/symbols_tests.rs +166 -0
- package/data/probe/tests/test_file.rs +45 -0
- package/data/probe/tests/test_tokenize.rs +28 -0
- package/data/probe/tests/timeout_tests.rs +82 -0
- package/data/probe/tests/tokenization_tests.rs +195 -0
- package/data/probe/tests/tokenized_block_filtering_tests.rs +174 -0
- package/data/probe/tests/typescript_extract_tests.rs +214 -0
- package/data/probe/tests/typescript_outline_format_tests.rs +2188 -0
- package/data/probe/tests/xml_format_tests.rs +568 -0
- package/data/probe/tests/xml_schema_validation_tests.rs +497 -0
- package/data/scripts/postinstall.mjs +9 -0
- package/data/scripts/set-version.js +0 -0
- package/data/scripts/wiki-build.sh +111 -0
- package/data/scripts/wiki-deploy.sh +73 -0
- package/data/serve.json +12 -0
- package/data/test/demo-dynamic.html +134 -0
- package/data/test/demo-esm.html +105 -0
- package/data/test/demo-iife.html +78 -0
- package/data/tsconfig.json +7 -0
- package/data/vite.server.ts +483 -0
- package/data/vitest.config.ts +40 -0
- package/data/wiki/Home.md +58 -0
- package/data/wiki/_Sidebar.md +39 -0
- package/docs-mcp.config.json +20 -0
- package/package.json +56 -0
- package/src/config.js +111 -0
- package/src/index.js +395 -0
|
@@ -0,0 +1,844 @@
|
|
|
1
|
+
#!/usr/bin/env cargo script
|
|
2
|
+
//! Cache Memory Growth Analysis Script
|
|
3
|
+
//!
|
|
4
|
+
//! This script demonstrates the memory growth issues in Probe's caching system
|
|
5
|
+
//! by simulating real-world usage patterns and measuring memory consumption.
|
|
6
|
+
//!
|
|
7
|
+
//! Usage: cargo script cache_memory_analysis.rs
|
|
8
|
+
//!
|
|
9
|
+
//! Demonstrates:
|
|
10
|
+
//! 1. Unbounded cache growth in tree cache
|
|
11
|
+
//! 2. Memory consumption patterns across different cache types
|
|
12
|
+
//! 3. Performance vs memory trade-offs
|
|
13
|
+
//! 4. Cache invalidation failure impacts
|
|
14
|
+
|
|
15
|
+
use std::collections::HashMap;
|
|
16
|
+
use std::fs::{self, File};
|
|
17
|
+
use std::io::Write;
|
|
18
|
+
use std::path::{Path, PathBuf};
|
|
19
|
+
use std::process::{Command, Stdio};
|
|
20
|
+
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
21
|
+
use std::sync::Arc;
|
|
22
|
+
use std::thread;
|
|
23
|
+
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
|
24
|
+
use tempfile::TempDir;
|
|
25
|
+
|
|
26
|
+
/// Memory usage tracker for cache analysis
|
|
27
|
+
#[derive(Debug, Clone)]
|
|
28
|
+
struct MemoryUsage {
|
|
29
|
+
timestamp: u64,
|
|
30
|
+
cache_entries: usize,
|
|
31
|
+
estimated_memory_mb: f64,
|
|
32
|
+
operation_count: usize,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Cache performance metrics
|
|
36
|
+
#[derive(Debug, Clone)]
|
|
37
|
+
struct CacheMetrics {
|
|
38
|
+
hits: usize,
|
|
39
|
+
misses: usize,
|
|
40
|
+
insertions: usize,
|
|
41
|
+
evictions: usize,
|
|
42
|
+
memory_usage: Vec<MemoryUsage>,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
impl CacheMetrics {
|
|
46
|
+
fn new() -> Self {
|
|
47
|
+
Self {
|
|
48
|
+
hits: 0,
|
|
49
|
+
misses: 0,
|
|
50
|
+
insertions: 0,
|
|
51
|
+
evictions: 0,
|
|
52
|
+
memory_usage: Vec::new(),
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
fn hit_rate(&self) -> f64 {
|
|
57
|
+
if self.hits + self.misses == 0 {
|
|
58
|
+
0.0
|
|
59
|
+
} else {
|
|
60
|
+
self.hits as f64 / (self.hits + self.misses) as f64
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
fn record_memory_usage(&mut self, entries: usize, estimated_mb: f64, ops: usize) {
|
|
65
|
+
let timestamp = SystemTime::now()
|
|
66
|
+
.duration_since(UNIX_EPOCH)
|
|
67
|
+
.unwrap_or_default()
|
|
68
|
+
.as_secs();
|
|
69
|
+
|
|
70
|
+
self.memory_usage.push(MemoryUsage {
|
|
71
|
+
timestamp,
|
|
72
|
+
cache_entries: entries,
|
|
73
|
+
estimated_memory_mb: estimated_mb,
|
|
74
|
+
operation_count: ops,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// Simulates tree cache memory growth
|
|
80
|
+
struct TreeCacheSimulator {
|
|
81
|
+
cache: HashMap<String, (String, u64)>, // file_path -> (content, hash)
|
|
82
|
+
metrics: CacheMetrics,
|
|
83
|
+
memory_per_entry_kb: f64,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
impl TreeCacheSimulator {
|
|
87
|
+
fn new() -> Self {
|
|
88
|
+
Self {
|
|
89
|
+
cache: HashMap::new(),
|
|
90
|
+
metrics: CacheMetrics::new(),
|
|
91
|
+
memory_per_entry_kb: 2.5, // Estimated memory per cached tree
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fn parse_file(&mut self, file_path: &str, content: &str) -> bool {
|
|
96
|
+
let content_hash = self.hash_content(content);
|
|
97
|
+
|
|
98
|
+
if let Some((cached_content, cached_hash)) = self.cache.get(file_path) {
|
|
99
|
+
if cached_hash == &content_hash {
|
|
100
|
+
self.metrics.hits += 1;
|
|
101
|
+
return true; // Cache hit
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
self.metrics.misses += 1;
|
|
106
|
+
self.cache.insert(file_path.to_string(), (content.to_string(), content_hash));
|
|
107
|
+
self.metrics.insertions += 1;
|
|
108
|
+
|
|
109
|
+
// Record memory usage every 100 operations
|
|
110
|
+
if self.metrics.insertions % 100 == 0 {
|
|
111
|
+
let memory_mb = (self.cache.len() as f64 * self.memory_per_entry_kb) / 1024.0;
|
|
112
|
+
self.metrics.record_memory_usage(
|
|
113
|
+
self.cache.len(),
|
|
114
|
+
memory_mb,
|
|
115
|
+
self.metrics.insertions,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
false // Cache miss
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
fn hash_content(&self, content: &str) -> u64 {
|
|
123
|
+
use std::collections::hash_map::DefaultHasher;
|
|
124
|
+
use std::hash::{Hash, Hasher};
|
|
125
|
+
|
|
126
|
+
let mut hasher = DefaultHasher::new();
|
|
127
|
+
content.hash(&mut hasher);
|
|
128
|
+
hasher.finish()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fn get_metrics(&self) -> &CacheMetrics {
|
|
132
|
+
&self.metrics
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fn get_memory_usage_mb(&self) -> f64 {
|
|
136
|
+
(self.cache.len() as f64 * self.memory_per_entry_kb) / 1024.0
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/// Simulates token cache with size limits
|
|
141
|
+
struct TokenCacheSimulator {
|
|
142
|
+
cache: HashMap<String, (usize, u64)>, // content_hash -> (token_count, last_accessed)
|
|
143
|
+
metrics: CacheMetrics,
|
|
144
|
+
max_entries: usize,
|
|
145
|
+
ttl_seconds: u64,
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
impl TokenCacheSimulator {
|
|
149
|
+
fn new(max_entries: usize, ttl_seconds: u64) -> Self {
|
|
150
|
+
Self {
|
|
151
|
+
cache: HashMap::new(),
|
|
152
|
+
metrics: CacheMetrics::new(),
|
|
153
|
+
max_entries,
|
|
154
|
+
ttl_seconds,
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
fn count_tokens(&mut self, content: &str) -> usize {
|
|
159
|
+
let content_hash = format!("{:x}", self.hash_content(content));
|
|
160
|
+
let current_time = SystemTime::now()
|
|
161
|
+
.duration_since(UNIX_EPOCH)
|
|
162
|
+
.unwrap_or_default()
|
|
163
|
+
.as_secs();
|
|
164
|
+
|
|
165
|
+
// Check cache
|
|
166
|
+
if let Some((token_count, last_accessed)) = self.cache.get_mut(&content_hash) {
|
|
167
|
+
if current_time - *last_accessed < self.ttl_seconds {
|
|
168
|
+
*last_accessed = current_time;
|
|
169
|
+
self.metrics.hits += 1;
|
|
170
|
+
return *token_count;
|
|
171
|
+
} else {
|
|
172
|
+
// Expired entry
|
|
173
|
+
self.cache.remove(&content_hash);
|
|
174
|
+
self.metrics.evictions += 1;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
self.metrics.misses += 1;
|
|
179
|
+
|
|
180
|
+
// Simulate token counting (just use character count / 4 as approximation)
|
|
181
|
+
let token_count = content.len() / 4;
|
|
182
|
+
|
|
183
|
+
// Evict entries if over limit
|
|
184
|
+
while self.cache.len() >= self.max_entries {
|
|
185
|
+
if let Some(oldest_key) = self.find_oldest_entry() {
|
|
186
|
+
self.cache.remove(&oldest_key);
|
|
187
|
+
self.metrics.evictions += 1;
|
|
188
|
+
} else {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
self.cache.insert(content_hash, (token_count, current_time));
|
|
194
|
+
self.metrics.insertions += 1;
|
|
195
|
+
|
|
196
|
+
// Record memory usage
|
|
197
|
+
if self.metrics.insertions % 50 == 0 {
|
|
198
|
+
let memory_mb = (self.cache.len() as f64 * 0.1) / 1024.0; // ~100 bytes per entry
|
|
199
|
+
self.metrics.record_memory_usage(
|
|
200
|
+
self.cache.len(),
|
|
201
|
+
memory_mb,
|
|
202
|
+
self.metrics.insertions,
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
token_count
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
fn find_oldest_entry(&self) -> Option<String> {
|
|
210
|
+
self.cache
|
|
211
|
+
.iter()
|
|
212
|
+
.min_by_key(|(_, (_, last_accessed))| *last_accessed)
|
|
213
|
+
.map(|(key, _)| key.clone())
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
fn hash_content(&self, content: &str) -> u64 {
|
|
217
|
+
use std::collections::hash_map::DefaultHasher;
|
|
218
|
+
use std::hash::{Hash, Hasher};
|
|
219
|
+
|
|
220
|
+
let mut hasher = DefaultHasher::new();
|
|
221
|
+
content.hash(&mut hasher);
|
|
222
|
+
hasher.finish()
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
fn get_metrics(&self) -> &CacheMetrics {
|
|
226
|
+
&self.metrics
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/// Generates realistic test content
|
|
231
|
+
struct ContentGenerator {
|
|
232
|
+
file_counter: AtomicUsize,
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
impl ContentGenerator {
|
|
236
|
+
fn new() -> Self {
|
|
237
|
+
Self {
|
|
238
|
+
file_counter: AtomicUsize::new(0),
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
fn generate_rust_file(&self) -> (String, String) {
|
|
243
|
+
let id = self.file_counter.fetch_add(1, Ordering::SeqCst);
|
|
244
|
+
let file_path = format!("src/module_{}.rs", id);
|
|
245
|
+
|
|
246
|
+
let content = format!(r#"
|
|
247
|
+
//! Module {} generated for cache testing
|
|
248
|
+
//! This file contains realistic Rust code to test caching behavior
|
|
249
|
+
|
|
250
|
+
use std::collections::HashMap;
|
|
251
|
+
use std::sync::{{Arc, Mutex}};
|
|
252
|
+
|
|
253
|
+
/// Structure for data processing in module {}
|
|
254
|
+
#[derive(Debug, Clone)]
|
|
255
|
+
pub struct DataProcessor_{} {{
|
|
256
|
+
data: HashMap<String, i32>,
|
|
257
|
+
counter: Arc<Mutex<usize>>,
|
|
258
|
+
config: ProcessorConfig_{},
|
|
259
|
+
}}
|
|
260
|
+
|
|
261
|
+
/// Configuration for processor {}
|
|
262
|
+
#[derive(Debug, Clone)]
|
|
263
|
+
struct ProcessorConfig_{} {{
|
|
264
|
+
max_entries: usize,
|
|
265
|
+
timeout_ms: u64,
|
|
266
|
+
batch_size: usize,
|
|
267
|
+
}}
|
|
268
|
+
|
|
269
|
+
impl DataProcessor_{} {{
|
|
270
|
+
/// Creates a new data processor instance
|
|
271
|
+
pub fn new() -> Self {{
|
|
272
|
+
Self {{
|
|
273
|
+
data: HashMap::new(),
|
|
274
|
+
counter: Arc::new(Mutex::new(0)),
|
|
275
|
+
config: ProcessorConfig_{} {{
|
|
276
|
+
max_entries: {},
|
|
277
|
+
timeout_ms: {},
|
|
278
|
+
batch_size: {},
|
|
279
|
+
}},
|
|
280
|
+
}}
|
|
281
|
+
}}
|
|
282
|
+
|
|
283
|
+
/// Processes a batch of data items
|
|
284
|
+
pub fn process_batch(&mut self, items: Vec<String>) -> Result<Vec<i32>, ProcessorError> {{
|
|
285
|
+
let mut results = Vec::new();
|
|
286
|
+
let mut counter = self.counter.lock().unwrap();
|
|
287
|
+
|
|
288
|
+
for item in items {{
|
|
289
|
+
let processed_value = self.process_single_item(&item)?;
|
|
290
|
+
results.push(processed_value);
|
|
291
|
+
*counter += 1;
|
|
292
|
+
|
|
293
|
+
if results.len() >= self.config.batch_size {{
|
|
294
|
+
break;
|
|
295
|
+
}}
|
|
296
|
+
}}
|
|
297
|
+
|
|
298
|
+
Ok(results)
|
|
299
|
+
}}
|
|
300
|
+
|
|
301
|
+
/// Processes a single data item
|
|
302
|
+
fn process_single_item(&mut self, item: &str) -> Result<i32, ProcessorError> {{
|
|
303
|
+
// Simulate processing logic
|
|
304
|
+
let hash_value = item.chars().map(|c| c as u32).sum::<u32>() as i32;
|
|
305
|
+
let processed = hash_value * {} + {};
|
|
306
|
+
|
|
307
|
+
self.data.insert(item.to_string(), processed);
|
|
308
|
+
Ok(processed)
|
|
309
|
+
}}
|
|
310
|
+
|
|
311
|
+
/// Gets statistics about processed data
|
|
312
|
+
pub fn get_stats(&self) -> ProcessorStats {{
|
|
313
|
+
let counter = self.counter.lock().unwrap();
|
|
314
|
+
ProcessorStats {{
|
|
315
|
+
total_processed: *counter,
|
|
316
|
+
unique_items: self.data.len(),
|
|
317
|
+
average_value: if self.data.is_empty() {{
|
|
318
|
+
0.0
|
|
319
|
+
}} else {{
|
|
320
|
+
self.data.values().sum::<i32>() as f64 / self.data.len() as f64
|
|
321
|
+
}},
|
|
322
|
+
}}
|
|
323
|
+
}}
|
|
324
|
+
}}
|
|
325
|
+
|
|
326
|
+
/// Statistics for the data processor
|
|
327
|
+
#[derive(Debug)]
|
|
328
|
+
pub struct ProcessorStats {{
|
|
329
|
+
pub total_processed: usize,
|
|
330
|
+
pub unique_items: usize,
|
|
331
|
+
pub average_value: f64,
|
|
332
|
+
}}
|
|
333
|
+
|
|
334
|
+
/// Error type for processor operations
|
|
335
|
+
#[derive(Debug)]
|
|
336
|
+
pub enum ProcessorError {{
|
|
337
|
+
InvalidInput(String),
|
|
338
|
+
ProcessingFailed(String),
|
|
339
|
+
ConfigurationError(String),
|
|
340
|
+
}}
|
|
341
|
+
|
|
342
|
+
impl std::error::Error for ProcessorError {{}}
|
|
343
|
+
|
|
344
|
+
impl std::fmt::Display for ProcessorError {{
|
|
345
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {{
|
|
346
|
+
match self {{
|
|
347
|
+
ProcessorError::InvalidInput(msg) => write!(f, "Invalid input: {{}}", msg),
|
|
348
|
+
ProcessorError::ProcessingFailed(msg) => write!(f, "Processing failed: {{}}", msg),
|
|
349
|
+
ProcessorError::ConfigurationError(msg) => write!(f, "Configuration error: {{}}", msg),
|
|
350
|
+
}}
|
|
351
|
+
}}
|
|
352
|
+
}}
|
|
353
|
+
|
|
354
|
+
#[cfg(test)]
|
|
355
|
+
mod tests {{
|
|
356
|
+
use super::*;
|
|
357
|
+
|
|
358
|
+
#[test]
|
|
359
|
+
fn test_processor_creation() {{
|
|
360
|
+
let processor = DataProcessor_{}::new();
|
|
361
|
+
let stats = processor.get_stats();
|
|
362
|
+
assert_eq!(stats.total_processed, 0);
|
|
363
|
+
assert_eq!(stats.unique_items, 0);
|
|
364
|
+
}}
|
|
365
|
+
|
|
366
|
+
#[test]
|
|
367
|
+
fn test_batch_processing() {{
|
|
368
|
+
let mut processor = DataProcessor_{}::new();
|
|
369
|
+
let items = vec!["item1".to_string(), "item2".to_string(), "item3".to_string()];
|
|
370
|
+
|
|
371
|
+
let results = processor.process_batch(items).unwrap();
|
|
372
|
+
assert_eq!(results.len(), 3);
|
|
373
|
+
|
|
374
|
+
let stats = processor.get_stats();
|
|
375
|
+
assert_eq!(stats.total_processed, 3);
|
|
376
|
+
assert_eq!(stats.unique_items, 3);
|
|
377
|
+
}}
|
|
378
|
+
}}
|
|
379
|
+
"#,
|
|
380
|
+
id, id, id, id, id, id, id,
|
|
381
|
+
id * 100 + 50, // max_entries
|
|
382
|
+
id * 1000 + 5000, // timeout_ms
|
|
383
|
+
id % 10 + 5, // batch_size
|
|
384
|
+
id * 13 + 7, // multiplier
|
|
385
|
+
id * 5 + 42, // offset
|
|
386
|
+
id, id
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
(file_path, content)
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
fn generate_javascript_file(&self) -> (String, String) {
|
|
393
|
+
let id = self.file_counter.fetch_add(1, Ordering::SeqCst);
|
|
394
|
+
let file_path = format!("src/component_{}.js", id);
|
|
395
|
+
|
|
396
|
+
let content = format!(r#"
|
|
397
|
+
/**
|
|
398
|
+
* Component {} - Generated for cache testing
|
|
399
|
+
* This file contains realistic JavaScript code patterns
|
|
400
|
+
*/
|
|
401
|
+
|
|
402
|
+
import React, {{ useState, useEffect, useCallback }} from 'react';
|
|
403
|
+
import {{ debounce, throttle }} from 'lodash';
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* DataProcessor component for module {}
|
|
407
|
+
*/
|
|
408
|
+
export const DataProcessor{} = ({{
|
|
409
|
+
initialData = [],
|
|
410
|
+
maxItems = {},
|
|
411
|
+
processingTimeout = {}
|
|
412
|
+
}}) => {{
|
|
413
|
+
const [data, setData] = useState(initialData);
|
|
414
|
+
const [processing, setProcessing] = useState(false);
|
|
415
|
+
const [stats, setStats] = useState({{
|
|
416
|
+
totalProcessed: 0,
|
|
417
|
+
averageValue: 0,
|
|
418
|
+
lastUpdate: null
|
|
419
|
+
}});
|
|
420
|
+
|
|
421
|
+
// Memoized processing function
|
|
422
|
+
const processItems = useCallback(async (items) => {{
|
|
423
|
+
setProcessing(true);
|
|
424
|
+
|
|
425
|
+
try {{
|
|
426
|
+
const processed = await Promise.all(
|
|
427
|
+
items.slice(0, maxItems).map(async (item, index) => {{
|
|
428
|
+
await new Promise(resolve => setTimeout(resolve, processingTimeout / items.length));
|
|
429
|
+
|
|
430
|
+
return {{
|
|
431
|
+
id: `item_${{id}}_${{index}}`,
|
|
432
|
+
value: item.value * {} + {},
|
|
433
|
+
processed: true,
|
|
434
|
+
timestamp: Date.now(),
|
|
435
|
+
metadata: {{
|
|
436
|
+
originalIndex: index,
|
|
437
|
+
processingTime: processingTimeout / items.length,
|
|
438
|
+
batchId: `batch_${{id}}_${{Date.now()}}`
|
|
439
|
+
}}
|
|
440
|
+
}};
|
|
441
|
+
}})
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
setData(processed);
|
|
445
|
+
setStats(prevStats => ({{
|
|
446
|
+
totalProcessed: prevStats.totalProcessed + processed.length,
|
|
447
|
+
averageValue: processed.reduce((sum, item) => sum + item.value, 0) / processed.length,
|
|
448
|
+
lastUpdate: new Date().toISOString()
|
|
449
|
+
}}));
|
|
450
|
+
|
|
451
|
+
}} catch (error) {{
|
|
452
|
+
console.error('Processing error in component {}:', error);
|
|
453
|
+
}} finally {{
|
|
454
|
+
setProcessing(false);
|
|
455
|
+
}}
|
|
456
|
+
}}, [maxItems, processingTimeout]);
|
|
457
|
+
|
|
458
|
+
// Debounced search function
|
|
459
|
+
const handleSearch = useCallback(
|
|
460
|
+
debounce((searchTerm) => {{
|
|
461
|
+
const filtered = data.filter(item =>
|
|
462
|
+
item.id.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
463
|
+
item.metadata.batchId.includes(searchTerm)
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
console.log(`Search results for "${{searchTerm}}" in component {}:`, filtered.length);
|
|
467
|
+
}}, 300),
|
|
468
|
+
[data]
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
// Throttled update function
|
|
472
|
+
const handleUpdate = useCallback(
|
|
473
|
+
throttle((updates) => {{
|
|
474
|
+
setData(prevData =>
|
|
475
|
+
prevData.map(item => {{
|
|
476
|
+
const update = updates.find(u => u.id === item.id);
|
|
477
|
+
return update ? {{ ...item, ...update }} : item;
|
|
478
|
+
}})
|
|
479
|
+
);
|
|
480
|
+
}}, 100),
|
|
481
|
+
[]
|
|
482
|
+
);
|
|
483
|
+
|
|
484
|
+
// Effect for processing data
|
|
485
|
+
useEffect(() => {{
|
|
486
|
+
if (initialData.length > 0) {{
|
|
487
|
+
processItems(initialData);
|
|
488
|
+
}}
|
|
489
|
+
}}, [initialData, processItems]);
|
|
490
|
+
|
|
491
|
+
// Effect for cleanup
|
|
492
|
+
useEffect(() => {{
|
|
493
|
+
return () => {{
|
|
494
|
+
console.log(`Cleanup component {} with ${{data.length}} items`);
|
|
495
|
+
}};
|
|
496
|
+
}}, [data.length]);
|
|
497
|
+
|
|
498
|
+
const renderItem = (item) => (
|
|
499
|
+
<div key={{item.id}} className="data-item">
|
|
500
|
+
<h3>{{item.id}}</h3>
|
|
501
|
+
<p>Value: {{item.value}}</p>
|
|
502
|
+
<p>Processed: {{item.processed ? 'Yes' : 'No'}}</p>
|
|
503
|
+
<small>{{item.timestamp}}</small>
|
|
504
|
+
</div>
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
const renderStats = () => (
|
|
508
|
+
<div className="stats-panel">
|
|
509
|
+
<h2>Processing Stats</h2>
|
|
510
|
+
<p>Total Processed: {{stats.totalProcessed}}</p>
|
|
511
|
+
<p>Average Value: {{stats.averageValue.toFixed(2)}}</p>
|
|
512
|
+
<p>Last Update: {{stats.lastUpdate}}</p>
|
|
513
|
+
<p>Current Items: {{data.length}}</p>
|
|
514
|
+
</div>
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
return (
|
|
518
|
+
<div className="data-processor-{{}}">
|
|
519
|
+
<h1>Data Processor Component {{}}</h1>
|
|
520
|
+
|
|
521
|
+
{{renderStats()}}
|
|
522
|
+
|
|
523
|
+
<div className="controls">
|
|
524
|
+
<button
|
|
525
|
+
onClick={{() => processItems(initialData)}}
|
|
526
|
+
disabled={{processing}}
|
|
527
|
+
>
|
|
528
|
+
{{processing ? 'Processing...' : 'Reprocess Data'}}
|
|
529
|
+
</button>
|
|
530
|
+
|
|
531
|
+
<input
|
|
532
|
+
type="text"
|
|
533
|
+
placeholder="Search items..."
|
|
534
|
+
onChange={{(e) => handleSearch(e.target.value)}}
|
|
535
|
+
/>
|
|
536
|
+
</div>
|
|
537
|
+
|
|
538
|
+
<div className="items-grid">
|
|
539
|
+
{{data.map(renderItem)}}
|
|
540
|
+
</div>
|
|
541
|
+
</div>
|
|
542
|
+
);
|
|
543
|
+
}};
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Utility functions for component {}
|
|
547
|
+
*/
|
|
548
|
+
export const ComponentUtils{} = {{
|
|
549
|
+
// Data transformation utilities
|
|
550
|
+
transformData: (rawData) => {{
|
|
551
|
+
return rawData.map((item, index) => ({{
|
|
552
|
+
...item,
|
|
553
|
+
id: `transformed_${{index}}_${{{}}}`,
|
|
554
|
+
transformedAt: Date.now(),
|
|
555
|
+
originalData: item
|
|
556
|
+
}}));
|
|
557
|
+
}},
|
|
558
|
+
|
|
559
|
+
// Validation utilities
|
|
560
|
+
validateItems: (items) => {{
|
|
561
|
+
const errors = [];
|
|
562
|
+
|
|
563
|
+
items.forEach((item, index) => {{
|
|
564
|
+
if (!item.id) {{
|
|
565
|
+
errors.push(`Item at index ${{index}} missing id`);
|
|
566
|
+
}}
|
|
567
|
+
if (typeof item.value !== 'number') {{
|
|
568
|
+
errors.push(`Item at index ${{index}} has invalid value type`);
|
|
569
|
+
}}
|
|
570
|
+
}});
|
|
571
|
+
|
|
572
|
+
return errors;
|
|
573
|
+
}},
|
|
574
|
+
|
|
575
|
+
// Performance utilities
|
|
576
|
+
measurePerformance: (fn, label = 'operation') => {{
|
|
577
|
+
return (...args) => {{
|
|
578
|
+
const start = performance.now();
|
|
579
|
+
const result = fn(...args);
|
|
580
|
+
const end = performance.now();
|
|
581
|
+
|
|
582
|
+
console.log(`${{label}} in component {} took ${{end - start}} milliseconds`);
|
|
583
|
+
return result;
|
|
584
|
+
}};
|
|
585
|
+
}}
|
|
586
|
+
}};
|
|
587
|
+
|
|
588
|
+
export default DataProcessor{};
|
|
589
|
+
"#,
|
|
590
|
+
id, id, id,
|
|
591
|
+
id * 10 + 20, // maxItems
|
|
592
|
+
id * 100 + 1000, // processingTimeout
|
|
593
|
+
id * 7 + 3, // multiplier
|
|
594
|
+
id * 2 + 10, // offset
|
|
595
|
+
id, id, id, id, id, id, id, id, id
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
(file_path, content)
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/// Runs the cache memory analysis
|
|
603
|
+
fn main() {
|
|
604
|
+
println!("๐ Probe Cache Memory Growth Analysis");
|
|
605
|
+
println!("=====================================\n");
|
|
606
|
+
|
|
607
|
+
// Test 1: Unbounded Tree Cache Growth
|
|
608
|
+
println!("๐ Test 1: Tree Cache Unbounded Growth");
|
|
609
|
+
test_tree_cache_growth();
|
|
610
|
+
println!();
|
|
611
|
+
|
|
612
|
+
// Test 2: Token Cache with Limits
|
|
613
|
+
println!("๐ Test 2: Token Cache with Size Limits");
|
|
614
|
+
test_token_cache_behavior();
|
|
615
|
+
println!();
|
|
616
|
+
|
|
617
|
+
// Test 3: Mixed Workload Memory Usage
|
|
618
|
+
println!("๐ Test 3: Mixed Workload Memory Impact");
|
|
619
|
+
test_mixed_workload();
|
|
620
|
+
println!();
|
|
621
|
+
|
|
622
|
+
// Test 4: Concurrent Access Memory Issues
|
|
623
|
+
println!("๐ Test 4: Concurrent Access Memory Patterns");
|
|
624
|
+
test_concurrent_memory_usage();
|
|
625
|
+
println!();
|
|
626
|
+
|
|
627
|
+
println!("โ
Analysis Complete - Results show critical memory management issues");
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
fn test_tree_cache_growth() {
|
|
631
|
+
let mut tree_cache = TreeCacheSimulator::new();
|
|
632
|
+
let generator = ContentGenerator::new();
|
|
633
|
+
|
|
634
|
+
println!(" Simulating tree cache with {} files...", 5000);
|
|
635
|
+
|
|
636
|
+
let start_time = Instant::now();
|
|
637
|
+
|
|
638
|
+
// Simulate parsing 5000 unique files (unbounded growth)
|
|
639
|
+
for i in 0..5000 {
|
|
640
|
+
let (file_path, content) = generator.generate_rust_file();
|
|
641
|
+
tree_cache.parse_file(&file_path, &content);
|
|
642
|
+
|
|
643
|
+
if i % 1000 == 0 && i > 0 {
|
|
644
|
+
let memory_mb = tree_cache.get_memory_usage_mb();
|
|
645
|
+
println!(" ๐ After {} files: {:.2} MB memory usage", i, memory_mb);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
let duration = start_time.elapsed();
|
|
650
|
+
let metrics = tree_cache.get_metrics();
|
|
651
|
+
|
|
652
|
+
println!(" โ ๏ธ CRITICAL: Tree cache has NO size limits!");
|
|
653
|
+
println!(" ๐พ Final memory usage: {:.2} MB", tree_cache.get_memory_usage_mb());
|
|
654
|
+
println!(" ๐ Cache entries: {}", tree_cache.cache.len());
|
|
655
|
+
println!(" ๐ฏ Hit rate: {:.2}%", metrics.hit_rate() * 100.0);
|
|
656
|
+
println!(" โฑ๏ธ Total time: {:?}", duration);
|
|
657
|
+
|
|
658
|
+
if tree_cache.get_memory_usage_mb() > 100.0 {
|
|
659
|
+
println!(" ๐จ Memory usage exceeds 100MB - OOM risk on large codebases!");
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
fn test_token_cache_behavior() {
|
|
664
|
+
let mut token_cache = TokenCacheSimulator::new(1000, 3600); // 1000 entries, 1 hour TTL
|
|
665
|
+
let generator = ContentGenerator::new();
|
|
666
|
+
|
|
667
|
+
println!(" Simulating token cache with {} content pieces...", 2000);
|
|
668
|
+
|
|
669
|
+
let start_time = Instant::now();
|
|
670
|
+
|
|
671
|
+
// Generate 2000 pieces of content (should trigger evictions)
|
|
672
|
+
for i in 0..2000 {
|
|
673
|
+
let (_, content) = if i % 2 == 0 {
|
|
674
|
+
generator.generate_rust_file()
|
|
675
|
+
} else {
|
|
676
|
+
generator.generate_javascript_file()
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
let _token_count = token_cache.count_tokens(&content);
|
|
680
|
+
|
|
681
|
+
if i % 500 == 0 && i > 0 {
|
|
682
|
+
let metrics = token_cache.get_metrics();
|
|
683
|
+
println!(" ๐ After {} items: {} cached, {:.2}% hit rate",
|
|
684
|
+
i, token_cache.cache.len(), metrics.hit_rate() * 100.0);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
let duration = start_time.elapsed();
|
|
689
|
+
let metrics = token_cache.get_metrics();
|
|
690
|
+
|
|
691
|
+
println!(" โ
Token cache respects size limits");
|
|
692
|
+
println!(" ๐ Final cache size: {}", token_cache.cache.len());
|
|
693
|
+
println!(" ๐ฏ Hit rate: {:.2}%", metrics.hit_rate() * 100.0);
|
|
694
|
+
println!(" ๐๏ธ Evictions: {}", metrics.evictions);
|
|
695
|
+
println!(" โฑ๏ธ Total time: {:?}", duration);
|
|
696
|
+
|
|
697
|
+
// Test TTL expiration simulation
|
|
698
|
+
println!(" Testing TTL expiration...");
|
|
699
|
+
thread::sleep(Duration::from_millis(100)); // Small delay
|
|
700
|
+
|
|
701
|
+
let expired_content = "This content should be expired";
|
|
702
|
+
let _token_count = token_cache.count_tokens(expired_content);
|
|
703
|
+
|
|
704
|
+
println!(" โ
TTL mechanism working (simulated)");
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
fn test_mixed_workload() {
|
|
708
|
+
let mut tree_cache = TreeCacheSimulator::new();
|
|
709
|
+
let mut token_cache = TokenCacheSimulator::new(500, 1800); // Smaller cache
|
|
710
|
+
let generator = ContentGenerator::new();
|
|
711
|
+
|
|
712
|
+
println!(" Simulating mixed workload: parsing + tokenization...");
|
|
713
|
+
|
|
714
|
+
let start_time = Instant::now();
|
|
715
|
+
let mut total_tree_memory = 0.0;
|
|
716
|
+
let mut files_processed = 0;
|
|
717
|
+
|
|
718
|
+
// Mixed workload: parse files and count tokens
|
|
719
|
+
for i in 0..1000 {
|
|
720
|
+
let (file_path, content) = if i % 3 == 0 {
|
|
721
|
+
generator.generate_rust_file()
|
|
722
|
+
} else {
|
|
723
|
+
generator.generate_javascript_file()
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
// Tree parsing (unbounded cache)
|
|
727
|
+
tree_cache.parse_file(&file_path, &content);
|
|
728
|
+
|
|
729
|
+
// Token counting (bounded cache)
|
|
730
|
+
let _token_count = token_cache.count_tokens(&content);
|
|
731
|
+
|
|
732
|
+
files_processed += 1;
|
|
733
|
+
|
|
734
|
+
if i % 200 == 0 && i > 0 {
|
|
735
|
+
total_tree_memory = tree_cache.get_memory_usage_mb();
|
|
736
|
+
let token_metrics = token_cache.get_metrics();
|
|
737
|
+
|
|
738
|
+
println!(" ๐ Mixed workload progress:");
|
|
739
|
+
println!(" - Files processed: {}", files_processed);
|
|
740
|
+
println!(" - Tree cache memory: {:.2} MB", total_tree_memory);
|
|
741
|
+
println!(" - Token cache size: {}", token_cache.cache.len());
|
|
742
|
+
println!(" - Token hit rate: {:.2}%", token_metrics.hit_rate() * 100.0);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
let duration = start_time.elapsed();
|
|
747
|
+
|
|
748
|
+
println!(" ๐ Mixed workload results:");
|
|
749
|
+
println!(" โ ๏ธ Tree cache memory: {:.2} MB (unbounded)", total_tree_memory);
|
|
750
|
+
println!(" โ
Token cache memory: ~{:.2} MB (bounded)", token_cache.cache.len() as f64 * 0.1 / 1024.0);
|
|
751
|
+
println!(" โฑ๏ธ Total time: {:?}", duration);
|
|
752
|
+
|
|
753
|
+
// Demonstrate the problem
|
|
754
|
+
let tree_to_token_ratio = total_tree_memory / (token_cache.cache.len() as f64 * 0.1 / 1024.0);
|
|
755
|
+
if tree_to_token_ratio > 50.0 {
|
|
756
|
+
println!(" ๐จ Tree cache uses {}x more memory than token cache!", tree_to_token_ratio as usize);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
fn test_concurrent_memory_usage() {
|
|
761
|
+
println!(" Simulating concurrent cache access...");
|
|
762
|
+
|
|
763
|
+
let tree_memory = Arc::new(AtomicUsize::new(0));
|
|
764
|
+
let files_processed = Arc::new(AtomicUsize::new(0));
|
|
765
|
+
|
|
766
|
+
let handles: Vec<_> = (0..4).map(|thread_id| {
|
|
767
|
+
let tree_memory = Arc::clone(&tree_memory);
|
|
768
|
+
let files_processed = Arc::clone(&files_processed);
|
|
769
|
+
|
|
770
|
+
thread::spawn(move || {
|
|
771
|
+
let mut local_tree_cache = TreeCacheSimulator::new();
|
|
772
|
+
let mut local_token_cache = TokenCacheSimulator::new(200, 1800);
|
|
773
|
+
let generator = ContentGenerator::new();
|
|
774
|
+
|
|
775
|
+
for i in 0..250 { // 250 files per thread = 1000 total
|
|
776
|
+
let (file_path, content) = if (thread_id + i) % 2 == 0 {
|
|
777
|
+
generator.generate_rust_file()
|
|
778
|
+
} else {
|
|
779
|
+
generator.generate_javascript_file()
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
local_tree_cache.parse_file(&file_path, &content);
|
|
783
|
+
let _token_count = local_token_cache.count_tokens(&content);
|
|
784
|
+
|
|
785
|
+
files_processed.fetch_add(1, Ordering::SeqCst);
|
|
786
|
+
|
|
787
|
+
// Update memory estimate (very rough)
|
|
788
|
+
let memory_kb = (local_tree_cache.cache.len() as f64 * 2.5) as usize;
|
|
789
|
+
tree_memory.store(memory_kb, Ordering::SeqCst);
|
|
790
|
+
|
|
791
|
+
// Small delay to simulate realistic processing
|
|
792
|
+
thread::sleep(Duration::from_millis(1));
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
(local_tree_cache.get_memory_usage_mb(), local_tree_cache.get_metrics().clone())
|
|
796
|
+
})
|
|
797
|
+
}).collect();
|
|
798
|
+
|
|
799
|
+
// Wait for completion and collect results
|
|
800
|
+
let mut total_memory = 0.0;
|
|
801
|
+
let mut total_entries = 0;
|
|
802
|
+
|
|
803
|
+
for handle in handles {
|
|
804
|
+
let (memory_mb, _metrics) = handle.join().unwrap();
|
|
805
|
+
total_memory += memory_mb;
|
|
806
|
+
total_entries += 1;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
let final_files = files_processed.load(Ordering::SeqCst);
|
|
810
|
+
|
|
811
|
+
println!(" ๐ Concurrent processing results:");
|
|
812
|
+
println!(" ๐ Total files processed: {}", final_files);
|
|
813
|
+
println!(" ๐พ Combined memory usage: {:.2} MB", total_memory);
|
|
814
|
+
println!(" ๐งต Memory per thread: {:.2} MB", total_memory / 4.0);
|
|
815
|
+
|
|
816
|
+
if total_memory > 50.0 {
|
|
817
|
+
println!(" ๐จ High memory usage in concurrent scenario!");
|
|
818
|
+
println!(" ๐ก Each thread maintains separate unbounded cache");
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
println!(" โ ๏ธ Real Probe would have shared caches with race conditions");
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/// Additional utility to demonstrate system memory pressure
|
|
825
|
+
fn check_system_memory() {
|
|
826
|
+
println!("\n๐ฅ๏ธ System Memory Check:");
|
|
827
|
+
|
|
828
|
+
// Try to get system memory info (Unix-like systems)
|
|
829
|
+
if let Ok(output) = Command::new("free")
|
|
830
|
+
.args(&["-m"])
|
|
831
|
+
.output()
|
|
832
|
+
{
|
|
833
|
+
if let Ok(output_str) = String::from_utf8(output.stdout) {
|
|
834
|
+
println!("{}", output_str);
|
|
835
|
+
}
|
|
836
|
+
} else if let Ok(output) = Command::new("vm_stat").output() {
|
|
837
|
+
// macOS alternative
|
|
838
|
+
if let Ok(output_str) = String::from_utf8(output.stdout) {
|
|
839
|
+
println!("macOS Memory Stats:\n{}", output_str);
|
|
840
|
+
}
|
|
841
|
+
} else {
|
|
842
|
+
println!(" โ Unable to get system memory info");
|
|
843
|
+
}
|
|
844
|
+
}
|