claude-mpm 3.9.11__py3-none-any.whl → 4.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +2 -2
- claude_mpm/__main__.py +3 -2
- claude_mpm/agents/__init__.py +85 -79
- claude_mpm/agents/agent_loader.py +464 -1003
- claude_mpm/agents/agent_loader_integration.py +45 -45
- claude_mpm/agents/agents_metadata.py +29 -30
- claude_mpm/agents/async_agent_loader.py +156 -138
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/base_agent_loader.py +179 -151
- claude_mpm/agents/frontmatter_validator.py +229 -130
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +213 -147
- claude_mpm/agents/templates/__init__.py +13 -13
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +23 -11
- claude_mpm/agents/templates/engineer.json +22 -6
- claude_mpm/agents/templates/memory_manager.json +1 -1
- claude_mpm/agents/templates/ops.json +2 -2
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/refactoring_engineer.json +222 -0
- claude_mpm/agents/templates/research.json +20 -14
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/ticketing.json +2 -2
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +3 -1
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/__init__.py +79 -51
- claude_mpm/cli/__main__.py +3 -2
- claude_mpm/cli/commands/__init__.py +20 -20
- claude_mpm/cli/commands/agents.py +279 -247
- claude_mpm/cli/commands/aggregate.py +138 -157
- claude_mpm/cli/commands/cleanup.py +147 -147
- claude_mpm/cli/commands/config.py +93 -76
- claude_mpm/cli/commands/info.py +17 -16
- claude_mpm/cli/commands/mcp.py +140 -905
- claude_mpm/cli/commands/mcp_command_router.py +139 -0
- claude_mpm/cli/commands/mcp_config_commands.py +20 -0
- claude_mpm/cli/commands/mcp_install_commands.py +20 -0
- claude_mpm/cli/commands/mcp_server_commands.py +175 -0
- claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
- claude_mpm/cli/commands/memory.py +239 -203
- claude_mpm/cli/commands/monitor.py +330 -86
- claude_mpm/cli/commands/run.py +380 -429
- claude_mpm/cli/commands/run_config_checker.py +160 -0
- claude_mpm/cli/commands/socketio_monitor.py +235 -0
- claude_mpm/cli/commands/tickets.py +363 -220
- claude_mpm/cli/parser.py +24 -1156
- claude_mpm/cli/parsers/__init__.py +29 -0
- claude_mpm/cli/parsers/agents_parser.py +136 -0
- claude_mpm/cli/parsers/base_parser.py +331 -0
- claude_mpm/cli/parsers/config_parser.py +85 -0
- claude_mpm/cli/parsers/mcp_parser.py +152 -0
- claude_mpm/cli/parsers/memory_parser.py +138 -0
- claude_mpm/cli/parsers/monitor_parser.py +124 -0
- claude_mpm/cli/parsers/run_parser.py +147 -0
- claude_mpm/cli/parsers/tickets_parser.py +203 -0
- claude_mpm/cli/ticket_cli.py +7 -3
- claude_mpm/cli/utils.py +55 -37
- claude_mpm/cli_module/__init__.py +6 -6
- claude_mpm/cli_module/args.py +188 -140
- claude_mpm/cli_module/commands.py +79 -70
- claude_mpm/cli_module/migration_example.py +38 -60
- claude_mpm/config/__init__.py +32 -25
- claude_mpm/config/agent_config.py +151 -119
- claude_mpm/config/experimental_features.py +71 -73
- claude_mpm/config/paths.py +94 -208
- claude_mpm/config/socketio_config.py +84 -73
- claude_mpm/constants.py +35 -18
- claude_mpm/core/__init__.py +9 -6
- claude_mpm/core/agent_name_normalizer.py +68 -71
- claude_mpm/core/agent_registry.py +372 -521
- claude_mpm/core/agent_session_manager.py +74 -63
- claude_mpm/core/base_service.py +116 -87
- claude_mpm/core/cache.py +119 -153
- claude_mpm/core/claude_runner.py +425 -1120
- claude_mpm/core/config.py +263 -168
- claude_mpm/core/config_aliases.py +69 -61
- claude_mpm/core/config_constants.py +292 -0
- claude_mpm/core/constants.py +57 -99
- claude_mpm/core/container.py +211 -178
- claude_mpm/core/exceptions.py +233 -89
- claude_mpm/core/factories.py +92 -54
- claude_mpm/core/framework_loader.py +378 -220
- claude_mpm/core/hook_manager.py +198 -83
- claude_mpm/core/hook_performance_config.py +136 -0
- claude_mpm/core/injectable_service.py +61 -55
- claude_mpm/core/interactive_session.py +165 -155
- claude_mpm/core/interfaces.py +221 -195
- claude_mpm/core/lazy.py +96 -96
- claude_mpm/core/logger.py +133 -107
- claude_mpm/core/logging_config.py +185 -157
- claude_mpm/core/minimal_framework_loader.py +20 -15
- claude_mpm/core/mixins.py +30 -29
- claude_mpm/core/oneshot_session.py +215 -181
- claude_mpm/core/optimized_agent_loader.py +134 -138
- claude_mpm/core/optimized_startup.py +159 -157
- claude_mpm/core/pm_hook_interceptor.py +85 -72
- claude_mpm/core/service_registry.py +103 -101
- claude_mpm/core/session_manager.py +97 -87
- claude_mpm/core/socketio_pool.py +212 -158
- claude_mpm/core/tool_access_control.py +58 -51
- claude_mpm/core/types.py +46 -24
- claude_mpm/core/typing_utils.py +166 -82
- claude_mpm/core/unified_agent_registry.py +721 -0
- claude_mpm/core/unified_config.py +550 -0
- claude_mpm/core/unified_paths.py +549 -0
- claude_mpm/dashboard/index.html +1 -1
- claude_mpm/dashboard/open_dashboard.py +51 -17
- claude_mpm/dashboard/static/built/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/built/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/built/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/built/dashboard.js +2 -0
- claude_mpm/dashboard/static/built/socket-client.js +2 -0
- claude_mpm/dashboard/static/css/dashboard.css +27 -8
- claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/dist/dashboard.js +2 -0
- claude_mpm/dashboard/static/dist/socket-client.js +2 -0
- claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
- claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
- claude_mpm/dashboard/static/js/components/event-viewer.js +93 -72
- claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +110 -96
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
- claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
- claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
- claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
- claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
- claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
- claude_mpm/dashboard/static/js/dashboard.js +178 -453
- claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
- claude_mpm/dashboard/static/js/socket-client.js +133 -53
- claude_mpm/dashboard/templates/index.html +40 -50
- claude_mpm/experimental/cli_enhancements.py +60 -58
- claude_mpm/generators/__init__.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +75 -65
- claude_mpm/hooks/__init__.py +1 -1
- claude_mpm/hooks/base_hook.py +33 -28
- claude_mpm/hooks/claude_hooks/__init__.py +1 -1
- claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
- claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
- claude_mpm/hooks/memory_integration_hook.py +140 -100
- claude_mpm/hooks/tool_call_interceptor.py +89 -76
- claude_mpm/hooks/validation_hooks.py +57 -49
- claude_mpm/init.py +145 -121
- claude_mpm/models/__init__.py +9 -9
- claude_mpm/models/agent_definition.py +33 -23
- claude_mpm/models/agent_session.py +228 -200
- claude_mpm/scripts/__init__.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +192 -75
- claude_mpm/scripts/socketio_server_manager.py +328 -0
- claude_mpm/scripts/start_activity_logging.py +25 -22
- claude_mpm/services/__init__.py +68 -43
- claude_mpm/services/agent_capabilities_service.py +271 -0
- claude_mpm/services/agents/__init__.py +23 -32
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
- claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
- claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
- claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
- claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
- claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
- claude_mpm/services/agents/deployment/agent_validator.py +352 -0
- claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
- claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
- claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
- claude_mpm/services/agents/deployment/config/__init__.py +13 -0
- claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
- claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
- claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
- claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
- claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
- claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
- claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
- claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
- claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
- claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
- claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
- claude_mpm/services/agents/deployment/results/__init__.py +13 -0
- claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
- claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
- claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
- claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
- claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
- claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
- claude_mpm/services/agents/loading/__init__.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
- claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
- claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
- claude_mpm/services/agents/management/__init__.py +2 -2
- claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
- claude_mpm/services/agents/management/agent_management_service.py +209 -156
- claude_mpm/services/agents/memory/__init__.py +9 -6
- claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
- claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
- claude_mpm/services/agents/memory/analyzer.py +430 -0
- claude_mpm/services/agents/memory/content_manager.py +376 -0
- claude_mpm/services/agents/memory/template_generator.py +468 -0
- claude_mpm/services/agents/registry/__init__.py +7 -10
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
- claude_mpm/services/agents/registry/modification_tracker.py +351 -285
- claude_mpm/services/async_session_logger.py +187 -153
- claude_mpm/services/claude_session_logger.py +87 -72
- claude_mpm/services/command_handler_service.py +217 -0
- claude_mpm/services/communication/__init__.py +3 -2
- claude_mpm/services/core/__init__.py +50 -97
- claude_mpm/services/core/base.py +60 -53
- claude_mpm/services/core/interfaces/__init__.py +188 -0
- claude_mpm/services/core/interfaces/agent.py +351 -0
- claude_mpm/services/core/interfaces/communication.py +343 -0
- claude_mpm/services/core/interfaces/infrastructure.py +413 -0
- claude_mpm/services/core/interfaces/service.py +434 -0
- claude_mpm/services/core/interfaces.py +19 -944
- claude_mpm/services/event_aggregator.py +208 -170
- claude_mpm/services/exceptions.py +387 -308
- claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
- claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
- claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
- claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
- claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
- claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
- claude_mpm/services/hook_service.py +106 -114
- claude_mpm/services/infrastructure/__init__.py +7 -5
- claude_mpm/services/infrastructure/context_preservation.py +233 -199
- claude_mpm/services/infrastructure/daemon_manager.py +279 -0
- claude_mpm/services/infrastructure/logging.py +83 -76
- claude_mpm/services/infrastructure/monitoring.py +547 -404
- claude_mpm/services/mcp_gateway/__init__.py +30 -13
- claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
- claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
- claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
- claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
- claude_mpm/services/mcp_gateway/core/base.py +80 -67
- claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
- claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
- claude_mpm/services/mcp_gateway/main.py +287 -137
- claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
- claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
- claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
- claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
- claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
- claude_mpm/services/memory/__init__.py +2 -2
- claude_mpm/services/memory/builder.py +451 -362
- claude_mpm/services/memory/cache/__init__.py +2 -2
- claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
- claude_mpm/services/memory/cache/simple_cache.py +107 -93
- claude_mpm/services/memory/indexed_memory.py +195 -193
- claude_mpm/services/memory/optimizer.py +267 -234
- claude_mpm/services/memory/router.py +571 -263
- claude_mpm/services/memory_hook_service.py +237 -0
- claude_mpm/services/port_manager.py +575 -0
- claude_mpm/services/project/__init__.py +3 -3
- claude_mpm/services/project/analyzer.py +451 -305
- claude_mpm/services/project/registry.py +262 -240
- claude_mpm/services/recovery_manager.py +287 -231
- claude_mpm/services/response_tracker.py +87 -67
- claude_mpm/services/runner_configuration_service.py +587 -0
- claude_mpm/services/session_management_service.py +304 -0
- claude_mpm/services/socketio/__init__.py +4 -4
- claude_mpm/services/socketio/client_proxy.py +174 -0
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +44 -30
- claude_mpm/services/socketio/handlers/connection.py +166 -64
- claude_mpm/services/socketio/handlers/file.py +123 -108
- claude_mpm/services/socketio/handlers/git.py +607 -373
- claude_mpm/services/socketio/handlers/hook.py +185 -0
- claude_mpm/services/socketio/handlers/memory.py +4 -4
- claude_mpm/services/socketio/handlers/project.py +4 -4
- claude_mpm/services/socketio/handlers/registry.py +53 -38
- claude_mpm/services/socketio/server/__init__.py +18 -0
- claude_mpm/services/socketio/server/broadcaster.py +252 -0
- claude_mpm/services/socketio/server/core.py +399 -0
- claude_mpm/services/socketio/server/main.py +323 -0
- claude_mpm/services/socketio_client_manager.py +160 -133
- claude_mpm/services/socketio_server.py +36 -1885
- claude_mpm/services/subprocess_launcher_service.py +316 -0
- claude_mpm/services/system_instructions_service.py +258 -0
- claude_mpm/services/ticket_manager.py +19 -533
- claude_mpm/services/utility_service.py +285 -0
- claude_mpm/services/version_control/__init__.py +18 -21
- claude_mpm/services/version_control/branch_strategy.py +20 -10
- claude_mpm/services/version_control/conflict_resolution.py +37 -13
- claude_mpm/services/version_control/git_operations.py +52 -21
- claude_mpm/services/version_control/semantic_versioning.py +92 -53
- claude_mpm/services/version_control/version_parser.py +145 -125
- claude_mpm/services/version_service.py +270 -0
- claude_mpm/storage/__init__.py +2 -2
- claude_mpm/storage/state_storage.py +177 -181
- claude_mpm/ticket_wrapper.py +2 -2
- claude_mpm/utils/__init__.py +2 -2
- claude_mpm/utils/agent_dependency_loader.py +453 -243
- claude_mpm/utils/config_manager.py +157 -118
- claude_mpm/utils/console.py +1 -1
- claude_mpm/utils/dependency_cache.py +102 -107
- claude_mpm/utils/dependency_manager.py +52 -47
- claude_mpm/utils/dependency_strategies.py +131 -96
- claude_mpm/utils/environment_context.py +110 -102
- claude_mpm/utils/error_handler.py +75 -55
- claude_mpm/utils/file_utils.py +80 -67
- claude_mpm/utils/framework_detection.py +12 -11
- claude_mpm/utils/import_migration_example.py +12 -60
- claude_mpm/utils/imports.py +48 -45
- claude_mpm/utils/path_operations.py +100 -93
- claude_mpm/utils/robust_installer.py +172 -164
- claude_mpm/utils/session_logging.py +30 -23
- claude_mpm/utils/subprocess_utils.py +99 -61
- claude_mpm/validation/__init__.py +1 -1
- claude_mpm/validation/agent_validator.py +151 -111
- claude_mpm/validation/frontmatter_validator.py +92 -71
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/METADATA +90 -22
- claude_mpm-4.0.4.dist-info/RECORD +417 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/licenses/LICENSE +1 -1
- claude_mpm/cli/commands/run_guarded.py +0 -511
- claude_mpm/config/memory_guardian_config.py +0 -325
- claude_mpm/config/memory_guardian_yaml.py +0 -335
- claude_mpm/core/config_paths.py +0 -150
- claude_mpm/core/memory_aware_runner.py +0 -353
- claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
- claude_mpm/deployment_paths.py +0 -261
- claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
- claude_mpm/models/state_models.py +0 -433
- claude_mpm/services/agent/__init__.py +0 -24
- claude_mpm/services/agent/deployment.py +0 -2548
- claude_mpm/services/agent/management.py +0 -598
- claude_mpm/services/agent/registry.py +0 -813
- claude_mpm/services/agents/registry/agent_registry.py +0 -813
- claude_mpm/services/communication/socketio.py +0 -1935
- claude_mpm/services/communication/websocket.py +0 -479
- claude_mpm/services/framework_claude_md_generator.py +0 -624
- claude_mpm/services/health_monitor.py +0 -893
- claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
- claude_mpm/services/infrastructure/health_monitor.py +0 -775
- claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
- claude_mpm/services/infrastructure/memory_guardian.py +0 -944
- claude_mpm/services/infrastructure/restart_protection.py +0 -642
- claude_mpm/services/infrastructure/state_manager.py +0 -774
- claude_mpm/services/mcp_gateway/manager.py +0 -334
- claude_mpm/services/optimized_hook_service.py +0 -542
- claude_mpm/services/project_analyzer.py +0 -864
- claude_mpm/services/project_registry.py +0 -608
- claude_mpm/services/standalone_socketio_server.py +0 -1300
- claude_mpm/services/ticket_manager_di.py +0 -318
- claude_mpm/services/ticketing_service_original.py +0 -510
- claude_mpm/utils/paths.py +0 -395
- claude_mpm/utils/platform_memory.py +0 -524
- claude_mpm-3.9.11.dist-info/RECORD +0 -306
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/top_level.txt +0 -0
| @@ -21,20 +21,22 @@ Security Considerations: | |
| 21 21 |  | 
| 22 22 | 
             
            import json
         | 
| 23 23 | 
             
            import logging
         | 
| 24 | 
            -
            from pathlib import Path
         | 
| 25 | 
            -
            from typing import Dict, List, Optional, Any, Tuple
         | 
| 26 24 | 
             
            from dataclasses import dataclass, field
         | 
| 27 25 | 
             
            from datetime import datetime
         | 
| 26 | 
            +
            from pathlib import Path
         | 
| 27 | 
            +
            from typing import Any, Dict, List, Optional, Tuple
         | 
| 28 | 
            +
             | 
| 28 29 | 
             
            import jsonschema
         | 
| 29 | 
            -
            from jsonschema import  | 
| 30 | 
            +
            from jsonschema import Draft7Validator, ValidationError, validate
         | 
| 31 | 
            +
             | 
| 30 32 | 
             
            from claude_mpm.config.paths import paths
         | 
| 31 33 | 
             
            from claude_mpm.core.constants import (
         | 
| 32 | 
            -
                SystemLimits,
         | 
| 33 | 
            -
                ResourceLimits,
         | 
| 34 | 
            -
                TimeoutConfig,
         | 
| 35 34 | 
             
                ComplexityMetrics,
         | 
| 36 35 | 
             
                ErrorMessages,
         | 
| 37 | 
            -
                 | 
| 36 | 
            +
                ResourceLimits,
         | 
| 37 | 
            +
                SystemLimits,
         | 
| 38 | 
            +
                TimeoutConfig,
         | 
| 39 | 
            +
                ValidationRules,
         | 
| 38 40 | 
             
            )
         | 
| 39 41 |  | 
| 40 42 | 
             
            logger = logging.getLogger(__name__)
         | 
| @@ -43,6 +45,7 @@ logger = logging.getLogger(__name__) | |
| 43 45 | 
             
            @dataclass
         | 
| 44 46 | 
             
            class ValidationResult:
         | 
| 45 47 | 
             
                """Result of agent validation."""
         | 
| 48 | 
            +
             | 
| 46 49 | 
             
                is_valid: bool
         | 
| 47 50 | 
             
                errors: List[str] = field(default_factory=list)
         | 
| 48 51 | 
             
                warnings: List[str] = field(default_factory=list)
         | 
| @@ -51,7 +54,7 @@ class ValidationResult: | |
| 51 54 |  | 
| 52 55 | 
             
            class AgentValidator:
         | 
| 53 56 | 
             
                """Validates agent configurations against JSON schema.
         | 
| 54 | 
            -
             | 
| 57 | 
            +
             | 
| 55 58 | 
             
                SECURITY CRITICAL: This class is the primary defense against malicious agent
         | 
| 56 59 | 
             
                configurations. All agent data must pass through this validator before being
         | 
| 57 60 | 
             
                used by the system. Bypassing this validator could lead to:
         | 
| @@ -60,7 +63,7 @@ class AgentValidator: | |
| 60 63 | 
             
                - Data exfiltration (via file/network access)
         | 
| 61 64 | 
             
                - Privilege escalation (via tool combinations)
         | 
| 62 65 | 
             
                """
         | 
| 63 | 
            -
             | 
| 66 | 
            +
             | 
| 64 67 | 
             
                # Model name mappings for normalization to tier names
         | 
| 65 68 | 
             
                MODEL_MAPPINGS = {
         | 
| 66 69 | 
             
                    # Sonnet variations
         | 
| @@ -77,19 +80,19 @@ class AgentValidator: | |
| 77 80 | 
             
                    "claude-3-haiku-20240307": "haiku",
         | 
| 78 81 | 
             
                    "claude-3-5-haiku-20241022": "haiku",
         | 
| 79 82 | 
             
                }
         | 
| 80 | 
            -
             | 
| 83 | 
            +
             | 
| 81 84 | 
             
                def __init__(self, schema_path: Optional[Path] = None):
         | 
| 82 85 | 
             
                    """Initialize the validator with the agent schema."""
         | 
| 83 86 | 
             
                    if schema_path is None:
         | 
| 84 87 | 
             
                        schema_path = paths.schemas_dir / "agent_schema.json"
         | 
| 85 | 
            -
             | 
| 88 | 
            +
             | 
| 86 89 | 
             
                    self.schema_path = schema_path
         | 
| 87 90 | 
             
                    self.schema = self._load_schema()
         | 
| 88 91 | 
             
                    self.validator = Draft7Validator(self.schema)
         | 
| 89 | 
            -
             | 
| 92 | 
            +
             | 
| 90 93 | 
             
                def _load_schema(self) -> Dict[str, Any]:
         | 
| 91 94 | 
             
                    """Load the JSON schema from file.
         | 
| 92 | 
            -
             | 
| 95 | 
            +
             | 
| 93 96 | 
             
                    Security Considerations:
         | 
| 94 97 | 
             
                    - Schema file path is validated to exist and be a file
         | 
| 95 98 | 
             
                    - JSON parsing errors are caught and logged
         | 
| @@ -101,95 +104,99 @@ class AgentValidator: | |
| 101 104 | 
             
                            raise FileNotFoundError(f"Schema file not found: {self.schema_path}")
         | 
| 102 105 | 
             
                        if not self.schema_path.is_file():
         | 
| 103 106 | 
             
                            raise ValueError(f"Schema path is not a file: {self.schema_path}")
         | 
| 104 | 
            -
             | 
| 105 | 
            -
                        with open(self.schema_path,  | 
| 107 | 
            +
             | 
| 108 | 
            +
                        with open(self.schema_path, "r") as f:
         | 
| 106 109 | 
             
                            return json.load(f)
         | 
| 107 110 | 
             
                    except Exception as e:
         | 
| 108 111 | 
             
                        logger.error(f"Failed to load schema from {self.schema_path}: {e}")
         | 
| 109 112 | 
             
                        raise
         | 
| 110 | 
            -
             | 
| 113 | 
            +
             | 
| 111 114 | 
             
                def _normalize_model(self, model: str) -> str:
         | 
| 112 115 | 
             
                    """Normalize model name to standard tier (opus, sonnet, haiku).
         | 
| 113 | 
            -
             | 
| 116 | 
            +
             | 
| 114 117 | 
             
                    Args:
         | 
| 115 118 | 
             
                        model: Original model name
         | 
| 116 | 
            -
             | 
| 119 | 
            +
             | 
| 117 120 | 
             
                    Returns:
         | 
| 118 121 | 
             
                        Normalized model tier name
         | 
| 119 122 | 
             
                    """
         | 
| 120 123 | 
             
                    # Direct mapping check
         | 
| 121 124 | 
             
                    if model in self.MODEL_MAPPINGS:
         | 
| 122 125 | 
             
                        return self.MODEL_MAPPINGS[model]
         | 
| 123 | 
            -
             | 
| 126 | 
            +
             | 
| 124 127 | 
             
                    # Already normalized
         | 
| 125 128 | 
             
                    if model in {"opus", "sonnet", "haiku"}:
         | 
| 126 129 | 
             
                        return model
         | 
| 127 | 
            -
             | 
| 130 | 
            +
             | 
| 128 131 | 
             
                    # Check if model contains tier name
         | 
| 129 132 | 
             
                    model_lower = model.lower()
         | 
| 130 133 | 
             
                    for tier in {"opus", "sonnet", "haiku"}:
         | 
| 131 134 | 
             
                        if tier in model_lower:
         | 
| 132 135 | 
             
                            return tier
         | 
| 133 | 
            -
             | 
| 136 | 
            +
             | 
| 134 137 | 
             
                    # Default to sonnet if unrecognized
         | 
| 135 138 | 
             
                    logger.warning(f"Unrecognized model '{model}', defaulting to 'sonnet'")
         | 
| 136 139 | 
             
                    return "sonnet"
         | 
| 137 | 
            -
             | 
| 140 | 
            +
             | 
| 138 141 | 
             
                def validate_agent(self, agent_data: Dict[str, Any]) -> ValidationResult:
         | 
| 139 142 | 
             
                    """
         | 
| 140 143 | 
             
                    Validate a single agent configuration against the schema.
         | 
| 141 | 
            -
             | 
| 144 | 
            +
             | 
| 142 145 | 
             
                    Security Features:
         | 
| 143 146 | 
             
                    - Strict JSON Schema validation prevents unexpected fields
         | 
| 144 147 | 
             
                    - Business rule validation adds additional security checks
         | 
| 145 148 | 
             
                    - Input size limits prevent memory exhaustion
         | 
| 146 149 | 
             
                    - Agent ID format validation prevents injection attacks
         | 
| 147 | 
            -
             | 
| 150 | 
            +
             | 
| 148 151 | 
             
                    Args:
         | 
| 149 152 | 
             
                        agent_data: Agent configuration dictionary
         | 
| 150 | 
            -
             | 
| 153 | 
            +
             | 
| 151 154 | 
             
                    Returns:
         | 
| 152 155 | 
             
                        ValidationResult with validation status and any errors/warnings
         | 
| 153 156 | 
             
                    """
         | 
| 154 157 | 
             
                    result = ValidationResult(is_valid=True)
         | 
| 155 | 
            -
             | 
| 158 | 
            +
             | 
| 156 159 | 
             
                    # Normalize model name before validation
         | 
| 157 160 | 
             
                    if "capabilities" in agent_data and "model" in agent_data["capabilities"]:
         | 
| 158 161 | 
             
                        original_model = agent_data["capabilities"]["model"]
         | 
| 159 162 | 
             
                        normalized_model = self._normalize_model(original_model)
         | 
| 160 163 | 
             
                        if original_model != normalized_model:
         | 
| 161 164 | 
             
                            agent_data["capabilities"]["model"] = normalized_model
         | 
| 162 | 
            -
                            result.warnings.append( | 
| 163 | 
            -
             | 
| 165 | 
            +
                            result.warnings.append(
         | 
| 166 | 
            +
                                f"Normalized model from '{original_model}' to '{normalized_model}'"
         | 
| 167 | 
            +
                            )
         | 
| 168 | 
            +
             | 
| 164 169 | 
             
                    # Perform JSON schema validation
         | 
| 165 170 | 
             
                    try:
         | 
| 166 171 | 
             
                        validate(instance=agent_data, schema=self.schema)
         | 
| 167 172 | 
             
                    except ValidationError as e:
         | 
| 168 173 | 
             
                        result.is_valid = False
         | 
| 169 174 | 
             
                        result.errors.append(f"Schema validation error: {e.message}")
         | 
| 170 | 
            -
             | 
| 175 | 
            +
             | 
| 171 176 | 
             
                        # Add path information if available
         | 
| 172 177 | 
             
                        if e.path:
         | 
| 173 178 | 
             
                            path = ".".join(str(p) for p in e.path)
         | 
| 174 179 | 
             
                            result.errors.append(f"Error at path: {path}")
         | 
| 175 | 
            -
             | 
| 180 | 
            +
             | 
| 176 181 | 
             
                    # SECURITY: Additional business rule validations beyond schema
         | 
| 177 182 | 
             
                    # These provide defense-in-depth security checks
         | 
| 178 183 | 
             
                    if result.is_valid:
         | 
| 179 184 | 
             
                        self._validate_business_rules(agent_data, result)
         | 
| 180 | 
            -
             | 
| 185 | 
            +
             | 
| 181 186 | 
             
                    # Add metadata
         | 
| 182 187 | 
             
                    result.metadata = {
         | 
| 183 188 | 
             
                        "validated_at": datetime.utcnow().isoformat(),
         | 
| 184 189 | 
             
                        "schema_version": self.schema.get("version", "1.1.0"),
         | 
| 185 | 
            -
                        "agent_id": agent_data.get("id", "unknown")
         | 
| 190 | 
            +
                        "agent_id": agent_data.get("id", "unknown"),
         | 
| 186 191 | 
             
                    }
         | 
| 187 | 
            -
             | 
| 192 | 
            +
             | 
| 188 193 | 
             
                    return result
         | 
| 189 | 
            -
             | 
| 190 | 
            -
                def _validate_business_rules( | 
| 194 | 
            +
             | 
| 195 | 
            +
                def _validate_business_rules(
         | 
| 196 | 
            +
                    self, agent_data: Dict[str, Any], result: ValidationResult
         | 
| 197 | 
            +
                ) -> None:
         | 
| 191 198 | 
             
                    """Apply additional business rule validations beyond schema.
         | 
| 192 | 
            -
             | 
| 199 | 
            +
             | 
| 193 200 | 
             
                    Security Validations:
         | 
| 194 201 | 
             
                    - Resource limits to prevent DoS attacks
         | 
| 195 202 | 
             
                    - Instruction length limits to prevent memory exhaustion
         | 
| @@ -197,49 +204,61 @@ class AgentValidator: | |
| 197 204 | 
             
                    - Tool compatibility to prevent privilege escalation
         | 
| 198 205 | 
             
                    - Self-reference prevention in handoff agents
         | 
| 199 206 | 
             
                    """
         | 
| 200 | 
            -
             | 
| 207 | 
            +
             | 
| 201 208 | 
             
                    # Validate resource tier consistency
         | 
| 202 209 | 
             
                    resource_tier = agent_data.get("capabilities", {}).get("resource_tier")
         | 
| 203 210 | 
             
                    if resource_tier:
         | 
| 204 211 | 
             
                        self._validate_resource_tier_limits(agent_data, resource_tier, result)
         | 
| 205 | 
            -
             | 
| 212 | 
            +
             | 
| 206 213 | 
             
                    # SECURITY: Validate instruction length to prevent memory exhaustion
         | 
| 207 214 | 
             
                    # Double-check even though schema enforces this - defense in depth
         | 
| 208 215 | 
             
                    instructions = agent_data.get("instructions", "")
         | 
| 209 216 | 
             
                    if len(instructions) > SystemLimits.MAX_INSTRUCTION_LENGTH:
         | 
| 210 | 
            -
                        result.errors.append( | 
| 211 | 
            -
                             | 
| 212 | 
            -
             | 
| 213 | 
            -
             | 
| 217 | 
            +
                        result.errors.append(
         | 
| 218 | 
            +
                            ErrorMessages.INSTRUCTION_TOO_LONG.format(
         | 
| 219 | 
            +
                                limit=SystemLimits.MAX_INSTRUCTION_LENGTH, actual=len(instructions)
         | 
| 220 | 
            +
                            )
         | 
| 221 | 
            +
                        )
         | 
| 214 222 | 
             
                        result.is_valid = False
         | 
| 215 | 
            -
             | 
| 223 | 
            +
             | 
| 216 224 | 
             
                    # Validate model compatibility with tools
         | 
| 217 225 | 
             
                    self._validate_model_tool_compatibility(agent_data, result)
         | 
| 218 | 
            -
             | 
| 226 | 
            +
             | 
| 219 227 | 
             
                    # SECURITY: Validate agent ID format to prevent injection attacks
         | 
| 220 228 | 
             
                    # Pattern enforced: ^[a-z][a-z0-9_]*$ prevents special characters
         | 
| 221 229 | 
             
                    agent_id = agent_data.get("id", "")
         | 
| 222 230 | 
             
                    if agent_id.endswith("_agent"):
         | 
| 223 | 
            -
                        result.warnings.append( | 
| 224 | 
            -
             | 
| 231 | 
            +
                        result.warnings.append(
         | 
| 232 | 
            +
                            f"Agent ID '{agent_id}' contains deprecated '_agent' suffix"
         | 
| 233 | 
            +
                        )
         | 
| 234 | 
            +
             | 
| 225 235 | 
             
                    # SECURITY: Additional ID validation for defense in depth
         | 
| 226 | 
            -
                    if agent_id and not agent_id.replace( | 
| 236 | 
            +
                    if agent_id and not agent_id.replace("_", "").replace("-", "").isalnum():
         | 
| 227 237 | 
             
                        result.errors.append(f"Agent ID '{agent_id}' contains invalid characters")
         | 
| 228 238 | 
             
                        result.is_valid = False
         | 
| 229 | 
            -
             | 
| 239 | 
            +
             | 
| 230 240 | 
             
                    # SECURITY: Validate handoff agents to prevent circular references and privilege escalation
         | 
| 231 241 | 
             
                    handoff_agents = agent_data.get("interactions", {}).get("handoff_agents", [])
         | 
| 232 242 | 
             
                    for handoff_id in handoff_agents:
         | 
| 233 243 | 
             
                        if handoff_id == agent_id:
         | 
| 234 | 
            -
                            result.warnings.append( | 
| 244 | 
            +
                            result.warnings.append(
         | 
| 245 | 
            +
                                f"Agent '{agent_id}' references itself in handoff_agents"
         | 
| 246 | 
            +
                            )
         | 
| 235 247 | 
             
                        # SECURITY: Ensure handoff IDs follow same pattern as agent IDs
         | 
| 236 | 
            -
                        if  | 
| 237 | 
            -
                             | 
| 248 | 
            +
                        if (
         | 
| 249 | 
            +
                            handoff_id
         | 
| 250 | 
            +
                            and not handoff_id.replace("_", "").replace("-", "").isalnum()
         | 
| 251 | 
            +
                        ):
         | 
| 252 | 
            +
                            result.errors.append(
         | 
| 253 | 
            +
                                f"Handoff agent ID '{handoff_id}' contains invalid characters"
         | 
| 254 | 
            +
                            )
         | 
| 238 255 | 
             
                            result.is_valid = False
         | 
| 239 | 
            -
             | 
| 240 | 
            -
                def _validate_resource_tier_limits( | 
| 256 | 
            +
             | 
| 257 | 
            +
                def _validate_resource_tier_limits(
         | 
| 258 | 
            +
                    self, agent_data: Dict[str, Any], tier: str, result: ValidationResult
         | 
| 259 | 
            +
                ) -> None:
         | 
| 241 260 | 
             
                    """Validate resource limits match the tier constraints.
         | 
| 242 | 
            -
             | 
| 261 | 
            +
             | 
| 243 262 | 
             
                    Security Purpose:
         | 
| 244 263 | 
             
                    - Prevents resource exhaustion attacks
         | 
| 245 264 | 
             
                    - Ensures agents can't request excessive resources
         | 
| @@ -250,26 +269,26 @@ class AgentValidator: | |
| 250 269 | 
             
                        "intensive": {
         | 
| 251 270 | 
             
                            "memory_limit": ResourceLimits.INTENSIVE_MEMORY_RANGE,
         | 
| 252 271 | 
             
                            "cpu_limit": ResourceLimits.INTENSIVE_CPU_RANGE,
         | 
| 253 | 
            -
                            "timeout": TimeoutConfig.INTENSIVE_TIMEOUT_RANGE
         | 
| 272 | 
            +
                            "timeout": TimeoutConfig.INTENSIVE_TIMEOUT_RANGE,
         | 
| 254 273 | 
             
                        },
         | 
| 255 274 | 
             
                        "standard": {
         | 
| 256 275 | 
             
                            "memory_limit": ResourceLimits.STANDARD_MEMORY_RANGE,
         | 
| 257 276 | 
             
                            "cpu_limit": ResourceLimits.STANDARD_CPU_RANGE,
         | 
| 258 | 
            -
                            "timeout": TimeoutConfig.STANDARD_TIMEOUT_RANGE
         | 
| 277 | 
            +
                            "timeout": TimeoutConfig.STANDARD_TIMEOUT_RANGE,
         | 
| 259 278 | 
             
                        },
         | 
| 260 279 | 
             
                        "lightweight": {
         | 
| 261 280 | 
             
                            "memory_limit": ResourceLimits.LIGHTWEIGHT_MEMORY_RANGE,
         | 
| 262 281 | 
             
                            "cpu_limit": ResourceLimits.LIGHTWEIGHT_CPU_RANGE,
         | 
| 263 | 
            -
                            "timeout": TimeoutConfig.LIGHTWEIGHT_TIMEOUT_RANGE
         | 
| 264 | 
            -
                        }
         | 
| 282 | 
            +
                            "timeout": TimeoutConfig.LIGHTWEIGHT_TIMEOUT_RANGE,
         | 
| 283 | 
            +
                        },
         | 
| 265 284 | 
             
                    }
         | 
| 266 | 
            -
             | 
| 285 | 
            +
             | 
| 267 286 | 
             
                    if tier not in tier_limits:
         | 
| 268 287 | 
             
                        return
         | 
| 269 | 
            -
             | 
| 288 | 
            +
             | 
| 270 289 | 
             
                    limits = tier_limits[tier]
         | 
| 271 290 | 
             
                    capabilities = agent_data.get("capabilities", {})
         | 
| 272 | 
            -
             | 
| 291 | 
            +
             | 
| 273 292 | 
             
                    # Check memory limit
         | 
| 274 293 | 
             
                    memory = capabilities.get("memory_limit")
         | 
| 275 294 | 
             
                    if memory is not None:
         | 
| @@ -279,7 +298,7 @@ class AgentValidator: | |
| 279 298 | 
             
                                f"Memory limit {memory}MB outside recommended range "
         | 
| 280 299 | 
             
                                f"{min_mem}-{max_mem}MB for tier '{tier}'"
         | 
| 281 300 | 
             
                            )
         | 
| 282 | 
            -
             | 
| 301 | 
            +
             | 
| 283 302 | 
             
                    # Check CPU limit
         | 
| 284 303 | 
             
                    cpu = capabilities.get("cpu_limit")
         | 
| 285 304 | 
             
                    if cpu is not None:
         | 
| @@ -289,7 +308,7 @@ class AgentValidator: | |
| 289 308 | 
             
                                f"CPU limit {cpu}% outside recommended range "
         | 
| 290 309 | 
             
                                f"{min_cpu}-{max_cpu}% for tier '{tier}'"
         | 
| 291 310 | 
             
                            )
         | 
| 292 | 
            -
             | 
| 311 | 
            +
             | 
| 293 312 | 
             
                    # Check timeout
         | 
| 294 313 | 
             
                    timeout = capabilities.get("timeout")
         | 
| 295 314 | 
             
                    if timeout is not None:
         | 
| @@ -299,49 +318,66 @@ class AgentValidator: | |
| 299 318 | 
             
                                f"Timeout {timeout}s outside recommended range "
         | 
| 300 319 | 
             
                                f"{min_timeout}-{max_timeout}s for tier '{tier}'"
         | 
| 301 320 | 
             
                            )
         | 
| 302 | 
            -
             | 
| 303 | 
            -
                def _validate_model_tool_compatibility( | 
| 321 | 
            +
             | 
| 322 | 
            +
                def _validate_model_tool_compatibility(
         | 
| 323 | 
            +
                    self, agent_data: Dict[str, Any], result: ValidationResult
         | 
| 324 | 
            +
                ) -> None:
         | 
| 304 325 | 
             
                    """Validate that model and tools are compatible."""
         | 
| 305 326 | 
             
                    model = agent_data.get("capabilities", {}).get("model", "")
         | 
| 306 327 | 
             
                    tools = agent_data.get("capabilities", {}).get("tools", [])
         | 
| 307 | 
            -
             | 
| 328 | 
            +
             | 
| 308 329 | 
             
                    # Normalize model name for comparison
         | 
| 309 330 | 
             
                    normalized_model = self._normalize_model(model)
         | 
| 310 | 
            -
             | 
| 331 | 
            +
             | 
| 311 332 | 
             
                    # Haiku models shouldn't use resource-intensive tools
         | 
| 312 333 | 
             
                    if normalized_model == "haiku":
         | 
| 313 | 
            -
                        intensive_tools = { | 
| 334 | 
            +
                        intensive_tools = {
         | 
| 335 | 
            +
                            "docker",
         | 
| 336 | 
            +
                            "kubectl",
         | 
| 337 | 
            +
                            "terraform",
         | 
| 338 | 
            +
                            "aws",
         | 
| 339 | 
            +
                            "gcloud",
         | 
| 340 | 
            +
                            "azure",
         | 
| 341 | 
            +
                        }
         | 
| 314 342 | 
             
                        used_intensive = set(tools) & intensive_tools
         | 
| 315 343 | 
             
                        if used_intensive:
         | 
| 316 344 | 
             
                            result.warnings.append(
         | 
| 317 345 | 
             
                                f"Haiku model '{model}' using resource-intensive tools: {used_intensive}"
         | 
| 318 346 | 
             
                            )
         | 
| 319 | 
            -
             | 
| 347 | 
            +
             | 
| 320 348 | 
             
                    # SECURITY: Network access requirement validation
         | 
| 321 349 | 
             
                    # Ensures agents can't use network tools without explicit permission
         | 
| 322 350 | 
             
                    network_tools = {"WebSearch", "WebFetch", "aws", "gcloud", "azure"}
         | 
| 323 351 | 
             
                    needs_network = bool(set(tools) & network_tools)
         | 
| 324 352 | 
             
                    has_network = agent_data.get("capabilities", {}).get("network_access", False)
         | 
| 325 | 
            -
             | 
| 353 | 
            +
             | 
| 326 354 | 
             
                    if needs_network and not has_network:
         | 
| 327 355 | 
             
                        result.warnings.append(
         | 
| 328 356 | 
             
                            f"Agent uses network tools {set(tools) & network_tools} but network_access is False"
         | 
| 329 357 | 
             
                        )
         | 
| 330 | 
            -
             | 
| 358 | 
            +
             | 
| 331 359 | 
             
                    # SECURITY: Check for potentially dangerous tool combinations
         | 
| 332 360 | 
             
                    dangerous_combos = [
         | 
| 333 | 
            -
                        ( | 
| 361 | 
            +
                        (
         | 
| 362 | 
            +
                            {"Bash", "Write"},
         | 
| 363 | 
            +
                            "Can execute arbitrary code by writing and running scripts",
         | 
| 364 | 
            +
                        ),
         | 
| 334 365 | 
             
                        ({"docker", "kubectl"}, "Container escape potential with both tools"),
         | 
| 335 | 
            -
                        ( | 
| 366 | 
            +
                        (
         | 
| 367 | 
            +
                            {"aws", "gcloud", "azure"},
         | 
| 368 | 
            +
                            "Multiple cloud access increases attack surface",
         | 
| 369 | 
            +
                        ),
         | 
| 336 370 | 
             
                    ]
         | 
| 337 | 
            -
             | 
| 371 | 
            +
             | 
| 338 372 | 
             
                    for combo, risk in dangerous_combos:
         | 
| 339 373 | 
             
                        if combo.issubset(set(tools)):
         | 
| 340 | 
            -
                            result.warnings.append( | 
| 341 | 
            -
             | 
| 374 | 
            +
                            result.warnings.append(
         | 
| 375 | 
            +
                                f"Potentially dangerous tool combination: {combo} - {risk}"
         | 
| 376 | 
            +
                            )
         | 
| 377 | 
            +
             | 
| 342 378 | 
             
                def validate_file(self, file_path: Path) -> ValidationResult:
         | 
| 343 379 | 
             
                    """Validate an agent configuration file.
         | 
| 344 | 
            -
             | 
| 380 | 
            +
             | 
| 345 381 | 
             
                    Security Measures:
         | 
| 346 382 | 
             
                    - Path traversal protection through Path object
         | 
| 347 383 | 
             
                    - Safe JSON parsing with error handling
         | 
| @@ -353,21 +389,19 @@ class AgentValidator: | |
| 353 389 | 
             
                            raise FileNotFoundError(f"File not found: {file_path}")
         | 
| 354 390 | 
             
                        if not file_path.is_file():
         | 
| 355 391 | 
             
                            raise ValueError(f"Path is not a file: {file_path}")
         | 
| 356 | 
            -
             | 
| 392 | 
            +
             | 
| 357 393 | 
             
                        # SECURITY: Check file size to prevent memory exhaustion
         | 
| 358 394 | 
             
                        file_size = file_path.stat().st_size
         | 
| 359 395 | 
             
                        max_size = SystemLimits.MAX_AGENT_CONFIG_SIZE
         | 
| 360 396 | 
             
                        if file_size > max_size:
         | 
| 361 | 
            -
                            raise ValueError(ErrorMessages.FILE_TOO_LARGE.format(
         | 
| 362 | 
            -
             | 
| 363 | 
            -
                            ))
         | 
| 364 | 
            -
                        with open(file_path, 'r') as f:
         | 
| 397 | 
            +
                            raise ValueError(ErrorMessages.FILE_TOO_LARGE.format(limit=max_size))
         | 
| 398 | 
            +
                        with open(file_path, "r") as f:
         | 
| 365 399 | 
             
                            agent_data = json.load(f)
         | 
| 366 | 
            -
             | 
| 400 | 
            +
             | 
| 367 401 | 
             
                        result = self.validate_agent(agent_data)
         | 
| 368 402 | 
             
                        result.metadata["file_path"] = str(file_path)
         | 
| 369 403 | 
             
                        return result
         | 
| 370 | 
            -
             | 
| 404 | 
            +
             | 
| 371 405 | 
             
                    except json.JSONDecodeError as e:
         | 
| 372 406 | 
             
                        result = ValidationResult(is_valid=False)
         | 
| 373 407 | 
             
                        result.errors.append(f"Invalid JSON in {file_path}: {e}")
         | 
| @@ -376,46 +410,48 @@ class AgentValidator: | |
| 376 410 | 
             
                        result = ValidationResult(is_valid=False)
         | 
| 377 411 | 
             
                        result.errors.append(f"Error reading {file_path}: {e}")
         | 
| 378 412 | 
             
                        return result
         | 
| 379 | 
            -
             | 
| 413 | 
            +
             | 
| 380 414 | 
             
                def validate_directory(self, directory: Path) -> Dict[str, ValidationResult]:
         | 
| 381 415 | 
             
                    """Validate all agent files in a directory.
         | 
| 382 | 
            -
             | 
| 416 | 
            +
             | 
| 383 417 | 
             
                    Security Considerations:
         | 
| 384 418 | 
             
                    - Directory traversal prevention through Path.glob
         | 
| 385 419 | 
             
                    - Symlink following should be disabled in production
         | 
| 386 420 | 
             
                    - Large directory DoS prevention through file count limits
         | 
| 387 421 | 
             
                    """
         | 
| 388 422 | 
             
                    results = {}
         | 
| 389 | 
            -
             | 
| 423 | 
            +
             | 
| 390 424 | 
             
                    # SECURITY: Validate directory exists and is accessible
         | 
| 391 425 | 
             
                    if not directory.exists():
         | 
| 392 426 | 
             
                        raise FileNotFoundError(f"Directory not found: {directory}")
         | 
| 393 427 | 
             
                    if not directory.is_dir():
         | 
| 394 428 | 
             
                        raise ValueError(f"Path is not a directory: {directory}")
         | 
| 395 | 
            -
             | 
| 429 | 
            +
             | 
| 396 430 | 
             
                    # SECURITY: Limit number of files to prevent DoS
         | 
| 397 431 | 
             
                    max_files = SystemLimits.MAX_FILES_TO_VALIDATE
         | 
| 398 432 | 
             
                    file_count = 0
         | 
| 399 | 
            -
             | 
| 433 | 
            +
             | 
| 400 434 | 
             
                    for json_file in directory.glob("*.json"):
         | 
| 401 435 | 
             
                        if json_file.name == "agent_schema.json":
         | 
| 402 436 | 
             
                            continue
         | 
| 403 | 
            -
             | 
| 437 | 
            +
             | 
| 404 438 | 
             
                        # SECURITY: Skip symlinks to prevent directory traversal
         | 
| 405 439 | 
             
                        if json_file.is_symlink():
         | 
| 406 440 | 
             
                            logger.warning(f"Skipping symlink: {json_file}")
         | 
| 407 441 | 
             
                            continue
         | 
| 408 | 
            -
             | 
| 442 | 
            +
             | 
| 409 443 | 
             
                        file_count += 1
         | 
| 410 444 | 
             
                        if file_count > max_files:
         | 
| 411 | 
            -
                            logger.warning( | 
| 445 | 
            +
                            logger.warning(
         | 
| 446 | 
            +
                                f"Reached maximum file limit ({max_files}), stopping validation"
         | 
| 447 | 
            +
                            )
         | 
| 412 448 | 
             
                            break
         | 
| 413 | 
            -
             | 
| 449 | 
            +
             | 
| 414 450 | 
             
                        logger.info(f"Validating {json_file}")
         | 
| 415 451 | 
             
                        results[json_file.name] = self.validate_file(json_file)
         | 
| 416 | 
            -
             | 
| 452 | 
            +
             | 
| 417 453 | 
             
                    return results
         | 
| 418 | 
            -
             | 
| 454 | 
            +
             | 
| 419 455 | 
             
                def get_schema_info(self) -> Dict[str, Any]:
         | 
| 420 456 | 
             
                    """Get information about the loaded schema."""
         | 
| 421 457 | 
             
                    return {
         | 
| @@ -423,32 +459,34 @@ class AgentValidator: | |
| 423 459 | 
             
                        "schema_title": self.schema.get("title", "Unknown"),
         | 
| 424 460 | 
             
                        "schema_description": self.schema.get("description", ""),
         | 
| 425 461 | 
             
                        "required_fields": self.schema.get("required", []),
         | 
| 426 | 
            -
                        "properties": list(self.schema.get("properties", {}).keys())
         | 
| 462 | 
            +
                        "properties": list(self.schema.get("properties", {}).keys()),
         | 
| 427 463 | 
             
                    }
         | 
| 428 464 |  | 
| 429 465 |  | 
| 430 | 
            -
            def validate_agent_migration( | 
| 466 | 
            +
            def validate_agent_migration(
         | 
| 467 | 
            +
                old_agent: Dict[str, Any], new_agent: Dict[str, Any]
         | 
| 468 | 
            +
            ) -> ValidationResult:
         | 
| 431 469 | 
             
                """
         | 
| 432 470 | 
             
                Validate that a migrated agent maintains compatibility.
         | 
| 433 | 
            -
             | 
| 471 | 
            +
             | 
| 434 472 | 
             
                Security Importance:
         | 
| 435 473 | 
             
                - Ensures privilege escalation doesn't occur during migration
         | 
| 436 474 | 
             
                - Validates that security constraints are preserved
         | 
| 437 475 | 
             
                - Prevents addition of dangerous tools without review
         | 
| 438 | 
            -
             | 
| 476 | 
            +
             | 
| 439 477 | 
             
                Args:
         | 
| 440 478 | 
             
                    old_agent: Original agent configuration
         | 
| 441 479 | 
             
                    new_agent: Migrated agent configuration
         | 
| 442 | 
            -
             | 
| 480 | 
            +
             | 
| 443 481 | 
             
                Returns:
         | 
| 444 482 | 
             
                    ValidationResult with migration validation results
         | 
| 445 483 | 
             
                """
         | 
| 446 484 | 
             
                result = ValidationResult(is_valid=True)
         | 
| 447 | 
            -
             | 
| 485 | 
            +
             | 
| 448 486 | 
             
                # SECURITY: Check that core functionality is preserved without privilege escalation
         | 
| 449 487 | 
             
                old_tools = set(old_agent.get("configuration_fields", {}).get("tools", []))
         | 
| 450 488 | 
             
                new_tools = set(new_agent.get("capabilities", {}).get("tools", []))
         | 
| 451 | 
            -
             | 
| 489 | 
            +
             | 
| 452 490 | 
             
                if old_tools != new_tools:
         | 
| 453 491 | 
             
                    missing = old_tools - new_tools
         | 
| 454 492 | 
             
                    added = new_tools - old_tools
         | 
| @@ -460,19 +498,21 @@ def validate_agent_migration(old_agent: Dict[str, Any], new_agent: Dict[str, Any | |
| 460 498 | 
             
                        dangerous_tools = {"Bash", "docker", "kubectl", "aws", "gcloud", "azure"}
         | 
| 461 499 | 
             
                        dangerous_added = added & dangerous_tools
         | 
| 462 500 | 
             
                        if dangerous_added:
         | 
| 463 | 
            -
                            result.errors.append( | 
| 501 | 
            +
                            result.errors.append(
         | 
| 502 | 
            +
                                f"SECURITY: Dangerous tools added in migration: {dangerous_added}"
         | 
| 503 | 
            +
                            )
         | 
| 464 504 | 
             
                            result.is_valid = False
         | 
| 465 | 
            -
             | 
| 505 | 
            +
             | 
| 466 506 | 
             
                # Check instruction preservation
         | 
| 467 507 | 
             
                old_instructions = old_agent.get("narrative_fields", {}).get("instructions", "")
         | 
| 468 508 | 
             
                new_instructions = new_agent.get("instructions", "")
         | 
| 469 | 
            -
             | 
| 509 | 
            +
             | 
| 470 510 | 
             
                if old_instructions and not new_instructions:
         | 
| 471 511 | 
             
                    result.errors.append("Instructions lost in migration")
         | 
| 472 512 | 
             
                    result.is_valid = False
         | 
| 473 513 | 
             
                elif len(old_instructions) > len(new_instructions) * 1.1:  # Allow 10% reduction
         | 
| 474 514 | 
             
                    result.warnings.append("Significant instruction content reduction in migration")
         | 
| 475 | 
            -
             | 
| 515 | 
            +
             | 
| 476 516 | 
             
                return result
         | 
| 477 517 |  | 
| 478 518 |  | 
| @@ -486,20 +526,20 @@ def validate_agent_file(file_path: Path) -> ValidationResult: | |
| 486 526 | 
             
            def validate_all_agents(directory: Path) -> Tuple[int, int, List[str]]:
         | 
| 487 527 | 
             
                """
         | 
| 488 528 | 
             
                Validate all agents in a directory and return summary.
         | 
| 489 | 
            -
             | 
| 529 | 
            +
             | 
| 490 530 | 
             
                Returns:
         | 
| 491 531 | 
             
                    Tuple of (valid_count, invalid_count, error_messages)
         | 
| 492 532 | 
             
                """
         | 
| 493 533 | 
             
                validator = AgentValidator()
         | 
| 494 534 | 
             
                results = validator.validate_directory(directory)
         | 
| 495 | 
            -
             | 
| 535 | 
            +
             | 
| 496 536 | 
             
                valid_count = sum(1 for r in results.values() if r.is_valid)
         | 
| 497 537 | 
             
                invalid_count = len(results) - valid_count
         | 
| 498 | 
            -
             | 
| 538 | 
            +
             | 
| 499 539 | 
             
                error_messages = []
         | 
| 500 540 | 
             
                for filename, result in results.items():
         | 
| 501 541 | 
             
                    if not result.is_valid:
         | 
| 502 542 | 
             
                        for error in result.errors:
         | 
| 503 543 | 
             
                            error_messages.append(f"{filename}: {error}")
         | 
| 504 | 
            -
             | 
| 505 | 
            -
                return valid_count, invalid_count, error_messages
         | 
| 544 | 
            +
             | 
| 545 | 
            +
                return valid_count, invalid_count, error_messages
         |