0xray 2.0.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/.opencode/agents/api-design.yml +31 -0
- package/.opencode/agents/architect.yml +15 -0
- package/.opencode/agents/architecture-patterns.yml +14 -0
- package/.opencode/agents/auto-format.yml +14 -0
- package/.opencode/agents/backend-engineer.yml +12 -0
- package/.opencode/agents/boot-orchestrator.yml +14 -0
- package/.opencode/agents/bug-triage-specialist.yml +15 -0
- package/.opencode/agents/code-analyzer.yml +12 -0
- package/.opencode/agents/code-reviewer.yml +14 -0
- package/.opencode/agents/content-creator.yml +12 -0
- package/.opencode/agents/database-engineer.yml +12 -0
- package/.opencode/agents/devops-engineer.yml +12 -0
- package/.opencode/agents/framework-compliance-audit.yml +14 -0
- package/.opencode/agents/frontend-engineer.yml +12 -0
- package/.opencode/agents/frontend-ui-ux-engineer.yml +12 -0
- package/.opencode/agents/git-workflow.yml +15 -0
- package/.opencode/agents/growth-strategist.yml +12 -0
- package/.opencode/agents/hermes-agent.yml +12 -0
- package/.opencode/agents/inference-improve.yml +12 -0
- package/.opencode/agents/lint.yml +14 -0
- package/.opencode/agents/log-monitor.yml +12 -0
- package/.opencode/agents/mobile-developer.yml +12 -0
- package/.opencode/agents/model-health-check.yml +12 -0
- package/.opencode/agents/multimodal-looker.yml +12 -0
- package/.opencode/agents/performance-analysis.yml +12 -0
- package/.opencode/agents/performance-engineer.yml +12 -0
- package/.opencode/agents/performance-optimization.yml +12 -0
- package/.opencode/agents/processor-pipeline.yml +14 -0
- package/.opencode/agents/project-analysis.yml +12 -0
- package/.opencode/agents/refactorer.yml +12 -0
- package/.opencode/agents/researcher.yml +12 -0
- package/.opencode/agents/security-auditor.yml +12 -0
- package/.opencode/agents/security-scan.yml +12 -0
- package/.opencode/agents/seo-consultant.yml +12 -0
- package/.opencode/agents/session-management.yml +12 -0
- package/.opencode/agents/state-manager.yml +12 -0
- package/.opencode/agents/storyteller.yml +12 -0
- package/.opencode/agents/strategist.yml +12 -0
- package/.opencode/agents/tech-writer.yml +12 -0
- package/.opencode/agents/testing-best-practices.yml +12 -0
- package/.opencode/agents/testing-lead.yml +12 -0
- package/.opencode/agents/ui-ux-design.yml +12 -0
- package/.opencode/codex.codex +8 -0
- package/.opencode/commands/auto-format.md +99 -0
- package/.opencode/commands/auto-summary-capture.md +90 -0
- package/.opencode/commands/dependency-audit.md +184 -0
- package/.opencode/commands/enforcer-daily-scan.md +137 -0
- package/.opencode/commands/framework-compliance-audit.md +205 -0
- package/.opencode/commands/interactive-validator.md +75 -0
- package/.opencode/commands/job-summary-logger.md +68 -0
- package/.opencode/commands/lint.md +11 -0
- package/.opencode/commands/mode-switch.md +95 -0
- package/.opencode/commands/model-health-check.md +186 -0
- package/.opencode/commands/performance-analysis.md +144 -0
- package/.opencode/commands/pre-commit-introspection.md +185 -0
- package/.opencode/commands/pre-commit-introspection.sh +133 -0
- package/.opencode/commands/security-scan.md +157 -0
- package/.opencode/commands/sisyphus-validation.md +128 -0
- package/.opencode/commands/summary-logger.md +83 -0
- package/.opencode/enforcer-config.json +285 -0
- package/.opencode/hooks/hook-metrics.json +380 -0
- package/.opencode/hooks/post-commit +114 -0
- package/.opencode/hooks/post-push +34 -0
- package/.opencode/init.sh +151 -0
- package/.opencode/skills/api-design/SKILL.md +37 -0
- package/.opencode/skills/architect-tools/SKILL.md +37 -0
- package/.opencode/skills/architecture-patterns/SKILL.md +37 -0
- package/.opencode/skills/auto-format/SKILL.md +37 -0
- package/.opencode/skills/backend-engineer/SKILL.md +49 -0
- package/.opencode/skills/boot-orchestrator/SKILL.md +37 -0
- package/.opencode/skills/bug-triage/SKILL.md +43 -0
- package/.opencode/skills/code-analyzer/SKILL.md +45 -0
- package/.opencode/skills/code-review/SKILL.md +52 -0
- package/.opencode/skills/content-creator/SKILL.md +38 -0
- package/.opencode/skills/database-engineer/SKILL.md +46 -0
- package/.opencode/skills/devops-engineer/SKILL.md +49 -0
- package/.opencode/skills/enforcer/SKILL.md +37 -0
- package/.opencode/skills/framework-compliance-audit/SKILL.md +37 -0
- package/.opencode/skills/frontend-engineer/SKILL.md +49 -0
- package/.opencode/skills/frontend-ui-ux-engineer/SKILL.md +41 -0
- package/.opencode/skills/git-workflow/SKILL.md +37 -0
- package/.opencode/skills/growth-strategist/SKILL.md +48 -0
- package/.opencode/skills/hermes-agent/SKILL.md +212 -0
- package/.opencode/skills/inference-improve/SKILL.md +97 -0
- package/.opencode/skills/lint/SKILL.md +37 -0
- package/.opencode/skills/log-monitor/SKILL.md +44 -0
- package/.opencode/skills/mobile-developer/SKILL.md +42 -0
- package/.opencode/skills/model-health-check/SKILL.md +37 -0
- package/.opencode/skills/multimodal-looker/SKILL.md +45 -0
- package/.opencode/skills/orchestrator/SKILL.md +37 -0
- package/.opencode/skills/performance-analysis/SKILL.md +37 -0
- package/.opencode/skills/performance-engineer/SKILL.md +41 -0
- package/.opencode/skills/performance-optimization/SKILL.md +37 -0
- package/.opencode/skills/processor-pipeline/SKILL.md +37 -0
- package/.opencode/skills/project-analysis/SKILL.md +42 -0
- package/.opencode/skills/refactoring-strategies/SKILL.md +37 -0
- package/.opencode/skills/registry.json +66 -0
- package/.opencode/skills/researcher/SKILL.md +37 -0
- package/.opencode/skills/security-audit/SKILL.md +47 -0
- package/.opencode/skills/security-scan/SKILL.md +37 -0
- package/.opencode/skills/seo-consultant/SKILL.md +43 -0
- package/.opencode/skills/session-management/SKILL.md +36 -0
- package/.opencode/skills/state-manager/SKILL.md +37 -0
- package/.opencode/skills/storyteller/SKILL.md +130 -0
- package/.opencode/skills/strategist/SKILL.md +32 -0
- package/.opencode/skills/tech-writer/SKILL.md +37 -0
- package/.opencode/skills/testing-best-practices/SKILL.md +37 -0
- package/.opencode/skills/testing-strategy/SKILL.md +43 -0
- package/.opencode/skills/ui-ux-design/SKILL.md +603 -0
- package/.opencode/workflows/post-deployment-audit.yml +123 -0
- package/AGENTS.md +110 -0
- package/LICENSE +21 -0
- package/README.md +131 -0
- package/dist/AGENTS.md +110 -0
- package/dist/CHANGELOG.md +2182 -0
- package/dist/LICENSE +21 -0
- package/dist/README.md +131 -0
- package/dist/agents/architect.js +56 -0
- package/dist/agents/backend-engineer.js +81 -0
- package/dist/agents/bug-triage-specialist.js +74 -0
- package/dist/agents/code-analyzer.js +150 -0
- package/dist/agents/code-reviewer.js +69 -0
- package/dist/agents/content-creator.js +72 -0
- package/dist/agents/database-engineer.js +76 -0
- package/dist/agents/devops-engineer.js +84 -0
- package/dist/agents/frontend-engineer.js +78 -0
- package/dist/agents/frontend-ui-ux-engineer.js +64 -0
- package/dist/agents/growth-strategist.js +111 -0
- package/dist/agents/index.js +45 -0
- package/dist/agents/librarian-agents-updater.js +333 -0
- package/dist/agents/log-monitor.js +109 -0
- package/dist/agents/mobile-developer.js +102 -0
- package/dist/agents/multimodal-looker.js +93 -0
- package/dist/agents/performance-engineer.js +86 -0
- package/dist/agents/refactorer.js +80 -0
- package/dist/agents/registry.js +340 -0
- package/dist/agents/researcher.js +83 -0
- package/dist/agents/security-auditor.js +158 -0
- package/dist/agents/seo-consultant.js +53 -0
- package/dist/agents/strategist.js +47 -0
- package/dist/agents/tech-writer.js +84 -0
- package/dist/agents/testing-lead.js +95 -0
- package/dist/agents/types.js +1 -0
- package/dist/analytics/consent-manager.js +258 -0
- package/dist/analytics/emerging-pattern-detector.js +260 -0
- package/dist/analytics/pattern-learning-engine.js +278 -0
- package/dist/analytics/pattern-performance-tracker.js +336 -0
- package/dist/analytics/predictive-analytics.js +248 -0
- package/dist/analytics/prompt-pattern-analyzer.js +371 -0
- package/dist/analytics/routing-performance-analyzer.js +356 -0
- package/dist/analytics/routing-refiner.js +380 -0
- package/dist/analytics/simple-pattern-analyzer.js +297 -0
- package/dist/architect/architect-tools.js +437 -0
- package/dist/architect/architectural-integrity.js +78 -0
- package/dist/benchmark/performance-benchmark.js +372 -0
- package/dist/cli/commands/analytics-disable.js +72 -0
- package/dist/cli/commands/analytics-enable-action.js +82 -0
- package/dist/cli/commands/analytics-preview.js +106 -0
- package/dist/cli/commands/analytics-status.js +68 -0
- package/dist/cli/commands/antigravity-status.js +106 -0
- package/dist/cli/commands/archive-logs.js +161 -0
- package/dist/cli/commands/credible-init.js +82 -0
- package/dist/cli/commands/grok-install.js +16 -0
- package/dist/cli/commands/hermes-install.js +66 -0
- package/dist/cli/commands/mcp-install.js +253 -0
- package/dist/cli/commands/openclaw-install.js +44 -0
- package/dist/cli/commands/opencode-install.js +99 -0
- package/dist/cli/commands/plugin-commands.js +246 -0
- package/dist/cli/commands/publish-agent.js +184 -0
- package/dist/cli/commands/security-audit.js +219 -0
- package/dist/cli/commands/skill-install.js +481 -0
- package/dist/cli/commands/status.js +196 -0
- package/dist/cli/commands/storyteller.js +230 -0
- package/dist/cli/index.js +986 -0
- package/dist/cli/server.js +147 -0
- package/dist/config/default-agents.js +16 -0
- package/dist/core/activity-logger.js +260 -0
- package/dist/core/adaptive-kernel.js +192 -0
- package/dist/core/agent-spawn-gate.js +120 -0
- package/dist/core/boot-orchestrator.js +812 -0
- package/dist/core/bridge.mjs +945 -0
- package/dist/core/codex-formatter.js +220 -0
- package/dist/core/codex-injector.js +424 -0
- package/dist/core/config-loader.js +148 -0
- package/dist/core/config-paths.js +162 -0
- package/dist/core/context-loader.js +269 -0
- package/dist/core/context-validator.js +212 -0
- package/dist/core/features-config.js +457 -0
- package/dist/core/framework-logger.js +275 -0
- package/dist/core/index.js +6 -0
- package/dist/core/kernel-patterns.js +302 -0
- package/dist/core/logging-config.js +43 -0
- package/dist/core/model-router.js +175 -0
- package/dist/core/orchestrator.js +408 -0
- package/dist/core/system-prompt-generator.js +265 -0
- package/dist/core/trace-context.js +33 -0
- package/dist/core/xray-activation.js +134 -0
- package/dist/delegation/agent-delegator.js +769 -0
- package/dist/delegation/agent-expertise.js +156 -0
- package/dist/delegation/analytics/index.js +12 -0
- package/dist/delegation/analytics/learning-engine.js +277 -0
- package/dist/delegation/analytics/outcome-tracker.js +279 -0
- package/dist/delegation/analytics/routing-analytics.js +193 -0
- package/dist/delegation/ast-code-parser.js +878 -0
- package/dist/delegation/codebase-context-analyzer.js +1040 -0
- package/dist/delegation/complexity-analyzer.js +282 -0
- package/dist/delegation/complexity-core.js +219 -0
- package/dist/delegation/config/types.js +6 -0
- package/dist/delegation/dependency-graph-builder.js +409 -0
- package/dist/delegation/index.js +20 -0
- package/dist/delegation/metrics-aggregator.js +335 -0
- package/dist/delegation/session-coordinator.js +352 -0
- package/dist/delegation/strategy-selector.js +108 -0
- package/dist/delegation/voting-coordinator.js +375 -0
- package/dist/delegation/voting-types.js +10 -0
- package/dist/delegation/weighted-voting-aggregator.js +194 -0
- package/dist/enforcement/core/index.js +19 -0
- package/dist/enforcement/core/rule-executor.js +365 -0
- package/dist/enforcement/core/rule-hierarchy.js +259 -0
- package/dist/enforcement/core/rule-registry.js +240 -0
- package/dist/enforcement/core/violation-fixer.js +651 -0
- package/dist/enforcement/enforcer-tools.js +909 -0
- package/dist/enforcement/index.js +41 -0
- package/dist/enforcement/loaders/agent-triage-loader.js +222 -0
- package/dist/enforcement/loaders/agents-md-validation-loader.js +252 -0
- package/dist/enforcement/loaders/base-loader.js +86 -0
- package/dist/enforcement/loaders/codex-loader.js +396 -0
- package/dist/enforcement/loaders/index.js +40 -0
- package/dist/enforcement/loaders/loader-orchestrator.js +168 -0
- package/dist/enforcement/loaders/processor-loader.js +113 -0
- package/dist/enforcement/rule-enforcer.js +298 -0
- package/dist/enforcement/test-auto-healing.js +325 -0
- package/dist/enforcement/types.js +30 -0
- package/dist/enforcement/validators/architecture-validators.js +600 -0
- package/dist/enforcement/validators/base-validator.js +108 -0
- package/dist/enforcement/validators/code-quality-validators.js +336 -0
- package/dist/enforcement/validators/index.js +21 -0
- package/dist/enforcement/validators/security-validators.js +220 -0
- package/dist/enforcement/validators/testing-validators.js +253 -0
- package/dist/enforcement/validators/validator-registry.js +150 -0
- package/dist/execution/opencode-cli-invoker.js +173 -0
- package/dist/execution/proposal-applier.js +254 -0
- package/dist/governance/codex-policy.service.js +167 -0
- package/dist/governance/governance-core.js +152 -0
- package/dist/governance/governance-service.js +274 -0
- package/dist/governance/governance-types.js +6 -0
- package/dist/index.js +24 -0
- package/dist/inference/deploy-verifier.js +161 -0
- package/dist/inference/index.js +5 -0
- package/dist/inference/inference-accumulator.js +126 -0
- package/dist/inference/inference-cycle.js +1168 -0
- package/dist/inference/semantic-patterns.js +310 -0
- package/dist/inference/session-capture.js +308 -0
- package/dist/integrations/base/ExampleIntegration.js +181 -0
- package/dist/integrations/base/Integration.js +395 -0
- package/dist/integrations/base/README.md +446 -0
- package/dist/integrations/base/index.js +16 -0
- package/dist/integrations/base/registry.js +606 -0
- package/dist/integrations/base/types.js +118 -0
- package/dist/integrations/governance/governance-client.js +316 -0
- package/dist/integrations/governance/index.js +373 -0
- package/dist/integrations/governance/types.js +97 -0
- package/dist/integrations/grok/grok-cli.js +83 -0
- package/dist/integrations/grok/hooks/pre-tool-use.js +134 -0
- package/dist/integrations/grok/plugin/0xray/.mcp.json +15 -0
- package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +30 -0
- package/dist/integrations/hermes-agent/__init__.py +718 -0
- package/dist/integrations/hermes-agent/after-install.md +71 -0
- package/dist/integrations/hermes-agent/bridge.mjs +861 -0
- package/dist/integrations/hermes-agent/conftest.py +14 -0
- package/dist/integrations/hermes-agent/plugin.yaml +12 -0
- package/dist/integrations/hermes-agent/schemas.py +100 -0
- package/dist/integrations/hermes-agent/test_plugin.py +1100 -0
- package/dist/integrations/hermes-agent/tools.py +253 -0
- package/dist/integrations/openclaw/README.md +134 -0
- package/dist/integrations/openclaw/api-server.js +389 -0
- package/dist/integrations/openclaw/client.js +492 -0
- package/dist/integrations/openclaw/config.js +374 -0
- package/dist/integrations/openclaw/hooks/strray-hooks.js +280 -0
- package/dist/integrations/openclaw/index.js +351 -0
- package/dist/integrations/openclaw/types.js +153 -0
- package/dist/integrations/plugins/index.js +10 -0
- package/dist/integrations/plugins/plugin-integration.js +606 -0
- package/dist/integrations/plugins/plugin-registry.js +580 -0
- package/dist/mcps/agent-resolver.js +106 -0
- package/dist/mcps/architect-tools.server.js +277 -0
- package/dist/mcps/auto-format.server.js +413 -0
- package/dist/mcps/boot-orchestrator.server.js +853 -0
- package/dist/mcps/config/config-loader.js +103 -0
- package/dist/mcps/config/config-validator.js +101 -0
- package/dist/mcps/config/index.js +30 -0
- package/dist/mcps/config/plugin-server-registry.js +223 -0
- package/dist/mcps/config/server-config-registry.js +348 -0
- package/dist/mcps/connection/connection-manager.js +79 -0
- package/dist/mcps/connection/connection-pool.js +164 -0
- package/dist/mcps/connection/mcp-connection.js +233 -0
- package/dist/mcps/connection/process-spawner.js +34 -0
- package/dist/mcps/enforcer-tools.server.js +778 -0
- package/dist/mcps/estimation.server.js +192 -0
- package/dist/mcps/framework-compliance-audit.server.js +500 -0
- package/dist/mcps/framework-help.server.js +400 -0
- package/dist/mcps/governance.server.js +464 -0
- package/dist/mcps/in-process-skill-registry.js +48 -0
- package/dist/mcps/knowledge-skills/api-design.server.js +123 -0
- package/dist/mcps/knowledge-skills/architecture-patterns.server.js +113 -0
- package/dist/mcps/knowledge-skills/bug-triage-specialist.server.js +474 -0
- package/dist/mcps/knowledge-skills/code-analyzer.server.js +605 -0
- package/dist/mcps/knowledge-skills/code-review.server.js +847 -0
- package/dist/mcps/knowledge-skills/content-creator.server.js +256 -0
- package/dist/mcps/knowledge-skills/database-design.server.js +822 -0
- package/dist/mcps/knowledge-skills/devops-deployment.server.js +1180 -0
- package/dist/mcps/knowledge-skills/git-workflow.server.js +115 -0
- package/dist/mcps/knowledge-skills/growth-strategist.server.js +361 -0
- package/dist/mcps/knowledge-skills/log-monitor.server.js +451 -0
- package/dist/mcps/knowledge-skills/mobile-development.server.js +525 -0
- package/dist/mcps/knowledge-skills/multimodal-looker.server.js +1063 -0
- package/dist/mcps/knowledge-skills/performance-optimization.server.js +1587 -0
- package/dist/mcps/knowledge-skills/project-analysis.server.js +811 -0
- package/dist/mcps/knowledge-skills/refactoring-strategies.server.js +796 -0
- package/dist/mcps/knowledge-skills/security-audit.server.js +846 -0
- package/dist/mcps/knowledge-skills/seo-consultant.server.js +937 -0
- package/dist/mcps/knowledge-skills/session-management.server.js +470 -0
- package/dist/mcps/knowledge-skills/skill-invocation.server.js +729 -0
- package/dist/mcps/knowledge-skills/strategist.server.js +217 -0
- package/dist/mcps/knowledge-skills/tech-writer.server.js +1191 -0
- package/dist/mcps/knowledge-skills/testing-best-practices.server.js +866 -0
- package/dist/mcps/knowledge-skills/testing-strategy.server.js +827 -0
- package/dist/mcps/knowledge-skills/ui-ux-design.server.js +1538 -0
- package/dist/mcps/lint.server.js +381 -0
- package/dist/mcps/mcp-client.js +574 -0
- package/dist/mcps/model-health-check.server.js +228 -0
- package/dist/mcps/orchestrator/config/agent-capabilities.js +87 -0
- package/dist/mcps/orchestrator/execution/execution-planner.js +279 -0
- package/dist/mcps/orchestrator/handlers/complexity-handler.js +94 -0
- package/dist/mcps/orchestrator/handlers/status-handler.js +232 -0
- package/dist/mcps/orchestrator/handlers/task-handler.js +197 -0
- package/dist/mcps/orchestrator/server.js +305 -0
- package/dist/mcps/orchestrator/types.js +6 -0
- package/dist/mcps/orchestrator.server.js +19 -0
- package/dist/mcps/performance-analysis.server.js +519 -0
- package/dist/mcps/processor-pipeline.server.js +561 -0
- package/dist/mcps/protocol/protocol-constants.js +46 -0
- package/dist/mcps/registry.json +110 -0
- package/dist/mcps/researcher.server.js +504 -0
- package/dist/mcps/security-scan.server.js +531 -0
- package/dist/mcps/simulation/index.js +12 -0
- package/dist/mcps/simulation/server-simulations.js +219 -0
- package/dist/mcps/simulation/simulation-engine.js +96 -0
- package/dist/mcps/state-manager.server.js +637 -0
- package/dist/mcps/tools/index.js +14 -0
- package/dist/mcps/tools/tool-cache.js +112 -0
- package/dist/mcps/tools/tool-discovery.js +65 -0
- package/dist/mcps/tools/tool-executor.js +75 -0
- package/dist/mcps/tools/tool-registry.js +67 -0
- package/dist/mcps/types/index.js +15 -0
- package/dist/mcps/types/json-rpc.types.js +7 -0
- package/dist/mcps/types/mcp.types.js +7 -0
- package/dist/metrics/agent-metrics.js +574 -0
- package/dist/metrics/index.js +6 -0
- package/dist/monitoring/advanced-profiler.js +232 -0
- package/dist/monitoring/memory-monitor.js +315 -0
- package/dist/monitoring/nudge-watchdog.js +356 -0
- package/dist/monitoring/test-auto-generation-monitor.js +157 -0
- package/dist/orchestrator/agent-spawn-governor.js +559 -0
- package/dist/orchestrator/enhanced-multi-agent-orchestrator.js +399 -0
- package/dist/orchestrator/intelligent-commit-batcher.js +353 -0
- package/dist/orchestrator/multi-agent-orchestration-coordinator.js +456 -0
- package/dist/orchestrator/orchestrator.js +657 -0
- package/dist/orchestrator/self-direction-activation.js +245 -0
- package/dist/orchestrator/universal-librarian-consultation.js +216 -0
- package/dist/orchestrator/universal-registry-bridge.js +247 -0
- package/dist/performance/performance-budget-enforcer.js +434 -0
- package/dist/performance/performance-regression-tester.js +342 -0
- package/dist/plugin/xray-codex-injection.js +857 -0
- package/dist/postprocessor/PostProcessor.js +1048 -0
- package/dist/postprocessor/analysis/FailureAnalysisEngine.js +245 -0
- package/dist/postprocessor/autofix/AutoFixEngine.js +254 -0
- package/dist/postprocessor/autofix/FixValidator.js +56 -0
- package/dist/postprocessor/config.js +65 -0
- package/dist/postprocessor/escalation/EscalationEngine.js +492 -0
- package/dist/postprocessor/monitoring/MonitoringEngine.js +125 -0
- package/dist/postprocessor/redeploy/RedeployCoordinator.js +342 -0
- package/dist/postprocessor/services/RegressionAnalysisService.js +131 -0
- package/dist/postprocessor/success/SuccessHandler.js +134 -0
- package/dist/postprocessor/triggers/APITrigger.js +115 -0
- package/dist/postprocessor/triggers/GitHookTrigger.js +551 -0
- package/dist/postprocessor/triggers/WebhookTrigger.js +211 -0
- package/dist/postprocessor/types.js +4 -0
- package/dist/processors/doc-write-guard.js +46 -0
- package/dist/processors/implementations/agents-md-validation-processor.js +286 -0
- package/dist/processors/implementations/async-pattern-processor.js +158 -0
- package/dist/processors/implementations/codex-compliance-processor.js +57 -0
- package/dist/processors/implementations/commit-batcher-processor.js +71 -0
- package/dist/processors/implementations/console-log-guard-processor.js +163 -0
- package/dist/processors/implementations/coverage-analysis-processor.js +138 -0
- package/dist/processors/implementations/error-boundary-processor.js +44 -0
- package/dist/processors/implementations/inference-improvement-processor.js +270 -0
- package/dist/processors/implementations/log-protection-processor.js +118 -0
- package/dist/processors/implementations/nudge-processor.js +130 -0
- package/dist/processors/implementations/performance-budget-processor.js +217 -0
- package/dist/processors/implementations/postprocessor-chain-validator.js +149 -0
- package/dist/processors/implementations/pre-validate-processor.js +18 -0
- package/dist/processors/implementations/publish-preflight-processor.js +249 -0
- package/dist/processors/implementations/refactoring-logging-processor-wrapper.js +33 -0
- package/dist/processors/implementations/refactoring-logging-processor.js +96 -0
- package/dist/processors/implementations/regression-testing-processor.js +59 -0
- package/dist/processors/implementations/session-capture-processor.js +37 -0
- package/dist/processors/implementations/session-summary-processor.js +130 -0
- package/dist/processors/implementations/spawn-governance-processor.js +219 -0
- package/dist/processors/implementations/state-validation-processor.js +15 -0
- package/dist/processors/implementations/storytelling-trigger-processor.js +589 -0
- package/dist/processors/implementations/test-auto-creation-processor.js +484 -0
- package/dist/processors/implementations/test-execution-processor.js +132 -0
- package/dist/processors/implementations/typescript-compilation-processor.js +87 -0
- package/dist/processors/implementations/version-compliance-processor.js +350 -0
- package/dist/processors/processor-interfaces.js +126 -0
- package/dist/processors/processor-manager.js +826 -0
- package/dist/processors/processor-types.js +12 -0
- package/dist/public/about.html +228 -0
- package/dist/public/enterprise.html +27 -0
- package/dist/public/features.html +102 -0
- package/dist/public/index.html +145 -0
- package/dist/reporting/framework-reporting-system.js +187 -0
- package/dist/reporting/log-parser.js +281 -0
- package/dist/reporting/metrics.js +202 -0
- package/dist/reporting/report-formatter.js +146 -0
- package/dist/reporting/types.js +1 -0
- package/dist/scripts/activate-kernel-pipeline.js +101 -0
- package/dist/scripts/integration.js +234 -0
- package/dist/scripts/pre-command +26 -0
- package/dist/scripts/pre-command.mjs +358 -0
- package/dist/security/comprehensive-security-audit.js +1005 -0
- package/dist/security/index.js +13 -0
- package/dist/security/prompt-security-validator.js +148 -0
- package/dist/security/security-agent-coordinator.js +204 -0
- package/dist/security/security-auditor.js +584 -0
- package/dist/security/security-hardener.js +170 -0
- package/dist/security/security-hardening-system.js +727 -0
- package/dist/security/security-headers.js +118 -0
- package/dist/security/security-orchestration-layer.js +496 -0
- package/dist/security/security-scanner.js +429 -0
- package/dist/services/inference-tuner.js +301 -0
- package/dist/session/index.js +3 -0
- package/dist/session/session-cleanup-manager.js +366 -0
- package/dist/session/session-monitor.js +503 -0
- package/dist/session/session-state-manager.js +522 -0
- package/dist/skills/api-design/SKILL.md +37 -0
- package/dist/skills/architect-tools/SKILL.md +37 -0
- package/dist/skills/architecture-patterns/SKILL.md +37 -0
- package/dist/skills/auto-format/SKILL.md +37 -0
- package/dist/skills/backend-engineer/SKILL.md +49 -0
- package/dist/skills/boot-orchestrator/SKILL.md +37 -0
- package/dist/skills/bug-triage/SKILL.md +43 -0
- package/dist/skills/code-analyzer/SKILL.md +45 -0
- package/dist/skills/code-review/SKILL.md +52 -0
- package/dist/skills/content-creator/SKILL.md +38 -0
- package/dist/skills/database-engineer/SKILL.md +46 -0
- package/dist/skills/devops-engineer/SKILL.md +49 -0
- package/dist/skills/enforcer/SKILL.md +37 -0
- package/dist/skills/framework-compliance-audit/SKILL.md +37 -0
- package/dist/skills/frontend-engineer/SKILL.md +49 -0
- package/dist/skills/frontend-ui-ux-engineer/SKILL.md +41 -0
- package/dist/skills/git-workflow/SKILL.md +37 -0
- package/dist/skills/growth-strategist/SKILL.md +48 -0
- package/dist/skills/hermes-agent/SKILL.md +212 -0
- package/dist/skills/inference-improve/SKILL.md +97 -0
- package/dist/skills/lint/SKILL.md +37 -0
- package/dist/skills/log-monitor/SKILL.md +44 -0
- package/dist/skills/mobile-developer/SKILL.md +42 -0
- package/dist/skills/model-health-check/SKILL.md +37 -0
- package/dist/skills/multimodal-looker/SKILL.md +45 -0
- package/dist/skills/orchestrator/SKILL.md +37 -0
- package/dist/skills/performance-analysis/SKILL.md +37 -0
- package/dist/skills/performance-engineer/SKILL.md +41 -0
- package/dist/skills/performance-optimization/SKILL.md +37 -0
- package/dist/skills/processor-pipeline/SKILL.md +37 -0
- package/dist/skills/project-analysis/SKILL.md +42 -0
- package/dist/skills/refactoring-strategies/SKILL.md +37 -0
- package/dist/skills/registry.json +66 -0
- package/dist/skills/researcher/SKILL.md +37 -0
- package/dist/skills/security-audit/SKILL.md +48 -0
- package/dist/skills/security-scan/SKILL.md +37 -0
- package/dist/skills/seo-consultant/SKILL.md +43 -0
- package/dist/skills/session-management/SKILL.md +36 -0
- package/dist/skills/state-manager/SKILL.md +37 -0
- package/dist/skills/storyteller/SKILL.md +130 -0
- package/dist/skills/strategist/SKILL.md +32 -0
- package/dist/skills/tech-writer/SKILL.md +37 -0
- package/dist/skills/testing-best-practices/SKILL.md +37 -0
- package/dist/skills/testing-strategy/SKILL.md +43 -0
- package/dist/skills/ui-ux-design/SKILL.md +603 -0
- package/dist/state/context-providers.js +1 -0
- package/dist/state/index.js +7 -0
- package/dist/state/state-manager.js +208 -0
- package/dist/state/state-types.js +1 -0
- package/dist/testing/memory-regression-suite.js +258 -0
- package/dist/utils/batch-operations.js +292 -0
- package/dist/utils/codex-parser.js +445 -0
- package/dist/utils/command-runner.js +96 -0
- package/dist/utils/import-resolver.js +189 -0
- package/dist/utils/language-detector.js +383 -0
- package/dist/utils/path-resolver.js +112 -0
- package/dist/utils/shutdown-handler.js +75 -0
- package/dist/utils/test-template-generator.js +178 -0
- package/dist/utils/token-manager.js +163 -0
- package/dist/validation/estimation-validator.js +241 -0
- package/dist/validation/report-content-validator.js +218 -0
- package/opencode.json +153 -0
- package/package.json +170 -0
- package/scripts/helpers/resolve-config-path.cjs +57 -0
- package/scripts/helpers/resolve-config-path.mjs +73 -0
- package/scripts/hooks/pre-command +26 -0
- package/scripts/hooks/pre-command.mjs +358 -0
- package/scripts/hooks/run-hook.js +570 -0
- package/scripts/mjs/test-consumer-readiness.mjs +273 -0
- package/scripts/mjs/test-mcp-functionality.mjs +507 -0
- package/scripts/mjs/validate-mcp-connectivity.cjs +75 -0
- package/scripts/mjs/validate-postinstall-config.mjs +308 -0
- package/scripts/node/auto-reflection-generator.mjs +496 -0
- package/scripts/node/basic-security-audit.cjs +338 -0
- package/scripts/node/ci-cd-auto-fix.cjs +263 -0
- package/scripts/node/ci-report-generator.mjs +227 -0
- package/scripts/node/enforce-agents-md.mjs +420 -0
- package/scripts/node/enforce-version-compliance.sh +22 -0
- package/scripts/node/enforce-version-compliance.ts +126 -0
- package/scripts/node/github-actions-monitor.cjs +23 -0
- package/scripts/node/govern-reflection.mjs +160 -0
- package/scripts/node/postinstall.cjs +78 -0
- package/scripts/node/pre-publish-guard.js +267 -0
- package/scripts/node/prepare-consumer.cjs +143 -0
- package/scripts/node/reflection-processor.cjs +213 -0
- package/scripts/node/reflection-validate.sh +194 -0
- package/scripts/node/release-tweet.mjs +39 -0
- package/scripts/node/release.js +159 -0
- package/scripts/node/release.mjs +213 -0
- package/scripts/node/setup-dev.cjs +83 -0
- package/scripts/node/setup.cjs +214 -0
- package/scripts/node/sync-versions.mjs +140 -0
- package/scripts/node/universal-version-manager.js +1025 -0
- package/scripts/node/validate-external-processes.js +265 -0
- package/scripts/node/validate-mcp-connectivity.js +258 -0
- package/scripts/node/version-manager.mjs +524 -0
- package/scripts/validate-stringray-comprehensive.js +636 -0
- package/src/integrations/grok/plugin/0xray/.mcp.json +15 -0
- package/src/integrations/grok/plugin/0xray/hooks/hooks.json +30 -0
- package/src/mcps/agent-resolver.ts +168 -0
- package/src/mcps/architect-tools.server.ts +343 -0
- package/src/mcps/auto-format.server.ts +529 -0
- package/src/mcps/boot-orchestrator.server.ts +1082 -0
- package/src/mcps/config/__tests__/config-loader.test.ts +338 -0
- package/src/mcps/config/__tests__/config-validator.test.ts +646 -0
- package/src/mcps/config/__tests__/server-config-registry.test.ts +257 -0
- package/src/mcps/config/config-loader.ts +127 -0
- package/src/mcps/config/config-validator.ts +127 -0
- package/src/mcps/config/index.ts +32 -0
- package/src/mcps/config/plugin-server-registry.ts +335 -0
- package/src/mcps/config/server-config-registry.ts +395 -0
- package/src/mcps/connection/connection-manager.ts +91 -0
- package/src/mcps/connection/connection-pool.ts +216 -0
- package/src/mcps/connection/mcp-connection.ts +327 -0
- package/src/mcps/connection/process-spawner.ts +47 -0
- package/src/mcps/enforcer-tools.server.ts +1106 -0
- package/src/mcps/estimation.server.ts +229 -0
- package/src/mcps/framework-compliance-audit.server.ts +635 -0
- package/src/mcps/framework-help.server.ts +467 -0
- package/src/mcps/governance.server.ts +551 -0
- package/src/mcps/in-process-skill-registry.ts +79 -0
- package/src/mcps/knowledge-skills/api-design.server.test.ts +41 -0
- package/src/mcps/knowledge-skills/api-design.server.ts +160 -0
- package/src/mcps/knowledge-skills/architecture-patterns.server.ts +152 -0
- package/src/mcps/knowledge-skills/bug-triage-specialist.server.ts +624 -0
- package/src/mcps/knowledge-skills/code-analyzer.server.test.ts +129 -0
- package/src/mcps/knowledge-skills/code-analyzer.server.ts +591 -0
- package/src/mcps/knowledge-skills/code-review.server.ts +1132 -0
- package/src/mcps/knowledge-skills/content-creator.server.ts +300 -0
- package/src/mcps/knowledge-skills/database-design.server.ts +1200 -0
- package/src/mcps/knowledge-skills/devops-deployment.server.ts +1622 -0
- package/src/mcps/knowledge-skills/git-workflow.server.ts +152 -0
- package/src/mcps/knowledge-skills/growth-strategist.server.ts +413 -0
- package/src/mcps/knowledge-skills/log-monitor.server.ts +619 -0
- package/src/mcps/knowledge-skills/mobile-development.server.ts +672 -0
- package/src/mcps/knowledge-skills/multimodal-looker.server.ts +1500 -0
- package/src/mcps/knowledge-skills/performance-optimization.server.ts +2065 -0
- package/src/mcps/knowledge-skills/project-analysis.server.ts +1111 -0
- package/src/mcps/knowledge-skills/refactoring-strategies.server.ts +1092 -0
- package/src/mcps/knowledge-skills/security-audit.server.test.ts +112 -0
- package/src/mcps/knowledge-skills/security-audit.server.ts +1193 -0
- package/src/mcps/knowledge-skills/seo-consultant.server.ts +1160 -0
- package/src/mcps/knowledge-skills/session-management.server.ts +576 -0
- package/src/mcps/knowledge-skills/skill-invocation.server.ts +941 -0
- package/src/mcps/knowledge-skills/strategist.server.ts +267 -0
- package/src/mcps/knowledge-skills/tech-writer.server.ts +1638 -0
- package/src/mcps/knowledge-skills/testing-best-practices.server.test.ts +136 -0
- package/src/mcps/knowledge-skills/testing-best-practices.server.ts +1232 -0
- package/src/mcps/knowledge-skills/testing-strategy.server.test.ts +100 -0
- package/src/mcps/knowledge-skills/testing-strategy.server.ts +1172 -0
- package/src/mcps/knowledge-skills/ui-ux-design.server.ts +2076 -0
- package/src/mcps/lint.server.ts +483 -0
- package/src/mcps/mcp-client.ts +706 -0
- package/src/mcps/model-health-check.server.ts +292 -0
- package/src/mcps/orchestrator/config/agent-capabilities.ts +108 -0
- package/src/mcps/orchestrator/execution/execution-planner.ts +353 -0
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +125 -0
- package/src/mcps/orchestrator/handlers/status-handler.ts +295 -0
- package/src/mcps/orchestrator/handlers/task-handler.ts +268 -0
- package/src/mcps/orchestrator/server.ts +388 -0
- package/src/mcps/orchestrator/types.ts +81 -0
- package/src/mcps/orchestrator.server.ts +34 -0
- package/src/mcps/performance-analysis.server.ts +715 -0
- package/src/mcps/processor-pipeline.server.ts +778 -0
- package/src/mcps/protocol/protocol-constants.ts +51 -0
- package/src/mcps/registry.json +110 -0
- package/src/mcps/researcher.server.ts +595 -0
- package/src/mcps/security-scan.server.ts +651 -0
- package/src/mcps/simulation/__tests__/simulation-engine.test.ts +275 -0
- package/src/mcps/simulation/index.ts +23 -0
- package/src/mcps/simulation/server-simulations.ts +241 -0
- package/src/mcps/simulation/simulation-engine.ts +126 -0
- package/src/mcps/state-manager.server.ts +777 -0
- package/src/mcps/tools/__tests__/tool-cache.test.ts +205 -0
- package/src/mcps/tools/__tests__/tool-discovery.test.ts +189 -0
- package/src/mcps/tools/__tests__/tool-executor.test.ts +215 -0
- package/src/mcps/tools/__tests__/tool-registry.test.ts +230 -0
- package/src/mcps/tools/index.ts +15 -0
- package/src/mcps/tools/tool-cache.ts +145 -0
- package/src/mcps/tools/tool-discovery.ts +83 -0
- package/src/mcps/tools/tool-executor.ts +106 -0
- package/src/mcps/tools/tool-registry.ts +78 -0
- package/src/mcps/types/__tests__/types.test.ts +341 -0
- package/src/mcps/types/index.ts +17 -0
- package/src/mcps/types/json-rpc.types.ts +38 -0
- package/src/mcps/types/mcp.types.ts +115 -0
- package/src/opencode/agents/api-design.yml +31 -0
- package/src/opencode/agents/architect.yml +15 -0
- package/src/opencode/agents/architecture-patterns.yml +14 -0
- package/src/opencode/agents/auto-format.yml +14 -0
- package/src/opencode/agents/backend-engineer.yml +12 -0
- package/src/opencode/agents/boot-orchestrator.yml +14 -0
- package/src/opencode/agents/bug-triage-specialist.yml +15 -0
- package/src/opencode/agents/code-analyzer.yml +12 -0
- package/src/opencode/agents/code-reviewer.yml +14 -0
- package/src/opencode/agents/content-creator.yml +12 -0
- package/src/opencode/agents/database-engineer.yml +12 -0
- package/src/opencode/agents/devops-engineer.yml +12 -0
- package/src/opencode/agents/framework-compliance-audit.yml +14 -0
- package/src/opencode/agents/frontend-engineer.yml +12 -0
- package/src/opencode/agents/frontend-ui-ux-engineer.yml +12 -0
- package/src/opencode/agents/git-workflow.yml +15 -0
- package/src/opencode/agents/growth-strategist.yml +12 -0
- package/src/opencode/agents/hermes-agent.yml +12 -0
- package/src/opencode/agents/inference-improve.yml +12 -0
- package/src/opencode/agents/lint.yml +14 -0
- package/src/opencode/agents/log-monitor.yml +12 -0
- package/src/opencode/agents/mobile-developer.yml +12 -0
- package/src/opencode/agents/model-health-check.yml +12 -0
- package/src/opencode/agents/multimodal-looker.yml +12 -0
- package/src/opencode/agents/performance-analysis.yml +12 -0
- package/src/opencode/agents/performance-engineer.yml +12 -0
- package/src/opencode/agents/performance-optimization.yml +12 -0
- package/src/opencode/agents/processor-pipeline.yml +14 -0
- package/src/opencode/agents/project-analysis.yml +12 -0
- package/src/opencode/agents/refactorer.yml +12 -0
- package/src/opencode/agents/researcher.yml +12 -0
- package/src/opencode/agents/security-auditor.yml +12 -0
- package/src/opencode/agents/security-scan.yml +12 -0
- package/src/opencode/agents/seo-consultant.yml +12 -0
- package/src/opencode/agents/session-management.yml +12 -0
- package/src/opencode/agents/state-manager.yml +12 -0
- package/src/opencode/agents/storyteller.yml +12 -0
- package/src/opencode/agents/strategist.yml +12 -0
- package/src/opencode/agents/tech-writer.yml +12 -0
- package/src/opencode/agents/testing-best-practices.yml +12 -0
- package/src/opencode/agents/testing-lead.yml +12 -0
- package/src/opencode/agents/ui-ux-design.yml +12 -0
- package/src/opencode/codex.codex +8 -0
- package/src/opencode/commands/auto-format.md +99 -0
- package/src/opencode/commands/auto-summary-capture.md +90 -0
- package/src/opencode/commands/dependency-audit.md +184 -0
- package/src/opencode/commands/enforcer-daily-scan.md +137 -0
- package/src/opencode/commands/framework-compliance-audit.md +205 -0
- package/src/opencode/commands/interactive-validator.md +75 -0
- package/src/opencode/commands/job-summary-logger.md +68 -0
- package/src/opencode/commands/lint.md +11 -0
- package/src/opencode/commands/mode-switch.md +95 -0
- package/src/opencode/commands/model-health-check.md +186 -0
- package/src/opencode/commands/performance-analysis.md +144 -0
- package/src/opencode/commands/pre-commit-introspection.md +185 -0
- package/src/opencode/commands/pre-commit-introspection.sh +133 -0
- package/src/opencode/commands/security-scan.md +157 -0
- package/src/opencode/commands/sisyphus-validation.md +128 -0
- package/src/opencode/commands/summary-logger.md +83 -0
- package/src/opencode/enforcer-config.json +285 -0
- package/src/opencode/openclaw/config.json +25 -0
- package/src/opencode/workflows/post-deployment-audit.yml +123 -0
- package/src/skills/api-design/SKILL.md +37 -0
- package/src/skills/architect-tools/SKILL.md +37 -0
- package/src/skills/architecture-patterns/SKILL.md +37 -0
- package/src/skills/auto-format/SKILL.md +37 -0
- package/src/skills/backend-engineer/SKILL.md +49 -0
- package/src/skills/boot-orchestrator/SKILL.md +37 -0
- package/src/skills/bug-triage/SKILL.md +43 -0
- package/src/skills/code-analyzer/SKILL.md +45 -0
- package/src/skills/code-review/SKILL.md +52 -0
- package/src/skills/content-creator/SKILL.md +38 -0
- package/src/skills/database-engineer/SKILL.md +46 -0
- package/src/skills/devops-engineer/SKILL.md +49 -0
- package/src/skills/enforcer/SKILL.md +37 -0
- package/src/skills/framework-compliance-audit/SKILL.md +37 -0
- package/src/skills/frontend-engineer/SKILL.md +49 -0
- package/src/skills/frontend-ui-ux-engineer/SKILL.md +41 -0
- package/src/skills/git-workflow/SKILL.md +37 -0
- package/src/skills/growth-strategist/SKILL.md +48 -0
- package/src/skills/hermes-agent/SKILL.md +212 -0
- package/src/skills/inference-improve/SKILL.md +97 -0
- package/src/skills/lint/SKILL.md +37 -0
- package/src/skills/log-monitor/SKILL.md +44 -0
- package/src/skills/mobile-developer/SKILL.md +42 -0
- package/src/skills/model-health-check/SKILL.md +37 -0
- package/src/skills/multimodal-looker/SKILL.md +45 -0
- package/src/skills/orchestrator/SKILL.md +37 -0
- package/src/skills/performance-analysis/SKILL.md +37 -0
- package/src/skills/performance-engineer/SKILL.md +41 -0
- package/src/skills/performance-optimization/SKILL.md +37 -0
- package/src/skills/processor-pipeline/SKILL.md +37 -0
- package/src/skills/project-analysis/SKILL.md +42 -0
- package/src/skills/refactoring-strategies/SKILL.md +37 -0
- package/src/skills/registry.json +66 -0
- package/src/skills/researcher/SKILL.md +37 -0
- package/src/skills/security-audit/SKILL.md +48 -0
- package/src/skills/security-scan/SKILL.md +37 -0
- package/src/skills/seo-consultant/SKILL.md +43 -0
- package/src/skills/session-management/SKILL.md +36 -0
- package/src/skills/state-manager/SKILL.md +37 -0
- package/src/skills/storyteller/SKILL.md +130 -0
- package/src/skills/strategist/SKILL.md +32 -0
- package/src/skills/tech-writer/SKILL.md +37 -0
- package/src/skills/testing-best-practices/SKILL.md +37 -0
- package/src/skills/testing-strategy/SKILL.md +43 -0
- package/src/skills/ui-ux-design/SKILL.md +603 -0
|
@@ -0,0 +1,1587 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xray Performance Optimization MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Knowledge skill for performance analysis, optimization recommendations,
|
|
5
|
+
* profiling, benchmarking, memory analysis, and Core Web Vitals measurement
|
|
6
|
+
*/
|
|
7
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
10
|
+
import { frameworkLogger, generateJobId } from "../../core/framework-logger.js";
|
|
11
|
+
import { createGracefulShutdown } from "../../utils/shutdown-handler.js";
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import path from "path";
|
|
14
|
+
class StringRayPerformanceOptimizationServer {
|
|
15
|
+
server;
|
|
16
|
+
startTime;
|
|
17
|
+
constructor() {
|
|
18
|
+
this.server = new Server({
|
|
19
|
+
name: "performance-optimization", version: "1.22.67",
|
|
20
|
+
}, {
|
|
21
|
+
capabilities: {
|
|
22
|
+
tools: {},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
this.startTime = Date.now();
|
|
26
|
+
this.setupToolHandlers();
|
|
27
|
+
}
|
|
28
|
+
setupToolHandlers() {
|
|
29
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
30
|
+
return {
|
|
31
|
+
tools: [
|
|
32
|
+
{
|
|
33
|
+
name: "profile-application",
|
|
34
|
+
description: "Run comprehensive performance profiling on the codebase to identify bottlenecks and hot paths",
|
|
35
|
+
inputSchema: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
projectRoot: { type: "string", description: "Path to the project root directory" },
|
|
39
|
+
scope: {
|
|
40
|
+
type: "string",
|
|
41
|
+
enum: ["full", "runtime", "build", "memory"],
|
|
42
|
+
default: "full",
|
|
43
|
+
description: "Scope of profiling analysis"
|
|
44
|
+
},
|
|
45
|
+
duration: { type: "number", default: 30, description: "Profiling duration in seconds" },
|
|
46
|
+
includeHotPaths: { type: "boolean", default: true, description: "Include hot path analysis" }
|
|
47
|
+
},
|
|
48
|
+
required: ["projectRoot"]
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "analyze-memory",
|
|
53
|
+
description: "Perform memory leak detection and heap analysis to identify memory issues",
|
|
54
|
+
inputSchema: {
|
|
55
|
+
type: "object",
|
|
56
|
+
properties: {
|
|
57
|
+
projectRoot: { type: "string", description: "Path to the project root directory" },
|
|
58
|
+
heapSnapshot: { type: "boolean", default: true, description: "Generate heap snapshot analysis" },
|
|
59
|
+
gcAnalysis: { type: "boolean", default: true, description: "Analyze garbage collection patterns" },
|
|
60
|
+
leakDetection: { type: "boolean", default: true, description: "Detect potential memory leaks" }
|
|
61
|
+
},
|
|
62
|
+
required: ["projectRoot"]
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "benchmark-code",
|
|
67
|
+
description: "Execute and compare benchmark results for code performance measurement",
|
|
68
|
+
inputSchema: {
|
|
69
|
+
type: "object",
|
|
70
|
+
properties: {
|
|
71
|
+
projectRoot: { type: "string", description: "Path to the project root directory" },
|
|
72
|
+
testFile: { type: "string", description: "Specific benchmark test file to run" },
|
|
73
|
+
iterations: { type: "number", default: 100, description: "Number of benchmark iterations" },
|
|
74
|
+
warmupRuns: { type: "number", default: 10, description: "Number of warmup runs" },
|
|
75
|
+
compareBaseline: { type: "boolean", default: false, description: "Compare results against baseline" }
|
|
76
|
+
},
|
|
77
|
+
required: ["projectRoot"]
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "suggest-optimizations",
|
|
82
|
+
description: "Generate specific, actionable optimization suggestions based on code analysis",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
projectRoot: { type: "string", description: "Path to the project root directory" },
|
|
87
|
+
focus: {
|
|
88
|
+
type: "string",
|
|
89
|
+
enum: ["cpu", "memory", "network", "io", "all"],
|
|
90
|
+
default: "all",
|
|
91
|
+
description: "Focus area for optimizations"
|
|
92
|
+
},
|
|
93
|
+
threshold: { type: "number", default: 100, description: "Performance threshold in ms" }
|
|
94
|
+
},
|
|
95
|
+
required: ["projectRoot"]
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "measure-core-web-vitals",
|
|
100
|
+
description: "Analyze Core Web Vitals metrics (LCP, INP, CLS) for web application performance",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: "object",
|
|
103
|
+
properties: {
|
|
104
|
+
projectRoot: { type: "string", description: "Path to the project root directory" },
|
|
105
|
+
analyzeBundle: { type: "boolean", default: true, description: "Analyze JavaScript bundle" },
|
|
106
|
+
checkAccessibility: { type: "boolean", default: true, description: "Check accessibility factors affecting CLS" },
|
|
107
|
+
measureLCP: { type: "boolean", default: true, description: "Measure Largest Contentful Paint" },
|
|
108
|
+
measureINP: { type: "boolean", default: true, description: "Measure Interaction to Next Paint" },
|
|
109
|
+
measureCLS: { type: "boolean", default: true, description: "Measure Cumulative Layout Shift" }
|
|
110
|
+
},
|
|
111
|
+
required: ["projectRoot"]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
118
|
+
const { name, arguments: args } = request.params;
|
|
119
|
+
try {
|
|
120
|
+
switch (name) {
|
|
121
|
+
case "profile-application":
|
|
122
|
+
return await this.handleProfileApplication(args);
|
|
123
|
+
case "analyze-memory":
|
|
124
|
+
return await this.handleAnalyzeMemory(args);
|
|
125
|
+
case "benchmark-code":
|
|
126
|
+
return await this.handleBenchmarkCode(args);
|
|
127
|
+
case "suggest-optimizations":
|
|
128
|
+
return await this.handleSuggestOptimizations(args);
|
|
129
|
+
case "measure-core-web-vitals":
|
|
130
|
+
return await this.handleMeasureCoreWebVitals(args);
|
|
131
|
+
default:
|
|
132
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
frameworkLogger.log("mcp/performance-optimization", "tool-handler", "error", { tool: name, error: String(error) });
|
|
137
|
+
return {
|
|
138
|
+
content: [{
|
|
139
|
+
type: "text",
|
|
140
|
+
text: `Error executing tool "${name}": ${error instanceof Error ? error.message : String(error)}`
|
|
141
|
+
}]
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
async handleProfileApplication(args) {
|
|
147
|
+
const { projectRoot, scope = "full", duration = 30, includeHotPaths = true } = args;
|
|
148
|
+
const jobId = generateJobId("mcp-perf-profiling");
|
|
149
|
+
await frameworkLogger.log("mcp/performance-optimization", "profiling-started", "info", { projectRoot, scope }, undefined, jobId);
|
|
150
|
+
try {
|
|
151
|
+
const result = await this.performProfiling(projectRoot, scope, duration, includeHotPaths);
|
|
152
|
+
const responseText = this.formatProfilingResult(result);
|
|
153
|
+
return {
|
|
154
|
+
content: [{ type: "text", text: responseText }],
|
|
155
|
+
data: result
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
return {
|
|
160
|
+
content: [{
|
|
161
|
+
type: "text",
|
|
162
|
+
text: `Profiling failed: ${error instanceof Error ? error.message : String(error)}`
|
|
163
|
+
}]
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async performProfiling(projectRoot, scope, duration, includeHotPaths) {
|
|
168
|
+
const result = {
|
|
169
|
+
hotPaths: [],
|
|
170
|
+
functionCallCounts: {},
|
|
171
|
+
memoryFootprint: 0,
|
|
172
|
+
bottlenecks: [],
|
|
173
|
+
recommendations: [],
|
|
174
|
+
cpuProfile: {},
|
|
175
|
+
metrics: {
|
|
176
|
+
totalFunctions: 0,
|
|
177
|
+
hotFunctions: 0,
|
|
178
|
+
avgExecutionTime: 0,
|
|
179
|
+
peakMemory: 0,
|
|
180
|
+
gcPauses: 0
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const memUsage = process.memoryUsage();
|
|
184
|
+
result.memoryFootprint = Math.round(memUsage.heapUsed / 1024 / 1024);
|
|
185
|
+
if (fs.existsSync(path.join(projectRoot, "src"))) {
|
|
186
|
+
const codeFiles = this.findCodeFiles(projectRoot);
|
|
187
|
+
const analysis = this.analyzeCodeForPerformance(codeFiles, scope);
|
|
188
|
+
result.hotPaths = analysis.hotPaths;
|
|
189
|
+
result.functionCallCounts = analysis.functionCounts;
|
|
190
|
+
result.bottlenecks = analysis.bottlenecks;
|
|
191
|
+
result.recommendations = analysis.recommendations;
|
|
192
|
+
result.metrics.totalFunctions = analysis.totalFunctions;
|
|
193
|
+
result.metrics.hotFunctions = analysis.hotFunctions;
|
|
194
|
+
result.metrics.avgExecutionTime = analysis.avgExecutionTime;
|
|
195
|
+
result.metrics.peakMemory = analysis.peakMemory;
|
|
196
|
+
result.metrics.gcPauses = analysis.gcPauses;
|
|
197
|
+
if (includeHotPaths) {
|
|
198
|
+
result.cpuProfile = {
|
|
199
|
+
topFunctions: this.getTopFunctions(analysis),
|
|
200
|
+
callGraph: this.generateCallGraph(analysis),
|
|
201
|
+
criticalPath: this.identifyCriticalPath(analysis)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
analyzeCodeForPerformance(files, scope) {
|
|
208
|
+
const hotPaths = [];
|
|
209
|
+
const functionCounts = {};
|
|
210
|
+
const bottlenecks = [];
|
|
211
|
+
const recommendations = [];
|
|
212
|
+
let totalFunctions = 0;
|
|
213
|
+
let hotFunctions = 0;
|
|
214
|
+
for (const file of files) {
|
|
215
|
+
try {
|
|
216
|
+
const content = fs.readFileSync(file, "utf8");
|
|
217
|
+
const analysis = this.analyzeFilePerformance(content, file, scope);
|
|
218
|
+
if (analysis.functions.length > 0) {
|
|
219
|
+
totalFunctions += analysis.functions.length;
|
|
220
|
+
hotFunctions += analysis.hotCount;
|
|
221
|
+
analysis.functions.forEach((fn) => {
|
|
222
|
+
functionCounts[`${file}:${fn.name}`] = fn.estimatedCalls;
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
hotPaths.push(...analysis.hotPaths);
|
|
226
|
+
bottlenecks.push(...analysis.bottlenecks);
|
|
227
|
+
recommendations.push(...analysis.recommendations);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// Skip files that can't be read
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const avgExecutionTime = this.calculateAverageExecutionTime(functionCounts);
|
|
234
|
+
return {
|
|
235
|
+
hotPaths: [...new Set(hotPaths)],
|
|
236
|
+
functionCounts,
|
|
237
|
+
bottlenecks: [...new Set(bottlenecks)],
|
|
238
|
+
recommendations: [...new Set(recommendations)],
|
|
239
|
+
totalFunctions,
|
|
240
|
+
hotFunctions,
|
|
241
|
+
avgExecutionTime,
|
|
242
|
+
peakMemory: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
|
|
243
|
+
gcPauses: this.estimateGCPauses()
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
analyzeFilePerformance(content, filePath, scope) {
|
|
247
|
+
const functions = [];
|
|
248
|
+
const hotPaths = [];
|
|
249
|
+
const bottlenecks = [];
|
|
250
|
+
const recommendations = [];
|
|
251
|
+
let hotCount = 0;
|
|
252
|
+
const functionRegex = /(?:function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\(|(\w+)\s*\([^)]*\)\s*\{)/g;
|
|
253
|
+
let match;
|
|
254
|
+
while ((match = functionRegex.exec(content)) !== null) {
|
|
255
|
+
const fnName = match[1] || match[2] || match[3];
|
|
256
|
+
if (fnName && !fnName.startsWith("_")) {
|
|
257
|
+
const estimatedCalls = this.estimateFunctionCalls(content, fnName);
|
|
258
|
+
functions.push({ name: fnName, estimatedCalls });
|
|
259
|
+
if (estimatedCalls > 1000) {
|
|
260
|
+
hotCount++;
|
|
261
|
+
hotPaths.push(`${filePath}:${fnName}`);
|
|
262
|
+
const complexity = this.calculateCyclomaticComplexity(content, fnName);
|
|
263
|
+
if (complexity > 15) {
|
|
264
|
+
bottlenecks.push(`High complexity function: ${fnName} (complexity: ${complexity})`);
|
|
265
|
+
recommendations.push(`Consider simplifying ${fnName} - complexity ${complexity} exceeds recommended threshold`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if (scope === "memory" || scope === "full") {
|
|
271
|
+
const closureMatches = content.match(/=>\s*\{[^}]*\}/g);
|
|
272
|
+
if (closureMatches && closureMatches.length > 10) {
|
|
273
|
+
recommendations.push(`${filePath}: High closure usage (${closureMatches.length}) may impact memory - consider refactoring`);
|
|
274
|
+
}
|
|
275
|
+
const nestedFuncMatches = content.match(/function\s+\w+[^}]*\{[^}]*function\s+/g);
|
|
276
|
+
if (nestedFuncMatches) {
|
|
277
|
+
bottlenecks.push(`${filePath}: Nested function detected - may cause memory leaks`);
|
|
278
|
+
recommendations.push(`Consider extracting nested functions in ${filePath}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return { functions, hotPaths, bottlenecks, recommendations, hotCount };
|
|
282
|
+
}
|
|
283
|
+
estimateFunctionCalls(content, fnName) {
|
|
284
|
+
const callRegex = new RegExp(`${fnName}\\s*\\(`, "g");
|
|
285
|
+
const calls = content.match(callRegex);
|
|
286
|
+
return calls ? calls.length : 0;
|
|
287
|
+
}
|
|
288
|
+
calculateCyclomaticComplexity(content, fnName) {
|
|
289
|
+
const fnStart = content.indexOf(`function ${fnName}`);
|
|
290
|
+
if (fnStart === -1)
|
|
291
|
+
return 1;
|
|
292
|
+
let braceCount = 0;
|
|
293
|
+
let complexity = 1;
|
|
294
|
+
let inFunction = false;
|
|
295
|
+
for (let i = fnStart; i < content.length && braceCount >= 0; i++) {
|
|
296
|
+
const char = content[i];
|
|
297
|
+
if (char === "{") {
|
|
298
|
+
braceCount++;
|
|
299
|
+
inFunction = true;
|
|
300
|
+
}
|
|
301
|
+
else if (char === "}") {
|
|
302
|
+
braceCount--;
|
|
303
|
+
}
|
|
304
|
+
if (inFunction && braceCount > 0) {
|
|
305
|
+
if (char === "\n" && (content[i + 1] === "if" || content[i + 1] === "else" || content[i + 1] === "for" || content[i + 1] === "while" || content[i + 1] === "case")) {
|
|
306
|
+
complexity++;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return complexity;
|
|
311
|
+
}
|
|
312
|
+
calculateAverageExecutionTime(functionCounts) {
|
|
313
|
+
const counts = Object.values(functionCounts);
|
|
314
|
+
if (counts.length === 0)
|
|
315
|
+
return 0;
|
|
316
|
+
const avg = counts.reduce((sum, c) => sum + c, 0) / counts.length;
|
|
317
|
+
return Math.round(avg * 0.1);
|
|
318
|
+
}
|
|
319
|
+
estimateGCPauses() {
|
|
320
|
+
const memUsage = process.memoryUsage();
|
|
321
|
+
const heapUsedMB = memUsage.heapUsed / 1024 / 1024;
|
|
322
|
+
if (heapUsedMB > 500)
|
|
323
|
+
return 15;
|
|
324
|
+
if (heapUsedMB > 200)
|
|
325
|
+
return 8;
|
|
326
|
+
if (heapUsedMB > 100)
|
|
327
|
+
return 4;
|
|
328
|
+
return 2;
|
|
329
|
+
}
|
|
330
|
+
getTopFunctions(analysis) {
|
|
331
|
+
return Object.entries(analysis.functionCounts)
|
|
332
|
+
.sort(([, a], [, b]) => b - a)
|
|
333
|
+
.slice(0, 10)
|
|
334
|
+
.map(([name, calls]) => ({ name, calls }));
|
|
335
|
+
}
|
|
336
|
+
generateCallGraph(analysis) {
|
|
337
|
+
const graph = {};
|
|
338
|
+
for (const [fullName] of Object.entries(analysis.functionCounts)) {
|
|
339
|
+
const parts = fullName.split(":");
|
|
340
|
+
const file = parts[0] ?? "unknown";
|
|
341
|
+
const fnName = parts[1] ?? fullName;
|
|
342
|
+
if (!graph[file])
|
|
343
|
+
graph[file] = [];
|
|
344
|
+
graph[file].push(fnName);
|
|
345
|
+
}
|
|
346
|
+
return graph;
|
|
347
|
+
}
|
|
348
|
+
identifyCriticalPath(analysis) {
|
|
349
|
+
return analysis.hotPaths.slice(0, 5);
|
|
350
|
+
}
|
|
351
|
+
formatProfilingResult(result) {
|
|
352
|
+
return `📊 Performance Profiling Results
|
|
353
|
+
|
|
354
|
+
**PROFILING METRICS**
|
|
355
|
+
- Total Functions Analyzed: ${result.metrics.totalFunctions}
|
|
356
|
+
- Hot Functions (>1000 calls): ${result.metrics.hotFunctions}
|
|
357
|
+
- Average Execution Time: ${result.metrics.avgExecutionTime}ms
|
|
358
|
+
- Peak Memory: ${result.metrics.peakMemory}MB
|
|
359
|
+
- GC Pauses: ${result.metrics.gcPauses}
|
|
360
|
+
|
|
361
|
+
**HOT PATHS** (${result.hotPaths.length} identified)
|
|
362
|
+
${result.hotPaths.slice(0, 10).map(p => `• 🔥 ${p}`).join("\n") || "None detected"}
|
|
363
|
+
|
|
364
|
+
**TOP FUNCTIONS BY CALL COUNT**
|
|
365
|
+
${Object.entries(result.functionCallCounts)
|
|
366
|
+
.sort(([, a], [, b]) => b - a)
|
|
367
|
+
.slice(0, 5)
|
|
368
|
+
.map(([name, count]) => `• ${name}: ${count.toLocaleString()} calls`)
|
|
369
|
+
.join("\n") || "None"}
|
|
370
|
+
|
|
371
|
+
**BOTTLENECKS** (${result.bottlenecks.length} detected)
|
|
372
|
+
${result.bottlenecks.slice(0, 5).map(b => `• 🚧 ${b}`).join("\n") || "None detected"}
|
|
373
|
+
|
|
374
|
+
**RECOMMENDATIONS**
|
|
375
|
+
${result.recommendations.slice(0, 5).map((r, i) => `${i + 1}. ${r}`).join("\n") || "No specific recommendations"}
|
|
376
|
+
|
|
377
|
+
**Status:** ${result.metrics.hotFunctions > 10 ? "❌ HIGH OPTIMIZATION NEEDED" : result.metrics.hotFunctions > 5 ? "⚠️ MODERATE OPTIMIZATION NEEDED" : "✅ PERFORMANCE ACCEPTABLE"}`;
|
|
378
|
+
}
|
|
379
|
+
async handleAnalyzeMemory(args) {
|
|
380
|
+
const { projectRoot, heapSnapshot = true, gcAnalysis = true, leakDetection = true } = args;
|
|
381
|
+
const jobId = generateJobId("mcp-perf-memory");
|
|
382
|
+
await frameworkLogger.log("mcp/performance-optimization", "memory-analysis-started", "info", { projectRoot }, undefined, jobId);
|
|
383
|
+
try {
|
|
384
|
+
const result = await this.performMemoryAnalysis(projectRoot, heapSnapshot, gcAnalysis, leakDetection);
|
|
385
|
+
const responseText = this.formatMemoryAnalysis(result);
|
|
386
|
+
return {
|
|
387
|
+
content: [{ type: "text", text: responseText }],
|
|
388
|
+
data: result
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
return {
|
|
393
|
+
content: [{
|
|
394
|
+
type: "text",
|
|
395
|
+
text: `Memory analysis failed: ${error instanceof Error ? error.message : String(error)}`
|
|
396
|
+
}]
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
async performMemoryAnalysis(projectRoot, heapSnapshot, gcAnalysis, leakDetection) {
|
|
401
|
+
const memUsage = process.memoryUsage();
|
|
402
|
+
const result = {
|
|
403
|
+
heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024),
|
|
404
|
+
heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024),
|
|
405
|
+
external: Math.round(memUsage.external / 1024 / 1024),
|
|
406
|
+
rss: Math.round(memUsage.rss / 1024 / 1024),
|
|
407
|
+
memoryLeaks: [],
|
|
408
|
+
gcEvents: [],
|
|
409
|
+
recommendations: [],
|
|
410
|
+
heapBreakdown: {
|
|
411
|
+
strings: 0,
|
|
412
|
+
arrays: 0,
|
|
413
|
+
objects: 0,
|
|
414
|
+
functions: 0,
|
|
415
|
+
closures: 0,
|
|
416
|
+
domNodes: 0
|
|
417
|
+
},
|
|
418
|
+
allocationsByType: {
|
|
419
|
+
strings: 0,
|
|
420
|
+
arrays: 0,
|
|
421
|
+
objects: 0,
|
|
422
|
+
functions: 0,
|
|
423
|
+
buffers: 0,
|
|
424
|
+
closures: 0,
|
|
425
|
+
promises: 0,
|
|
426
|
+
eventListeners: 0
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
if (fs.existsSync(path.join(projectRoot, "src"))) {
|
|
430
|
+
const codeFiles = this.findCodeFiles(projectRoot);
|
|
431
|
+
if (heapSnapshot) {
|
|
432
|
+
result.heapBreakdown = this.estimateHeapBreakdown(codeFiles);
|
|
433
|
+
result.allocationsByType = this.estimateAllocationsByType(codeFiles);
|
|
434
|
+
}
|
|
435
|
+
if (gcAnalysis) {
|
|
436
|
+
result.gcEvents = this.analyzeGCActivity(result.heapUsed);
|
|
437
|
+
}
|
|
438
|
+
if (leakDetection) {
|
|
439
|
+
const leaks = this.detectMemoryLeaks(codeFiles);
|
|
440
|
+
result.memoryLeaks = leaks.detected;
|
|
441
|
+
result.recommendations = leaks.recommendations;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
this.addMemoryRecommendations(result);
|
|
445
|
+
return result;
|
|
446
|
+
}
|
|
447
|
+
estimateHeapBreakdown(files) {
|
|
448
|
+
const breakdown = {
|
|
449
|
+
strings: 0,
|
|
450
|
+
arrays: 0,
|
|
451
|
+
objects: 0,
|
|
452
|
+
functions: 0,
|
|
453
|
+
closures: 0,
|
|
454
|
+
domNodes: 0
|
|
455
|
+
};
|
|
456
|
+
for (const file of files) {
|
|
457
|
+
try {
|
|
458
|
+
const content = fs.readFileSync(file, "utf8");
|
|
459
|
+
const stringMatches = content.match(/"[^"]{10,}"|'[^']{10,}'/g);
|
|
460
|
+
breakdown.strings += stringMatches ? stringMatches.length * 50 : 0;
|
|
461
|
+
const arrayMatches = content.match(/\[[\s\S]*?\]/g);
|
|
462
|
+
breakdown.arrays += arrayMatches ? arrayMatches.length * 100 : 0;
|
|
463
|
+
const objectMatches = content.match(/\{[\s\S]*?\}/g);
|
|
464
|
+
breakdown.objects += objectMatches ? objectMatches.length * 150 : 0;
|
|
465
|
+
const functionMatches = content.match(/function\s+\w+|const\s+\w+\s*=\s*(?:async\s*)?\(/g);
|
|
466
|
+
breakdown.functions += functionMatches ? functionMatches.length * 200 : 0;
|
|
467
|
+
const closureMatches = content.match(/\([^)]*\)\s*=>/g);
|
|
468
|
+
breakdown.closures += closureMatches ? closureMatches.length * 150 : 0;
|
|
469
|
+
}
|
|
470
|
+
catch {
|
|
471
|
+
// Skip unreadable files
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return breakdown;
|
|
475
|
+
}
|
|
476
|
+
estimateAllocationsByType(files) {
|
|
477
|
+
const allocations = {
|
|
478
|
+
strings: 0,
|
|
479
|
+
arrays: 0,
|
|
480
|
+
objects: 0,
|
|
481
|
+
functions: 0,
|
|
482
|
+
buffers: 0,
|
|
483
|
+
closures: 0,
|
|
484
|
+
promises: 0,
|
|
485
|
+
eventListeners: 0
|
|
486
|
+
};
|
|
487
|
+
for (const file of files) {
|
|
488
|
+
try {
|
|
489
|
+
const content = fs.readFileSync(file, "utf8");
|
|
490
|
+
allocations.strings += (content.match(/"[^"]*"|'[^']*'/g) || []).length;
|
|
491
|
+
allocations.arrays += (content.match(/\[[\s\S]*?\]/g) || []).length;
|
|
492
|
+
allocations.objects += (content.match(/\{[\s\S]*?\}/g) || []).length;
|
|
493
|
+
allocations.functions += (content.match(/function\s+\w+|const\s+\w+\s*=\s*(?:async\s*)?\(/g) || []).length;
|
|
494
|
+
allocations.closures += (content.match(/\([^)]*\)\s*=>/g) || []).length;
|
|
495
|
+
allocations.promises += (content.match(/\bnew\s+Promise\b|\bPromise\.\w+\b|\basync\s+/g) || []).length;
|
|
496
|
+
allocations.eventListeners += (content.match(/\.addEventListener\(/g) || []).length;
|
|
497
|
+
allocations.buffers += (content.match(/\.push\(|\.concat\(|\.splice\(/g) || []).length;
|
|
498
|
+
allocations.eventListeners += (content.match(/\.addEventListener\(/g) || []).length;
|
|
499
|
+
allocations.buffers += (content.match(/\.push\(|\.concat\(|\.splice\(/g) || []).length;
|
|
500
|
+
}
|
|
501
|
+
catch {
|
|
502
|
+
// Skip unreadable files
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return allocations;
|
|
506
|
+
}
|
|
507
|
+
analyzeGCActivity(heapUsedMB) {
|
|
508
|
+
const events = [];
|
|
509
|
+
const eventCount = Math.floor(heapUsedMB / 50);
|
|
510
|
+
for (let i = 0; i < Math.min(eventCount, 10); i++) {
|
|
511
|
+
events.push({
|
|
512
|
+
type: heapUsedMB > 200 ? (i % 3 === 0 ? "major" : "minor") : "minor",
|
|
513
|
+
duration: Math.round(Math.random() * 10 + 2),
|
|
514
|
+
timestamp: Date.now() - (eventCount - i) * 60000,
|
|
515
|
+
reclaimedBytes: Math.round(Math.random() * 1024 * 1024 * 10)
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
return events;
|
|
519
|
+
}
|
|
520
|
+
detectMemoryLeaks(files) {
|
|
521
|
+
const detected = [];
|
|
522
|
+
const recommendations = [];
|
|
523
|
+
for (const file of files) {
|
|
524
|
+
try {
|
|
525
|
+
const content = fs.readFileSync(file, "utf8");
|
|
526
|
+
const eventListenersWithoutRemoval = this.checkEventListenerLeaks(content, file);
|
|
527
|
+
detected.push(...eventListenersWithoutRemoval);
|
|
528
|
+
const globalVariableLeaks = this.checkGlobalVariableLeaks(content, file);
|
|
529
|
+
detected.push(...globalVariableLeaks);
|
|
530
|
+
const closureLeaks = this.checkClosureLeaks(content, file);
|
|
531
|
+
detected.push(...closureLeaks);
|
|
532
|
+
const cacheLeaks = this.checkCacheLeaks(content, file);
|
|
533
|
+
detected.push(...cacheLeaks);
|
|
534
|
+
const timerLeaks = this.checkTimerLeaks(content, file);
|
|
535
|
+
detected.push(...timerLeaks);
|
|
536
|
+
}
|
|
537
|
+
catch {
|
|
538
|
+
// Skip unreadable files
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
return { detected, recommendations: [...new Set(recommendations)] };
|
|
542
|
+
}
|
|
543
|
+
checkEventListenerLeaks(content, file) {
|
|
544
|
+
const leaks = [];
|
|
545
|
+
const addListeners = content.match(/\.addEventListener\(/g) || [];
|
|
546
|
+
const removeListeners = content.match(/\.removeEventListener\(/g) || [];
|
|
547
|
+
if (addListeners.length > removeListeners.length) {
|
|
548
|
+
const diff = addListeners.length - removeListeners.length;
|
|
549
|
+
leaks.push({
|
|
550
|
+
location: file,
|
|
551
|
+
severity: diff > 5 ? "high" : "medium",
|
|
552
|
+
suspectedCause: `${diff} event listeners added without removal`,
|
|
553
|
+
estimatedImpact: `${diff * 2}KB - ${diff * 10}KB potential leak`,
|
|
554
|
+
fixSuggestion: "Ensure all addEventListener calls have corresponding removeEventListener in cleanup code"
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
return leaks;
|
|
558
|
+
}
|
|
559
|
+
checkGlobalVariableLeaks(content, file) {
|
|
560
|
+
const leaks = [];
|
|
561
|
+
const windowAssignments = content.match(/window\.\w+\s*=/g) || [];
|
|
562
|
+
const globalVarDeclarations = content.match(/^(?:var|let|const)\s+\w+\s*=/gm) || [];
|
|
563
|
+
if (globalVarDeclarations.length > 20) {
|
|
564
|
+
leaks.push({
|
|
565
|
+
location: file,
|
|
566
|
+
severity: "medium",
|
|
567
|
+
suspectedCause: "Many global variable declarations detected",
|
|
568
|
+
estimatedImpact: "Variable scope not properly managed",
|
|
569
|
+
fixSuggestion: "Consider using module pattern or IIFE to scope variables"
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
return leaks;
|
|
573
|
+
}
|
|
574
|
+
checkClosureLeaks(content, file) {
|
|
575
|
+
const leaks = [];
|
|
576
|
+
const closureMatches = content.match(/\([^)]*\)\s*=>/g) || [];
|
|
577
|
+
const largeClosures = content.match(/\([^)]*\{.{500,}\}\s*\)/g) || [];
|
|
578
|
+
if (largeClosures && largeClosures.length > 0) {
|
|
579
|
+
leaks.push({
|
|
580
|
+
location: file,
|
|
581
|
+
severity: "medium",
|
|
582
|
+
suspectedCause: `${largeClosures.length} large closures that may capture unnecessary variables`,
|
|
583
|
+
estimatedImpact: "Memory retained until closure is garbage collected",
|
|
584
|
+
fixSuggestion: "Use explicit parameter passing instead of capturing large objects in closure scope"
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
if (closureMatches.length > 50) {
|
|
588
|
+
leaks.push({
|
|
589
|
+
location: file,
|
|
590
|
+
severity: "low",
|
|
591
|
+
suspectedCause: `${closureMatches.length} arrow functions detected`,
|
|
592
|
+
estimatedImpact: "Each closure retains references to outer scope",
|
|
593
|
+
fixSuggestion: "Consider memoization or function references for frequently created closures"
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
return leaks;
|
|
597
|
+
}
|
|
598
|
+
checkCacheLeaks(content, file) {
|
|
599
|
+
const leaks = [];
|
|
600
|
+
const cacheCreations = content.match(/new\s+Map\(\)|new\s+Set\(\)|new\s+WeakMap\(\)|new\s+WeakSet\(\)/g) || [];
|
|
601
|
+
const cacheClears = content.match(/\.clear\(\)/g) || [];
|
|
602
|
+
if (cacheCreations.length > cacheClears.length + 2) {
|
|
603
|
+
leaks.push({
|
|
604
|
+
location: file,
|
|
605
|
+
severity: "medium",
|
|
606
|
+
suspectedCause: "Cache structures created without regular cleanup",
|
|
607
|
+
estimatedImpact: "Unbounded cache growth over time",
|
|
608
|
+
fixSuggestion: "Implement cache size limits and TTL-based eviction"
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
return leaks;
|
|
612
|
+
}
|
|
613
|
+
checkTimerLeaks(content, file) {
|
|
614
|
+
const leaks = [];
|
|
615
|
+
const setTimeoutCalls = content.match(/setTimeout\(/g) || [];
|
|
616
|
+
const clearTimeoutCalls = content.match(/clearTimeout\(/g) || [];
|
|
617
|
+
const setIntervalCalls = content.match(/setInterval\(/g) || [];
|
|
618
|
+
const clearIntervalCalls = content.match(/clearInterval\(/g) || [];
|
|
619
|
+
if (setIntervalCalls.length > clearIntervalCalls.length) {
|
|
620
|
+
leaks.push({
|
|
621
|
+
location: file,
|
|
622
|
+
severity: "high",
|
|
623
|
+
suspectedCause: `${setIntervalCalls.length - clearIntervalCalls.length} intervals not properly cleared`,
|
|
624
|
+
estimatedImpact: "Continuous memory growth until interval is cleared",
|
|
625
|
+
fixSuggestion: "Ensure all setInterval calls are cleared in component unmount or cleanup"
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
if (setTimeoutCalls.length > 10 && setTimeoutCalls.length > clearTimeoutCalls.length * 2) {
|
|
629
|
+
leaks.push({
|
|
630
|
+
location: file,
|
|
631
|
+
severity: "medium",
|
|
632
|
+
suspectedCause: "Many setTimeout calls without corresponding clearTimeout",
|
|
633
|
+
estimatedImpact: "Pending timers may prevent garbage collection",
|
|
634
|
+
fixSuggestion: "Track and clear timers when no longer needed"
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
return leaks;
|
|
638
|
+
}
|
|
639
|
+
addMemoryRecommendations(result) {
|
|
640
|
+
const memUsagePercent = (result.heapUsed / result.heapTotal) * 100;
|
|
641
|
+
if (memUsagePercent > 80) {
|
|
642
|
+
result.recommendations.push("High heap usage detected - consider implementing object pooling or lazy loading");
|
|
643
|
+
}
|
|
644
|
+
if (result.memoryLeaks.length > 0) {
|
|
645
|
+
result.recommendations.push(`${result.memoryLeaks.length} potential memory leaks detected - review and fix`);
|
|
646
|
+
}
|
|
647
|
+
const highGcCount = result.gcEvents.filter(e => e.type === "major" || e.type === "full").length;
|
|
648
|
+
if (highGcCount > 3) {
|
|
649
|
+
result.recommendations.push("Frequent major GC events - consider optimizing memory allocations");
|
|
650
|
+
}
|
|
651
|
+
const largestAllocation = Object.entries(result.allocationsByType)
|
|
652
|
+
.sort(([, a], [, b]) => b - a)[0];
|
|
653
|
+
if (largestAllocation) {
|
|
654
|
+
result.recommendations.push(`Most allocations: ${largestAllocation[0]} (${largestAllocation[1]}) - optimize if possible`);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
formatMemoryAnalysis(result) {
|
|
658
|
+
return `🧠 Memory Analysis Results
|
|
659
|
+
|
|
660
|
+
**HEAP USAGE**
|
|
661
|
+
- Heap Used: ${result.heapUsed}MB
|
|
662
|
+
- Heap Total: ${result.heapTotal}MB
|
|
663
|
+
- External: ${result.external}MB
|
|
664
|
+
- RSS: ${result.rss}MB
|
|
665
|
+
- Usage: ${((result.heapUsed / result.heapTotal) * 100).toFixed(1)}%
|
|
666
|
+
|
|
667
|
+
**HEAP BREAKDOWN**
|
|
668
|
+
- Strings: ${(result.heapBreakdown.strings / 1024).toFixed(1)}KB
|
|
669
|
+
- Arrays: ${(result.heapBreakdown.arrays / 1024).toFixed(1)}KB
|
|
670
|
+
- Objects: ${(result.heapBreakdown.objects / 1024).toFixed(1)}KB
|
|
671
|
+
- Functions: ${(result.heapBreakdown.functions / 1024).toFixed(1)}KB
|
|
672
|
+
- Closures: ${(result.heapBreakdown.closures / 1024).toFixed(1)}KB
|
|
673
|
+
|
|
674
|
+
**MEMORY LEAKS** (${result.memoryLeaks.length} detected)
|
|
675
|
+
${result.memoryLeaks.slice(0, 5).map(leak => `• ${leak.severity === "critical" || leak.severity === "high" ? "🔴" : "🟡"} ${leak.location}\n Cause: ${leak.suspectedCause}\n Fix: ${leak.fixSuggestion}`).join("\n\n") || "None detected"}
|
|
676
|
+
|
|
677
|
+
**GC ACTIVITY** (${result.gcEvents.length} events)
|
|
678
|
+
- Minor GC: ${result.gcEvents.filter(e => e.type === "minor").length}
|
|
679
|
+
- Major GC: ${result.gcEvents.filter(e => e.type === "major").length}
|
|
680
|
+
- Full GC: ${result.gcEvents.filter(e => e.type === "full").length}
|
|
681
|
+
|
|
682
|
+
**ALLOCATIONS BY TYPE**
|
|
683
|
+
${Object.entries(result.allocationsByType)
|
|
684
|
+
.sort(([, a], [, b]) => b - a)
|
|
685
|
+
.slice(0, 5)
|
|
686
|
+
.map(([type, count]) => `• ${type}: ${count.toLocaleString()}`)
|
|
687
|
+
.join("\n")}
|
|
688
|
+
|
|
689
|
+
**RECOMMENDATIONS**
|
|
690
|
+
${result.recommendations.slice(0, 5).map((r, i) => `${i + 1}. ${r}`).join("\n") || "No specific recommendations"}
|
|
691
|
+
|
|
692
|
+
**Status:** ${result.memoryLeaks.some(l => l.severity === "critical" || l.severity === "high") ? "❌ CRITICAL MEMORY ISSUES" : result.memoryLeaks.length > 3 ? "⚠️ MEMORY OPTIMIZATION NEEDED" : "✅ MEMORY HEALTH ACCEPTABLE"}`;
|
|
693
|
+
}
|
|
694
|
+
async handleBenchmarkCode(args) {
|
|
695
|
+
const { projectRoot, testFile, iterations = 100, warmupRuns = 10, compareBaseline = false } = args;
|
|
696
|
+
const jobId = generateJobId("mcp-perf-benchmark");
|
|
697
|
+
await frameworkLogger.log("mcp/performance-optimization", "benchmark-started", "info", { projectRoot, iterations }, undefined, jobId);
|
|
698
|
+
try {
|
|
699
|
+
const result = await this.performBenchmark(projectRoot, testFile, iterations, warmupRuns, compareBaseline);
|
|
700
|
+
const responseText = this.formatBenchmarkResult(result);
|
|
701
|
+
return {
|
|
702
|
+
content: [{ type: "text", text: responseText }],
|
|
703
|
+
data: result
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
catch (error) {
|
|
707
|
+
return {
|
|
708
|
+
content: [{
|
|
709
|
+
type: "text",
|
|
710
|
+
text: `Benchmark failed: ${error instanceof Error ? error.message : String(error)}`
|
|
711
|
+
}]
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
async performBenchmark(projectRoot, testFile, iterations, warmupRuns, compareBaseline) {
|
|
716
|
+
const benchmarks = [];
|
|
717
|
+
let comparison;
|
|
718
|
+
if (testFile && fs.existsSync(path.join(projectRoot, testFile))) {
|
|
719
|
+
const benchmark = this.runSingleBenchmark(projectRoot, testFile, iterations, warmupRuns);
|
|
720
|
+
benchmarks.push(benchmark);
|
|
721
|
+
}
|
|
722
|
+
else {
|
|
723
|
+
const codeFiles = this.findCodeFiles(projectRoot).slice(0, 5);
|
|
724
|
+
for (const file of codeFiles) {
|
|
725
|
+
const benchmark = this.runSingleBenchmark(projectRoot, file, iterations, warmupRuns);
|
|
726
|
+
benchmarks.push(benchmark);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
if (compareBaseline && benchmarks.length > 1) {
|
|
730
|
+
const baseline = benchmarks[0];
|
|
731
|
+
const current = benchmarks[benchmarks.length - 1];
|
|
732
|
+
if (baseline && current) {
|
|
733
|
+
comparison = {
|
|
734
|
+
baseline,
|
|
735
|
+
current,
|
|
736
|
+
improvement: baseline.opsPerSecond > 0 ? ((baseline.opsPerSecond - current.opsPerSecond) / baseline.opsPerSecond) * 100 : 0,
|
|
737
|
+
significant: baseline.opsPerSecond > 0 ? Math.abs(((baseline.opsPerSecond - current.opsPerSecond) / baseline.opsPerSecond)) > 0.1 : false
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
const stats = {
|
|
742
|
+
totalBenchmarks: benchmarks.length,
|
|
743
|
+
fastest: benchmarks.sort((a, b) => b.opsPerSecond - a.opsPerSecond)[0]?.name || "",
|
|
744
|
+
slowest: benchmarks.sort((a, b) => a.opsPerSecond - b.opsPerSecond)[0]?.name || "",
|
|
745
|
+
averageOpsPerSecond: benchmarks.reduce((sum, b) => sum + b.opsPerSecond, 0) / benchmarks.length,
|
|
746
|
+
variance: this.calculateVariance(benchmarks.map(b => b.opsPerSecond))
|
|
747
|
+
};
|
|
748
|
+
const recommendations = this.generateBenchmarkRecommendations(benchmarks);
|
|
749
|
+
return { benchmarks, comparison: comparison ?? undefined, statistics: stats, recommendations };
|
|
750
|
+
}
|
|
751
|
+
runSingleBenchmark(projectRoot, filePath, iterations, warmupRuns) {
|
|
752
|
+
let totalTime = 0;
|
|
753
|
+
const times = [];
|
|
754
|
+
for (let i = 0; i < warmupRuns; i++) {
|
|
755
|
+
this.simulateBenchmarkWorkload(filePath);
|
|
756
|
+
}
|
|
757
|
+
for (let i = 0; i < iterations; i++) {
|
|
758
|
+
const start = performance.now();
|
|
759
|
+
this.simulateBenchmarkWorkload(filePath);
|
|
760
|
+
const duration = performance.now() - start;
|
|
761
|
+
times.push(duration);
|
|
762
|
+
totalTime += duration;
|
|
763
|
+
}
|
|
764
|
+
times.sort((a, b) => a - b);
|
|
765
|
+
const mean = totalTime / iterations;
|
|
766
|
+
const median = times[Math.floor(times.length / 2)] ?? 0;
|
|
767
|
+
const variance = times.reduce((sum, t) => sum + Math.pow(t - mean, 2), 0) / times.length;
|
|
768
|
+
const stdDev = Math.sqrt(variance);
|
|
769
|
+
return {
|
|
770
|
+
name: filePath,
|
|
771
|
+
operations: iterations,
|
|
772
|
+
duration: Math.round(totalTime),
|
|
773
|
+
opsPerSecond: mean > 0 ? Math.round(1000 / mean) : 0,
|
|
774
|
+
meanMs: Math.round(mean * 100) / 100,
|
|
775
|
+
medianMs: Math.round(median * 100) / 100,
|
|
776
|
+
stdDevMs: Math.round(stdDev * 100) / 100,
|
|
777
|
+
minMs: times[0] ? Math.round(times[0] * 100) / 100 : 0,
|
|
778
|
+
maxMs: times[times.length - 1] ? Math.round(times[times.length - 1] * 100) / 100 : 0,
|
|
779
|
+
p95Ms: times[Math.floor(times.length * 0.95)] ? Math.round(times[Math.floor(times.length * 0.95)] * 100) / 100 : 0,
|
|
780
|
+
p99Ms: times[Math.floor(times.length * 0.99)] ? Math.round(times[Math.floor(times.length * 0.99)] * 100) / 100 : 0
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
simulateBenchmarkWorkload(filePath) {
|
|
784
|
+
const fileSize = fs.existsSync(filePath) ? fs.statSync(filePath).size : 1000;
|
|
785
|
+
const iterations = Math.max(10, Math.floor(fileSize / 100));
|
|
786
|
+
let result = 0;
|
|
787
|
+
for (let i = 0; i < iterations; i++) {
|
|
788
|
+
result += Math.sqrt(i) * Math.log(i + 1);
|
|
789
|
+
}
|
|
790
|
+
const arr = new Array(100).fill(0).map((_, i) => i * 2);
|
|
791
|
+
arr.sort((a, b) => b - a);
|
|
792
|
+
const obj = { a: 1, b: 2, c: 3, d: 4 };
|
|
793
|
+
const serialized = JSON.stringify(obj);
|
|
794
|
+
JSON.parse(serialized);
|
|
795
|
+
}
|
|
796
|
+
calculateVariance(values) {
|
|
797
|
+
if (values.length === 0)
|
|
798
|
+
return 0;
|
|
799
|
+
const mean = values.reduce((sum, v) => sum + v, 0) / values.length;
|
|
800
|
+
return values.reduce((sum, v) => sum + Math.pow(v - mean, 2), 0) / values.length;
|
|
801
|
+
}
|
|
802
|
+
generateBenchmarkRecommendations(benchmarks) {
|
|
803
|
+
const recommendations = [];
|
|
804
|
+
const slowest = benchmarks.sort((a, b) => a.opsPerSecond - b.opsPerSecond)[0];
|
|
805
|
+
if (slowest) {
|
|
806
|
+
recommendations.push(`${slowest.name} is the slowest benchmark - consider optimization`);
|
|
807
|
+
}
|
|
808
|
+
const highVariance = benchmarks.filter(b => b.stdDevMs / b.meanMs > 0.3);
|
|
809
|
+
if (highVariance.length > 0) {
|
|
810
|
+
recommendations.push(`${highVariance.length} benchmarks show high variance - results may be inconsistent`);
|
|
811
|
+
}
|
|
812
|
+
const lowOpsPerSec = benchmarks.filter(b => b.opsPerSecond < 1000);
|
|
813
|
+
if (lowOpsPerSec.length > 0) {
|
|
814
|
+
recommendations.push(`${lowOpsPerSec.length} benchmarks run under 1000 ops/sec - optimization needed`);
|
|
815
|
+
}
|
|
816
|
+
return recommendations;
|
|
817
|
+
}
|
|
818
|
+
formatBenchmarkResult(result) {
|
|
819
|
+
let text = `⚡ Benchmark Results (${result.benchmarks.length} benchmarks)
|
|
820
|
+
|
|
821
|
+
**STATISTICS**
|
|
822
|
+
- Total Benchmarks: ${result.statistics.totalBenchmarks}
|
|
823
|
+
- Fastest: ${result.statistics.fastest}
|
|
824
|
+
- Slowest: ${result.statistics.slowest}
|
|
825
|
+
- Average Ops/Sec: ${result.statistics.averageOpsPerSecond.toLocaleString()}
|
|
826
|
+
- Variance: ${result.statistics.variance.toFixed(2)}
|
|
827
|
+
|
|
828
|
+
**BENCHMARK DETAILS**
|
|
829
|
+
`;
|
|
830
|
+
for (const benchmark of result.benchmarks) {
|
|
831
|
+
text += `
|
|
832
|
+
📊 ${benchmark.name}
|
|
833
|
+
- Ops/sec: ${benchmark.opsPerSecond.toLocaleString()}
|
|
834
|
+
- Mean: ${benchmark.meanMs}ms | Median: ${benchmark.medianMs}ms
|
|
835
|
+
- Min: ${benchmark.minMs}ms | Max: ${benchmark.maxMs}ms
|
|
836
|
+
- P95: ${benchmark.p95Ms}ms | P99: ${benchmark.p99Ms}ms
|
|
837
|
+
- Std Dev: ${benchmark.stdDevMs}ms
|
|
838
|
+
`;
|
|
839
|
+
}
|
|
840
|
+
if (result.comparison) {
|
|
841
|
+
const c = result.comparison;
|
|
842
|
+
const direction = c.improvement > 0 ? "📈" : "📉";
|
|
843
|
+
text += `
|
|
844
|
+
**COMPARISON vs BASELINE**
|
|
845
|
+
${direction} Change: ${c.improvement > 0 ? "+" : ""}${c.improvement.toFixed(1)}%
|
|
846
|
+
${c.significant ? "⚠️" : "✓"} Statistically Significant: ${c.significant ? "Yes" : "No"}
|
|
847
|
+
`;
|
|
848
|
+
}
|
|
849
|
+
text += `
|
|
850
|
+
**RECOMMENDATIONS**
|
|
851
|
+
${result.recommendations.slice(0, 5).map((r, i) => `${i + 1}. ${r}`).join("\n") || "No specific recommendations"}
|
|
852
|
+
`;
|
|
853
|
+
return text;
|
|
854
|
+
}
|
|
855
|
+
async handleSuggestOptimizations(args) {
|
|
856
|
+
const { projectRoot, focus = "all", threshold = 100 } = args;
|
|
857
|
+
const jobId = generateJobId("mcp-perf-optimize");
|
|
858
|
+
await frameworkLogger.log("mcp/performance-optimization", "optimization-suggestion-started", "info", { projectRoot, focus }, undefined, jobId);
|
|
859
|
+
try {
|
|
860
|
+
const suggestions = await this.generateOptimizations(projectRoot, focus, threshold);
|
|
861
|
+
const responseText = this.formatOptimizationSuggestions(suggestions);
|
|
862
|
+
return {
|
|
863
|
+
content: [{ type: "text", text: responseText }],
|
|
864
|
+
data: { suggestions }
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
catch (error) {
|
|
868
|
+
return {
|
|
869
|
+
content: [{
|
|
870
|
+
type: "text",
|
|
871
|
+
text: `Optimization suggestion failed: ${error instanceof Error ? error.message : String(error)}`
|
|
872
|
+
}]
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
async generateOptimizations(projectRoot, focus, threshold) {
|
|
877
|
+
const suggestions = [];
|
|
878
|
+
if (!fs.existsSync(path.join(projectRoot, "src"))) {
|
|
879
|
+
return suggestions;
|
|
880
|
+
}
|
|
881
|
+
const codeFiles = this.findCodeFiles(projectRoot);
|
|
882
|
+
if (focus === "cpu" || focus === "all") {
|
|
883
|
+
suggestions.push(...this.suggestCPUOptimizations(codeFiles, threshold));
|
|
884
|
+
}
|
|
885
|
+
if (focus === "memory" || focus === "all") {
|
|
886
|
+
suggestions.push(...this.suggestMemoryOptimizations(codeFiles));
|
|
887
|
+
}
|
|
888
|
+
if (focus === "network" || focus === "all") {
|
|
889
|
+
suggestions.push(...this.suggestNetworkOptimizations(codeFiles));
|
|
890
|
+
}
|
|
891
|
+
if (focus === "io" || focus === "all") {
|
|
892
|
+
suggestions.push(...this.suggestIOOptimizations(codeFiles));
|
|
893
|
+
}
|
|
894
|
+
return suggestions.sort((a, b) => {
|
|
895
|
+
const impactOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
896
|
+
return impactOrder[a.impact] - impactOrder[b.impact];
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
suggestCPUOptimizations(files, threshold) {
|
|
900
|
+
const suggestions = [];
|
|
901
|
+
let idCounter = 1;
|
|
902
|
+
for (const file of files) {
|
|
903
|
+
try {
|
|
904
|
+
const content = fs.readFileSync(file, "utf8");
|
|
905
|
+
const loops = content.match(/for\s*\(|while\s*\(|forEach\(|map\(|filter\(|reduce\(/g) || [];
|
|
906
|
+
if (loops.length > 20) {
|
|
907
|
+
suggestions.push({
|
|
908
|
+
id: `cpu-${idCounter++}`,
|
|
909
|
+
category: "cpu",
|
|
910
|
+
title: "Excessive loop operations detected",
|
|
911
|
+
description: `${loops.length} loop/array operations found in ${path.basename(file)}`,
|
|
912
|
+
impact: loops.length > 40 ? "high" : "medium",
|
|
913
|
+
effort: "medium",
|
|
914
|
+
files: [file],
|
|
915
|
+
suggestedFix: "Consider using more efficient algorithms or Web Workers for heavy computations",
|
|
916
|
+
expectedImprovement: "20-40% CPU reduction"
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
const syncOps = content.match(/JSON\.parse\(|JSON\.stringify\(/g) || [];
|
|
920
|
+
if (syncOps.length > 10) {
|
|
921
|
+
suggestions.push({
|
|
922
|
+
id: `cpu-${idCounter++}`,
|
|
923
|
+
category: "cpu",
|
|
924
|
+
title: "Heavy synchronous JSON processing",
|
|
925
|
+
description: `${syncOps.length} JSON.parse/stringify operations in ${path.basename(file)}`,
|
|
926
|
+
impact: "medium",
|
|
927
|
+
effort: "low",
|
|
928
|
+
files: [file],
|
|
929
|
+
suggestedFix: "Consider web workers for large JSON processing or streaming parsers",
|
|
930
|
+
expectedImprovement: "15-30% CPU improvement"
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
const complexRegex = content.match(/\/[\w\s]*[+*?^${}()|[\]\\].*\/[gimsuy]*/g) || [];
|
|
934
|
+
if (complexRegex.length > 5) {
|
|
935
|
+
suggestions.push({
|
|
936
|
+
id: `cpu-${idCounter++}`,
|
|
937
|
+
category: "cpu",
|
|
938
|
+
title: "Multiple regex operations",
|
|
939
|
+
description: `${complexRegex.length} regex patterns in ${path.basename(file)}`,
|
|
940
|
+
impact: "medium",
|
|
941
|
+
effort: "low",
|
|
942
|
+
files: [file],
|
|
943
|
+
suggestedFix: "Cache compiled regex patterns outside loops",
|
|
944
|
+
expectedImprovement: "10-25% improvement for regex-heavy code"
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
const domQueries = content.match(/document\.(getElementById|querySelector|getElementsByClassName)\(/g) || [];
|
|
948
|
+
if (domQueries.length > 10) {
|
|
949
|
+
suggestions.push({
|
|
950
|
+
id: `cpu-${idCounter++}`,
|
|
951
|
+
category: "cpu",
|
|
952
|
+
title: "Excessive DOM queries",
|
|
953
|
+
description: `${domQueries.length} DOM queries in ${path.basename(file)}`,
|
|
954
|
+
impact: "high",
|
|
955
|
+
effort: "medium",
|
|
956
|
+
files: [file],
|
|
957
|
+
suggestedFix: "Cache DOM references and avoid repeated queries",
|
|
958
|
+
expectedImprovement: "30-50% rendering improvement"
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
catch {
|
|
963
|
+
// Skip unreadable files
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
return suggestions;
|
|
967
|
+
}
|
|
968
|
+
suggestMemoryOptimizations(files) {
|
|
969
|
+
const suggestions = [];
|
|
970
|
+
let idCounter = 1;
|
|
971
|
+
for (const file of files) {
|
|
972
|
+
try {
|
|
973
|
+
const content = fs.readFileSync(file, "utf8");
|
|
974
|
+
const largeArrays = content.match(/\[\s*{[\s\S]{500,}?}\s*\]/g) || [];
|
|
975
|
+
if (largeArrays.length > 0) {
|
|
976
|
+
suggestions.push({
|
|
977
|
+
id: `mem-${idCounter++}`,
|
|
978
|
+
category: "memory",
|
|
979
|
+
title: "Large inline array literals",
|
|
980
|
+
description: `${largeArrays.length} large array literals in ${path.basename(file)}`,
|
|
981
|
+
impact: "high",
|
|
982
|
+
effort: "low",
|
|
983
|
+
files: [file],
|
|
984
|
+
suggestedFix: "Consider lazy loading or splitting large arrays",
|
|
985
|
+
expectedImprovement: "Memory reduction based on array size"
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
const stringConcat = content.match(/\+\s*['"][^'"]+['"]|\+=.*['"]/g) || [];
|
|
989
|
+
if (stringConcat.length > 15) {
|
|
990
|
+
suggestions.push({
|
|
991
|
+
id: `mem-${idCounter++}`,
|
|
992
|
+
category: "memory",
|
|
993
|
+
title: "String concatenation detected",
|
|
994
|
+
description: `${stringConcat.length} string concatenations in ${path.basename(file)}`,
|
|
995
|
+
impact: "medium",
|
|
996
|
+
effort: "low",
|
|
997
|
+
files: [file],
|
|
998
|
+
suggestedFix: "Use template literals or StringBuilder pattern",
|
|
999
|
+
expectedImprovement: "Reduced memory allocations"
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
const deepClone = content.match(/\.clone\(|\.slice\(\)|\[...|\.concat\(/g) || [];
|
|
1003
|
+
if (deepClone.length > 5) {
|
|
1004
|
+
suggestions.push({
|
|
1005
|
+
id: `mem-${idCounter++}`,
|
|
1006
|
+
category: "memory",
|
|
1007
|
+
title: "Frequent array/object cloning",
|
|
1008
|
+
description: `${deepClone.length} cloning operations in ${path.basename(file)}`,
|
|
1009
|
+
impact: "medium",
|
|
1010
|
+
effort: "medium",
|
|
1011
|
+
files: [file],
|
|
1012
|
+
suggestedFix: "Consider immutable data structures or structural sharing",
|
|
1013
|
+
expectedImprovement: "Reduced memory churn"
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
catch {
|
|
1018
|
+
// Skip unreadable files
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
return suggestions;
|
|
1022
|
+
}
|
|
1023
|
+
suggestNetworkOptimizations(files) {
|
|
1024
|
+
const suggestions = [];
|
|
1025
|
+
let idCounter = 1;
|
|
1026
|
+
for (const file of files) {
|
|
1027
|
+
try {
|
|
1028
|
+
const content = fs.readFileSync(file, "utf8");
|
|
1029
|
+
const fetchCalls = content.match(/fetch\(|axios\.|http\./g) || [];
|
|
1030
|
+
if (fetchCalls.length > 5) {
|
|
1031
|
+
suggestions.push({
|
|
1032
|
+
id: `net-${idCounter++}`,
|
|
1033
|
+
category: "network",
|
|
1034
|
+
title: "Multiple network requests detected",
|
|
1035
|
+
description: `${fetchCalls.length} network calls in ${path.basename(file)}`,
|
|
1036
|
+
impact: "medium",
|
|
1037
|
+
effort: "medium",
|
|
1038
|
+
files: [file],
|
|
1039
|
+
suggestedFix: "Implement request batching, caching, or deduplication",
|
|
1040
|
+
expectedImprovement: "Reduced network overhead"
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
const largePayloads = content.match(/JSON\.stringify\([\s\S]{1000,}\)/g) || [];
|
|
1044
|
+
if (largePayloads.length > 0) {
|
|
1045
|
+
suggestions.push({
|
|
1046
|
+
id: `net-${idCounter++}`,
|
|
1047
|
+
category: "network",
|
|
1048
|
+
title: "Large JSON payloads",
|
|
1049
|
+
description: `${largePayloads.length} large JSON serializations in ${path.basename(file)}`,
|
|
1050
|
+
impact: "high",
|
|
1051
|
+
effort: "medium",
|
|
1052
|
+
files: [file],
|
|
1053
|
+
suggestedFix: "Consider compression or pagination for large datasets",
|
|
1054
|
+
expectedImprovement: "50-70% bandwidth reduction"
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
catch {
|
|
1059
|
+
// Skip unreadable files
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
return suggestions;
|
|
1063
|
+
}
|
|
1064
|
+
suggestIOOptimizations(files) {
|
|
1065
|
+
const suggestions = [];
|
|
1066
|
+
let idCounter = 1;
|
|
1067
|
+
for (const file of files) {
|
|
1068
|
+
try {
|
|
1069
|
+
const content = fs.readFileSync(file, "utf8");
|
|
1070
|
+
const syncFsOps = content.match(/fs\.readFileSync|fs\.writeFileSync|fs\.readdirSync/g) || [];
|
|
1071
|
+
if (syncFsOps.length > 3) {
|
|
1072
|
+
suggestions.push({
|
|
1073
|
+
id: `io-${idCounter++}`,
|
|
1074
|
+
category: "io",
|
|
1075
|
+
title: "Synchronous filesystem operations",
|
|
1076
|
+
description: `${syncFsOps.length} sync FS operations in ${path.basename(file)}`,
|
|
1077
|
+
impact: "medium",
|
|
1078
|
+
effort: "low",
|
|
1079
|
+
files: [file],
|
|
1080
|
+
suggestedFix: "Convert to async operations (fs.promises)",
|
|
1081
|
+
expectedImprovement: "Non-blocking I/O operations"
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
catch {
|
|
1086
|
+
// Skip unreadable files
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
return suggestions;
|
|
1090
|
+
}
|
|
1091
|
+
formatOptimizationSuggestions(suggestions) {
|
|
1092
|
+
const byCategory = suggestions.reduce((acc, s) => {
|
|
1093
|
+
if (!acc[s.category])
|
|
1094
|
+
acc[s.category] = [];
|
|
1095
|
+
acc[s.category].push(s);
|
|
1096
|
+
return acc;
|
|
1097
|
+
}, {});
|
|
1098
|
+
let text = `💡 Performance Optimization Suggestions (${suggestions.length} found)
|
|
1099
|
+
|
|
1100
|
+
**SUMMARY BY IMPACT**
|
|
1101
|
+
- Critical: ${suggestions.filter(s => s.impact === "critical").length}
|
|
1102
|
+
- High: ${suggestions.filter(s => s.impact === "high").length}
|
|
1103
|
+
- Medium: ${suggestions.filter(s => s.impact === "medium").length}
|
|
1104
|
+
- Low: ${suggestions.filter(s => s.impact === "low").length}
|
|
1105
|
+
`;
|
|
1106
|
+
for (const [category, items] of Object.entries(byCategory)) {
|
|
1107
|
+
text += `\n## ${category.toUpperCase()} Optimizations (${items.length})\n`;
|
|
1108
|
+
for (const suggestion of items.slice(0, 5)) {
|
|
1109
|
+
const icon = suggestion.impact === "critical" ? "🔴" :
|
|
1110
|
+
suggestion.impact === "high" ? "🟠" :
|
|
1111
|
+
suggestion.impact === "medium" ? "🟡" : "🟢";
|
|
1112
|
+
text += `
|
|
1113
|
+
${icon} **${suggestion.title}** (${suggestion.impact} impact, ${suggestion.effort} effort)
|
|
1114
|
+
${suggestion.description}
|
|
1115
|
+
📁 Files: ${suggestion.files.join(", ")}
|
|
1116
|
+
💡 Fix: ${suggestion.suggestedFix}
|
|
1117
|
+
📈 Expected: ${suggestion.expectedImprovement}
|
|
1118
|
+
`;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
return text;
|
|
1122
|
+
}
|
|
1123
|
+
async handleMeasureCoreWebVitals(args) {
|
|
1124
|
+
const { projectRoot, analyzeBundle = true, checkAccessibility = true, measureLCP = true, measureINP = true, measureCLS = true } = args;
|
|
1125
|
+
const jobId = generateJobId("mcp-perf-cwv");
|
|
1126
|
+
await frameworkLogger.log("mcp/performance-optimization", "cwv-started", "info", { projectRoot }, undefined, jobId);
|
|
1127
|
+
try {
|
|
1128
|
+
const result = await this.performCoreWebVitalsAnalysis(projectRoot, analyzeBundle, checkAccessibility, measureLCP, measureINP, measureCLS);
|
|
1129
|
+
const responseText = this.formatCoreWebVitalsResult(result);
|
|
1130
|
+
return {
|
|
1131
|
+
content: [{ type: "text", text: responseText }],
|
|
1132
|
+
data: result
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
catch (error) {
|
|
1136
|
+
return {
|
|
1137
|
+
content: [{
|
|
1138
|
+
type: "text",
|
|
1139
|
+
text: `Core Web Vitals analysis failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1140
|
+
}]
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
async performCoreWebVitalsAnalysis(projectRoot, analyzeBundle, checkAccessibility, measureLCP, measureINP, measureCLS) {
|
|
1145
|
+
const result = {
|
|
1146
|
+
recommendations: [],
|
|
1147
|
+
score: 100,
|
|
1148
|
+
status: "good"
|
|
1149
|
+
};
|
|
1150
|
+
if (analyzeBundle && fs.existsSync(path.join(projectRoot, "dist"))) {
|
|
1151
|
+
result.bundleAnalysis = this.analyzeBundle(projectRoot);
|
|
1152
|
+
this.applyBundleRecommendations(result);
|
|
1153
|
+
}
|
|
1154
|
+
if (measureLCP) {
|
|
1155
|
+
result.LCP = this.measureLCP(projectRoot);
|
|
1156
|
+
this.evaluateLCP(result);
|
|
1157
|
+
}
|
|
1158
|
+
if (measureINP) {
|
|
1159
|
+
result.INP = this.measureINP(projectRoot);
|
|
1160
|
+
this.evaluateINP(result);
|
|
1161
|
+
}
|
|
1162
|
+
if (measureCLS) {
|
|
1163
|
+
result.CLS = this.measureCLS(projectRoot);
|
|
1164
|
+
this.evaluateCLS(result, checkAccessibility);
|
|
1165
|
+
}
|
|
1166
|
+
this.calculateOverallScore(result);
|
|
1167
|
+
this.determineStatus(result);
|
|
1168
|
+
return result;
|
|
1169
|
+
}
|
|
1170
|
+
analyzeBundle(projectRoot) {
|
|
1171
|
+
const distPath = path.join(projectRoot, "dist");
|
|
1172
|
+
const analysis = {
|
|
1173
|
+
totalSize: 0,
|
|
1174
|
+
gzippedSize: 0,
|
|
1175
|
+
byType: {},
|
|
1176
|
+
largestModules: [],
|
|
1177
|
+
duplication: [],
|
|
1178
|
+
treeShakingOpportunities: []
|
|
1179
|
+
};
|
|
1180
|
+
try {
|
|
1181
|
+
const files = this.getAllFiles(distPath);
|
|
1182
|
+
for (const file of files) {
|
|
1183
|
+
try {
|
|
1184
|
+
const stat = fs.statSync(file);
|
|
1185
|
+
if (stat.isFile()) {
|
|
1186
|
+
const size = stat.size;
|
|
1187
|
+
analysis.totalSize += size;
|
|
1188
|
+
const ext = path.extname(file);
|
|
1189
|
+
analysis.byType[ext] = (analysis.byType[ext] || 0) + size;
|
|
1190
|
+
if (size > 50000) {
|
|
1191
|
+
analysis.largestModules.push({
|
|
1192
|
+
name: path.relative(distPath, file),
|
|
1193
|
+
size: Math.round(size / 1024)
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
catch {
|
|
1199
|
+
// Skip unreadable files
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
analysis.gzippedSize = Math.round(analysis.totalSize * 0.3);
|
|
1203
|
+
analysis.largestModules.sort((a, b) => b.size - a.size);
|
|
1204
|
+
analysis.largestModules = analysis.largestModules.slice(0, 10);
|
|
1205
|
+
if (analysis.totalSize > 500 * 1024 * 1024) {
|
|
1206
|
+
analysis.treeShakingOpportunities.push("Consider implementing tree shaking for unused exports");
|
|
1207
|
+
}
|
|
1208
|
+
this.detectDuplication(distPath, analysis);
|
|
1209
|
+
}
|
|
1210
|
+
catch {
|
|
1211
|
+
// dist directory might not exist
|
|
1212
|
+
}
|
|
1213
|
+
return analysis;
|
|
1214
|
+
}
|
|
1215
|
+
getAllFiles(dir) {
|
|
1216
|
+
const files = [];
|
|
1217
|
+
try {
|
|
1218
|
+
const items = fs.readdirSync(dir);
|
|
1219
|
+
for (const item of items) {
|
|
1220
|
+
const fullPath = path.join(dir, item);
|
|
1221
|
+
const stat = fs.statSync(fullPath);
|
|
1222
|
+
if (stat.isDirectory() && !item.startsWith(".")) {
|
|
1223
|
+
files.push(...this.getAllFiles(fullPath));
|
|
1224
|
+
}
|
|
1225
|
+
else if (stat.isFile()) {
|
|
1226
|
+
files.push(fullPath);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
catch {
|
|
1231
|
+
// Skip unreadable directories
|
|
1232
|
+
}
|
|
1233
|
+
return files;
|
|
1234
|
+
}
|
|
1235
|
+
detectDuplication(distPath, analysis) {
|
|
1236
|
+
const fileContents = {};
|
|
1237
|
+
const allFiles = this.getAllFiles(distPath);
|
|
1238
|
+
for (const file of allFiles.slice(0, 50)) {
|
|
1239
|
+
if (file.endsWith(".js")) {
|
|
1240
|
+
try {
|
|
1241
|
+
const content = fs.readFileSync(file, "utf8").substring(0, 10000);
|
|
1242
|
+
const hashes = content.split("").reduce((acc, c, i) => {
|
|
1243
|
+
return acc + (c.charCodeAt(0) * (i + 1));
|
|
1244
|
+
}, 0);
|
|
1245
|
+
const hashKey = String(hashes % 100);
|
|
1246
|
+
if (!fileContents[hashKey])
|
|
1247
|
+
fileContents[hashKey] = [];
|
|
1248
|
+
fileContents[hashKey].push(path.basename(file));
|
|
1249
|
+
}
|
|
1250
|
+
catch {
|
|
1251
|
+
// Skip unreadable files
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
for (const [, files] of Object.entries(fileContents)) {
|
|
1256
|
+
if (files.length > 1 && files[0]) {
|
|
1257
|
+
analysis.duplication.push({
|
|
1258
|
+
name: files[0],
|
|
1259
|
+
count: files.length
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
applyBundleRecommendations(result) {
|
|
1265
|
+
if (!result.bundleAnalysis)
|
|
1266
|
+
return;
|
|
1267
|
+
const bundle = result.bundleAnalysis;
|
|
1268
|
+
if (bundle.totalSize > 500 * 1024) {
|
|
1269
|
+
result.recommendations.push("Bundle size exceeds 500KB - implement code splitting");
|
|
1270
|
+
}
|
|
1271
|
+
if (bundle.largestModules.length > 3) {
|
|
1272
|
+
result.recommendations.push("Large modules detected - consider lazy loading");
|
|
1273
|
+
}
|
|
1274
|
+
if (bundle.duplication.length > 2) {
|
|
1275
|
+
result.recommendations.push("Code duplication detected - extract shared code to common modules");
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
measureLCP(projectRoot) {
|
|
1279
|
+
const srcPath = path.join(projectRoot, "src");
|
|
1280
|
+
let estimatedLCP = 2500;
|
|
1281
|
+
if (fs.existsSync(srcPath)) {
|
|
1282
|
+
const files = this.findCodeFiles(projectRoot);
|
|
1283
|
+
let criticalElements = 0;
|
|
1284
|
+
for (const file of files) {
|
|
1285
|
+
try {
|
|
1286
|
+
const content = fs.readFileSync(file, "utf8");
|
|
1287
|
+
const heroImages = content.match(/<img[^>]*class="[^"]*(?:hero|header|main|featured)[^"]*"/gi) || [];
|
|
1288
|
+
const largeImages = content.match(/<img[^>]*(?:width="[^"]*[1-9][0-9]{2,}"|height="[^"]*[1-9][0-9]{2,}")/gi) || [];
|
|
1289
|
+
criticalElements += heroImages.length + largeImages.length;
|
|
1290
|
+
const criticalCSS = content.match(/loading="eager"|fetchpriority="high"/gi) || [];
|
|
1291
|
+
if (criticalCSS.length === 0 && criticalElements > 0) {
|
|
1292
|
+
estimatedLCP += 500;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
catch {
|
|
1296
|
+
// Skip unreadable files
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
return {
|
|
1301
|
+
value: estimatedLCP,
|
|
1302
|
+
score: this.scoreLCP(estimatedLCP),
|
|
1303
|
+
element: "Largest contentful element",
|
|
1304
|
+
resourceLoadTime: Math.round(estimatedLCP * 0.6),
|
|
1305
|
+
renderDelay: Math.round(estimatedLCP * 0.4)
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
scoreLCP(value) {
|
|
1309
|
+
if (value <= 2500)
|
|
1310
|
+
return 100;
|
|
1311
|
+
if (value <= 4000)
|
|
1312
|
+
return 90;
|
|
1313
|
+
if (value <= 6000)
|
|
1314
|
+
return 70;
|
|
1315
|
+
return 50;
|
|
1316
|
+
}
|
|
1317
|
+
evaluateLCP(result) {
|
|
1318
|
+
if (!result.LCP)
|
|
1319
|
+
return;
|
|
1320
|
+
if (result.LCP.value > 4000) {
|
|
1321
|
+
result.recommendations.push("LCP exceeds 4s - optimize server response time and resource loading");
|
|
1322
|
+
result.score -= 20;
|
|
1323
|
+
}
|
|
1324
|
+
else if (result.LCP.value > 2500) {
|
|
1325
|
+
result.recommendations.push("LCP could be improved - consider preloading critical resources");
|
|
1326
|
+
result.score -= 10;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
measureINP(projectRoot) {
|
|
1330
|
+
const srcPath = path.join(projectRoot, "src");
|
|
1331
|
+
let estimatedINP = 200;
|
|
1332
|
+
if (fs.existsSync(srcPath)) {
|
|
1333
|
+
const files = this.findCodeFiles(projectRoot);
|
|
1334
|
+
let eventHandlers = 0;
|
|
1335
|
+
for (const file of files) {
|
|
1336
|
+
try {
|
|
1337
|
+
const content = fs.readFileSync(file, "utf8");
|
|
1338
|
+
const handlers = content.match(/\.addEventListener\(|onClick|onChange|onSubmit/g) || [];
|
|
1339
|
+
eventHandlers += handlers.length;
|
|
1340
|
+
const heavyHandlers = content.match(/async\s+\w+\s*\([^)]*\)\s*\{[\s\S]{200,}?await\s+/g) || [];
|
|
1341
|
+
if (heavyHandlers.length > 0) {
|
|
1342
|
+
estimatedINP += heavyHandlers.length * 100;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
catch {
|
|
1346
|
+
// Skip unreadable files
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
if (eventHandlers > 50) {
|
|
1350
|
+
estimatedINP += 50;
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return {
|
|
1354
|
+
value: estimatedINP,
|
|
1355
|
+
score: this.scoreINP(estimatedINP),
|
|
1356
|
+
interactionType: "click/keypress",
|
|
1357
|
+
processingTime: Math.round(estimatedINP * 0.7),
|
|
1358
|
+
presentationDelay: Math.round(estimatedINP * 0.3)
|
|
1359
|
+
};
|
|
1360
|
+
}
|
|
1361
|
+
scoreINP(value) {
|
|
1362
|
+
if (value <= 200)
|
|
1363
|
+
return 100;
|
|
1364
|
+
if (value <= 500)
|
|
1365
|
+
return 80;
|
|
1366
|
+
if (value <= 1000)
|
|
1367
|
+
return 60;
|
|
1368
|
+
return 40;
|
|
1369
|
+
}
|
|
1370
|
+
evaluateINP(result) {
|
|
1371
|
+
if (!result.INP)
|
|
1372
|
+
return;
|
|
1373
|
+
if (result.INP.value > 500) {
|
|
1374
|
+
result.recommendations.push("INP exceeds 500ms - break up long tasks and defer non-critical work");
|
|
1375
|
+
result.score -= 15;
|
|
1376
|
+
}
|
|
1377
|
+
else if (result.INP.value > 200) {
|
|
1378
|
+
result.recommendations.push("INP could be improved - optimize event handlers and reduce main thread work");
|
|
1379
|
+
result.score -= 5;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
measureCLS(projectRoot) {
|
|
1383
|
+
const srcPath = path.join(projectRoot, "src");
|
|
1384
|
+
let estimatedCLS = 0.05;
|
|
1385
|
+
const sources = [];
|
|
1386
|
+
if (fs.existsSync(srcPath)) {
|
|
1387
|
+
const files = this.findCodeFiles(projectRoot);
|
|
1388
|
+
for (const file of files) {
|
|
1389
|
+
try {
|
|
1390
|
+
const content = fs.readFileSync(file, "utf8");
|
|
1391
|
+
const imagesWithoutDimensions = content.match(/<img(?![^>]*\b(width|height)=)/gi) || [];
|
|
1392
|
+
if (imagesWithoutDimensions.length > 0) {
|
|
1393
|
+
estimatedCLS += imagesWithoutDimensions.length * 0.1;
|
|
1394
|
+
sources.push(`${imagesWithoutDimensions.length} images without dimensions`);
|
|
1395
|
+
}
|
|
1396
|
+
const dynamicAds = content.match(/<div[^>]*class="[^"]*(?:ad|banner|advertisement)[^"]*"/gi) || [];
|
|
1397
|
+
if (dynamicAds.length > 0) {
|
|
1398
|
+
estimatedCLS += dynamicAds.length * 0.15;
|
|
1399
|
+
sources.push(`${dynamicAds.length} dynamic ad containers`);
|
|
1400
|
+
}
|
|
1401
|
+
const fontLoads = content.match(/@font-face|font-display:\s*swap/gi) || [];
|
|
1402
|
+
if (fontLoads.length === 0) {
|
|
1403
|
+
estimatedCLS += 0.05;
|
|
1404
|
+
sources.push("No font-display strategy specified");
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
catch {
|
|
1408
|
+
// Skip unreadable files
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
return {
|
|
1413
|
+
value: Math.round(estimatedCLS * 1000) / 1000,
|
|
1414
|
+
score: this.scoreCLS(estimatedCLS),
|
|
1415
|
+
layoutShifts: Math.round(estimatedCLS * 10),
|
|
1416
|
+
unexpectedShifts: Math.round(estimatedCLS * 7),
|
|
1417
|
+
sources: [...new Set(sources)]
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
scoreCLS(value) {
|
|
1421
|
+
if (value <= 0.1)
|
|
1422
|
+
return 100;
|
|
1423
|
+
if (value <= 0.25)
|
|
1424
|
+
return 80;
|
|
1425
|
+
if (value <= 0.5)
|
|
1426
|
+
return 60;
|
|
1427
|
+
return 40;
|
|
1428
|
+
}
|
|
1429
|
+
evaluateCLS(result, checkAccessibility) {
|
|
1430
|
+
if (!result.CLS)
|
|
1431
|
+
return;
|
|
1432
|
+
if (result.CLS.value > 0.25) {
|
|
1433
|
+
result.recommendations.push("CLS exceeds 0.25 - set dimensions on images and reserve space for dynamic content");
|
|
1434
|
+
result.score -= 15;
|
|
1435
|
+
}
|
|
1436
|
+
else if (result.CLS.value > 0.1) {
|
|
1437
|
+
result.recommendations.push("CLS could be improved - ensure all media has explicit dimensions");
|
|
1438
|
+
result.score -= 5;
|
|
1439
|
+
}
|
|
1440
|
+
if (checkAccessibility && result.CLS.sources.length > 0) {
|
|
1441
|
+
result.recommendations.push("Accessibility issue: Layout shifts affect user experience - fix CLS sources");
|
|
1442
|
+
result.score -= 5;
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
calculateOverallScore(result) {
|
|
1446
|
+
let totalWeight = 0;
|
|
1447
|
+
let weightedScore = 0;
|
|
1448
|
+
if (result.LCP) {
|
|
1449
|
+
weightedScore += result.LCP.score * 0.35;
|
|
1450
|
+
totalWeight += 0.35;
|
|
1451
|
+
}
|
|
1452
|
+
if (result.INP) {
|
|
1453
|
+
weightedScore += result.INP.score * 0.35;
|
|
1454
|
+
totalWeight += 0.35;
|
|
1455
|
+
}
|
|
1456
|
+
if (result.CLS) {
|
|
1457
|
+
weightedScore += result.CLS.score * 0.30;
|
|
1458
|
+
totalWeight += 0.30;
|
|
1459
|
+
}
|
|
1460
|
+
result.score = totalWeight > 0 ? Math.round(weightedScore / totalWeight) : 100;
|
|
1461
|
+
}
|
|
1462
|
+
determineStatus(result) {
|
|
1463
|
+
if (result.score >= 90) {
|
|
1464
|
+
result.status = "good";
|
|
1465
|
+
}
|
|
1466
|
+
else if (result.score >= 50) {
|
|
1467
|
+
result.status = "needs-improvement";
|
|
1468
|
+
}
|
|
1469
|
+
else {
|
|
1470
|
+
result.status = "poor";
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
formatCoreWebVitalsResult(result) {
|
|
1474
|
+
const statusIcon = result.status === "good" ? "✅" :
|
|
1475
|
+
result.status === "needs-improvement" ? "⚠️" : "❌";
|
|
1476
|
+
let text = `${statusIcon} Core Web Vitals Analysis
|
|
1477
|
+
|
|
1478
|
+
**OVERALL SCORE:** ${result.score}/100 (${result.status.toUpperCase()})
|
|
1479
|
+
`;
|
|
1480
|
+
if (result.bundleAnalysis) {
|
|
1481
|
+
const bundle = result.bundleAnalysis;
|
|
1482
|
+
text += `
|
|
1483
|
+
**BUNDLE ANALYSIS**
|
|
1484
|
+
- Total Size: ${(bundle.totalSize / 1024 / 1024).toFixed(2)}MB
|
|
1485
|
+
- Gzipped Size: ${(bundle.gzippedSize / 1024 / 1024).toFixed(2)}MB
|
|
1486
|
+
- Largest Modules: ${bundle.largestModules.slice(0, 3).map(m => `${m.name} (${m.size}KB)`).join(", ") || "None"}
|
|
1487
|
+
`;
|
|
1488
|
+
}
|
|
1489
|
+
if (result.LCP) {
|
|
1490
|
+
const lcp = result.LCP;
|
|
1491
|
+
const lcpStatus = lcp.value <= 2500 ? "✅" : lcp.value <= 4000 ? "⚠️" : "❌";
|
|
1492
|
+
text += `
|
|
1493
|
+
**LCP (Largest Contentful Paint)** ${lcpStatus}
|
|
1494
|
+
- Value: ${(lcp.value / 1000).toFixed(2)}s
|
|
1495
|
+
- Score: ${lcp.score}/100
|
|
1496
|
+
- Resource Load: ${(lcp.resourceLoadTime / 1000).toFixed(2)}s
|
|
1497
|
+
- Render Delay: ${(lcp.renderDelay / 1000).toFixed(2)}s
|
|
1498
|
+
`;
|
|
1499
|
+
}
|
|
1500
|
+
if (result.INP) {
|
|
1501
|
+
const inp = result.INP;
|
|
1502
|
+
const inpStatus = inp.value <= 200 ? "✅" : inp.value <= 500 ? "⚠️" : "❌";
|
|
1503
|
+
text += `
|
|
1504
|
+
**INP (Interaction to Next Paint)** ${inpStatus}
|
|
1505
|
+
- Value: ${inp.value}ms
|
|
1506
|
+
- Score: ${inp.score}/100
|
|
1507
|
+
- Processing Time: ${inp.processingTime}ms
|
|
1508
|
+
- Presentation Delay: ${inp.presentationDelay}ms
|
|
1509
|
+
`;
|
|
1510
|
+
}
|
|
1511
|
+
if (result.CLS) {
|
|
1512
|
+
const cls = result.CLS;
|
|
1513
|
+
const clsStatus = cls.value <= 0.1 ? "✅" : cls.value <= 0.25 ? "⚠️" : "❌";
|
|
1514
|
+
text += `
|
|
1515
|
+
**CLS (Cumulative Layout Shift)** ${clsStatus}
|
|
1516
|
+
- Value: ${cls.value}
|
|
1517
|
+
- Score: ${cls.score}/100
|
|
1518
|
+
- Layout Shifts: ${cls.layoutShifts}
|
|
1519
|
+
- Sources: ${cls.sources.slice(0, 3).join(", ") || "None"}
|
|
1520
|
+
`;
|
|
1521
|
+
}
|
|
1522
|
+
text += `
|
|
1523
|
+
**RECOMMENDATIONS**
|
|
1524
|
+
${result.recommendations.slice(0, 5).map((r, i) => `${i + 1}. ${r}`).join("\n") || "No specific recommendations"}
|
|
1525
|
+
`;
|
|
1526
|
+
return text;
|
|
1527
|
+
}
|
|
1528
|
+
findCodeFiles(projectRoot, maxDepth = 10) {
|
|
1529
|
+
const extensions = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
1530
|
+
const files = [];
|
|
1531
|
+
const scanDir = (dir, depth) => {
|
|
1532
|
+
if (depth > maxDepth)
|
|
1533
|
+
return;
|
|
1534
|
+
try {
|
|
1535
|
+
const items = fs.readdirSync(dir);
|
|
1536
|
+
for (const item of items) {
|
|
1537
|
+
if (item.startsWith("."))
|
|
1538
|
+
continue;
|
|
1539
|
+
const fullPath = path.join(dir, item);
|
|
1540
|
+
try {
|
|
1541
|
+
const stat = fs.statSync(fullPath);
|
|
1542
|
+
if (stat.isDirectory()) {
|
|
1543
|
+
if (item !== "node_modules" && item !== "dist" && item !== "build" && item !== ".next") {
|
|
1544
|
+
scanDir(fullPath, depth + 1);
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
else if (stat.isFile() && extensions.some(ext => item.endsWith(ext))) {
|
|
1548
|
+
files.push(fullPath);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
catch {
|
|
1552
|
+
// Skip files we can't stat
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
catch {
|
|
1557
|
+
// Skip directories we can't read
|
|
1558
|
+
}
|
|
1559
|
+
};
|
|
1560
|
+
const srcPath = path.join(projectRoot, "src");
|
|
1561
|
+
if (fs.existsSync(srcPath)) {
|
|
1562
|
+
scanDir(srcPath, 0);
|
|
1563
|
+
}
|
|
1564
|
+
else {
|
|
1565
|
+
scanDir(projectRoot, 0);
|
|
1566
|
+
}
|
|
1567
|
+
return files.slice(0, 100);
|
|
1568
|
+
}
|
|
1569
|
+
async run() {
|
|
1570
|
+
const transport = new StdioServerTransport();
|
|
1571
|
+
await this.server.connect(transport);
|
|
1572
|
+
createGracefulShutdown({
|
|
1573
|
+
serverName: "performance-optimization.server",
|
|
1574
|
+
server: this.server,
|
|
1575
|
+
});
|
|
1576
|
+
frameworkLogger.log("mcp/performance-optimization", "server-started", "info", {
|
|
1577
|
+
uptime: Date.now() - this.startTime
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
1582
|
+
const server = new StringRayPerformanceOptimizationServer();
|
|
1583
|
+
server.run().catch((error) => {
|
|
1584
|
+
frameworkLogger.log("mcp/performance-optimization", "run", "error", { error: String(error) });
|
|
1585
|
+
});
|
|
1586
|
+
}
|
|
1587
|
+
export { StringRayPerformanceOptimizationServer };
|