claude-mpm 3.9.9__py3-none-any.whl → 4.0.3__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 +155 -0
- 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 +1 -1
- 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 +90 -49
- claude_mpm/cli/__main__.py +3 -2
- claude_mpm/cli/commands/__init__.py +21 -18
- 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 +143 -762
- 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 +203 -81
- 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 +305 -197
- claude_mpm/cli/parser.py +24 -1150
- 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 +104 -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 +217 -0
- claude_mpm/config/paths.py +94 -208
- claude_mpm/config/socketio_config.py +84 -73
- claude_mpm/constants.py +36 -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/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 +74 -70
- claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
- 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 +120 -54
- 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 +571 -0
- 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 +40 -23
- 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 +14 -21
- 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 +97 -93
- claude_mpm/services/mcp_gateway/main.py +307 -127
- claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +100 -101
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
- claude_mpm/services/mcp_gateway/server/__init__.py +4 -4
- claude_mpm/services/mcp_gateway/server/{mcp_server.py → mcp_gateway.py} +149 -153
- 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 +110 -121
- 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 +223 -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 +145 -65
- 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 +170 -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 +20 -534
- 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 +9 -0
- claude_mpm/storage/state_storage.py +552 -0
- 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.9.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +51 -2
- claude_mpm-4.0.3.dist-info/RECORD +402 -0
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
- claude_mpm/config/memory_guardian_config.py +0 -325
- claude_mpm/core/config_paths.py +0 -150
- 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/memory_guardian.py +0 -770
- claude_mpm/services/mcp_gateway/server/mcp_server_simple.py +0 -444
- 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.9.dist-info/RECORD +0 -293
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            from pathlib import Path
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            #!/usr/bin/env python3
         | 
| 2 4 | 
             
            """
         | 
| 3 5 | 
             
            Agent Management Service
         | 
| @@ -9,98 +11,106 @@ section extraction/updates, and version management. | |
| 9 11 | 
             
            Uses python-frontmatter and mistune for markdown parsing as recommended.
         | 
| 10 12 | 
             
            """
         | 
| 11 13 |  | 
| 14 | 
            +
            import logging
         | 
| 12 15 | 
             
            import os
         | 
| 13 16 | 
             
            import re
         | 
| 14 | 
            -
            import json
         | 
| 15 | 
            -
            import yaml
         | 
| 16 | 
            -
            import logging
         | 
| 17 | 
            -
            from pathlib import Path
         | 
| 18 | 
            -
            from typing import Dict, List, Optional, Tuple, Any
         | 
| 19 17 | 
             
            from datetime import datetime
         | 
| 18 | 
            +
            from typing import Any, Dict, List, Optional, Tuple
         | 
| 20 19 |  | 
| 21 20 | 
             
            import frontmatter
         | 
| 22 21 | 
             
            import mistune
         | 
| 22 | 
            +
            import yaml
         | 
| 23 23 |  | 
| 24 | 
            +
            from claude_mpm.core.unified_paths import get_path_manager
         | 
| 24 25 | 
             
            from claude_mpm.models.agent_definition import (
         | 
| 25 | 
            -
                AgentDefinition, | 
| 26 | 
            -
                 | 
| 26 | 
            +
                AgentDefinition,
         | 
| 27 | 
            +
                AgentMetadata,
         | 
| 28 | 
            +
                AgentPermissions,
         | 
| 29 | 
            +
                AgentSection,
         | 
| 30 | 
            +
                AgentType,
         | 
| 31 | 
            +
                AgentWorkflow,
         | 
| 27 32 | 
             
            )
         | 
| 28 | 
            -
            from ..deployment.agent_versioning import AgentVersionManager
         | 
| 29 33 | 
             
            from claude_mpm.services.memory.cache.shared_prompt_cache import SharedPromptCache
         | 
| 30 | 
            -
             | 
| 31 | 
            -
            from  | 
| 34 | 
            +
             | 
| 35 | 
            +
            from ..deployment.agent_versioning import AgentVersionManager
         | 
| 32 36 |  | 
| 33 37 | 
             
            logger = logging.getLogger(__name__)
         | 
| 34 38 |  | 
| 35 39 |  | 
| 36 40 | 
             
            class AgentManager:
         | 
| 37 41 | 
             
                """Manages agent definitions with CRUD operations and versioning."""
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                def __init__( | 
| 42 | 
            +
             | 
| 43 | 
            +
                def __init__(
         | 
| 44 | 
            +
                    self, framework_dir: Optional[Path] = None, project_dir: Optional[Path] = None
         | 
| 45 | 
            +
                ):
         | 
| 40 46 | 
             
                    """
         | 
| 41 47 | 
             
                    Initialize AgentManager.
         | 
| 42 | 
            -
             | 
| 48 | 
            +
             | 
| 43 49 | 
             
                    Args:
         | 
| 44 50 | 
             
                        framework_dir: Path to agents templates directory
         | 
| 45 51 | 
             
                        project_dir: Path to project-specific agents directory
         | 
| 46 52 | 
             
                    """
         | 
| 47 | 
            -
                    # Use  | 
| 53 | 
            +
                    # Use get_path_manager() for consistent path discovery
         | 
| 48 54 | 
             
                    if framework_dir is None:
         | 
| 49 55 | 
             
                        try:
         | 
| 50 56 | 
             
                            # Use agents templates directory
         | 
| 51 | 
            -
                            self.framework_dir =  | 
| 57 | 
            +
                            self.framework_dir = (
         | 
| 58 | 
            +
                                Path(__file__).parent.parent / "agents" / "templates"
         | 
| 59 | 
            +
                            )
         | 
| 52 60 | 
             
                        except Exception:
         | 
| 53 61 | 
             
                            # Fallback to agents directory
         | 
| 54 | 
            -
                            self.framework_dir =  | 
| 62 | 
            +
                            self.framework_dir = get_path_manager().get_agents_dir()
         | 
| 55 63 | 
             
                    else:
         | 
| 56 64 | 
             
                        self.framework_dir = framework_dir
         | 
| 57 | 
            -
             | 
| 65 | 
            +
             | 
| 58 66 | 
             
                    if project_dir is None:
         | 
| 59 | 
            -
                        project_root =  | 
| 67 | 
            +
                        project_root = get_path_manager().get_project_root()
         | 
| 60 68 | 
             
                        # Use direct agents directory without subdirectory to match deployment expectations
         | 
| 61 | 
            -
                        self.project_dir = project_root /  | 
| 69 | 
            +
                        self.project_dir = project_root / get_path_manager().CONFIG_DIR / "agents"
         | 
| 62 70 | 
             
                    else:
         | 
| 63 71 | 
             
                        self.project_dir = project_dir
         | 
| 64 72 | 
             
                    self.version_manager = AgentVersionManager()
         | 
| 65 73 | 
             
                    self.cache = SharedPromptCache.get_instance()
         | 
| 66 74 | 
             
                    self._markdown = mistune.create_markdown()
         | 
| 67 | 
            -
             | 
| 68 | 
            -
                def create_agent( | 
| 75 | 
            +
             | 
| 76 | 
            +
                def create_agent(
         | 
| 77 | 
            +
                    self, name: str, definition: AgentDefinition, location: str = "project"
         | 
| 78 | 
            +
                ) -> Path:
         | 
| 69 79 | 
             
                    """
         | 
| 70 80 | 
             
                    Create a new agent definition file.
         | 
| 71 | 
            -
             | 
| 81 | 
            +
             | 
| 72 82 | 
             
                    Args:
         | 
| 73 83 | 
             
                        name: Agent name (e.g., "performance-agent")
         | 
| 74 84 | 
             
                        definition: Agent definition object
         | 
| 75 85 | 
             
                        location: "project" or "framework"
         | 
| 76 | 
            -
             | 
| 86 | 
            +
             | 
| 77 87 | 
             
                    Returns:
         | 
| 78 88 | 
             
                        Path to created file
         | 
| 79 89 | 
             
                    """
         | 
| 80 90 | 
             
                    # Determine target directory
         | 
| 81 91 | 
             
                    target_dir = self.project_dir if location == "project" else self.framework_dir
         | 
| 82 92 | 
             
                    target_dir.mkdir(parents=True, exist_ok=True)
         | 
| 83 | 
            -
             | 
| 93 | 
            +
             | 
| 84 94 | 
             
                    # Generate markdown content
         | 
| 85 95 | 
             
                    content = self._definition_to_markdown(definition)
         | 
| 86 | 
            -
             | 
| 96 | 
            +
             | 
| 87 97 | 
             
                    # Write file
         | 
| 88 98 | 
             
                    file_path = target_dir / f"{name}.md"
         | 
| 89 | 
            -
                    file_path.write_text(content, encoding= | 
| 90 | 
            -
             | 
| 99 | 
            +
                    file_path.write_text(content, encoding="utf-8")
         | 
| 100 | 
            +
             | 
| 91 101 | 
             
                    # Clear cache
         | 
| 92 102 | 
             
                    self._clear_agent_cache(name)
         | 
| 93 | 
            -
             | 
| 103 | 
            +
             | 
| 94 104 | 
             
                    logger.info(f"Created agent '{name}' at {file_path}")
         | 
| 95 105 | 
             
                    return file_path
         | 
| 96 | 
            -
             | 
| 106 | 
            +
             | 
| 97 107 | 
             
                def read_agent(self, name: str) -> Optional[AgentDefinition]:
         | 
| 98 108 | 
             
                    """
         | 
| 99 109 | 
             
                    Read an agent definition.
         | 
| 100 | 
            -
             | 
| 110 | 
            +
             | 
| 101 111 | 
             
                    Args:
         | 
| 102 112 | 
             
                        name: Agent name (without .md extension)
         | 
| 103 | 
            -
             | 
| 113 | 
            +
             | 
| 104 114 | 
             
                    Returns:
         | 
| 105 115 | 
             
                        AgentDefinition or None if not found
         | 
| 106 116 | 
             
                    """
         | 
| @@ -109,25 +119,26 @@ class AgentManager: | |
| 109 119 | 
             
                    if not agent_path:
         | 
| 110 120 | 
             
                        logger.warning(f"Agent '{name}' not found")
         | 
| 111 121 | 
             
                        return None
         | 
| 112 | 
            -
             | 
| 122 | 
            +
             | 
| 113 123 | 
             
                    try:
         | 
| 114 124 | 
             
                        # Read and parse the file
         | 
| 115 | 
            -
                        content = agent_path.read_text(encoding= | 
| 125 | 
            +
                        content = agent_path.read_text(encoding="utf-8")
         | 
| 116 126 | 
             
                        return self._parse_agent_markdown(content, name, str(agent_path))
         | 
| 117 127 | 
             
                    except Exception as e:
         | 
| 118 128 | 
             
                        logger.error(f"Error reading agent '{name}': {e}")
         | 
| 119 129 | 
             
                        return None
         | 
| 120 | 
            -
             | 
| 121 | 
            -
                def update_agent( | 
| 122 | 
            -
             | 
| 130 | 
            +
             | 
| 131 | 
            +
                def update_agent(
         | 
| 132 | 
            +
                    self, name: str, updates: Dict[str, Any], increment_version: bool = True
         | 
| 133 | 
            +
                ) -> Optional[AgentDefinition]:
         | 
| 123 134 | 
             
                    """
         | 
| 124 135 | 
             
                    Update an agent definition.
         | 
| 125 | 
            -
             | 
| 136 | 
            +
             | 
| 126 137 | 
             
                    Args:
         | 
| 127 138 | 
             
                        name: Agent name
         | 
| 128 139 | 
             
                        updates: Dictionary of updates to apply
         | 
| 129 140 | 
             
                        increment_version: Whether to increment serial version
         | 
| 130 | 
            -
             | 
| 141 | 
            +
             | 
| 131 142 | 
             
                    Returns:
         | 
| 132 143 | 
             
                        Updated AgentDefinition or None if failed
         | 
| 133 144 | 
             
                    """
         | 
| @@ -135,51 +146,58 @@ class AgentManager: | |
| 135 146 | 
             
                    agent_def = self.read_agent(name)
         | 
| 136 147 | 
             
                    if not agent_def:
         | 
| 137 148 | 
             
                        return None
         | 
| 138 | 
            -
             | 
| 149 | 
            +
             | 
| 139 150 | 
             
                    # Apply updates
         | 
| 140 151 | 
             
                    for key, value in updates.items():
         | 
| 141 152 | 
             
                        if hasattr(agent_def, key):
         | 
| 142 153 | 
             
                            setattr(agent_def, key, value)
         | 
| 143 154 | 
             
                        elif key in ["type", "model_preference", "tags", "specializations"]:
         | 
| 144 155 | 
             
                            setattr(agent_def.metadata, key, value)
         | 
| 145 | 
            -
             | 
| 156 | 
            +
             | 
| 146 157 | 
             
                    # Increment version if requested
         | 
| 147 158 | 
             
                    if increment_version:
         | 
| 148 159 | 
             
                        agent_def.metadata.increment_serial_version()
         | 
| 149 160 | 
             
                        agent_def.metadata.last_updated = datetime.now()
         | 
| 150 | 
            -
             | 
| 161 | 
            +
             | 
| 151 162 | 
             
                    # Write back
         | 
| 152 163 | 
             
                    agent_path = self._find_agent_file(name)
         | 
| 153 164 | 
             
                    if agent_path:
         | 
| 154 165 | 
             
                        content = self._definition_to_markdown(agent_def)
         | 
| 155 | 
            -
                        agent_path.write_text(content, encoding= | 
| 156 | 
            -
             | 
| 166 | 
            +
                        agent_path.write_text(content, encoding="utf-8")
         | 
| 167 | 
            +
             | 
| 157 168 | 
             
                        # Clear cache
         | 
| 158 169 | 
             
                        self._clear_agent_cache(name)
         | 
| 159 | 
            -
             | 
| 160 | 
            -
                        logger.info( | 
| 170 | 
            +
             | 
| 171 | 
            +
                        logger.info(
         | 
| 172 | 
            +
                            f"Updated agent '{name}' to version {agent_def.metadata.version}"
         | 
| 173 | 
            +
                        )
         | 
| 161 174 | 
             
                        return agent_def
         | 
| 162 | 
            -
             | 
| 175 | 
            +
             | 
| 163 176 | 
             
                    return None
         | 
| 164 | 
            -
             | 
| 165 | 
            -
                def update_section( | 
| 166 | 
            -
             | 
| 177 | 
            +
             | 
| 178 | 
            +
                def update_section(
         | 
| 179 | 
            +
                    self,
         | 
| 180 | 
            +
                    name: str,
         | 
| 181 | 
            +
                    section: AgentSection,
         | 
| 182 | 
            +
                    content: str,
         | 
| 183 | 
            +
                    increment_version: bool = True,
         | 
| 184 | 
            +
                ) -> Optional[AgentDefinition]:
         | 
| 167 185 | 
             
                    """
         | 
| 168 186 | 
             
                    Update a specific section of an agent.
         | 
| 169 | 
            -
             | 
| 187 | 
            +
             | 
| 170 188 | 
             
                    Args:
         | 
| 171 189 | 
             
                        name: Agent name
         | 
| 172 190 | 
             
                        section: Section to update
         | 
| 173 191 | 
             
                        content: New section content
         | 
| 174 192 | 
             
                        increment_version: Whether to increment version
         | 
| 175 | 
            -
             | 
| 193 | 
            +
             | 
| 176 194 | 
             
                    Returns:
         | 
| 177 195 | 
             
                        Updated AgentDefinition or None
         | 
| 178 196 | 
             
                    """
         | 
| 179 197 | 
             
                    agent_def = self.read_agent(name)
         | 
| 180 198 | 
             
                    if not agent_def:
         | 
| 181 199 | 
             
                        return None
         | 
| 182 | 
            -
             | 
| 200 | 
            +
             | 
| 183 201 | 
             
                    # Map section to attribute
         | 
| 184 202 | 
             
                    section_map = {
         | 
| 185 203 | 
             
                        AgentSection.PRIMARY_ROLE: "primary_role",
         | 
| @@ -187,18 +205,22 @@ class AgentManager: | |
| 187 205 | 
             
                        AgentSection.TOOLS: "tools_commands",
         | 
| 188 206 | 
             
                        AgentSection.ESCALATION: "escalation_triggers",
         | 
| 189 207 | 
             
                        AgentSection.KPI: "kpis",
         | 
| 190 | 
            -
                        AgentSection.DEPENDENCIES: "dependencies"
         | 
| 208 | 
            +
                        AgentSection.DEPENDENCIES: "dependencies",
         | 
| 191 209 | 
             
                    }
         | 
| 192 | 
            -
             | 
| 210 | 
            +
             | 
| 193 211 | 
             
                    if section in section_map:
         | 
| 194 212 | 
             
                        attr_name = section_map[section]
         | 
| 195 | 
            -
                        if section in [ | 
| 196 | 
            -
             | 
| 213 | 
            +
                        if section in [
         | 
| 214 | 
            +
                            AgentSection.CAPABILITIES,
         | 
| 215 | 
            +
                            AgentSection.ESCALATION,
         | 
| 216 | 
            +
                            AgentSection.KPI,
         | 
| 217 | 
            +
                            AgentSection.DEPENDENCIES,
         | 
| 218 | 
            +
                        ]:
         | 
| 197 219 | 
             
                            # Parse list content
         | 
| 198 220 | 
             
                            setattr(agent_def, attr_name, self._parse_list_content(content))
         | 
| 199 221 | 
             
                        else:
         | 
| 200 222 | 
             
                            setattr(agent_def, attr_name, content.strip())
         | 
| 201 | 
            -
             | 
| 223 | 
            +
             | 
| 202 224 | 
             
                    # Special handling for complex sections
         | 
| 203 225 | 
             
                    elif section == AgentSection.WHEN_TO_USE:
         | 
| 204 226 | 
             
                        agent_def.when_to_use = self._parse_when_to_use(content)
         | 
| @@ -206,32 +228,32 @@ class AgentManager: | |
| 206 228 | 
             
                        agent_def.authority = self._parse_authority(content)
         | 
| 207 229 | 
             
                    elif section == AgentSection.WORKFLOWS:
         | 
| 208 230 | 
             
                        agent_def.workflows = self._parse_workflows(content)
         | 
| 209 | 
            -
             | 
| 231 | 
            +
             | 
| 210 232 | 
             
                    # Update raw section
         | 
| 211 233 | 
             
                    agent_def.raw_sections[section.value] = content
         | 
| 212 | 
            -
             | 
| 234 | 
            +
             | 
| 213 235 | 
             
                    # Increment version
         | 
| 214 236 | 
             
                    if increment_version:
         | 
| 215 237 | 
             
                        agent_def.metadata.increment_serial_version()
         | 
| 216 238 | 
             
                        agent_def.metadata.last_updated = datetime.now()
         | 
| 217 | 
            -
             | 
| 239 | 
            +
             | 
| 218 240 | 
             
                    # Write back
         | 
| 219 241 | 
             
                    return self.update_agent(name, {}, increment_version=False)
         | 
| 220 | 
            -
             | 
| 242 | 
            +
             | 
| 221 243 | 
             
                def delete_agent(self, name: str) -> bool:
         | 
| 222 244 | 
             
                    """
         | 
| 223 245 | 
             
                    Delete an agent definition.
         | 
| 224 | 
            -
             | 
| 246 | 
            +
             | 
| 225 247 | 
             
                    Args:
         | 
| 226 248 | 
             
                        name: Agent name
         | 
| 227 | 
            -
             | 
| 249 | 
            +
             | 
| 228 250 | 
             
                    Returns:
         | 
| 229 251 | 
             
                        True if deleted, False otherwise
         | 
| 230 252 | 
             
                    """
         | 
| 231 253 | 
             
                    agent_path = self._find_agent_file(name)
         | 
| 232 254 | 
             
                    if not agent_path:
         | 
| 233 255 | 
             
                        return False
         | 
| 234 | 
            -
             | 
| 256 | 
            +
             | 
| 235 257 | 
             
                    try:
         | 
| 236 258 | 
             
                        agent_path.unlink()
         | 
| 237 259 | 
             
                        self._clear_agent_cache(name)
         | 
| @@ -240,19 +262,19 @@ class AgentManager: | |
| 240 262 | 
             
                    except Exception as e:
         | 
| 241 263 | 
             
                        logger.error(f"Error deleting agent '{name}': {e}")
         | 
| 242 264 | 
             
                        return False
         | 
| 243 | 
            -
             | 
| 265 | 
            +
             | 
| 244 266 | 
             
                def list_agents(self, location: Optional[str] = None) -> Dict[str, Dict[str, Any]]:
         | 
| 245 267 | 
             
                    """
         | 
| 246 268 | 
             
                    List all available agents.
         | 
| 247 | 
            -
             | 
| 269 | 
            +
             | 
| 248 270 | 
             
                    Args:
         | 
| 249 271 | 
             
                        location: Filter by location ("project", "framework", or None for all)
         | 
| 250 | 
            -
             | 
| 272 | 
            +
             | 
| 251 273 | 
             
                    Returns:
         | 
| 252 274 | 
             
                        Dictionary of agent info
         | 
| 253 275 | 
             
                    """
         | 
| 254 276 | 
             
                    agents = {}
         | 
| 255 | 
            -
             | 
| 277 | 
            +
             | 
| 256 278 | 
             
                    # Check framework agents
         | 
| 257 279 | 
             
                    if location in [None, "framework"]:
         | 
| 258 280 | 
             
                        for agent_file in self.framework_dir.glob("*.md"):
         | 
| @@ -265,9 +287,9 @@ class AgentManager: | |
| 265 287 | 
             
                                        "path": str(agent_file),
         | 
| 266 288 | 
             
                                        "version": agent_def.metadata.version,
         | 
| 267 289 | 
             
                                        "type": agent_def.metadata.type.value,
         | 
| 268 | 
            -
                                        "specializations": agent_def.metadata.specializations
         | 
| 290 | 
            +
                                        "specializations": agent_def.metadata.specializations,
         | 
| 269 291 | 
             
                                    }
         | 
| 270 | 
            -
             | 
| 292 | 
            +
             | 
| 271 293 | 
             
                    # Check project agents
         | 
| 272 294 | 
             
                    if location in [None, "project"] and self.project_dir.exists():
         | 
| 273 295 | 
             
                        for agent_file in self.project_dir.glob("*.md"):
         | 
| @@ -279,29 +301,29 @@ class AgentManager: | |
| 279 301 | 
             
                                    "path": str(agent_file),
         | 
| 280 302 | 
             
                                    "version": agent_def.metadata.version,
         | 
| 281 303 | 
             
                                    "type": agent_def.metadata.type.value,
         | 
| 282 | 
            -
                                    "specializations": agent_def.metadata.specializations
         | 
| 304 | 
            +
                                    "specializations": agent_def.metadata.specializations,
         | 
| 283 305 | 
             
                                }
         | 
| 284 | 
            -
             | 
| 306 | 
            +
             | 
| 285 307 | 
             
                    return agents
         | 
| 286 | 
            -
             | 
| 308 | 
            +
             | 
| 287 309 | 
             
                def get_agent_api(self, name: str) -> Optional[Dict[str, Any]]:
         | 
| 288 310 | 
             
                    """
         | 
| 289 311 | 
             
                    Get agent data in API-friendly format.
         | 
| 290 | 
            -
             | 
| 312 | 
            +
             | 
| 291 313 | 
             
                    Args:
         | 
| 292 314 | 
             
                        name: Agent name
         | 
| 293 | 
            -
             | 
| 315 | 
            +
             | 
| 294 316 | 
             
                    Returns:
         | 
| 295 317 | 
             
                        Agent data dictionary or None
         | 
| 296 318 | 
             
                    """
         | 
| 297 319 | 
             
                    agent_def = self.read_agent(name)
         | 
| 298 320 | 
             
                    if not agent_def:
         | 
| 299 321 | 
             
                        return None
         | 
| 300 | 
            -
             | 
| 322 | 
            +
             | 
| 301 323 | 
             
                    return agent_def.to_dict()
         | 
| 302 | 
            -
             | 
| 324 | 
            +
             | 
| 303 325 | 
             
                # Private helper methods
         | 
| 304 | 
            -
             | 
| 326 | 
            +
             | 
| 305 327 | 
             
                def _find_agent_file(self, name: str) -> Optional[Path]:
         | 
| 306 328 | 
             
                    """Find agent file in project or framework directories."""
         | 
| 307 329 | 
             
                    # Check project first (higher precedence)
         | 
| @@ -309,19 +331,21 @@ class AgentManager: | |
| 309 331 | 
             
                        project_path = self.project_dir / f"{name}.md"
         | 
| 310 332 | 
             
                        if project_path.exists():
         | 
| 311 333 | 
             
                            return project_path
         | 
| 312 | 
            -
             | 
| 334 | 
            +
             | 
| 313 335 | 
             
                    # Check framework
         | 
| 314 336 | 
             
                    framework_path = self.framework_dir / f"{name}.md"
         | 
| 315 337 | 
             
                    if framework_path.exists():
         | 
| 316 338 | 
             
                        return framework_path
         | 
| 317 | 
            -
             | 
| 339 | 
            +
             | 
| 318 340 | 
             
                    return None
         | 
| 319 | 
            -
             | 
| 320 | 
            -
                def _parse_agent_markdown( | 
| 341 | 
            +
             | 
| 342 | 
            +
                def _parse_agent_markdown(
         | 
| 343 | 
            +
                    self, content: str, name: str, file_path: str
         | 
| 344 | 
            +
                ) -> AgentDefinition:
         | 
| 321 345 | 
             
                    """Parse markdown content into AgentDefinition."""
         | 
| 322 346 | 
             
                    # Parse frontmatter
         | 
| 323 347 | 
             
                    post = frontmatter.loads(content)
         | 
| 324 | 
            -
             | 
| 348 | 
            +
             | 
| 325 349 | 
             
                    # Extract metadata
         | 
| 326 350 | 
             
                    metadata = AgentMetadata(
         | 
| 327 351 | 
             
                        type=AgentType(post.metadata.get("type", "core")),
         | 
| @@ -330,22 +354,22 @@ class AgentManager: | |
| 330 354 | 
             
                        last_updated=post.metadata.get("last_updated"),
         | 
| 331 355 | 
             
                        author=post.metadata.get("author"),
         | 
| 332 356 | 
             
                        tags=post.metadata.get("tags", []),
         | 
| 333 | 
            -
                        specializations=post.metadata.get("specializations", [])
         | 
| 357 | 
            +
                        specializations=post.metadata.get("specializations", []),
         | 
| 334 358 | 
             
                    )
         | 
| 335 | 
            -
             | 
| 359 | 
            +
             | 
| 336 360 | 
             
                    # Extract version from content if not in frontmatter
         | 
| 337 361 | 
             
                    if not post.metadata.get("version"):
         | 
| 338 362 | 
             
                        version = self.version_manager.extract_version_from_markdown(content)
         | 
| 339 363 | 
             
                        if version:
         | 
| 340 364 | 
             
                            metadata.version = version
         | 
| 341 | 
            -
             | 
| 365 | 
            +
             | 
| 342 366 | 
             
                    # Parse sections
         | 
| 343 367 | 
             
                    sections = self._extract_sections(post.content)
         | 
| 344 | 
            -
             | 
| 368 | 
            +
             | 
| 345 369 | 
             
                    # Extract title
         | 
| 346 | 
            -
                    title_match = re.search(r | 
| 347 | 
            -
                    title = title_match.group(1) if title_match else name.replace( | 
| 348 | 
            -
             | 
| 370 | 
            +
                    title_match = re.search(r"^#\s+(.+)$", post.content, re.MULTILINE)
         | 
| 371 | 
            +
                    title = title_match.group(1) if title_match else name.replace("-", " ").title()
         | 
| 372 | 
            +
             | 
| 349 373 | 
             
                    # Build definition
         | 
| 350 374 | 
             
                    definition = AgentDefinition(
         | 
| 351 375 | 
             
                        name=name,
         | 
| @@ -353,37 +377,51 @@ class AgentManager: | |
| 353 377 | 
             
                        file_path=file_path,
         | 
| 354 378 | 
             
                        metadata=metadata,
         | 
| 355 379 | 
             
                        primary_role=sections.get("Primary Role", ""),
         | 
| 356 | 
            -
                        when_to_use=self._parse_when_to_use( | 
| 357 | 
            -
             | 
| 358 | 
            -
                         | 
| 359 | 
            -
                         | 
| 360 | 
            -
             | 
| 361 | 
            -
                         | 
| 362 | 
            -
                         | 
| 380 | 
            +
                        when_to_use=self._parse_when_to_use(
         | 
| 381 | 
            +
                            sections.get("When to Use This Agent", "")
         | 
| 382 | 
            +
                        ),
         | 
| 383 | 
            +
                        capabilities=self._parse_list_content(
         | 
| 384 | 
            +
                            sections.get("Core Capabilities", "")
         | 
| 385 | 
            +
                        ),
         | 
| 386 | 
            +
                        authority=self._parse_authority(
         | 
| 387 | 
            +
                            sections.get("Authority & Permissions", "")
         | 
| 388 | 
            +
                        ),
         | 
| 389 | 
            +
                        workflows=self._parse_workflows(
         | 
| 390 | 
            +
                            sections.get("Agent-Specific Workflows", "")
         | 
| 391 | 
            +
                        ),
         | 
| 392 | 
            +
                        escalation_triggers=self._parse_list_content(
         | 
| 393 | 
            +
                            sections.get("Unique Escalation Triggers", "")
         | 
| 394 | 
            +
                        ),
         | 
| 395 | 
            +
                        kpis=self._parse_list_content(
         | 
| 396 | 
            +
                            sections.get("Key Performance Indicators", "")
         | 
| 397 | 
            +
                        ),
         | 
| 398 | 
            +
                        dependencies=self._parse_list_content(
         | 
| 399 | 
            +
                            sections.get("Critical Dependencies", "")
         | 
| 400 | 
            +
                        ),
         | 
| 363 401 | 
             
                        tools_commands=sections.get("Specialized Tools/Commands", ""),
         | 
| 364 402 | 
             
                        raw_content=content,
         | 
| 365 | 
            -
                        raw_sections=sections
         | 
| 403 | 
            +
                        raw_sections=sections,
         | 
| 366 404 | 
             
                    )
         | 
| 367 | 
            -
             | 
| 405 | 
            +
             | 
| 368 406 | 
             
                    return definition
         | 
| 369 | 
            -
             | 
| 407 | 
            +
             | 
| 370 408 | 
             
                def _extract_sections(self, content: str) -> Dict[str, str]:
         | 
| 371 409 | 
             
                    """Extract sections from markdown content."""
         | 
| 372 410 | 
             
                    sections = {}
         | 
| 373 411 | 
             
                    current_section = None
         | 
| 374 412 | 
             
                    current_content = []
         | 
| 375 | 
            -
             | 
| 413 | 
            +
             | 
| 376 414 | 
             
                    # Split into lines
         | 
| 377 | 
            -
                    lines = content.split( | 
| 378 | 
            -
             | 
| 415 | 
            +
                    lines = content.split("\n")
         | 
| 416 | 
            +
             | 
| 379 417 | 
             
                    for line in lines:
         | 
| 380 418 | 
             
                        # Check if this is a section header
         | 
| 381 | 
            -
                        header_match = re.match(r | 
| 419 | 
            +
                        header_match = re.match(r"^##\s+(?:🎯|🔧|🔑|📋|🚨|📊|🔄|🛠️)?\s*(.+)$", line)
         | 
| 382 420 | 
             
                        if header_match:
         | 
| 383 421 | 
             
                            # Save previous section
         | 
| 384 422 | 
             
                            if current_section:
         | 
| 385 | 
            -
                                sections[current_section] =  | 
| 386 | 
            -
             | 
| 423 | 
            +
                                sections[current_section] = "\n".join(current_content).strip()
         | 
| 424 | 
            +
             | 
| 387 425 | 
             
                            # Start new section
         | 
| 388 426 | 
             
                            current_section = header_match.group(1).strip()
         | 
| 389 427 | 
             
                            current_content = []
         | 
| @@ -391,94 +429,105 @@ class AgentManager: | |
| 391 429 | 
             
                            # Add to current section
         | 
| 392 430 | 
             
                            if current_section:
         | 
| 393 431 | 
             
                                current_content.append(line)
         | 
| 394 | 
            -
             | 
| 432 | 
            +
             | 
| 395 433 | 
             
                    # Save last section
         | 
| 396 434 | 
             
                    if current_section:
         | 
| 397 | 
            -
                        sections[current_section] =  | 
| 398 | 
            -
             | 
| 435 | 
            +
                        sections[current_section] = "\n".join(current_content).strip()
         | 
| 436 | 
            +
             | 
| 399 437 | 
             
                    return sections
         | 
| 400 | 
            -
             | 
| 438 | 
            +
             | 
| 401 439 | 
             
                def _parse_list_content(self, content: str) -> List[str]:
         | 
| 402 440 | 
             
                    """Parse bullet point or numbered list content."""
         | 
| 403 441 | 
             
                    items = []
         | 
| 404 | 
            -
                    for line in content.split( | 
| 442 | 
            +
                    for line in content.split("\n"):
         | 
| 405 443 | 
             
                        # Match bullet points or numbered items
         | 
| 406 | 
            -
                        match = re.match(r | 
| 444 | 
            +
                        match = re.match(r"^[-*•]\s+(.+)$|^\d+\.\s+(.+)$", line.strip())
         | 
| 407 445 | 
             
                        if match:
         | 
| 408 446 | 
             
                            item = match.group(1) or match.group(2)
         | 
| 409 447 | 
             
                            items.append(item.strip())
         | 
| 410 448 | 
             
                    return items
         | 
| 411 | 
            -
             | 
| 449 | 
            +
             | 
| 412 450 | 
             
                def _parse_when_to_use(self, content: str) -> Dict[str, List[str]]:
         | 
| 413 451 | 
             
                    """Parse When to Use section."""
         | 
| 414 452 | 
             
                    result = {"select": [], "do_not_select": []}
         | 
| 415 453 | 
             
                    current_mode = None
         | 
| 416 | 
            -
             | 
| 417 | 
            -
                    for line in content.split( | 
| 418 | 
            -
                        if  | 
| 454 | 
            +
             | 
| 455 | 
            +
                    for line in content.split("\n"):
         | 
| 456 | 
            +
                        if (
         | 
| 457 | 
            +
                            "Select this agent when:" in line
         | 
| 458 | 
            +
                            or "**Select this agent when:**" in line
         | 
| 459 | 
            +
                        ):
         | 
| 419 460 | 
             
                            current_mode = "select"
         | 
| 420 461 | 
             
                        elif "Do NOT select for:" in line or "**Do NOT select for:**" in line:
         | 
| 421 462 | 
             
                            current_mode = "do_not_select"
         | 
| 422 | 
            -
                        elif current_mode and line.strip().startswith( | 
| 463 | 
            +
                        elif current_mode and line.strip().startswith("-"):
         | 
| 423 464 | 
             
                            item = line.strip()[1:].strip()
         | 
| 424 465 | 
             
                            result[current_mode].append(item)
         | 
| 425 | 
            -
             | 
| 466 | 
            +
             | 
| 426 467 | 
             
                    return result
         | 
| 427 | 
            -
             | 
| 468 | 
            +
             | 
| 428 469 | 
             
                def _parse_authority(self, content: str) -> AgentPermissions:
         | 
| 429 470 | 
             
                    """Parse Authority & Permissions section."""
         | 
| 430 471 | 
             
                    permissions = AgentPermissions()
         | 
| 431 472 | 
             
                    current_section = None
         | 
| 432 | 
            -
             | 
| 433 | 
            -
                    for line in content.split( | 
| 473 | 
            +
             | 
| 474 | 
            +
                    for line in content.split("\n"):
         | 
| 434 475 | 
             
                        if "Exclusive Write Access" in line:
         | 
| 435 476 | 
             
                            current_section = "write"
         | 
| 436 477 | 
             
                        elif "Forbidden Operations" in line:
         | 
| 437 478 | 
             
                            current_section = "forbidden"
         | 
| 438 479 | 
             
                        elif "Read Access" in line:
         | 
| 439 480 | 
             
                            current_section = "read"
         | 
| 440 | 
            -
                        elif current_section and line.strip().startswith( | 
| 481 | 
            +
                        elif current_section and line.strip().startswith("-"):
         | 
| 441 482 | 
             
                            item = line.strip()[1:].strip()
         | 
| 442 483 | 
             
                            # Remove inline comments
         | 
| 443 | 
            -
                            item = re.sub(r | 
| 444 | 
            -
             | 
| 484 | 
            +
                            item = re.sub(r"\s*#.*$", "", item).strip()
         | 
| 485 | 
            +
             | 
| 445 486 | 
             
                            if current_section == "write":
         | 
| 446 487 | 
             
                                permissions.exclusive_write_access.append(item)
         | 
| 447 488 | 
             
                            elif current_section == "forbidden":
         | 
| 448 489 | 
             
                                permissions.forbidden_operations.append(item)
         | 
| 449 490 | 
             
                            elif current_section == "read":
         | 
| 450 491 | 
             
                                permissions.read_access.append(item)
         | 
| 451 | 
            -
             | 
| 492 | 
            +
             | 
| 452 493 | 
             
                    return permissions
         | 
| 453 | 
            -
             | 
| 494 | 
            +
             | 
| 454 495 | 
             
                def _parse_workflows(self, content: str) -> List[AgentWorkflow]:
         | 
| 455 496 | 
             
                    """Parse workflows from YAML blocks."""
         | 
| 456 497 | 
             
                    workflows = []
         | 
| 457 | 
            -
             | 
| 498 | 
            +
             | 
| 458 499 | 
             
                    # Find all YAML blocks
         | 
| 459 | 
            -
                    yaml_blocks = re.findall(r | 
| 460 | 
            -
             | 
| 500 | 
            +
                    yaml_blocks = re.findall(r"```yaml\n(.*?)\n```", content, re.DOTALL)
         | 
| 501 | 
            +
             | 
| 461 502 | 
             
                    for block in yaml_blocks:
         | 
| 462 503 | 
             
                        try:
         | 
| 463 504 | 
             
                            data = yaml.safe_load(block)
         | 
| 464 | 
            -
                            if isinstance(data, dict) and all( | 
| 505 | 
            +
                            if isinstance(data, dict) and all(
         | 
| 506 | 
            +
                                k in data for k in ["trigger", "process", "output"]
         | 
| 507 | 
            +
                            ):
         | 
| 465 508 | 
             
                                # Extract workflow name from preceding heading if available
         | 
| 466 | 
            -
                                name_match = re.search( | 
| 509 | 
            +
                                name_match = re.search(
         | 
| 510 | 
            +
                                    r"###\s+(.+)\n```yaml\n" + re.escape(block), content
         | 
| 511 | 
            +
                                )
         | 
| 467 512 | 
             
                                name = name_match.group(1) if name_match else "Unnamed Workflow"
         | 
| 468 | 
            -
             | 
| 513 | 
            +
             | 
| 469 514 | 
             
                                workflow = AgentWorkflow(
         | 
| 470 515 | 
             
                                    name=name,
         | 
| 471 516 | 
             
                                    trigger=data["trigger"],
         | 
| 472 | 
            -
                                    process= | 
| 517 | 
            +
                                    process=(
         | 
| 518 | 
            +
                                        data["process"]
         | 
| 519 | 
            +
                                        if isinstance(data["process"], list)
         | 
| 520 | 
            +
                                        else [data["process"]]
         | 
| 521 | 
            +
                                    ),
         | 
| 473 522 | 
             
                                    output=data["output"],
         | 
| 474 | 
            -
                                    raw_yaml=block
         | 
| 523 | 
            +
                                    raw_yaml=block,
         | 
| 475 524 | 
             
                                )
         | 
| 476 525 | 
             
                                workflows.append(workflow)
         | 
| 477 526 | 
             
                        except yaml.YAMLError:
         | 
| 478 527 | 
             
                            logger.warning("Failed to parse YAML workflow block")
         | 
| 479 | 
            -
             | 
| 528 | 
            +
             | 
| 480 529 | 
             
                    return workflows
         | 
| 481 | 
            -
             | 
| 530 | 
            +
             | 
| 482 531 | 
             
                def _definition_to_markdown(self, definition: AgentDefinition) -> str:
         | 
| 483 532 | 
             
                    """Convert AgentDefinition back to markdown."""
         | 
| 484 533 | 
             
                    # Start with frontmatter
         | 
| @@ -489,21 +538,21 @@ class AgentManager: | |
| 489 538 | 
             
                        "last_updated": definition.metadata.last_updated,
         | 
| 490 539 | 
             
                        "author": definition.metadata.author,
         | 
| 491 540 | 
             
                        "tags": definition.metadata.tags,
         | 
| 492 | 
            -
                        "specializations": definition.metadata.specializations
         | 
| 541 | 
            +
                        "specializations": definition.metadata.specializations,
         | 
| 493 542 | 
             
                    }
         | 
| 494 | 
            -
             | 
| 543 | 
            +
             | 
| 495 544 | 
             
                    # Remove None values
         | 
| 496 545 | 
             
                    frontmatter_data = {k: v for k, v in frontmatter_data.items() if v is not None}
         | 
| 497 | 
            -
             | 
| 546 | 
            +
             | 
| 498 547 | 
             
                    # Build content
         | 
| 499 548 | 
             
                    content = []
         | 
| 500 549 | 
             
                    content.append(f"# {definition.title}\n")
         | 
| 501 | 
            -
             | 
| 550 | 
            +
             | 
| 502 551 | 
             
                    # Primary Role
         | 
| 503 552 | 
             
                    content.append("## 🎯 Primary Role")
         | 
| 504 553 | 
             
                    content.append(definition.primary_role)
         | 
| 505 554 | 
             
                    content.append("")
         | 
| 506 | 
            -
             | 
| 555 | 
            +
             | 
| 507 556 | 
             
                    # When to Use
         | 
| 508 557 | 
             
                    content.append("## 🎯 When to Use This Agent")
         | 
| 509 558 | 
             
                    content.append("")
         | 
| @@ -515,13 +564,13 @@ class AgentManager: | |
| 515 564 | 
             
                    for item in definition.when_to_use.get("do_not_select", []):
         | 
| 516 565 | 
             
                        content.append(f"- {item}")
         | 
| 517 566 | 
             
                    content.append("")
         | 
| 518 | 
            -
             | 
| 567 | 
            +
             | 
| 519 568 | 
             
                    # Capabilities
         | 
| 520 569 | 
             
                    content.append("## 🔧 Core Capabilities")
         | 
| 521 570 | 
             
                    for capability in definition.capabilities:
         | 
| 522 571 | 
             
                        content.append(f"- {capability}")
         | 
| 523 572 | 
             
                    content.append("")
         | 
| 524 | 
            -
             | 
| 573 | 
            +
             | 
| 525 574 | 
             
                    # Authority
         | 
| 526 575 | 
             
                    content.append("## 🔑 Authority & Permissions")
         | 
| 527 576 | 
             
                    content.append("")
         | 
| @@ -533,7 +582,7 @@ class AgentManager: | |
| 533 582 | 
             
                    for item in definition.authority.forbidden_operations:
         | 
| 534 583 | 
             
                        content.append(f"- {item}")
         | 
| 535 584 | 
             
                    content.append("")
         | 
| 536 | 
            -
             | 
| 585 | 
            +
             | 
| 537 586 | 
             
                    # Workflows
         | 
| 538 587 | 
             
                    if definition.workflows:
         | 
| 539 588 | 
             
                        content.append("## 📋 Agent-Specific Workflows")
         | 
| @@ -544,55 +593,59 @@ class AgentManager: | |
| 544 593 | 
             
                            yaml_content = {
         | 
| 545 594 | 
             
                                "trigger": workflow.trigger,
         | 
| 546 595 | 
             
                                "process": workflow.process,
         | 
| 547 | 
            -
                                "output": workflow.output
         | 
| 596 | 
            +
                                "output": workflow.output,
         | 
| 548 597 | 
             
                            }
         | 
| 549 | 
            -
                            content.append( | 
| 598 | 
            +
                            content.append(
         | 
| 599 | 
            +
                                yaml.dump(yaml_content, default_flow_style=False).strip()
         | 
| 600 | 
            +
                            )
         | 
| 550 601 | 
             
                            content.append("```")
         | 
| 551 602 | 
             
                            content.append("")
         | 
| 552 | 
            -
             | 
| 603 | 
            +
             | 
| 553 604 | 
             
                    # Escalation
         | 
| 554 605 | 
             
                    if definition.escalation_triggers:
         | 
| 555 606 | 
             
                        content.append("## 🚨 Unique Escalation Triggers")
         | 
| 556 607 | 
             
                        for trigger in definition.escalation_triggers:
         | 
| 557 608 | 
             
                            content.append(f"- {trigger}")
         | 
| 558 609 | 
             
                        content.append("")
         | 
| 559 | 
            -
             | 
| 610 | 
            +
             | 
| 560 611 | 
             
                    # KPIs
         | 
| 561 612 | 
             
                    if definition.kpis:
         | 
| 562 613 | 
             
                        content.append("## 📊 Key Performance Indicators")
         | 
| 563 614 | 
             
                        for i, kpi in enumerate(definition.kpis, 1):
         | 
| 564 615 | 
             
                            content.append(f"{i}. {kpi}")
         | 
| 565 616 | 
             
                        content.append("")
         | 
| 566 | 
            -
             | 
| 617 | 
            +
             | 
| 567 618 | 
             
                    # Dependencies
         | 
| 568 619 | 
             
                    if definition.dependencies:
         | 
| 569 620 | 
             
                        content.append("## 🔄 Critical Dependencies")
         | 
| 570 621 | 
             
                        for dep in definition.dependencies:
         | 
| 571 622 | 
             
                            content.append(f"- {dep}")
         | 
| 572 623 | 
             
                        content.append("")
         | 
| 573 | 
            -
             | 
| 624 | 
            +
             | 
| 574 625 | 
             
                    # Tools
         | 
| 575 626 | 
             
                    if definition.tools_commands:
         | 
| 576 627 | 
             
                        content.append("## 🛠️ Specialized Tools/Commands")
         | 
| 577 628 | 
             
                        content.append(definition.tools_commands)
         | 
| 578 629 | 
             
                        content.append("")
         | 
| 579 | 
            -
             | 
| 630 | 
            +
             | 
| 580 631 | 
             
                    # Footer
         | 
| 581 632 | 
             
                    content.append("---")
         | 
| 582 633 | 
             
                    content.append(f"**Agent Type**: {definition.metadata.type.value}")
         | 
| 583 634 | 
             
                    content.append(f"**Model Preference**: {definition.metadata.model_preference}")
         | 
| 584 635 | 
             
                    content.append(f"**Version**: {definition.metadata.version}")
         | 
| 585 636 | 
             
                    if definition.metadata.last_updated:
         | 
| 586 | 
            -
                        content.append( | 
| 587 | 
            -
             | 
| 637 | 
            +
                        content.append(
         | 
| 638 | 
            +
                            f"**Last Updated**: {definition.metadata.last_updated.strftime('%Y-%m-%d %H:%M:%S')}"
         | 
| 639 | 
            +
                        )
         | 
| 640 | 
            +
             | 
| 588 641 | 
             
                    # Combine with frontmatter
         | 
| 589 | 
            -
                    post = frontmatter.Post( | 
| 642 | 
            +
                    post = frontmatter.Post("\n".join(content), **frontmatter_data)
         | 
| 590 643 | 
             
                    return frontmatter.dumps(post)
         | 
| 591 | 
            -
             | 
| 644 | 
            +
             | 
| 592 645 | 
             
                def _clear_agent_cache(self, name: str):
         | 
| 593 646 | 
             
                    """Clear cache for a specific agent."""
         | 
| 594 647 | 
             
                    try:
         | 
| 595 648 | 
             
                        cache_key = f"agent_prompt:{name}:md"
         | 
| 596 649 | 
             
                        self.cache.invalidate(cache_key)
         | 
| 597 650 | 
             
                    except Exception as e:
         | 
| 598 | 
            -
                        logger.warning(f"Failed to clear cache for agent '{name}': {e}")
         | 
| 651 | 
            +
                        logger.warning(f"Failed to clear cache for agent '{name}': {e}")
         |