claude-mpm 4.7.4__py3-none-any.whl → 4.18.2__py3-none-any.whl
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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
- claude_mpm/agents/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +106 -1
- claude_mpm/agents/OUTPUT_STYLE.md +329 -11
- claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
- claude_mpm/agents/agent_loader.py +17 -5
- claude_mpm/agents/frontmatter_validator.py +284 -253
- claude_mpm/agents/templates/README.md +465 -0
- claude_mpm/agents/templates/agent-manager.json +4 -1
- claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
- claude_mpm/agents/templates/api_qa.json +11 -2
- claude_mpm/agents/templates/circuit_breakers.md +638 -0
- claude_mpm/agents/templates/clerk-ops.json +12 -2
- claude_mpm/agents/templates/code_analyzer.json +8 -2
- claude_mpm/agents/templates/content-agent.json +358 -0
- claude_mpm/agents/templates/dart_engineer.json +15 -2
- claude_mpm/agents/templates/data_engineer.json +15 -2
- claude_mpm/agents/templates/documentation.json +10 -2
- claude_mpm/agents/templates/engineer.json +21 -1
- claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
- claude_mpm/agents/templates/git_file_tracking.md +584 -0
- claude_mpm/agents/templates/golang_engineer.json +270 -0
- claude_mpm/agents/templates/imagemagick.json +4 -1
- claude_mpm/agents/templates/java_engineer.json +346 -0
- claude_mpm/agents/templates/local_ops_agent.json +1227 -6
- claude_mpm/agents/templates/memory_manager.json +4 -1
- claude_mpm/agents/templates/nextjs_engineer.json +141 -133
- claude_mpm/agents/templates/ops.json +12 -2
- claude_mpm/agents/templates/php-engineer.json +270 -174
- claude_mpm/agents/templates/pm_examples.md +474 -0
- claude_mpm/agents/templates/pm_red_flags.md +240 -0
- claude_mpm/agents/templates/product_owner.json +338 -0
- claude_mpm/agents/templates/project_organizer.json +14 -4
- claude_mpm/agents/templates/prompt-engineer.json +13 -2
- claude_mpm/agents/templates/python_engineer.json +174 -81
- claude_mpm/agents/templates/qa.json +11 -2
- claude_mpm/agents/templates/react_engineer.json +16 -3
- claude_mpm/agents/templates/refactoring_engineer.json +12 -2
- claude_mpm/agents/templates/research.json +34 -21
- claude_mpm/agents/templates/response_format.md +583 -0
- claude_mpm/agents/templates/ruby-engineer.json +129 -192
- claude_mpm/agents/templates/rust_engineer.json +270 -0
- claude_mpm/agents/templates/security.json +10 -2
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/agents/templates/ticketing.json +10 -2
- claude_mpm/agents/templates/typescript_engineer.json +116 -125
- claude_mpm/agents/templates/validation_templates.md +312 -0
- claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
- claude_mpm/agents/templates/version_control.json +12 -2
- claude_mpm/agents/templates/web_qa.json +11 -2
- claude_mpm/agents/templates/web_ui.json +15 -2
- claude_mpm/cli/__init__.py +34 -614
- claude_mpm/cli/commands/agent_manager.py +25 -12
- claude_mpm/cli/commands/agent_state_manager.py +186 -0
- claude_mpm/cli/commands/agents.py +235 -148
- claude_mpm/cli/commands/agents_detect.py +380 -0
- claude_mpm/cli/commands/agents_recommend.py +309 -0
- claude_mpm/cli/commands/aggregate.py +7 -3
- claude_mpm/cli/commands/analyze.py +9 -4
- claude_mpm/cli/commands/analyze_code.py +7 -2
- claude_mpm/cli/commands/auto_configure.py +570 -0
- claude_mpm/cli/commands/config.py +47 -13
- claude_mpm/cli/commands/configure.py +419 -1571
- claude_mpm/cli/commands/configure_agent_display.py +261 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +167 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/local_deploy.py +537 -0
- claude_mpm/cli/commands/memory.py +54 -20
- claude_mpm/cli/commands/mpm_init.py +585 -196
- claude_mpm/cli/commands/mpm_init_handler.py +37 -3
- claude_mpm/cli/commands/search.py +170 -4
- claude_mpm/cli/commands/upgrade.py +152 -0
- claude_mpm/cli/executor.py +202 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +3 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parsers/__init__.py +7 -1
- claude_mpm/cli/parsers/agents_parser.py +9 -0
- claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
- claude_mpm/cli/parsers/base_parser.py +110 -3
- claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
- claude_mpm/cli/shared/output_formatters.py +28 -19
- claude_mpm/cli/startup.py +481 -0
- claude_mpm/cli/utils.py +52 -1
- claude_mpm/commands/mpm-agents-detect.md +168 -0
- claude_mpm/commands/mpm-agents-recommend.md +214 -0
- claude_mpm/commands/mpm-agents.md +75 -1
- claude_mpm/commands/mpm-auto-configure.md +217 -0
- claude_mpm/commands/mpm-help.md +163 -0
- claude_mpm/commands/mpm-init.md +148 -3
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +1 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/config/model_config.py +428 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/base_service.py +13 -12
- claude_mpm/core/enums.py +452 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/instruction_reinforcement_hook.py +2 -1
- claude_mpm/core/interactive_session.py +9 -3
- claude_mpm/core/log_manager.py +2 -0
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/oneshot_session.py +8 -4
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/core/output_style_manager.py +12 -192
- claude_mpm/core/service_registry.py +5 -1
- claude_mpm/core/types.py +2 -9
- claude_mpm/core/typing_utils.py +7 -6
- claude_mpm/dashboard/static/js/dashboard.js +0 -14
- claude_mpm/dashboard/templates/index.html +3 -41
- claude_mpm/hooks/__init__.py +20 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
- claude_mpm/hooks/failure_learning/__init__.py +60 -0
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
- claude_mpm/hooks/instruction_reinforcement.py +7 -2
- claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
- claude_mpm/hooks/kuzu_memory_hook.py +37 -12
- claude_mpm/hooks/kuzu_response_hook.py +183 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/__init__.py +18 -5
- claude_mpm/services/agents/auto_config_manager.py +796 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
- claude_mpm/services/agents/observers.py +547 -0
- claude_mpm/services/agents/recommender.py +568 -0
- claude_mpm/services/agents/registry/modification_tracker.py +5 -2
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/__init__.py +33 -1
- claude_mpm/services/core/interfaces/__init__.py +90 -3
- claude_mpm/services/core/interfaces/agent.py +184 -0
- claude_mpm/services/core/interfaces/health.py +172 -0
- claude_mpm/services/core/interfaces/model.py +281 -0
- claude_mpm/services/core/interfaces/process.py +372 -0
- claude_mpm/services/core/interfaces/project.py +121 -0
- claude_mpm/services/core/interfaces/restart.py +307 -0
- claude_mpm/services/core/interfaces/stability.py +260 -0
- claude_mpm/services/core/memory_manager.py +11 -24
- claude_mpm/services/core/models/__init__.py +79 -0
- claude_mpm/services/core/models/agent_config.py +381 -0
- claude_mpm/services/core/models/health.py +162 -0
- claude_mpm/services/core/models/process.py +235 -0
- claude_mpm/services/core/models/restart.py +302 -0
- claude_mpm/services/core/models/stability.py +264 -0
- claude_mpm/services/core/models/toolchain.py +306 -0
- claude_mpm/services/core/path_resolver.py +23 -7
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
- claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
- claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
- claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
- claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
- claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
- claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
- claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
- claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
- claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
- claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
- claude_mpm/services/diagnostics/models.py +19 -24
- claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
- claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
- claude_mpm/services/infrastructure/monitoring/base.py +5 -13
- claude_mpm/services/infrastructure/monitoring/network.py +7 -6
- claude_mpm/services/infrastructure/monitoring/process.py +13 -12
- claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/local_ops/__init__.py +163 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
- claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
- claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
- claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
- claude_mpm/services/local_ops/health_manager.py +430 -0
- claude_mpm/services/local_ops/log_monitor.py +396 -0
- claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
- claude_mpm/services/local_ops/process_manager.py +595 -0
- claude_mpm/services/local_ops/resource_monitor.py +331 -0
- claude_mpm/services/local_ops/restart_manager.py +401 -0
- claude_mpm/services/local_ops/restart_policy.py +387 -0
- claude_mpm/services/local_ops/state_manager.py +372 -0
- claude_mpm/services/local_ops/unified_manager.py +600 -0
- claude_mpm/services/mcp_config_manager.py +9 -4
- claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
- claude_mpm/services/mcp_gateway/core/base.py +18 -31
- claude_mpm/services/mcp_gateway/main.py +30 -0
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
- claude_mpm/services/mcp_service_verifier.py +1 -1
- claude_mpm/services/memory/failure_tracker.py +563 -0
- claude_mpm/services/memory_hook_service.py +165 -4
- claude_mpm/services/model/__init__.py +147 -0
- claude_mpm/services/model/base_provider.py +365 -0
- claude_mpm/services/model/claude_provider.py +412 -0
- claude_mpm/services/model/model_router.py +453 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/daemon_manager.py +3 -2
- claude_mpm/services/monitor/handlers/dashboard.py +2 -1
- claude_mpm/services/monitor/handlers/hooks.py +2 -1
- claude_mpm/services/monitor/management/lifecycle.py +3 -2
- claude_mpm/services/monitor/server.py +2 -1
- claude_mpm/services/project/__init__.py +23 -0
- claude_mpm/services/project/detection_strategies.py +719 -0
- claude_mpm/services/project/toolchain_analyzer.py +581 -0
- claude_mpm/services/self_upgrade_service.py +342 -0
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/session_manager.py +205 -1
- claude_mpm/services/shared/async_service_base.py +16 -27
- claude_mpm/services/shared/lifecycle_service_base.py +1 -14
- claude_mpm/services/socketio/handlers/__init__.py +5 -2
- claude_mpm/services/socketio/handlers/hook.py +13 -2
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/server/main.py +10 -8
- claude_mpm/services/subprocess_launcher_service.py +14 -5
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
- claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
- claude_mpm/services/unified/deployment_strategies/local.py +6 -5
- claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
- claude_mpm/services/unified/interfaces.py +3 -1
- claude_mpm/services/unified/unified_analyzer.py +14 -10
- claude_mpm/services/unified/unified_config.py +2 -1
- claude_mpm/services/unified/unified_deployment.py +9 -4
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +21 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +286 -0
- claude_mpm/skills/skill_manager.py +310 -0
- claude_mpm/storage/state_storage.py +15 -15
- claude_mpm/tools/code_tree_analyzer.py +177 -141
- claude_mpm/tools/code_tree_events.py +4 -2
- claude_mpm/utils/agent_dependency_loader.py +40 -20
- claude_mpm/utils/display_helper.py +260 -0
- claude_mpm/utils/git_analyzer.py +407 -0
- claude_mpm/utils/robust_installer.py +73 -19
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
- claude_mpm/dashboard/static/css/code-tree.css +0 -1639
- claude_mpm/dashboard/static/index-hub-backup.html +0 -713
- claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
- claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
- claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
- claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
- claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
- claude_mpm/services/project/analyzer_refactored.py +0 -450
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/top_level.txt +0 -0
|
@@ -1528,10 +1528,31 @@ class CodeTreeAnalyzer:
|
|
|
1528
1528
|
if not path.exists() or not path.is_file():
|
|
1529
1529
|
return {"error": f"Invalid file: {file_path}"}
|
|
1530
1530
|
|
|
1531
|
-
# Get language first (needed for return statement)
|
|
1532
1531
|
language = self._get_language(path)
|
|
1532
|
+
self._emit_analysis_start(path, language)
|
|
1533
1533
|
|
|
1534
|
-
#
|
|
1534
|
+
# Check cache
|
|
1535
|
+
file_hash = self._get_file_hash(path)
|
|
1536
|
+
cache_key = f"{file_path}:{file_hash}"
|
|
1537
|
+
|
|
1538
|
+
if cache_key in self.cache:
|
|
1539
|
+
nodes = self.cache[cache_key]
|
|
1540
|
+
self._emit_cache_hit(path)
|
|
1541
|
+
filtered_nodes = self._filter_nodes(nodes)
|
|
1542
|
+
else:
|
|
1543
|
+
nodes, filtered_nodes, duration = self._analyze_and_cache_file(
|
|
1544
|
+
path, language, cache_key
|
|
1545
|
+
)
|
|
1546
|
+
self._emit_analysis_complete(path, filtered_nodes, duration)
|
|
1547
|
+
|
|
1548
|
+
# Prepare final data structures
|
|
1549
|
+
final_nodes = self._prepare_final_nodes(nodes, filtered_nodes)
|
|
1550
|
+
elements = self._convert_nodes_to_elements(final_nodes)
|
|
1551
|
+
|
|
1552
|
+
return self._build_result(file_path, language, final_nodes, elements)
|
|
1553
|
+
|
|
1554
|
+
def _emit_analysis_start(self, path: Path, language: str) -> None:
|
|
1555
|
+
"""Emit analysis start event."""
|
|
1535
1556
|
if self.emitter:
|
|
1536
1557
|
from datetime import datetime
|
|
1537
1558
|
|
|
@@ -1546,179 +1567,194 @@ class CodeTreeAnalyzer:
|
|
|
1546
1567
|
},
|
|
1547
1568
|
)
|
|
1548
1569
|
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1570
|
+
def _emit_cache_hit(self, path: Path) -> None:
|
|
1571
|
+
"""Emit cache hit event."""
|
|
1572
|
+
if self.emitter:
|
|
1573
|
+
from datetime import datetime
|
|
1552
1574
|
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1575
|
+
self.emitter.emit(
|
|
1576
|
+
"info",
|
|
1577
|
+
{
|
|
1578
|
+
"type": "cache.hit",
|
|
1579
|
+
"file": str(path),
|
|
1580
|
+
"message": f"Using cached analysis for {path.name}",
|
|
1581
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1582
|
+
},
|
|
1583
|
+
)
|
|
1557
1584
|
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
"file": str(path),
|
|
1563
|
-
"message": f"Using cached analysis for {path.name}",
|
|
1564
|
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1565
|
-
},
|
|
1566
|
-
)
|
|
1567
|
-
else:
|
|
1568
|
-
# Analyze file
|
|
1569
|
-
if self.emitter:
|
|
1570
|
-
from datetime import datetime
|
|
1585
|
+
def _emit_cache_miss(self, path: Path) -> None:
|
|
1586
|
+
"""Emit cache miss event."""
|
|
1587
|
+
if self.emitter:
|
|
1588
|
+
from datetime import datetime
|
|
1571
1589
|
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1590
|
+
self.emitter.emit(
|
|
1591
|
+
"info",
|
|
1592
|
+
{
|
|
1593
|
+
"type": "cache.miss",
|
|
1594
|
+
"file": str(path),
|
|
1595
|
+
"message": f"Cache miss, analyzing fresh: {path.name}",
|
|
1596
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1597
|
+
},
|
|
1598
|
+
)
|
|
1581
1599
|
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1600
|
+
def _emit_parsing_start(self, path: Path) -> None:
|
|
1601
|
+
"""Emit parsing start event."""
|
|
1602
|
+
if self.emitter:
|
|
1603
|
+
from datetime import datetime
|
|
1604
|
+
|
|
1605
|
+
self.emitter.emit(
|
|
1606
|
+
"info",
|
|
1607
|
+
{
|
|
1608
|
+
"type": "analysis.parse",
|
|
1609
|
+
"file": str(path),
|
|
1610
|
+
"message": f"Parsing file content: {path.name}",
|
|
1611
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1612
|
+
},
|
|
1613
|
+
)
|
|
1588
1614
|
|
|
1589
|
-
|
|
1615
|
+
def _emit_node_found(self, node: CodeNode, path: Path) -> None:
|
|
1616
|
+
"""Emit node found event."""
|
|
1617
|
+
if self.emitter:
|
|
1618
|
+
from datetime import datetime
|
|
1590
1619
|
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1620
|
+
self.emitter.emit(
|
|
1621
|
+
"info",
|
|
1622
|
+
{
|
|
1623
|
+
"type": f"analysis.{node.node_type}",
|
|
1624
|
+
"name": node.name,
|
|
1625
|
+
"file": str(path),
|
|
1626
|
+
"line_start": node.line_start,
|
|
1627
|
+
"complexity": node.complexity,
|
|
1628
|
+
"message": f"Found {node.node_type}: {node.name}",
|
|
1629
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1630
|
+
},
|
|
1631
|
+
)
|
|
1594
1632
|
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1602
|
-
},
|
|
1603
|
-
)
|
|
1633
|
+
def _emit_analysis_complete(
|
|
1634
|
+
self, path: Path, filtered_nodes: list, duration: float
|
|
1635
|
+
) -> None:
|
|
1636
|
+
"""Emit analysis complete event."""
|
|
1637
|
+
if not self.emitter:
|
|
1638
|
+
return
|
|
1604
1639
|
|
|
1605
|
-
|
|
1606
|
-
|
|
1640
|
+
from datetime import datetime
|
|
1641
|
+
|
|
1642
|
+
stats = self._calculate_node_stats(filtered_nodes)
|
|
1643
|
+
self.emitter.emit(
|
|
1644
|
+
"info",
|
|
1645
|
+
{
|
|
1646
|
+
"type": "analysis.complete",
|
|
1647
|
+
"file": str(path),
|
|
1648
|
+
"stats": stats,
|
|
1649
|
+
"duration": duration,
|
|
1650
|
+
"message": f"Analysis complete: {stats['classes']} classes, {stats['functions']} functions, {stats['methods']} methods",
|
|
1651
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1652
|
+
},
|
|
1653
|
+
)
|
|
1654
|
+
self.emitter.emit_file_analyzed(str(path), filtered_nodes, duration)
|
|
1607
1655
|
|
|
1608
|
-
|
|
1609
|
-
|
|
1656
|
+
def _analyze_and_cache_file(
|
|
1657
|
+
self, path: Path, language: str, cache_key: str
|
|
1658
|
+
) -> tuple:
|
|
1659
|
+
"""Analyze file content and cache results."""
|
|
1660
|
+
self._emit_cache_miss(path)
|
|
1661
|
+
self._emit_parsing_start(path)
|
|
1610
1662
|
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
classes_count = 0
|
|
1614
|
-
functions_count = 0
|
|
1615
|
-
methods_count = 0
|
|
1663
|
+
# Select analyzer based on language
|
|
1664
|
+
analyzer = self._select_analyzer(language)
|
|
1616
1665
|
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
if self.emitter:
|
|
1622
|
-
from datetime import datetime
|
|
1666
|
+
# Perform analysis
|
|
1667
|
+
start_time = time.time()
|
|
1668
|
+
nodes = analyzer.analyze_file(path) if analyzer else []
|
|
1669
|
+
duration = time.time() - start_time
|
|
1623
1670
|
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
{
|
|
1627
|
-
"type": f"analysis.{node.node_type}",
|
|
1628
|
-
"name": node.name,
|
|
1629
|
-
"file": str(path),
|
|
1630
|
-
"line_start": node.line_start,
|
|
1631
|
-
"complexity": node.complexity,
|
|
1632
|
-
"message": f"Found {node.node_type}: {node.name}",
|
|
1633
|
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1634
|
-
},
|
|
1635
|
-
)
|
|
1671
|
+
# Cache results
|
|
1672
|
+
self.cache[cache_key] = nodes
|
|
1636
1673
|
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
classes_count += 1
|
|
1640
|
-
elif node.node_type == "function":
|
|
1641
|
-
functions_count += 1
|
|
1642
|
-
elif node.node_type == "method":
|
|
1643
|
-
methods_count += 1
|
|
1644
|
-
|
|
1645
|
-
filtered_nodes.append(
|
|
1646
|
-
{
|
|
1647
|
-
"name": node.name,
|
|
1648
|
-
"type": node.node_type,
|
|
1649
|
-
"line_start": node.line_start,
|
|
1650
|
-
"line_end": node.line_end,
|
|
1651
|
-
"complexity": node.complexity,
|
|
1652
|
-
"has_docstring": node.has_docstring,
|
|
1653
|
-
"signature": node.signature,
|
|
1654
|
-
}
|
|
1655
|
-
)
|
|
1674
|
+
# Filter and process nodes
|
|
1675
|
+
filtered_nodes = self._filter_and_emit_nodes(nodes, path)
|
|
1656
1676
|
|
|
1657
|
-
|
|
1658
|
-
if self.emitter:
|
|
1659
|
-
from datetime import datetime
|
|
1677
|
+
return nodes, filtered_nodes, duration
|
|
1660
1678
|
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
"functions": functions_count,
|
|
1669
|
-
"methods": methods_count,
|
|
1670
|
-
"total_nodes": len(filtered_nodes),
|
|
1671
|
-
},
|
|
1672
|
-
"duration": duration,
|
|
1673
|
-
"message": f"Analysis complete: {classes_count} classes, {functions_count} functions, {methods_count} methods",
|
|
1674
|
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
1675
|
-
},
|
|
1676
|
-
)
|
|
1679
|
+
def _select_analyzer(self, language: str):
|
|
1680
|
+
"""Select appropriate analyzer for language."""
|
|
1681
|
+
if language == "python":
|
|
1682
|
+
return self.python_analyzer
|
|
1683
|
+
if language in {"javascript", "typescript"}:
|
|
1684
|
+
return self.javascript_analyzer
|
|
1685
|
+
return self.generic_analyzer
|
|
1677
1686
|
|
|
1678
|
-
|
|
1687
|
+
def _filter_nodes(self, nodes: list) -> list:
|
|
1688
|
+
"""Filter nodes without emitting events."""
|
|
1689
|
+
return [self._node_to_dict(n) for n in nodes if not self._is_internal_node(n)]
|
|
1679
1690
|
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1691
|
+
def _filter_and_emit_nodes(self, nodes: list, path: Path) -> list:
|
|
1692
|
+
"""Filter nodes and emit events for each."""
|
|
1693
|
+
filtered_nodes = []
|
|
1694
|
+
for node in nodes:
|
|
1695
|
+
if not self._is_internal_node(node):
|
|
1696
|
+
self._emit_node_found(node, path)
|
|
1697
|
+
filtered_nodes.append(self._node_to_dict(node))
|
|
1698
|
+
return filtered_nodes
|
|
1699
|
+
|
|
1700
|
+
def _node_to_dict(self, node: CodeNode) -> dict:
|
|
1701
|
+
"""Convert CodeNode to dictionary."""
|
|
1702
|
+
return {
|
|
1703
|
+
"name": node.name,
|
|
1704
|
+
"type": node.node_type,
|
|
1705
|
+
"line_start": node.line_start,
|
|
1706
|
+
"line_end": node.line_end,
|
|
1707
|
+
"complexity": node.complexity,
|
|
1708
|
+
"has_docstring": node.has_docstring,
|
|
1709
|
+
"signature": node.signature,
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
def _calculate_node_stats(self, filtered_nodes: list) -> dict:
|
|
1713
|
+
"""Calculate statistics from filtered nodes."""
|
|
1714
|
+
classes_count = sum(1 for n in filtered_nodes if n["type"] == "class")
|
|
1715
|
+
functions_count = sum(1 for n in filtered_nodes if n["type"] == "function")
|
|
1716
|
+
methods_count = sum(1 for n in filtered_nodes if n["type"] == "method")
|
|
1717
|
+
return {
|
|
1718
|
+
"classes": classes_count,
|
|
1719
|
+
"functions": functions_count,
|
|
1720
|
+
"methods": methods_count,
|
|
1721
|
+
"total_nodes": len(filtered_nodes),
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
def _prepare_final_nodes(self, nodes: list, filtered_nodes: list) -> list:
|
|
1725
|
+
"""Prepare final nodes data structure."""
|
|
1726
|
+
if filtered_nodes:
|
|
1727
|
+
return filtered_nodes
|
|
1728
|
+
return [self._node_to_dict(n) for n in nodes if not self._is_internal_node(n)]
|
|
1698
1729
|
|
|
1699
|
-
|
|
1730
|
+
def _convert_nodes_to_elements(self, final_nodes: list) -> list:
|
|
1731
|
+
"""Convert nodes to elements format for dashboard."""
|
|
1700
1732
|
elements = []
|
|
1701
1733
|
for node in final_nodes:
|
|
1702
1734
|
element = {
|
|
1703
1735
|
"name": node["name"],
|
|
1704
1736
|
"type": node["type"],
|
|
1705
|
-
"line": node["line_start"],
|
|
1737
|
+
"line": node["line_start"],
|
|
1706
1738
|
"complexity": node["complexity"],
|
|
1707
1739
|
"signature": node.get("signature", ""),
|
|
1708
1740
|
"has_docstring": node.get("has_docstring", False),
|
|
1709
1741
|
}
|
|
1710
|
-
# Add methods if it's a class (for expandable tree)
|
|
1711
1742
|
if node["type"] == "class":
|
|
1712
|
-
element["methods"] = []
|
|
1743
|
+
element["methods"] = []
|
|
1713
1744
|
elements.append(element)
|
|
1745
|
+
return elements
|
|
1714
1746
|
|
|
1747
|
+
def _build_result(
|
|
1748
|
+
self, file_path: str, language: str, final_nodes: list, elements: list
|
|
1749
|
+
) -> dict:
|
|
1750
|
+
"""Build final result dictionary."""
|
|
1715
1751
|
return {
|
|
1716
1752
|
"path": file_path,
|
|
1717
1753
|
"language": language,
|
|
1718
|
-
"nodes": final_nodes,
|
|
1719
|
-
"elements": elements,
|
|
1754
|
+
"nodes": final_nodes,
|
|
1755
|
+
"elements": elements,
|
|
1720
1756
|
"complexity": sum(e["complexity"] for e in elements),
|
|
1721
|
-
"lines": len(elements),
|
|
1757
|
+
"lines": len(elements),
|
|
1722
1758
|
"stats": {
|
|
1723
1759
|
"classes": len([e for e in elements if e["type"] == "class"]),
|
|
1724
1760
|
"functions": len([e for e in elements if e["type"] == "function"]),
|
|
@@ -22,6 +22,8 @@ from dataclasses import asdict, dataclass
|
|
|
22
22
|
from datetime import datetime, timezone
|
|
23
23
|
from typing import Any, Dict, List, Optional
|
|
24
24
|
|
|
25
|
+
from ..core.enums import OperationResult
|
|
26
|
+
|
|
25
27
|
try:
|
|
26
28
|
import socketio
|
|
27
29
|
|
|
@@ -268,7 +270,7 @@ class CodeTreeEventEmitter:
|
|
|
268
270
|
"name": Path(file_path).name,
|
|
269
271
|
"language": language or "unknown",
|
|
270
272
|
"type": "file",
|
|
271
|
-
"status":
|
|
273
|
+
"status": OperationResult.PENDING,
|
|
272
274
|
},
|
|
273
275
|
)
|
|
274
276
|
|
|
@@ -287,7 +289,7 @@ class CodeTreeEventEmitter:
|
|
|
287
289
|
"nodes_count": nodes_count,
|
|
288
290
|
"duration": duration,
|
|
289
291
|
"type": "file",
|
|
290
|
-
"status":
|
|
292
|
+
"status": OperationResult.COMPLETED,
|
|
291
293
|
},
|
|
292
294
|
)
|
|
293
295
|
|
|
@@ -14,7 +14,7 @@ import logging
|
|
|
14
14
|
import subprocess
|
|
15
15
|
import sys
|
|
16
16
|
import time
|
|
17
|
-
from typing import Dict, List, Optional, Set, Tuple
|
|
17
|
+
from typing import Any, Dict, List, Optional, Set, Tuple
|
|
18
18
|
|
|
19
19
|
from packaging.requirements import InvalidRequirement, Requirement
|
|
20
20
|
|
|
@@ -72,7 +72,7 @@ class AgentDependencyLoader:
|
|
|
72
72
|
Returns:
|
|
73
73
|
Dictionary mapping agent IDs to their file paths
|
|
74
74
|
"""
|
|
75
|
-
deployed_agents = {}
|
|
75
|
+
deployed_agents: Dict[str, Path] = {}
|
|
76
76
|
claude_agents_dir = Path.cwd() / ".claude" / "agents"
|
|
77
77
|
|
|
78
78
|
if not claude_agents_dir.exists():
|
|
@@ -85,7 +85,7 @@ class AgentDependencyLoader:
|
|
|
85
85
|
deployed_agents[agent_id] = agent_file
|
|
86
86
|
logger.debug(f"Found deployed agent: {agent_id}")
|
|
87
87
|
|
|
88
|
-
logger.
|
|
88
|
+
logger.debug(f"Discovered {len(deployed_agents)} deployed agents")
|
|
89
89
|
self.deployed_agents = deployed_agents
|
|
90
90
|
return deployed_agents
|
|
91
91
|
|
|
@@ -121,7 +121,7 @@ class AgentDependencyLoader:
|
|
|
121
121
|
logger.warning(f"Failed to load config for {agent_id}: {e}")
|
|
122
122
|
|
|
123
123
|
self.agent_dependencies = agent_dependencies
|
|
124
|
-
logger.
|
|
124
|
+
logger.debug(f"Loaded dependencies for {len(agent_dependencies)} agents")
|
|
125
125
|
return agent_dependencies
|
|
126
126
|
|
|
127
127
|
def check_python_dependency(self, package_spec: str) -> Tuple[bool, Optional[str]]:
|
|
@@ -409,7 +409,7 @@ class AgentDependencyLoader:
|
|
|
409
409
|
Returns:
|
|
410
410
|
Analysis results including missing and satisfied dependencies
|
|
411
411
|
"""
|
|
412
|
-
results = {
|
|
412
|
+
results: Dict[str, Any] = {
|
|
413
413
|
"agents": {},
|
|
414
414
|
"summary": {
|
|
415
415
|
"total_agents": len(self.deployed_agents),
|
|
@@ -422,7 +422,7 @@ class AgentDependencyLoader:
|
|
|
422
422
|
}
|
|
423
423
|
|
|
424
424
|
for agent_id, deps in self.agent_dependencies.items():
|
|
425
|
-
agent_result = {
|
|
425
|
+
agent_result: Dict[str, Dict[str, List[str]]] = {
|
|
426
426
|
"python": {"satisfied": [], "missing": [], "outdated": []},
|
|
427
427
|
"system": {"satisfied": [], "missing": []},
|
|
428
428
|
}
|
|
@@ -476,8 +476,8 @@ class AgentDependencyLoader:
|
|
|
476
476
|
"""
|
|
477
477
|
import sys
|
|
478
478
|
|
|
479
|
-
compatible = []
|
|
480
|
-
incompatible = []
|
|
479
|
+
compatible: List[str] = []
|
|
480
|
+
incompatible: List[str] = []
|
|
481
481
|
|
|
482
482
|
for dep in dependencies:
|
|
483
483
|
try:
|
|
@@ -593,20 +593,37 @@ class AgentDependencyLoader:
|
|
|
593
593
|
try:
|
|
594
594
|
cmd = [sys.executable, "-m", "pip", "install"]
|
|
595
595
|
|
|
596
|
-
# Check
|
|
596
|
+
# Check environment and add appropriate flags
|
|
597
|
+
import os
|
|
597
598
|
import sysconfig
|
|
598
599
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
600
|
+
# Check if in virtualenv
|
|
601
|
+
in_virtualenv = (
|
|
602
|
+
(hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix)
|
|
603
|
+
or (hasattr(sys, "real_prefix"))
|
|
604
|
+
or (os.environ.get("VIRTUAL_ENV") is not None)
|
|
605
|
+
)
|
|
602
606
|
|
|
603
|
-
if
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
)
|
|
609
|
-
|
|
607
|
+
if in_virtualenv:
|
|
608
|
+
# In virtualenv - no special flags needed
|
|
609
|
+
logger.debug("Installing in virtualenv (no special flags)")
|
|
610
|
+
else:
|
|
611
|
+
# Check for PEP 668 managed environment
|
|
612
|
+
stdlib_path = sysconfig.get_path("stdlib")
|
|
613
|
+
marker_file = Path(stdlib_path) / "EXTERNALLY-MANAGED"
|
|
614
|
+
parent_marker = marker_file.parent.parent / "EXTERNALLY-MANAGED"
|
|
615
|
+
|
|
616
|
+
if marker_file.exists() or parent_marker.exists():
|
|
617
|
+
logger.warning(
|
|
618
|
+
"PEP 668 managed environment detected. "
|
|
619
|
+
"Installing with --break-system-packages flag. "
|
|
620
|
+
"Consider using a virtual environment instead."
|
|
621
|
+
)
|
|
622
|
+
cmd.append("--break-system-packages")
|
|
623
|
+
else:
|
|
624
|
+
# Normal system Python - use --user
|
|
625
|
+
cmd.append("--user")
|
|
626
|
+
logger.debug("Installing with --user flag")
|
|
610
627
|
|
|
611
628
|
cmd.extend(compatible)
|
|
612
629
|
|
|
@@ -946,13 +963,16 @@ class AgentDependencyLoader:
|
|
|
946
963
|
|
|
947
964
|
def check_deployed_agent_dependencies(
|
|
948
965
|
auto_install: bool = False, verbose: bool = False
|
|
949
|
-
) ->
|
|
966
|
+
) -> int:
|
|
950
967
|
"""
|
|
951
968
|
Check dependencies for currently deployed agents.
|
|
952
969
|
|
|
953
970
|
Args:
|
|
954
971
|
auto_install: If True, automatically install missing Python dependencies
|
|
955
972
|
verbose: If True, enable verbose logging
|
|
973
|
+
|
|
974
|
+
Returns:
|
|
975
|
+
Status code: 0 if all dependencies satisfied, 1 if missing dependencies
|
|
956
976
|
"""
|
|
957
977
|
if verbose:
|
|
958
978
|
logging.getLogger().setLevel(logging.DEBUG)
|