claude-mpm 4.1.6__py3-none-any.whl → 4.24.0__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 +431 -214
- 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/MEMORY.md +3 -0
- claude_mpm/agents/OUTPUT_STYLE.md +335 -0
- claude_mpm/agents/PM_INSTRUCTIONS.md +1159 -0
- claude_mpm/agents/WORKFLOW.md +355 -187
- claude_mpm/agents/agent_loader.py +40 -10
- claude_mpm/agents/agent_loader_integration.py +3 -2
- claude_mpm/agents/agents_metadata.py +57 -0
- claude_mpm/agents/async_agent_loader.py +3 -3
- claude_mpm/agents/base_agent_loader.py +11 -9
- claude_mpm/agents/frontmatter_validator.py +291 -251
- claude_mpm/agents/system_agent_config.py +3 -2
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +17 -0
- claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +3 -0
- claude_mpm/agents/templates/README.md +465 -0
- claude_mpm/agents/templates/agent-manager.json +267 -18
- claude_mpm/agents/templates/agentic-coder-optimizer.json +248 -0
- claude_mpm/agents/templates/api_qa.json +16 -4
- claude_mpm/agents/templates/circuit_breakers.md +638 -0
- claude_mpm/agents/templates/clerk-ops.json +235 -0
- claude_mpm/agents/templates/code_analyzer.json +25 -9
- claude_mpm/agents/templates/content-agent.json +358 -0
- claude_mpm/agents/templates/dart_engineer.json +307 -0
- claude_mpm/agents/templates/data_engineer.json +87 -14
- claude_mpm/agents/templates/documentation.json +76 -13
- claude_mpm/agents/templates/engineer.json +44 -10
- claude_mpm/agents/templates/gcp_ops_agent.json +253 -0
- claude_mpm/agents/templates/git_file_tracking.md +584 -0
- claude_mpm/agents/templates/golang_engineer.json +270 -0
- claude_mpm/agents/templates/imagemagick.json +5 -2
- claude_mpm/agents/templates/java_engineer.json +346 -0
- claude_mpm/agents/templates/javascript_engineer_agent.json +380 -0
- claude_mpm/agents/templates/local_ops_agent.json +1840 -0
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +39 -0
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md +400 -0
- claude_mpm/agents/templates/memory_manager.json +6 -3
- claude_mpm/agents/templates/nextjs_engineer.json +285 -0
- claude_mpm/agents/templates/ops.json +27 -8
- claude_mpm/agents/templates/php-engineer.json +287 -0
- claude_mpm/agents/templates/pm_examples.md +474 -0
- claude_mpm/agents/templates/pm_red_flags.md +262 -0
- claude_mpm/agents/templates/product_owner.json +338 -0
- claude_mpm/agents/templates/project_organizer.json +19 -5
- claude_mpm/agents/templates/prompt-engineer.json +737 -0
- claude_mpm/agents/templates/python_engineer.json +387 -0
- claude_mpm/agents/templates/qa.json +26 -6
- claude_mpm/agents/templates/react_engineer.json +239 -0
- claude_mpm/agents/templates/refactoring_engineer.json +15 -5
- claude_mpm/agents/templates/research.json +47 -22
- claude_mpm/agents/templates/response_format.md +583 -0
- claude_mpm/agents/templates/ruby-engineer.json +280 -0
- claude_mpm/agents/templates/rust_engineer.json +275 -0
- claude_mpm/agents/templates/security.json +59 -10
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/agents/templates/tauri_engineer.json +274 -0
- claude_mpm/agents/templates/ticketing.json +16 -7
- claude_mpm/agents/templates/typescript_engineer.json +285 -0
- claude_mpm/agents/templates/validation_templates.md +312 -0
- claude_mpm/agents/templates/vercel_ops_agent.json +164 -33
- claude_mpm/agents/templates/version_control.json +16 -4
- claude_mpm/agents/templates/web_qa.json +243 -21
- claude_mpm/agents/templates/web_ui.json +18 -5
- claude_mpm/cli/__init__.py +38 -363
- claude_mpm/cli/commands/__init__.py +8 -0
- claude_mpm/cli/commands/agent_manager.py +675 -20
- claude_mpm/cli/commands/agent_state_manager.py +186 -0
- claude_mpm/cli/commands/agents.py +722 -150
- claude_mpm/cli/commands/agents_detect.py +380 -0
- claude_mpm/cli/commands/agents_recommend.py +309 -0
- claude_mpm/cli/commands/aggregate.py +10 -6
- claude_mpm/cli/commands/analyze.py +553 -0
- claude_mpm/cli/commands/analyze_code.py +528 -0
- claude_mpm/cli/commands/auto_configure.py +570 -0
- claude_mpm/cli/commands/cleanup.py +12 -12
- claude_mpm/cli/commands/config.py +47 -13
- claude_mpm/cli/commands/configure.py +488 -884
- claude_mpm/cli/commands/configure_agent_display.py +261 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +167 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/dashboard.py +286 -0
- claude_mpm/cli/commands/debug.py +1386 -0
- claude_mpm/cli/commands/doctor.py +43 -7
- claude_mpm/cli/commands/info.py +3 -4
- claude_mpm/cli/commands/local_deploy.py +537 -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 +168 -617
- claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
- claude_mpm/cli/commands/mpm_init/core.py +525 -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 +195 -0
- claude_mpm/cli/commands/run.py +169 -42
- claude_mpm/cli/commands/search.py +458 -0
- claude_mpm/cli/commands/skills.py +488 -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 +204 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +21 -0
- claude_mpm/cli/interactive/agent_wizard.py +962 -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/agents_parser.py +116 -0
- claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
- claude_mpm/cli/parsers/analyze_parser.py +135 -0
- claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
- claude_mpm/cli/parsers/base_parser.py +187 -3
- claude_mpm/cli/parsers/configure_parser.py +34 -15
- claude_mpm/cli/parsers/dashboard_parser.py +113 -0
- claude_mpm/cli/parsers/debug_parser.py +319 -0
- 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 +311 -0
- claude_mpm/cli/parsers/run_parser.py +5 -0
- claude_mpm/cli/parsers/search_parser.py +245 -0
- claude_mpm/cli/parsers/skills_parser.py +137 -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 +562 -0
- claude_mpm/cli/startup_logging.py +179 -13
- claude_mpm/cli/utils.py +53 -2
- claude_mpm/commands/__init__.py +14 -0
- claude_mpm/commands/mpm-agents-detect.md +168 -0
- claude_mpm/commands/mpm-agents-recommend.md +214 -0
- claude_mpm/commands/mpm-agents.md +122 -0
- claude_mpm/commands/mpm-auto-configure.md +269 -0
- claude_mpm/commands/mpm-config.md +141 -0
- claude_mpm/commands/mpm-doctor.md +24 -0
- claude_mpm/commands/mpm-help.md +290 -0
- claude_mpm/commands/mpm-init.md +521 -0
- claude_mpm/commands/mpm-monitor.md +409 -0
- claude_mpm/commands/mpm-organize.md +295 -0
- claude_mpm/commands/mpm-resume.md +372 -0
- claude_mpm/commands/mpm-status.md +75 -0
- claude_mpm/commands/mpm-tickets.md +151 -0
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +21 -0
- claude_mpm/config/agent_config.py +4 -4
- 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/socketio_config.py +36 -7
- claude_mpm/constants.py +27 -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 +19 -8
- claude_mpm/core/config.py +103 -8
- claude_mpm/core/config_aliases.py +7 -6
- claude_mpm/core/constants.py +65 -0
- 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 +38 -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 +223 -0
- claude_mpm/core/framework/loaders/instruction_loader.py +161 -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 +323 -1491
- claude_mpm/core/hook_manager.py +8 -6
- claude_mpm/core/injectable_service.py +11 -8
- claude_mpm/core/instruction_reinforcement_hook.py +267 -0
- claude_mpm/core/interactive_session.py +55 -8
- claude_mpm/core/interfaces.py +56 -1
- claude_mpm/core/lazy.py +3 -3
- claude_mpm/core/log_manager.py +100 -28
- claude_mpm/core/logger.py +19 -14
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/logging_utils.py +520 -0
- claude_mpm/core/oneshot_session.py +51 -7
- 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 +118 -15
- 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/socketio_pool.py +15 -15
- 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 +116 -12
- claude_mpm/core/unified_config.py +6 -6
- claude_mpm/core/unified_paths.py +23 -20
- claude_mpm/dashboard/.claude-mpm/socketio-instances.json +1 -0
- claude_mpm/dashboard/__init__.py +12 -0
- claude_mpm/dashboard/analysis_runner.py +455 -0
- claude_mpm/dashboard/api/simple_directory.py +261 -0
- claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +188 -0
- claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +156 -0
- claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +38 -0
- claude_mpm/dashboard/react/components/shared/FilterBar.module.css +92 -0
- claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +248 -0
- claude_mpm/dashboard/static/archive/activity_dashboard_test.html +61 -0
- claude_mpm/dashboard/static/archive/test_activity_connection.html +179 -0
- claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +68 -0
- claude_mpm/dashboard/static/archive/test_dashboard.html +409 -0
- claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +519 -0
- claude_mpm/dashboard/static/archive/test_dashboard_verification.html +181 -0
- claude_mpm/dashboard/static/archive/test_file_data.html +315 -0
- claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +243 -0
- claude_mpm/dashboard/static/archive/test_file_tree_fix.html +234 -0
- claude_mpm/dashboard/static/archive/test_file_tree_rename.html +117 -0
- claude_mpm/dashboard/static/archive/test_file_tree_tab.html +115 -0
- claude_mpm/dashboard/static/archive/test_file_viewer.html +224 -0
- claude_mpm/dashboard/static/archive/test_final_activity.html +220 -0
- claude_mpm/dashboard/static/archive/test_tab_fix.html +139 -0
- claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +1 -0
- claude_mpm/dashboard/static/built/components/activity-tree.js +2 -0
- claude_mpm/dashboard/static/built/components/agent-hierarchy.js +777 -0
- claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
- claude_mpm/dashboard/static/built/components/build-tracker.js +333 -0
- claude_mpm/dashboard/static/built/components/code-simple.js +857 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +353 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +235 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +409 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +435 -0
- claude_mpm/dashboard/static/built/components/code-tree.js +2 -0
- claude_mpm/dashboard/static/built/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/connection-debug.js +654 -0
- claude_mpm/dashboard/static/built/components/diff-viewer.js +891 -0
- claude_mpm/dashboard/static/built/components/event-processor.js +1 -1
- claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/export-manager.js +1 -1
- claude_mpm/dashboard/static/built/components/file-change-tracker.js +443 -0
- claude_mpm/dashboard/static/built/components/file-change-viewer.js +690 -0
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
- claude_mpm/dashboard/static/built/components/file-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/nav-bar.js +145 -0
- claude_mpm/dashboard/static/built/components/page-structure.js +429 -0
- claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/built/components/unified-data-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
- claude_mpm/dashboard/static/built/connection-manager.js +536 -0
- claude_mpm/dashboard/static/built/dashboard.js +1 -1
- claude_mpm/dashboard/static/built/extension-error-handler.js +164 -0
- claude_mpm/dashboard/static/built/react/events.js +30 -0
- claude_mpm/dashboard/static/built/shared/dom-helpers.js +396 -0
- claude_mpm/dashboard/static/built/shared/event-bus.js +330 -0
- claude_mpm/dashboard/static/built/shared/event-filter-service.js +540 -0
- claude_mpm/dashboard/static/built/shared/logger.js +385 -0
- claude_mpm/dashboard/static/built/shared/page-structure.js +249 -0
- claude_mpm/dashboard/static/built/shared/tooltip-service.js +253 -0
- claude_mpm/dashboard/static/built/socket-client.js +1 -1
- claude_mpm/dashboard/static/built/tab-isolation-fix.js +185 -0
- claude_mpm/dashboard/static/css/activity.css +1958 -0
- claude_mpm/dashboard/static/css/dashboard.css +1413 -72
- claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +1 -0
- claude_mpm/dashboard/static/dist/components/activity-tree.js +2 -0
- claude_mpm/dashboard/static/dist/components/agent-inference.js +1 -1
- claude_mpm/dashboard/static/dist/components/code-tree.js +2 -0
- claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-processor.js +1 -1
- claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/export-manager.js +1 -1
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +1 -1
- claude_mpm/dashboard/static/dist/components/file-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/dist/components/unified-data-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/working-directory.js +1 -1
- claude_mpm/dashboard/static/dist/dashboard.js +1 -1
- claude_mpm/dashboard/static/dist/react/events.js +30 -0
- claude_mpm/dashboard/static/dist/socket-client.js +1 -1
- claude_mpm/dashboard/static/events.html +607 -0
- claude_mpm/dashboard/static/index.html +635 -0
- claude_mpm/dashboard/static/js/components/activity-tree.js +1871 -0
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +4 -1
- claude_mpm/dashboard/static/js/components/agent-inference.js +3 -0
- claude_mpm/dashboard/static/js/components/build-tracker.js +23 -13
- claude_mpm/dashboard/static/js/components/code-simple.js +857 -0
- claude_mpm/dashboard/static/js/components/diff-viewer.js +891 -0
- claude_mpm/dashboard/static/js/components/event-processor.js +3 -107
- claude_mpm/dashboard/static/js/components/event-viewer.js +98 -11
- 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 +30 -10
- claude_mpm/dashboard/static/js/components/file-viewer.js +580 -0
- claude_mpm/dashboard/static/js/components/module-viewer.js +68 -205
- claude_mpm/dashboard/static/js/components/session-manager.js +46 -10
- claude_mpm/dashboard/static/js/components/socket-manager.js +16 -0
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +359 -40
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +1824 -0
- claude_mpm/dashboard/static/js/components/working-directory.js +61 -10
- claude_mpm/dashboard/static/js/connection-manager.js +1 -1
- claude_mpm/dashboard/static/js/dashboard.js +523 -622
- claude_mpm/dashboard/static/js/shared/dom-helpers.js +396 -0
- claude_mpm/dashboard/static/js/shared/event-bus.js +330 -0
- claude_mpm/dashboard/static/js/shared/logger.js +385 -0
- claude_mpm/dashboard/static/js/shared/tooltip-service.js +253 -0
- claude_mpm/dashboard/static/js/socket-client.js +549 -62
- claude_mpm/dashboard/static/js/stores/dashboard-store.js +562 -0
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +185 -0
- claude_mpm/dashboard/static/legacy/activity.html +736 -0
- claude_mpm/dashboard/static/legacy/agents.html +786 -0
- claude_mpm/dashboard/static/legacy/files.html +747 -0
- claude_mpm/dashboard/static/legacy/tools.html +831 -0
- claude_mpm/dashboard/static/monitors.html +431 -0
- claude_mpm/dashboard/static/production/events.html +659 -0
- claude_mpm/dashboard/static/production/main.html +698 -0
- claude_mpm/dashboard/static/production/monitors.html +483 -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/static/test-archive/dashboard.html +635 -0
- claude_mpm/dashboard/static/test-archive/debug-events.html +147 -0
- claude_mpm/dashboard/static/test-archive/test-navigation.html +256 -0
- claude_mpm/dashboard/static/test-archive/test-react-exports.html +180 -0
- claude_mpm/dashboard/static/test-archive/test_debug.html +25 -0
- claude_mpm/dashboard/templates/code_simple.html +153 -0
- claude_mpm/dashboard/templates/index.html +267 -9
- claude_mpm/experimental/__init__.py +10 -0
- claude_mpm/experimental/cli_enhancements.py +4 -2
- 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/connection_pool.py +4 -4
- claude_mpm/hooks/claude_hooks/event_handlers.py +21 -18
- claude_mpm/hooks/claude_hooks/hook_handler.py +209 -25
- claude_mpm/hooks/claude_hooks/installer.py +783 -0
- 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/connection_manager.py +64 -49
- 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 +60 -0
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
- claude_mpm/hooks/instruction_reinforcement.py +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 +183 -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/resume_log.py +340 -0
- claude_mpm/schemas/__init__.py +12 -0
- claude_mpm/scripts/claude-hook-handler.sh +187 -0
- 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 +156 -396
- claude_mpm/services/__init__.py +144 -160
- claude_mpm/services/agents/__init__.py +18 -5
- claude_mpm/services/agents/agent_builder.py +13 -11
- claude_mpm/services/agents/auto_config_manager.py +796 -0
- claude_mpm/services/agents/deployment/agent_config_provider.py +127 -27
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_deployment.py +38 -15
- claude_mpm/services/agents/deployment/agent_discovery_service.py +125 -7
- 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 +4 -2
- claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_record_service.py +5 -6
- claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_template_builder.py +722 -37
- claude_mpm/services/agents/deployment/agent_validator.py +31 -7
- claude_mpm/services/agents/deployment/agent_version_manager.py +9 -1
- claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- 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/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 +134 -38
- 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 +9 -6
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +9 -6
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- 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/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 +2 -2
- claude_mpm/services/agents/local_template_manager.py +744 -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 +7 -7
- 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/async_session_logger.py +141 -98
- claude_mpm/services/claude_session_logger.py +82 -74
- claude_mpm/services/cli/agent_cleanup_service.py +6 -5
- claude_mpm/services/cli/agent_dependency_service.py +1 -1
- claude_mpm/services/cli/agent_listing_service.py +5 -5
- claude_mpm/services/cli/agent_validation_service.py +6 -5
- 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 -21
- claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
- claude_mpm/services/command_deployment_service.py +17 -9
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/__init__.py +33 -1
- claude_mpm/services/core/base.py +26 -11
- claude_mpm/services/core/cache_manager.py +1 -3
- claude_mpm/services/core/interfaces/__init__.py +90 -3
- claude_mpm/services/core/interfaces/agent.py +184 -0
- claude_mpm/services/core/interfaces/health.py +172 -0
- claude_mpm/services/core/interfaces/model.py +281 -0
- claude_mpm/services/core/interfaces/process.py +372 -0
- claude_mpm/services/core/interfaces/project.py +121 -0
- claude_mpm/services/core/interfaces/restart.py +307 -0
- claude_mpm/services/core/interfaces/stability.py +260 -0
- claude_mpm/services/core/interfaces.py +56 -1
- claude_mpm/services/core/memory_manager.py +92 -47
- claude_mpm/services/core/models/__init__.py +79 -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 +37 -18
- claude_mpm/services/core/service_container.py +2 -2
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/__init__.py +4 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +30 -32
- 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 +22 -24
- claude_mpm/services/diagnostics/checks/mcp_check.py +57 -43
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +1066 -0
- claude_mpm/services/diagnostics/checks/monitor_check.py +24 -23
- claude_mpm/services/diagnostics/checks/startup_log_check.py +14 -11
- claude_mpm/services/diagnostics/diagnostic_runner.py +22 -13
- claude_mpm/services/diagnostics/doctor_reporter.py +275 -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 +152 -13
- 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/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/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 +12 -12
- claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
- claude_mpm/services/infrastructure/monitoring/base.py +5 -13
- claude_mpm/services/infrastructure/monitoring/network.py +7 -6
- claude_mpm/services/infrastructure/monitoring/process.py +13 -12
- claude_mpm/services/infrastructure/monitoring/resources.py +8 -7
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/infrastructure/monitoring.py +12 -12
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/local_ops/__init__.py +165 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
- claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
- claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
- claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
- claude_mpm/services/local_ops/health_manager.py +430 -0
- claude_mpm/services/local_ops/log_monitor.py +396 -0
- claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
- claude_mpm/services/local_ops/process_manager.py +595 -0
- claude_mpm/services/local_ops/resource_monitor.py +331 -0
- claude_mpm/services/local_ops/restart_manager.py +401 -0
- claude_mpm/services/local_ops/restart_policy.py +387 -0
- claude_mpm/services/local_ops/state_manager.py +372 -0
- claude_mpm/services/local_ops/unified_manager.py +600 -0
- claude_mpm/services/mcp_config_manager.py +1612 -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 +23 -4
- 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 +585 -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 +4 -4
- claude_mpm/services/mcp_gateway/server/stdio_server.py +9 -15
- 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 +551 -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 +729 -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 +453 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/__init__.py +20 -0
- claude_mpm/services/monitor/daemon.py +671 -0
- claude_mpm/services/monitor/daemon_manager.py +963 -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 +2 -2
- claude_mpm/services/project/__init__.py +23 -0
- claude_mpm/services/project/analyzer.py +3 -3
- claude_mpm/services/project/architecture_analyzer.py +6 -6
- claude_mpm/services/project/archive_manager.py +1045 -0
- claude_mpm/services/project/dependency_analyzer.py +8 -8
- claude_mpm/services/project/detection_strategies.py +719 -0
- claude_mpm/services/project/documentation_manager.py +553 -0
- claude_mpm/services/project/enhanced_analyzer.py +572 -0
- claude_mpm/services/project/language_analyzer.py +3 -3
- claude_mpm/services/project/metrics_collector.py +7 -10
- claude_mpm/services/project/project_organizer.py +1005 -0
- claude_mpm/services/project/registry.py +13 -7
- claude_mpm/services/project/toolchain_analyzer.py +581 -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 +1 -0
- claude_mpm/services/self_upgrade_service.py +500 -0
- claude_mpm/services/session_management_service.py +7 -5
- 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/socketio/client_proxy.py +60 -5
- claude_mpm/services/socketio/dashboard_server.py +361 -0
- claude_mpm/services/socketio/event_normalizer.py +74 -6
- claude_mpm/services/socketio/handlers/__init__.py +5 -0
- claude_mpm/services/socketio/handlers/base.py +2 -2
- claude_mpm/services/socketio/handlers/code_analysis.py +682 -0
- claude_mpm/services/socketio/handlers/connection.py +21 -40
- claude_mpm/services/socketio/handlers/connection_handler.py +16 -28
- claude_mpm/services/socketio/handlers/file.py +46 -10
- claude_mpm/services/socketio/handlers/git.py +8 -8
- claude_mpm/services/socketio/handlers/hook.py +29 -17
- claude_mpm/services/socketio/handlers/registry.py +4 -0
- 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 +131 -68
- claude_mpm/services/socketio/server/core.py +275 -22
- claude_mpm/services/socketio/server/eventbus_integration.py +20 -14
- claude_mpm/services/socketio/server/main.py +99 -29
- 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 +2 -2
- 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 +903 -0
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +746 -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 +475 -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 +470 -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 +8 -4
- 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 +19 -0
- claude_mpm/services/visualization/mermaid_generator.py +938 -0
- 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/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -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/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -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/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -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/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -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/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -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/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -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 +348 -0
- claude_mpm/skills/skills_service.py +739 -0
- claude_mpm/storage/state_storage.py +31 -31
- claude_mpm/tools/__init__.py +10 -0
- claude_mpm/tools/__main__.py +208 -0
- 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 +631 -0
- claude_mpm/tools/code_tree_events.py +420 -0
- claude_mpm/tools/socketio_debug.py +671 -0
- claude_mpm/utils/agent_dependency_loader.py +108 -27
- 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 +2 -2
- 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/log_cleanup.py +627 -0
- claude_mpm/utils/path_operations.py +7 -4
- claude_mpm/utils/robust_installer.py +133 -24
- claude_mpm/utils/session_logging.py +2 -2
- 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-4.24.0.dist-info/METADATA +675 -0
- claude_mpm-4.24.0.dist-info/RECORD +1018 -0
- {claude_mpm-4.1.6.dist-info → claude_mpm-4.24.0.dist-info}/entry_points.txt +1 -0
- claude_mpm/agents/INSTRUCTIONS.md +0 -237
- claude_mpm/agents/schema/agent_schema.json +0 -314
- claude_mpm/agents/templates/agent-manager.md +0 -304
- claude_mpm/cli/commands/configure_tui.py +0 -1921
- claude_mpm/cli/commands/socketio_monitor.py +0 -233
- 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_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 -424
- claude_mpm/services/cli/socketio_manager.py +0 -498
- 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-4.1.6.dist-info/METADATA +0 -325
- claude_mpm-4.1.6.dist-info/RECORD +0 -550
- {claude_mpm-4.1.6.dist-info → claude_mpm-4.24.0.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.6.dist-info → claude_mpm-4.24.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.6.dist-info → claude_mpm-4.24.0.dist-info}/top_level.txt +0 -0
|
@@ -1,31 +1,37 @@
|
|
|
1
|
-
"""Framework loader for Claude MPM."""
|
|
1
|
+
"""Framework loader for Claude MPM - Refactored modular version."""
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
from datetime import datetime
|
|
3
|
+
import asyncio
|
|
4
|
+
import os
|
|
6
5
|
from pathlib import Path
|
|
7
|
-
from typing import Any, Dict, Optional
|
|
8
|
-
|
|
9
|
-
# Import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
22
23
|
|
|
23
|
-
# Import with fallback support
|
|
24
|
-
get_logger = safe_import("claude_mpm.core.logger", "core.logger", ["get_logger"])
|
|
24
|
+
# Import with fallback support
|
|
25
25
|
AgentRegistryAdapter = safe_import(
|
|
26
26
|
"claude_mpm.core.agent_registry", "core.agent_registry", ["AgentRegistryAdapter"]
|
|
27
27
|
)
|
|
28
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
|
+
|
|
29
35
|
# Import the service container and interfaces
|
|
30
36
|
try:
|
|
31
37
|
from claude_mpm.services.core.cache_manager import CacheManager
|
|
@@ -57,43 +63,13 @@ class FrameworkLoader:
|
|
|
57
63
|
"""
|
|
58
64
|
Load and prepare framework instructions for injection.
|
|
59
65
|
|
|
60
|
-
This
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
The framework loader supports custom instructions through .claude-mpm/ directories.
|
|
68
|
-
It NEVER reads from .claude/ directories to avoid conflicts with Claude Code.
|
|
69
|
-
|
|
70
|
-
File Loading Precedence (highest to lowest):
|
|
71
|
-
|
|
72
|
-
INSTRUCTIONS.md:
|
|
73
|
-
1. Project: ./.claude-mpm/INSTRUCTIONS.md
|
|
74
|
-
2. User: ~/.claude-mpm/INSTRUCTIONS.md
|
|
75
|
-
3. System: (built-in framework instructions)
|
|
76
|
-
|
|
77
|
-
WORKFLOW.md:
|
|
78
|
-
1. Project: ./.claude-mpm/WORKFLOW.md
|
|
79
|
-
2. User: ~/.claude-mpm/WORKFLOW.md
|
|
80
|
-
3. System: src/claude_mpm/agents/WORKFLOW.md
|
|
81
|
-
|
|
82
|
-
MEMORY.md:
|
|
83
|
-
1. Project: ./.claude-mpm/MEMORY.md
|
|
84
|
-
2. User: ~/.claude-mpm/MEMORY.md
|
|
85
|
-
3. System: src/claude_mpm/agents/MEMORY.md
|
|
86
|
-
|
|
87
|
-
Actual Memories:
|
|
88
|
-
- User: ~/.claude-mpm/memories/PM_memories.md
|
|
89
|
-
- Project: ./.claude-mpm/memories/PM_memories.md (overrides user)
|
|
90
|
-
- Agent memories: *_memories.md files (only loaded if agent is deployed)
|
|
91
|
-
|
|
92
|
-
Important Notes:
|
|
93
|
-
- Project-level files always override user-level files
|
|
94
|
-
- User-level files always override system defaults
|
|
95
|
-
- The framework NEVER reads from .claude/ directories
|
|
96
|
-
- 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
|
|
97
73
|
"""
|
|
98
74
|
|
|
99
75
|
def __init__(
|
|
@@ -101,35 +77,80 @@ class FrameworkLoader:
|
|
|
101
77
|
framework_path: Optional[Path] = None,
|
|
102
78
|
agents_dir: Optional[Path] = None,
|
|
103
79
|
service_container: Optional[ServiceContainer] = None,
|
|
80
|
+
config: Optional[Dict[str, Any]] = None,
|
|
104
81
|
):
|
|
105
82
|
"""
|
|
106
|
-
Initialize framework loader.
|
|
83
|
+
Initialize framework loader with modular components.
|
|
107
84
|
|
|
108
85
|
Args:
|
|
109
86
|
framework_path: Explicit path to framework (auto-detected if None)
|
|
110
87
|
agents_dir: Custom agents directory (overrides framework agents)
|
|
111
88
|
service_container: Optional service container for dependency injection
|
|
89
|
+
config: Optional configuration dictionary for API validation and other settings
|
|
112
90
|
"""
|
|
113
91
|
self.logger = get_logger("framework_loader")
|
|
114
92
|
self.agents_dir = agents_dir
|
|
115
93
|
self.framework_version = None
|
|
116
94
|
self.framework_last_modified = None
|
|
95
|
+
self.config = config or {}
|
|
96
|
+
|
|
97
|
+
# Validate API keys on startup (before any other initialization)
|
|
98
|
+
self._validate_api_keys()
|
|
117
99
|
|
|
118
|
-
#
|
|
100
|
+
# Initialize service container
|
|
119
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)
|
|
120
125
|
|
|
121
|
-
#
|
|
126
|
+
# Output style manager (deferred initialization)
|
|
127
|
+
self.output_style_manager = None
|
|
128
|
+
|
|
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."""
|
|
122
145
|
if not self.container.is_registered(ICacheManager):
|
|
123
|
-
self.container.register(ICacheManager, CacheManager, True)
|
|
146
|
+
self.container.register(ICacheManager, CacheManager, True)
|
|
124
147
|
|
|
125
148
|
if not self.container.is_registered(IPathResolver):
|
|
126
|
-
# PathResolver depends on CacheManager, so resolve it first
|
|
127
149
|
cache_manager = self.container.resolve(ICacheManager)
|
|
128
150
|
path_resolver = PathResolver(cache_manager=cache_manager)
|
|
129
151
|
self.container.register_instance(IPathResolver, path_resolver)
|
|
130
152
|
|
|
131
153
|
if not self.container.is_registered(IMemoryManager):
|
|
132
|
-
# MemoryManager depends on both CacheManager and PathResolver
|
|
133
154
|
cache_manager = self.container.resolve(ICacheManager)
|
|
134
155
|
path_resolver = self.container.resolve(IPathResolver)
|
|
135
156
|
memory_manager = MemoryManager(
|
|
@@ -137,18 +158,26 @@ class FrameworkLoader:
|
|
|
137
158
|
)
|
|
138
159
|
self.container.register_instance(IMemoryManager, memory_manager)
|
|
139
160
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
self.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
self.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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."""
|
|
152
181
|
if hasattr(self._cache_manager, "capabilities_ttl"):
|
|
153
182
|
self.CAPABILITIES_CACHE_TTL = self._cache_manager.capabilities_ttl
|
|
154
183
|
self.DEPLOYED_AGENTS_CACHE_TTL = self._cache_manager.deployed_agents_ttl
|
|
@@ -161,430 +190,24 @@ class FrameworkLoader:
|
|
|
161
190
|
self.METADATA_CACHE_TTL = 60
|
|
162
191
|
self.MEMORIES_CACHE_TTL = 60
|
|
163
192
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
# Initialize agent registry
|
|
167
|
-
self.agent_registry = AgentRegistryAdapter(self.framework_path)
|
|
168
|
-
|
|
169
|
-
# Initialize output style manager (must be after content is loaded)
|
|
170
|
-
self.output_style_manager = None
|
|
171
|
-
# Defer initialization until first use to ensure content is loaded
|
|
193
|
+
# === Cache Management Methods (backward compatibility) ===
|
|
172
194
|
|
|
173
195
|
def clear_all_caches(self) -> None:
|
|
174
196
|
"""Clear all caches to force reload on next access."""
|
|
175
197
|
self._cache_manager.clear_all()
|
|
176
198
|
|
|
177
199
|
def clear_agent_caches(self) -> None:
|
|
178
|
-
"""Clear agent-related caches
|
|
200
|
+
"""Clear agent-related caches."""
|
|
179
201
|
self._cache_manager.clear_agent_caches()
|
|
180
202
|
|
|
181
203
|
def clear_memory_caches(self) -> None:
|
|
182
204
|
"""Clear memory-related caches."""
|
|
183
205
|
self._cache_manager.clear_memory_caches()
|
|
184
206
|
|
|
185
|
-
|
|
186
|
-
"""Initialize output style management and deploy if applicable."""
|
|
187
|
-
try:
|
|
188
|
-
from claude_mpm.core.output_style_manager import OutputStyleManager
|
|
189
|
-
|
|
190
|
-
self.output_style_manager = OutputStyleManager()
|
|
191
|
-
|
|
192
|
-
# Log detailed output style status
|
|
193
|
-
self._log_output_style_status()
|
|
194
|
-
|
|
195
|
-
# Extract and save output style content (pass self to reuse loaded content)
|
|
196
|
-
output_style_content = (
|
|
197
|
-
self.output_style_manager.extract_output_style_content(
|
|
198
|
-
framework_loader=self
|
|
199
|
-
)
|
|
200
|
-
)
|
|
201
|
-
self.output_style_manager.save_output_style(output_style_content)
|
|
202
|
-
|
|
203
|
-
# Deploy to Claude Code if supported
|
|
204
|
-
deployed = self.output_style_manager.deploy_output_style(
|
|
205
|
-
output_style_content
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
if deployed:
|
|
209
|
-
self.logger.info("✅ Output style deployed to Claude Code >= 1.0.83")
|
|
210
|
-
else:
|
|
211
|
-
self.logger.info(
|
|
212
|
-
"📝 Output style will be injected into instructions for older Claude versions"
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
except Exception as e:
|
|
216
|
-
self.logger.warning(f"❌ Failed to initialize output style manager: {e}")
|
|
217
|
-
# Continue without output style management
|
|
218
|
-
|
|
219
|
-
def _log_output_style_status(self) -> None:
|
|
220
|
-
"""Log comprehensive output style status information."""
|
|
221
|
-
if not self.output_style_manager:
|
|
222
|
-
return
|
|
223
|
-
|
|
224
|
-
# Claude version detection
|
|
225
|
-
claude_version = self.output_style_manager.claude_version
|
|
226
|
-
if claude_version:
|
|
227
|
-
self.logger.info(f"Claude Code version detected: {claude_version}")
|
|
228
|
-
|
|
229
|
-
# Check if version supports output styles
|
|
230
|
-
if self.output_style_manager.supports_output_styles():
|
|
231
|
-
self.logger.info("✅ Claude Code supports output styles (>= 1.0.83)")
|
|
232
|
-
|
|
233
|
-
# Check deployment status
|
|
234
|
-
output_style_path = self.output_style_manager.output_style_path
|
|
235
|
-
if output_style_path.exists():
|
|
236
|
-
self.logger.info(
|
|
237
|
-
f"📁 Output style file exists: {output_style_path}"
|
|
238
|
-
)
|
|
239
|
-
else:
|
|
240
|
-
self.logger.info(
|
|
241
|
-
f"📝 Output style will be created at: {output_style_path}"
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
else:
|
|
245
|
-
self.logger.info(
|
|
246
|
-
f"⚠️ Claude Code {claude_version} does not support output styles (< 1.0.83)"
|
|
247
|
-
)
|
|
248
|
-
self.logger.info(
|
|
249
|
-
"📝 Output style content will be injected into framework instructions"
|
|
250
|
-
)
|
|
251
|
-
else:
|
|
252
|
-
self.logger.info("⚠️ Claude Code not detected or version unknown")
|
|
253
|
-
self.logger.info(
|
|
254
|
-
"📝 Output style content will be injected into framework instructions as fallback"
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
def _try_load_file(self, file_path: Path, file_type: str) -> Optional[str]:
|
|
258
|
-
"""
|
|
259
|
-
Try to load a file with error handling.
|
|
260
|
-
|
|
261
|
-
Args:
|
|
262
|
-
file_path: Path to the file to load
|
|
263
|
-
file_type: Description of file type for logging
|
|
264
|
-
|
|
265
|
-
Returns:
|
|
266
|
-
File content if successful, None otherwise
|
|
267
|
-
"""
|
|
268
|
-
try:
|
|
269
|
-
content = file_path.read_text()
|
|
270
|
-
if hasattr(self.logger, "level") and self.logger.level <= logging.INFO:
|
|
271
|
-
self.logger.info(f"Loaded {file_type} from: {file_path}")
|
|
272
|
-
|
|
273
|
-
# Extract metadata if present
|
|
274
|
-
import re
|
|
275
|
-
|
|
276
|
-
version_match = re.search(r"<!-- FRAMEWORK_VERSION: (\d+) -->", content)
|
|
277
|
-
if version_match:
|
|
278
|
-
version = version_match.group(
|
|
279
|
-
1
|
|
280
|
-
) # Keep as string to preserve leading zeros
|
|
281
|
-
self.logger.info(f"Framework version: {version}")
|
|
282
|
-
# Store framework version if this is the main INSTRUCTIONS.md
|
|
283
|
-
if "INSTRUCTIONS.md" in str(file_path):
|
|
284
|
-
self.framework_version = version
|
|
285
|
-
|
|
286
|
-
# Extract modification timestamp
|
|
287
|
-
timestamp_match = re.search(r"<!-- LAST_MODIFIED: ([^>]+) -->", content)
|
|
288
|
-
if timestamp_match:
|
|
289
|
-
timestamp = timestamp_match.group(1).strip()
|
|
290
|
-
self.logger.info(f"Last modified: {timestamp}")
|
|
291
|
-
# Store timestamp if this is the main INSTRUCTIONS.md
|
|
292
|
-
if "INSTRUCTIONS.md" in str(file_path):
|
|
293
|
-
self.framework_last_modified = timestamp
|
|
294
|
-
|
|
295
|
-
return content
|
|
296
|
-
except Exception as e:
|
|
297
|
-
if hasattr(self.logger, "level") and self.logger.level <= logging.ERROR:
|
|
298
|
-
self.logger.error(f"Failed to load {file_type}: {e}")
|
|
299
|
-
return None
|
|
300
|
-
|
|
301
|
-
def _load_instructions_file(self, content: Dict[str, Any]) -> None:
|
|
302
|
-
"""
|
|
303
|
-
Load custom INSTRUCTIONS.md from .claude-mpm directories.
|
|
304
|
-
|
|
305
|
-
Precedence (highest to lowest):
|
|
306
|
-
1. Project-specific: ./.claude-mpm/INSTRUCTIONS.md
|
|
307
|
-
2. User-specific: ~/.claude-mpm/INSTRUCTIONS.md
|
|
308
|
-
|
|
309
|
-
NOTE: We do NOT load CLAUDE.md files since Claude Code already picks them up automatically.
|
|
310
|
-
This prevents duplication of instructions.
|
|
311
|
-
|
|
312
|
-
Args:
|
|
313
|
-
content: Dictionary to update with loaded instructions
|
|
314
|
-
"""
|
|
315
|
-
# Check for project-specific INSTRUCTIONS.md first
|
|
316
|
-
project_instructions_path = Path.cwd() / ".claude-mpm" / "INSTRUCTIONS.md"
|
|
317
|
-
if project_instructions_path.exists():
|
|
318
|
-
loaded_content = self._try_load_file(
|
|
319
|
-
project_instructions_path, "project-specific INSTRUCTIONS.md"
|
|
320
|
-
)
|
|
321
|
-
if loaded_content:
|
|
322
|
-
content["custom_instructions"] = loaded_content
|
|
323
|
-
content["custom_instructions_level"] = "project"
|
|
324
|
-
self.logger.info(
|
|
325
|
-
"Using project-specific PM instructions from .claude-mpm/INSTRUCTIONS.md"
|
|
326
|
-
)
|
|
327
|
-
return
|
|
328
|
-
|
|
329
|
-
# Check for user-specific INSTRUCTIONS.md
|
|
330
|
-
user_instructions_path = Path.home() / ".claude-mpm" / "INSTRUCTIONS.md"
|
|
331
|
-
if user_instructions_path.exists():
|
|
332
|
-
loaded_content = self._try_load_file(
|
|
333
|
-
user_instructions_path, "user-specific INSTRUCTIONS.md"
|
|
334
|
-
)
|
|
335
|
-
if loaded_content:
|
|
336
|
-
content["custom_instructions"] = loaded_content
|
|
337
|
-
content["custom_instructions_level"] = "user"
|
|
338
|
-
self.logger.info(
|
|
339
|
-
"Using user-specific PM instructions from ~/.claude-mpm/INSTRUCTIONS.md"
|
|
340
|
-
)
|
|
341
|
-
return
|
|
342
|
-
|
|
343
|
-
def _load_workflow_instructions(self, content: Dict[str, Any]) -> None:
|
|
344
|
-
"""
|
|
345
|
-
Load WORKFLOW.md from .claude-mpm directories.
|
|
346
|
-
|
|
347
|
-
Precedence (highest to lowest):
|
|
348
|
-
1. Project-specific: ./.claude-mpm/WORKFLOW.md
|
|
349
|
-
2. User-specific: ~/.claude-mpm/WORKFLOW.md
|
|
350
|
-
3. System default: src/claude_mpm/agents/WORKFLOW.md or packaged
|
|
351
|
-
|
|
352
|
-
NOTE: We do NOT load from .claude/ directories to avoid conflicts.
|
|
353
|
-
|
|
354
|
-
Args:
|
|
355
|
-
content: Dictionary to update with workflow instructions
|
|
356
|
-
"""
|
|
357
|
-
# Check for project-specific WORKFLOW.md first (highest priority)
|
|
358
|
-
project_workflow_path = Path.cwd() / ".claude-mpm" / "WORKFLOW.md"
|
|
359
|
-
if project_workflow_path.exists():
|
|
360
|
-
loaded_content = self._try_load_file(
|
|
361
|
-
project_workflow_path, "project-specific WORKFLOW.md"
|
|
362
|
-
)
|
|
363
|
-
if loaded_content:
|
|
364
|
-
content["workflow_instructions"] = loaded_content
|
|
365
|
-
content["workflow_instructions_level"] = "project"
|
|
366
|
-
self.logger.info(
|
|
367
|
-
"Using project-specific workflow instructions from .claude-mpm/WORKFLOW.md"
|
|
368
|
-
)
|
|
369
|
-
return
|
|
370
|
-
|
|
371
|
-
# Check for user-specific WORKFLOW.md (medium priority)
|
|
372
|
-
user_workflow_path = Path.home() / ".claude-mpm" / "WORKFLOW.md"
|
|
373
|
-
if user_workflow_path.exists():
|
|
374
|
-
loaded_content = self._try_load_file(
|
|
375
|
-
user_workflow_path, "user-specific WORKFLOW.md"
|
|
376
|
-
)
|
|
377
|
-
if loaded_content:
|
|
378
|
-
content["workflow_instructions"] = loaded_content
|
|
379
|
-
content["workflow_instructions_level"] = "user"
|
|
380
|
-
self.logger.info(
|
|
381
|
-
"Using user-specific workflow instructions from ~/.claude-mpm/WORKFLOW.md"
|
|
382
|
-
)
|
|
383
|
-
return
|
|
384
|
-
|
|
385
|
-
# Fall back to system workflow (lowest priority)
|
|
386
|
-
if self.framework_path and self.framework_path != Path("__PACKAGED__"):
|
|
387
|
-
system_workflow_path = (
|
|
388
|
-
self.framework_path / "src" / "claude_mpm" / "agents" / "WORKFLOW.md"
|
|
389
|
-
)
|
|
390
|
-
if system_workflow_path.exists():
|
|
391
|
-
loaded_content = self._try_load_file(
|
|
392
|
-
system_workflow_path, "system WORKFLOW.md"
|
|
393
|
-
)
|
|
394
|
-
if loaded_content:
|
|
395
|
-
content["workflow_instructions"] = loaded_content
|
|
396
|
-
content["workflow_instructions_level"] = "system"
|
|
397
|
-
self.logger.info("Using system workflow instructions")
|
|
398
|
-
|
|
399
|
-
def _load_memory_instructions(self, content: Dict[str, Any]) -> None:
|
|
400
|
-
"""
|
|
401
|
-
Load MEMORY.md from .claude-mpm directories.
|
|
402
|
-
|
|
403
|
-
Precedence (highest to lowest):
|
|
404
|
-
1. Project-specific: ./.claude-mpm/MEMORY.md
|
|
405
|
-
2. User-specific: ~/.claude-mpm/MEMORY.md
|
|
406
|
-
3. System default: src/claude_mpm/agents/MEMORY.md or packaged
|
|
407
|
-
|
|
408
|
-
NOTE: We do NOT load from .claude/ directories to avoid conflicts.
|
|
409
|
-
|
|
410
|
-
Args:
|
|
411
|
-
content: Dictionary to update with memory instructions
|
|
412
|
-
"""
|
|
413
|
-
# Check for project-specific MEMORY.md first (highest priority)
|
|
414
|
-
project_memory_path = Path.cwd() / ".claude-mpm" / "MEMORY.md"
|
|
415
|
-
if project_memory_path.exists():
|
|
416
|
-
loaded_content = self._try_load_file(
|
|
417
|
-
project_memory_path, "project-specific MEMORY.md"
|
|
418
|
-
)
|
|
419
|
-
if loaded_content:
|
|
420
|
-
content["memory_instructions"] = loaded_content
|
|
421
|
-
content["memory_instructions_level"] = "project"
|
|
422
|
-
self.logger.info(
|
|
423
|
-
"Using project-specific memory instructions from .claude-mpm/MEMORY.md"
|
|
424
|
-
)
|
|
425
|
-
return
|
|
426
|
-
|
|
427
|
-
# Check for user-specific MEMORY.md (medium priority)
|
|
428
|
-
user_memory_path = Path.home() / ".claude-mpm" / "MEMORY.md"
|
|
429
|
-
if user_memory_path.exists():
|
|
430
|
-
loaded_content = self._try_load_file(
|
|
431
|
-
user_memory_path, "user-specific MEMORY.md"
|
|
432
|
-
)
|
|
433
|
-
if loaded_content:
|
|
434
|
-
content["memory_instructions"] = loaded_content
|
|
435
|
-
content["memory_instructions_level"] = "user"
|
|
436
|
-
self.logger.info(
|
|
437
|
-
"Using user-specific memory instructions from ~/.claude-mpm/MEMORY.md"
|
|
438
|
-
)
|
|
439
|
-
return
|
|
440
|
-
|
|
441
|
-
# Fall back to system memory instructions (lowest priority)
|
|
442
|
-
if self.framework_path and self.framework_path != Path("__PACKAGED__"):
|
|
443
|
-
system_memory_path = (
|
|
444
|
-
self.framework_path / "src" / "claude_mpm" / "agents" / "MEMORY.md"
|
|
445
|
-
)
|
|
446
|
-
if system_memory_path.exists():
|
|
447
|
-
loaded_content = self._try_load_file(
|
|
448
|
-
system_memory_path, "system MEMORY.md"
|
|
449
|
-
)
|
|
450
|
-
if loaded_content:
|
|
451
|
-
content["memory_instructions"] = loaded_content
|
|
452
|
-
content["memory_instructions_level"] = "system"
|
|
453
|
-
self.logger.info("Using system memory instructions")
|
|
454
|
-
|
|
455
|
-
def _get_deployed_agents(self) -> set:
|
|
456
|
-
"""
|
|
457
|
-
Get a set of deployed agent names from .claude/agents/ directories.
|
|
458
|
-
Uses caching to avoid repeated filesystem scans.
|
|
459
|
-
|
|
460
|
-
Returns:
|
|
461
|
-
Set of agent names (file stems) that are deployed
|
|
462
|
-
"""
|
|
463
|
-
# Try to get from cache first
|
|
464
|
-
cached = self._cache_manager.get_deployed_agents()
|
|
465
|
-
if cached is not None:
|
|
466
|
-
return cached
|
|
467
|
-
|
|
468
|
-
# Cache miss or expired - perform actual scan
|
|
469
|
-
self.logger.debug("Scanning for deployed agents (cache miss or expired)")
|
|
470
|
-
deployed = set()
|
|
471
|
-
|
|
472
|
-
# Check multiple locations for deployed agents
|
|
473
|
-
agents_dirs = [
|
|
474
|
-
Path.cwd() / ".claude" / "agents", # Project-specific agents
|
|
475
|
-
Path.home() / ".claude" / "agents", # User's system agents
|
|
476
|
-
]
|
|
477
|
-
|
|
478
|
-
for agents_dir in agents_dirs:
|
|
479
|
-
if agents_dir.exists():
|
|
480
|
-
for agent_file in agents_dir.glob("*.md"):
|
|
481
|
-
if not agent_file.name.startswith("."):
|
|
482
|
-
# Use stem to get agent name without extension
|
|
483
|
-
deployed.add(agent_file.stem)
|
|
484
|
-
self.logger.debug(
|
|
485
|
-
f"Found deployed agent: {agent_file.stem} in {agents_dir}"
|
|
486
|
-
)
|
|
487
|
-
|
|
488
|
-
self.logger.debug(f"Total deployed agents found: {len(deployed)}")
|
|
489
|
-
|
|
490
|
-
# Update cache
|
|
491
|
-
self._cache_manager.set_deployed_agents(deployed)
|
|
492
|
-
|
|
493
|
-
return deployed
|
|
494
|
-
|
|
495
|
-
def _load_actual_memories(self, content: Dict[str, Any]) -> None:
|
|
496
|
-
"""
|
|
497
|
-
Load actual memories using the MemoryManager service.
|
|
498
|
-
|
|
499
|
-
This method delegates all memory loading operations to the MemoryManager,
|
|
500
|
-
which handles caching, aggregation, deduplication, and legacy format migration.
|
|
501
|
-
|
|
502
|
-
Args:
|
|
503
|
-
content: Dictionary to update with actual memories
|
|
504
|
-
"""
|
|
505
|
-
# Use MemoryManager to load all memories
|
|
506
|
-
memories = self._memory_manager.load_memories()
|
|
507
|
-
|
|
508
|
-
# Apply loaded memories to content
|
|
509
|
-
if "actual_memories" in memories:
|
|
510
|
-
content["actual_memories"] = memories["actual_memories"]
|
|
511
|
-
if "agent_memories" in memories:
|
|
512
|
-
content["agent_memories"] = memories["agent_memories"]
|
|
513
|
-
|
|
514
|
-
def _load_single_agent(
|
|
515
|
-
self, agent_file: Path
|
|
516
|
-
) -> tuple[Optional[str], Optional[str]]:
|
|
517
|
-
"""
|
|
518
|
-
Load a single agent file.
|
|
519
|
-
|
|
520
|
-
Args:
|
|
521
|
-
agent_file: Path to the agent file
|
|
522
|
-
|
|
523
|
-
Returns:
|
|
524
|
-
Tuple of (agent_name, agent_content) or (None, None) on failure
|
|
525
|
-
"""
|
|
526
|
-
try:
|
|
527
|
-
agent_name = agent_file.stem
|
|
528
|
-
# Skip README files
|
|
529
|
-
if agent_name.upper() == "README":
|
|
530
|
-
return None, None
|
|
531
|
-
content = agent_file.read_text()
|
|
532
|
-
self.logger.debug(f"Loaded agent: {agent_name}")
|
|
533
|
-
return agent_name, content
|
|
534
|
-
except Exception as e:
|
|
535
|
-
self.logger.error(f"Failed to load agent {agent_file}: {e}")
|
|
536
|
-
return None, None
|
|
537
|
-
|
|
538
|
-
def _load_base_agent_fallback(
|
|
539
|
-
self, content: Dict[str, Any], main_dir: Optional[Path]
|
|
540
|
-
) -> None:
|
|
541
|
-
"""
|
|
542
|
-
Load base_agent.md from main directory as fallback.
|
|
543
|
-
|
|
544
|
-
Args:
|
|
545
|
-
content: Dictionary to update with base agent
|
|
546
|
-
main_dir: Main agents directory path
|
|
547
|
-
"""
|
|
548
|
-
if main_dir and main_dir.exists() and "base_agent" not in content["agents"]:
|
|
549
|
-
base_agent_file = main_dir / "base_agent.md"
|
|
550
|
-
if base_agent_file.exists():
|
|
551
|
-
agent_name, agent_content = self._load_single_agent(base_agent_file)
|
|
552
|
-
if agent_name and agent_content:
|
|
553
|
-
content["agents"][agent_name] = agent_content
|
|
554
|
-
|
|
555
|
-
def _load_agents_directory(
|
|
556
|
-
self,
|
|
557
|
-
content: Dict[str, Any],
|
|
558
|
-
agents_dir: Optional[Path],
|
|
559
|
-
templates_dir: Optional[Path],
|
|
560
|
-
main_dir: Optional[Path],
|
|
561
|
-
) -> None:
|
|
562
|
-
"""
|
|
563
|
-
Load agent definitions from the appropriate directory.
|
|
564
|
-
|
|
565
|
-
Args:
|
|
566
|
-
content: Dictionary to update with loaded agents
|
|
567
|
-
agents_dir: Primary agents directory to load from
|
|
568
|
-
templates_dir: Templates directory path
|
|
569
|
-
main_dir: Main agents directory path
|
|
570
|
-
"""
|
|
571
|
-
if not agents_dir or not agents_dir.exists():
|
|
572
|
-
return
|
|
573
|
-
|
|
574
|
-
content["loaded"] = True
|
|
575
|
-
|
|
576
|
-
# Load all agent files
|
|
577
|
-
for agent_file in agents_dir.glob("*.md"):
|
|
578
|
-
agent_name, agent_content = self._load_single_agent(agent_file)
|
|
579
|
-
if agent_name and agent_content:
|
|
580
|
-
content["agents"][agent_name] = agent_content
|
|
581
|
-
|
|
582
|
-
# If we used templates dir, also check main dir for base_agent.md
|
|
583
|
-
if agents_dir == templates_dir:
|
|
584
|
-
self._load_base_agent_fallback(content, main_dir)
|
|
207
|
+
# === Content Loading Methods ===
|
|
585
208
|
|
|
586
209
|
def _load_framework_content(self) -> Dict[str, Any]:
|
|
587
|
-
"""Load framework content."""
|
|
210
|
+
"""Load framework content using modular components."""
|
|
588
211
|
content = {
|
|
589
212
|
"claude_md": "",
|
|
590
213
|
"agents": {},
|
|
@@ -593,242 +216,102 @@ class FrameworkLoader:
|
|
|
593
216
|
"working_claude_md": "",
|
|
594
217
|
"framework_instructions": "",
|
|
595
218
|
"workflow_instructions": "",
|
|
596
|
-
"workflow_instructions_level": "",
|
|
219
|
+
"workflow_instructions_level": "",
|
|
597
220
|
"memory_instructions": "",
|
|
598
|
-
"memory_instructions_level": "",
|
|
599
|
-
"project_workflow": "", # Deprecated
|
|
600
|
-
"project_memory": "", # Deprecated
|
|
601
|
-
"actual_memories": "",
|
|
221
|
+
"memory_instructions_level": "",
|
|
222
|
+
"project_workflow": "", # Deprecated
|
|
223
|
+
"project_memory": "", # Deprecated
|
|
224
|
+
"actual_memories": "",
|
|
225
|
+
"agent_memories": {},
|
|
602
226
|
}
|
|
603
227
|
|
|
604
|
-
# Load instructions
|
|
605
|
-
self.
|
|
228
|
+
# Load all instructions
|
|
229
|
+
self.instruction_loader.load_all_instructions(content)
|
|
606
230
|
|
|
607
|
-
|
|
608
|
-
|
|
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
|
|
609
237
|
|
|
610
|
-
#
|
|
611
|
-
if self.framework_path == Path("__PACKAGED__"):
|
|
612
|
-
# Load files using importlib.resources for packaged installations
|
|
613
|
-
self._load_packaged_framework_content(content)
|
|
614
|
-
else:
|
|
615
|
-
# Load from filesystem for development mode
|
|
616
|
-
# Load framework's INSTRUCTIONS.md
|
|
617
|
-
framework_instructions_path = (
|
|
618
|
-
self.framework_path
|
|
619
|
-
/ "src"
|
|
620
|
-
/ "claude_mpm"
|
|
621
|
-
/ "agents"
|
|
622
|
-
/ "INSTRUCTIONS.md"
|
|
623
|
-
)
|
|
624
|
-
if framework_instructions_path.exists():
|
|
625
|
-
loaded_content = self._try_load_file(
|
|
626
|
-
framework_instructions_path, "framework INSTRUCTIONS.md"
|
|
627
|
-
)
|
|
628
|
-
if loaded_content:
|
|
629
|
-
content["framework_instructions"] = loaded_content
|
|
630
|
-
content["loaded"] = True
|
|
631
|
-
# Add framework version to content
|
|
632
|
-
if self.framework_version:
|
|
633
|
-
content["instructions_version"] = self.framework_version
|
|
634
|
-
content["version"] = (
|
|
635
|
-
self.framework_version
|
|
636
|
-
) # Update main version key
|
|
637
|
-
# Add modification timestamp to content
|
|
638
|
-
if self.framework_last_modified:
|
|
639
|
-
content["instructions_last_modified"] = (
|
|
640
|
-
self.framework_last_modified
|
|
641
|
-
)
|
|
642
|
-
|
|
643
|
-
# Load BASE_PM.md for core framework requirements
|
|
644
|
-
base_pm_path = (
|
|
645
|
-
self.framework_path / "src" / "claude_mpm" / "agents" / "BASE_PM.md"
|
|
646
|
-
)
|
|
647
|
-
if base_pm_path.exists():
|
|
648
|
-
base_pm_content = self._try_load_file(
|
|
649
|
-
base_pm_path, "BASE_PM framework requirements"
|
|
650
|
-
)
|
|
651
|
-
if base_pm_content:
|
|
652
|
-
content["base_pm_instructions"] = base_pm_content
|
|
653
|
-
|
|
654
|
-
# Load WORKFLOW.md - check for project-specific first, then system
|
|
655
|
-
self._load_workflow_instructions(content)
|
|
656
|
-
|
|
657
|
-
# Load MEMORY.md - check for project-specific first, then system
|
|
658
|
-
self._load_memory_instructions(content)
|
|
659
|
-
|
|
660
|
-
# Load actual memories from .claude-mpm/memories/PM_memories.md
|
|
238
|
+
# Load memories
|
|
661
239
|
self._load_actual_memories(content)
|
|
662
240
|
|
|
663
|
-
# Discover
|
|
241
|
+
# Discover and load agents
|
|
664
242
|
agents_dir, templates_dir, main_dir = self._path_resolver.discover_agent_paths(
|
|
665
243
|
agents_dir=self.agents_dir, framework_path=self.framework_path
|
|
666
244
|
)
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
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
|
|
670
251
|
|
|
671
252
|
return content
|
|
672
253
|
|
|
673
|
-
def
|
|
674
|
-
"""Load
|
|
675
|
-
|
|
676
|
-
self.logger.warning(
|
|
677
|
-
"importlib.resources not available, cannot load packaged framework"
|
|
678
|
-
)
|
|
679
|
-
self.logger.debug(f"files variable is: {files}")
|
|
680
|
-
# Try alternative import methods
|
|
681
|
-
try:
|
|
682
|
-
from importlib import resources
|
|
683
|
-
|
|
684
|
-
self.logger.info("Using importlib.resources as fallback")
|
|
685
|
-
self._load_packaged_framework_content_fallback(content, resources)
|
|
686
|
-
return
|
|
687
|
-
except ImportError:
|
|
688
|
-
self.logger.error(
|
|
689
|
-
"No importlib.resources available, using minimal framework"
|
|
690
|
-
)
|
|
691
|
-
return
|
|
692
|
-
|
|
693
|
-
try:
|
|
694
|
-
# Load INSTRUCTIONS.md
|
|
695
|
-
instructions_content = self._load_packaged_file("INSTRUCTIONS.md")
|
|
696
|
-
if instructions_content:
|
|
697
|
-
content["framework_instructions"] = instructions_content
|
|
698
|
-
content["loaded"] = True
|
|
699
|
-
# Extract and store version/timestamp metadata
|
|
700
|
-
self._extract_metadata_from_content(
|
|
701
|
-
instructions_content, "INSTRUCTIONS.md"
|
|
702
|
-
)
|
|
703
|
-
if self.framework_version:
|
|
704
|
-
content["instructions_version"] = self.framework_version
|
|
705
|
-
content["version"] = self.framework_version
|
|
706
|
-
if self.framework_last_modified:
|
|
707
|
-
content["instructions_last_modified"] = self.framework_last_modified
|
|
708
|
-
|
|
709
|
-
# Load BASE_PM.md
|
|
710
|
-
base_pm_content = self._load_packaged_file("BASE_PM.md")
|
|
711
|
-
if base_pm_content:
|
|
712
|
-
content["base_pm_instructions"] = base_pm_content
|
|
713
|
-
|
|
714
|
-
# Load WORKFLOW.md
|
|
715
|
-
workflow_content = self._load_packaged_file("WORKFLOW.md")
|
|
716
|
-
if workflow_content:
|
|
717
|
-
content["workflow_instructions"] = workflow_content
|
|
718
|
-
content["project_workflow"] = "system"
|
|
719
|
-
|
|
720
|
-
# Load MEMORY.md
|
|
721
|
-
memory_content = self._load_packaged_file("MEMORY.md")
|
|
722
|
-
if memory_content:
|
|
723
|
-
content["memory_instructions"] = memory_content
|
|
724
|
-
content["project_memory"] = "system"
|
|
725
|
-
|
|
726
|
-
except Exception as e:
|
|
727
|
-
self.logger.error(f"Failed to load packaged framework content: {e}")
|
|
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()
|
|
728
257
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
try:
|
|
734
|
-
# Load INSTRUCTIONS.md
|
|
735
|
-
instructions_content = self._load_packaged_file_fallback(
|
|
736
|
-
"INSTRUCTIONS.md", resources
|
|
737
|
-
)
|
|
738
|
-
if instructions_content:
|
|
739
|
-
content["framework_instructions"] = instructions_content
|
|
740
|
-
content["loaded"] = True
|
|
741
|
-
# Extract and store version/timestamp metadata
|
|
742
|
-
self._extract_metadata_from_content(
|
|
743
|
-
instructions_content, "INSTRUCTIONS.md"
|
|
744
|
-
)
|
|
745
|
-
if self.framework_version:
|
|
746
|
-
content["instructions_version"] = self.framework_version
|
|
747
|
-
content["version"] = self.framework_version
|
|
748
|
-
if self.framework_last_modified:
|
|
749
|
-
content["instructions_last_modified"] = self.framework_last_modified
|
|
750
|
-
|
|
751
|
-
# Load BASE_PM.md
|
|
752
|
-
base_pm_content = self._load_packaged_file_fallback("BASE_PM.md", resources)
|
|
753
|
-
if base_pm_content:
|
|
754
|
-
content["base_pm_instructions"] = base_pm_content
|
|
755
|
-
|
|
756
|
-
# Load WORKFLOW.md
|
|
757
|
-
workflow_content = self._load_packaged_file_fallback(
|
|
758
|
-
"WORKFLOW.md", resources
|
|
759
|
-
)
|
|
760
|
-
if workflow_content:
|
|
761
|
-
content["workflow_instructions"] = workflow_content
|
|
762
|
-
content["project_workflow"] = "system"
|
|
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"]
|
|
763
262
|
|
|
764
|
-
|
|
765
|
-
memory_content = self._load_packaged_file_fallback("MEMORY.md", resources)
|
|
766
|
-
if memory_content:
|
|
767
|
-
content["memory_instructions"] = memory_content
|
|
768
|
-
content["project_memory"] = "system"
|
|
263
|
+
# === Agent Discovery Methods ===
|
|
769
264
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
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
|
|
774
270
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
# Try different resource loading methods
|
|
779
|
-
try:
|
|
780
|
-
# Method 1: resources.read_text (Python 3.9+)
|
|
781
|
-
content = resources.read_text("claude_mpm.agents", filename)
|
|
782
|
-
self.logger.info(f"Loaded {filename} from package using read_text")
|
|
783
|
-
return content
|
|
784
|
-
except AttributeError:
|
|
785
|
-
# Method 2: resources.files (Python 3.9+)
|
|
786
|
-
agents_files = resources.files("claude_mpm.agents")
|
|
787
|
-
file_path = agents_files / filename
|
|
788
|
-
if file_path.is_file():
|
|
789
|
-
content = file_path.read_text()
|
|
790
|
-
self.logger.info(f"Loaded {filename} from package using files")
|
|
791
|
-
return content
|
|
792
|
-
self.logger.warning(f"File {filename} not found in package")
|
|
793
|
-
return None
|
|
794
|
-
except Exception as e:
|
|
795
|
-
self.logger.error(
|
|
796
|
-
f"Failed to load {filename} from package with fallback: {e}"
|
|
797
|
-
)
|
|
798
|
-
return None
|
|
271
|
+
deployed = self.agent_loader.get_deployed_agents()
|
|
272
|
+
self._cache_manager.set_deployed_agents(deployed)
|
|
273
|
+
return deployed
|
|
799
274
|
|
|
800
|
-
def
|
|
801
|
-
"""
|
|
802
|
-
|
|
803
|
-
# Use importlib.resources to load file from package
|
|
804
|
-
agents_package = files("claude_mpm.agents")
|
|
805
|
-
file_path = agents_package / filename
|
|
806
|
-
|
|
807
|
-
if file_path.is_file():
|
|
808
|
-
content = file_path.read_text()
|
|
809
|
-
self.logger.info(f"Loaded {filename} from package")
|
|
810
|
-
return content
|
|
811
|
-
self.logger.warning(f"File {filename} not found in package")
|
|
812
|
-
return None
|
|
813
|
-
except Exception as e:
|
|
814
|
-
self.logger.error(f"Failed to load {filename} from package: {e}")
|
|
815
|
-
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()
|
|
816
278
|
|
|
817
|
-
def
|
|
818
|
-
"""
|
|
819
|
-
|
|
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)
|
|
820
311
|
|
|
821
|
-
|
|
822
|
-
version_match = re.search(r"<!-- FRAMEWORK_VERSION: (\d+) -->", content)
|
|
823
|
-
if version_match and "INSTRUCTIONS.md" in filename:
|
|
824
|
-
self.framework_version = version_match.group(1)
|
|
825
|
-
self.logger.info(f"Framework version: {self.framework_version}")
|
|
312
|
+
return agent_data
|
|
826
313
|
|
|
827
|
-
|
|
828
|
-
timestamp_match = re.search(r"<!-- LAST_MODIFIED: ([^>]+) -->", content)
|
|
829
|
-
if timestamp_match and "INSTRUCTIONS.md" in filename:
|
|
830
|
-
self.framework_last_modified = timestamp_match.group(1).strip()
|
|
831
|
-
self.logger.info(f"Last modified: {self.framework_last_modified}")
|
|
314
|
+
# === Framework Instructions Generation ===
|
|
832
315
|
|
|
833
316
|
def get_framework_instructions(self) -> str:
|
|
834
317
|
"""
|
|
@@ -837,872 +320,221 @@ class FrameworkLoader:
|
|
|
837
320
|
Returns:
|
|
838
321
|
Complete framework instructions ready for injection
|
|
839
322
|
"""
|
|
840
|
-
#
|
|
841
|
-
|
|
842
|
-
from .log_manager import get_log_manager
|
|
843
|
-
|
|
844
|
-
log_manager = get_log_manager()
|
|
845
|
-
except ImportError:
|
|
846
|
-
log_manager = None
|
|
323
|
+
# Log the system prompt if needed
|
|
324
|
+
self._log_system_prompt()
|
|
847
325
|
|
|
848
326
|
# Generate the instructions
|
|
849
327
|
if self.framework_content["loaded"]:
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
else:
|
|
853
|
-
# Use minimal fallback
|
|
854
|
-
instructions = self._format_minimal_framework()
|
|
855
|
-
|
|
856
|
-
# Log the system prompt if LogManager is available
|
|
857
|
-
if log_manager:
|
|
858
|
-
try:
|
|
859
|
-
import asyncio
|
|
860
|
-
import os
|
|
861
|
-
|
|
862
|
-
# Get or create event loop
|
|
863
|
-
try:
|
|
864
|
-
loop = asyncio.get_running_loop()
|
|
865
|
-
except RuntimeError:
|
|
866
|
-
loop = asyncio.new_event_loop()
|
|
867
|
-
asyncio.set_event_loop(loop)
|
|
868
|
-
|
|
869
|
-
# Prepare metadata
|
|
870
|
-
metadata = {
|
|
871
|
-
"framework_version": self.framework_version,
|
|
872
|
-
"framework_loaded": self.framework_content.get("loaded", False),
|
|
873
|
-
"session_id": os.environ.get("CLAUDE_SESSION_ID", "unknown"),
|
|
874
|
-
"instructions_length": len(instructions),
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
# Log the prompt asynchronously
|
|
878
|
-
if loop.is_running():
|
|
879
|
-
asyncio.create_task(
|
|
880
|
-
log_manager.log_prompt("system_prompt", instructions, metadata)
|
|
881
|
-
)
|
|
882
|
-
else:
|
|
883
|
-
loop.run_until_complete(
|
|
884
|
-
log_manager.log_prompt("system_prompt", instructions, metadata)
|
|
885
|
-
)
|
|
886
|
-
|
|
887
|
-
self.logger.debug("System prompt logged to prompts directory")
|
|
888
|
-
except Exception as e:
|
|
889
|
-
self.logger.debug(f"Could not log system prompt: {e}")
|
|
890
|
-
|
|
891
|
-
return instructions
|
|
892
|
-
|
|
893
|
-
def _strip_metadata_comments(self, content: str) -> str:
|
|
894
|
-
"""Strip metadata HTML comments from content.
|
|
895
|
-
|
|
896
|
-
Removes comments like:
|
|
897
|
-
<!-- FRAMEWORK_VERSION: 0010 -->
|
|
898
|
-
<!-- LAST_MODIFIED: 2025-08-10T00:00:00Z -->
|
|
899
|
-
"""
|
|
900
|
-
import re
|
|
901
|
-
|
|
902
|
-
# Remove HTML comments that contain metadata
|
|
903
|
-
cleaned = re.sub(
|
|
904
|
-
r"<!--\s*(FRAMEWORK_VERSION|LAST_MODIFIED|WORKFLOW_VERSION|PROJECT_WORKFLOW_VERSION|CUSTOM_PROJECT_WORKFLOW)[^>]*-->\n?",
|
|
905
|
-
"",
|
|
906
|
-
content,
|
|
907
|
-
)
|
|
908
|
-
# Also remove any leading blank lines that might result
|
|
909
|
-
return cleaned.lstrip("\n")
|
|
328
|
+
return self._format_full_framework()
|
|
329
|
+
return self._format_minimal_framework()
|
|
910
330
|
|
|
911
331
|
def _format_full_framework(self) -> str:
|
|
912
|
-
"""Format full framework instructions."""
|
|
913
|
-
|
|
914
|
-
# 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
|
|
915
334
|
if self.output_style_manager is None:
|
|
916
335
|
self._initialize_output_style()
|
|
917
336
|
|
|
918
|
-
# Check if we need to inject output style
|
|
337
|
+
# Check if we need to inject output style
|
|
919
338
|
inject_output_style = False
|
|
339
|
+
output_style_content = None
|
|
920
340
|
if self.output_style_manager:
|
|
921
341
|
inject_output_style = self.output_style_manager.should_inject_content()
|
|
922
342
|
if inject_output_style:
|
|
923
|
-
self.logger.info(
|
|
924
|
-
"Injecting output style content into instructions for Claude < 1.0.83"
|
|
925
|
-
)
|
|
926
|
-
|
|
927
|
-
# If we have the full framework INSTRUCTIONS.md, use it
|
|
928
|
-
if self.framework_content.get("framework_instructions"):
|
|
929
|
-
instructions = self._strip_metadata_comments(
|
|
930
|
-
self.framework_content["framework_instructions"]
|
|
931
|
-
)
|
|
932
|
-
|
|
933
|
-
# Note: We don't add working directory CLAUDE.md here since Claude Code
|
|
934
|
-
# already picks it up automatically. This prevents duplication.
|
|
935
|
-
|
|
936
|
-
# Add custom INSTRUCTIONS.md if present (overrides or extends framework instructions)
|
|
937
|
-
if self.framework_content.get("custom_instructions"):
|
|
938
|
-
level = self.framework_content.get(
|
|
939
|
-
"custom_instructions_level", "unknown"
|
|
940
|
-
)
|
|
941
|
-
instructions += f"\n\n## Custom PM Instructions ({level} level)\n\n"
|
|
942
|
-
instructions += "**The following custom instructions override or extend the framework defaults:**\n\n"
|
|
943
|
-
instructions += self._strip_metadata_comments(
|
|
944
|
-
self.framework_content["custom_instructions"]
|
|
945
|
-
)
|
|
946
|
-
instructions += "\n"
|
|
947
|
-
|
|
948
|
-
# Add WORKFLOW.md after instructions
|
|
949
|
-
if self.framework_content.get("workflow_instructions"):
|
|
950
|
-
workflow_content = self._strip_metadata_comments(
|
|
951
|
-
self.framework_content["workflow_instructions"]
|
|
952
|
-
)
|
|
953
|
-
level = self.framework_content.get(
|
|
954
|
-
"workflow_instructions_level", "system"
|
|
955
|
-
)
|
|
956
|
-
if level != "system":
|
|
957
|
-
instructions += f"\n\n## Workflow Instructions ({level} level)\n\n"
|
|
958
|
-
instructions += "**The following workflow instructions override system defaults:**\n\n"
|
|
959
|
-
instructions += f"{workflow_content}\n"
|
|
960
|
-
|
|
961
|
-
# Add MEMORY.md after workflow instructions
|
|
962
|
-
if self.framework_content.get("memory_instructions"):
|
|
963
|
-
memory_content = self._strip_metadata_comments(
|
|
964
|
-
self.framework_content["memory_instructions"]
|
|
965
|
-
)
|
|
966
|
-
level = self.framework_content.get(
|
|
967
|
-
"memory_instructions_level", "system"
|
|
968
|
-
)
|
|
969
|
-
if level != "system":
|
|
970
|
-
instructions += f"\n\n## Memory Instructions ({level} level)\n\n"
|
|
971
|
-
instructions += "**The following memory instructions override system defaults:**\n\n"
|
|
972
|
-
instructions += f"{memory_content}\n"
|
|
973
|
-
|
|
974
|
-
# Add actual PM memories after memory instructions
|
|
975
|
-
if self.framework_content.get("actual_memories"):
|
|
976
|
-
instructions += "\n\n## Current PM Memories\n\n"
|
|
977
|
-
instructions += "**The following are your accumulated memories and knowledge from this project:**\n\n"
|
|
978
|
-
instructions += self.framework_content["actual_memories"]
|
|
979
|
-
instructions += "\n"
|
|
980
|
-
|
|
981
|
-
# Add agent memories if available
|
|
982
|
-
if self.framework_content.get("agent_memories"):
|
|
983
|
-
agent_memories = self.framework_content["agent_memories"]
|
|
984
|
-
if agent_memories:
|
|
985
|
-
instructions += "\n\n## Agent Memories\n\n"
|
|
986
|
-
instructions += "**The following are accumulated memories from specialized agents:**\n\n"
|
|
987
|
-
|
|
988
|
-
for agent_name in sorted(agent_memories.keys()):
|
|
989
|
-
memory_content = agent_memories[agent_name]
|
|
990
|
-
if memory_content:
|
|
991
|
-
instructions += f"### {agent_name.replace('_', ' ').title()} Agent Memory\n\n"
|
|
992
|
-
instructions += memory_content
|
|
993
|
-
instructions += "\n\n"
|
|
994
|
-
|
|
995
|
-
# Add dynamic agent capabilities section
|
|
996
|
-
instructions += self._generate_agent_capabilities_section()
|
|
997
|
-
|
|
998
|
-
# Add current date for temporal awareness
|
|
999
|
-
instructions += f"\n\n## Temporal Context\n**Today's Date**: {datetime.now().strftime('%Y-%m-%d')}\n"
|
|
1000
|
-
instructions += (
|
|
1001
|
-
"Apply date awareness to all time-sensitive tasks and decisions.\n"
|
|
1002
|
-
)
|
|
1003
|
-
|
|
1004
|
-
# Add BASE_PM.md framework requirements AFTER INSTRUCTIONS.md
|
|
1005
|
-
if self.framework_content.get("base_pm_instructions"):
|
|
1006
|
-
base_pm = self._strip_metadata_comments(
|
|
1007
|
-
self.framework_content["base_pm_instructions"]
|
|
1008
|
-
)
|
|
1009
|
-
instructions += f"\n\n{base_pm}"
|
|
1010
|
-
|
|
1011
|
-
# Inject output style content if needed (for Claude < 1.0.83)
|
|
1012
|
-
if inject_output_style and self.output_style_manager:
|
|
1013
343
|
output_style_content = self.output_style_manager.get_injectable_content(
|
|
1014
344
|
framework_loader=self
|
|
1015
345
|
)
|
|
1016
|
-
|
|
1017
|
-
instructions += "\n\n## Output Style Configuration\n"
|
|
1018
|
-
instructions += "**Note: The following output style is injected for Claude < 1.0.83**\n\n"
|
|
1019
|
-
instructions += output_style_content
|
|
1020
|
-
instructions += "\n"
|
|
1021
|
-
|
|
1022
|
-
# Clean up any trailing whitespace
|
|
1023
|
-
return instructions.rstrip() + "\n"
|
|
1024
|
-
|
|
1025
|
-
# Otherwise fall back to generating framework
|
|
1026
|
-
instructions = """# Claude MPM Framework Instructions
|
|
1027
|
-
|
|
1028
|
-
You are operating within the Claude Multi-Agent Project Manager (MPM) framework.
|
|
1029
|
-
|
|
1030
|
-
## Core Role
|
|
1031
|
-
You are a multi-agent orchestrator. Your primary responsibilities are:
|
|
1032
|
-
- Delegate all implementation work to specialized agents via Task Tool
|
|
1033
|
-
- Coordinate multi-agent workflows and cross-agent collaboration
|
|
1034
|
-
- Extract and track TODO/BUG/FEATURE items for ticket creation
|
|
1035
|
-
- Maintain project visibility and strategic oversight
|
|
1036
|
-
- NEVER perform direct implementation work yourself
|
|
1037
|
-
|
|
1038
|
-
"""
|
|
1039
|
-
|
|
1040
|
-
# Note: We don't add working directory CLAUDE.md here since Claude Code
|
|
1041
|
-
# already picks it up automatically. This prevents duplication.
|
|
1042
|
-
|
|
1043
|
-
# Add agent definitions
|
|
1044
|
-
if self.framework_content["agents"]:
|
|
1045
|
-
instructions += "## Available Agents\n\n"
|
|
1046
|
-
instructions += "You have the following specialized agents available for delegation:\n\n"
|
|
1047
|
-
|
|
1048
|
-
# List agents with brief descriptions and correct IDs
|
|
1049
|
-
agent_list = []
|
|
1050
|
-
for agent_name in sorted(self.framework_content["agents"].keys()):
|
|
1051
|
-
# Use the actual agent_name as the ID (it's the filename stem)
|
|
1052
|
-
agent_id = agent_name
|
|
1053
|
-
clean_name = agent_name.replace("-", " ").replace("_", " ").title()
|
|
1054
|
-
if (
|
|
1055
|
-
"engineer" in agent_name.lower()
|
|
1056
|
-
and "data" not in agent_name.lower()
|
|
1057
|
-
):
|
|
1058
|
-
agent_list.append(
|
|
1059
|
-
f"- **Engineer Agent** (`{agent_id}`): Code implementation and development"
|
|
1060
|
-
)
|
|
1061
|
-
elif "qa" in agent_name.lower():
|
|
1062
|
-
agent_list.append(
|
|
1063
|
-
f"- **QA Agent** (`{agent_id}`): Testing and quality assurance"
|
|
1064
|
-
)
|
|
1065
|
-
elif "documentation" in agent_name.lower():
|
|
1066
|
-
agent_list.append(
|
|
1067
|
-
f"- **Documentation Agent** (`{agent_id}`): Documentation creation and maintenance"
|
|
1068
|
-
)
|
|
1069
|
-
elif "research" in agent_name.lower():
|
|
1070
|
-
agent_list.append(
|
|
1071
|
-
f"- **Research Agent** (`{agent_id}`): Investigation and analysis"
|
|
1072
|
-
)
|
|
1073
|
-
elif "security" in agent_name.lower():
|
|
1074
|
-
agent_list.append(
|
|
1075
|
-
f"- **Security Agent** (`{agent_id}`): Security analysis and protection"
|
|
1076
|
-
)
|
|
1077
|
-
elif "version" in agent_name.lower():
|
|
1078
|
-
agent_list.append(
|
|
1079
|
-
f"- **Version Control Agent** (`{agent_id}`): Git operations and version management"
|
|
1080
|
-
)
|
|
1081
|
-
elif "ops" in agent_name.lower():
|
|
1082
|
-
agent_list.append(
|
|
1083
|
-
f"- **Ops Agent** (`{agent_id}`): Deployment and operations"
|
|
1084
|
-
)
|
|
1085
|
-
elif "data" in agent_name.lower():
|
|
1086
|
-
agent_list.append(
|
|
1087
|
-
f"- **Data Engineer Agent** (`{agent_id}`): Data management and AI API integration"
|
|
1088
|
-
)
|
|
1089
|
-
else:
|
|
1090
|
-
agent_list.append(
|
|
1091
|
-
f"- **{clean_name}** (`{agent_id}`): Available for specialized tasks"
|
|
1092
|
-
)
|
|
346
|
+
self.logger.info("Injecting output style content for Claude < 1.0.83")
|
|
1093
347
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
instructions += "### Agent Details\n\n"
|
|
1098
|
-
for agent_name, agent_content in sorted(
|
|
1099
|
-
self.framework_content["agents"].items()
|
|
1100
|
-
):
|
|
1101
|
-
instructions += f"#### {agent_name.replace('-', ' ').title()}\n"
|
|
1102
|
-
instructions += agent_content + "\n\n"
|
|
1103
|
-
|
|
1104
|
-
# Add orchestration principles
|
|
1105
|
-
instructions += """
|
|
1106
|
-
## Orchestration Principles
|
|
1107
|
-
1. **Always Delegate**: Never perform direct work - use Task Tool for all implementation
|
|
1108
|
-
2. **Comprehensive Context**: Provide rich, filtered context to each agent
|
|
1109
|
-
3. **Track Everything**: Extract all TODO/BUG/FEATURE items systematically
|
|
1110
|
-
4. **Cross-Agent Coordination**: Orchestrate workflows spanning multiple agents
|
|
1111
|
-
5. **Results Integration**: Actively receive and integrate agent results
|
|
1112
|
-
|
|
1113
|
-
## Task Tool Format
|
|
1114
|
-
```
|
|
1115
|
-
**[Agent Name]**: [Clear task description with deliverables]
|
|
1116
|
-
|
|
1117
|
-
TEMPORAL CONTEXT: Today is [date]. Apply date awareness to [specific considerations].
|
|
1118
|
-
|
|
1119
|
-
**Task**: [Detailed task breakdown]
|
|
1120
|
-
1. [Specific action item 1]
|
|
1121
|
-
2. [Specific action item 2]
|
|
1122
|
-
3. [Specific action item 3]
|
|
1123
|
-
|
|
1124
|
-
**Context**: [Comprehensive filtered context for this agent]
|
|
1125
|
-
**Authority**: [Agent's decision-making scope]
|
|
1126
|
-
**Expected Results**: [Specific deliverables needed]
|
|
1127
|
-
**Integration**: [How results integrate with other work]
|
|
1128
|
-
```
|
|
1129
|
-
|
|
1130
|
-
## Ticket Extraction Patterns
|
|
1131
|
-
Extract tickets from these patterns:
|
|
1132
|
-
- TODO: [description] → TODO ticket
|
|
1133
|
-
- BUG: [description] → BUG ticket
|
|
1134
|
-
- FEATURE: [description] → FEATURE ticket
|
|
1135
|
-
- ISSUE: [description] → ISSUE ticket
|
|
1136
|
-
- FIXME: [description] → BUG ticket
|
|
1137
|
-
|
|
1138
|
-
---
|
|
1139
|
-
"""
|
|
1140
|
-
|
|
1141
|
-
return instructions
|
|
348
|
+
# Generate dynamic sections
|
|
349
|
+
capabilities_section = self._generate_agent_capabilities_section()
|
|
350
|
+
context_section = self.context_generator.generate_temporal_user_context()
|
|
1142
351
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
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
|
+
)
|
|
360
|
+
|
|
361
|
+
def _format_minimal_framework(self) -> str:
|
|
362
|
+
"""Format minimal framework instructions."""
|
|
363
|
+
return self.content_formatter.format_minimal_framework(self.framework_content)
|
|
1146
364
|
|
|
1147
|
-
|
|
365
|
+
def _generate_agent_capabilities_section(self) -> str:
|
|
366
|
+
"""Generate agent capabilities section with caching."""
|
|
367
|
+
# Try cache first
|
|
1148
368
|
cached_capabilities = self._cache_manager.get_capabilities()
|
|
1149
369
|
if cached_capabilities is not None:
|
|
1150
370
|
return cached_capabilities
|
|
1151
371
|
|
|
1152
|
-
|
|
1153
|
-
current_time = time.time()
|
|
1154
|
-
|
|
1155
|
-
# Cache miss or expired - generate capabilities
|
|
1156
|
-
self.logger.debug("Generating agent capabilities (cache miss or expired)")
|
|
372
|
+
self.logger.debug("Generating agent capabilities (cache miss)")
|
|
1157
373
|
|
|
1158
374
|
try:
|
|
1159
|
-
|
|
375
|
+
# Discover local JSON templates
|
|
376
|
+
local_agents = self._discover_local_json_templates()
|
|
1160
377
|
|
|
1161
|
-
#
|
|
1162
|
-
|
|
1163
|
-
# Priority order: project > user home > fallback
|
|
378
|
+
# Get deployed agents from .claude/agents/
|
|
379
|
+
deployed_agents = []
|
|
1164
380
|
agents_dirs = [
|
|
1165
|
-
Path.cwd() / ".claude" / "agents",
|
|
1166
|
-
Path.home() / ".claude" / "agents",
|
|
381
|
+
Path.cwd() / ".claude" / "agents",
|
|
382
|
+
Path.home() / ".claude" / "agents",
|
|
1167
383
|
]
|
|
1168
384
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
continue
|
|
1181
|
-
|
|
1182
|
-
# Parse agent metadata (with caching)
|
|
1183
|
-
agent_data = self._parse_agent_metadata(agent_file)
|
|
1184
|
-
if agent_data:
|
|
1185
|
-
agent_id = agent_data["id"]
|
|
1186
|
-
# Only add if not already present (project has priority 0, user has priority 1)
|
|
1187
|
-
# Lower priority number wins (project > user)
|
|
1188
|
-
if (
|
|
1189
|
-
agent_id not in all_agents
|
|
1190
|
-
or priority < all_agents[agent_id][1]
|
|
1191
|
-
):
|
|
1192
|
-
all_agents[agent_id] = (agent_data, priority)
|
|
1193
|
-
self.logger.debug(
|
|
1194
|
-
f"Added/Updated agent {agent_id} from {potential_dir} (priority {priority})"
|
|
1195
|
-
)
|
|
1196
|
-
|
|
1197
|
-
if not all_agents:
|
|
1198
|
-
self.logger.warning(f"No agents found in any location: {agents_dirs}")
|
|
1199
|
-
result = self._get_fallback_capabilities()
|
|
1200
|
-
# Cache the fallback result too
|
|
1201
|
-
self._cache_manager.set_capabilities(result)
|
|
1202
|
-
return result
|
|
1203
|
-
|
|
1204
|
-
# Log agent collection summary
|
|
1205
|
-
project_agents = [aid for aid, (_, pri) in all_agents.items() if pri == 0]
|
|
1206
|
-
user_agents = [aid for aid, (_, pri) in all_agents.items() if pri == 1]
|
|
1207
|
-
|
|
1208
|
-
if project_agents:
|
|
1209
|
-
self.logger.info(
|
|
1210
|
-
f"Loaded {len(project_agents)} project agents: {', '.join(sorted(project_agents))}"
|
|
1211
|
-
)
|
|
1212
|
-
if user_agents:
|
|
1213
|
-
self.logger.info(
|
|
1214
|
-
f"Loaded {len(user_agents)} user agents: {', '.join(sorted(user_agents))}"
|
|
1215
|
-
)
|
|
1216
|
-
|
|
1217
|
-
# Build capabilities section
|
|
1218
|
-
section = "\n\n## Available Agent Capabilities\n\n"
|
|
1219
|
-
|
|
1220
|
-
# Extract just the agent data (drop priority info) and sort
|
|
1221
|
-
deployed_agents = [agent_data for agent_data, _ in all_agents.values()]
|
|
1222
|
-
|
|
1223
|
-
if not deployed_agents:
|
|
1224
|
-
result = self._get_fallback_capabilities()
|
|
1225
|
-
# Cache the fallback result
|
|
1226
|
-
self._cache_manager.set_capabilities(result)
|
|
1227
|
-
return result
|
|
1228
|
-
|
|
1229
|
-
# Sort agents alphabetically by ID
|
|
1230
|
-
deployed_agents.sort(key=lambda x: x["id"])
|
|
1231
|
-
|
|
1232
|
-
# Display all agents with their rich descriptions
|
|
1233
|
-
for agent in deployed_agents:
|
|
1234
|
-
# Clean up display name - handle common acronyms
|
|
1235
|
-
display_name = agent["display_name"]
|
|
1236
|
-
display_name = (
|
|
1237
|
-
display_name.replace("Qa ", "QA ")
|
|
1238
|
-
.replace("Ui ", "UI ")
|
|
1239
|
-
.replace("Api ", "API ")
|
|
1240
|
-
)
|
|
1241
|
-
if display_name.lower() == "qa agent":
|
|
1242
|
-
display_name = "QA Agent"
|
|
1243
|
-
|
|
1244
|
-
section += f"\n### {display_name} (`{agent['id']}`)\n"
|
|
1245
|
-
section += f"{agent['description']}\n"
|
|
1246
|
-
|
|
1247
|
-
# Add routing information if available
|
|
1248
|
-
if agent.get("routing"):
|
|
1249
|
-
routing = agent["routing"]
|
|
1250
|
-
|
|
1251
|
-
# Format routing hints for PM usage
|
|
1252
|
-
routing_hints = []
|
|
1253
|
-
|
|
1254
|
-
if routing.get("keywords"):
|
|
1255
|
-
# Show first 5 keywords for brevity
|
|
1256
|
-
keywords = routing["keywords"][:5]
|
|
1257
|
-
routing_hints.append(f"Keywords: {', '.join(keywords)}")
|
|
1258
|
-
|
|
1259
|
-
if routing.get("paths"):
|
|
1260
|
-
# Show first 3 paths for brevity
|
|
1261
|
-
paths = routing["paths"][:3]
|
|
1262
|
-
routing_hints.append(f"Paths: {', '.join(paths)}")
|
|
1263
|
-
|
|
1264
|
-
if routing.get("priority"):
|
|
1265
|
-
routing_hints.append(f"Priority: {routing['priority']}")
|
|
1266
|
-
|
|
1267
|
-
if routing_hints:
|
|
1268
|
-
section += f"- **Routing**: {' | '.join(routing_hints)}\n"
|
|
1269
|
-
|
|
1270
|
-
# Add when_to_use if present
|
|
1271
|
-
if routing.get("when_to_use"):
|
|
1272
|
-
section += f"- **When to use**: {routing['when_to_use']}\n"
|
|
1273
|
-
|
|
1274
|
-
# Add any additional metadata if present
|
|
1275
|
-
if agent.get("authority"):
|
|
1276
|
-
section += f"- **Authority**: {agent['authority']}\n"
|
|
1277
|
-
if agent.get("primary_function"):
|
|
1278
|
-
section += f"- **Primary Function**: {agent['primary_function']}\n"
|
|
1279
|
-
if agent.get("handoff_to"):
|
|
1280
|
-
section += f"- **Handoff To**: {agent['handoff_to']}\n"
|
|
1281
|
-
if agent.get("tools") and agent["tools"] != "standard":
|
|
1282
|
-
section += f"- **Tools**: {agent['tools']}\n"
|
|
1283
|
-
if agent.get("model") and agent["model"] != "opus":
|
|
1284
|
-
section += f"- **Model**: {agent['model']}\n"
|
|
1285
|
-
|
|
1286
|
-
# Add memory routing information if available
|
|
1287
|
-
if agent.get("memory_routing"):
|
|
1288
|
-
memory_routing = agent["memory_routing"]
|
|
1289
|
-
if memory_routing.get("description"):
|
|
1290
|
-
section += (
|
|
1291
|
-
f"- **Memory Routing**: {memory_routing['description']}\n"
|
|
1292
|
-
)
|
|
1293
|
-
|
|
1294
|
-
# Add simple Context-Aware Agent Selection
|
|
1295
|
-
section += "\n## Context-Aware Agent Selection\n\n"
|
|
1296
|
-
section += (
|
|
1297
|
-
"Select agents based on their descriptions above. Key principles:\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
|
|
1298
396
|
)
|
|
1299
|
-
section += "- **PM questions** → Answer directly (only exception)\n"
|
|
1300
|
-
section += "- Match task requirements to agent descriptions and authority\n"
|
|
1301
|
-
section += "- Consider agent handoff recommendations\n"
|
|
1302
|
-
section += (
|
|
1303
|
-
"- Use the agent ID in parentheses when delegating via Task tool\n"
|
|
1304
|
-
)
|
|
1305
|
-
|
|
1306
|
-
# Add summary
|
|
1307
|
-
section += f"\n**Total Available Agents**: {len(deployed_agents)}\n"
|
|
1308
397
|
|
|
1309
|
-
# Cache the
|
|
398
|
+
# Cache the result
|
|
1310
399
|
self._cache_manager.set_capabilities(section)
|
|
1311
|
-
self.logger.debug(
|
|
1312
|
-
f"Cached agent capabilities section ({len(section)} chars)"
|
|
1313
|
-
)
|
|
400
|
+
self.logger.debug(f"Cached agent capabilities ({len(section)} chars)")
|
|
1314
401
|
|
|
1315
402
|
return section
|
|
1316
403
|
|
|
1317
404
|
except Exception as e:
|
|
1318
|
-
self.logger.warning(f"Could not generate
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
self._agent_capabilities_cache_time = current_time
|
|
1323
|
-
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
|
|
1324
409
|
|
|
1325
|
-
|
|
1326
|
-
"""Parse agent metadata from deployed agent file.
|
|
1327
|
-
Uses caching based on file path and modification time.
|
|
410
|
+
# === Output Style Management ===
|
|
1328
411
|
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
"""
|
|
412
|
+
def _initialize_output_style(self) -> None:
|
|
413
|
+
"""Initialize output style management."""
|
|
1332
414
|
try:
|
|
1333
|
-
|
|
1334
|
-
cache_key = str(agent_file)
|
|
1335
|
-
file_mtime = agent_file.stat().st_mtime
|
|
1336
|
-
current_time = time.time()
|
|
1337
|
-
|
|
1338
|
-
# Try to get from cache first
|
|
1339
|
-
cached_result = self._cache_manager.get_agent_metadata(cache_key)
|
|
1340
|
-
if cached_result is not None:
|
|
1341
|
-
cached_data, cached_mtime = cached_result
|
|
1342
|
-
# Use cache if file hasn't been modified and cache isn't too old
|
|
1343
|
-
if cached_mtime == file_mtime:
|
|
1344
|
-
self.logger.debug(f"Using cached metadata for {agent_file.name}")
|
|
1345
|
-
return cached_data
|
|
1346
|
-
|
|
1347
|
-
# Cache miss or expired - parse the file
|
|
1348
|
-
self.logger.debug(
|
|
1349
|
-
f"Parsing metadata for {agent_file.name} (cache miss or expired)"
|
|
1350
|
-
)
|
|
1351
|
-
|
|
1352
|
-
import yaml
|
|
1353
|
-
|
|
1354
|
-
with open(agent_file) as f:
|
|
1355
|
-
content = f.read()
|
|
415
|
+
from claude_mpm.core.output_style_manager import OutputStyleManager
|
|
1356
416
|
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
"id": agent_file.stem,
|
|
1360
|
-
"display_name": agent_file.stem.replace("_", " ")
|
|
1361
|
-
.replace("-", " ")
|
|
1362
|
-
.title(),
|
|
1363
|
-
"description": "Specialized agent",
|
|
1364
|
-
}
|
|
417
|
+
self.output_style_manager = OutputStyleManager()
|
|
418
|
+
self._log_output_style_status()
|
|
1365
419
|
|
|
1366
|
-
# Extract
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
frontmatter = content[3:end_marker]
|
|
1371
|
-
metadata = yaml.safe_load(frontmatter)
|
|
1372
|
-
if metadata:
|
|
1373
|
-
# Use name as ID for Task tool
|
|
1374
|
-
agent_data["id"] = metadata.get("name", agent_data["id"])
|
|
1375
|
-
agent_data["display_name"] = (
|
|
1376
|
-
metadata.get("name", agent_data["display_name"])
|
|
1377
|
-
.replace("-", " ")
|
|
1378
|
-
.title()
|
|
1379
|
-
)
|
|
1380
|
-
|
|
1381
|
-
# Copy all metadata fields directly
|
|
1382
|
-
for key, value in metadata.items():
|
|
1383
|
-
if key not in ["name"]: # Skip already processed fields
|
|
1384
|
-
agent_data[key] = value
|
|
1385
|
-
|
|
1386
|
-
# IMPORTANT: Do NOT add spaces to tools field - it breaks deployment!
|
|
1387
|
-
# Tools must remain as comma-separated without spaces: "Read,Write,Edit"
|
|
1388
|
-
|
|
1389
|
-
# Try to load routing metadata from JSON template if not in YAML frontmatter
|
|
1390
|
-
if "routing" not in agent_data:
|
|
1391
|
-
routing_data = self._load_routing_from_template(agent_file.stem)
|
|
1392
|
-
if routing_data:
|
|
1393
|
-
agent_data["routing"] = routing_data
|
|
1394
|
-
|
|
1395
|
-
# Try to load memory routing metadata from JSON template if not in YAML frontmatter
|
|
1396
|
-
if "memory_routing" not in agent_data:
|
|
1397
|
-
memory_routing_data = self._load_memory_routing_from_template(
|
|
1398
|
-
agent_file.stem
|
|
420
|
+
# Extract and save output style content
|
|
421
|
+
output_style_content = (
|
|
422
|
+
self.output_style_manager.extract_output_style_content(
|
|
423
|
+
framework_loader=self
|
|
1399
424
|
)
|
|
1400
|
-
if memory_routing_data:
|
|
1401
|
-
agent_data["memory_routing"] = memory_routing_data
|
|
1402
|
-
|
|
1403
|
-
# Cache the parsed metadata
|
|
1404
|
-
self._cache_manager.set_agent_metadata(cache_key, agent_data, file_mtime)
|
|
1405
|
-
|
|
1406
|
-
return agent_data
|
|
1407
|
-
|
|
1408
|
-
except Exception as e:
|
|
1409
|
-
self.logger.debug(f"Could not parse metadata from {agent_file}: {e}")
|
|
1410
|
-
return None
|
|
1411
|
-
|
|
1412
|
-
def _load_memory_routing_from_template(
|
|
1413
|
-
self, agent_name: str
|
|
1414
|
-
) -> Optional[Dict[str, Any]]:
|
|
1415
|
-
"""Load memory routing metadata from agent JSON template.
|
|
1416
|
-
|
|
1417
|
-
Args:
|
|
1418
|
-
agent_name: Name of the agent (stem of the file)
|
|
1419
|
-
|
|
1420
|
-
Returns:
|
|
1421
|
-
Dictionary with memory routing metadata or None if not found
|
|
1422
|
-
"""
|
|
1423
|
-
try:
|
|
1424
|
-
import json
|
|
1425
|
-
|
|
1426
|
-
# Check if we have a framework path
|
|
1427
|
-
if not self.framework_path or self.framework_path == Path("__PACKAGED__"):
|
|
1428
|
-
# For packaged installations, try to load from package resources
|
|
1429
|
-
if files:
|
|
1430
|
-
try:
|
|
1431
|
-
templates_package = files("claude_mpm.agents.templates")
|
|
1432
|
-
template_file = templates_package / f"{agent_name}.json"
|
|
1433
|
-
|
|
1434
|
-
if template_file.is_file():
|
|
1435
|
-
template_content = template_file.read_text()
|
|
1436
|
-
template_data = json.loads(template_content)
|
|
1437
|
-
return template_data.get("memory_routing")
|
|
1438
|
-
except Exception as e:
|
|
1439
|
-
self.logger.debug(
|
|
1440
|
-
f"Could not load memory routing from packaged template for {agent_name}: {e}"
|
|
1441
|
-
)
|
|
1442
|
-
return None
|
|
1443
|
-
|
|
1444
|
-
# For development mode, load from filesystem
|
|
1445
|
-
templates_dir = (
|
|
1446
|
-
self.framework_path / "src" / "claude_mpm" / "agents" / "templates"
|
|
1447
|
-
)
|
|
1448
|
-
template_file = templates_dir / f"{agent_name}.json"
|
|
1449
|
-
|
|
1450
|
-
if template_file.exists():
|
|
1451
|
-
with open(template_file) as f:
|
|
1452
|
-
template_data = json.load(f)
|
|
1453
|
-
return template_data.get("memory_routing")
|
|
1454
|
-
|
|
1455
|
-
# Also check for variations in naming (underscore vs dash)
|
|
1456
|
-
# Handle common naming variations between deployed .md files and .json templates
|
|
1457
|
-
# Remove duplicates by using a set
|
|
1458
|
-
alternative_names = list(
|
|
1459
|
-
{
|
|
1460
|
-
agent_name.replace("-", "_"), # api-qa -> api_qa
|
|
1461
|
-
agent_name.replace("_", "-"), # api_qa -> api-qa
|
|
1462
|
-
agent_name.replace("-", ""), # api-qa -> apiqa
|
|
1463
|
-
agent_name.replace("_", ""), # api_qa -> apiqa
|
|
1464
|
-
agent_name.replace("-agent", ""), # research-agent -> research
|
|
1465
|
-
agent_name.replace("_agent", ""), # research_agent -> research
|
|
1466
|
-
agent_name + "_agent", # research -> research_agent
|
|
1467
|
-
agent_name + "-agent", # research -> research-agent
|
|
1468
|
-
}
|
|
1469
425
|
)
|
|
426
|
+
self.output_style_manager.save_output_style(output_style_content)
|
|
1470
427
|
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
if alt_file.exists():
|
|
1475
|
-
with open(alt_file) as f:
|
|
1476
|
-
template_data = json.load(f)
|
|
1477
|
-
return template_data.get("memory_routing")
|
|
1478
|
-
|
|
1479
|
-
return None
|
|
1480
|
-
|
|
1481
|
-
except Exception as e:
|
|
1482
|
-
self.logger.debug(
|
|
1483
|
-
f"Could not load memory routing from template for {agent_name}: {e}"
|
|
1484
|
-
)
|
|
1485
|
-
return None
|
|
1486
|
-
|
|
1487
|
-
def _load_routing_from_template(self, agent_name: str) -> Optional[Dict[str, Any]]:
|
|
1488
|
-
"""Load routing metadata from agent JSON template.
|
|
1489
|
-
|
|
1490
|
-
Args:
|
|
1491
|
-
agent_name: Name of the agent (stem of the file)
|
|
1492
|
-
|
|
1493
|
-
Returns:
|
|
1494
|
-
Dictionary with routing metadata or None if not found
|
|
1495
|
-
"""
|
|
1496
|
-
try:
|
|
1497
|
-
import json
|
|
1498
|
-
|
|
1499
|
-
# Check if we have a framework path
|
|
1500
|
-
if not self.framework_path or self.framework_path == Path("__PACKAGED__"):
|
|
1501
|
-
# For packaged installations, try to load from package resources
|
|
1502
|
-
if files:
|
|
1503
|
-
try:
|
|
1504
|
-
templates_package = files("claude_mpm.agents.templates")
|
|
1505
|
-
template_file = templates_package / f"{agent_name}.json"
|
|
1506
|
-
|
|
1507
|
-
if template_file.is_file():
|
|
1508
|
-
template_content = template_file.read_text()
|
|
1509
|
-
template_data = json.loads(template_content)
|
|
1510
|
-
return template_data.get("routing")
|
|
1511
|
-
except Exception as e:
|
|
1512
|
-
self.logger.debug(
|
|
1513
|
-
f"Could not load routing from packaged template for {agent_name}: {e}"
|
|
1514
|
-
)
|
|
1515
|
-
return None
|
|
1516
|
-
|
|
1517
|
-
# For development mode, load from filesystem
|
|
1518
|
-
templates_dir = (
|
|
1519
|
-
self.framework_path / "src" / "claude_mpm" / "agents" / "templates"
|
|
1520
|
-
)
|
|
1521
|
-
template_file = templates_dir / f"{agent_name}.json"
|
|
1522
|
-
|
|
1523
|
-
if template_file.exists():
|
|
1524
|
-
with open(template_file) as f:
|
|
1525
|
-
template_data = json.load(f)
|
|
1526
|
-
return template_data.get("routing")
|
|
1527
|
-
|
|
1528
|
-
# Also check for variations in naming (underscore vs dash)
|
|
1529
|
-
# Handle common naming variations between deployed .md files and .json templates
|
|
1530
|
-
# Remove duplicates by using a set
|
|
1531
|
-
alternative_names = list(
|
|
1532
|
-
{
|
|
1533
|
-
agent_name.replace("-", "_"), # api-qa -> api_qa
|
|
1534
|
-
agent_name.replace("_", "-"), # api_qa -> api-qa
|
|
1535
|
-
agent_name.replace("-", ""), # api-qa -> apiqa
|
|
1536
|
-
agent_name.replace("_", ""), # api_qa -> apiqa
|
|
1537
|
-
}
|
|
428
|
+
# Deploy to Claude Code if supported
|
|
429
|
+
deployed = self.output_style_manager.deploy_output_style(
|
|
430
|
+
output_style_content
|
|
1538
431
|
)
|
|
1539
432
|
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
with open(alt_file) as f:
|
|
1545
|
-
template_data = json.load(f)
|
|
1546
|
-
return template_data.get("routing")
|
|
1547
|
-
|
|
1548
|
-
self.logger.debug(f"No JSON template found for agent: {agent_name}")
|
|
1549
|
-
return None
|
|
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")
|
|
1550
437
|
|
|
1551
438
|
except Exception as e:
|
|
1552
|
-
self.logger.
|
|
1553
|
-
return None
|
|
1554
|
-
|
|
1555
|
-
def _generate_agent_selection_guide(self, deployed_agents: list) -> str:
|
|
1556
|
-
"""Generate Context-Aware Agent Selection guide from deployed agents.
|
|
1557
|
-
|
|
1558
|
-
Creates a mapping of task types to appropriate agents based on their
|
|
1559
|
-
descriptions and capabilities.
|
|
1560
|
-
"""
|
|
1561
|
-
guide = ""
|
|
439
|
+
self.logger.warning(f"❌ Failed to initialize output style manager: {e}")
|
|
1562
440
|
|
|
1563
|
-
|
|
1564
|
-
|
|
441
|
+
def _log_output_style_status(self) -> None:
|
|
442
|
+
"""Log output style status information."""
|
|
443
|
+
if not self.output_style_manager:
|
|
444
|
+
return
|
|
1565
445
|
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
446
|
+
claude_version = self.output_style_manager.claude_version
|
|
447
|
+
if claude_version:
|
|
448
|
+
self.logger.info(f"Claude Code version detected: {claude_version}")
|
|
1569
449
|
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
f"{
|
|
1584
|
-
)
|
|
1585
|
-
if "documentation" in desc_lower:
|
|
1586
|
-
selection_map["Documentation"] = (
|
|
1587
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1588
|
-
)
|
|
1589
|
-
if "security" in desc_lower or "sast" in desc_lower:
|
|
1590
|
-
selection_map["Security operations"] = (
|
|
1591
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1592
|
-
)
|
|
1593
|
-
if (
|
|
1594
|
-
"deployment" in desc_lower
|
|
1595
|
-
or "infrastructure" in desc_lower
|
|
1596
|
-
or "ops" in agent_id
|
|
1597
|
-
):
|
|
1598
|
-
selection_map["Deployment/infrastructure"] = (
|
|
1599
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1600
|
-
)
|
|
1601
|
-
if "data" in desc_lower and (
|
|
1602
|
-
"pipeline" in desc_lower or "etl" in desc_lower
|
|
1603
|
-
):
|
|
1604
|
-
selection_map["Data pipeline/ETL"] = (
|
|
1605
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1606
|
-
)
|
|
1607
|
-
if "git" in desc_lower or "version control" in desc_lower:
|
|
1608
|
-
selection_map["Version control"] = (
|
|
1609
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1610
|
-
)
|
|
1611
|
-
if "ticket" in desc_lower or "epic" in desc_lower:
|
|
1612
|
-
selection_map["Ticket/issue management"] = (
|
|
1613
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
1614
|
-
)
|
|
1615
|
-
if "browser" in desc_lower or "e2e" in desc_lower:
|
|
1616
|
-
selection_map["Browser/E2E testing"] = (
|
|
1617
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
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"
|
|
1618
464
|
)
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
f"{agent['display_name']} (`{agent_id}`)"
|
|
465
|
+
self.logger.info(
|
|
466
|
+
"📝 Output style will be injected into framework instructions"
|
|
1622
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")
|
|
1623
471
|
|
|
1624
|
-
|
|
1625
|
-
selection_map["PM questions"] = "Answer directly (only exception)"
|
|
472
|
+
# === Logging Methods ===
|
|
1626
473
|
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
474
|
+
def _log_system_prompt(self) -> None:
|
|
475
|
+
"""Log the system prompt if LogManager is available."""
|
|
476
|
+
try:
|
|
477
|
+
from .log_manager import get_log_manager
|
|
1630
478
|
|
|
1631
|
-
|
|
479
|
+
log_manager = get_log_manager()
|
|
480
|
+
except ImportError:
|
|
481
|
+
return
|
|
1632
482
|
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
483
|
+
try:
|
|
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
|
+
}
|
|
1636
497
|
|
|
1637
|
-
|
|
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)
|
|
1638
505
|
|
|
1639
|
-
|
|
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)
|
|
513
|
+
)
|
|
1640
514
|
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
- **Documentation** (`documentation-agent`): Documentation creation and maintenance
|
|
1645
|
-
- **Security** (`security-agent`): Security analysis and protection
|
|
1646
|
-
- **Data Engineer** (`data-engineer`): Data management and pipelines
|
|
1647
|
-
- **Ops** (`ops-agent`): Deployment and operations
|
|
1648
|
-
- **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}")
|
|
1649
518
|
|
|
1650
|
-
|
|
1651
|
-
"""
|
|
519
|
+
# === Agent Registry Methods (backward compatibility) ===
|
|
1652
520
|
|
|
1653
|
-
def
|
|
1654
|
-
"""Format minimal framework instructions when full framework not available."""
|
|
1655
|
-
return """
|
|
1656
|
-
# Claude PM Framework Instructions
|
|
1657
|
-
|
|
1658
|
-
You are operating within a Claude PM Framework deployment.
|
|
1659
|
-
|
|
1660
|
-
## Role
|
|
1661
|
-
You are a multi-agent orchestrator. Your primary responsibilities:
|
|
1662
|
-
- Delegate tasks to specialized agents via Task Tool
|
|
1663
|
-
- Coordinate multi-agent workflows
|
|
1664
|
-
- Extract TODO/BUG/FEATURE items for ticket creation
|
|
1665
|
-
- NEVER perform direct implementation work
|
|
1666
|
-
|
|
1667
|
-
## Core Agents
|
|
1668
|
-
- Documentation Agent - Documentation tasks
|
|
1669
|
-
- Engineer Agent - Code implementation
|
|
1670
|
-
- QA Agent - Testing and validation
|
|
1671
|
-
- Research Agent - Investigation and analysis
|
|
1672
|
-
- Version Control Agent - Git operations
|
|
1673
|
-
|
|
1674
|
-
## Important Rules
|
|
1675
|
-
1. Always delegate work via Task Tool
|
|
1676
|
-
2. Provide comprehensive context to agents
|
|
1677
|
-
3. Track all TODO/BUG/FEATURE items
|
|
1678
|
-
4. Maintain project visibility
|
|
1679
|
-
|
|
1680
|
-
---
|
|
1681
|
-
"""
|
|
1682
|
-
|
|
1683
|
-
def get_agent_list(self) -> list:
|
|
521
|
+
def get_agent_list(self) -> List[str]:
|
|
1684
522
|
"""Get list of available agents."""
|
|
1685
|
-
# First try agent registry
|
|
1686
523
|
if self.agent_registry:
|
|
1687
524
|
agents = self.agent_registry.list_agents()
|
|
1688
525
|
if agents:
|
|
1689
526
|
return list(agents.keys())
|
|
1690
|
-
|
|
1691
|
-
# Fallback to loaded content
|
|
1692
527
|
return list(self.framework_content["agents"].keys())
|
|
1693
528
|
|
|
1694
529
|
def get_agent_definition(self, agent_name: str) -> Optional[str]:
|
|
1695
530
|
"""Get specific agent definition."""
|
|
1696
|
-
# First try agent registry
|
|
1697
531
|
if self.agent_registry:
|
|
1698
532
|
definition = self.agent_registry.get_agent_definition(agent_name)
|
|
1699
533
|
if definition:
|
|
1700
534
|
return definition
|
|
1701
|
-
|
|
1702
|
-
# Fallback to loaded content
|
|
1703
535
|
return self.framework_content["agents"].get(agent_name)
|
|
1704
536
|
|
|
1705
|
-
def get_agent_hierarchy(self) -> Dict[str,
|
|
537
|
+
def get_agent_hierarchy(self) -> Dict[str, List]:
|
|
1706
538
|
"""Get agent hierarchy from registry."""
|
|
1707
539
|
if self.agent_registry:
|
|
1708
540
|
return self.agent_registry.get_agent_hierarchy()
|