claude-mpm 3.9.11__py3-none-any.whl → 4.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +2 -2
- claude_mpm/__main__.py +3 -2
- claude_mpm/agents/__init__.py +85 -79
- claude_mpm/agents/agent_loader.py +464 -1003
- claude_mpm/agents/agent_loader_integration.py +45 -45
- claude_mpm/agents/agents_metadata.py +29 -30
- claude_mpm/agents/async_agent_loader.py +156 -138
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/base_agent_loader.py +179 -151
- claude_mpm/agents/frontmatter_validator.py +229 -130
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +213 -147
- claude_mpm/agents/templates/__init__.py +13 -13
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +23 -11
- claude_mpm/agents/templates/engineer.json +22 -6
- claude_mpm/agents/templates/memory_manager.json +1 -1
- claude_mpm/agents/templates/ops.json +2 -2
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/refactoring_engineer.json +222 -0
- claude_mpm/agents/templates/research.json +20 -14
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/ticketing.json +2 -2
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +3 -1
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/__init__.py +79 -51
- claude_mpm/cli/__main__.py +3 -2
- claude_mpm/cli/commands/__init__.py +20 -20
- claude_mpm/cli/commands/agents.py +279 -247
- claude_mpm/cli/commands/aggregate.py +138 -157
- claude_mpm/cli/commands/cleanup.py +147 -147
- claude_mpm/cli/commands/config.py +93 -76
- claude_mpm/cli/commands/info.py +17 -16
- claude_mpm/cli/commands/mcp.py +140 -905
- claude_mpm/cli/commands/mcp_command_router.py +139 -0
- claude_mpm/cli/commands/mcp_config_commands.py +20 -0
- claude_mpm/cli/commands/mcp_install_commands.py +20 -0
- claude_mpm/cli/commands/mcp_server_commands.py +175 -0
- claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
- claude_mpm/cli/commands/memory.py +239 -203
- claude_mpm/cli/commands/monitor.py +330 -86
- claude_mpm/cli/commands/run.py +380 -429
- claude_mpm/cli/commands/run_config_checker.py +160 -0
- claude_mpm/cli/commands/socketio_monitor.py +235 -0
- claude_mpm/cli/commands/tickets.py +363 -220
- claude_mpm/cli/parser.py +24 -1156
- claude_mpm/cli/parsers/__init__.py +29 -0
- claude_mpm/cli/parsers/agents_parser.py +136 -0
- claude_mpm/cli/parsers/base_parser.py +331 -0
- claude_mpm/cli/parsers/config_parser.py +85 -0
- claude_mpm/cli/parsers/mcp_parser.py +152 -0
- claude_mpm/cli/parsers/memory_parser.py +138 -0
- claude_mpm/cli/parsers/monitor_parser.py +124 -0
- claude_mpm/cli/parsers/run_parser.py +147 -0
- claude_mpm/cli/parsers/tickets_parser.py +203 -0
- claude_mpm/cli/ticket_cli.py +7 -3
- claude_mpm/cli/utils.py +55 -37
- claude_mpm/cli_module/__init__.py +6 -6
- claude_mpm/cli_module/args.py +188 -140
- claude_mpm/cli_module/commands.py +79 -70
- claude_mpm/cli_module/migration_example.py +38 -60
- claude_mpm/config/__init__.py +32 -25
- claude_mpm/config/agent_config.py +151 -119
- claude_mpm/config/experimental_features.py +71 -73
- claude_mpm/config/paths.py +94 -208
- claude_mpm/config/socketio_config.py +84 -73
- claude_mpm/constants.py +35 -18
- claude_mpm/core/__init__.py +9 -6
- claude_mpm/core/agent_name_normalizer.py +68 -71
- claude_mpm/core/agent_registry.py +372 -521
- claude_mpm/core/agent_session_manager.py +74 -63
- claude_mpm/core/base_service.py +116 -87
- claude_mpm/core/cache.py +119 -153
- claude_mpm/core/claude_runner.py +425 -1120
- claude_mpm/core/config.py +263 -168
- claude_mpm/core/config_aliases.py +69 -61
- claude_mpm/core/config_constants.py +292 -0
- claude_mpm/core/constants.py +57 -99
- claude_mpm/core/container.py +211 -178
- claude_mpm/core/exceptions.py +233 -89
- claude_mpm/core/factories.py +92 -54
- claude_mpm/core/framework_loader.py +378 -220
- claude_mpm/core/hook_manager.py +198 -83
- claude_mpm/core/hook_performance_config.py +136 -0
- claude_mpm/core/injectable_service.py +61 -55
- claude_mpm/core/interactive_session.py +165 -155
- claude_mpm/core/interfaces.py +221 -195
- claude_mpm/core/lazy.py +96 -96
- claude_mpm/core/logger.py +133 -107
- claude_mpm/core/logging_config.py +185 -157
- claude_mpm/core/minimal_framework_loader.py +20 -15
- claude_mpm/core/mixins.py +30 -29
- claude_mpm/core/oneshot_session.py +215 -181
- claude_mpm/core/optimized_agent_loader.py +134 -138
- claude_mpm/core/optimized_startup.py +159 -157
- claude_mpm/core/pm_hook_interceptor.py +85 -72
- claude_mpm/core/service_registry.py +103 -101
- claude_mpm/core/session_manager.py +97 -87
- claude_mpm/core/socketio_pool.py +212 -158
- claude_mpm/core/tool_access_control.py +58 -51
- claude_mpm/core/types.py +46 -24
- claude_mpm/core/typing_utils.py +166 -82
- claude_mpm/core/unified_agent_registry.py +721 -0
- claude_mpm/core/unified_config.py +550 -0
- claude_mpm/core/unified_paths.py +549 -0
- claude_mpm/dashboard/index.html +1 -1
- claude_mpm/dashboard/open_dashboard.py +51 -17
- claude_mpm/dashboard/static/built/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/built/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/built/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/built/dashboard.js +2 -0
- claude_mpm/dashboard/static/built/socket-client.js +2 -0
- claude_mpm/dashboard/static/css/dashboard.css +27 -8
- claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/dist/dashboard.js +2 -0
- claude_mpm/dashboard/static/dist/socket-client.js +2 -0
- claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
- claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
- claude_mpm/dashboard/static/js/components/event-viewer.js +93 -72
- claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +110 -96
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
- claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
- claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
- claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
- claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
- claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
- claude_mpm/dashboard/static/js/dashboard.js +178 -453
- claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
- claude_mpm/dashboard/static/js/socket-client.js +133 -53
- claude_mpm/dashboard/templates/index.html +40 -50
- claude_mpm/experimental/cli_enhancements.py +60 -58
- claude_mpm/generators/__init__.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +75 -65
- claude_mpm/hooks/__init__.py +1 -1
- claude_mpm/hooks/base_hook.py +33 -28
- claude_mpm/hooks/claude_hooks/__init__.py +1 -1
- claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
- claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
- claude_mpm/hooks/memory_integration_hook.py +140 -100
- claude_mpm/hooks/tool_call_interceptor.py +89 -76
- claude_mpm/hooks/validation_hooks.py +57 -49
- claude_mpm/init.py +145 -121
- claude_mpm/models/__init__.py +9 -9
- claude_mpm/models/agent_definition.py +33 -23
- claude_mpm/models/agent_session.py +228 -200
- claude_mpm/scripts/__init__.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +192 -75
- claude_mpm/scripts/socketio_server_manager.py +328 -0
- claude_mpm/scripts/start_activity_logging.py +25 -22
- claude_mpm/services/__init__.py +68 -43
- claude_mpm/services/agent_capabilities_service.py +271 -0
- claude_mpm/services/agents/__init__.py +23 -32
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
- claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
- claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
- claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
- claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
- claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
- claude_mpm/services/agents/deployment/agent_validator.py +352 -0
- claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
- claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
- claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
- claude_mpm/services/agents/deployment/config/__init__.py +13 -0
- claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
- claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
- claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
- claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
- claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
- claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
- claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
- claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
- claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
- claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
- claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
- claude_mpm/services/agents/deployment/results/__init__.py +13 -0
- claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
- claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
- claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
- claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
- claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
- claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
- claude_mpm/services/agents/loading/__init__.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
- claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
- claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
- claude_mpm/services/agents/management/__init__.py +2 -2
- claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
- claude_mpm/services/agents/management/agent_management_service.py +209 -156
- claude_mpm/services/agents/memory/__init__.py +9 -6
- claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
- claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
- claude_mpm/services/agents/memory/analyzer.py +430 -0
- claude_mpm/services/agents/memory/content_manager.py +376 -0
- claude_mpm/services/agents/memory/template_generator.py +468 -0
- claude_mpm/services/agents/registry/__init__.py +7 -10
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
- claude_mpm/services/agents/registry/modification_tracker.py +351 -285
- claude_mpm/services/async_session_logger.py +187 -153
- claude_mpm/services/claude_session_logger.py +87 -72
- claude_mpm/services/command_handler_service.py +217 -0
- claude_mpm/services/communication/__init__.py +3 -2
- claude_mpm/services/core/__init__.py +50 -97
- claude_mpm/services/core/base.py +60 -53
- claude_mpm/services/core/interfaces/__init__.py +188 -0
- claude_mpm/services/core/interfaces/agent.py +351 -0
- claude_mpm/services/core/interfaces/communication.py +343 -0
- claude_mpm/services/core/interfaces/infrastructure.py +413 -0
- claude_mpm/services/core/interfaces/service.py +434 -0
- claude_mpm/services/core/interfaces.py +19 -944
- claude_mpm/services/event_aggregator.py +208 -170
- claude_mpm/services/exceptions.py +387 -308
- claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
- claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
- claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
- claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
- claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
- claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
- claude_mpm/services/hook_service.py +106 -114
- claude_mpm/services/infrastructure/__init__.py +7 -5
- claude_mpm/services/infrastructure/context_preservation.py +233 -199
- claude_mpm/services/infrastructure/daemon_manager.py +279 -0
- claude_mpm/services/infrastructure/logging.py +83 -76
- claude_mpm/services/infrastructure/monitoring.py +547 -404
- claude_mpm/services/mcp_gateway/__init__.py +30 -13
- claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
- claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
- claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
- claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
- claude_mpm/services/mcp_gateway/core/base.py +80 -67
- claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
- claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
- claude_mpm/services/mcp_gateway/main.py +287 -137
- claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
- claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
- claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
- claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
- claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
- claude_mpm/services/memory/__init__.py +2 -2
- claude_mpm/services/memory/builder.py +451 -362
- claude_mpm/services/memory/cache/__init__.py +2 -2
- claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
- claude_mpm/services/memory/cache/simple_cache.py +107 -93
- claude_mpm/services/memory/indexed_memory.py +195 -193
- claude_mpm/services/memory/optimizer.py +267 -234
- claude_mpm/services/memory/router.py +571 -263
- claude_mpm/services/memory_hook_service.py +237 -0
- claude_mpm/services/port_manager.py +575 -0
- claude_mpm/services/project/__init__.py +3 -3
- claude_mpm/services/project/analyzer.py +451 -305
- claude_mpm/services/project/registry.py +262 -240
- claude_mpm/services/recovery_manager.py +287 -231
- claude_mpm/services/response_tracker.py +87 -67
- claude_mpm/services/runner_configuration_service.py +587 -0
- claude_mpm/services/session_management_service.py +304 -0
- claude_mpm/services/socketio/__init__.py +4 -4
- claude_mpm/services/socketio/client_proxy.py +174 -0
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +44 -30
- claude_mpm/services/socketio/handlers/connection.py +166 -64
- claude_mpm/services/socketio/handlers/file.py +123 -108
- claude_mpm/services/socketio/handlers/git.py +607 -373
- claude_mpm/services/socketio/handlers/hook.py +185 -0
- claude_mpm/services/socketio/handlers/memory.py +4 -4
- claude_mpm/services/socketio/handlers/project.py +4 -4
- claude_mpm/services/socketio/handlers/registry.py +53 -38
- claude_mpm/services/socketio/server/__init__.py +18 -0
- claude_mpm/services/socketio/server/broadcaster.py +252 -0
- claude_mpm/services/socketio/server/core.py +399 -0
- claude_mpm/services/socketio/server/main.py +323 -0
- claude_mpm/services/socketio_client_manager.py +160 -133
- claude_mpm/services/socketio_server.py +36 -1885
- claude_mpm/services/subprocess_launcher_service.py +316 -0
- claude_mpm/services/system_instructions_service.py +258 -0
- claude_mpm/services/ticket_manager.py +19 -533
- claude_mpm/services/utility_service.py +285 -0
- claude_mpm/services/version_control/__init__.py +18 -21
- claude_mpm/services/version_control/branch_strategy.py +20 -10
- claude_mpm/services/version_control/conflict_resolution.py +37 -13
- claude_mpm/services/version_control/git_operations.py +52 -21
- claude_mpm/services/version_control/semantic_versioning.py +92 -53
- claude_mpm/services/version_control/version_parser.py +145 -125
- claude_mpm/services/version_service.py +270 -0
- claude_mpm/storage/__init__.py +2 -2
- claude_mpm/storage/state_storage.py +177 -181
- claude_mpm/ticket_wrapper.py +2 -2
- claude_mpm/utils/__init__.py +2 -2
- claude_mpm/utils/agent_dependency_loader.py +453 -243
- claude_mpm/utils/config_manager.py +157 -118
- claude_mpm/utils/console.py +1 -1
- claude_mpm/utils/dependency_cache.py +102 -107
- claude_mpm/utils/dependency_manager.py +52 -47
- claude_mpm/utils/dependency_strategies.py +131 -96
- claude_mpm/utils/environment_context.py +110 -102
- claude_mpm/utils/error_handler.py +75 -55
- claude_mpm/utils/file_utils.py +80 -67
- claude_mpm/utils/framework_detection.py +12 -11
- claude_mpm/utils/import_migration_example.py +12 -60
- claude_mpm/utils/imports.py +48 -45
- claude_mpm/utils/path_operations.py +100 -93
- claude_mpm/utils/robust_installer.py +172 -164
- claude_mpm/utils/session_logging.py +30 -23
- claude_mpm/utils/subprocess_utils.py +99 -61
- claude_mpm/validation/__init__.py +1 -1
- claude_mpm/validation/agent_validator.py +151 -111
- claude_mpm/validation/frontmatter_validator.py +92 -71
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/METADATA +90 -22
- claude_mpm-4.0.4.dist-info/RECORD +417 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/licenses/LICENSE +1 -1
- claude_mpm/cli/commands/run_guarded.py +0 -511
- claude_mpm/config/memory_guardian_config.py +0 -325
- claude_mpm/config/memory_guardian_yaml.py +0 -335
- claude_mpm/core/config_paths.py +0 -150
- claude_mpm/core/memory_aware_runner.py +0 -353
- claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
- claude_mpm/deployment_paths.py +0 -261
- claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
- claude_mpm/models/state_models.py +0 -433
- claude_mpm/services/agent/__init__.py +0 -24
- claude_mpm/services/agent/deployment.py +0 -2548
- claude_mpm/services/agent/management.py +0 -598
- claude_mpm/services/agent/registry.py +0 -813
- claude_mpm/services/agents/registry/agent_registry.py +0 -813
- claude_mpm/services/communication/socketio.py +0 -1935
- claude_mpm/services/communication/websocket.py +0 -479
- claude_mpm/services/framework_claude_md_generator.py +0 -624
- claude_mpm/services/health_monitor.py +0 -893
- claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
- claude_mpm/services/infrastructure/health_monitor.py +0 -775
- claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
- claude_mpm/services/infrastructure/memory_guardian.py +0 -944
- claude_mpm/services/infrastructure/restart_protection.py +0 -642
- claude_mpm/services/infrastructure/state_manager.py +0 -774
- claude_mpm/services/mcp_gateway/manager.py +0 -334
- claude_mpm/services/optimized_hook_service.py +0 -542
- claude_mpm/services/project_analyzer.py +0 -864
- claude_mpm/services/project_registry.py +0 -608
- claude_mpm/services/standalone_socketio_server.py +0 -1300
- claude_mpm/services/ticket_manager_di.py +0 -318
- claude_mpm/services/ticketing_service_original.py +0 -510
- claude_mpm/utils/paths.py +0 -395
- claude_mpm/utils/platform_memory.py +0 -524
- claude_mpm-3.9.11.dist-info/RECORD +0 -306
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/top_level.txt +0 -0
| @@ -15,18 +15,18 @@ Key Features: | |
| 15 15 | 
             
            - Dynamic prompt templates based on task complexity
         | 
| 16 16 |  | 
| 17 17 | 
             
            Usage:
         | 
| 18 | 
            -
                from  | 
| 19 | 
            -
             | 
| 18 | 
            +
                from claude_mpm.agents.base_agent_loader import prepend_base_instructions
         | 
| 19 | 
            +
             | 
| 20 20 | 
             
                # Get agent prompt with base instructions prepended
         | 
| 21 | 
            -
                full_prompt = prepend_base_instructions( | 
| 21 | 
            +
                full_prompt = prepend_base_instructions(get_agent_prompt("documentation-agent"))
         | 
| 22 22 | 
             
            """
         | 
| 23 23 |  | 
| 24 24 | 
             
            import json
         | 
| 25 25 | 
             
            import logging
         | 
| 26 26 | 
             
            import os
         | 
| 27 | 
            -
            from pathlib import Path
         | 
| 28 | 
            -
            from typing import Optional, Dict, Any
         | 
| 29 27 | 
             
            from enum import Enum
         | 
| 28 | 
            +
            from pathlib import Path
         | 
| 29 | 
            +
            from typing import Any, Dict, Optional
         | 
| 30 30 |  | 
| 31 31 | 
             
            from claude_mpm.services.memory.cache.shared_prompt_cache import SharedPromptCache
         | 
| 32 32 |  | 
| @@ -36,14 +36,16 @@ logger = logging.getLogger(__name__) | |
| 36 36 | 
             
            # Cache key for base agent instructions
         | 
| 37 37 | 
             
            BASE_AGENT_CACHE_KEY = "base_agent:instructions"
         | 
| 38 38 |  | 
| 39 | 
            +
             | 
| 39 40 | 
             
            def _get_base_agent_file() -> Path:
         | 
| 40 41 | 
             
                """Get the base agent file path."""
         | 
| 41 42 | 
             
                # Check if we're running from a wheel installation
         | 
| 42 43 | 
             
                try:
         | 
| 43 44 | 
             
                    import claude_mpm
         | 
| 45 | 
            +
             | 
| 44 46 | 
             
                    package_path = Path(claude_mpm.__file__).parent
         | 
| 45 47 | 
             
                    path_str = str(package_path.resolve())
         | 
| 46 | 
            -
                    if  | 
| 48 | 
            +
                    if "site-packages" in path_str or "dist-packages" in path_str:
         | 
| 47 49 | 
             
                        # For wheel installations, check data directory
         | 
| 48 50 | 
             
                        data_base_agent = package_path / "data" / "agents" / "base_agent.json"
         | 
| 49 51 | 
             
                        if data_base_agent.exists():
         | 
| @@ -51,13 +53,13 @@ def _get_base_agent_file() -> Path: | |
| 51 53 | 
             
                            return data_base_agent
         | 
| 52 54 | 
             
                except Exception:
         | 
| 53 55 | 
             
                    pass
         | 
| 54 | 
            -
             | 
| 56 | 
            +
             | 
| 55 57 | 
             
                # Use the base_agent.json in the agents directory
         | 
| 56 58 | 
             
                base_agent_path = Path(__file__).parent / "base_agent.json"
         | 
| 57 59 | 
             
                if base_agent_path.exists():
         | 
| 58 60 | 
             
                    logger.debug(f"Using base agent template: {base_agent_path}")
         | 
| 59 61 | 
             
                    return base_agent_path
         | 
| 60 | 
            -
             | 
| 62 | 
            +
             | 
| 61 63 | 
             
                # Fallback error
         | 
| 62 64 | 
             
                logger.error("Base agent template file not found")
         | 
| 63 65 | 
             
                raise FileNotFoundError("base_agent.json not found in agents directory")
         | 
| @@ -69,9 +71,10 @@ BASE_AGENT_FILE = _get_base_agent_file() | |
| 69 71 |  | 
| 70 72 | 
             
            class PromptTemplate(Enum):
         | 
| 71 73 | 
             
                """Dynamic prompt template levels."""
         | 
| 72 | 
            -
             | 
| 74 | 
            +
             | 
| 75 | 
            +
                MINIMAL = "MINIMAL"  # Core instructions only (~300 chars)
         | 
| 73 76 | 
             
                STANDARD = "STANDARD"  # Core + context + basic integration (~700 chars)
         | 
| 74 | 
            -
                FULL = "FULL" | 
| 77 | 
            +
                FULL = "FULL"  # All sections including escalation (~1500 chars)
         | 
| 75 78 |  | 
| 76 79 |  | 
| 77 80 | 
             
            # Template section definitions
         | 
| @@ -79,72 +82,60 @@ class PromptTemplate(Enum): | |
| 79 82 | 
             
            TEMPLATE_SECTIONS = {
         | 
| 80 83 | 
             
                "core_principles": {
         | 
| 81 84 | 
             
                    "templates": ["MINIMAL", "STANDARD", "FULL"],
         | 
| 82 | 
            -
                    "content": "Core Agent Principles"
         | 
| 85 | 
            +
                    "content": "Core Agent Principles",
         | 
| 83 86 | 
             
                },
         | 
| 84 87 | 
             
                "communication_standards": {
         | 
| 85 88 | 
             
                    "templates": ["MINIMAL", "STANDARD", "FULL"],
         | 
| 86 | 
            -
                    "content": "Communication Standards"
         | 
| 89 | 
            +
                    "content": "Communication Standards",
         | 
| 87 90 | 
             
                },
         | 
| 88 91 | 
             
                "test_protocols": {
         | 
| 89 92 | 
             
                    "templates": ["FULL"],  # Moved to FULL only - not needed for most tasks
         | 
| 90 | 
            -
                    "content": "Test Response Protocol"
         | 
| 93 | 
            +
                    "content": "Test Response Protocol",
         | 
| 91 94 | 
             
                },
         | 
| 92 95 | 
             
                "reporting_requirements": {
         | 
| 93 96 | 
             
                    "templates": ["STANDARD", "FULL"],
         | 
| 94 | 
            -
                    "content": "Reporting Requirements"
         | 
| 95 | 
            -
                },
         | 
| 96 | 
            -
                "error_handling": {
         | 
| 97 | 
            -
                    "templates": ["STANDARD", "FULL"],
         | 
| 98 | 
            -
                    "content": "Error Handling"
         | 
| 99 | 
            -
                },
         | 
| 100 | 
            -
                "security_awareness": {
         | 
| 101 | 
            -
                    "templates": ["FULL"],
         | 
| 102 | 
            -
                    "content": "Security Awareness"
         | 
| 97 | 
            +
                    "content": "Reporting Requirements",
         | 
| 103 98 | 
             
                },
         | 
| 99 | 
            +
                "error_handling": {"templates": ["STANDARD", "FULL"], "content": "Error Handling"},
         | 
| 100 | 
            +
                "security_awareness": {"templates": ["FULL"], "content": "Security Awareness"},
         | 
| 104 101 | 
             
                "temporal_context": {
         | 
| 105 102 | 
             
                    "templates": ["FULL"],  # Moved to FULL - not essential for STANDARD
         | 
| 106 | 
            -
                    "content": "Temporal Context Integration"
         | 
| 107 | 
            -
                },
         | 
| 108 | 
            -
                "quality_standards": {
         | 
| 109 | 
            -
                    "templates": ["FULL"],
         | 
| 110 | 
            -
                    "content": "Quality Standards"
         | 
| 103 | 
            +
                    "content": "Temporal Context Integration",
         | 
| 111 104 | 
             
                },
         | 
| 105 | 
            +
                "quality_standards": {"templates": ["FULL"], "content": "Quality Standards"},
         | 
| 112 106 | 
             
                "tool_usage": {
         | 
| 113 107 | 
             
                    "templates": ["FULL"],  # Moved to FULL - agent-specific guidance suffices
         | 
| 114 | 
            -
                    "content": "Tool Usage Guidelines"
         | 
| 108 | 
            +
                    "content": "Tool Usage Guidelines",
         | 
| 115 109 | 
             
                },
         | 
| 116 110 | 
             
                "collaboration_protocols": {
         | 
| 117 111 | 
             
                    "templates": ["STANDARD", "FULL"],  # Keep for STANDARD - essential
         | 
| 118 | 
            -
                    "content": "Collaboration Protocols"
         | 
| 112 | 
            +
                    "content": "Collaboration Protocols",
         | 
| 119 113 | 
             
                },
         | 
| 120 114 | 
             
                "cross_agent_dependencies": {
         | 
| 121 115 | 
             
                    "templates": ["FULL"],  # Only needed for complex multi-agent tasks
         | 
| 122 | 
            -
                    "content": "Cross-Agent Dependencies"
         | 
| 116 | 
            +
                    "content": "Cross-Agent Dependencies",
         | 
| 123 117 | 
             
                },
         | 
| 124 118 | 
             
                "performance_optimization": {
         | 
| 125 119 | 
             
                    "templates": ["FULL"],
         | 
| 126 | 
            -
                    "content": "Performance Optimization"
         | 
| 127 | 
            -
                },
         | 
| 128 | 
            -
                "escalation_triggers": {
         | 
| 129 | 
            -
                    "templates": ["FULL"],
         | 
| 130 | 
            -
                    "content": "Escalation Triggers"
         | 
| 120 | 
            +
                    "content": "Performance Optimization",
         | 
| 131 121 | 
             
                },
         | 
| 122 | 
            +
                "escalation_triggers": {"templates": ["FULL"], "content": "Escalation Triggers"},
         | 
| 132 123 | 
             
                "output_formatting": {
         | 
| 133 124 | 
             
                    "templates": ["FULL"],  # Moved to FULL - basic formatting in STANDARD suffices
         | 
| 134 | 
            -
                    "content": "Output Formatting Standards"
         | 
| 125 | 
            +
                    "content": "Output Formatting Standards",
         | 
| 135 126 | 
             
                },
         | 
| 136 127 | 
             
                "framework_integration": {
         | 
| 137 128 | 
             
                    "templates": ["FULL"],
         | 
| 138 | 
            -
                    "content": "Framework Integration"
         | 
| 129 | 
            +
                    "content": "Framework Integration",
         | 
| 139 130 | 
             
                },
         | 
| 140 131 | 
             
                "constraints": {
         | 
| 141 132 | 
             
                    "templates": ["MINIMAL", "STANDARD", "FULL"],
         | 
| 142 | 
            -
                    "content": "Universal Constraints"
         | 
| 133 | 
            +
                    "content": "Universal Constraints",
         | 
| 143 134 | 
             
                },
         | 
| 144 135 | 
             
                "success_criteria": {
         | 
| 145 136 | 
             
                    "templates": ["FULL"],  # Moved to FULL - implicit for simpler tasks
         | 
| 146 | 
            -
                    "content": "Success Criteria"
         | 
| 147 | 
            -
                }
         | 
| 137 | 
            +
                    "content": "Success Criteria",
         | 
| 138 | 
            +
                },
         | 
| 148 139 | 
             
            }
         | 
| 149 140 |  | 
| 150 141 |  | 
| @@ -152,68 +143,81 @@ def load_base_agent_instructions(force_reload: bool = False) -> Optional[str]: | |
| 152 143 | 
             
                """
         | 
| 153 144 | 
             
                Load base agent instructions from base_agent.json with caching.
         | 
| 154 145 | 
             
                Conditionally includes test-mode instructions based on CLAUDE_PM_TEST_MODE.
         | 
| 155 | 
            -
             | 
| 146 | 
            +
             | 
| 156 147 | 
             
                Args:
         | 
| 157 148 | 
             
                    force_reload: Force reload from file, bypassing cache
         | 
| 158 | 
            -
             | 
| 149 | 
            +
             | 
| 159 150 | 
             
                Returns:
         | 
| 160 151 | 
             
                    str: Base agent instructions content, or None if file not found
         | 
| 161 152 | 
             
                """
         | 
| 162 153 | 
             
                try:
         | 
| 163 154 | 
             
                    # Check if we're in test mode
         | 
| 164 | 
            -
                    test_mode = os.environ.get( | 
| 165 | 
            -
             | 
| 155 | 
            +
                    test_mode = os.environ.get("CLAUDE_PM_TEST_MODE", "").lower() in [
         | 
| 156 | 
            +
                        "true",
         | 
| 157 | 
            +
                        "1",
         | 
| 158 | 
            +
                        "yes",
         | 
| 159 | 
            +
                    ]
         | 
| 160 | 
            +
             | 
| 166 161 | 
             
                    # Get cache instance
         | 
| 167 162 | 
             
                    cache = SharedPromptCache.get_instance()
         | 
| 168 | 
            -
             | 
| 163 | 
            +
             | 
| 169 164 | 
             
                    # Different cache keys for test mode vs normal mode
         | 
| 170 165 | 
             
                    cache_key = f"{BASE_AGENT_CACHE_KEY}:{'test' if test_mode else 'normal'}"
         | 
| 171 | 
            -
             | 
| 166 | 
            +
             | 
| 172 167 | 
             
                    # Check cache first (unless force reload)
         | 
| 173 168 | 
             
                    if not force_reload:
         | 
| 174 169 | 
             
                        cached_content = cache.get(cache_key)
         | 
| 175 170 | 
             
                        if cached_content is not None:
         | 
| 176 | 
            -
                            logger.debug( | 
| 171 | 
            +
                            logger.debug(
         | 
| 172 | 
            +
                                f"Base agent instructions loaded from cache (test_mode={test_mode})"
         | 
| 173 | 
            +
                            )
         | 
| 177 174 | 
             
                            return str(cached_content)
         | 
| 178 | 
            -
             | 
| 175 | 
            +
             | 
| 179 176 | 
             
                    # Get fresh base agent file path
         | 
| 180 177 | 
             
                    base_agent_file = _get_base_agent_file()
         | 
| 181 | 
            -
             | 
| 178 | 
            +
             | 
| 182 179 | 
             
                    # Load from file
         | 
| 183 180 | 
             
                    if not base_agent_file.exists():
         | 
| 184 181 | 
             
                        logger.warning(f"Base agent instructions file not found: {base_agent_file}")
         | 
| 185 182 | 
             
                        return None
         | 
| 186 | 
            -
             | 
| 183 | 
            +
             | 
| 187 184 | 
             
                    logger.debug(f"Loading base agent instructions from: {base_agent_file}")
         | 
| 188 | 
            -
             | 
| 185 | 
            +
             | 
| 189 186 | 
             
                    # Load JSON and extract instructions
         | 
| 190 | 
            -
                    with open(base_agent_file,  | 
| 187 | 
            +
                    with open(base_agent_file, "r", encoding="utf-8") as f:
         | 
| 191 188 | 
             
                        base_agent_data = json.load(f)
         | 
| 192 | 
            -
             | 
| 189 | 
            +
             | 
| 193 190 | 
             
                    # Extract instructions from the JSON structure
         | 
| 194 | 
            -
                    if  | 
| 195 | 
            -
                         | 
| 191 | 
            +
                    if (
         | 
| 192 | 
            +
                        "narrative_fields" in base_agent_data
         | 
| 193 | 
            +
                        and "instructions" in base_agent_data["narrative_fields"]
         | 
| 194 | 
            +
                    ):
         | 
| 195 | 
            +
                        content = base_agent_data["narrative_fields"]["instructions"]
         | 
| 196 196 | 
             
                    else:
         | 
| 197 197 | 
             
                        # Fallback for older format
         | 
| 198 | 
            -
                        content = base_agent_data.get( | 
| 199 | 
            -
             | 
| 198 | 
            +
                        content = base_agent_data.get("instructions", "")
         | 
| 199 | 
            +
             | 
| 200 200 | 
             
                    if not content:
         | 
| 201 201 | 
             
                        logger.error("No instructions found in base agent JSON")
         | 
| 202 202 | 
             
                        return None
         | 
| 203 | 
            -
             | 
| 203 | 
            +
             | 
| 204 204 | 
             
                    # If NOT in test mode, remove test-specific instructions to save context
         | 
| 205 205 | 
             
                    if not test_mode:
         | 
| 206 206 | 
             
                        content = _remove_test_mode_instructions(content)
         | 
| 207 207 | 
             
                        logger.debug("Test-mode instructions removed (not in test mode)")
         | 
| 208 208 | 
             
                    else:
         | 
| 209 | 
            -
                        logger.info( | 
| 210 | 
            -
             | 
| 209 | 
            +
                        logger.info(
         | 
| 210 | 
            +
                            "Test-mode instructions included (CLAUDE_PM_TEST_MODE is enabled)"
         | 
| 211 | 
            +
                        )
         | 
| 212 | 
            +
             | 
| 211 213 | 
             
                    # Cache the content with 1 hour TTL
         | 
| 212 214 | 
             
                    cache.set(cache_key, content, ttl=3600)
         | 
| 213 | 
            -
                    logger.debug( | 
| 214 | 
            -
             | 
| 215 | 
            +
                    logger.debug(
         | 
| 216 | 
            +
                        f"Base agent instructions cached successfully (test_mode={test_mode})"
         | 
| 217 | 
            +
                    )
         | 
| 218 | 
            +
             | 
| 215 219 | 
             
                    return content
         | 
| 216 | 
            -
             | 
| 220 | 
            +
             | 
| 217 221 | 
             
                except Exception as e:
         | 
| 218 222 | 
             
                    logger.error(f"Error loading base agent instructions: {e}")
         | 
| 219 223 | 
             
                    return None
         | 
| @@ -222,36 +226,39 @@ def load_base_agent_instructions(force_reload: bool = False) -> Optional[str]: | |
| 222 226 | 
             
            def _remove_test_mode_instructions(content: str) -> str:
         | 
| 223 227 | 
             
                """
         | 
| 224 228 | 
             
                Remove test-mode specific instructions from base agent content.
         | 
| 225 | 
            -
             | 
| 229 | 
            +
             | 
| 226 230 | 
             
                This removes the "Standard Test Response Protocol"
         | 
| 227 231 | 
             
                sections to save context when not in test mode.
         | 
| 228 | 
            -
             | 
| 232 | 
            +
             | 
| 229 233 | 
             
                Args:
         | 
| 230 234 | 
             
                    content: Full base agent instructions content
         | 
| 231 | 
            -
             | 
| 235 | 
            +
             | 
| 232 236 | 
             
                Returns:
         | 
| 233 237 | 
             
                    str: Content with test-mode instructions removed
         | 
| 234 238 | 
             
                """
         | 
| 235 | 
            -
                lines = content.split( | 
| 239 | 
            +
                lines = content.split("\n")
         | 
| 236 240 | 
             
                filtered_lines = []
         | 
| 237 241 | 
             
                skip_section = False
         | 
| 238 | 
            -
             | 
| 242 | 
            +
             | 
| 239 243 | 
             
                i = 0
         | 
| 240 244 | 
             
                while i < len(lines):
         | 
| 241 245 | 
             
                    line = lines[i]
         | 
| 242 | 
            -
             | 
| 246 | 
            +
             | 
| 243 247 | 
             
                    # Check if we're entering the test response protocol section
         | 
| 244 | 
            -
                    if line.strip() ==  | 
| 248 | 
            +
                    if line.strip() == "## Standard Test Response Protocol":
         | 
| 245 249 | 
             
                        skip_section = True
         | 
| 246 250 | 
             
                        i += 1
         | 
| 247 251 | 
             
                        continue
         | 
| 248 | 
            -
             | 
| 252 | 
            +
             | 
| 249 253 | 
             
                    # Check if we're in the test section and need to continue skipping
         | 
| 250 254 | 
             
                    if skip_section:
         | 
| 251 255 | 
             
                        # Check if we've reached a section that's NOT part of test protocol
         | 
| 252 256 | 
             
                        # This includes any heading that's not a subsection of the test protocol
         | 
| 253 | 
            -
                        if ( | 
| 254 | 
            -
             | 
| 257 | 
            +
                        if (
         | 
| 258 | 
            +
                            line.startswith("####")
         | 
| 259 | 
            +
                            or line.startswith("###")
         | 
| 260 | 
            +
                            or line.startswith("##")
         | 
| 261 | 
            +
                        ) and "Standard Test Response Protocol" not in line:
         | 
| 255 262 | 
             
                            skip_section = False
         | 
| 256 263 | 
             
                            # Don't skip this line - it's the start of a new section
         | 
| 257 264 | 
             
                            filtered_lines.append(line)
         | 
| @@ -260,45 +267,47 @@ def _remove_test_mode_instructions(content: str) -> str: | |
| 260 267 | 
             
                        # Skip this line as we're still in test section
         | 
| 261 268 | 
             
                        i += 1
         | 
| 262 269 | 
             
                        continue
         | 
| 263 | 
            -
             | 
| 270 | 
            +
             | 
| 264 271 | 
             
                    # Not in test section, keep the line
         | 
| 265 272 | 
             
                    filtered_lines.append(line)
         | 
| 266 273 | 
             
                    i += 1
         | 
| 267 | 
            -
             | 
| 274 | 
            +
             | 
| 268 275 | 
             
                # Join back and clean up extra blank lines
         | 
| 269 | 
            -
                result =  | 
| 270 | 
            -
             | 
| 276 | 
            +
                result = "\n".join(filtered_lines)
         | 
| 277 | 
            +
             | 
| 271 278 | 
             
                # Replace multiple consecutive newlines with double newlines
         | 
| 272 | 
            -
                while  | 
| 273 | 
            -
                    result = result.replace( | 
| 274 | 
            -
             | 
| 279 | 
            +
                while "\n\n\n" in result:
         | 
| 280 | 
            +
                    result = result.replace("\n\n\n", "\n\n")
         | 
| 281 | 
            +
             | 
| 275 282 | 
             
                return result.strip()
         | 
| 276 283 |  | 
| 277 284 |  | 
| 278 285 | 
             
            def _build_dynamic_prompt(content: str, template: PromptTemplate) -> str:
         | 
| 279 286 | 
             
                """
         | 
| 280 287 | 
             
                Build a dynamic prompt based on the template level.
         | 
| 281 | 
            -
             | 
| 288 | 
            +
             | 
| 282 289 | 
             
                Args:
         | 
| 283 290 | 
             
                    content: Full base agent content
         | 
| 284 291 | 
             
                    template: Template level to use
         | 
| 285 | 
            -
             | 
| 292 | 
            +
             | 
| 286 293 | 
             
                Returns:
         | 
| 287 294 | 
             
                    str: Filtered content based on template
         | 
| 288 295 | 
             
                """
         | 
| 289 296 | 
             
                if template == PromptTemplate.FULL:
         | 
| 290 297 | 
             
                    # Return full content for FULL template
         | 
| 291 298 | 
             
                    return content
         | 
| 292 | 
            -
             | 
| 299 | 
            +
             | 
| 293 300 | 
             
                # Parse content into sections
         | 
| 294 301 | 
             
                sections = _parse_content_sections(content)
         | 
| 295 | 
            -
             | 
| 302 | 
            +
             | 
| 296 303 | 
             
                # Build prompt based on template sections
         | 
| 297 304 | 
             
                filtered_lines = []
         | 
| 298 305 | 
             
                filtered_lines.append("# Base Agent Instructions\n")
         | 
| 299 306 | 
             
                filtered_lines.append("## 🤖 Agent Framework Context\n")
         | 
| 300 | 
            -
                filtered_lines.append( | 
| 301 | 
            -
             | 
| 307 | 
            +
                filtered_lines.append(
         | 
| 308 | 
            +
                    "You are operating as a specialized agent within the Claude PM Framework. You have been delegated a specific task by the PM Orchestrator and must complete it according to your specialized role and authority.\n"
         | 
| 309 | 
            +
                )
         | 
| 310 | 
            +
             | 
| 302 311 | 
             
                # Add sections based on template
         | 
| 303 312 | 
             
                template_name = template.value
         | 
| 304 313 | 
             
                for section_key, section_config in TEMPLATE_SECTIONS.items():
         | 
| @@ -307,101 +316,111 @@ def _build_dynamic_prompt(content: str, template: PromptTemplate) -> str: | |
| 307 316 | 
             
                        assert isinstance(section_name, str), "Section name must be string"
         | 
| 308 317 | 
             
                        if section_name in sections:
         | 
| 309 318 | 
             
                            filtered_lines.append(sections[section_name])
         | 
| 310 | 
            -
             | 
| 319 | 
            +
             | 
| 311 320 | 
             
                # Clean up multiple newlines
         | 
| 312 | 
            -
                result =  | 
| 313 | 
            -
                while  | 
| 314 | 
            -
                    result = result.replace( | 
| 315 | 
            -
             | 
| 321 | 
            +
                result = "\n".join(filtered_lines)
         | 
| 322 | 
            +
                while "\n\n\n" in result:
         | 
| 323 | 
            +
                    result = result.replace("\n\n\n", "\n\n")
         | 
| 324 | 
            +
             | 
| 316 325 | 
             
                return result.strip()
         | 
| 317 326 |  | 
| 318 327 |  | 
| 319 328 | 
             
            def _parse_content_sections(content: str) -> Dict[str, str]:
         | 
| 320 329 | 
             
                """
         | 
| 321 330 | 
             
                Parse content into named sections.
         | 
| 322 | 
            -
             | 
| 331 | 
            +
             | 
| 323 332 | 
             
                Args:
         | 
| 324 333 | 
             
                    content: Full content to parse
         | 
| 325 | 
            -
             | 
| 334 | 
            +
             | 
| 326 335 | 
             
                Returns:
         | 
| 327 336 | 
             
                    Dict mapping section names to their content
         | 
| 328 337 | 
             
                """
         | 
| 329 338 | 
             
                sections = {}
         | 
| 330 339 | 
             
                current_section = None
         | 
| 331 340 | 
             
                current_content = []
         | 
| 332 | 
            -
             | 
| 333 | 
            -
                lines = content.split( | 
| 334 | 
            -
             | 
| 341 | 
            +
             | 
| 342 | 
            +
                lines = content.split("\n")
         | 
| 343 | 
            +
             | 
| 335 344 | 
             
                for line in lines:
         | 
| 336 345 | 
             
                    # Check if this is a section header
         | 
| 337 | 
            -
                    if line.startswith( | 
| 346 | 
            +
                    if line.startswith("### "):
         | 
| 338 347 | 
             
                        # Save previous section if exists
         | 
| 339 348 | 
             
                        if current_section:
         | 
| 340 | 
            -
                            sections[current_section] =  | 
| 349 | 
            +
                            sections[current_section] = "\n".join(current_content)
         | 
| 341 350 | 
             
                            current_content = []
         | 
| 342 | 
            -
             | 
| 351 | 
            +
             | 
| 343 352 | 
             
                        # Extract section name
         | 
| 344 353 | 
             
                        current_section = line[4:].strip()
         | 
| 345 354 | 
             
                        current_content.append(line)
         | 
| 346 | 
            -
             | 
| 347 | 
            -
                    elif line.startswith( | 
| 355 | 
            +
             | 
| 356 | 
            +
                    elif line.startswith("## ") and "Agent Framework Context" not in line:
         | 
| 348 357 | 
             
                        # Handle ## level sections (skip the main header)
         | 
| 349 358 | 
             
                        if current_section:
         | 
| 350 | 
            -
                            sections[current_section] =  | 
| 359 | 
            +
                            sections[current_section] = "\n".join(current_content)
         | 
| 351 360 | 
             
                            current_content = []
         | 
| 352 | 
            -
             | 
| 361 | 
            +
             | 
| 353 362 | 
             
                        current_section = line[3:].strip()
         | 
| 354 363 | 
             
                        current_content.append(line)
         | 
| 355 | 
            -
             | 
| 356 | 
            -
                    elif line.startswith( | 
| 364 | 
            +
             | 
| 365 | 
            +
                    elif line.startswith("#### "):
         | 
| 357 366 | 
             
                        # Handle #### level subsections
         | 
| 358 367 | 
             
                        if current_section:
         | 
| 359 368 | 
             
                            # Check for PM Orchestrator Integration vs PM Workflow Integration
         | 
| 360 369 | 
             
                            subsection_name = line[5:].strip()
         | 
| 361 | 
            -
                            if subsection_name in [ | 
| 370 | 
            +
                            if subsection_name in [
         | 
| 371 | 
            +
                                "PM Orchestrator Integration",
         | 
| 372 | 
            +
                                "PM Workflow Integration",
         | 
| 373 | 
            +
                            ]:
         | 
| 362 374 | 
             
                                # Merge these redundant sections under "Collaboration Protocols"
         | 
| 363 375 | 
             
                                if current_section != "Collaboration Protocols":
         | 
| 364 376 | 
             
                                    current_section = "PM Integration"
         | 
| 365 377 | 
             
                            current_content.append(line)
         | 
| 366 | 
            -
             | 
| 378 | 
            +
             | 
| 367 379 | 
             
                    elif current_section:
         | 
| 368 380 | 
             
                        current_content.append(line)
         | 
| 369 | 
            -
             | 
| 381 | 
            +
             | 
| 370 382 | 
             
                # Save final section
         | 
| 371 383 | 
             
                if current_section and current_content:
         | 
| 372 | 
            -
                    sections[current_section] =  | 
| 373 | 
            -
             | 
| 384 | 
            +
                    sections[current_section] = "\n".join(current_content)
         | 
| 385 | 
            +
             | 
| 374 386 | 
             
                # Merge redundant PM sections if both exist
         | 
| 375 | 
            -
                if  | 
| 387 | 
            +
                if (
         | 
| 388 | 
            +
                    "PM Orchestrator Integration" in sections
         | 
| 389 | 
            +
                    and "PM Workflow Integration" in sections
         | 
| 390 | 
            +
                ):
         | 
| 376 391 | 
             
                    # Combine into single PM Integration section
         | 
| 377 392 | 
             
                    sections["PM Integration"] = (
         | 
| 378 | 
            -
                        "#### PM Integration\n" | 
| 379 | 
            -
                        sections["PM Orchestrator Integration"] | 
| 380 | 
            -
                        " | 
| 381 | 
            -
                         | 
| 393 | 
            +
                        "#### PM Integration\n"
         | 
| 394 | 
            +
                        + sections["PM Orchestrator Integration"]
         | 
| 395 | 
            +
                        .replace("#### PM Orchestrator Integration", "")
         | 
| 396 | 
            +
                        .strip()
         | 
| 397 | 
            +
                        + "\n\n"
         | 
| 398 | 
            +
                        + sections["PM Workflow Integration"]
         | 
| 399 | 
            +
                        .replace("#### PM Workflow Integration", "")
         | 
| 400 | 
            +
                        .strip()
         | 
| 382 401 | 
             
                    )
         | 
| 383 402 | 
             
                    # Remove redundant sections
         | 
| 384 403 | 
             
                    del sections["PM Orchestrator Integration"]
         | 
| 385 404 | 
             
                    del sections["PM Workflow Integration"]
         | 
| 386 | 
            -
             | 
| 405 | 
            +
             | 
| 387 406 | 
             
                return sections
         | 
| 388 407 |  | 
| 389 408 |  | 
| 390 409 | 
             
            def prepend_base_instructions(
         | 
| 391 | 
            -
                agent_prompt: str, | 
| 410 | 
            +
                agent_prompt: str,
         | 
| 392 411 | 
             
                separator: str = "\n\n---\n\n",
         | 
| 393 412 | 
             
                template: Optional[PromptTemplate] = None,
         | 
| 394 | 
            -
                complexity_score: Optional[int] = None
         | 
| 413 | 
            +
                complexity_score: Optional[int] = None,
         | 
| 395 414 | 
             
            ) -> str:
         | 
| 396 415 | 
             
                """
         | 
| 397 416 | 
             
                Prepend base agent instructions to an agent-specific prompt.
         | 
| 398 | 
            -
             | 
| 417 | 
            +
             | 
| 399 418 | 
             
                Args:
         | 
| 400 419 | 
             
                    agent_prompt: The agent-specific prompt to prepend to
         | 
| 401 420 | 
             
                    separator: String to separate base instructions from agent prompt
         | 
| 402 421 | 
             
                    template: Optional template level to use (auto-selected if not provided)
         | 
| 403 422 | 
             
                    complexity_score: Optional complexity score for template selection
         | 
| 404 | 
            -
             | 
| 423 | 
            +
             | 
| 405 424 | 
             
                Returns:
         | 
| 406 425 | 
             
                    str: Combined prompt with base instructions prepended
         | 
| 407 426 | 
             
                """
         | 
| @@ -417,49 +436,59 @@ def prepend_base_instructions( | |
| 417 436 | 
             
                    else:
         | 
| 418 437 | 
             
                        # Default to STANDARD if no complexity info
         | 
| 419 438 | 
             
                        template = PromptTemplate.STANDARD
         | 
| 420 | 
            -
             | 
| 439 | 
            +
             | 
| 421 440 | 
             
                # Check if we're in test mode - always use FULL template for tests
         | 
| 422 | 
            -
                test_mode = os.environ.get( | 
| 441 | 
            +
                test_mode = os.environ.get("CLAUDE_PM_TEST_MODE", "").lower() in [
         | 
| 442 | 
            +
                    "true",
         | 
| 443 | 
            +
                    "1",
         | 
| 444 | 
            +
                    "yes",
         | 
| 445 | 
            +
                ]
         | 
| 423 446 | 
             
                if test_mode:
         | 
| 424 447 | 
             
                    template = PromptTemplate.FULL
         | 
| 425 | 
            -
             | 
| 448 | 
            +
             | 
| 426 449 | 
             
                # Get cache instance
         | 
| 427 450 | 
             
                cache = SharedPromptCache.get_instance()
         | 
| 428 | 
            -
             | 
| 451 | 
            +
             | 
| 429 452 | 
             
                # Different cache keys for different templates and test mode
         | 
| 430 | 
            -
                cache_key =  | 
| 431 | 
            -
             | 
| 453 | 
            +
                cache_key = (
         | 
| 454 | 
            +
                    f"{BASE_AGENT_CACHE_KEY}:{template.value}:{'test' if test_mode else 'normal'}"
         | 
| 455 | 
            +
                )
         | 
| 456 | 
            +
             | 
| 432 457 | 
             
                # Check cache first
         | 
| 433 458 | 
             
                cached_content = cache.get(cache_key)
         | 
| 434 459 | 
             
                if cached_content is not None:
         | 
| 435 | 
            -
                    logger.debug( | 
| 460 | 
            +
                    logger.debug(
         | 
| 461 | 
            +
                        f"Base agent instructions loaded from cache (template={template.value}, test_mode={test_mode})"
         | 
| 462 | 
            +
                    )
         | 
| 436 463 | 
             
                    base_instructions = cached_content
         | 
| 437 464 | 
             
                else:
         | 
| 438 465 | 
             
                    # Load full content
         | 
| 439 466 | 
             
                    full_content = load_base_agent_instructions()
         | 
| 440 | 
            -
             | 
| 467 | 
            +
             | 
| 441 468 | 
             
                    # If no base instructions, return original prompt
         | 
| 442 469 | 
             
                    if not full_content:
         | 
| 443 470 | 
             
                        logger.warning("No base instructions available, returning original prompt")
         | 
| 444 471 | 
             
                        return agent_prompt
         | 
| 445 | 
            -
             | 
| 472 | 
            +
             | 
| 446 473 | 
             
                    # Build dynamic prompt based on template
         | 
| 447 474 | 
             
                    base_instructions = _build_dynamic_prompt(full_content, template)
         | 
| 448 | 
            -
             | 
| 475 | 
            +
             | 
| 449 476 | 
             
                    # Cache the filtered content
         | 
| 450 477 | 
             
                    cache.set(cache_key, base_instructions, ttl=3600)
         | 
| 451 | 
            -
                    logger.debug( | 
| 452 | 
            -
             | 
| 478 | 
            +
                    logger.debug(
         | 
| 479 | 
            +
                        f"Dynamic base agent instructions cached (template={template.value})"
         | 
| 480 | 
            +
                    )
         | 
| 481 | 
            +
             | 
| 453 482 | 
             
                # Log template selection
         | 
| 454 483 | 
             
                if complexity_score is not None:
         | 
| 455 484 | 
             
                    logger.info(
         | 
| 456 485 | 
             
                        f"Using {template.value} prompt template "
         | 
| 457 486 | 
             
                        f"(complexity_score={complexity_score}, size={len(base_instructions)} chars)"
         | 
| 458 487 | 
             
                    )
         | 
| 459 | 
            -
             | 
| 488 | 
            +
             | 
| 460 489 | 
             
                # Combine base instructions with agent prompt
         | 
| 461 490 | 
             
                combined_prompt = f"{base_instructions}{separator}{agent_prompt}"
         | 
| 462 | 
            -
             | 
| 491 | 
            +
             | 
| 463 492 | 
             
                return combined_prompt
         | 
| 464 493 |  | 
| 465 494 |  | 
| @@ -469,14 +498,14 @@ def clear_base_agent_cache() -> None: | |
| 469 498 | 
             
                    cache = SharedPromptCache.get_instance()
         | 
| 470 499 | 
             
                    # Clear caches for all template levels and modes
         | 
| 471 500 | 
             
                    for template in PromptTemplate:
         | 
| 472 | 
            -
                        for mode in [ | 
| 501 | 
            +
                        for mode in ["normal", "test"]:
         | 
| 473 502 | 
             
                            cache_key = f"{BASE_AGENT_CACHE_KEY}:{template.value}:{mode}"
         | 
| 474 503 | 
             
                            cache.invalidate(cache_key)
         | 
| 475 | 
            -
             | 
| 504 | 
            +
             | 
| 476 505 | 
             
                    # Also clear the old-style caches for backward compatibility
         | 
| 477 506 | 
             
                    cache.invalidate(f"{BASE_AGENT_CACHE_KEY}:normal")
         | 
| 478 507 | 
             
                    cache.invalidate(f"{BASE_AGENT_CACHE_KEY}:test")
         | 
| 479 | 
            -
             | 
| 508 | 
            +
             | 
| 480 509 | 
             
                    logger.debug("Base agent cache cleared (all templates and modes)")
         | 
| 481 510 | 
             
                except Exception as e:
         | 
| 482 511 | 
             
                    logger.error(f"Error clearing base agent cache: {e}")
         | 
| @@ -490,7 +519,7 @@ def get_base_agent_path() -> Path: | |
| 490 519 | 
             
            def validate_base_agent_file() -> bool:
         | 
| 491 520 | 
             
                """
         | 
| 492 521 | 
             
                Validate that base agent file exists and is readable.
         | 
| 493 | 
            -
             | 
| 522 | 
            +
             | 
| 494 523 | 
             
                Returns:
         | 
| 495 524 | 
             
                    bool: True if file exists and is readable, False otherwise
         | 
| 496 525 | 
             
                """
         | 
| @@ -498,15 +527,15 @@ def validate_base_agent_file() -> bool: | |
| 498 527 | 
             
                    if not BASE_AGENT_FILE.exists():
         | 
| 499 528 | 
             
                        logger.error(f"Base agent file does not exist: {BASE_AGENT_FILE}")
         | 
| 500 529 | 
             
                        return False
         | 
| 501 | 
            -
             | 
| 530 | 
            +
             | 
| 502 531 | 
             
                    if not BASE_AGENT_FILE.is_file():
         | 
| 503 532 | 
             
                        logger.error(f"Base agent path is not a file: {BASE_AGENT_FILE}")
         | 
| 504 533 | 
             
                        return False
         | 
| 505 | 
            -
             | 
| 534 | 
            +
             | 
| 506 535 | 
             
                    # Try to read the file
         | 
| 507 | 
            -
                    BASE_AGENT_FILE.read_text(encoding= | 
| 536 | 
            +
                    BASE_AGENT_FILE.read_text(encoding="utf-8")
         | 
| 508 537 | 
             
                    return True
         | 
| 509 | 
            -
             | 
| 538 | 
            +
             | 
| 510 539 | 
             
                except Exception as e:
         | 
| 511 540 | 
             
                    logger.error(f"Base agent file validation failed: {e}")
         | 
| 512 541 | 
             
                    return False
         | 
| @@ -516,14 +545,13 @@ def validate_base_agent_file() -> bool: | |
| 516 545 | 
             
            if not validate_base_agent_file():
         | 
| 517 546 | 
             
                logger.warning("Base agent file validation failed during module import")
         | 
| 518 547 |  | 
| 519 | 
            -
             | 
| 520 548 | 
             
            # Export key components
         | 
| 521 549 | 
             
            __all__ = [
         | 
| 522 | 
            -
                 | 
| 523 | 
            -
                 | 
| 524 | 
            -
                 | 
| 525 | 
            -
                 | 
| 526 | 
            -
                 | 
| 527 | 
            -
                 | 
| 528 | 
            -
                 | 
| 529 | 
            -
            ]
         | 
| 550 | 
            +
                "prepend_base_instructions",
         | 
| 551 | 
            +
                "load_base_agent_instructions",
         | 
| 552 | 
            +
                "clear_base_agent_cache",
         | 
| 553 | 
            +
                "get_base_agent_path",
         | 
| 554 | 
            +
                "validate_base_agent_file",
         | 
| 555 | 
            +
                "PromptTemplate",
         | 
| 556 | 
            +
                "TEMPLATE_SECTIONS",
         | 
| 557 | 
            +
            ]
         |