claude-mpm 3.9.11__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 +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 +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 +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 +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 -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 +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 +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/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 +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 +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 +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.3.dist-info}/METADATA +27 -1
- claude_mpm-4.0.3.dist-info/RECORD +402 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.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.3.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.11.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 Modification Tracker - Consolidated Service
         | 
| @@ -28,29 +30,29 @@ import os | |
| 28 30 | 
             
            import shutil
         | 
| 29 31 | 
             
            import time
         | 
| 30 32 | 
             
            import uuid
         | 
| 31 | 
            -
            from dataclasses import dataclass, field | 
| 33 | 
            +
            from dataclasses import asdict, dataclass, field
         | 
| 32 34 | 
             
            from datetime import datetime
         | 
| 33 35 | 
             
            from enum import Enum
         | 
| 34 | 
            -
            from  | 
| 35 | 
            -
            from typing import Dict, List, Optional, Any, Callable, Tuple, Set
         | 
| 36 | 
            +
            from typing import Any, Callable, Dict, List, Optional, Set, Tuple
         | 
| 36 37 |  | 
| 38 | 
            +
            from watchdog.events import FileSystemEvent, FileSystemEventHandler
         | 
| 37 39 | 
             
            from watchdog.observers import Observer
         | 
| 38 | 
            -
            from watchdog.events import FileSystemEventHandler, FileSystemEvent
         | 
| 39 40 |  | 
| 40 41 | 
             
            from claude_mpm.core.base_service import BaseService
         | 
| 41 | 
            -
            from claude_mpm.core. | 
| 42 | 
            +
            from claude_mpm.core.unified_agent_registry import UnifiedAgentRegistry as AgentRegistry
         | 
| 43 | 
            +
            from claude_mpm.core.unified_paths import get_path_manager
         | 
| 42 44 | 
             
            from claude_mpm.services.memory.cache.shared_prompt_cache import SharedPromptCache
         | 
| 43 | 
            -
            from .agent_registry import AgentRegistry
         | 
| 44 | 
            -
            from claude_mpm.utils.path_operations import path_ops
         | 
| 45 45 | 
             
            from claude_mpm.utils.config_manager import ConfigurationManager
         | 
| 46 | 
            -
             | 
| 46 | 
            +
            from claude_mpm.utils.path_operations import path_ops
         | 
| 47 47 |  | 
| 48 48 | 
             
            # ============================================================================
         | 
| 49 49 | 
             
            # Data Models
         | 
| 50 50 | 
             
            # ============================================================================
         | 
| 51 51 |  | 
| 52 | 
            +
             | 
| 52 53 | 
             
            class ModificationType(Enum):
         | 
| 53 54 | 
             
                """Types of agent modifications."""
         | 
| 55 | 
            +
             | 
| 54 56 | 
             
                CREATE = "create"
         | 
| 55 57 | 
             
                MODIFY = "modify"
         | 
| 56 58 | 
             
                DELETE = "delete"
         | 
| @@ -60,6 +62,7 @@ class ModificationType(Enum): | |
| 60 62 |  | 
| 61 63 | 
             
            class ModificationTier(Enum):
         | 
| 62 64 | 
             
                """Agent hierarchy tiers for modification tracking."""
         | 
| 65 | 
            +
             | 
| 63 66 | 
             
                PROJECT = "project"
         | 
| 64 67 | 
             
                USER = "user"
         | 
| 65 68 | 
             
                SYSTEM = "system"
         | 
| @@ -68,7 +71,7 @@ class ModificationTier(Enum): | |
| 68 71 | 
             
            @dataclass
         | 
| 69 72 | 
             
            class AgentModification:
         | 
| 70 73 | 
             
                """Agent modification record with comprehensive metadata."""
         | 
| 71 | 
            -
             | 
| 74 | 
            +
             | 
| 72 75 | 
             
                modification_id: str
         | 
| 73 76 | 
             
                agent_name: str
         | 
| 74 77 | 
             
                modification_type: ModificationType
         | 
| @@ -86,58 +89,60 @@ class AgentModification: | |
| 86 89 | 
             
                validation_errors: List[str] = field(default_factory=list)
         | 
| 87 90 | 
             
                related_modifications: List[str] = field(default_factory=list)
         | 
| 88 91 | 
             
                metadata: Dict[str, Any] = field(default_factory=dict)
         | 
| 89 | 
            -
             | 
| 92 | 
            +
             | 
| 90 93 | 
             
                @property
         | 
| 91 94 | 
             
                def modification_datetime(self) -> datetime:
         | 
| 92 95 | 
             
                    """Get modification timestamp as datetime."""
         | 
| 93 96 | 
             
                    return datetime.fromtimestamp(self.timestamp)
         | 
| 94 | 
            -
             | 
| 97 | 
            +
             | 
| 95 98 | 
             
                @property
         | 
| 96 99 | 
             
                def age_seconds(self) -> float:
         | 
| 97 100 | 
             
                    """Get age of modification in seconds."""
         | 
| 98 101 | 
             
                    return time.time() - self.timestamp
         | 
| 99 | 
            -
             | 
| 102 | 
            +
             | 
| 100 103 | 
             
                def to_dict(self) -> Dict[str, Any]:
         | 
| 101 104 | 
             
                    """Convert to dictionary for serialization."""
         | 
| 102 105 | 
             
                    data = asdict(self)
         | 
| 103 | 
            -
                    data[ | 
| 104 | 
            -
                    data[ | 
| 106 | 
            +
                    data["modification_type"] = self.modification_type.value
         | 
| 107 | 
            +
                    data["tier"] = self.tier.value
         | 
| 105 108 | 
             
                    return data
         | 
| 106 | 
            -
             | 
| 109 | 
            +
             | 
| 107 110 | 
             
                @classmethod
         | 
| 108 | 
            -
                def from_dict(cls, data: Dict[str, Any]) ->  | 
| 111 | 
            +
                def from_dict(cls, data: Dict[str, Any]) -> "AgentModification":
         | 
| 109 112 | 
             
                    """Create from dictionary."""
         | 
| 110 | 
            -
                    data[ | 
| 111 | 
            -
                    data[ | 
| 113 | 
            +
                    data["modification_type"] = ModificationType(data["modification_type"])
         | 
| 114 | 
            +
                    data["tier"] = ModificationTier(data["tier"])
         | 
| 112 115 | 
             
                    return cls(**data)
         | 
| 113 116 |  | 
| 114 117 |  | 
| 115 118 | 
             
            @dataclass
         | 
| 116 119 | 
             
            class ModificationHistory:
         | 
| 117 120 | 
             
                """Complete modification history for an agent."""
         | 
| 118 | 
            -
             | 
| 121 | 
            +
             | 
| 119 122 | 
             
                agent_name: str
         | 
| 120 123 | 
             
                modifications: List[AgentModification] = field(default_factory=list)
         | 
| 121 124 | 
             
                current_version: Optional[str] = None
         | 
| 122 125 | 
             
                total_modifications: int = 0
         | 
| 123 126 | 
             
                first_seen: Optional[float] = None
         | 
| 124 127 | 
             
                last_modified: Optional[float] = None
         | 
| 125 | 
            -
             | 
| 128 | 
            +
             | 
| 126 129 | 
             
                def add_modification(self, modification: AgentModification) -> None:
         | 
| 127 130 | 
             
                    """Add a modification to history."""
         | 
| 128 131 | 
             
                    self.modifications.append(modification)
         | 
| 129 132 | 
             
                    self.total_modifications += 1
         | 
| 130 133 | 
             
                    self.last_modified = modification.timestamp
         | 
| 131 | 
            -
             | 
| 134 | 
            +
             | 
| 132 135 | 
             
                    if self.first_seen is None:
         | 
| 133 136 | 
             
                        self.first_seen = modification.timestamp
         | 
| 134 | 
            -
             | 
| 137 | 
            +
             | 
| 135 138 | 
             
                def get_recent_modifications(self, hours: int = 24) -> List[AgentModification]:
         | 
| 136 139 | 
             
                    """Get modifications within specified hours."""
         | 
| 137 140 | 
             
                    cutoff = time.time() - (hours * 3600)
         | 
| 138 141 | 
             
                    return [mod for mod in self.modifications if mod.timestamp >= cutoff]
         | 
| 139 | 
            -
             | 
| 140 | 
            -
                def get_modifications_by_type( | 
| 142 | 
            +
             | 
| 143 | 
            +
                def get_modifications_by_type(
         | 
| 144 | 
            +
                    self, mod_type: ModificationType
         | 
| 145 | 
            +
                ) -> List[AgentModification]:
         | 
| 141 146 | 
             
                    """Get modifications by type."""
         | 
| 142 147 | 
             
                    return [mod for mod in self.modifications if mod.modification_type == mod_type]
         | 
| 143 148 |  | 
| @@ -146,37 +151,52 @@ class ModificationHistory: | |
| 146 151 | 
             
            # File System Monitoring
         | 
| 147 152 | 
             
            # ============================================================================
         | 
| 148 153 |  | 
| 154 | 
            +
             | 
| 149 155 | 
             
            class AgentFileSystemHandler(FileSystemEventHandler):
         | 
| 150 156 | 
             
                """Handles file system events for agent files."""
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                def __init__(self, tracker:  | 
| 157 | 
            +
             | 
| 158 | 
            +
                def __init__(self, tracker: "AgentModificationTracker"):
         | 
| 153 159 | 
             
                    self.tracker = tracker
         | 
| 154 160 | 
             
                    self.logger = logging.getLogger(__name__)
         | 
| 155 | 
            -
             | 
| 161 | 
            +
             | 
| 156 162 | 
             
                def on_created(self, event: FileSystemEvent) -> None:
         | 
| 157 163 | 
             
                    """Handle file creation events."""
         | 
| 158 | 
            -
                    if not event.is_directory and event.src_path.endswith( | 
| 164 | 
            +
                    if not event.is_directory and event.src_path.endswith(
         | 
| 165 | 
            +
                        (".md", ".json", ".yaml")
         | 
| 166 | 
            +
                    ):
         | 
| 159 167 | 
             
                        asyncio.create_task(
         | 
| 160 | 
            -
                            self.tracker._handle_file_modification( | 
| 168 | 
            +
                            self.tracker._handle_file_modification(
         | 
| 169 | 
            +
                                event.src_path, ModificationType.CREATE
         | 
| 170 | 
            +
                            )
         | 
| 161 171 | 
             
                        )
         | 
| 162 | 
            -
             | 
| 172 | 
            +
             | 
| 163 173 | 
             
                def on_modified(self, event: FileSystemEvent) -> None:
         | 
| 164 174 | 
             
                    """Handle file modification events."""
         | 
| 165 | 
            -
                    if not event.is_directory and event.src_path.endswith( | 
| 175 | 
            +
                    if not event.is_directory and event.src_path.endswith(
         | 
| 176 | 
            +
                        (".md", ".json", ".yaml")
         | 
| 177 | 
            +
                    ):
         | 
| 166 178 | 
             
                        asyncio.create_task(
         | 
| 167 | 
            -
                            self.tracker._handle_file_modification( | 
| 179 | 
            +
                            self.tracker._handle_file_modification(
         | 
| 180 | 
            +
                                event.src_path, ModificationType.MODIFY
         | 
| 181 | 
            +
                            )
         | 
| 168 182 | 
             
                        )
         | 
| 169 | 
            -
             | 
| 183 | 
            +
             | 
| 170 184 | 
             
                def on_deleted(self, event: FileSystemEvent) -> None:
         | 
| 171 185 | 
             
                    """Handle file deletion events."""
         | 
| 172 | 
            -
                    if not event.is_directory and event.src_path.endswith( | 
| 186 | 
            +
                    if not event.is_directory and event.src_path.endswith(
         | 
| 187 | 
            +
                        (".md", ".json", ".yaml")
         | 
| 188 | 
            +
                    ):
         | 
| 173 189 | 
             
                        asyncio.create_task(
         | 
| 174 | 
            -
                            self.tracker._handle_file_modification( | 
| 190 | 
            +
                            self.tracker._handle_file_modification(
         | 
| 191 | 
            +
                                event.src_path, ModificationType.DELETE
         | 
| 192 | 
            +
                            )
         | 
| 175 193 | 
             
                        )
         | 
| 176 | 
            -
             | 
| 194 | 
            +
             | 
| 177 195 | 
             
                def on_moved(self, event: FileSystemEvent) -> None:
         | 
| 178 196 | 
             
                    """Handle file move events."""
         | 
| 179 | 
            -
                    if not event.is_directory and event.src_path.endswith( | 
| 197 | 
            +
                    if not event.is_directory and event.src_path.endswith(
         | 
| 198 | 
            +
                        (".md", ".json", ".yaml")
         | 
| 199 | 
            +
                    ):
         | 
| 180 200 | 
             
                        asyncio.create_task(
         | 
| 181 201 | 
             
                            self.tracker._handle_file_move(event.src_path, event.dest_path)
         | 
| 182 202 | 
             
                        )
         | 
| @@ -186,170 +206,183 @@ class AgentFileSystemHandler(FileSystemEventHandler): | |
| 186 206 | 
             
            # Main Service Class
         | 
| 187 207 | 
             
            # ============================================================================
         | 
| 188 208 |  | 
| 209 | 
            +
             | 
| 189 210 | 
             
            class AgentModificationTracker(BaseService):
         | 
| 190 211 | 
             
                """
         | 
| 191 212 | 
             
                Agent Modification Tracker - Comprehensive modification tracking and persistence system.
         | 
| 192 | 
            -
             | 
| 213 | 
            +
             | 
| 193 214 | 
             
                This consolidated service combines all functionality from the previous multi-file
         | 
| 194 215 | 
             
                implementation into a single, maintainable module.
         | 
| 195 216 | 
             
                """
         | 
| 196 | 
            -
             | 
| 217 | 
            +
             | 
| 197 218 | 
             
                def __init__(self, config: Optional[Dict[str, Any]] = None):
         | 
| 198 219 | 
             
                    """Initialize the agent modification tracker."""
         | 
| 199 220 | 
             
                    super().__init__("agent_modification_tracker", config)
         | 
| 200 | 
            -
             | 
| 221 | 
            +
             | 
| 201 222 | 
             
                    # Configuration
         | 
| 202 223 | 
             
                    self.enable_monitoring = self.get_config("enable_monitoring", True)
         | 
| 203 224 | 
             
                    self.backup_enabled = self.get_config("backup_enabled", True)
         | 
| 204 225 | 
             
                    self.max_history_days = self.get_config("max_history_days", 30)
         | 
| 205 226 | 
             
                    self.validation_enabled = self.get_config("validation_enabled", True)
         | 
| 206 227 | 
             
                    self.persistence_interval = self.get_config("persistence_interval", 300)
         | 
| 207 | 
            -
             | 
| 228 | 
            +
             | 
| 208 229 | 
             
                    # Core components
         | 
| 209 230 | 
             
                    self.shared_cache: Optional[SharedPromptCache] = None
         | 
| 210 231 | 
             
                    self.agent_registry: Optional[AgentRegistry] = None
         | 
| 211 | 
            -
             | 
| 232 | 
            +
             | 
| 212 233 | 
             
                    # Tracking data structures
         | 
| 213 234 | 
             
                    self.modification_history: Dict[str, ModificationHistory] = {}
         | 
| 214 235 | 
             
                    self.active_modifications: Dict[str, AgentModification] = {}
         | 
| 215 | 
            -
             | 
| 236 | 
            +
             | 
| 216 237 | 
             
                    # File monitoring
         | 
| 217 238 | 
             
                    self.file_observer: Optional[Observer] = None
         | 
| 218 239 | 
             
                    self.watched_paths: Set[Path] = set()
         | 
| 219 | 
            -
             | 
| 240 | 
            +
             | 
| 220 241 | 
             
                    # Persistence paths
         | 
| 221 | 
            -
                    self.persistence_root =  | 
| 222 | 
            -
                    self.backup_root = self.persistence_root /  | 
| 223 | 
            -
                    self.history_root = self.persistence_root /  | 
| 224 | 
            -
             | 
| 242 | 
            +
                    self.persistence_root = get_path_manager().get_tracking_dir()
         | 
| 243 | 
            +
                    self.backup_root = self.persistence_root / "backups"
         | 
| 244 | 
            +
                    self.history_root = self.persistence_root / "history"
         | 
| 245 | 
            +
             | 
| 225 246 | 
             
                    # Create directories
         | 
| 226 247 | 
             
                    self.persistence_root.mkdir(parents=True, exist_ok=True)
         | 
| 227 248 | 
             
                    self.backup_root.mkdir(parents=True, exist_ok=True)
         | 
| 228 249 | 
             
                    self.history_root.mkdir(parents=True, exist_ok=True)
         | 
| 229 | 
            -
             | 
| 250 | 
            +
             | 
| 230 251 | 
             
                    # Background tasks
         | 
| 231 252 | 
             
                    self._persistence_task: Optional[asyncio.Task] = None
         | 
| 232 253 | 
             
                    self._cleanup_task: Optional[asyncio.Task] = None
         | 
| 233 | 
            -
             | 
| 254 | 
            +
             | 
| 234 255 | 
             
                    # Callbacks
         | 
| 235 256 | 
             
                    self.modification_callbacks: List[Callable[[AgentModification], None]] = []
         | 
| 236 | 
            -
             | 
| 257 | 
            +
             | 
| 237 258 | 
             
                    self.logger.info(
         | 
| 238 259 | 
             
                        f"AgentModificationTracker initialized with monitoring="
         | 
| 239 260 | 
             
                        f"{'enabled' if self.enable_monitoring else 'disabled'}"
         | 
| 240 261 | 
             
                    )
         | 
| 241 | 
            -
             | 
| 262 | 
            +
             | 
| 242 263 | 
             
                async def _initialize(self) -> None:
         | 
| 243 264 | 
             
                    """Initialize the modification tracker service."""
         | 
| 244 265 | 
             
                    self.logger.info("Initializing AgentModificationTracker service...")
         | 
| 245 | 
            -
             | 
| 266 | 
            +
             | 
| 246 267 | 
             
                    # Initialize cache and registry integration
         | 
| 247 268 | 
             
                    await self._initialize_integrations()
         | 
| 248 | 
            -
             | 
| 269 | 
            +
             | 
| 249 270 | 
             
                    # Load existing modification history
         | 
| 250 271 | 
             
                    await self._load_modification_history()
         | 
| 251 | 
            -
             | 
| 272 | 
            +
             | 
| 252 273 | 
             
                    # Set up file system monitoring
         | 
| 253 274 | 
             
                    if self.enable_monitoring:
         | 
| 254 275 | 
             
                        await self._setup_file_monitoring()
         | 
| 255 | 
            -
             | 
| 276 | 
            +
             | 
| 256 277 | 
             
                    # Start background tasks
         | 
| 257 278 | 
             
                    self._persistence_task = asyncio.create_task(self._persistence_loop())
         | 
| 258 279 | 
             
                    self._cleanup_task = asyncio.create_task(self._cleanup_loop())
         | 
| 259 | 
            -
             | 
| 280 | 
            +
             | 
| 260 281 | 
             
                    self.logger.info("AgentModificationTracker service initialized successfully")
         | 
| 261 | 
            -
             | 
| 282 | 
            +
             | 
| 262 283 | 
             
                async def _cleanup(self) -> None:
         | 
| 263 284 | 
             
                    """Cleanup modification tracker resources."""
         | 
| 264 285 | 
             
                    self.logger.info("Cleaning up AgentModificationTracker service...")
         | 
| 265 | 
            -
             | 
| 286 | 
            +
             | 
| 266 287 | 
             
                    # Stop file system monitoring
         | 
| 267 288 | 
             
                    if self.enable_monitoring and self.file_observer:
         | 
| 268 289 | 
             
                        self.file_observer.stop()
         | 
| 269 290 | 
             
                        self.file_observer.join()
         | 
| 270 | 
            -
             | 
| 291 | 
            +
             | 
| 271 292 | 
             
                    # Cancel background tasks
         | 
| 272 293 | 
             
                    if self._persistence_task:
         | 
| 273 294 | 
             
                        self._persistence_task.cancel()
         | 
| 274 295 | 
             
                    if self._cleanup_task:
         | 
| 275 296 | 
             
                        self._cleanup_task.cancel()
         | 
| 276 | 
            -
             | 
| 297 | 
            +
             | 
| 277 298 | 
             
                    # Save final state
         | 
| 278 299 | 
             
                    await self._save_modification_history()
         | 
| 279 | 
            -
             | 
| 300 | 
            +
             | 
| 280 301 | 
             
                    self.logger.info("AgentModificationTracker service cleaned up")
         | 
| 281 | 
            -
             | 
| 302 | 
            +
             | 
| 282 303 | 
             
                async def _health_check(self) -> Dict[str, bool]:
         | 
| 283 304 | 
             
                    """Perform modification tracker health checks."""
         | 
| 284 305 | 
             
                    checks = {}
         | 
| 285 | 
            -
             | 
| 306 | 
            +
             | 
| 286 307 | 
             
                    try:
         | 
| 287 308 | 
             
                        # Check persistence directories
         | 
| 288 | 
            -
                        checks["persistence_directories"] = all( | 
| 289 | 
            -
                             | 
| 290 | 
            -
             | 
| 291 | 
            -
             | 
| 292 | 
            -
             | 
| 293 | 
            -
             | 
| 309 | 
            +
                        checks["persistence_directories"] = all(
         | 
| 310 | 
            +
                            [
         | 
| 311 | 
            +
                                self.persistence_root.exists(),
         | 
| 312 | 
            +
                                self.backup_root.exists(),
         | 
| 313 | 
            +
                                self.history_root.exists(),
         | 
| 314 | 
            +
                            ]
         | 
| 315 | 
            +
                        )
         | 
| 316 | 
            +
             | 
| 294 317 | 
             
                        # Check file system monitoring
         | 
| 295 318 | 
             
                        checks["file_monitoring"] = (
         | 
| 296 | 
            -
                            self.file_observer is not None and 
         | 
| 297 | 
            -
                            self. | 
| 298 | 
            -
             | 
| 299 | 
            -
                        
         | 
| 319 | 
            +
                            (self.file_observer is not None and self.file_observer.is_alive())
         | 
| 320 | 
            +
                            if self.enable_monitoring
         | 
| 321 | 
            +
                            else True
         | 
| 322 | 
            +
                        )
         | 
| 323 | 
            +
             | 
| 300 324 | 
             
                        # Check integration components
         | 
| 301 325 | 
             
                        checks["cache_integration"] = self.shared_cache is not None
         | 
| 302 326 | 
             
                        checks["registry_integration"] = self.agent_registry is not None
         | 
| 303 | 
            -
             | 
| 327 | 
            +
             | 
| 304 328 | 
             
                        # Check background tasks
         | 
| 305 329 | 
             
                        checks["persistence_task"] = (
         | 
| 306 | 
            -
                            self._persistence_task is not None and 
         | 
| 307 | 
            -
                            not self._persistence_task.done()
         | 
| 330 | 
            +
                            self._persistence_task is not None and not self._persistence_task.done()
         | 
| 308 331 | 
             
                        )
         | 
| 309 332 | 
             
                        checks["cleanup_task"] = (
         | 
| 310 | 
            -
                            self._cleanup_task is not None and 
         | 
| 311 | 
            -
                            not self._cleanup_task.done()
         | 
| 333 | 
            +
                            self._cleanup_task is not None and not self._cleanup_task.done()
         | 
| 312 334 | 
             
                        )
         | 
| 313 | 
            -
             | 
| 335 | 
            +
             | 
| 314 336 | 
             
                        checks["modification_tracking"] = True
         | 
| 315 | 
            -
             | 
| 337 | 
            +
             | 
| 316 338 | 
             
                    except Exception as e:
         | 
| 317 339 | 
             
                        self.logger.error(f"Modification tracker health check failed: {e}")
         | 
| 318 340 | 
             
                        checks["health_check_error"] = False
         | 
| 319 | 
            -
             | 
| 341 | 
            +
             | 
| 320 342 | 
             
                    return checks
         | 
| 321 | 
            -
             | 
| 343 | 
            +
             | 
| 322 344 | 
             
                # ========================================================================
         | 
| 323 345 | 
             
                # Core Functionality
         | 
| 324 346 | 
             
                # ========================================================================
         | 
| 325 | 
            -
             | 
| 326 | 
            -
                async def track_modification( | 
| 327 | 
            -
             | 
| 328 | 
            -
             | 
| 329 | 
            -
             | 
| 330 | 
            -
             | 
| 331 | 
            -
             | 
| 347 | 
            +
             | 
| 348 | 
            +
                async def track_modification(
         | 
| 349 | 
            +
                    self,
         | 
| 350 | 
            +
                    agent_name: str,
         | 
| 351 | 
            +
                    modification_type: ModificationType,
         | 
| 352 | 
            +
                    file_path: str,
         | 
| 353 | 
            +
                    tier: ModificationTier,
         | 
| 354 | 
            +
                    **kwargs,
         | 
| 355 | 
            +
                ) -> AgentModification:
         | 
| 332 356 | 
             
                    """Track an agent modification with comprehensive metadata collection."""
         | 
| 333 357 | 
             
                    # Generate modification ID
         | 
| 334 | 
            -
                    modification_id =  | 
| 335 | 
            -
             | 
| 358 | 
            +
                    modification_id = (
         | 
| 359 | 
            +
                        f"{agent_name}_{modification_type.value}_{uuid.uuid4().hex[:8]}"
         | 
| 360 | 
            +
                    )
         | 
| 361 | 
            +
             | 
| 336 362 | 
             
                    # Collect file metadata
         | 
| 337 363 | 
             
                    file_metadata = await self._collect_file_metadata(file_path, modification_type)
         | 
| 338 | 
            -
             | 
| 364 | 
            +
             | 
| 339 365 | 
             
                    # Create backup if enabled
         | 
| 340 366 | 
             
                    backup_path = None
         | 
| 341 | 
            -
                    if self.backup_enabled and modification_type in [ | 
| 367 | 
            +
                    if self.backup_enabled and modification_type in [
         | 
| 368 | 
            +
                        ModificationType.MODIFY,
         | 
| 369 | 
            +
                        ModificationType.DELETE,
         | 
| 370 | 
            +
                    ]:
         | 
| 342 371 | 
             
                        backup_path = await self._create_backup(file_path, modification_id)
         | 
| 343 | 
            -
             | 
| 372 | 
            +
             | 
| 344 373 | 
             
                    # Create modification record
         | 
| 345 374 | 
             
                    # Only include valid AgentModification fields from file_metadata
         | 
| 346 | 
            -
                    valid_metadata_fields = { | 
| 347 | 
            -
                    filtered_metadata = { | 
| 348 | 
            -
             | 
| 375 | 
            +
                    valid_metadata_fields = {"file_hash_after", "file_size_after"}
         | 
| 376 | 
            +
                    filtered_metadata = {
         | 
| 377 | 
            +
                        k: v for k, v in file_metadata.items() if k in valid_metadata_fields
         | 
| 378 | 
            +
                    }
         | 
| 379 | 
            +
             | 
| 349 380 | 
             
                    # Add other metadata to the metadata field
         | 
| 350 | 
            -
                    extra_metadata = { | 
| 381 | 
            +
                    extra_metadata = {
         | 
| 382 | 
            +
                        k: v for k, v in file_metadata.items() if k not in valid_metadata_fields
         | 
| 383 | 
            +
                    }
         | 
| 351 384 | 
             
                    extra_metadata.update(kwargs)
         | 
| 352 | 
            -
             | 
| 385 | 
            +
             | 
| 353 386 | 
             
                    modification = AgentModification(
         | 
| 354 387 | 
             
                        modification_id=modification_id,
         | 
| 355 388 | 
             
                        agent_name=agent_name,
         | 
| @@ -359,39 +392,41 @@ class AgentModificationTracker(BaseService): | |
| 359 392 | 
             
                        timestamp=time.time(),
         | 
| 360 393 | 
             
                        backup_path=backup_path,
         | 
| 361 394 | 
             
                        metadata=extra_metadata,
         | 
| 362 | 
            -
                        **filtered_metadata
         | 
| 395 | 
            +
                        **filtered_metadata,
         | 
| 363 396 | 
             
                    )
         | 
| 364 | 
            -
             | 
| 397 | 
            +
             | 
| 365 398 | 
             
                    # Validate modification if enabled
         | 
| 366 399 | 
             
                    if self.validation_enabled:
         | 
| 367 400 | 
             
                        await self._validate_modification(modification)
         | 
| 368 | 
            -
             | 
| 401 | 
            +
             | 
| 369 402 | 
             
                    # Store in active modifications
         | 
| 370 403 | 
             
                    self.active_modifications[modification_id] = modification
         | 
| 371 | 
            -
             | 
| 404 | 
            +
             | 
| 372 405 | 
             
                    # Add to history
         | 
| 373 406 | 
             
                    if agent_name not in self.modification_history:
         | 
| 374 | 
            -
                        self.modification_history[agent_name] = ModificationHistory( | 
| 375 | 
            -
             | 
| 407 | 
            +
                        self.modification_history[agent_name] = ModificationHistory(
         | 
| 408 | 
            +
                            agent_name=agent_name
         | 
| 409 | 
            +
                        )
         | 
| 410 | 
            +
             | 
| 376 411 | 
             
                    self.modification_history[agent_name].add_modification(modification)
         | 
| 377 | 
            -
             | 
| 412 | 
            +
             | 
| 378 413 | 
             
                    # Invalidate cache
         | 
| 379 414 | 
             
                    if self.shared_cache:
         | 
| 380 415 | 
             
                        await self._invalidate_agent_cache(agent_name)
         | 
| 381 | 
            -
             | 
| 416 | 
            +
             | 
| 382 417 | 
             
                    # Trigger callbacks
         | 
| 383 418 | 
             
                    await self._trigger_modification_callbacks(modification)
         | 
| 384 | 
            -
             | 
| 419 | 
            +
             | 
| 385 420 | 
             
                    self.logger.info(
         | 
| 386 421 | 
             
                        f"Tracked {modification_type.value} modification for agent '{agent_name}': {modification_id}"
         | 
| 387 422 | 
             
                    )
         | 
| 388 | 
            -
             | 
| 423 | 
            +
             | 
| 389 424 | 
             
                    return modification
         | 
| 390 | 
            -
             | 
| 425 | 
            +
             | 
| 391 426 | 
             
                # ========================================================================
         | 
| 392 427 | 
             
                # Helper Methods
         | 
| 393 428 | 
             
                # ========================================================================
         | 
| 394 | 
            -
             | 
| 429 | 
            +
             | 
| 395 430 | 
             
                async def _initialize_integrations(self) -> None:
         | 
| 396 431 | 
             
                    """Initialize cache and registry integrations."""
         | 
| 397 432 | 
             
                    try:
         | 
| @@ -400,115 +435,125 @@ class AgentModificationTracker(BaseService): | |
| 400 435 | 
             
                        self.logger.info("Successfully initialized cache and registry integrations")
         | 
| 401 436 | 
             
                    except Exception as e:
         | 
| 402 437 | 
             
                        self.logger.warning(f"Failed to initialize integrations: {e}")
         | 
| 403 | 
            -
             | 
| 438 | 
            +
             | 
| 404 439 | 
             
                async def _setup_file_monitoring(self) -> None:
         | 
| 405 440 | 
             
                    """Set up file system monitoring for agent files."""
         | 
| 406 441 | 
             
                    try:
         | 
| 407 442 | 
             
                        self.file_observer = Observer()
         | 
| 408 443 | 
             
                        event_handler = AgentFileSystemHandler(self)
         | 
| 409 | 
            -
             | 
| 444 | 
            +
             | 
| 410 445 | 
             
                        # Monitor standard agent directories
         | 
| 411 446 | 
             
                        agent_dirs = [
         | 
| 412 447 | 
             
                            Path("agents"),
         | 
| 413 448 | 
             
                            Path("src/claude_mpm/agents"),
         | 
| 414 | 
            -
                             | 
| 449 | 
            +
                            get_path_manager().get_user_agents_dir(),
         | 
| 415 450 | 
             
                        ]
         | 
| 416 | 
            -
             | 
| 451 | 
            +
             | 
| 417 452 | 
             
                        for agent_dir in agent_dirs:
         | 
| 418 453 | 
             
                            if agent_dir.exists():
         | 
| 419 | 
            -
                                self.file_observer.schedule( | 
| 454 | 
            +
                                self.file_observer.schedule(
         | 
| 455 | 
            +
                                    event_handler, str(agent_dir), recursive=True
         | 
| 456 | 
            +
                                )
         | 
| 420 457 | 
             
                                self.watched_paths.add(agent_dir)
         | 
| 421 458 | 
             
                                self.logger.info(f"Monitoring agent directory: {agent_dir}")
         | 
| 422 | 
            -
             | 
| 459 | 
            +
             | 
| 423 460 | 
             
                        self.file_observer.start()
         | 
| 424 | 
            -
             | 
| 461 | 
            +
             | 
| 425 462 | 
             
                    except Exception as e:
         | 
| 426 463 | 
             
                        self.logger.error(f"Failed to setup file monitoring: {e}")
         | 
| 427 | 
            -
             | 
| 428 | 
            -
                async def _collect_file_metadata( | 
| 464 | 
            +
             | 
| 465 | 
            +
                async def _collect_file_metadata(
         | 
| 466 | 
            +
                    self, file_path: str, modification_type: ModificationType
         | 
| 467 | 
            +
                ) -> Dict[str, Any]:
         | 
| 429 468 | 
             
                    """Collect comprehensive file metadata."""
         | 
| 430 469 | 
             
                    metadata = {}
         | 
| 431 | 
            -
             | 
| 470 | 
            +
             | 
| 432 471 | 
             
                    try:
         | 
| 433 472 | 
             
                        path = Path(file_path)
         | 
| 434 | 
            -
             | 
| 473 | 
            +
             | 
| 435 474 | 
             
                        if path.exists() and modification_type != ModificationType.DELETE:
         | 
| 436 475 | 
             
                            # File size
         | 
| 437 | 
            -
                            metadata[ | 
| 438 | 
            -
             | 
| 476 | 
            +
                            metadata["file_size_after"] = path.stat().st_size
         | 
| 477 | 
            +
             | 
| 439 478 | 
             
                            # File hash
         | 
| 440 | 
            -
                            with open(path,  | 
| 441 | 
            -
                                metadata[ | 
| 442 | 
            -
             | 
| 479 | 
            +
                            with open(path, "rb") as f:
         | 
| 480 | 
            +
                                metadata["file_hash_after"] = hashlib.sha256(f.read()).hexdigest()
         | 
| 481 | 
            +
             | 
| 443 482 | 
             
                            # File type
         | 
| 444 | 
            -
                            metadata[ | 
| 445 | 
            -
             | 
| 483 | 
            +
                            metadata["file_type"] = path.suffix
         | 
| 484 | 
            +
             | 
| 446 485 | 
             
                            # Modification time
         | 
| 447 | 
            -
                            metadata[ | 
| 448 | 
            -
             | 
| 486 | 
            +
                            metadata["mtime"] = path.stat().st_mtime
         | 
| 487 | 
            +
             | 
| 449 488 | 
             
                    except Exception as e:
         | 
| 450 489 | 
             
                        self.logger.error(f"Error collecting file metadata: {e}")
         | 
| 451 | 
            -
             | 
| 490 | 
            +
             | 
| 452 491 | 
             
                    return metadata
         | 
| 453 | 
            -
             | 
| 454 | 
            -
                async def _create_backup( | 
| 492 | 
            +
             | 
| 493 | 
            +
                async def _create_backup(
         | 
| 494 | 
            +
                    self, file_path: str, modification_id: str
         | 
| 495 | 
            +
                ) -> Optional[str]:
         | 
| 455 496 | 
             
                    """Create backup of agent file."""
         | 
| 456 497 | 
             
                    try:
         | 
| 457 498 | 
             
                        source = Path(file_path)
         | 
| 458 499 | 
             
                        if not source.exists():
         | 
| 459 500 | 
             
                            return None
         | 
| 460 | 
            -
             | 
| 501 | 
            +
             | 
| 461 502 | 
             
                        # Create backup directory for this modification
         | 
| 462 503 | 
             
                        backup_dir = self.backup_root / modification_id
         | 
| 463 504 | 
             
                        backup_dir.mkdir(parents=True, exist_ok=True)
         | 
| 464 | 
            -
             | 
| 505 | 
            +
             | 
| 465 506 | 
             
                        # Create backup file
         | 
| 466 507 | 
             
                        backup_path = backup_dir / source.name
         | 
| 467 508 | 
             
                        shutil.copy2(source, backup_path)
         | 
| 468 | 
            -
             | 
| 509 | 
            +
             | 
| 469 510 | 
             
                        # Save backup metadata
         | 
| 470 511 | 
             
                        metadata = {
         | 
| 471 | 
            -
                             | 
| 472 | 
            -
                             | 
| 473 | 
            -
                             | 
| 512 | 
            +
                            "original_path": str(file_path),
         | 
| 513 | 
            +
                            "backup_time": time.time(),
         | 
| 514 | 
            +
                            "modification_id": modification_id,
         | 
| 474 515 | 
             
                        }
         | 
| 475 | 
            -
             | 
| 476 | 
            -
                        metadata_path = backup_dir /  | 
| 477 | 
            -
                        with open(metadata_path,  | 
| 516 | 
            +
             | 
| 517 | 
            +
                        metadata_path = backup_dir / "metadata.json"
         | 
| 518 | 
            +
                        with open(metadata_path, "w") as f:
         | 
| 478 519 | 
             
                            json.dump(metadata, f, indent=2)
         | 
| 479 | 
            -
             | 
| 520 | 
            +
             | 
| 480 521 | 
             
                        return str(backup_path)
         | 
| 481 | 
            -
             | 
| 522 | 
            +
             | 
| 482 523 | 
             
                    except Exception as e:
         | 
| 483 524 | 
             
                        self.logger.error(f"Failed to create backup: {e}")
         | 
| 484 525 | 
             
                        return None
         | 
| 485 | 
            -
             | 
| 526 | 
            +
             | 
| 486 527 | 
             
                async def _validate_modification(self, modification: AgentModification) -> None:
         | 
| 487 528 | 
             
                    """Validate agent modification."""
         | 
| 488 529 | 
             
                    errors = []
         | 
| 489 | 
            -
             | 
| 530 | 
            +
             | 
| 490 531 | 
             
                    try:
         | 
| 491 532 | 
             
                        # Check for conflicts
         | 
| 492 533 | 
             
                        for mod_id, active_mod in self.active_modifications.items():
         | 
| 493 | 
            -
                            if ( | 
| 494 | 
            -
                                active_mod. | 
| 495 | 
            -
                                active_mod. | 
| 496 | 
            -
                                 | 
| 497 | 
            -
             | 
| 534 | 
            +
                            if (
         | 
| 535 | 
            +
                                active_mod.agent_name == modification.agent_name
         | 
| 536 | 
            +
                                and active_mod.modification_id != modification.modification_id
         | 
| 537 | 
            +
                                and active_mod.age_seconds < 60
         | 
| 538 | 
            +
                            ):  # Recent modification
         | 
| 539 | 
            +
                                errors.append(
         | 
| 540 | 
            +
                                    f"Potential conflict with recent modification: {mod_id}"
         | 
| 541 | 
            +
                                )
         | 
| 542 | 
            +
             | 
| 498 543 | 
             
                        # Validate file path
         | 
| 499 544 | 
             
                        if modification.modification_type != ModificationType.DELETE:
         | 
| 500 545 | 
             
                            if not Path(modification.file_path).exists():
         | 
| 501 546 | 
             
                                errors.append(f"File does not exist: {modification.file_path}")
         | 
| 502 | 
            -
             | 
| 547 | 
            +
             | 
| 503 548 | 
             
                        # Update validation status
         | 
| 504 549 | 
             
                        modification.validation_status = "failed" if errors else "passed"
         | 
| 505 550 | 
             
                        modification.validation_errors = errors
         | 
| 506 | 
            -
             | 
| 551 | 
            +
             | 
| 507 552 | 
             
                    except Exception as e:
         | 
| 508 553 | 
             
                        self.logger.error(f"Validation error: {e}")
         | 
| 509 554 | 
             
                        modification.validation_status = "error"
         | 
| 510 555 | 
             
                        modification.validation_errors.append(str(e))
         | 
| 511 | 
            -
             | 
| 556 | 
            +
             | 
| 512 557 | 
             
                async def _invalidate_agent_cache(self, agent_name: str) -> None:
         | 
| 513 558 | 
             
                    """Invalidate cache entries for modified agent."""
         | 
| 514 559 | 
             
                    if self.shared_cache:
         | 
| @@ -518,34 +563,36 @@ class AgentModificationTracker(BaseService): | |
| 518 563 | 
             
                            self.logger.debug(f"Invalidated cache for agent: {agent_name}")
         | 
| 519 564 | 
             
                        except Exception as e:
         | 
| 520 565 | 
             
                            self.logger.error(f"Failed to invalidate cache: {e}")
         | 
| 521 | 
            -
             | 
| 522 | 
            -
                async def _handle_file_modification( | 
| 566 | 
            +
             | 
| 567 | 
            +
                async def _handle_file_modification(
         | 
| 568 | 
            +
                    self, file_path: str, modification_type: ModificationType
         | 
| 569 | 
            +
                ) -> None:
         | 
| 523 570 | 
             
                    """Handle file system modification events."""
         | 
| 524 571 | 
             
                    try:
         | 
| 525 572 | 
             
                        # Extract agent information from path
         | 
| 526 573 | 
             
                        agent_info = self._extract_agent_info_from_path(file_path)
         | 
| 527 574 | 
             
                        if not agent_info:
         | 
| 528 575 | 
             
                            return
         | 
| 529 | 
            -
             | 
| 576 | 
            +
             | 
| 530 577 | 
             
                        agent_name, tier = agent_info
         | 
| 531 | 
            -
             | 
| 578 | 
            +
             | 
| 532 579 | 
             
                        # Track the modification
         | 
| 533 580 | 
             
                        await self.track_modification(
         | 
| 534 581 | 
             
                            agent_name=agent_name,
         | 
| 535 582 | 
             
                            modification_type=modification_type,
         | 
| 536 583 | 
             
                            file_path=file_path,
         | 
| 537 584 | 
             
                            tier=tier,
         | 
| 538 | 
            -
                            source="file_system_monitor"
         | 
| 585 | 
            +
                            source="file_system_monitor",
         | 
| 539 586 | 
             
                        )
         | 
| 540 | 
            -
             | 
| 587 | 
            +
             | 
| 541 588 | 
             
                    except Exception as e:
         | 
| 542 589 | 
             
                        self.logger.error(f"Error handling file modification {file_path}: {e}")
         | 
| 543 | 
            -
             | 
| 590 | 
            +
             | 
| 544 591 | 
             
                async def _handle_file_move(self, src_path: str, dest_path: str) -> None:
         | 
| 545 592 | 
             
                    """Handle file move events."""
         | 
| 546 593 | 
             
                    try:
         | 
| 547 594 | 
             
                        src_info = self._extract_agent_info_from_path(src_path)
         | 
| 548 | 
            -
             | 
| 595 | 
            +
             | 
| 549 596 | 
             
                        if src_info:
         | 
| 550 597 | 
             
                            agent_name, tier = src_info
         | 
| 551 598 | 
             
                            await self.track_modification(
         | 
| @@ -555,39 +602,48 @@ class AgentModificationTracker(BaseService): | |
| 555 602 | 
             
                                tier=tier,
         | 
| 556 603 | 
             
                                source="file_system_monitor",
         | 
| 557 604 | 
             
                                move_source=src_path,
         | 
| 558 | 
            -
                                move_destination=dest_path
         | 
| 605 | 
            +
                                move_destination=dest_path,
         | 
| 559 606 | 
             
                            )
         | 
| 560 | 
            -
             | 
| 607 | 
            +
             | 
| 561 608 | 
             
                    except Exception as e:
         | 
| 562 | 
            -
                        self.logger.error( | 
| 563 | 
            -
             | 
| 564 | 
            -
             | 
| 609 | 
            +
                        self.logger.error(
         | 
| 610 | 
            +
                            f"Error handling file move {src_path} -> {dest_path}: {e}"
         | 
| 611 | 
            +
                        )
         | 
| 612 | 
            +
             | 
| 613 | 
            +
                def _extract_agent_info_from_path(
         | 
| 614 | 
            +
                    self, file_path: str
         | 
| 615 | 
            +
                ) -> Optional[Tuple[str, ModificationTier]]:
         | 
| 565 616 | 
             
                    """Extract agent name and tier from file path."""
         | 
| 566 617 | 
             
                    try:
         | 
| 567 618 | 
             
                        path = Path(file_path)
         | 
| 568 | 
            -
             | 
| 619 | 
            +
             | 
| 569 620 | 
             
                        # Extract agent name from filename
         | 
| 570 621 | 
             
                        agent_name = path.stem
         | 
| 571 | 
            -
                        if agent_name.endswith( | 
| 622 | 
            +
                        if agent_name.endswith("_agent"):
         | 
| 572 623 | 
             
                            agent_name = agent_name[:-6]  # Remove _agent suffix
         | 
| 573 | 
            -
                        elif agent_name.endswith( | 
| 624 | 
            +
                        elif agent_name.endswith("-agent"):
         | 
| 574 625 | 
             
                            agent_name = agent_name[:-6]  # Remove -agent suffix
         | 
| 575 | 
            -
             | 
| 626 | 
            +
             | 
| 576 627 | 
             
                        # Determine tier based on path
         | 
| 577 628 | 
             
                        path_str = str(path).lower()
         | 
| 578 | 
            -
                        if  | 
| 629 | 
            +
                        if "system" in path_str or "/claude_mpm/agents/" in path_str:
         | 
| 579 630 | 
             
                            tier = ModificationTier.SYSTEM
         | 
| 580 | 
            -
                        elif  | 
| 631 | 
            +
                        elif (
         | 
| 632 | 
            +
                            get_path_manager().CONFIG_DIR.lower() in path_str
         | 
| 633 | 
            +
                            or str(Path.home()) in path_str
         | 
| 634 | 
            +
                        ):
         | 
| 581 635 | 
             
                            tier = ModificationTier.USER
         | 
| 582 636 | 
             
                        else:
         | 
| 583 637 | 
             
                            tier = ModificationTier.PROJECT
         | 
| 584 | 
            -
             | 
| 638 | 
            +
             | 
| 585 639 | 
             
                        return agent_name, tier
         | 
| 586 | 
            -
             | 
| 640 | 
            +
             | 
| 587 641 | 
             
                    except Exception:
         | 
| 588 642 | 
             
                        return None
         | 
| 589 | 
            -
             | 
| 590 | 
            -
                async def _trigger_modification_callbacks( | 
| 643 | 
            +
             | 
| 644 | 
            +
                async def _trigger_modification_callbacks(
         | 
| 645 | 
            +
                    self, modification: AgentModification
         | 
| 646 | 
            +
                ) -> None:
         | 
| 591 647 | 
             
                    """Trigger registered modification callbacks."""
         | 
| 592 648 | 
             
                    for callback in self.modification_callbacks:
         | 
| 593 649 | 
             
                        try:
         | 
| @@ -597,78 +653,78 @@ class AgentModificationTracker(BaseService): | |
| 597 653 | 
             
                                callback(modification)
         | 
| 598 654 | 
             
                        except Exception as e:
         | 
| 599 655 | 
             
                            self.logger.error(f"Modification callback failed: {e}")
         | 
| 600 | 
            -
             | 
| 656 | 
            +
             | 
| 601 657 | 
             
                # ========================================================================
         | 
| 602 658 | 
             
                # Persistence Methods
         | 
| 603 659 | 
             
                # ========================================================================
         | 
| 604 | 
            -
             | 
| 660 | 
            +
             | 
| 605 661 | 
             
                async def _load_modification_history(self) -> None:
         | 
| 606 662 | 
             
                    """Load modification history from disk."""
         | 
| 607 663 | 
             
                    try:
         | 
| 608 664 | 
             
                        # Load active modifications
         | 
| 609 | 
            -
                        active_path = self.persistence_root /  | 
| 665 | 
            +
                        active_path = self.persistence_root / "active_modifications.json"
         | 
| 610 666 | 
             
                        if active_path.exists():
         | 
| 611 | 
            -
                            with open(active_path,  | 
| 667 | 
            +
                            with open(active_path, "r") as f:
         | 
| 612 668 | 
             
                                data = json.load(f)
         | 
| 613 669 | 
             
                                self.active_modifications = {
         | 
| 614 670 | 
             
                                    k: AgentModification.from_dict(v) for k, v in data.items()
         | 
| 615 671 | 
             
                                }
         | 
| 616 | 
            -
             | 
| 672 | 
            +
             | 
| 617 673 | 
             
                        # Load modification history
         | 
| 618 | 
            -
                        for history_file in self.history_root.glob( | 
| 619 | 
            -
                            with open(history_file,  | 
| 674 | 
            +
                        for history_file in self.history_root.glob("*.json"):
         | 
| 675 | 
            +
                            with open(history_file, "r") as f:
         | 
| 620 676 | 
             
                                data = json.load(f)
         | 
| 621 | 
            -
                                agent_name = data[ | 
| 677 | 
            +
                                agent_name = data["agent_name"]
         | 
| 622 678 | 
             
                                history = ModificationHistory(agent_name=agent_name)
         | 
| 623 | 
            -
             | 
| 679 | 
            +
             | 
| 624 680 | 
             
                                # Recreate modifications
         | 
| 625 | 
            -
                                for mod_data in data.get( | 
| 681 | 
            +
                                for mod_data in data.get("modifications", []):
         | 
| 626 682 | 
             
                                    history.add_modification(AgentModification.from_dict(mod_data))
         | 
| 627 | 
            -
             | 
| 628 | 
            -
                                history.current_version = data.get( | 
| 629 | 
            -
                                history.first_seen = data.get( | 
| 630 | 
            -
                                history.last_modified = data.get( | 
| 631 | 
            -
             | 
| 683 | 
            +
             | 
| 684 | 
            +
                                history.current_version = data.get("current_version")
         | 
| 685 | 
            +
                                history.first_seen = data.get("first_seen")
         | 
| 686 | 
            +
                                history.last_modified = data.get("last_modified")
         | 
| 687 | 
            +
             | 
| 632 688 | 
             
                                self.modification_history[agent_name] = history
         | 
| 633 | 
            -
             | 
| 689 | 
            +
             | 
| 634 690 | 
             
                        self.logger.info(
         | 
| 635 691 | 
             
                            f"Loaded {len(self.active_modifications)} active modifications and "
         | 
| 636 692 | 
             
                            f"{len(self.modification_history)} agent histories"
         | 
| 637 693 | 
             
                        )
         | 
| 638 | 
            -
             | 
| 694 | 
            +
             | 
| 639 695 | 
             
                    except Exception as e:
         | 
| 640 696 | 
             
                        self.logger.error(f"Failed to load modification history: {e}")
         | 
| 641 | 
            -
             | 
| 697 | 
            +
             | 
| 642 698 | 
             
                async def _save_modification_history(self) -> None:
         | 
| 643 699 | 
             
                    """Save modification history to disk."""
         | 
| 644 700 | 
             
                    try:
         | 
| 645 701 | 
             
                        # Save active modifications
         | 
| 646 702 | 
             
                        active_data = {k: v.to_dict() for k, v in self.active_modifications.items()}
         | 
| 647 | 
            -
                        active_path = self.persistence_root /  | 
| 648 | 
            -
             | 
| 649 | 
            -
                        with open(active_path,  | 
| 703 | 
            +
                        active_path = self.persistence_root / "active_modifications.json"
         | 
| 704 | 
            +
             | 
| 705 | 
            +
                        with open(active_path, "w") as f:
         | 
| 650 706 | 
             
                            json.dump(active_data, f, indent=2)
         | 
| 651 | 
            -
             | 
| 707 | 
            +
             | 
| 652 708 | 
             
                        # Save modification history
         | 
| 653 709 | 
             
                        for agent_name, history in self.modification_history.items():
         | 
| 654 710 | 
             
                            history_data = {
         | 
| 655 | 
            -
                                 | 
| 656 | 
            -
                                 | 
| 657 | 
            -
                                 | 
| 658 | 
            -
                                 | 
| 659 | 
            -
                                 | 
| 660 | 
            -
                                 | 
| 711 | 
            +
                                "agent_name": history.agent_name,
         | 
| 712 | 
            +
                                "modifications": [mod.to_dict() for mod in history.modifications],
         | 
| 713 | 
            +
                                "current_version": history.current_version,
         | 
| 714 | 
            +
                                "total_modifications": history.total_modifications,
         | 
| 715 | 
            +
                                "first_seen": history.first_seen,
         | 
| 716 | 
            +
                                "last_modified": history.last_modified,
         | 
| 661 717 | 
             
                            }
         | 
| 662 | 
            -
             | 
| 718 | 
            +
             | 
| 663 719 | 
             
                            history_path = self.history_root / f"{agent_name}_history.json"
         | 
| 664 | 
            -
                            with open(history_path,  | 
| 720 | 
            +
                            with open(history_path, "w") as f:
         | 
| 665 721 | 
             
                                json.dump(history_data, f, indent=2)
         | 
| 666 | 
            -
             | 
| 722 | 
            +
             | 
| 667 723 | 
             
                        self.logger.debug("Saved modification history to disk")
         | 
| 668 | 
            -
             | 
| 724 | 
            +
             | 
| 669 725 | 
             
                    except Exception as e:
         | 
| 670 726 | 
             
                        self.logger.error(f"Failed to save modification history: {e}")
         | 
| 671 | 
            -
             | 
| 727 | 
            +
             | 
| 672 728 | 
             
                async def _persistence_loop(self) -> None:
         | 
| 673 729 | 
             
                    """Background task to persist modification history."""
         | 
| 674 730 | 
             
                    while not self._stop_event.is_set():
         | 
| @@ -680,7 +736,7 @@ class AgentModificationTracker(BaseService): | |
| 680 736 | 
             
                        except Exception as e:
         | 
| 681 737 | 
             
                            self.logger.error(f"Persistence loop error: {e}")
         | 
| 682 738 | 
             
                            await asyncio.sleep(self.persistence_interval)
         | 
| 683 | 
            -
             | 
| 739 | 
            +
             | 
| 684 740 | 
             
                async def _cleanup_loop(self) -> None:
         | 
| 685 741 | 
             
                    """Background task to cleanup old modifications and backups."""
         | 
| 686 742 | 
             
                    while not self._stop_event.is_set():
         | 
| @@ -692,159 +748,169 @@ class AgentModificationTracker(BaseService): | |
| 692 748 | 
             
                        except Exception as e:
         | 
| 693 749 | 
             
                            self.logger.error(f"Cleanup loop error: {e}")
         | 
| 694 750 | 
             
                            await asyncio.sleep(3600)
         | 
| 695 | 
            -
             | 
| 751 | 
            +
             | 
| 696 752 | 
             
                async def _cleanup_old_data(self) -> None:
         | 
| 697 753 | 
             
                    """Clean up old modifications and backups."""
         | 
| 698 754 | 
             
                    try:
         | 
| 699 755 | 
             
                        cutoff_time = time.time() - (self.max_history_days * 24 * 3600)
         | 
| 700 | 
            -
             | 
| 756 | 
            +
             | 
| 701 757 | 
             
                        # Clean up old modifications from active list
         | 
| 702 758 | 
             
                        old_active = [
         | 
| 703 | 
            -
                            mod_id | 
| 759 | 
            +
                            mod_id
         | 
| 760 | 
            +
                            for mod_id, mod in self.active_modifications.items()
         | 
| 704 761 | 
             
                            if mod.timestamp < cutoff_time
         | 
| 705 762 | 
             
                        ]
         | 
| 706 | 
            -
             | 
| 763 | 
            +
             | 
| 707 764 | 
             
                        for mod_id in old_active:
         | 
| 708 765 | 
             
                            del self.active_modifications[mod_id]
         | 
| 709 | 
            -
             | 
| 766 | 
            +
             | 
| 710 767 | 
             
                        # Clean up old backups
         | 
| 711 768 | 
             
                        backup_count = 0
         | 
| 712 769 | 
             
                        for backup_dir in self.backup_root.iterdir():
         | 
| 713 770 | 
             
                            if backup_dir.is_dir():
         | 
| 714 | 
            -
                                metadata_path = backup_dir /  | 
| 771 | 
            +
                                metadata_path = backup_dir / "metadata.json"
         | 
| 715 772 | 
             
                                if metadata_path.exists():
         | 
| 716 | 
            -
                                    with open(metadata_path,  | 
| 773 | 
            +
                                    with open(metadata_path, "r") as f:
         | 
| 717 774 | 
             
                                        metadata = json.load(f)
         | 
| 718 | 
            -
                                        if metadata.get( | 
| 775 | 
            +
                                        if metadata.get("backup_time", 0) < cutoff_time:
         | 
| 719 776 | 
             
                                            shutil.rmtree(backup_dir)
         | 
| 720 777 | 
             
                                            backup_count += 1
         | 
| 721 | 
            -
             | 
| 778 | 
            +
             | 
| 722 779 | 
             
                        if old_active or backup_count > 0:
         | 
| 723 780 | 
             
                            self.logger.info(
         | 
| 724 781 | 
             
                                f"Cleaned up {len(old_active)} old modifications and {backup_count} old backups"
         | 
| 725 782 | 
             
                            )
         | 
| 726 | 
            -
             | 
| 783 | 
            +
             | 
| 727 784 | 
             
                    except Exception as e:
         | 
| 728 785 | 
             
                        self.logger.error(f"Failed to cleanup old data: {e}")
         | 
| 729 | 
            -
             | 
| 786 | 
            +
             | 
| 730 787 | 
             
                # ========================================================================
         | 
| 731 788 | 
             
                # Public API Methods
         | 
| 732 789 | 
             
                # ========================================================================
         | 
| 733 | 
            -
             | 
| 734 | 
            -
                async def get_modification_history( | 
| 790 | 
            +
             | 
| 791 | 
            +
                async def get_modification_history(
         | 
| 792 | 
            +
                    self, agent_name: str
         | 
| 793 | 
            +
                ) -> Optional[ModificationHistory]:
         | 
| 735 794 | 
             
                    """Get modification history for specific agent."""
         | 
| 736 795 | 
             
                    return self.modification_history.get(agent_name)
         | 
| 737 | 
            -
             | 
| 738 | 
            -
                async def get_recent_modifications( | 
| 796 | 
            +
             | 
| 797 | 
            +
                async def get_recent_modifications(
         | 
| 798 | 
            +
                    self, hours: int = 24
         | 
| 799 | 
            +
                ) -> List[AgentModification]:
         | 
| 739 800 | 
             
                    """Get all recent modifications across all agents."""
         | 
| 740 801 | 
             
                    cutoff = time.time() - (hours * 3600)
         | 
| 741 802 | 
             
                    recent = []
         | 
| 742 | 
            -
             | 
| 803 | 
            +
             | 
| 743 804 | 
             
                    for history in self.modification_history.values():
         | 
| 744 | 
            -
                        recent.extend( | 
| 745 | 
            -
                            mod for mod in history.modifications 
         | 
| 746 | 
            -
             | 
| 747 | 
            -
             | 
| 748 | 
            -
                    
         | 
| 805 | 
            +
                        recent.extend(
         | 
| 806 | 
            +
                            [mod for mod in history.modifications if mod.timestamp >= cutoff]
         | 
| 807 | 
            +
                        )
         | 
| 808 | 
            +
             | 
| 749 809 | 
             
                    return sorted(recent, key=lambda x: x.timestamp, reverse=True)
         | 
| 750 | 
            -
             | 
| 810 | 
            +
             | 
| 751 811 | 
             
                async def restore_agent_backup(self, modification_id: str) -> bool:
         | 
| 752 812 | 
             
                    """Restore agent from backup."""
         | 
| 753 813 | 
             
                    try:
         | 
| 754 814 | 
             
                        modification = self.active_modifications.get(modification_id)
         | 
| 755 815 | 
             
                        if not modification or not modification.backup_path:
         | 
| 756 816 | 
             
                            return False
         | 
| 757 | 
            -
             | 
| 817 | 
            +
             | 
| 758 818 | 
             
                        # Restore from backup
         | 
| 759 819 | 
             
                        backup_path = Path(modification.backup_path)
         | 
| 760 820 | 
             
                        if not backup_path.exists():
         | 
| 761 821 | 
             
                            return False
         | 
| 762 | 
            -
             | 
| 822 | 
            +
             | 
| 763 823 | 
             
                        original_path = Path(modification.file_path)
         | 
| 764 824 | 
             
                        shutil.copy2(backup_path, original_path)
         | 
| 765 | 
            -
             | 
| 825 | 
            +
             | 
| 766 826 | 
             
                        # Track restore operation
         | 
| 767 827 | 
             
                        await self.track_modification(
         | 
| 768 828 | 
             
                            agent_name=modification.agent_name,
         | 
| 769 829 | 
             
                            modification_type=ModificationType.RESTORE,
         | 
| 770 830 | 
             
                            file_path=modification.file_path,
         | 
| 771 831 | 
             
                            tier=modification.tier,
         | 
| 772 | 
            -
                            restored_from=modification_id
         | 
| 832 | 
            +
                            restored_from=modification_id,
         | 
| 773 833 | 
             
                        )
         | 
| 774 | 
            -
             | 
| 834 | 
            +
             | 
| 775 835 | 
             
                        return True
         | 
| 776 | 
            -
             | 
| 836 | 
            +
             | 
| 777 837 | 
             
                    except Exception as e:
         | 
| 778 838 | 
             
                        self.logger.error(f"Failed to restore agent backup: {e}")
         | 
| 779 839 | 
             
                        return False
         | 
| 780 | 
            -
             | 
| 840 | 
            +
             | 
| 781 841 | 
             
                async def get_modification_stats(self) -> Dict[str, Any]:
         | 
| 782 842 | 
             
                    """Get comprehensive modification statistics."""
         | 
| 783 843 | 
             
                    stats = {
         | 
| 784 | 
            -
                         | 
| 785 | 
            -
                         | 
| 786 | 
            -
             | 
| 787 | 
            -
                         | 
| 788 | 
            -
                         | 
| 789 | 
            -
                         | 
| 790 | 
            -
                         | 
| 844 | 
            +
                        "total_agents_tracked": len(self.modification_history),
         | 
| 845 | 
            +
                        "total_modifications": sum(
         | 
| 846 | 
            +
                            h.total_modifications for h in self.modification_history.values()
         | 
| 847 | 
            +
                        ),
         | 
| 848 | 
            +
                        "active_modifications": len(self.active_modifications),
         | 
| 849 | 
            +
                        "watched_paths": len(self.watched_paths),
         | 
| 850 | 
            +
                        "monitoring_enabled": self.enable_monitoring,
         | 
| 851 | 
            +
                        "backup_enabled": self.backup_enabled,
         | 
| 852 | 
            +
                        "validation_enabled": self.validation_enabled,
         | 
| 791 853 | 
             
                    }
         | 
| 792 | 
            -
             | 
| 854 | 
            +
             | 
| 793 855 | 
             
                    # Modification type breakdown
         | 
| 794 856 | 
             
                    type_counts = {}
         | 
| 795 857 | 
             
                    for history in self.modification_history.values():
         | 
| 796 858 | 
             
                        for mod in history.modifications:
         | 
| 797 | 
            -
                            type_counts[mod.modification_type.value] =  | 
| 798 | 
            -
             | 
| 799 | 
            -
             | 
| 800 | 
            -
             | 
| 859 | 
            +
                            type_counts[mod.modification_type.value] = (
         | 
| 860 | 
            +
                                type_counts.get(mod.modification_type.value, 0) + 1
         | 
| 861 | 
            +
                            )
         | 
| 862 | 
            +
             | 
| 863 | 
            +
                    stats["modifications_by_type"] = type_counts
         | 
| 864 | 
            +
             | 
| 801 865 | 
             
                    # Tier breakdown
         | 
| 802 866 | 
             
                    tier_counts = {}
         | 
| 803 867 | 
             
                    for history in self.modification_history.values():
         | 
| 804 868 | 
             
                        for mod in history.modifications:
         | 
| 805 869 | 
             
                            tier_counts[mod.tier.value] = tier_counts.get(mod.tier.value, 0) + 1
         | 
| 806 | 
            -
             | 
| 807 | 
            -
                    stats[ | 
| 808 | 
            -
             | 
| 870 | 
            +
             | 
| 871 | 
            +
                    stats["modifications_by_tier"] = tier_counts
         | 
| 872 | 
            +
             | 
| 809 873 | 
             
                    # Recent activity
         | 
| 810 874 | 
             
                    recent_24h = await self.get_recent_modifications(24)
         | 
| 811 875 | 
             
                    recent_7d = await self.get_recent_modifications(24 * 7)
         | 
| 812 | 
            -
             | 
| 813 | 
            -
                    stats[ | 
| 814 | 
            -
                         | 
| 815 | 
            -
                         | 
| 876 | 
            +
             | 
| 877 | 
            +
                    stats["recent_activity"] = {
         | 
| 878 | 
            +
                        "last_24_hours": len(recent_24h),
         | 
| 879 | 
            +
                        "last_7_days": len(recent_7d),
         | 
| 816 880 | 
             
                    }
         | 
| 817 | 
            -
             | 
| 881 | 
            +
             | 
| 818 882 | 
             
                    # Validation stats
         | 
| 819 | 
            -
                    validation_stats = {
         | 
| 820 | 
            -
             | 
| 821 | 
            -
                        'failed': 0,
         | 
| 822 | 
            -
                        'pending': 0,
         | 
| 823 | 
            -
                        'error': 0
         | 
| 824 | 
            -
                    }
         | 
| 825 | 
            -
                    
         | 
| 883 | 
            +
                    validation_stats = {"passed": 0, "failed": 0, "pending": 0, "error": 0}
         | 
| 884 | 
            +
             | 
| 826 885 | 
             
                    for mod in self.active_modifications.values():
         | 
| 827 | 
            -
                        validation_stats[mod.validation_status] =  | 
| 828 | 
            -
             | 
| 829 | 
            -
             | 
| 830 | 
            -
             | 
| 886 | 
            +
                        validation_stats[mod.validation_status] = (
         | 
| 887 | 
            +
                            validation_stats.get(mod.validation_status, 0) + 1
         | 
| 888 | 
            +
                        )
         | 
| 889 | 
            +
             | 
| 890 | 
            +
                    stats["validation_stats"] = validation_stats
         | 
| 891 | 
            +
             | 
| 831 892 | 
             
                    # Backup stats
         | 
| 832 893 | 
             
                    backup_stats = {
         | 
| 833 | 
            -
                         | 
| 834 | 
            -
                         | 
| 835 | 
            -
                            f.stat().st_size for f in self.backup_root.rglob( | 
| 836 | 
            -
                        ) | 
| 894 | 
            +
                        "total_backups": len(list(self.backup_root.iterdir())),
         | 
| 895 | 
            +
                        "backup_size_mb": sum(
         | 
| 896 | 
            +
                            f.stat().st_size for f in self.backup_root.rglob("*") if f.is_file()
         | 
| 897 | 
            +
                        )
         | 
| 898 | 
            +
                        / (1024 * 1024),
         | 
| 837 899 | 
             
                    }
         | 
| 838 | 
            -
             | 
| 839 | 
            -
                    stats[ | 
| 840 | 
            -
             | 
| 900 | 
            +
             | 
| 901 | 
            +
                    stats["backup_stats"] = backup_stats
         | 
| 902 | 
            +
             | 
| 841 903 | 
             
                    return stats
         | 
| 842 | 
            -
             | 
| 843 | 
            -
                def register_modification_callback( | 
| 904 | 
            +
             | 
| 905 | 
            +
                def register_modification_callback(
         | 
| 906 | 
            +
                    self, callback: Callable[[AgentModification], None]
         | 
| 907 | 
            +
                ) -> None:
         | 
| 844 908 | 
             
                    """Register callback for modification events."""
         | 
| 845 909 | 
             
                    self.modification_callbacks.append(callback)
         | 
| 846 | 
            -
             | 
| 847 | 
            -
                def unregister_modification_callback( | 
| 910 | 
            +
             | 
| 911 | 
            +
                def unregister_modification_callback(
         | 
| 912 | 
            +
                    self, callback: Callable[[AgentModification], None]
         | 
| 913 | 
            +
                ) -> None:
         | 
| 848 914 | 
             
                    """Unregister modification callback."""
         | 
| 849 915 | 
             
                    if callback in self.modification_callbacks:
         | 
| 850 | 
            -
                        self.modification_callbacks.remove(callback)
         | 
| 916 | 
            +
                        self.modification_callbacks.remove(callback)
         |