claude-mpm 4.1.26__py3-none-any.whl → 5.0.9__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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +20 -5
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
- claude_mpm/agents/BASE_DOCUMENTATION.md +53 -0
- claude_mpm/agents/BASE_ENGINEER.md +658 -0
- claude_mpm/agents/BASE_OPS.md +219 -0
- claude_mpm/agents/BASE_PM.md +432 -158
- claude_mpm/agents/BASE_PROMPT_ENGINEER.md +787 -0
- claude_mpm/agents/BASE_QA.md +167 -0
- claude_mpm/agents/BASE_RESEARCH.md +53 -0
- claude_mpm/agents/OUTPUT_STYLE.md +254 -29
- claude_mpm/agents/PM_INSTRUCTIONS.md +969 -0
- claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +1322 -0
- claude_mpm/agents/WORKFLOW.md +355 -191
- claude_mpm/agents/__init__.py +6 -0
- claude_mpm/agents/agent_loader.py +41 -14
- claude_mpm/agents/agent_loader_integration.py +3 -2
- claude_mpm/agents/async_agent_loader.py +3 -3
- claude_mpm/agents/base_agent.json +6 -3
- claude_mpm/agents/base_agent_loader.py +21 -44
- claude_mpm/agents/frontmatter_validator.py +292 -252
- claude_mpm/agents/system_agent_config.py +3 -2
- claude_mpm/agents/templates/README.md +465 -0
- claude_mpm/agents/templates/circuit-breakers.md +1005 -0
- claude_mpm/agents/templates/context-management-examples.md +544 -0
- claude_mpm/agents/templates/git-file-tracking.md +584 -0
- claude_mpm/agents/templates/pm-examples.md +474 -0
- claude_mpm/agents/templates/pm-red-flags.md +310 -0
- claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
- claude_mpm/agents/templates/research-gate-examples.md +669 -0
- claude_mpm/agents/templates/response-format.md +583 -0
- claude_mpm/agents/templates/structured-questions-examples.md +615 -0
- claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
- claude_mpm/agents/templates/ticketing-examples.md +277 -0
- claude_mpm/agents/templates/validation-templates.md +312 -0
- claude_mpm/cli/__init__.py +72 -376
- claude_mpm/cli/commands/__init__.py +4 -0
- claude_mpm/cli/commands/agent_manager.py +675 -20
- claude_mpm/cli/commands/agent_source.py +774 -0
- claude_mpm/cli/commands/agent_state_manager.py +344 -0
- claude_mpm/cli/commands/agents.py +1673 -178
- claude_mpm/cli/commands/agents_cleanup.py +210 -0
- claude_mpm/cli/commands/agents_detect.py +380 -0
- claude_mpm/cli/commands/agents_discover.py +338 -0
- claude_mpm/cli/commands/agents_recommend.py +309 -0
- claude_mpm/cli/commands/aggregate.py +11 -7
- claude_mpm/cli/commands/analyze.py +18 -13
- claude_mpm/cli/commands/analyze_code.py +8 -4
- claude_mpm/cli/commands/auto_configure.py +566 -0
- claude_mpm/cli/commands/cleanup.py +12 -12
- claude_mpm/cli/commands/config.py +54 -17
- claude_mpm/cli/commands/configure.py +1184 -1055
- 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 +184 -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/dashboard.py +50 -52
- claude_mpm/cli/commands/debug.py +19 -19
- claude_mpm/cli/commands/doctor.py +51 -7
- claude_mpm/cli/commands/hook_errors.py +277 -0
- claude_mpm/cli/commands/info.py +3 -4
- claude_mpm/cli/commands/local_deploy.py +534 -0
- claude_mpm/cli/commands/mcp.py +17 -10
- claude_mpm/cli/commands/mcp_command_router.py +11 -0
- claude_mpm/cli/commands/mcp_config.py +154 -0
- claude_mpm/cli/commands/mcp_external_commands.py +249 -0
- claude_mpm/cli/commands/mcp_install_commands.py +101 -32
- claude_mpm/cli/commands/mcp_pipx_config.py +2 -2
- claude_mpm/cli/commands/mcp_setup_external.py +868 -0
- claude_mpm/cli/commands/memory.py +55 -21
- claude_mpm/cli/commands/monitor.py +160 -70
- claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
- claude_mpm/cli/commands/mpm_init/core.py +573 -0
- claude_mpm/cli/commands/mpm_init/display.py +341 -0
- claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
- claude_mpm/cli/commands/mpm_init/modes.py +397 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
- claude_mpm/cli/commands/mpm_init_cli.py +396 -0
- claude_mpm/cli/commands/mpm_init_handler.py +114 -4
- claude_mpm/cli/commands/postmortem.py +401 -0
- claude_mpm/cli/commands/run.py +252 -167
- claude_mpm/cli/commands/search.py +458 -0
- claude_mpm/cli/commands/skill_source.py +694 -0
- claude_mpm/cli/commands/skills.py +1225 -0
- claude_mpm/cli/commands/uninstall.py +176 -0
- claude_mpm/cli/commands/upgrade.py +152 -0
- claude_mpm/cli/commands/verify.py +119 -0
- claude_mpm/cli/executor.py +279 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +21 -0
- claude_mpm/cli/interactive/agent_wizard.py +1872 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parser.py +79 -2
- claude_mpm/cli/parsers/__init__.py +7 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +161 -1
- claude_mpm/cli/parsers/agent_source_parser.py +171 -0
- claude_mpm/cli/parsers/agents_parser.py +369 -1
- claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
- claude_mpm/cli/parsers/base_parser.py +196 -3
- claude_mpm/cli/parsers/config_parser.py +96 -43
- claude_mpm/cli/parsers/configure_parser.py +11 -15
- claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
- claude_mpm/cli/parsers/mcp_parser.py +15 -0
- claude_mpm/cli/parsers/monitor_parser.py +12 -2
- claude_mpm/cli/parsers/mpm_init_parser.py +179 -9
- claude_mpm/cli/parsers/run_parser.py +5 -0
- claude_mpm/cli/parsers/search_parser.py +245 -0
- claude_mpm/cli/parsers/skill_source_parser.py +169 -0
- claude_mpm/cli/parsers/skills_parser.py +282 -0
- claude_mpm/cli/parsers/source_parser.py +138 -0
- claude_mpm/cli/shared/argument_patterns.py +20 -13
- claude_mpm/cli/shared/base_command.py +2 -2
- claude_mpm/cli/shared/output_formatters.py +28 -19
- claude_mpm/cli/startup.py +994 -0
- claude_mpm/cli/startup_display.py +480 -0
- claude_mpm/cli/startup_logging.py +179 -13
- claude_mpm/cli/utils.py +54 -3
- claude_mpm/cli_module/commands.py +1 -1
- claude_mpm/commands/mpm-agents-auto-configure.md +278 -0
- claude_mpm/commands/mpm-agents-detect.md +177 -0
- claude_mpm/commands/mpm-agents-list.md +131 -0
- claude_mpm/commands/mpm-agents-recommend.md +223 -0
- claude_mpm/commands/mpm-config-view.md +150 -0
- claude_mpm/commands/mpm-doctor.md +9 -0
- claude_mpm/commands/mpm-help.md +297 -5
- claude_mpm/commands/mpm-init.md +401 -17
- claude_mpm/commands/mpm-monitor.md +418 -0
- claude_mpm/commands/mpm-postmortem.md +123 -0
- claude_mpm/commands/mpm-session-resume.md +381 -0
- claude_mpm/commands/mpm-status.md +79 -8
- claude_mpm/commands/mpm-ticket-organize.md +304 -0
- claude_mpm/commands/mpm-ticket-view.md +552 -0
- claude_mpm/commands/mpm-version.md +122 -0
- claude_mpm/commands/mpm.md +12 -0
- claude_mpm/config/agent_config.py +4 -4
- claude_mpm/config/agent_presets.py +488 -0
- claude_mpm/config/agent_sources.py +325 -0
- claude_mpm/config/experimental_features.py +7 -7
- claude_mpm/config/model_config.py +428 -0
- claude_mpm/config/paths.py +3 -2
- claude_mpm/config/skill_presets.py +392 -0
- claude_mpm/config/skill_sources.py +590 -0
- claude_mpm/config/socketio_config.py +3 -3
- claude_mpm/constants.py +28 -1
- claude_mpm/core/__init__.py +53 -17
- claude_mpm/core/agent_name_normalizer.py +3 -2
- claude_mpm/core/agent_registry.py +2 -2
- claude_mpm/core/agent_session_manager.py +10 -10
- claude_mpm/core/api_validator.py +330 -0
- claude_mpm/core/base_service.py +33 -23
- claude_mpm/core/cache.py +9 -9
- claude_mpm/core/claude_runner.py +24 -42
- claude_mpm/core/config.py +101 -8
- claude_mpm/core/config_aliases.py +7 -6
- claude_mpm/core/constants.py +66 -1
- claude_mpm/core/container.py +11 -5
- claude_mpm/core/enums.py +452 -0
- claude_mpm/core/error_handler.py +623 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/file_utils.py +764 -0
- claude_mpm/core/framework/__init__.py +25 -0
- claude_mpm/core/framework/formatters/__init__.py +11 -0
- claude_mpm/core/framework/formatters/capability_generator.py +367 -0
- claude_mpm/core/framework/formatters/content_formatter.py +288 -0
- claude_mpm/core/framework/formatters/context_generator.py +185 -0
- claude_mpm/core/framework/loaders/__init__.py +13 -0
- claude_mpm/core/framework/loaders/agent_loader.py +210 -0
- claude_mpm/core/framework/loaders/file_loader.py +176 -0
- claude_mpm/core/framework/loaders/instruction_loader.py +181 -0
- claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
- claude_mpm/core/framework/processors/__init__.py +11 -0
- claude_mpm/core/framework/processors/memory_processor.py +230 -0
- claude_mpm/core/framework/processors/metadata_processor.py +146 -0
- claude_mpm/core/framework/processors/template_processor.py +244 -0
- claude_mpm/core/framework_loader.py +321 -1631
- claude_mpm/core/hook_error_memory.py +381 -0
- claude_mpm/core/hook_manager.py +49 -8
- claude_mpm/core/injectable_service.py +11 -8
- claude_mpm/core/instruction_reinforcement_hook.py +4 -3
- claude_mpm/core/interactive_session.py +146 -18
- claude_mpm/core/interfaces.py +56 -1
- claude_mpm/core/lazy.py +3 -3
- claude_mpm/core/log_manager.py +92 -23
- claude_mpm/core/logger.py +22 -15
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/logging_utils.py +520 -0
- claude_mpm/core/oneshot_session.py +122 -15
- claude_mpm/core/optimized_agent_loader.py +9 -9
- claude_mpm/core/optimized_startup.py +1 -1
- claude_mpm/core/output_style_manager.py +12 -192
- claude_mpm/core/pm_hook_interceptor.py +18 -12
- claude_mpm/core/protocols/__init__.py +23 -0
- claude_mpm/core/protocols/runner_protocol.py +103 -0
- claude_mpm/core/protocols/session_protocol.py +131 -0
- claude_mpm/core/service_registry.py +7 -3
- claude_mpm/core/session_manager.py +14 -12
- claude_mpm/core/shared/config_loader.py +1 -1
- claude_mpm/core/shared/singleton_manager.py +11 -4
- claude_mpm/core/socketio_pool.py +15 -15
- claude_mpm/core/system_context.py +38 -0
- claude_mpm/core/tool_access_control.py +3 -2
- claude_mpm/core/types.py +4 -11
- claude_mpm/core/typing_utils.py +7 -6
- claude_mpm/core/unified_agent_registry.py +115 -11
- claude_mpm/core/unified_config.py +6 -6
- claude_mpm/core/unified_paths.py +23 -20
- claude_mpm/dashboard/analysis_runner.py +4 -4
- claude_mpm/dashboard/api/simple_directory.py +261 -0
- claude_mpm/dashboard/static/css/activity.css +69 -69
- claude_mpm/dashboard/static/css/connection-status.css +10 -10
- claude_mpm/dashboard/static/css/dashboard.css +600 -18
- claude_mpm/dashboard/static/js/components/activity-tree.js +181 -195
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +105 -102
- claude_mpm/dashboard/static/js/components/agent-inference.js +34 -31
- claude_mpm/dashboard/static/js/components/build-tracker.js +67 -59
- claude_mpm/dashboard/static/js/components/code-simple.js +857 -0
- claude_mpm/dashboard/static/js/components/connection-debug.js +101 -101
- claude_mpm/dashboard/static/js/components/diff-viewer.js +891 -0
- claude_mpm/dashboard/static/js/components/event-processor.js +3 -0
- claude_mpm/dashboard/static/js/components/event-viewer.js +50 -13
- claude_mpm/dashboard/static/js/components/export-manager.js +3 -0
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +443 -0
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +690 -0
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +36 -16
- claude_mpm/dashboard/static/js/components/file-viewer.js +580 -0
- claude_mpm/dashboard/static/js/components/module-viewer.js +49 -23
- claude_mpm/dashboard/static/js/components/session-manager.js +19 -19
- claude_mpm/dashboard/static/js/components/socket-manager.js +5 -1
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +356 -41
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +520 -88
- claude_mpm/dashboard/static/js/components/working-directory.js +46 -11
- claude_mpm/dashboard/static/js/connection-manager.js +76 -76
- claude_mpm/dashboard/static/js/dashboard.js +309 -178
- claude_mpm/dashboard/static/js/extension-error-handler.js +22 -22
- claude_mpm/dashboard/static/js/socket-client.js +183 -139
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +185 -0
- claude_mpm/dashboard/static/socket.io.min.js +7 -0
- claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +7 -0
- claude_mpm/dashboard/templates/code_simple.html +153 -0
- claude_mpm/dashboard/templates/index.html +125 -122
- claude_mpm/experimental/cli_enhancements.py +5 -7
- claude_mpm/generators/agent_profile_generator.py +5 -3
- claude_mpm/hooks/__init__.py +37 -1
- claude_mpm/hooks/base_hook.py +5 -4
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
- claude_mpm/hooks/claude_hooks/event_handlers.py +24 -19
- claude_mpm/hooks/claude_hooks/hook_handler.py +29 -22
- claude_mpm/hooks/claude_hooks/installer.py +67 -22
- claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
- claude_mpm/hooks/claude_hooks/response_tracking.py +57 -17
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +62 -64
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +140 -76
- claude_mpm/hooks/claude_hooks/services/state_manager.py +11 -9
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
- claude_mpm/hooks/failure_learning/__init__.py +54 -0
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +230 -0
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +212 -0
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +281 -0
- claude_mpm/hooks/instruction_reinforcement.py +301 -0
- claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
- claude_mpm/hooks/kuzu_memory_hook.py +386 -0
- claude_mpm/hooks/kuzu_response_hook.py +179 -0
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/hooks/session_resume_hook.py +121 -0
- claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
- claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
- claude_mpm/hooks/tool_call_interceptor.py +8 -5
- claude_mpm/hooks/validation_hooks.py +3 -3
- claude_mpm/init.py +23 -4
- claude_mpm/models/agent_session.py +8 -6
- claude_mpm/models/git_repository.py +198 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/scripts/claude-hook-handler.sh +35 -9
- claude_mpm/scripts/launch_monitor.py +85 -0
- claude_mpm/scripts/mcp_server.py +3 -5
- claude_mpm/scripts/mpm_doctor.py +3 -2
- claude_mpm/scripts/socketio_daemon.py +159 -512
- claude_mpm/scripts/start_activity_logging.py +3 -1
- claude_mpm/services/__init__.py +144 -160
- claude_mpm/services/agents/__init__.py +18 -5
- claude_mpm/services/agents/agent_builder.py +56 -18
- claude_mpm/services/agents/agent_preset_service.py +238 -0
- claude_mpm/services/agents/agent_selection_service.py +484 -0
- claude_mpm/services/agents/auto_config_manager.py +796 -0
- claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
- claude_mpm/services/agents/cache_git_manager.py +621 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_deployment.py +164 -17
- claude_mpm/services/agents/deployment/agent_discovery_service.py +191 -41
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_format_converter.py +56 -12
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -7
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +3 -3
- claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_record_service.py +4 -4
- claude_mpm/services/agents/deployment/agent_restore_handler.py +1 -4
- claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_template_builder.py +939 -50
- claude_mpm/services/agents/deployment/agent_validator.py +31 -7
- claude_mpm/services/agents/deployment/agent_version_manager.py +8 -5
- claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +101 -15
- claude_mpm/services/agents/deployment/async_agent_deployment.py +3 -2
- claude_mpm/services/agents/deployment/deployment_config_loader.py +131 -7
- claude_mpm/services/agents/deployment/deployment_type_detector.py +10 -14
- claude_mpm/services/agents/deployment/deployment_wrapper.py +58 -0
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -3
- claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
- claude_mpm/services/agents/deployment/local_template_deployment.py +360 -0
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +249 -53
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +8 -7
- 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 +7 -5
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +10 -10
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +363 -0
- claude_mpm/services/agents/deployment/single_agent_deployer.py +2 -2
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +168 -43
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +2 -2
- claude_mpm/services/agents/deployment/validation/template_validator.py +64 -44
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/agents/git_source_manager.py +629 -0
- claude_mpm/services/agents/loading/agent_profile_loader.py +10 -9
- claude_mpm/services/agents/loading/base_agent_manager.py +16 -6
- claude_mpm/services/agents/loading/framework_agent_loader.py +11 -14
- claude_mpm/services/agents/local_template_manager.py +784 -0
- claude_mpm/services/agents/management/agent_capabilities_generator.py +3 -2
- claude_mpm/services/agents/management/agent_management_service.py +5 -5
- claude_mpm/services/agents/memory/agent_memory_manager.py +32 -29
- claude_mpm/services/agents/memory/content_manager.py +17 -9
- claude_mpm/services/agents/memory/memory_categorization_service.py +4 -2
- claude_mpm/services/agents/memory/memory_file_service.py +32 -6
- claude_mpm/services/agents/memory/memory_format_service.py +6 -4
- claude_mpm/services/agents/memory/memory_limits_service.py +4 -2
- claude_mpm/services/agents/memory/template_generator.py +3 -3
- claude_mpm/services/agents/observers.py +547 -0
- claude_mpm/services/agents/recommender.py +615 -0
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +3 -3
- claude_mpm/services/agents/registry/modification_tracker.py +30 -19
- claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
- claude_mpm/services/agents/sources/__init__.py +13 -0
- claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
- claude_mpm/services/agents/sources/git_source_sync_service.py +1087 -0
- claude_mpm/services/agents/startup_sync.py +239 -0
- claude_mpm/services/agents/toolchain_detector.py +474 -0
- claude_mpm/services/analysis/__init__.py +25 -0
- claude_mpm/services/analysis/postmortem_reporter.py +474 -0
- claude_mpm/services/analysis/postmortem_service.py +765 -0
- claude_mpm/services/async_session_logger.py +141 -98
- claude_mpm/services/claude_session_logger.py +82 -74
- claude_mpm/services/cli/agent_cleanup_service.py +5 -0
- claude_mpm/services/cli/agent_listing_service.py +5 -5
- claude_mpm/services/cli/agent_validation_service.py +3 -1
- claude_mpm/services/cli/memory_crud_service.py +12 -7
- claude_mpm/services/cli/memory_output_formatter.py +2 -2
- claude_mpm/services/cli/resume_service.py +617 -0
- claude_mpm/services/cli/session_manager.py +104 -13
- claude_mpm/services/cli/session_pause_manager.py +504 -0
- claude_mpm/services/cli/session_resume_helper.py +372 -0
- claude_mpm/services/cli/startup_checker.py +13 -10
- claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
- claude_mpm/services/command_deployment_service.py +209 -13
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/__init__.py +33 -1
- claude_mpm/services/core/base.py +31 -11
- claude_mpm/services/core/interfaces/__init__.py +88 -3
- claude_mpm/services/core/interfaces/agent.py +184 -0
- claude_mpm/services/core/interfaces/health.py +169 -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/interfaces.py +56 -1
- claude_mpm/services/core/memory_manager.py +92 -47
- claude_mpm/services/core/models/__init__.py +70 -0
- claude_mpm/services/core/models/agent_config.py +384 -0
- claude_mpm/services/core/models/health.py +162 -0
- claude_mpm/services/core/models/process.py +239 -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 +36 -14
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/__init__.py +8 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +30 -34
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
- claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
- claude_mpm/services/diagnostics/checks/common_issues_check.py +28 -27
- claude_mpm/services/diagnostics/checks/configuration_check.py +26 -25
- claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
- claude_mpm/services/diagnostics/checks/installation_check.py +165 -60
- claude_mpm/services/diagnostics/checks/instructions_check.py +21 -21
- claude_mpm/services/diagnostics/checks/mcp_check.py +57 -44
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +1058 -0
- claude_mpm/services/diagnostics/checks/monitor_check.py +24 -24
- claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
- claude_mpm/services/diagnostics/checks/startup_log_check.py +14 -11
- claude_mpm/services/diagnostics/diagnostic_runner.py +31 -13
- claude_mpm/services/diagnostics/doctor_reporter.py +305 -47
- claude_mpm/services/diagnostics/models.py +37 -21
- claude_mpm/services/event_aggregator.py +5 -3
- claude_mpm/services/event_bus/direct_relay.py +11 -7
- claude_mpm/services/event_bus/event_bus.py +51 -9
- claude_mpm/services/event_bus/relay.py +33 -14
- claude_mpm/services/events/consumers/dead_letter.py +7 -5
- claude_mpm/services/events/consumers/logging.py +1 -2
- claude_mpm/services/events/core.py +5 -6
- claude_mpm/services/events/producers/hook.py +6 -6
- claude_mpm/services/events/producers/system.py +8 -8
- claude_mpm/services/exceptions.py +5 -5
- claude_mpm/services/framework_claude_md_generator/__init__.py +1 -1
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +5 -5
- claude_mpm/services/framework_claude_md_generator/content_validator.py +2 -2
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +3 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
- claude_mpm/services/framework_claude_md_generator/version_manager.py +1 -1
- claude_mpm/services/git/__init__.py +21 -0
- claude_mpm/services/git/git_operations_service.py +494 -0
- claude_mpm/services/github/__init__.py +21 -0
- claude_mpm/services/github/github_cli_service.py +397 -0
- claude_mpm/services/hook_installer_service.py +506 -0
- claude_mpm/services/hook_service.py +5 -6
- claude_mpm/services/infrastructure/context_preservation.py +13 -11
- claude_mpm/services/infrastructure/daemon_manager.py +9 -9
- claude_mpm/services/infrastructure/logging.py +2 -2
- claude_mpm/services/infrastructure/monitoring/__init__.py +2 -6
- claude_mpm/services/infrastructure/monitoring/aggregator.py +13 -18
- 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 +8 -7
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/instructions/__init__.py +9 -0
- claude_mpm/services/instructions/instruction_cache_service.py +374 -0
- claude_mpm/services/local_ops/__init__.py +155 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +26 -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 +427 -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 +1542 -0
- claude_mpm/services/mcp_gateway/__init__.py +97 -93
- claude_mpm/services/mcp_gateway/auto_configure.py +43 -38
- claude_mpm/services/mcp_gateway/config/config_loader.py +3 -3
- claude_mpm/services/mcp_gateway/config/configuration.py +24 -5
- claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
- claude_mpm/services/mcp_gateway/core/base.py +20 -33
- claude_mpm/services/mcp_gateway/core/process_pool.py +591 -31
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +2 -2
- claude_mpm/services/mcp_gateway/core/startup_verification.py +3 -3
- claude_mpm/services/mcp_gateway/main.py +90 -15
- claude_mpm/services/mcp_gateway/registry/service_registry.py +4 -2
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +12 -9
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +5 -10
- claude_mpm/services/mcp_gateway/server/stdio_server.py +9 -17
- claude_mpm/services/mcp_gateway/tools/__init__.py +14 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +10 -9
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +654 -0
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +36 -34
- claude_mpm/services/mcp_gateway/tools/hello_world.py +8 -8
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +555 -0
- claude_mpm/services/mcp_gateway/utils/__init__.py +14 -0
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +160 -0
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +170 -0
- claude_mpm/services/mcp_service_verifier.py +732 -0
- claude_mpm/services/memory/builder.py +9 -8
- claude_mpm/services/memory/cache/shared_prompt_cache.py +2 -1
- claude_mpm/services/memory/cache/simple_cache.py +2 -2
- claude_mpm/services/memory/failure_tracker.py +578 -0
- claude_mpm/services/memory/indexed_memory.py +8 -8
- claude_mpm/services/memory/optimizer.py +8 -9
- claude_mpm/services/memory/router.py +3 -3
- 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 +452 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/__init__.py +20 -0
- claude_mpm/services/monitor/daemon.py +691 -0
- claude_mpm/services/monitor/daemon_manager.py +1040 -0
- claude_mpm/services/monitor/event_emitter.py +350 -0
- claude_mpm/services/monitor/handlers/__init__.py +21 -0
- claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
- claude_mpm/services/monitor/handlers/dashboard.py +299 -0
- claude_mpm/services/monitor/handlers/file.py +264 -0
- claude_mpm/services/monitor/handlers/hooks.py +512 -0
- claude_mpm/services/monitor/management/__init__.py +18 -0
- claude_mpm/services/monitor/management/health.py +124 -0
- claude_mpm/services/monitor/management/lifecycle.py +724 -0
- claude_mpm/services/monitor/server.py +817 -0
- claude_mpm/services/monitor_build_service.py +2 -2
- claude_mpm/services/native_agent_converter.py +356 -0
- claude_mpm/services/orphan_detection.py +786 -0
- claude_mpm/services/port_manager.py +3 -3
- claude_mpm/services/pr/__init__.py +14 -0
- claude_mpm/services/pr/pr_template_service.py +329 -0
- claude_mpm/services/project/__init__.py +23 -0
- claude_mpm/services/project/analyzer.py +3 -3
- claude_mpm/services/project/architecture_analyzer.py +5 -5
- claude_mpm/services/project/archive_manager.py +1045 -0
- claude_mpm/services/project/dependency_analyzer.py +4 -4
- claude_mpm/services/project/detection_strategies.py +719 -0
- claude_mpm/services/project/documentation_manager.py +554 -0
- claude_mpm/services/project/enhanced_analyzer.py +572 -0
- claude_mpm/services/project/metrics_collector.py +4 -4
- claude_mpm/services/project/project_organizer.py +1005 -0
- claude_mpm/services/project/registry.py +13 -7
- claude_mpm/services/project/toolchain_analyzer.py +583 -0
- claude_mpm/services/project_port_allocator.py +596 -0
- claude_mpm/services/response_tracker.py +21 -10
- claude_mpm/services/runner_configuration_service.py +17 -3
- claude_mpm/services/self_upgrade_service.py +500 -0
- claude_mpm/services/session_management_service.py +23 -9
- claude_mpm/services/session_manager.py +380 -0
- claude_mpm/services/shared/__init__.py +2 -1
- claude_mpm/services/shared/async_service_base.py +16 -27
- claude_mpm/services/shared/config_service_base.py +17 -14
- claude_mpm/services/shared/lifecycle_service_base.py +1 -14
- claude_mpm/services/shared/service_factory.py +8 -5
- claude_mpm/services/skills/__init__.py +18 -0
- claude_mpm/services/skills/git_skill_source_manager.py +1169 -0
- claude_mpm/services/skills/skill_discovery_service.py +568 -0
- claude_mpm/services/skills_config.py +547 -0
- claude_mpm/services/skills_deployer.py +955 -0
- claude_mpm/services/socketio/client_proxy.py +60 -5
- claude_mpm/services/socketio/dashboard_server.py +361 -0
- claude_mpm/services/socketio/event_normalizer.py +10 -6
- claude_mpm/services/socketio/handlers/__init__.py +5 -2
- claude_mpm/services/socketio/handlers/base.py +2 -2
- claude_mpm/services/socketio/handlers/code_analysis.py +90 -27
- claude_mpm/services/socketio/handlers/connection.py +22 -41
- claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
- claude_mpm/services/socketio/handlers/file.py +46 -10
- claude_mpm/services/socketio/handlers/git.py +9 -9
- claude_mpm/services/socketio/handlers/hook.py +29 -17
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/monitor_client.py +364 -0
- claude_mpm/services/socketio/server/broadcaster.py +9 -7
- claude_mpm/services/socketio/server/connection_manager.py +2 -2
- claude_mpm/services/socketio/server/core.py +142 -8
- claude_mpm/services/socketio/server/eventbus_integration.py +20 -14
- claude_mpm/services/socketio/server/main.py +24 -24
- claude_mpm/services/socketio_client_manager.py +4 -4
- claude_mpm/services/subprocess_launcher_service.py +19 -15
- claude_mpm/services/system_instructions_service.py +3 -5
- claude_mpm/services/ticket_services/formatter_service.py +1 -1
- claude_mpm/services/ticket_services/validation_service.py +5 -5
- claude_mpm/services/unified/__init__.py +65 -0
- claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +900 -0
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +745 -0
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
- claude_mpm/services/unified/config_strategies/__init__.py +175 -0
- claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
- claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
- claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
- claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
- claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
- claude_mpm/services/unified/deployment_strategies/base.py +553 -0
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
- claude_mpm/services/unified/deployment_strategies/local.py +607 -0
- claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
- claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
- claude_mpm/services/unified/interfaces.py +475 -0
- claude_mpm/services/unified/migration.py +509 -0
- claude_mpm/services/unified/strategies.py +534 -0
- claude_mpm/services/unified/unified_analyzer.py +542 -0
- claude_mpm/services/unified/unified_config.py +691 -0
- claude_mpm/services/unified/unified_deployment.py +466 -0
- claude_mpm/services/utility_service.py +6 -3
- claude_mpm/services/version_control/branch_strategy.py +2 -2
- claude_mpm/services/version_control/conflict_resolution.py +14 -8
- claude_mpm/services/version_control/git_operations.py +26 -24
- claude_mpm/services/version_control/semantic_versioning.py +14 -14
- claude_mpm/services/version_control/version_parser.py +14 -11
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/services/visualization/__init__.py +1 -5
- claude_mpm/services/visualization/mermaid_generator.py +2 -3
- claude_mpm/skills/__init__.py +42 -0
- claude_mpm/skills/agent_skills_injector.py +324 -0
- claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -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/infrastructure/env-manager/scripts/validate_env.py +576 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -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 +573 -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/testing/webapp-testing/examples/console_logging.py +35 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -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/skills/skills_registry.py +347 -0
- claude_mpm/skills/skills_service.py +739 -0
- claude_mpm/storage/state_storage.py +31 -31
- claude_mpm/templates/questions/__init__.py +38 -0
- claude_mpm/templates/questions/base.py +193 -0
- claude_mpm/templates/questions/pr_strategy.py +311 -0
- claude_mpm/templates/questions/project_init.py +385 -0
- claude_mpm/templates/questions/ticket_mgmt.py +394 -0
- claude_mpm/tools/__main__.py +9 -9
- claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
- claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
- claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
- claude_mpm/tools/code_tree_analyzer/core.py +380 -0
- claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
- claude_mpm/tools/code_tree_analyzer/events.py +168 -0
- claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
- claude_mpm/tools/code_tree_analyzer/models.py +39 -0
- claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
- claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
- claude_mpm/tools/code_tree_builder.py +6 -6
- claude_mpm/tools/code_tree_events.py +14 -10
- claude_mpm/tools/socketio_debug.py +11 -11
- claude_mpm/utils/agent_dependency_loader.py +184 -36
- claude_mpm/utils/agent_filters.py +288 -0
- claude_mpm/utils/common.py +544 -0
- claude_mpm/utils/config_manager.py +12 -6
- claude_mpm/utils/database_connector.py +298 -0
- claude_mpm/utils/dependency_cache.py +5 -3
- claude_mpm/utils/dependency_strategies.py +15 -10
- claude_mpm/utils/display_helper.py +260 -0
- claude_mpm/utils/environment_context.py +4 -3
- claude_mpm/utils/error_handler.py +5 -3
- claude_mpm/utils/file_utils.py +13 -14
- claude_mpm/utils/git_analyzer.py +407 -0
- claude_mpm/utils/gitignore.py +241 -0
- claude_mpm/utils/log_cleanup.py +627 -0
- claude_mpm/utils/migration.py +372 -0
- claude_mpm/utils/path_operations.py +7 -4
- claude_mpm/utils/progress.py +387 -0
- claude_mpm/utils/robust_installer.py +131 -24
- claude_mpm/utils/session_logging.py +2 -2
- claude_mpm/utils/structured_questions.py +619 -0
- claude_mpm/utils/subprocess_utils.py +9 -8
- claude_mpm/validation/agent_validator.py +6 -6
- claude_mpm/validation/frontmatter_validator.py +6 -6
- claude_mpm-5.0.9.dist-info/METADATA +1028 -0
- claude_mpm-5.0.9.dist-info/RECORD +864 -0
- {claude_mpm-4.1.26.dist-info → claude_mpm-5.0.9.dist-info}/entry_points.txt +1 -0
- claude_mpm/agents/INSTRUCTIONS.md +0 -261
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -17
- claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +0 -3
- claude_mpm/agents/templates/agent-manager.json +0 -270
- claude_mpm/agents/templates/agent-manager.md +0 -619
- claude_mpm/agents/templates/agentic_coder_optimizer.json +0 -222
- claude_mpm/agents/templates/api_qa.json +0 -171
- claude_mpm/agents/templates/code_analyzer.json +0 -95
- claude_mpm/agents/templates/data_engineer.json +0 -152
- claude_mpm/agents/templates/documentation.json +0 -175
- claude_mpm/agents/templates/engineer.json +0 -176
- claude_mpm/agents/templates/imagemagick.json +0 -261
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +0 -39
- claude_mpm/agents/templates/memory_manager.json +0 -155
- claude_mpm/agents/templates/ops.json +0 -175
- claude_mpm/agents/templates/project_organizer.json +0 -130
- claude_mpm/agents/templates/qa.json +0 -223
- claude_mpm/agents/templates/refactoring_engineer.json +0 -266
- claude_mpm/agents/templates/research.json +0 -163
- claude_mpm/agents/templates/security.json +0 -153
- claude_mpm/agents/templates/ticketing.json +0 -169
- claude_mpm/agents/templates/vercel_ops_agent.json +0 -281
- claude_mpm/agents/templates/version_control.json +0 -147
- claude_mpm/agents/templates/web_qa.json +0 -254
- claude_mpm/agents/templates/web_ui.json +0 -176
- claude_mpm/cli/commands/configure_tui.py +0 -1927
- claude_mpm/cli/commands/mpm_init.py +0 -594
- claude_mpm/cli/commands/socketio_monitor.py +0 -233
- claude_mpm/commands/mpm-agents.md +0 -12
- claude_mpm/commands/mpm-config.md +0 -18
- claude_mpm/commands/mpm-tickets.md +0 -102
- claude_mpm/dashboard/.claude-mpm/socketio-instances.json +0 -1
- claude_mpm/dashboard/static/built/components/activity-tree.js +0 -2
- claude_mpm/dashboard/static/built/components/agent-inference.js +0 -2
- claude_mpm/dashboard/static/built/components/code-tree.js +0 -2
- claude_mpm/dashboard/static/built/components/code-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/event-processor.js +0 -2
- claude_mpm/dashboard/static/built/components/event-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/export-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +0 -2
- claude_mpm/dashboard/static/built/components/hud-library-loader.js +0 -2
- claude_mpm/dashboard/static/built/components/hud-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/hud-visualizer.js +0 -2
- claude_mpm/dashboard/static/built/components/module-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/session-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/socket-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/ui-state-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/unified-data-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/working-directory.js +0 -2
- claude_mpm/dashboard/static/built/dashboard.js +0 -2
- claude_mpm/dashboard/static/built/socket-client.js +0 -2
- claude_mpm/dashboard/static/css/code-tree.css +0 -1408
- claude_mpm/dashboard/static/dist/components/activity-tree.js +0 -2
- claude_mpm/dashboard/static/dist/components/agent-inference.js +0 -2
- claude_mpm/dashboard/static/dist/components/code-tree.js +0 -2
- claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/event-processor.js +0 -2
- claude_mpm/dashboard/static/dist/components/event-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/export-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +0 -2
- claude_mpm/dashboard/static/dist/components/module-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/session-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/socket-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/unified-data-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/working-directory.js +0 -2
- claude_mpm/dashboard/static/dist/dashboard.js +0 -2
- claude_mpm/dashboard/static/dist/socket-client.js +0 -2
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -3220
- claude_mpm/dashboard/static/js/components/code-viewer.js +0 -480
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1040
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
- claude_mpm/scripts/socketio_daemon_hardened.py +0 -937
- claude_mpm/scripts/socketio_daemon_wrapper.py +0 -78
- claude_mpm/scripts/socketio_server_manager.py +0 -349
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
- claude_mpm/services/cli/dashboard_launcher.py +0 -423
- claude_mpm/services/cli/socketio_manager.py +0 -537
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +0 -286
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
- claude_mpm/services/project/analyzer_refactored.py +0 -450
- claude_mpm/tools/code_tree_analyzer.py +0 -1693
- claude_mpm-4.1.26.dist-info/METADATA +0 -332
- claude_mpm-4.1.26.dist-info/RECORD +0 -606
- {claude_mpm-4.1.26.dist-info → claude_mpm-5.0.9.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.26.dist-info → claude_mpm-5.0.9.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.26.dist-info → claude_mpm-5.0.9.dist-info}/top_level.txt +0 -0
|
@@ -1,35 +1,37 @@
|
|
|
1
|
-
"""Framework loader for Claude MPM."""
|
|
1
|
+
"""Framework loader for Claude MPM - Refactored modular version."""
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import locale
|
|
5
|
-
import logging
|
|
3
|
+
import asyncio
|
|
6
4
|
import os
|
|
7
|
-
import platform
|
|
8
|
-
import time
|
|
9
|
-
from datetime import datetime
|
|
10
5
|
from pathlib import Path
|
|
11
|
-
from typing import Any, Dict, Optional
|
|
12
|
-
|
|
13
|
-
# Import
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
6
|
+
from typing import Any, Dict, List, Optional, Set
|
|
7
|
+
|
|
8
|
+
# Import framework components
|
|
9
|
+
from claude_mpm.core.framework import (
|
|
10
|
+
AgentLoader,
|
|
11
|
+
CapabilityGenerator,
|
|
12
|
+
ContentFormatter,
|
|
13
|
+
ContextGenerator,
|
|
14
|
+
FileLoader,
|
|
15
|
+
InstructionLoader,
|
|
16
|
+
MemoryProcessor,
|
|
17
|
+
MetadataProcessor,
|
|
18
|
+
PackagedLoader,
|
|
19
|
+
TemplateProcessor,
|
|
20
|
+
)
|
|
21
|
+
from claude_mpm.core.logging_utils import get_logger
|
|
22
|
+
from claude_mpm.utils.imports import safe_import
|
|
26
23
|
|
|
27
|
-
# Import with fallback support
|
|
28
|
-
get_logger = safe_import("claude_mpm.core.logger", "core.logger", ["get_logger"])
|
|
24
|
+
# Import with fallback support
|
|
29
25
|
AgentRegistryAdapter = safe_import(
|
|
30
26
|
"claude_mpm.core.agent_registry", "core.agent_registry", ["AgentRegistryAdapter"]
|
|
31
27
|
)
|
|
32
28
|
|
|
29
|
+
# Import API validator
|
|
30
|
+
try:
|
|
31
|
+
from claude_mpm.core.api_validator import validate_api_keys
|
|
32
|
+
except ImportError:
|
|
33
|
+
from ..core.api_validator import validate_api_keys
|
|
34
|
+
|
|
33
35
|
# Import the service container and interfaces
|
|
34
36
|
try:
|
|
35
37
|
from claude_mpm.services.core.cache_manager import CacheManager
|
|
@@ -61,43 +63,13 @@ class FrameworkLoader:
|
|
|
61
63
|
"""
|
|
62
64
|
Load and prepare framework instructions for injection.
|
|
63
65
|
|
|
64
|
-
This
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
The framework loader supports custom instructions through .claude-mpm/ directories.
|
|
72
|
-
It NEVER reads from .claude/ directories to avoid conflicts with Claude Code.
|
|
73
|
-
|
|
74
|
-
File Loading Precedence (highest to lowest):
|
|
75
|
-
|
|
76
|
-
INSTRUCTIONS.md:
|
|
77
|
-
1. Project: ./.claude-mpm/INSTRUCTIONS.md
|
|
78
|
-
2. User: ~/.claude-mpm/INSTRUCTIONS.md
|
|
79
|
-
3. System: (built-in framework instructions)
|
|
80
|
-
|
|
81
|
-
WORKFLOW.md:
|
|
82
|
-
1. Project: ./.claude-mpm/WORKFLOW.md
|
|
83
|
-
2. User: ~/.claude-mpm/WORKFLOW.md
|
|
84
|
-
3. System: src/claude_mpm/agents/WORKFLOW.md
|
|
85
|
-
|
|
86
|
-
MEMORY.md:
|
|
87
|
-
1. Project: ./.claude-mpm/MEMORY.md
|
|
88
|
-
2. User: ~/.claude-mpm/MEMORY.md
|
|
89
|
-
3. System: src/claude_mpm/agents/MEMORY.md
|
|
90
|
-
|
|
91
|
-
Actual Memories:
|
|
92
|
-
- User: ~/.claude-mpm/memories/PM_memories.md
|
|
93
|
-
- Project: ./.claude-mpm/memories/PM_memories.md (overrides user)
|
|
94
|
-
- Agent memories: *_memories.md files (only loaded if agent is deployed)
|
|
95
|
-
|
|
96
|
-
Important Notes:
|
|
97
|
-
- Project-level files always override user-level files
|
|
98
|
-
- User-level files always override system defaults
|
|
99
|
-
- The framework NEVER reads from .claude/ directories
|
|
100
|
-
- Custom instructions are clearly labeled with their source level
|
|
66
|
+
This refactored version uses modular components for better maintainability
|
|
67
|
+
and testability while maintaining backward compatibility.
|
|
68
|
+
|
|
69
|
+
Components:
|
|
70
|
+
- Loaders: Handle file I/O and resource loading
|
|
71
|
+
- Formatters: Generate and format content sections
|
|
72
|
+
- Processors: Process metadata, templates, and memories
|
|
101
73
|
"""
|
|
102
74
|
|
|
103
75
|
def __init__(
|
|
@@ -105,35 +77,80 @@ class FrameworkLoader:
|
|
|
105
77
|
framework_path: Optional[Path] = None,
|
|
106
78
|
agents_dir: Optional[Path] = None,
|
|
107
79
|
service_container: Optional[ServiceContainer] = None,
|
|
80
|
+
config: Optional[Dict[str, Any]] = None,
|
|
108
81
|
):
|
|
109
82
|
"""
|
|
110
|
-
Initialize framework loader.
|
|
83
|
+
Initialize framework loader with modular components.
|
|
111
84
|
|
|
112
85
|
Args:
|
|
113
86
|
framework_path: Explicit path to framework (auto-detected if None)
|
|
114
87
|
agents_dir: Custom agents directory (overrides framework agents)
|
|
115
88
|
service_container: Optional service container for dependency injection
|
|
89
|
+
config: Optional configuration dictionary for API validation and other settings
|
|
116
90
|
"""
|
|
117
91
|
self.logger = get_logger("framework_loader")
|
|
118
92
|
self.agents_dir = agents_dir
|
|
119
93
|
self.framework_version = None
|
|
120
94
|
self.framework_last_modified = None
|
|
95
|
+
self.config = config or {}
|
|
121
96
|
|
|
122
|
-
#
|
|
97
|
+
# Validate API keys on startup (before any other initialization)
|
|
98
|
+
self._validate_api_keys()
|
|
99
|
+
|
|
100
|
+
# Initialize service container
|
|
123
101
|
self.container = service_container or get_global_container()
|
|
102
|
+
self._register_services()
|
|
103
|
+
|
|
104
|
+
# Resolve services from container
|
|
105
|
+
self._cache_manager = self.container.resolve(ICacheManager)
|
|
106
|
+
self._path_resolver = self.container.resolve(IPathResolver)
|
|
107
|
+
self._memory_manager = self.container.resolve(IMemoryManager)
|
|
108
|
+
|
|
109
|
+
# Initialize framework path
|
|
110
|
+
self.framework_path = (
|
|
111
|
+
framework_path or self._path_resolver.detect_framework_path()
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Initialize modular components
|
|
115
|
+
self._init_components()
|
|
116
|
+
|
|
117
|
+
# Keep cache TTL constants for backward compatibility
|
|
118
|
+
self._init_cache_ttl()
|
|
119
|
+
|
|
120
|
+
# Load framework content
|
|
121
|
+
self.framework_content = self._load_framework_content()
|
|
122
|
+
|
|
123
|
+
# Initialize agent registry
|
|
124
|
+
self.agent_registry = AgentRegistryAdapter(self.framework_path)
|
|
125
|
+
|
|
126
|
+
# Output style manager (deferred initialization)
|
|
127
|
+
self.output_style_manager = None
|
|
124
128
|
|
|
125
|
-
|
|
129
|
+
def _validate_api_keys(self) -> None:
|
|
130
|
+
"""Validate API keys if enabled in config."""
|
|
131
|
+
if self.config.get("validate_api_keys", True):
|
|
132
|
+
try:
|
|
133
|
+
self.logger.info("Validating configured API keys...")
|
|
134
|
+
validate_api_keys(config=self.config, strict=True)
|
|
135
|
+
self.logger.info("✅ API key validation completed successfully")
|
|
136
|
+
except ValueError as e:
|
|
137
|
+
self.logger.error(f"❌ API key validation failed: {e}")
|
|
138
|
+
raise
|
|
139
|
+
except Exception as e:
|
|
140
|
+
self.logger.error(f"❌ Unexpected error during API validation: {e}")
|
|
141
|
+
raise
|
|
142
|
+
|
|
143
|
+
def _register_services(self) -> None:
|
|
144
|
+
"""Register services in the container if not already registered."""
|
|
126
145
|
if not self.container.is_registered(ICacheManager):
|
|
127
|
-
self.container.register(ICacheManager, CacheManager, True)
|
|
146
|
+
self.container.register(ICacheManager, CacheManager, True)
|
|
128
147
|
|
|
129
148
|
if not self.container.is_registered(IPathResolver):
|
|
130
|
-
# PathResolver depends on CacheManager, so resolve it first
|
|
131
149
|
cache_manager = self.container.resolve(ICacheManager)
|
|
132
150
|
path_resolver = PathResolver(cache_manager=cache_manager)
|
|
133
151
|
self.container.register_instance(IPathResolver, path_resolver)
|
|
134
152
|
|
|
135
153
|
if not self.container.is_registered(IMemoryManager):
|
|
136
|
-
# MemoryManager depends on both CacheManager and PathResolver
|
|
137
154
|
cache_manager = self.container.resolve(ICacheManager)
|
|
138
155
|
path_resolver = self.container.resolve(IPathResolver)
|
|
139
156
|
memory_manager = MemoryManager(
|
|
@@ -141,18 +158,26 @@ class FrameworkLoader:
|
|
|
141
158
|
)
|
|
142
159
|
self.container.register_instance(IMemoryManager, memory_manager)
|
|
143
160
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
self.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
self.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
161
|
+
def _init_components(self) -> None:
|
|
162
|
+
"""Initialize modular components."""
|
|
163
|
+
# Loaders
|
|
164
|
+
self.file_loader = FileLoader()
|
|
165
|
+
self.packaged_loader = PackagedLoader()
|
|
166
|
+
self.instruction_loader = InstructionLoader(self.framework_path)
|
|
167
|
+
self.agent_loader = AgentLoader(self.framework_path)
|
|
168
|
+
|
|
169
|
+
# Formatters
|
|
170
|
+
self.content_formatter = ContentFormatter()
|
|
171
|
+
self.capability_generator = CapabilityGenerator()
|
|
172
|
+
self.context_generator = ContextGenerator()
|
|
173
|
+
|
|
174
|
+
# Processors
|
|
175
|
+
self.metadata_processor = MetadataProcessor()
|
|
176
|
+
self.template_processor = TemplateProcessor(self.framework_path)
|
|
177
|
+
self.memory_processor = MemoryProcessor()
|
|
178
|
+
|
|
179
|
+
def _init_cache_ttl(self) -> None:
|
|
180
|
+
"""Initialize cache TTL constants for backward compatibility."""
|
|
156
181
|
if hasattr(self._cache_manager, "capabilities_ttl"):
|
|
157
182
|
self.CAPABILITIES_CACHE_TTL = self._cache_manager.capabilities_ttl
|
|
158
183
|
self.DEPLOYED_AGENTS_CACHE_TTL = self._cache_manager.deployed_agents_ttl
|
|
@@ -165,430 +190,24 @@ class FrameworkLoader:
|
|
|
165
190
|
self.METADATA_CACHE_TTL = 60
|
|
166
191
|
self.MEMORIES_CACHE_TTL = 60
|
|
167
192
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
# Initialize agent registry
|
|
171
|
-
self.agent_registry = AgentRegistryAdapter(self.framework_path)
|
|
172
|
-
|
|
173
|
-
# Initialize output style manager (must be after content is loaded)
|
|
174
|
-
self.output_style_manager = None
|
|
175
|
-
# Defer initialization until first use to ensure content is loaded
|
|
193
|
+
# === Cache Management Methods (backward compatibility) ===
|
|
176
194
|
|
|
177
195
|
def clear_all_caches(self) -> None:
|
|
178
196
|
"""Clear all caches to force reload on next access."""
|
|
179
197
|
self._cache_manager.clear_all()
|
|
180
198
|
|
|
181
199
|
def clear_agent_caches(self) -> None:
|
|
182
|
-
"""Clear agent-related caches
|
|
200
|
+
"""Clear agent-related caches."""
|
|
183
201
|
self._cache_manager.clear_agent_caches()
|
|
184
202
|
|
|
185
203
|
def clear_memory_caches(self) -> None:
|
|
186
204
|
"""Clear memory-related caches."""
|
|
187
205
|
self._cache_manager.clear_memory_caches()
|
|
188
206
|
|
|
189
|
-
|
|
190
|
-
"""Initialize output style management and deploy if applicable."""
|
|
191
|
-
try:
|
|
192
|
-
from claude_mpm.core.output_style_manager import OutputStyleManager
|
|
193
|
-
|
|
194
|
-
self.output_style_manager = OutputStyleManager()
|
|
195
|
-
|
|
196
|
-
# Log detailed output style status
|
|
197
|
-
self._log_output_style_status()
|
|
198
|
-
|
|
199
|
-
# Extract and save output style content (pass self to reuse loaded content)
|
|
200
|
-
output_style_content = (
|
|
201
|
-
self.output_style_manager.extract_output_style_content(
|
|
202
|
-
framework_loader=self
|
|
203
|
-
)
|
|
204
|
-
)
|
|
205
|
-
self.output_style_manager.save_output_style(output_style_content)
|
|
206
|
-
|
|
207
|
-
# Deploy to Claude Code if supported
|
|
208
|
-
deployed = self.output_style_manager.deploy_output_style(
|
|
209
|
-
output_style_content
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
if deployed:
|
|
213
|
-
self.logger.info("✅ Output style deployed to Claude Code >= 1.0.83")
|
|
214
|
-
else:
|
|
215
|
-
self.logger.info(
|
|
216
|
-
"📝 Output style will be injected into instructions for older Claude versions"
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
except Exception as e:
|
|
220
|
-
self.logger.warning(f"❌ Failed to initialize output style manager: {e}")
|
|
221
|
-
# Continue without output style management
|
|
222
|
-
|
|
223
|
-
def _log_output_style_status(self) -> None:
|
|
224
|
-
"""Log comprehensive output style status information."""
|
|
225
|
-
if not self.output_style_manager:
|
|
226
|
-
return
|
|
227
|
-
|
|
228
|
-
# Claude version detection
|
|
229
|
-
claude_version = self.output_style_manager.claude_version
|
|
230
|
-
if claude_version:
|
|
231
|
-
self.logger.info(f"Claude Code version detected: {claude_version}")
|
|
232
|
-
|
|
233
|
-
# Check if version supports output styles
|
|
234
|
-
if self.output_style_manager.supports_output_styles():
|
|
235
|
-
self.logger.info("✅ Claude Code supports output styles (>= 1.0.83)")
|
|
236
|
-
|
|
237
|
-
# Check deployment status
|
|
238
|
-
output_style_path = self.output_style_manager.output_style_path
|
|
239
|
-
if output_style_path.exists():
|
|
240
|
-
self.logger.info(
|
|
241
|
-
f"📁 Output style file exists: {output_style_path}"
|
|
242
|
-
)
|
|
243
|
-
else:
|
|
244
|
-
self.logger.info(
|
|
245
|
-
f"📝 Output style will be created at: {output_style_path}"
|
|
246
|
-
)
|
|
247
|
-
|
|
248
|
-
else:
|
|
249
|
-
self.logger.info(
|
|
250
|
-
f"⚠️ Claude Code {claude_version} does not support output styles (< 1.0.83)"
|
|
251
|
-
)
|
|
252
|
-
self.logger.info(
|
|
253
|
-
"📝 Output style content will be injected into framework instructions"
|
|
254
|
-
)
|
|
255
|
-
else:
|
|
256
|
-
self.logger.info("⚠️ Claude Code not detected or version unknown")
|
|
257
|
-
self.logger.info(
|
|
258
|
-
"📝 Output style content will be injected into framework instructions as fallback"
|
|
259
|
-
)
|
|
260
|
-
|
|
261
|
-
def _try_load_file(self, file_path: Path, file_type: str) -> Optional[str]:
|
|
262
|
-
"""
|
|
263
|
-
Try to load a file with error handling.
|
|
264
|
-
|
|
265
|
-
Args:
|
|
266
|
-
file_path: Path to the file to load
|
|
267
|
-
file_type: Description of file type for logging
|
|
268
|
-
|
|
269
|
-
Returns:
|
|
270
|
-
File content if successful, None otherwise
|
|
271
|
-
"""
|
|
272
|
-
try:
|
|
273
|
-
content = file_path.read_text()
|
|
274
|
-
if hasattr(self.logger, "level") and self.logger.level <= logging.INFO:
|
|
275
|
-
self.logger.info(f"Loaded {file_type} from: {file_path}")
|
|
276
|
-
|
|
277
|
-
# Extract metadata if present
|
|
278
|
-
import re
|
|
279
|
-
|
|
280
|
-
version_match = re.search(r"<!-- FRAMEWORK_VERSION: (\d+) -->", content)
|
|
281
|
-
if version_match:
|
|
282
|
-
version = version_match.group(
|
|
283
|
-
1
|
|
284
|
-
) # Keep as string to preserve leading zeros
|
|
285
|
-
self.logger.info(f"Framework version: {version}")
|
|
286
|
-
# Store framework version if this is the main INSTRUCTIONS.md
|
|
287
|
-
if "INSTRUCTIONS.md" in str(file_path):
|
|
288
|
-
self.framework_version = version
|
|
289
|
-
|
|
290
|
-
# Extract modification timestamp
|
|
291
|
-
timestamp_match = re.search(r"<!-- LAST_MODIFIED: ([^>]+) -->", content)
|
|
292
|
-
if timestamp_match:
|
|
293
|
-
timestamp = timestamp_match.group(1).strip()
|
|
294
|
-
self.logger.info(f"Last modified: {timestamp}")
|
|
295
|
-
# Store timestamp if this is the main INSTRUCTIONS.md
|
|
296
|
-
if "INSTRUCTIONS.md" in str(file_path):
|
|
297
|
-
self.framework_last_modified = timestamp
|
|
298
|
-
|
|
299
|
-
return content
|
|
300
|
-
except Exception as e:
|
|
301
|
-
if hasattr(self.logger, "level") and self.logger.level <= logging.ERROR:
|
|
302
|
-
self.logger.error(f"Failed to load {file_type}: {e}")
|
|
303
|
-
return None
|
|
304
|
-
|
|
305
|
-
def _load_instructions_file(self, content: Dict[str, Any]) -> None:
|
|
306
|
-
"""
|
|
307
|
-
Load custom INSTRUCTIONS.md from .claude-mpm directories.
|
|
308
|
-
|
|
309
|
-
Precedence (highest to lowest):
|
|
310
|
-
1. Project-specific: ./.claude-mpm/INSTRUCTIONS.md
|
|
311
|
-
2. User-specific: ~/.claude-mpm/INSTRUCTIONS.md
|
|
312
|
-
|
|
313
|
-
NOTE: We do NOT load CLAUDE.md files since Claude Code already picks them up automatically.
|
|
314
|
-
This prevents duplication of instructions.
|
|
315
|
-
|
|
316
|
-
Args:
|
|
317
|
-
content: Dictionary to update with loaded instructions
|
|
318
|
-
"""
|
|
319
|
-
# Check for project-specific INSTRUCTIONS.md first
|
|
320
|
-
project_instructions_path = Path.cwd() / ".claude-mpm" / "INSTRUCTIONS.md"
|
|
321
|
-
if project_instructions_path.exists():
|
|
322
|
-
loaded_content = self._try_load_file(
|
|
323
|
-
project_instructions_path, "project-specific INSTRUCTIONS.md"
|
|
324
|
-
)
|
|
325
|
-
if loaded_content:
|
|
326
|
-
content["custom_instructions"] = loaded_content
|
|
327
|
-
content["custom_instructions_level"] = "project"
|
|
328
|
-
self.logger.info(
|
|
329
|
-
"Using project-specific PM instructions from .claude-mpm/INSTRUCTIONS.md"
|
|
330
|
-
)
|
|
331
|
-
return
|
|
332
|
-
|
|
333
|
-
# Check for user-specific INSTRUCTIONS.md
|
|
334
|
-
user_instructions_path = Path.home() / ".claude-mpm" / "INSTRUCTIONS.md"
|
|
335
|
-
if user_instructions_path.exists():
|
|
336
|
-
loaded_content = self._try_load_file(
|
|
337
|
-
user_instructions_path, "user-specific INSTRUCTIONS.md"
|
|
338
|
-
)
|
|
339
|
-
if loaded_content:
|
|
340
|
-
content["custom_instructions"] = loaded_content
|
|
341
|
-
content["custom_instructions_level"] = "user"
|
|
342
|
-
self.logger.info(
|
|
343
|
-
"Using user-specific PM instructions from ~/.claude-mpm/INSTRUCTIONS.md"
|
|
344
|
-
)
|
|
345
|
-
return
|
|
346
|
-
|
|
347
|
-
def _load_workflow_instructions(self, content: Dict[str, Any]) -> None:
|
|
348
|
-
"""
|
|
349
|
-
Load WORKFLOW.md from .claude-mpm directories.
|
|
350
|
-
|
|
351
|
-
Precedence (highest to lowest):
|
|
352
|
-
1. Project-specific: ./.claude-mpm/WORKFLOW.md
|
|
353
|
-
2. User-specific: ~/.claude-mpm/WORKFLOW.md
|
|
354
|
-
3. System default: src/claude_mpm/agents/WORKFLOW.md or packaged
|
|
355
|
-
|
|
356
|
-
NOTE: We do NOT load from .claude/ directories to avoid conflicts.
|
|
357
|
-
|
|
358
|
-
Args:
|
|
359
|
-
content: Dictionary to update with workflow instructions
|
|
360
|
-
"""
|
|
361
|
-
# Check for project-specific WORKFLOW.md first (highest priority)
|
|
362
|
-
project_workflow_path = Path.cwd() / ".claude-mpm" / "WORKFLOW.md"
|
|
363
|
-
if project_workflow_path.exists():
|
|
364
|
-
loaded_content = self._try_load_file(
|
|
365
|
-
project_workflow_path, "project-specific WORKFLOW.md"
|
|
366
|
-
)
|
|
367
|
-
if loaded_content:
|
|
368
|
-
content["workflow_instructions"] = loaded_content
|
|
369
|
-
content["workflow_instructions_level"] = "project"
|
|
370
|
-
self.logger.info(
|
|
371
|
-
"Using project-specific workflow instructions from .claude-mpm/WORKFLOW.md"
|
|
372
|
-
)
|
|
373
|
-
return
|
|
374
|
-
|
|
375
|
-
# Check for user-specific WORKFLOW.md (medium priority)
|
|
376
|
-
user_workflow_path = Path.home() / ".claude-mpm" / "WORKFLOW.md"
|
|
377
|
-
if user_workflow_path.exists():
|
|
378
|
-
loaded_content = self._try_load_file(
|
|
379
|
-
user_workflow_path, "user-specific WORKFLOW.md"
|
|
380
|
-
)
|
|
381
|
-
if loaded_content:
|
|
382
|
-
content["workflow_instructions"] = loaded_content
|
|
383
|
-
content["workflow_instructions_level"] = "user"
|
|
384
|
-
self.logger.info(
|
|
385
|
-
"Using user-specific workflow instructions from ~/.claude-mpm/WORKFLOW.md"
|
|
386
|
-
)
|
|
387
|
-
return
|
|
388
|
-
|
|
389
|
-
# Fall back to system workflow (lowest priority)
|
|
390
|
-
if self.framework_path and self.framework_path != Path("__PACKAGED__"):
|
|
391
|
-
system_workflow_path = (
|
|
392
|
-
self.framework_path / "src" / "claude_mpm" / "agents" / "WORKFLOW.md"
|
|
393
|
-
)
|
|
394
|
-
if system_workflow_path.exists():
|
|
395
|
-
loaded_content = self._try_load_file(
|
|
396
|
-
system_workflow_path, "system WORKFLOW.md"
|
|
397
|
-
)
|
|
398
|
-
if loaded_content:
|
|
399
|
-
content["workflow_instructions"] = loaded_content
|
|
400
|
-
content["workflow_instructions_level"] = "system"
|
|
401
|
-
self.logger.info("Using system workflow instructions")
|
|
402
|
-
|
|
403
|
-
def _load_memory_instructions(self, content: Dict[str, Any]) -> None:
|
|
404
|
-
"""
|
|
405
|
-
Load MEMORY.md from .claude-mpm directories.
|
|
406
|
-
|
|
407
|
-
Precedence (highest to lowest):
|
|
408
|
-
1. Project-specific: ./.claude-mpm/MEMORY.md
|
|
409
|
-
2. User-specific: ~/.claude-mpm/MEMORY.md
|
|
410
|
-
3. System default: src/claude_mpm/agents/MEMORY.md or packaged
|
|
411
|
-
|
|
412
|
-
NOTE: We do NOT load from .claude/ directories to avoid conflicts.
|
|
413
|
-
|
|
414
|
-
Args:
|
|
415
|
-
content: Dictionary to update with memory instructions
|
|
416
|
-
"""
|
|
417
|
-
# Check for project-specific MEMORY.md first (highest priority)
|
|
418
|
-
project_memory_path = Path.cwd() / ".claude-mpm" / "MEMORY.md"
|
|
419
|
-
if project_memory_path.exists():
|
|
420
|
-
loaded_content = self._try_load_file(
|
|
421
|
-
project_memory_path, "project-specific MEMORY.md"
|
|
422
|
-
)
|
|
423
|
-
if loaded_content:
|
|
424
|
-
content["memory_instructions"] = loaded_content
|
|
425
|
-
content["memory_instructions_level"] = "project"
|
|
426
|
-
self.logger.info(
|
|
427
|
-
"Using project-specific memory instructions from .claude-mpm/MEMORY.md"
|
|
428
|
-
)
|
|
429
|
-
return
|
|
430
|
-
|
|
431
|
-
# Check for user-specific MEMORY.md (medium priority)
|
|
432
|
-
user_memory_path = Path.home() / ".claude-mpm" / "MEMORY.md"
|
|
433
|
-
if user_memory_path.exists():
|
|
434
|
-
loaded_content = self._try_load_file(
|
|
435
|
-
user_memory_path, "user-specific MEMORY.md"
|
|
436
|
-
)
|
|
437
|
-
if loaded_content:
|
|
438
|
-
content["memory_instructions"] = loaded_content
|
|
439
|
-
content["memory_instructions_level"] = "user"
|
|
440
|
-
self.logger.info(
|
|
441
|
-
"Using user-specific memory instructions from ~/.claude-mpm/MEMORY.md"
|
|
442
|
-
)
|
|
443
|
-
return
|
|
444
|
-
|
|
445
|
-
# Fall back to system memory instructions (lowest priority)
|
|
446
|
-
if self.framework_path and self.framework_path != Path("__PACKAGED__"):
|
|
447
|
-
system_memory_path = (
|
|
448
|
-
self.framework_path / "src" / "claude_mpm" / "agents" / "MEMORY.md"
|
|
449
|
-
)
|
|
450
|
-
if system_memory_path.exists():
|
|
451
|
-
loaded_content = self._try_load_file(
|
|
452
|
-
system_memory_path, "system MEMORY.md"
|
|
453
|
-
)
|
|
454
|
-
if loaded_content:
|
|
455
|
-
content["memory_instructions"] = loaded_content
|
|
456
|
-
content["memory_instructions_level"] = "system"
|
|
457
|
-
self.logger.info("Using system memory instructions")
|
|
458
|
-
|
|
459
|
-
def _get_deployed_agents(self) -> set:
|
|
460
|
-
"""
|
|
461
|
-
Get a set of deployed agent names from .claude/agents/ directories.
|
|
462
|
-
Uses caching to avoid repeated filesystem scans.
|
|
463
|
-
|
|
464
|
-
Returns:
|
|
465
|
-
Set of agent names (file stems) that are deployed
|
|
466
|
-
"""
|
|
467
|
-
# Try to get from cache first
|
|
468
|
-
cached = self._cache_manager.get_deployed_agents()
|
|
469
|
-
if cached is not None:
|
|
470
|
-
return cached
|
|
471
|
-
|
|
472
|
-
# Cache miss or expired - perform actual scan
|
|
473
|
-
self.logger.debug("Scanning for deployed agents (cache miss or expired)")
|
|
474
|
-
deployed = set()
|
|
475
|
-
|
|
476
|
-
# Check multiple locations for deployed agents
|
|
477
|
-
agents_dirs = [
|
|
478
|
-
Path.cwd() / ".claude" / "agents", # Project-specific agents
|
|
479
|
-
Path.home() / ".claude" / "agents", # User's system agents
|
|
480
|
-
]
|
|
481
|
-
|
|
482
|
-
for agents_dir in agents_dirs:
|
|
483
|
-
if agents_dir.exists():
|
|
484
|
-
for agent_file in agents_dir.glob("*.md"):
|
|
485
|
-
if not agent_file.name.startswith("."):
|
|
486
|
-
# Use stem to get agent name without extension
|
|
487
|
-
deployed.add(agent_file.stem)
|
|
488
|
-
self.logger.debug(
|
|
489
|
-
f"Found deployed agent: {agent_file.stem} in {agents_dir}"
|
|
490
|
-
)
|
|
491
|
-
|
|
492
|
-
self.logger.debug(f"Total deployed agents found: {len(deployed)}")
|
|
493
|
-
|
|
494
|
-
# Update cache
|
|
495
|
-
self._cache_manager.set_deployed_agents(deployed)
|
|
496
|
-
|
|
497
|
-
return deployed
|
|
498
|
-
|
|
499
|
-
def _load_actual_memories(self, content: Dict[str, Any]) -> None:
|
|
500
|
-
"""
|
|
501
|
-
Load actual memories using the MemoryManager service.
|
|
502
|
-
|
|
503
|
-
This method delegates all memory loading operations to the MemoryManager,
|
|
504
|
-
which handles caching, aggregation, deduplication, and legacy format migration.
|
|
505
|
-
|
|
506
|
-
Args:
|
|
507
|
-
content: Dictionary to update with actual memories
|
|
508
|
-
"""
|
|
509
|
-
# Use MemoryManager to load all memories
|
|
510
|
-
memories = self._memory_manager.load_memories()
|
|
511
|
-
|
|
512
|
-
# Apply loaded memories to content
|
|
513
|
-
if "actual_memories" in memories:
|
|
514
|
-
content["actual_memories"] = memories["actual_memories"]
|
|
515
|
-
if "agent_memories" in memories:
|
|
516
|
-
content["agent_memories"] = memories["agent_memories"]
|
|
517
|
-
|
|
518
|
-
def _load_single_agent(
|
|
519
|
-
self, agent_file: Path
|
|
520
|
-
) -> tuple[Optional[str], Optional[str]]:
|
|
521
|
-
"""
|
|
522
|
-
Load a single agent file.
|
|
523
|
-
|
|
524
|
-
Args:
|
|
525
|
-
agent_file: Path to the agent file
|
|
526
|
-
|
|
527
|
-
Returns:
|
|
528
|
-
Tuple of (agent_name, agent_content) or (None, None) on failure
|
|
529
|
-
"""
|
|
530
|
-
try:
|
|
531
|
-
agent_name = agent_file.stem
|
|
532
|
-
# Skip README files
|
|
533
|
-
if agent_name.upper() == "README":
|
|
534
|
-
return None, None
|
|
535
|
-
content = agent_file.read_text()
|
|
536
|
-
self.logger.debug(f"Loaded agent: {agent_name}")
|
|
537
|
-
return agent_name, content
|
|
538
|
-
except Exception as e:
|
|
539
|
-
self.logger.error(f"Failed to load agent {agent_file}: {e}")
|
|
540
|
-
return None, None
|
|
541
|
-
|
|
542
|
-
def _load_base_agent_fallback(
|
|
543
|
-
self, content: Dict[str, Any], main_dir: Optional[Path]
|
|
544
|
-
) -> None:
|
|
545
|
-
"""
|
|
546
|
-
Load base_agent.md from main directory as fallback.
|
|
547
|
-
|
|
548
|
-
Args:
|
|
549
|
-
content: Dictionary to update with base agent
|
|
550
|
-
main_dir: Main agents directory path
|
|
551
|
-
"""
|
|
552
|
-
if main_dir and main_dir.exists() and "base_agent" not in content["agents"]:
|
|
553
|
-
base_agent_file = main_dir / "base_agent.md"
|
|
554
|
-
if base_agent_file.exists():
|
|
555
|
-
agent_name, agent_content = self._load_single_agent(base_agent_file)
|
|
556
|
-
if agent_name and agent_content:
|
|
557
|
-
content["agents"][agent_name] = agent_content
|
|
558
|
-
|
|
559
|
-
def _load_agents_directory(
|
|
560
|
-
self,
|
|
561
|
-
content: Dict[str, Any],
|
|
562
|
-
agents_dir: Optional[Path],
|
|
563
|
-
templates_dir: Optional[Path],
|
|
564
|
-
main_dir: Optional[Path],
|
|
565
|
-
) -> None:
|
|
566
|
-
"""
|
|
567
|
-
Load agent definitions from the appropriate directory.
|
|
568
|
-
|
|
569
|
-
Args:
|
|
570
|
-
content: Dictionary to update with loaded agents
|
|
571
|
-
agents_dir: Primary agents directory to load from
|
|
572
|
-
templates_dir: Templates directory path
|
|
573
|
-
main_dir: Main agents directory path
|
|
574
|
-
"""
|
|
575
|
-
if not agents_dir or not agents_dir.exists():
|
|
576
|
-
return
|
|
577
|
-
|
|
578
|
-
content["loaded"] = True
|
|
579
|
-
|
|
580
|
-
# Load all agent files
|
|
581
|
-
for agent_file in agents_dir.glob("*.md"):
|
|
582
|
-
agent_name, agent_content = self._load_single_agent(agent_file)
|
|
583
|
-
if agent_name and agent_content:
|
|
584
|
-
content["agents"][agent_name] = agent_content
|
|
585
|
-
|
|
586
|
-
# If we used templates dir, also check main dir for base_agent.md
|
|
587
|
-
if agents_dir == templates_dir:
|
|
588
|
-
self._load_base_agent_fallback(content, main_dir)
|
|
207
|
+
# === Content Loading Methods ===
|
|
589
208
|
|
|
590
209
|
def _load_framework_content(self) -> Dict[str, Any]:
|
|
591
|
-
"""Load framework content."""
|
|
210
|
+
"""Load framework content using modular components."""
|
|
592
211
|
content = {
|
|
593
212
|
"claude_md": "",
|
|
594
213
|
"agents": {},
|
|
@@ -597,242 +216,102 @@ class FrameworkLoader:
|
|
|
597
216
|
"working_claude_md": "",
|
|
598
217
|
"framework_instructions": "",
|
|
599
218
|
"workflow_instructions": "",
|
|
600
|
-
"workflow_instructions_level": "",
|
|
219
|
+
"workflow_instructions_level": "",
|
|
601
220
|
"memory_instructions": "",
|
|
602
|
-
"memory_instructions_level": "",
|
|
603
|
-
"project_workflow": "", # Deprecated
|
|
604
|
-
"project_memory": "", # Deprecated
|
|
605
|
-
"actual_memories": "",
|
|
221
|
+
"memory_instructions_level": "",
|
|
222
|
+
"project_workflow": "", # Deprecated
|
|
223
|
+
"project_memory": "", # Deprecated
|
|
224
|
+
"actual_memories": "",
|
|
225
|
+
"agent_memories": {},
|
|
606
226
|
}
|
|
607
227
|
|
|
608
|
-
# Load instructions
|
|
609
|
-
self.
|
|
228
|
+
# Load all instructions
|
|
229
|
+
self.instruction_loader.load_all_instructions(content)
|
|
610
230
|
|
|
611
|
-
|
|
612
|
-
|
|
231
|
+
# Transfer metadata from loaders
|
|
232
|
+
if self.file_loader.framework_version:
|
|
233
|
+
self.framework_version = self.file_loader.framework_version
|
|
234
|
+
content["version"] = self.framework_version
|
|
235
|
+
if self.file_loader.framework_last_modified:
|
|
236
|
+
self.framework_last_modified = self.file_loader.framework_last_modified
|
|
613
237
|
|
|
614
|
-
#
|
|
615
|
-
if self.framework_path == Path("__PACKAGED__"):
|
|
616
|
-
# Load files using importlib.resources for packaged installations
|
|
617
|
-
self._load_packaged_framework_content(content)
|
|
618
|
-
else:
|
|
619
|
-
# Load from filesystem for development mode
|
|
620
|
-
# Load framework's INSTRUCTIONS.md
|
|
621
|
-
framework_instructions_path = (
|
|
622
|
-
self.framework_path
|
|
623
|
-
/ "src"
|
|
624
|
-
/ "claude_mpm"
|
|
625
|
-
/ "agents"
|
|
626
|
-
/ "INSTRUCTIONS.md"
|
|
627
|
-
)
|
|
628
|
-
if framework_instructions_path.exists():
|
|
629
|
-
loaded_content = self._try_load_file(
|
|
630
|
-
framework_instructions_path, "framework INSTRUCTIONS.md"
|
|
631
|
-
)
|
|
632
|
-
if loaded_content:
|
|
633
|
-
content["framework_instructions"] = loaded_content
|
|
634
|
-
content["loaded"] = True
|
|
635
|
-
# Add framework version to content
|
|
636
|
-
if self.framework_version:
|
|
637
|
-
content["instructions_version"] = self.framework_version
|
|
638
|
-
content["version"] = (
|
|
639
|
-
self.framework_version
|
|
640
|
-
) # Update main version key
|
|
641
|
-
# Add modification timestamp to content
|
|
642
|
-
if self.framework_last_modified:
|
|
643
|
-
content["instructions_last_modified"] = (
|
|
644
|
-
self.framework_last_modified
|
|
645
|
-
)
|
|
646
|
-
|
|
647
|
-
# Load BASE_PM.md for core framework requirements
|
|
648
|
-
base_pm_path = (
|
|
649
|
-
self.framework_path / "src" / "claude_mpm" / "agents" / "BASE_PM.md"
|
|
650
|
-
)
|
|
651
|
-
if base_pm_path.exists():
|
|
652
|
-
base_pm_content = self._try_load_file(
|
|
653
|
-
base_pm_path, "BASE_PM framework requirements"
|
|
654
|
-
)
|
|
655
|
-
if base_pm_content:
|
|
656
|
-
content["base_pm_instructions"] = base_pm_content
|
|
657
|
-
|
|
658
|
-
# Load WORKFLOW.md - check for project-specific first, then system
|
|
659
|
-
self._load_workflow_instructions(content)
|
|
660
|
-
|
|
661
|
-
# Load MEMORY.md - check for project-specific first, then system
|
|
662
|
-
self._load_memory_instructions(content)
|
|
663
|
-
|
|
664
|
-
# Load actual memories from .claude-mpm/memories/PM_memories.md
|
|
238
|
+
# Load memories
|
|
665
239
|
self._load_actual_memories(content)
|
|
666
240
|
|
|
667
|
-
# Discover
|
|
241
|
+
# Discover and load agents
|
|
668
242
|
agents_dir, templates_dir, main_dir = self._path_resolver.discover_agent_paths(
|
|
669
243
|
agents_dir=self.agents_dir, framework_path=self.framework_path
|
|
670
244
|
)
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
245
|
+
agents = self.agent_loader.load_agents_directory(
|
|
246
|
+
agents_dir, templates_dir, main_dir
|
|
247
|
+
)
|
|
248
|
+
if agents:
|
|
249
|
+
content["agents"] = agents
|
|
250
|
+
content["loaded"] = True
|
|
674
251
|
|
|
675
252
|
return content
|
|
676
253
|
|
|
677
|
-
def
|
|
678
|
-
"""Load
|
|
679
|
-
|
|
680
|
-
self.logger.warning(
|
|
681
|
-
"importlib.resources not available, cannot load packaged framework"
|
|
682
|
-
)
|
|
683
|
-
self.logger.debug(f"files variable is: {files}")
|
|
684
|
-
# Try alternative import methods
|
|
685
|
-
try:
|
|
686
|
-
from importlib import resources
|
|
687
|
-
|
|
688
|
-
self.logger.info("Using importlib.resources as fallback")
|
|
689
|
-
self._load_packaged_framework_content_fallback(content, resources)
|
|
690
|
-
return
|
|
691
|
-
except ImportError:
|
|
692
|
-
self.logger.error(
|
|
693
|
-
"No importlib.resources available, using minimal framework"
|
|
694
|
-
)
|
|
695
|
-
return
|
|
696
|
-
|
|
697
|
-
try:
|
|
698
|
-
# Load INSTRUCTIONS.md
|
|
699
|
-
instructions_content = self._load_packaged_file("INSTRUCTIONS.md")
|
|
700
|
-
if instructions_content:
|
|
701
|
-
content["framework_instructions"] = instructions_content
|
|
702
|
-
content["loaded"] = True
|
|
703
|
-
# Extract and store version/timestamp metadata
|
|
704
|
-
self._extract_metadata_from_content(
|
|
705
|
-
instructions_content, "INSTRUCTIONS.md"
|
|
706
|
-
)
|
|
707
|
-
if self.framework_version:
|
|
708
|
-
content["instructions_version"] = self.framework_version
|
|
709
|
-
content["version"] = self.framework_version
|
|
710
|
-
if self.framework_last_modified:
|
|
711
|
-
content["instructions_last_modified"] = self.framework_last_modified
|
|
712
|
-
|
|
713
|
-
# Load BASE_PM.md
|
|
714
|
-
base_pm_content = self._load_packaged_file("BASE_PM.md")
|
|
715
|
-
if base_pm_content:
|
|
716
|
-
content["base_pm_instructions"] = base_pm_content
|
|
717
|
-
|
|
718
|
-
# Load WORKFLOW.md
|
|
719
|
-
workflow_content = self._load_packaged_file("WORKFLOW.md")
|
|
720
|
-
if workflow_content:
|
|
721
|
-
content["workflow_instructions"] = workflow_content
|
|
722
|
-
content["project_workflow"] = "system"
|
|
723
|
-
|
|
724
|
-
# Load MEMORY.md
|
|
725
|
-
memory_content = self._load_packaged_file("MEMORY.md")
|
|
726
|
-
if memory_content:
|
|
727
|
-
content["memory_instructions"] = memory_content
|
|
728
|
-
content["project_memory"] = "system"
|
|
254
|
+
def _load_actual_memories(self, content: Dict[str, Any]) -> None:
|
|
255
|
+
"""Load actual memories using the MemoryManager service."""
|
|
256
|
+
memories = self._memory_manager.load_memories()
|
|
729
257
|
|
|
730
|
-
|
|
731
|
-
|
|
258
|
+
if "actual_memories" in memories:
|
|
259
|
+
content["actual_memories"] = memories["actual_memories"]
|
|
260
|
+
if "agent_memories" in memories:
|
|
261
|
+
content["agent_memories"] = memories["agent_memories"]
|
|
732
262
|
|
|
733
|
-
|
|
734
|
-
self, content: Dict[str, Any], resources
|
|
735
|
-
) -> None:
|
|
736
|
-
"""Load framework content using importlib.resources fallback."""
|
|
737
|
-
try:
|
|
738
|
-
# Load INSTRUCTIONS.md
|
|
739
|
-
instructions_content = self._load_packaged_file_fallback(
|
|
740
|
-
"INSTRUCTIONS.md", resources
|
|
741
|
-
)
|
|
742
|
-
if instructions_content:
|
|
743
|
-
content["framework_instructions"] = instructions_content
|
|
744
|
-
content["loaded"] = True
|
|
745
|
-
# Extract and store version/timestamp metadata
|
|
746
|
-
self._extract_metadata_from_content(
|
|
747
|
-
instructions_content, "INSTRUCTIONS.md"
|
|
748
|
-
)
|
|
749
|
-
if self.framework_version:
|
|
750
|
-
content["instructions_version"] = self.framework_version
|
|
751
|
-
content["version"] = self.framework_version
|
|
752
|
-
if self.framework_last_modified:
|
|
753
|
-
content["instructions_last_modified"] = self.framework_last_modified
|
|
754
|
-
|
|
755
|
-
# Load BASE_PM.md
|
|
756
|
-
base_pm_content = self._load_packaged_file_fallback("BASE_PM.md", resources)
|
|
757
|
-
if base_pm_content:
|
|
758
|
-
content["base_pm_instructions"] = base_pm_content
|
|
759
|
-
|
|
760
|
-
# Load WORKFLOW.md
|
|
761
|
-
workflow_content = self._load_packaged_file_fallback(
|
|
762
|
-
"WORKFLOW.md", resources
|
|
763
|
-
)
|
|
764
|
-
if workflow_content:
|
|
765
|
-
content["workflow_instructions"] = workflow_content
|
|
766
|
-
content["project_workflow"] = "system"
|
|
263
|
+
# === Agent Discovery Methods ===
|
|
767
264
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
265
|
+
def _get_deployed_agents(self) -> Set[str]:
|
|
266
|
+
"""Get deployed agents with caching."""
|
|
267
|
+
cached = self._cache_manager.get_deployed_agents()
|
|
268
|
+
if cached is not None:
|
|
269
|
+
return cached
|
|
773
270
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
)
|
|
271
|
+
deployed = self.agent_loader.get_deployed_agents()
|
|
272
|
+
self._cache_manager.set_deployed_agents(deployed)
|
|
273
|
+
return deployed
|
|
778
274
|
|
|
779
|
-
def
|
|
780
|
-
"""
|
|
781
|
-
|
|
782
|
-
# Try different resource loading methods
|
|
783
|
-
try:
|
|
784
|
-
# Method 1: resources.read_text (Python 3.9+)
|
|
785
|
-
content = resources.read_text("claude_mpm.agents", filename)
|
|
786
|
-
self.logger.info(f"Loaded {filename} from package using read_text")
|
|
787
|
-
return content
|
|
788
|
-
except AttributeError:
|
|
789
|
-
# Method 2: resources.files (Python 3.9+)
|
|
790
|
-
agents_files = resources.files("claude_mpm.agents")
|
|
791
|
-
file_path = agents_files / filename
|
|
792
|
-
if file_path.is_file():
|
|
793
|
-
content = file_path.read_text()
|
|
794
|
-
self.logger.info(f"Loaded {filename} from package using files")
|
|
795
|
-
return content
|
|
796
|
-
self.logger.warning(f"File {filename} not found in package")
|
|
797
|
-
return None
|
|
798
|
-
except Exception as e:
|
|
799
|
-
self.logger.error(
|
|
800
|
-
f"Failed to load {filename} from package with fallback: {e}"
|
|
801
|
-
)
|
|
802
|
-
return None
|
|
275
|
+
def _discover_local_json_templates(self) -> Dict[str, Dict[str, Any]]:
|
|
276
|
+
"""Discover local JSON agent templates."""
|
|
277
|
+
return self.agent_loader.discover_local_json_templates()
|
|
803
278
|
|
|
804
|
-
def
|
|
805
|
-
"""
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
279
|
+
def _parse_agent_metadata(self, agent_file: Path) -> Optional[Dict[str, Any]]:
|
|
280
|
+
"""Parse agent metadata with caching."""
|
|
281
|
+
cache_key = str(agent_file)
|
|
282
|
+
file_mtime = agent_file.stat().st_mtime
|
|
283
|
+
|
|
284
|
+
# Try cache first
|
|
285
|
+
cached_result = self._cache_manager.get_agent_metadata(cache_key)
|
|
286
|
+
if cached_result is not None:
|
|
287
|
+
cached_data, cached_mtime = cached_result
|
|
288
|
+
if cached_mtime == file_mtime:
|
|
289
|
+
self.logger.debug(f"Using cached metadata for {agent_file.name}")
|
|
290
|
+
return cached_data
|
|
291
|
+
|
|
292
|
+
# Cache miss - parse the file
|
|
293
|
+
agent_data = self.metadata_processor.parse_agent_metadata(agent_file)
|
|
294
|
+
|
|
295
|
+
# Add routing information if not present
|
|
296
|
+
if agent_data and "routing" not in agent_data:
|
|
297
|
+
template_data = self.template_processor.load_template(agent_file.stem)
|
|
298
|
+
if template_data:
|
|
299
|
+
routing = self.template_processor.extract_routing(template_data)
|
|
300
|
+
if routing:
|
|
301
|
+
agent_data["routing"] = routing
|
|
302
|
+
memory_routing = self.template_processor.extract_memory_routing(
|
|
303
|
+
template_data
|
|
304
|
+
)
|
|
305
|
+
if memory_routing:
|
|
306
|
+
agent_data["memory_routing"] = memory_routing
|
|
307
|
+
|
|
308
|
+
# Cache the result
|
|
309
|
+
if agent_data:
|
|
310
|
+
self._cache_manager.set_agent_metadata(cache_key, agent_data, file_mtime)
|
|
824
311
|
|
|
825
|
-
|
|
826
|
-
version_match = re.search(r"<!-- FRAMEWORK_VERSION: (\d+) -->", content)
|
|
827
|
-
if version_match and "INSTRUCTIONS.md" in filename:
|
|
828
|
-
self.framework_version = version_match.group(1)
|
|
829
|
-
self.logger.info(f"Framework version: {self.framework_version}")
|
|
312
|
+
return agent_data
|
|
830
313
|
|
|
831
|
-
|
|
832
|
-
timestamp_match = re.search(r"<!-- LAST_MODIFIED: ([^>]+) -->", content)
|
|
833
|
-
if timestamp_match and "INSTRUCTIONS.md" in filename:
|
|
834
|
-
self.framework_last_modified = timestamp_match.group(1).strip()
|
|
835
|
-
self.logger.info(f"Last modified: {self.framework_last_modified}")
|
|
314
|
+
# === Framework Instructions Generation ===
|
|
836
315
|
|
|
837
316
|
def get_framework_instructions(self) -> str:
|
|
838
317
|
"""
|
|
@@ -841,1010 +320,221 @@ class FrameworkLoader:
|
|
|
841
320
|
Returns:
|
|
842
321
|
Complete framework instructions ready for injection
|
|
843
322
|
"""
|
|
844
|
-
#
|
|
845
|
-
|
|
846
|
-
from .log_manager import get_log_manager
|
|
847
|
-
|
|
848
|
-
log_manager = get_log_manager()
|
|
849
|
-
except ImportError:
|
|
850
|
-
log_manager = None
|
|
323
|
+
# Log the system prompt if needed
|
|
324
|
+
self._log_system_prompt()
|
|
851
325
|
|
|
852
326
|
# Generate the instructions
|
|
853
327
|
if self.framework_content["loaded"]:
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
else:
|
|
857
|
-
# Use minimal fallback
|
|
858
|
-
instructions = self._format_minimal_framework()
|
|
859
|
-
|
|
860
|
-
# Log the system prompt if LogManager is available
|
|
861
|
-
if log_manager:
|
|
862
|
-
try:
|
|
863
|
-
import asyncio
|
|
864
|
-
import os
|
|
865
|
-
|
|
866
|
-
# Get or create event loop
|
|
867
|
-
try:
|
|
868
|
-
loop = asyncio.get_running_loop()
|
|
869
|
-
except RuntimeError:
|
|
870
|
-
loop = asyncio.new_event_loop()
|
|
871
|
-
asyncio.set_event_loop(loop)
|
|
872
|
-
|
|
873
|
-
# Prepare metadata
|
|
874
|
-
metadata = {
|
|
875
|
-
"framework_version": self.framework_version,
|
|
876
|
-
"framework_loaded": self.framework_content.get("loaded", False),
|
|
877
|
-
"session_id": os.environ.get("CLAUDE_SESSION_ID", "unknown"),
|
|
878
|
-
"instructions_length": len(instructions),
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
# Log the prompt asynchronously
|
|
882
|
-
if loop.is_running():
|
|
883
|
-
asyncio.create_task(
|
|
884
|
-
log_manager.log_prompt("system_prompt", instructions, metadata)
|
|
885
|
-
)
|
|
886
|
-
else:
|
|
887
|
-
loop.run_until_complete(
|
|
888
|
-
log_manager.log_prompt("system_prompt", instructions, metadata)
|
|
889
|
-
)
|
|
890
|
-
|
|
891
|
-
self.logger.debug("System prompt logged to prompts directory")
|
|
892
|
-
except Exception as e:
|
|
893
|
-
self.logger.debug(f"Could not log system prompt: {e}")
|
|
894
|
-
|
|
895
|
-
return instructions
|
|
896
|
-
|
|
897
|
-
def _strip_metadata_comments(self, content: str) -> str:
|
|
898
|
-
"""Strip metadata HTML comments from content.
|
|
899
|
-
|
|
900
|
-
Removes comments like:
|
|
901
|
-
<!-- FRAMEWORK_VERSION: 0010 -->
|
|
902
|
-
<!-- LAST_MODIFIED: 2025-08-10T00:00:00Z -->
|
|
903
|
-
"""
|
|
904
|
-
import re
|
|
905
|
-
|
|
906
|
-
# Remove HTML comments that contain metadata
|
|
907
|
-
cleaned = re.sub(
|
|
908
|
-
r"<!--\s*(FRAMEWORK_VERSION|LAST_MODIFIED|WORKFLOW_VERSION|PROJECT_WORKFLOW_VERSION|CUSTOM_PROJECT_WORKFLOW)[^>]*-->\n?",
|
|
909
|
-
"",
|
|
910
|
-
content,
|
|
911
|
-
)
|
|
912
|
-
# Also remove any leading blank lines that might result
|
|
913
|
-
return cleaned.lstrip("\n")
|
|
328
|
+
return self._format_full_framework()
|
|
329
|
+
return self._format_minimal_framework()
|
|
914
330
|
|
|
915
331
|
def _format_full_framework(self) -> str:
|
|
916
|
-
"""Format full framework instructions."""
|
|
917
|
-
|
|
918
|
-
# Initialize output style manager on first use (ensures content is loaded)
|
|
332
|
+
"""Format full framework instructions using modular components."""
|
|
333
|
+
# Initialize output style manager on first use
|
|
919
334
|
if self.output_style_manager is None:
|
|
920
335
|
self._initialize_output_style()
|
|
921
336
|
|
|
922
|
-
# Check if we need to inject output style
|
|
337
|
+
# Check if we need to inject output style
|
|
923
338
|
inject_output_style = False
|
|
339
|
+
output_style_content = None
|
|
924
340
|
if self.output_style_manager:
|
|
925
341
|
inject_output_style = self.output_style_manager.should_inject_content()
|
|
926
342
|
if inject_output_style:
|
|
927
|
-
self.logger.info(
|
|
928
|
-
"Injecting output style content into instructions for Claude < 1.0.83"
|
|
929
|
-
)
|
|
930
|
-
|
|
931
|
-
# If we have the full framework INSTRUCTIONS.md, use it
|
|
932
|
-
if self.framework_content.get("framework_instructions"):
|
|
933
|
-
instructions = self._strip_metadata_comments(
|
|
934
|
-
self.framework_content["framework_instructions"]
|
|
935
|
-
)
|
|
936
|
-
|
|
937
|
-
# Note: We don't add working directory CLAUDE.md here since Claude Code
|
|
938
|
-
# already picks it up automatically. This prevents duplication.
|
|
939
|
-
|
|
940
|
-
# Add custom INSTRUCTIONS.md if present (overrides or extends framework instructions)
|
|
941
|
-
if self.framework_content.get("custom_instructions"):
|
|
942
|
-
level = self.framework_content.get(
|
|
943
|
-
"custom_instructions_level", "unknown"
|
|
944
|
-
)
|
|
945
|
-
instructions += f"\n\n## Custom PM Instructions ({level} level)\n\n"
|
|
946
|
-
instructions += "**The following custom instructions override or extend the framework defaults:**\n\n"
|
|
947
|
-
instructions += self._strip_metadata_comments(
|
|
948
|
-
self.framework_content["custom_instructions"]
|
|
949
|
-
)
|
|
950
|
-
instructions += "\n"
|
|
951
|
-
|
|
952
|
-
# Add WORKFLOW.md after instructions
|
|
953
|
-
if self.framework_content.get("workflow_instructions"):
|
|
954
|
-
workflow_content = self._strip_metadata_comments(
|
|
955
|
-
self.framework_content["workflow_instructions"]
|
|
956
|
-
)
|
|
957
|
-
level = self.framework_content.get(
|
|
958
|
-
"workflow_instructions_level", "system"
|
|
959
|
-
)
|
|
960
|
-
if level != "system":
|
|
961
|
-
instructions += f"\n\n## Workflow Instructions ({level} level)\n\n"
|
|
962
|
-
instructions += "**The following workflow instructions override system defaults:**\n\n"
|
|
963
|
-
instructions += f"{workflow_content}\n"
|
|
964
|
-
|
|
965
|
-
# Add MEMORY.md after workflow instructions
|
|
966
|
-
if self.framework_content.get("memory_instructions"):
|
|
967
|
-
memory_content = self._strip_metadata_comments(
|
|
968
|
-
self.framework_content["memory_instructions"]
|
|
969
|
-
)
|
|
970
|
-
level = self.framework_content.get(
|
|
971
|
-
"memory_instructions_level", "system"
|
|
972
|
-
)
|
|
973
|
-
if level != "system":
|
|
974
|
-
instructions += f"\n\n## Memory Instructions ({level} level)\n\n"
|
|
975
|
-
instructions += "**The following memory instructions override system defaults:**\n\n"
|
|
976
|
-
instructions += f"{memory_content}\n"
|
|
977
|
-
|
|
978
|
-
# Add actual PM memories after memory instructions
|
|
979
|
-
if self.framework_content.get("actual_memories"):
|
|
980
|
-
instructions += "\n\n## Current PM Memories\n\n"
|
|
981
|
-
instructions += "**The following are your accumulated memories and knowledge from this project:**\n\n"
|
|
982
|
-
instructions += self.framework_content["actual_memories"]
|
|
983
|
-
instructions += "\n"
|
|
984
|
-
|
|
985
|
-
# Add agent memories if available
|
|
986
|
-
if self.framework_content.get("agent_memories"):
|
|
987
|
-
agent_memories = self.framework_content["agent_memories"]
|
|
988
|
-
if agent_memories:
|
|
989
|
-
instructions += "\n\n## Agent Memories\n\n"
|
|
990
|
-
instructions += "**The following are accumulated memories from specialized agents:**\n\n"
|
|
991
|
-
|
|
992
|
-
for agent_name in sorted(agent_memories.keys()):
|
|
993
|
-
memory_content = agent_memories[agent_name]
|
|
994
|
-
if memory_content:
|
|
995
|
-
instructions += f"### {agent_name.replace('_', ' ').title()} Agent Memory\n\n"
|
|
996
|
-
instructions += memory_content
|
|
997
|
-
instructions += "\n\n"
|
|
998
|
-
|
|
999
|
-
# Add dynamic agent capabilities section
|
|
1000
|
-
instructions += self._generate_agent_capabilities_section()
|
|
1001
|
-
|
|
1002
|
-
# Add enhanced temporal and user context for better awareness
|
|
1003
|
-
instructions += self._generate_temporal_user_context()
|
|
1004
|
-
|
|
1005
|
-
# Add BASE_PM.md framework requirements AFTER INSTRUCTIONS.md
|
|
1006
|
-
if self.framework_content.get("base_pm_instructions"):
|
|
1007
|
-
base_pm = self._strip_metadata_comments(
|
|
1008
|
-
self.framework_content["base_pm_instructions"]
|
|
1009
|
-
)
|
|
1010
|
-
instructions += f"\n\n{base_pm}"
|
|
1011
|
-
|
|
1012
|
-
# Inject output style content if needed (for Claude < 1.0.83)
|
|
1013
|
-
if inject_output_style and self.output_style_manager:
|
|
1014
343
|
output_style_content = self.output_style_manager.get_injectable_content(
|
|
1015
344
|
framework_loader=self
|
|
1016
345
|
)
|
|
1017
|
-
|
|
1018
|
-
instructions += "\n\n## Output Style Configuration\n"
|
|
1019
|
-
instructions += "**Note: The following output style is injected for Claude < 1.0.83**\n\n"
|
|
1020
|
-
instructions += output_style_content
|
|
1021
|
-
instructions += "\n"
|
|
1022
|
-
|
|
1023
|
-
# Clean up any trailing whitespace
|
|
1024
|
-
return instructions.rstrip() + "\n"
|
|
1025
|
-
|
|
1026
|
-
# Otherwise fall back to generating framework
|
|
1027
|
-
instructions = """# Claude MPM Framework Instructions
|
|
1028
|
-
|
|
1029
|
-
You are operating within the Claude Multi-Agent Project Manager (MPM) framework.
|
|
1030
|
-
|
|
1031
|
-
## Core Role
|
|
1032
|
-
You are a multi-agent orchestrator. Your primary responsibilities are:
|
|
1033
|
-
- Delegate all implementation work to specialized agents via Task Tool
|
|
1034
|
-
- Coordinate multi-agent workflows and cross-agent collaboration
|
|
1035
|
-
- Extract and track TODO/BUG/FEATURE items for ticket creation
|
|
1036
|
-
- Maintain project visibility and strategic oversight
|
|
1037
|
-
- NEVER perform direct implementation work yourself
|
|
1038
|
-
|
|
1039
|
-
"""
|
|
1040
|
-
|
|
1041
|
-
# Note: We don't add working directory CLAUDE.md here since Claude Code
|
|
1042
|
-
# already picks it up automatically. This prevents duplication.
|
|
1043
|
-
|
|
1044
|
-
# Add agent definitions
|
|
1045
|
-
if self.framework_content["agents"]:
|
|
1046
|
-
instructions += "## Available Agents\n\n"
|
|
1047
|
-
instructions += "You have the following specialized agents available for delegation:\n\n"
|
|
1048
|
-
|
|
1049
|
-
# List agents with brief descriptions and correct IDs
|
|
1050
|
-
agent_list = []
|
|
1051
|
-
for agent_name in sorted(self.framework_content["agents"].keys()):
|
|
1052
|
-
# Use the actual agent_name as the ID (it's the filename stem)
|
|
1053
|
-
agent_id = agent_name
|
|
1054
|
-
clean_name = agent_name.replace("-", " ").replace("_", " ").title()
|
|
1055
|
-
if (
|
|
1056
|
-
"engineer" in agent_name.lower()
|
|
1057
|
-
and "data" not in agent_name.lower()
|
|
1058
|
-
):
|
|
1059
|
-
agent_list.append(
|
|
1060
|
-
f"- **Engineer Agent** (`{agent_id}`): Code implementation and development"
|
|
1061
|
-
)
|
|
1062
|
-
elif "qa" in agent_name.lower():
|
|
1063
|
-
agent_list.append(
|
|
1064
|
-
f"- **QA Agent** (`{agent_id}`): Testing and quality assurance"
|
|
1065
|
-
)
|
|
1066
|
-
elif "documentation" in agent_name.lower():
|
|
1067
|
-
agent_list.append(
|
|
1068
|
-
f"- **Documentation Agent** (`{agent_id}`): Documentation creation and maintenance"
|
|
1069
|
-
)
|
|
1070
|
-
elif "research" in agent_name.lower():
|
|
1071
|
-
agent_list.append(
|
|
1072
|
-
f"- **Research Agent** (`{agent_id}`): Investigation and analysis"
|
|
1073
|
-
)
|
|
1074
|
-
elif "security" in agent_name.lower():
|
|
1075
|
-
agent_list.append(
|
|
1076
|
-
f"- **Security Agent** (`{agent_id}`): Security analysis and protection"
|
|
1077
|
-
)
|
|
1078
|
-
elif "version" in agent_name.lower():
|
|
1079
|
-
agent_list.append(
|
|
1080
|
-
f"- **Version Control Agent** (`{agent_id}`): Git operations and version management"
|
|
1081
|
-
)
|
|
1082
|
-
elif "ops" in agent_name.lower():
|
|
1083
|
-
agent_list.append(
|
|
1084
|
-
f"- **Ops Agent** (`{agent_id}`): Deployment and operations"
|
|
1085
|
-
)
|
|
1086
|
-
elif "data" in agent_name.lower():
|
|
1087
|
-
agent_list.append(
|
|
1088
|
-
f"- **Data Engineer Agent** (`{agent_id}`): Data management and AI API integration"
|
|
1089
|
-
)
|
|
1090
|
-
else:
|
|
1091
|
-
agent_list.append(
|
|
1092
|
-
f"- **{clean_name}** (`{agent_id}`): Available for specialized tasks"
|
|
1093
|
-
)
|
|
346
|
+
self.logger.info("Injecting output style content for Claude < 1.0.83")
|
|
1094
347
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
instructions += "### Agent Details\n\n"
|
|
1099
|
-
for agent_name, agent_content in sorted(
|
|
1100
|
-
self.framework_content["agents"].items()
|
|
1101
|
-
):
|
|
1102
|
-
instructions += f"#### {agent_name.replace('-', ' ').title()}\n"
|
|
1103
|
-
instructions += agent_content + "\n\n"
|
|
1104
|
-
|
|
1105
|
-
# Add orchestration principles
|
|
1106
|
-
instructions += """
|
|
1107
|
-
## Orchestration Principles
|
|
1108
|
-
1. **Always Delegate**: Never perform direct work - use Task Tool for all implementation
|
|
1109
|
-
2. **Comprehensive Context**: Provide rich, filtered context to each agent
|
|
1110
|
-
3. **Track Everything**: Extract all TODO/BUG/FEATURE items systematically
|
|
1111
|
-
4. **Cross-Agent Coordination**: Orchestrate workflows spanning multiple agents
|
|
1112
|
-
5. **Results Integration**: Actively receive and integrate agent results
|
|
1113
|
-
|
|
1114
|
-
## Task Tool Format
|
|
1115
|
-
```
|
|
1116
|
-
**[Agent Name]**: [Clear task description with deliverables]
|
|
1117
|
-
|
|
1118
|
-
TEMPORAL CONTEXT: Today is [date]. Apply date awareness to [specific considerations].
|
|
1119
|
-
|
|
1120
|
-
**Task**: [Detailed task breakdown]
|
|
1121
|
-
1. [Specific action item 1]
|
|
1122
|
-
2. [Specific action item 2]
|
|
1123
|
-
3. [Specific action item 3]
|
|
1124
|
-
|
|
1125
|
-
**Context**: [Comprehensive filtered context for this agent]
|
|
1126
|
-
**Authority**: [Agent's decision-making scope]
|
|
1127
|
-
**Expected Results**: [Specific deliverables needed]
|
|
1128
|
-
**Integration**: [How results integrate with other work]
|
|
1129
|
-
```
|
|
1130
|
-
|
|
1131
|
-
## Ticket Extraction Patterns
|
|
1132
|
-
Extract tickets from these patterns:
|
|
1133
|
-
- TODO: [description] → TODO ticket
|
|
1134
|
-
- BUG: [description] → BUG ticket
|
|
1135
|
-
- FEATURE: [description] → FEATURE ticket
|
|
1136
|
-
- ISSUE: [description] → ISSUE ticket
|
|
1137
|
-
- FIXME: [description] → BUG ticket
|
|
1138
|
-
|
|
1139
|
-
---
|
|
1140
|
-
"""
|
|
1141
|
-
|
|
1142
|
-
return instructions
|
|
348
|
+
# Generate dynamic sections
|
|
349
|
+
capabilities_section = self._generate_agent_capabilities_section()
|
|
350
|
+
context_section = self.context_generator.generate_temporal_user_context()
|
|
1143
351
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
352
|
+
# Format the complete framework
|
|
353
|
+
return self.content_formatter.format_full_framework(
|
|
354
|
+
self.framework_content,
|
|
355
|
+
capabilities_section,
|
|
356
|
+
context_section,
|
|
357
|
+
inject_output_style,
|
|
358
|
+
output_style_content,
|
|
359
|
+
)
|
|
1147
360
|
|
|
1148
|
-
|
|
361
|
+
def _format_minimal_framework(self) -> str:
|
|
362
|
+
"""Format minimal framework instructions."""
|
|
363
|
+
return self.content_formatter.format_minimal_framework(self.framework_content)
|
|
364
|
+
|
|
365
|
+
def _generate_agent_capabilities_section(self) -> str:
|
|
366
|
+
"""Generate agent capabilities section with caching."""
|
|
367
|
+
# Try cache first
|
|
1149
368
|
cached_capabilities = self._cache_manager.get_capabilities()
|
|
1150
369
|
if cached_capabilities is not None:
|
|
1151
370
|
return cached_capabilities
|
|
1152
371
|
|
|
1153
|
-
|
|
1154
|
-
current_time = time.time()
|
|
1155
|
-
|
|
1156
|
-
# Cache miss or expired - generate capabilities
|
|
1157
|
-
self.logger.debug("Generating agent capabilities (cache miss or expired)")
|
|
372
|
+
self.logger.debug("Generating agent capabilities (cache miss)")
|
|
1158
373
|
|
|
1159
374
|
try:
|
|
1160
|
-
|
|
375
|
+
# Discover local JSON templates
|
|
376
|
+
local_agents = self._discover_local_json_templates()
|
|
1161
377
|
|
|
1162
|
-
#
|
|
1163
|
-
|
|
1164
|
-
# Priority order: project > user home > fallback
|
|
378
|
+
# Get deployed agents from .claude/agents/
|
|
379
|
+
deployed_agents = []
|
|
1165
380
|
agents_dirs = [
|
|
1166
|
-
Path.cwd() / ".claude" / "agents",
|
|
1167
|
-
Path.home() / ".claude" / "agents",
|
|
381
|
+
Path.cwd() / ".claude" / "agents",
|
|
382
|
+
Path.home() / ".claude" / "agents",
|
|
1168
383
|
]
|
|
1169
384
|
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
continue
|
|
1182
|
-
|
|
1183
|
-
# Parse agent metadata (with caching)
|
|
1184
|
-
agent_data = self._parse_agent_metadata(agent_file)
|
|
1185
|
-
if agent_data:
|
|
1186
|
-
agent_id = agent_data["id"]
|
|
1187
|
-
# Only add if not already present (project has priority 0, user has priority 1)
|
|
1188
|
-
# Lower priority number wins (project > user)
|
|
1189
|
-
if (
|
|
1190
|
-
agent_id not in all_agents
|
|
1191
|
-
or priority < all_agents[agent_id][1]
|
|
1192
|
-
):
|
|
1193
|
-
all_agents[agent_id] = (agent_data, priority)
|
|
1194
|
-
self.logger.debug(
|
|
1195
|
-
f"Added/Updated agent {agent_id} from {potential_dir} (priority {priority})"
|
|
1196
|
-
)
|
|
1197
|
-
|
|
1198
|
-
if not all_agents:
|
|
1199
|
-
self.logger.warning(f"No agents found in any location: {agents_dirs}")
|
|
1200
|
-
result = self._get_fallback_capabilities()
|
|
1201
|
-
# Cache the fallback result too
|
|
1202
|
-
self._cache_manager.set_capabilities(result)
|
|
1203
|
-
return result
|
|
1204
|
-
|
|
1205
|
-
# Log agent collection summary
|
|
1206
|
-
project_agents = [aid for aid, (_, pri) in all_agents.items() if pri == 0]
|
|
1207
|
-
user_agents = [aid for aid, (_, pri) in all_agents.items() if pri == 1]
|
|
1208
|
-
|
|
1209
|
-
if project_agents:
|
|
1210
|
-
self.logger.info(
|
|
1211
|
-
f"Loaded {len(project_agents)} project agents: {', '.join(sorted(project_agents))}"
|
|
1212
|
-
)
|
|
1213
|
-
if user_agents:
|
|
1214
|
-
self.logger.info(
|
|
1215
|
-
f"Loaded {len(user_agents)} user agents: {', '.join(sorted(user_agents))}"
|
|
1216
|
-
)
|
|
1217
|
-
|
|
1218
|
-
# Build capabilities section
|
|
1219
|
-
section = "\n\n## Available Agent Capabilities\n\n"
|
|
1220
|
-
|
|
1221
|
-
# Extract just the agent data (drop priority info) and sort
|
|
1222
|
-
deployed_agents = [agent_data for agent_data, _ in all_agents.values()]
|
|
1223
|
-
|
|
1224
|
-
if not deployed_agents:
|
|
1225
|
-
result = self._get_fallback_capabilities()
|
|
1226
|
-
# Cache the fallback result
|
|
1227
|
-
self._cache_manager.set_capabilities(result)
|
|
1228
|
-
return result
|
|
1229
|
-
|
|
1230
|
-
# Sort agents alphabetically by ID
|
|
1231
|
-
deployed_agents.sort(key=lambda x: x["id"])
|
|
1232
|
-
|
|
1233
|
-
# Display all agents with their rich descriptions
|
|
1234
|
-
for agent in deployed_agents:
|
|
1235
|
-
# Clean up display name - handle common acronyms
|
|
1236
|
-
display_name = agent["display_name"]
|
|
1237
|
-
display_name = (
|
|
1238
|
-
display_name.replace("Qa ", "QA ")
|
|
1239
|
-
.replace("Ui ", "UI ")
|
|
1240
|
-
.replace("Api ", "API ")
|
|
1241
|
-
)
|
|
1242
|
-
if display_name.lower() == "qa agent":
|
|
1243
|
-
display_name = "QA Agent"
|
|
1244
|
-
|
|
1245
|
-
section += f"\n### {display_name} (`{agent['id']}`)\n"
|
|
1246
|
-
section += f"{agent['description']}\n"
|
|
1247
|
-
|
|
1248
|
-
# Add routing information if available
|
|
1249
|
-
if agent.get("routing"):
|
|
1250
|
-
routing = agent["routing"]
|
|
1251
|
-
|
|
1252
|
-
# Format routing hints for PM usage
|
|
1253
|
-
routing_hints = []
|
|
1254
|
-
|
|
1255
|
-
if routing.get("keywords"):
|
|
1256
|
-
# Show first 5 keywords for brevity
|
|
1257
|
-
keywords = routing["keywords"][:5]
|
|
1258
|
-
routing_hints.append(f"Keywords: {', '.join(keywords)}")
|
|
1259
|
-
|
|
1260
|
-
if routing.get("paths"):
|
|
1261
|
-
# Show first 3 paths for brevity
|
|
1262
|
-
paths = routing["paths"][:3]
|
|
1263
|
-
routing_hints.append(f"Paths: {', '.join(paths)}")
|
|
1264
|
-
|
|
1265
|
-
if routing.get("priority"):
|
|
1266
|
-
routing_hints.append(f"Priority: {routing['priority']}")
|
|
1267
|
-
|
|
1268
|
-
if routing_hints:
|
|
1269
|
-
section += f"- **Routing**: {' | '.join(routing_hints)}\n"
|
|
1270
|
-
|
|
1271
|
-
# Add when_to_use if present
|
|
1272
|
-
if routing.get("when_to_use"):
|
|
1273
|
-
section += f"- **When to use**: {routing['when_to_use']}\n"
|
|
1274
|
-
|
|
1275
|
-
# Add any additional metadata if present
|
|
1276
|
-
if agent.get("authority"):
|
|
1277
|
-
section += f"- **Authority**: {agent['authority']}\n"
|
|
1278
|
-
if agent.get("primary_function"):
|
|
1279
|
-
section += f"- **Primary Function**: {agent['primary_function']}\n"
|
|
1280
|
-
if agent.get("handoff_to"):
|
|
1281
|
-
section += f"- **Handoff To**: {agent['handoff_to']}\n"
|
|
1282
|
-
if agent.get("tools") and agent["tools"] != "standard":
|
|
1283
|
-
section += f"- **Tools**: {agent['tools']}\n"
|
|
1284
|
-
if agent.get("model") and agent["model"] != "opus":
|
|
1285
|
-
section += f"- **Model**: {agent['model']}\n"
|
|
1286
|
-
|
|
1287
|
-
# Add memory routing information if available
|
|
1288
|
-
if agent.get("memory_routing"):
|
|
1289
|
-
memory_routing = agent["memory_routing"]
|
|
1290
|
-
if memory_routing.get("description"):
|
|
1291
|
-
section += (
|
|
1292
|
-
f"- **Memory Routing**: {memory_routing['description']}\n"
|
|
1293
|
-
)
|
|
1294
|
-
|
|
1295
|
-
# Add simple Context-Aware Agent Selection
|
|
1296
|
-
section += "\n## Context-Aware Agent Selection\n\n"
|
|
1297
|
-
section += (
|
|
1298
|
-
"Select agents based on their descriptions above. Key principles:\n"
|
|
1299
|
-
)
|
|
1300
|
-
section += "- **PM questions** → Answer directly (only exception)\n"
|
|
1301
|
-
section += "- Match task requirements to agent descriptions and authority\n"
|
|
1302
|
-
section += "- Consider agent handoff recommendations\n"
|
|
1303
|
-
section += (
|
|
1304
|
-
"- Use the agent ID in parentheses when delegating via Task tool\n"
|
|
385
|
+
for agents_dir in agents_dirs:
|
|
386
|
+
if agents_dir.exists():
|
|
387
|
+
for agent_file in agents_dir.glob("*.md"):
|
|
388
|
+
if not agent_file.name.startswith("."):
|
|
389
|
+
agent_data = self._parse_agent_metadata(agent_file)
|
|
390
|
+
if agent_data:
|
|
391
|
+
deployed_agents.append(agent_data)
|
|
392
|
+
|
|
393
|
+
# Generate capabilities section
|
|
394
|
+
section = self.capability_generator.generate_capabilities_section(
|
|
395
|
+
deployed_agents, local_agents
|
|
1305
396
|
)
|
|
1306
397
|
|
|
1307
|
-
#
|
|
1308
|
-
section += f"\n**Total Available Agents**: {len(deployed_agents)}\n"
|
|
1309
|
-
|
|
1310
|
-
# Cache the generated capabilities
|
|
398
|
+
# Cache the result
|
|
1311
399
|
self._cache_manager.set_capabilities(section)
|
|
1312
|
-
self.logger.debug(
|
|
1313
|
-
f"Cached agent capabilities section ({len(section)} chars)"
|
|
1314
|
-
)
|
|
400
|
+
self.logger.debug(f"Cached agent capabilities ({len(section)} chars)")
|
|
1315
401
|
|
|
1316
402
|
return section
|
|
1317
403
|
|
|
1318
404
|
except Exception as e:
|
|
1319
|
-
self.logger.warning(f"Could not generate
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
self._agent_capabilities_cache_time = current_time
|
|
1324
|
-
return result
|
|
405
|
+
self.logger.warning(f"Could not generate agent capabilities: {e}")
|
|
406
|
+
fallback = self.content_formatter.get_fallback_capabilities()
|
|
407
|
+
self._cache_manager.set_capabilities(fallback)
|
|
408
|
+
return fallback
|
|
1325
409
|
|
|
1326
|
-
|
|
1327
|
-
"""Generate enhanced temporal and user context for better PM awareness.
|
|
1328
|
-
|
|
1329
|
-
Returns:
|
|
1330
|
-
str: Formatted context string with datetime, user, and system information
|
|
1331
|
-
"""
|
|
1332
|
-
context_lines = ["\n\n## Temporal & User Context\n"]
|
|
410
|
+
# === Output Style Management ===
|
|
1333
411
|
|
|
412
|
+
def _initialize_output_style(self) -> None:
|
|
413
|
+
"""Initialize output style management."""
|
|
1334
414
|
try:
|
|
1335
|
-
|
|
1336
|
-
now = datetime.now()
|
|
1337
|
-
|
|
1338
|
-
# Try to get timezone info - fallback to UTC offset if timezone name not available
|
|
1339
|
-
try:
|
|
1340
|
-
import time as time_module
|
|
1341
|
-
|
|
1342
|
-
if hasattr(time_module, "tzname"):
|
|
1343
|
-
tz_name = time_module.tzname[time_module.daylight]
|
|
1344
|
-
tz_offset = time_module.strftime("%z")
|
|
1345
|
-
if tz_offset:
|
|
1346
|
-
# Format UTC offset properly (e.g., -0800 to -08:00)
|
|
1347
|
-
tz_offset = (
|
|
1348
|
-
f"{tz_offset[:3]}:{tz_offset[3:]}"
|
|
1349
|
-
if len(tz_offset) >= 4
|
|
1350
|
-
else tz_offset
|
|
1351
|
-
)
|
|
1352
|
-
tz_info = f"{tz_name} (UTC{tz_offset})"
|
|
1353
|
-
else:
|
|
1354
|
-
tz_info = tz_name
|
|
1355
|
-
else:
|
|
1356
|
-
tz_info = "Local Time"
|
|
1357
|
-
except Exception:
|
|
1358
|
-
tz_info = "Local Time"
|
|
415
|
+
from claude_mpm.core.output_style_manager import OutputStyleManager
|
|
1359
416
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
time_str = now.strftime("%H:%M:%S")
|
|
1363
|
-
day_name = now.strftime("%A")
|
|
417
|
+
self.output_style_manager = OutputStyleManager()
|
|
418
|
+
self._log_output_style_status()
|
|
1364
419
|
|
|
1365
|
-
|
|
1366
|
-
|
|
420
|
+
# Extract and save output style content
|
|
421
|
+
output_style_content = (
|
|
422
|
+
self.output_style_manager.extract_output_style_content(
|
|
423
|
+
framework_loader=self
|
|
424
|
+
)
|
|
1367
425
|
)
|
|
1368
|
-
|
|
426
|
+
self.output_style_manager.save_output_style(output_style_content)
|
|
1369
427
|
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
context_lines.append(
|
|
1374
|
-
f"**Today's Date**: {datetime.now().strftime('%Y-%m-%d')}\n"
|
|
428
|
+
# Deploy to Claude Code if supported
|
|
429
|
+
deployed = self.output_style_manager.deploy_output_style(
|
|
430
|
+
output_style_content
|
|
1375
431
|
)
|
|
1376
432
|
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
# Try multiple methods to get username
|
|
1382
|
-
methods = [
|
|
1383
|
-
lambda: os.environ.get("USER"),
|
|
1384
|
-
lambda: os.environ.get("USERNAME"), # Windows fallback
|
|
1385
|
-
lambda: getpass.getuser(),
|
|
1386
|
-
]
|
|
1387
|
-
|
|
1388
|
-
for method in methods:
|
|
1389
|
-
try:
|
|
1390
|
-
username = method()
|
|
1391
|
-
if username:
|
|
1392
|
-
break
|
|
1393
|
-
except Exception:
|
|
1394
|
-
continue
|
|
1395
|
-
|
|
1396
|
-
if username:
|
|
1397
|
-
context_lines.append(f"**User**: {username}\n")
|
|
1398
|
-
|
|
1399
|
-
# Add home directory if available
|
|
1400
|
-
try:
|
|
1401
|
-
home_dir = os.path.expanduser("~")
|
|
1402
|
-
if home_dir and home_dir != "~":
|
|
1403
|
-
context_lines.append(f"**Home Directory**: {home_dir}\n")
|
|
1404
|
-
except Exception:
|
|
1405
|
-
pass
|
|
1406
|
-
|
|
1407
|
-
except Exception as e:
|
|
1408
|
-
# User detection is optional, don't fail
|
|
1409
|
-
self.logger.debug(f"Could not detect user information: {e}")
|
|
1410
|
-
|
|
1411
|
-
try:
|
|
1412
|
-
# Get system information
|
|
1413
|
-
system_info = platform.system()
|
|
1414
|
-
if system_info:
|
|
1415
|
-
# Enhance system name for common platforms
|
|
1416
|
-
system_names = {
|
|
1417
|
-
"Darwin": "Darwin (macOS)",
|
|
1418
|
-
"Linux": "Linux",
|
|
1419
|
-
"Windows": "Windows",
|
|
1420
|
-
}
|
|
1421
|
-
system_display = system_names.get(system_info, system_info)
|
|
1422
|
-
context_lines.append(f"**System**: {system_display}\n")
|
|
1423
|
-
|
|
1424
|
-
# Add platform version if available
|
|
1425
|
-
try:
|
|
1426
|
-
platform_version = platform.release()
|
|
1427
|
-
if platform_version:
|
|
1428
|
-
context_lines.append(
|
|
1429
|
-
f"**System Version**: {platform_version}\n"
|
|
1430
|
-
)
|
|
1431
|
-
except Exception:
|
|
1432
|
-
pass
|
|
433
|
+
if deployed:
|
|
434
|
+
self.logger.info("✅ Output style deployed to Claude Code >= 1.0.83")
|
|
435
|
+
else:
|
|
436
|
+
self.logger.info("📝 Output style will be injected into instructions")
|
|
1433
437
|
|
|
1434
438
|
except Exception as e:
|
|
1435
|
-
|
|
1436
|
-
self.logger.debug(f"Could not detect system information: {e}")
|
|
1437
|
-
|
|
1438
|
-
try:
|
|
1439
|
-
# Add current working directory
|
|
1440
|
-
cwd = os.getcwd()
|
|
1441
|
-
if cwd:
|
|
1442
|
-
context_lines.append(f"**Working Directory**: {cwd}\n")
|
|
1443
|
-
except Exception:
|
|
1444
|
-
pass
|
|
1445
|
-
|
|
1446
|
-
try:
|
|
1447
|
-
# Add locale information if available
|
|
1448
|
-
current_locale = locale.getlocale()
|
|
1449
|
-
if current_locale and current_locale[0]:
|
|
1450
|
-
context_lines.append(f"**Locale**: {current_locale[0]}\n")
|
|
1451
|
-
except Exception:
|
|
1452
|
-
# Locale is optional
|
|
1453
|
-
pass
|
|
1454
|
-
|
|
1455
|
-
# Add instruction for applying context
|
|
1456
|
-
context_lines.append(
|
|
1457
|
-
"\nApply temporal and user awareness to all tasks, "
|
|
1458
|
-
"decisions, and interactions.\n"
|
|
1459
|
-
)
|
|
1460
|
-
context_lines.append(
|
|
1461
|
-
"Use this context for personalized responses and "
|
|
1462
|
-
"time-sensitive operations.\n"
|
|
1463
|
-
)
|
|
1464
|
-
|
|
1465
|
-
return "".join(context_lines)
|
|
1466
|
-
|
|
1467
|
-
def _parse_agent_metadata(self, agent_file: Path) -> Optional[Dict[str, Any]]:
|
|
1468
|
-
"""Parse agent metadata from deployed agent file.
|
|
1469
|
-
Uses caching based on file path and modification time.
|
|
1470
|
-
|
|
1471
|
-
Returns:
|
|
1472
|
-
Dictionary with agent metadata directly from YAML frontmatter.
|
|
1473
|
-
"""
|
|
1474
|
-
try:
|
|
1475
|
-
# Check cache based on file path and modification time
|
|
1476
|
-
cache_key = str(agent_file)
|
|
1477
|
-
file_mtime = agent_file.stat().st_mtime
|
|
1478
|
-
time.time()
|
|
1479
|
-
|
|
1480
|
-
# Try to get from cache first
|
|
1481
|
-
cached_result = self._cache_manager.get_agent_metadata(cache_key)
|
|
1482
|
-
if cached_result is not None:
|
|
1483
|
-
cached_data, cached_mtime = cached_result
|
|
1484
|
-
# Use cache if file hasn't been modified and cache isn't too old
|
|
1485
|
-
if cached_mtime == file_mtime:
|
|
1486
|
-
self.logger.debug(f"Using cached metadata for {agent_file.name}")
|
|
1487
|
-
return cached_data
|
|
1488
|
-
|
|
1489
|
-
# Cache miss or expired - parse the file
|
|
1490
|
-
self.logger.debug(
|
|
1491
|
-
f"Parsing metadata for {agent_file.name} (cache miss or expired)"
|
|
1492
|
-
)
|
|
1493
|
-
|
|
1494
|
-
import yaml
|
|
439
|
+
self.logger.warning(f"❌ Failed to initialize output style manager: {e}")
|
|
1495
440
|
|
|
1496
|
-
|
|
1497
|
-
|
|
441
|
+
def _log_output_style_status(self) -> None:
|
|
442
|
+
"""Log output style status information."""
|
|
443
|
+
if not self.output_style_manager:
|
|
444
|
+
return
|
|
1498
445
|
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
"display_name": agent_file.stem.replace("_", " ")
|
|
1503
|
-
.replace("-", " ")
|
|
1504
|
-
.title(),
|
|
1505
|
-
"description": "Specialized agent",
|
|
1506
|
-
}
|
|
446
|
+
claude_version = self.output_style_manager.claude_version
|
|
447
|
+
if claude_version:
|
|
448
|
+
self.logger.info(f"Claude Code version detected: {claude_version}")
|
|
1507
449
|
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
if
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
# Copy all metadata fields directly
|
|
1524
|
-
for key, value in metadata.items():
|
|
1525
|
-
if key not in ["name"]: # Skip already processed fields
|
|
1526
|
-
agent_data[key] = value
|
|
1527
|
-
|
|
1528
|
-
# IMPORTANT: Do NOT add spaces to tools field - it breaks deployment!
|
|
1529
|
-
# Tools must remain as comma-separated without spaces: "Read,Write,Edit"
|
|
1530
|
-
|
|
1531
|
-
# Try to load routing metadata from JSON template if not in YAML frontmatter
|
|
1532
|
-
if "routing" not in agent_data:
|
|
1533
|
-
routing_data = self._load_routing_from_template(agent_file.stem)
|
|
1534
|
-
if routing_data:
|
|
1535
|
-
agent_data["routing"] = routing_data
|
|
1536
|
-
|
|
1537
|
-
# Try to load memory routing metadata from JSON template if not in YAML frontmatter
|
|
1538
|
-
if "memory_routing" not in agent_data:
|
|
1539
|
-
memory_routing_data = self._load_memory_routing_from_template(
|
|
1540
|
-
agent_file.stem
|
|
450
|
+
if self.output_style_manager.supports_output_styles():
|
|
451
|
+
self.logger.info("✅ Claude Code supports output styles (>= 1.0.83)")
|
|
452
|
+
output_style_path = self.output_style_manager.output_style_path
|
|
453
|
+
if output_style_path.exists():
|
|
454
|
+
self.logger.info(
|
|
455
|
+
f"📁 Output style file exists: {output_style_path}"
|
|
456
|
+
)
|
|
457
|
+
else:
|
|
458
|
+
self.logger.info(
|
|
459
|
+
f"📝 Output style will be created at: {output_style_path}"
|
|
460
|
+
)
|
|
461
|
+
else:
|
|
462
|
+
self.logger.info(
|
|
463
|
+
f"⚠️ Claude Code {claude_version} does not support output styles"
|
|
1541
464
|
)
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
self.
|
|
1547
|
-
|
|
1548
|
-
return agent_data
|
|
1549
|
-
|
|
1550
|
-
except Exception as e:
|
|
1551
|
-
self.logger.debug(f"Could not parse metadata from {agent_file}: {e}")
|
|
1552
|
-
return None
|
|
1553
|
-
|
|
1554
|
-
def _load_memory_routing_from_template(
|
|
1555
|
-
self, agent_name: str
|
|
1556
|
-
) -> Optional[Dict[str, Any]]:
|
|
1557
|
-
"""Load memory routing metadata from agent JSON template.
|
|
465
|
+
self.logger.info(
|
|
466
|
+
"📝 Output style will be injected into framework instructions"
|
|
467
|
+
)
|
|
468
|
+
else:
|
|
469
|
+
self.logger.info("⚠️ Claude Code not detected or version unknown")
|
|
470
|
+
self.logger.info("📝 Output style will be injected as fallback")
|
|
1558
471
|
|
|
1559
|
-
|
|
1560
|
-
agent_name: Name of the agent (stem of the file)
|
|
472
|
+
# === Logging Methods ===
|
|
1561
473
|
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
"""
|
|
474
|
+
def _log_system_prompt(self) -> None:
|
|
475
|
+
"""Log the system prompt if LogManager is available."""
|
|
1565
476
|
try:
|
|
1566
|
-
import
|
|
1567
|
-
|
|
1568
|
-
# Check if we have a framework path
|
|
1569
|
-
if not self.framework_path or self.framework_path == Path("__PACKAGED__"):
|
|
1570
|
-
# For packaged installations, try to load from package resources
|
|
1571
|
-
if files:
|
|
1572
|
-
try:
|
|
1573
|
-
templates_package = files("claude_mpm.agents.templates")
|
|
1574
|
-
template_file = templates_package / f"{agent_name}.json"
|
|
1575
|
-
|
|
1576
|
-
if template_file.is_file():
|
|
1577
|
-
template_content = template_file.read_text()
|
|
1578
|
-
template_data = json.loads(template_content)
|
|
1579
|
-
return template_data.get("memory_routing")
|
|
1580
|
-
except Exception as e:
|
|
1581
|
-
self.logger.debug(
|
|
1582
|
-
f"Could not load memory routing from packaged template for {agent_name}: {e}"
|
|
1583
|
-
)
|
|
1584
|
-
return None
|
|
1585
|
-
|
|
1586
|
-
# For development mode, load from filesystem
|
|
1587
|
-
templates_dir = (
|
|
1588
|
-
self.framework_path / "src" / "claude_mpm" / "agents" / "templates"
|
|
1589
|
-
)
|
|
1590
|
-
template_file = templates_dir / f"{agent_name}.json"
|
|
1591
|
-
|
|
1592
|
-
if template_file.exists():
|
|
1593
|
-
with open(template_file) as f:
|
|
1594
|
-
template_data = json.load(f)
|
|
1595
|
-
return template_data.get("memory_routing")
|
|
1596
|
-
|
|
1597
|
-
# Also check for variations in naming (underscore vs dash)
|
|
1598
|
-
# Handle common naming variations between deployed .md files and .json templates
|
|
1599
|
-
# Remove duplicates by using a set
|
|
1600
|
-
alternative_names = list(
|
|
1601
|
-
{
|
|
1602
|
-
agent_name.replace("-", "_"), # api-qa -> api_qa
|
|
1603
|
-
agent_name.replace("_", "-"), # api_qa -> api-qa
|
|
1604
|
-
agent_name.replace("-", ""), # api-qa -> apiqa
|
|
1605
|
-
agent_name.replace("_", ""), # api_qa -> apiqa
|
|
1606
|
-
agent_name.replace("-agent", ""), # research-agent -> research
|
|
1607
|
-
agent_name.replace("_agent", ""), # research_agent -> research
|
|
1608
|
-
agent_name + "_agent", # research -> research_agent
|
|
1609
|
-
agent_name + "-agent", # research -> research-agent
|
|
1610
|
-
}
|
|
1611
|
-
)
|
|
1612
|
-
|
|
1613
|
-
for alt_name in alternative_names:
|
|
1614
|
-
if alt_name != agent_name: # Skip the original name we already tried
|
|
1615
|
-
alt_file = templates_dir / f"{alt_name}.json"
|
|
1616
|
-
if alt_file.exists():
|
|
1617
|
-
with open(alt_file) as f:
|
|
1618
|
-
template_data = json.load(f)
|
|
1619
|
-
return template_data.get("memory_routing")
|
|
1620
|
-
|
|
1621
|
-
return None
|
|
1622
|
-
|
|
1623
|
-
except Exception as e:
|
|
1624
|
-
self.logger.debug(
|
|
1625
|
-
f"Could not load memory routing from template for {agent_name}: {e}"
|
|
1626
|
-
)
|
|
1627
|
-
return None
|
|
1628
|
-
|
|
1629
|
-
def _load_routing_from_template(self, agent_name: str) -> Optional[Dict[str, Any]]:
|
|
1630
|
-
"""Load routing metadata from agent JSON template.
|
|
477
|
+
from .log_manager import get_log_manager
|
|
1631
478
|
|
|
1632
|
-
|
|
1633
|
-
|
|
479
|
+
log_manager = get_log_manager()
|
|
480
|
+
except ImportError:
|
|
481
|
+
return
|
|
1634
482
|
|
|
1635
|
-
Returns:
|
|
1636
|
-
Dictionary with routing metadata or None if not found
|
|
1637
|
-
"""
|
|
1638
483
|
try:
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
return template_data.get("routing")
|
|
1653
|
-
except Exception as e:
|
|
1654
|
-
self.logger.debug(
|
|
1655
|
-
f"Could not load routing from packaged template for {agent_name}: {e}"
|
|
1656
|
-
)
|
|
1657
|
-
return None
|
|
1658
|
-
|
|
1659
|
-
# For development mode, load from filesystem
|
|
1660
|
-
templates_dir = (
|
|
1661
|
-
self.framework_path / "src" / "claude_mpm" / "agents" / "templates"
|
|
1662
|
-
)
|
|
1663
|
-
template_file = templates_dir / f"{agent_name}.json"
|
|
1664
|
-
|
|
1665
|
-
if template_file.exists():
|
|
1666
|
-
with open(template_file) as f:
|
|
1667
|
-
template_data = json.load(f)
|
|
1668
|
-
return template_data.get("routing")
|
|
1669
|
-
|
|
1670
|
-
# Also check for variations in naming (underscore vs dash)
|
|
1671
|
-
# Handle common naming variations between deployed .md files and .json templates
|
|
1672
|
-
# Remove duplicates by using a set
|
|
1673
|
-
alternative_names = list(
|
|
1674
|
-
{
|
|
1675
|
-
agent_name.replace("-", "_"), # api-qa -> api_qa
|
|
1676
|
-
agent_name.replace("_", "-"), # api_qa -> api-qa
|
|
1677
|
-
agent_name.replace("-", ""), # api-qa -> apiqa
|
|
1678
|
-
agent_name.replace("_", ""), # api_qa -> apiqa
|
|
1679
|
-
}
|
|
1680
|
-
)
|
|
1681
|
-
|
|
1682
|
-
for alt_name in alternative_names:
|
|
1683
|
-
if alt_name != agent_name:
|
|
1684
|
-
alt_file = templates_dir / f"{alt_name}.json"
|
|
1685
|
-
if alt_file.exists():
|
|
1686
|
-
with open(alt_file) as f:
|
|
1687
|
-
template_data = json.load(f)
|
|
1688
|
-
return template_data.get("routing")
|
|
1689
|
-
|
|
1690
|
-
self.logger.debug(f"No JSON template found for agent: {agent_name}")
|
|
1691
|
-
return None
|
|
1692
|
-
|
|
1693
|
-
except Exception as e:
|
|
1694
|
-
self.logger.debug(f"Could not load routing metadata for {agent_name}: {e}")
|
|
1695
|
-
return None
|
|
1696
|
-
|
|
1697
|
-
def _generate_agent_selection_guide(self, deployed_agents: list) -> str:
|
|
1698
|
-
"""Generate Context-Aware Agent Selection guide from deployed agents.
|
|
1699
|
-
|
|
1700
|
-
Creates a mapping of task types to appropriate agents based on their
|
|
1701
|
-
descriptions and capabilities.
|
|
1702
|
-
"""
|
|
1703
|
-
guide = ""
|
|
1704
|
-
|
|
1705
|
-
# Build selection mapping based on deployed agents
|
|
1706
|
-
selection_map = {}
|
|
484
|
+
# Get or create event loop
|
|
485
|
+
try:
|
|
486
|
+
loop = asyncio.get_running_loop()
|
|
487
|
+
except RuntimeError:
|
|
488
|
+
loop = asyncio.new_event_loop()
|
|
489
|
+
asyncio.set_event_loop(loop)
|
|
490
|
+
|
|
491
|
+
# Prepare metadata
|
|
492
|
+
metadata = {
|
|
493
|
+
"framework_version": self.framework_version,
|
|
494
|
+
"framework_loaded": self.framework_content.get("loaded", False),
|
|
495
|
+
"session_id": os.environ.get("CLAUDE_SESSION_ID", "unknown"),
|
|
496
|
+
}
|
|
1707
497
|
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
498
|
+
# Log the prompt asynchronously
|
|
499
|
+
instructions = (
|
|
500
|
+
self._format_full_framework()
|
|
501
|
+
if self.framework_content["loaded"]
|
|
502
|
+
else self._format_minimal_framework()
|
|
503
|
+
)
|
|
504
|
+
metadata["instructions_length"] = len(instructions)
|
|
1711
505
|
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
if "codebase analysis" in desc_lower or "research" in agent_id:
|
|
1720
|
-
selection_map["Codebase analysis"] = (
|
|
1721
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1722
|
-
)
|
|
1723
|
-
if "testing" in desc_lower or "qa" in agent_id:
|
|
1724
|
-
selection_map["Testing/quality"] = (
|
|
1725
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1726
|
-
)
|
|
1727
|
-
if "documentation" in desc_lower:
|
|
1728
|
-
selection_map["Documentation"] = (
|
|
1729
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1730
|
-
)
|
|
1731
|
-
if "security" in desc_lower or "sast" in desc_lower:
|
|
1732
|
-
selection_map["Security operations"] = (
|
|
1733
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1734
|
-
)
|
|
1735
|
-
if (
|
|
1736
|
-
"deployment" in desc_lower
|
|
1737
|
-
or "infrastructure" in desc_lower
|
|
1738
|
-
or "ops" in agent_id
|
|
1739
|
-
):
|
|
1740
|
-
selection_map["Deployment/infrastructure"] = (
|
|
1741
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1742
|
-
)
|
|
1743
|
-
if "data" in desc_lower and (
|
|
1744
|
-
"pipeline" in desc_lower or "etl" in desc_lower
|
|
1745
|
-
):
|
|
1746
|
-
selection_map["Data pipeline/ETL"] = (
|
|
1747
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1748
|
-
)
|
|
1749
|
-
if "git" in desc_lower or "version control" in desc_lower:
|
|
1750
|
-
selection_map["Version control"] = (
|
|
1751
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1752
|
-
)
|
|
1753
|
-
if "ticket" in desc_lower or "epic" in desc_lower:
|
|
1754
|
-
selection_map["Ticket/issue management"] = (
|
|
1755
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1756
|
-
)
|
|
1757
|
-
if "browser" in desc_lower or "e2e" in desc_lower:
|
|
1758
|
-
selection_map["Browser/E2E testing"] = (
|
|
1759
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1760
|
-
)
|
|
1761
|
-
if "frontend" in desc_lower or "ui" in desc_lower or "html" in desc_lower:
|
|
1762
|
-
selection_map["Frontend/UI development"] = (
|
|
1763
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
506
|
+
if loop.is_running():
|
|
507
|
+
_task = asyncio.create_task(
|
|
508
|
+
log_manager.log_prompt("system_prompt", instructions, metadata)
|
|
509
|
+
) # Fire-and-forget logging
|
|
510
|
+
else:
|
|
511
|
+
loop.run_until_complete(
|
|
512
|
+
log_manager.log_prompt("system_prompt", instructions, metadata)
|
|
1764
513
|
)
|
|
1765
514
|
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
# Format the selection guide
|
|
1770
|
-
for task_type, agent_info in selection_map.items():
|
|
1771
|
-
guide += f"- **{task_type}** → {agent_info}\n"
|
|
1772
|
-
|
|
1773
|
-
return guide
|
|
1774
|
-
|
|
1775
|
-
def _get_fallback_capabilities(self) -> str:
|
|
1776
|
-
"""Return fallback capabilities when dynamic discovery fails."""
|
|
1777
|
-
return """
|
|
1778
|
-
|
|
1779
|
-
## Available Agent Capabilities
|
|
1780
|
-
|
|
1781
|
-
You have the following specialized agents available for delegation:
|
|
1782
|
-
|
|
1783
|
-
- **Engineer** (`engineer`): Code implementation and development
|
|
1784
|
-
- **Research** (`research-agent`): Investigation and analysis
|
|
1785
|
-
- **QA** (`qa-agent`): Testing and quality assurance
|
|
1786
|
-
- **Documentation** (`documentation-agent`): Documentation creation and maintenance
|
|
1787
|
-
- **Security** (`security-agent`): Security analysis and protection
|
|
1788
|
-
- **Data Engineer** (`data-engineer`): Data management and pipelines
|
|
1789
|
-
- **Ops** (`ops-agent`): Deployment and operations
|
|
1790
|
-
- **Version Control** (`version-control`): Git operations and version management
|
|
515
|
+
self.logger.debug("System prompt logged to prompts directory")
|
|
516
|
+
except Exception as e:
|
|
517
|
+
self.logger.debug(f"Could not log system prompt: {e}")
|
|
1791
518
|
|
|
1792
|
-
|
|
1793
|
-
"""
|
|
519
|
+
# === Agent Registry Methods (backward compatibility) ===
|
|
1794
520
|
|
|
1795
|
-
def
|
|
1796
|
-
"""Format minimal framework instructions when full framework not available."""
|
|
1797
|
-
return """
|
|
1798
|
-
# Claude PM Framework Instructions
|
|
1799
|
-
|
|
1800
|
-
You are operating within a Claude PM Framework deployment.
|
|
1801
|
-
|
|
1802
|
-
## Role
|
|
1803
|
-
You are a multi-agent orchestrator. Your primary responsibilities:
|
|
1804
|
-
- Delegate tasks to specialized agents via Task Tool
|
|
1805
|
-
- Coordinate multi-agent workflows
|
|
1806
|
-
- Extract TODO/BUG/FEATURE items for ticket creation
|
|
1807
|
-
- NEVER perform direct implementation work
|
|
1808
|
-
|
|
1809
|
-
## Core Agents
|
|
1810
|
-
- Documentation Agent - Documentation tasks
|
|
1811
|
-
- Engineer Agent - Code implementation
|
|
1812
|
-
- QA Agent - Testing and validation
|
|
1813
|
-
- Research Agent - Investigation and analysis
|
|
1814
|
-
- Version Control Agent - Git operations
|
|
1815
|
-
|
|
1816
|
-
## Important Rules
|
|
1817
|
-
1. Always delegate work via Task Tool
|
|
1818
|
-
2. Provide comprehensive context to agents
|
|
1819
|
-
3. Track all TODO/BUG/FEATURE items
|
|
1820
|
-
4. Maintain project visibility
|
|
1821
|
-
|
|
1822
|
-
---
|
|
1823
|
-
"""
|
|
1824
|
-
|
|
1825
|
-
def get_agent_list(self) -> list:
|
|
521
|
+
def get_agent_list(self) -> List[str]:
|
|
1826
522
|
"""Get list of available agents."""
|
|
1827
|
-
# First try agent registry
|
|
1828
523
|
if self.agent_registry:
|
|
1829
524
|
agents = self.agent_registry.list_agents()
|
|
1830
525
|
if agents:
|
|
1831
526
|
return list(agents.keys())
|
|
1832
|
-
|
|
1833
|
-
# Fallback to loaded content
|
|
1834
527
|
return list(self.framework_content["agents"].keys())
|
|
1835
528
|
|
|
1836
529
|
def get_agent_definition(self, agent_name: str) -> Optional[str]:
|
|
1837
530
|
"""Get specific agent definition."""
|
|
1838
|
-
# First try agent registry
|
|
1839
531
|
if self.agent_registry:
|
|
1840
532
|
definition = self.agent_registry.get_agent_definition(agent_name)
|
|
1841
533
|
if definition:
|
|
1842
534
|
return definition
|
|
1843
|
-
|
|
1844
|
-
# Fallback to loaded content
|
|
1845
535
|
return self.framework_content["agents"].get(agent_name)
|
|
1846
536
|
|
|
1847
|
-
def get_agent_hierarchy(self) -> Dict[str,
|
|
537
|
+
def get_agent_hierarchy(self) -> Dict[str, List]:
|
|
1848
538
|
"""Get agent hierarchy from registry."""
|
|
1849
539
|
if self.agent_registry:
|
|
1850
540
|
return self.agent_registry.get_agent_hierarchy()
|