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,12 +1,12 @@ | |
| 1 1 | 
             
            """Session ID management for Claude subprocess optimization."""
         | 
| 2 2 |  | 
| 3 | 
            -
            import  | 
| 4 | 
            -
            from typing import Optional, Dict, Any, List
         | 
| 5 | 
            -
            from datetime import datetime, timedelta
         | 
| 3 | 
            +
            import gzip
         | 
| 6 4 | 
             
            import json
         | 
| 7 5 | 
             
            import shutil
         | 
| 8 | 
            -
            import  | 
| 6 | 
            +
            import uuid
         | 
| 7 | 
            +
            from datetime import datetime, timedelta
         | 
| 9 8 | 
             
            from pathlib import Path
         | 
| 9 | 
            +
            from typing import Any, Dict, List, Optional
         | 
| 10 10 |  | 
| 11 11 | 
             
            from ..core.logger import get_logger
         | 
| 12 12 |  | 
| @@ -15,10 +15,10 @@ logger = get_logger(__name__) | |
| 15 15 |  | 
| 16 16 | 
             
            class SessionManager:
         | 
| 17 17 | 
             
                """Manages session IDs for Claude subprocess reuse."""
         | 
| 18 | 
            -
             | 
| 18 | 
            +
             | 
| 19 19 | 
             
                def __init__(self, session_dir: Optional[Path] = None):
         | 
| 20 20 | 
             
                    """Initialize session manager.
         | 
| 21 | 
            -
             | 
| 21 | 
            +
             | 
| 22 22 | 
             
                    Args:
         | 
| 23 23 | 
             
                        session_dir: Directory to store session metadata
         | 
| 24 24 | 
             
                    """
         | 
| @@ -26,46 +26,48 @@ class SessionManager: | |
| 26 26 | 
             
                    self.session_dir.mkdir(parents=True, exist_ok=True)
         | 
| 27 27 | 
             
                    self.active_sessions: Dict[str, Dict[str, Any]] = {}
         | 
| 28 28 | 
             
                    self._load_sessions()
         | 
| 29 | 
            -
             | 
| 29 | 
            +
             | 
| 30 30 | 
             
                def create_session(self, context: str = "default") -> str:
         | 
| 31 31 | 
             
                    """Create a new session ID.
         | 
| 32 | 
            -
             | 
| 32 | 
            +
             | 
| 33 33 | 
             
                    Args:
         | 
| 34 34 | 
             
                        context: Context identifier (e.g., "pm_orchestration", "agent_delegation")
         | 
| 35 | 
            -
             | 
| 35 | 
            +
             | 
| 36 36 | 
             
                    Returns:
         | 
| 37 37 | 
             
                        UUID session ID
         | 
| 38 38 | 
             
                    """
         | 
| 39 39 | 
             
                    session_id = str(uuid.uuid4())
         | 
| 40 | 
            -
             | 
| 40 | 
            +
             | 
| 41 41 | 
             
                    self.active_sessions[session_id] = {
         | 
| 42 42 | 
             
                        "id": session_id,
         | 
| 43 43 | 
             
                        "context": context,
         | 
| 44 44 | 
             
                        "created_at": datetime.now().isoformat(),
         | 
| 45 45 | 
             
                        "last_used": datetime.now().isoformat(),
         | 
| 46 46 | 
             
                        "use_count": 0,
         | 
| 47 | 
            -
                        "agents_run": []
         | 
| 47 | 
            +
                        "agents_run": [],
         | 
| 48 48 | 
             
                    }
         | 
| 49 | 
            -
             | 
| 49 | 
            +
             | 
| 50 50 | 
             
                    self._save_sessions()
         | 
| 51 51 | 
             
                    logger.info(f"Created session {session_id} for context: {context}")
         | 
| 52 | 
            -
             | 
| 52 | 
            +
             | 
| 53 53 | 
             
                    return session_id
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                def get_or_create_session( | 
| 54 | 
            +
             | 
| 55 | 
            +
                def get_or_create_session(
         | 
| 56 | 
            +
                    self, context: str = "default", max_age_minutes: int = 30
         | 
| 57 | 
            +
                ) -> str:
         | 
| 56 58 | 
             
                    """Get existing session or create new one.
         | 
| 57 | 
            -
             | 
| 59 | 
            +
             | 
| 58 60 | 
             
                    Args:
         | 
| 59 61 | 
             
                        context: Context identifier
         | 
| 60 62 | 
             
                        max_age_minutes: Maximum age of session to reuse
         | 
| 61 | 
            -
             | 
| 63 | 
            +
             | 
| 62 64 | 
             
                    Returns:
         | 
| 63 65 | 
             
                        Session ID
         | 
| 64 66 | 
             
                    """
         | 
| 65 67 | 
             
                    # Look for existing session in context
         | 
| 66 68 | 
             
                    now = datetime.now()
         | 
| 67 69 | 
             
                    max_age = timedelta(minutes=max_age_minutes)
         | 
| 68 | 
            -
             | 
| 70 | 
            +
             | 
| 69 71 | 
             
                    for session_id, session_data in self.active_sessions.items():
         | 
| 70 72 | 
             
                        if session_data["context"] == context:
         | 
| 71 73 | 
             
                            last_used = datetime.fromisoformat(session_data["last_used"])
         | 
| @@ -76,95 +78,101 @@ class SessionManager: | |
| 76 78 | 
             
                                self._save_sessions()
         | 
| 77 79 | 
             
                                logger.info(f"Reusing session {session_id} for context: {context}")
         | 
| 78 80 | 
             
                                return session_id
         | 
| 79 | 
            -
             | 
| 81 | 
            +
             | 
| 80 82 | 
             
                    # No valid session found, create new one
         | 
| 81 83 | 
             
                    return self.create_session(context)
         | 
| 82 | 
            -
             | 
| 84 | 
            +
             | 
| 83 85 | 
             
                def record_agent_use(self, session_id: str, agent: str, task: str):
         | 
| 84 86 | 
             
                    """Record that an agent used this session.
         | 
| 85 | 
            -
             | 
| 87 | 
            +
             | 
| 86 88 | 
             
                    Args:
         | 
| 87 89 | 
             
                        session_id: Session ID
         | 
| 88 90 | 
             
                        agent: Agent name
         | 
| 89 91 | 
             
                        task: Task description
         | 
| 90 92 | 
             
                    """
         | 
| 91 93 | 
             
                    if session_id in self.active_sessions:
         | 
| 92 | 
            -
                        self.active_sessions[session_id]["agents_run"].append( | 
| 93 | 
            -
                             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 94 | 
            +
                        self.active_sessions[session_id]["agents_run"].append(
         | 
| 95 | 
            +
                            {
         | 
| 96 | 
            +
                                "agent": agent,
         | 
| 97 | 
            +
                                "task": task[:100],  # Truncate long tasks
         | 
| 98 | 
            +
                                "timestamp": datetime.now().isoformat(),
         | 
| 99 | 
            +
                            }
         | 
| 100 | 
            +
                        )
         | 
| 97 101 | 
             
                        self.active_sessions[session_id]["last_used"] = datetime.now().isoformat()
         | 
| 98 102 | 
             
                        self._save_sessions()
         | 
| 99 | 
            -
             | 
| 103 | 
            +
             | 
| 100 104 | 
             
                def cleanup_old_sessions(self, max_age_hours: int = 24, archive: bool = True):
         | 
| 101 105 | 
             
                    """Remove sessions older than max_age_hours.
         | 
| 102 | 
            -
             | 
| 106 | 
            +
             | 
| 103 107 | 
             
                    WHY: We archive old sessions instead of just deleting them to preserve
         | 
| 104 108 | 
             
                    conversation history while reducing active memory usage.
         | 
| 105 | 
            -
             | 
| 109 | 
            +
             | 
| 106 110 | 
             
                    Args:
         | 
| 107 111 | 
             
                        max_age_hours: Maximum age in hours
         | 
| 108 112 | 
             
                        archive: Whether to archive sessions before removing
         | 
| 109 113 | 
             
                    """
         | 
| 110 114 | 
             
                    now = datetime.now()
         | 
| 111 115 | 
             
                    max_age = timedelta(hours=max_age_hours)
         | 
| 112 | 
            -
             | 
| 116 | 
            +
             | 
| 113 117 | 
             
                    expired = []
         | 
| 114 118 | 
             
                    for session_id, session_data in self.active_sessions.items():
         | 
| 115 119 | 
             
                        created = datetime.fromisoformat(session_data["created_at"])
         | 
| 116 120 | 
             
                        if now - created > max_age:
         | 
| 117 121 | 
             
                            expired.append(session_id)
         | 
| 118 | 
            -
             | 
| 122 | 
            +
             | 
| 119 123 | 
             
                    # Archive sessions if requested
         | 
| 120 124 | 
             
                    if archive and expired:
         | 
| 121 125 | 
             
                        self._archive_sessions([self.active_sessions[sid] for sid in expired])
         | 
| 122 | 
            -
             | 
| 126 | 
            +
             | 
| 123 127 | 
             
                    for session_id in expired:
         | 
| 124 128 | 
             
                        del self.active_sessions[session_id]
         | 
| 125 129 | 
             
                        logger.info(f"Cleaned up expired session: {session_id}")
         | 
| 126 | 
            -
             | 
| 130 | 
            +
             | 
| 127 131 | 
             
                    if expired:
         | 
| 128 132 | 
             
                        self._save_sessions()
         | 
| 129 | 
            -
             | 
| 130 | 
            -
                def get_recent_sessions( | 
| 133 | 
            +
             | 
| 134 | 
            +
                def get_recent_sessions(
         | 
| 135 | 
            +
                    self, limit: int = 10, context: Optional[str] = None
         | 
| 136 | 
            +
                ) -> list:
         | 
| 131 137 | 
             
                    """Get recent sessions sorted by last used time.
         | 
| 132 | 
            -
             | 
| 138 | 
            +
             | 
| 133 139 | 
             
                    Args:
         | 
| 134 140 | 
             
                        limit: Maximum number of sessions to return
         | 
| 135 141 | 
             
                        context: Filter by context (optional)
         | 
| 136 | 
            -
             | 
| 142 | 
            +
             | 
| 137 143 | 
             
                    Returns:
         | 
| 138 144 | 
             
                        List of session data dictionaries sorted by last_used descending
         | 
| 139 145 | 
             
                    """
         | 
| 140 146 | 
             
                    sessions = list(self.active_sessions.values())
         | 
| 141 | 
            -
             | 
| 147 | 
            +
             | 
| 142 148 | 
             
                    # Filter by context if specified
         | 
| 143 149 | 
             
                    if context:
         | 
| 144 150 | 
             
                        sessions = [s for s in sessions if s.get("context") == context]
         | 
| 145 | 
            -
             | 
| 151 | 
            +
             | 
| 146 152 | 
             
                    # Sort by last_used descending (most recent first)
         | 
| 147 | 
            -
                    sessions.sort( | 
| 148 | 
            -
             | 
| 153 | 
            +
                    sessions.sort(
         | 
| 154 | 
            +
                        key=lambda s: datetime.fromisoformat(s["last_used"]), reverse=True
         | 
| 155 | 
            +
                    )
         | 
| 156 | 
            +
             | 
| 149 157 | 
             
                    return sessions[:limit]
         | 
| 150 | 
            -
             | 
| 158 | 
            +
             | 
| 151 159 | 
             
                def get_session_by_id(self, session_id: str) -> Optional[Dict[str, Any]]:
         | 
| 152 160 | 
             
                    """Get session data by ID.
         | 
| 153 | 
            -
             | 
| 161 | 
            +
             | 
| 154 162 | 
             
                    Args:
         | 
| 155 163 | 
             
                        session_id: Session ID to look up
         | 
| 156 | 
            -
             | 
| 164 | 
            +
             | 
| 157 165 | 
             
                    Returns:
         | 
| 158 166 | 
             
                        Session data dictionary or None if not found
         | 
| 159 167 | 
             
                    """
         | 
| 160 168 | 
             
                    return self.active_sessions.get(session_id)
         | 
| 161 | 
            -
             | 
| 169 | 
            +
             | 
| 162 170 | 
             
                def get_last_interactive_session(self) -> Optional[str]:
         | 
| 163 171 | 
             
                    """Get the most recently used interactive session ID.
         | 
| 164 | 
            -
             | 
| 172 | 
            +
             | 
| 165 173 | 
             
                    WHY: For --resume without arguments, we want to resume the last
         | 
| 166 174 | 
             
                    interactive session (context="default" for regular Claude runs).
         | 
| 167 | 
            -
             | 
| 175 | 
            +
             | 
| 168 176 | 
             
                    Returns:
         | 
| 169 177 | 
             
                        Session ID of most recent interactive session, or None if none found
         | 
| 170 178 | 
             
                    """
         | 
| @@ -172,120 +180,122 @@ class SessionManager: | |
| 172 180 | 
             
                    if recent_sessions:
         | 
| 173 181 | 
             
                        return recent_sessions[0]["id"]
         | 
| 174 182 | 
             
                    return None
         | 
| 175 | 
            -
             | 
| 183 | 
            +
             | 
| 176 184 | 
             
                def _save_sessions(self):
         | 
| 177 185 | 
             
                    """Save sessions to disk."""
         | 
| 178 186 | 
             
                    session_file = self.session_dir / "active_sessions.json"
         | 
| 179 187 | 
             
                    try:
         | 
| 180 | 
            -
                        with open(session_file,  | 
| 188 | 
            +
                        with open(session_file, "w") as f:
         | 
| 181 189 | 
             
                            json.dump(self.active_sessions, f, indent=2)
         | 
| 182 190 | 
             
                    except Exception as e:
         | 
| 183 191 | 
             
                        logger.error(f"Failed to save sessions: {e}")
         | 
| 184 | 
            -
             | 
| 192 | 
            +
             | 
| 185 193 | 
             
                def _load_sessions(self):
         | 
| 186 194 | 
             
                    """Load sessions from disk."""
         | 
| 187 195 | 
             
                    session_file = self.session_dir / "active_sessions.json"
         | 
| 188 196 | 
             
                    if session_file.exists():
         | 
| 189 197 | 
             
                        try:
         | 
| 190 | 
            -
                            with open(session_file,  | 
| 198 | 
            +
                            with open(session_file, "r") as f:
         | 
| 191 199 | 
             
                                self.active_sessions = json.load(f)
         | 
| 192 | 
            -
             | 
| 200 | 
            +
             | 
| 193 201 | 
             
                            # Clean up old sessions on load (archive by default)
         | 
| 194 202 | 
             
                            self.cleanup_old_sessions(archive=True)
         | 
| 195 | 
            -
             | 
| 203 | 
            +
             | 
| 196 204 | 
             
                            # Also check and clean .claude.json if needed
         | 
| 197 205 | 
             
                            self._check_claude_json_size()
         | 
| 198 206 | 
             
                        except Exception as e:
         | 
| 199 207 | 
             
                            logger.error(f"Failed to load sessions: {e}")
         | 
| 200 208 | 
             
                            self.active_sessions = {}
         | 
| 201 | 
            -
             | 
| 209 | 
            +
             | 
| 202 210 | 
             
                def _archive_sessions(self, sessions: List[Dict[str, Any]]):
         | 
| 203 211 | 
             
                    """Archive sessions to compressed files.
         | 
| 204 | 
            -
             | 
| 212 | 
            +
             | 
| 205 213 | 
             
                    WHY: Archiving preserves conversation history while reducing the size
         | 
| 206 214 | 
             
                    of active memory files like .claude.json.
         | 
| 207 | 
            -
             | 
| 215 | 
            +
             | 
| 208 216 | 
             
                    Args:
         | 
| 209 217 | 
             
                        sessions: List of session data dictionaries to archive
         | 
| 210 218 | 
             
                    """
         | 
| 211 219 | 
             
                    if not sessions:
         | 
| 212 220 | 
             
                        return
         | 
| 213 | 
            -
             | 
| 221 | 
            +
             | 
| 214 222 | 
             
                    archive_dir = self.session_dir.parent / "archives" / "sessions"
         | 
| 215 223 | 
             
                    archive_dir.mkdir(parents=True, exist_ok=True)
         | 
| 216 | 
            -
             | 
| 224 | 
            +
             | 
| 217 225 | 
             
                    # Create timestamped archive file
         | 
| 218 226 | 
             
                    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
         | 
| 219 227 | 
             
                    archive_name = f"sessions_archive_{timestamp}.json.gz"
         | 
| 220 228 | 
             
                    archive_path = archive_dir / archive_name
         | 
| 221 | 
            -
             | 
| 229 | 
            +
             | 
| 222 230 | 
             
                    try:
         | 
| 223 231 | 
             
                        # Compress and save sessions
         | 
| 224 | 
            -
                        with gzip.open(archive_path,  | 
| 232 | 
            +
                        with gzip.open(archive_path, "wt", encoding="utf-8") as f:
         | 
| 225 233 | 
             
                            json.dump(sessions, f, indent=2)
         | 
| 226 | 
            -
             | 
| 234 | 
            +
             | 
| 227 235 | 
             
                        logger.info(f"Archived {len(sessions)} sessions to {archive_path}")
         | 
| 228 236 | 
             
                    except Exception as e:
         | 
| 229 237 | 
             
                        logger.error(f"Failed to archive sessions: {e}")
         | 
| 230 | 
            -
             | 
| 238 | 
            +
             | 
| 231 239 | 
             
                def _check_claude_json_size(self):
         | 
| 232 240 | 
             
                    """Check .claude.json size and suggest cleanup if needed.
         | 
| 233 | 
            -
             | 
| 241 | 
            +
             | 
| 234 242 | 
             
                    WHY: Large .claude.json files cause memory issues. This provides
         | 
| 235 243 | 
             
                    proactive monitoring and suggestions for cleanup.
         | 
| 236 244 | 
             
                    """
         | 
| 237 245 | 
             
                    claude_json_path = Path.home() / ".claude.json"
         | 
| 238 | 
            -
             | 
| 246 | 
            +
             | 
| 239 247 | 
             
                    if not claude_json_path.exists():
         | 
| 240 248 | 
             
                        return
         | 
| 241 | 
            -
             | 
| 249 | 
            +
             | 
| 242 250 | 
             
                    file_size = claude_json_path.stat().st_size
         | 
| 243 251 | 
             
                    warning_threshold = 500 * 1024  # 500KB
         | 
| 244 | 
            -
             | 
| 252 | 
            +
             | 
| 245 253 | 
             
                    if file_size > warning_threshold:
         | 
| 246 254 | 
             
                        size_mb = file_size / (1024 * 1024)
         | 
| 247 | 
            -
                        logger.warning( | 
| 248 | 
            -
             | 
| 255 | 
            +
                        logger.warning(
         | 
| 256 | 
            +
                            f".claude.json is {size_mb:.1f}MB - consider running 'claude-mpm cleanup-memory'"
         | 
| 257 | 
            +
                        )
         | 
| 258 | 
            +
             | 
| 249 259 | 
             
                def archive_claude_json(self, keep_days: int = 30) -> bool:
         | 
| 250 260 | 
             
                    """Archive old conversations from .claude.json.
         | 
| 251 | 
            -
             | 
| 261 | 
            +
             | 
| 252 262 | 
             
                    WHY: This is called by the cleanup command to reduce memory usage
         | 
| 253 263 | 
             
                    while preserving conversation history.
         | 
| 254 | 
            -
             | 
| 264 | 
            +
             | 
| 255 265 | 
             
                    Args:
         | 
| 256 266 | 
             
                        keep_days: Number of days of history to keep
         | 
| 257 | 
            -
             | 
| 267 | 
            +
             | 
| 258 268 | 
             
                    Returns:
         | 
| 259 269 | 
             
                        True if successful, False otherwise
         | 
| 260 270 | 
             
                    """
         | 
| 261 271 | 
             
                    claude_json_path = Path.home() / ".claude.json"
         | 
| 262 | 
            -
             | 
| 272 | 
            +
             | 
| 263 273 | 
             
                    if not claude_json_path.exists():
         | 
| 264 274 | 
             
                        logger.info("No .claude.json file to archive")
         | 
| 265 275 | 
             
                        return True
         | 
| 266 | 
            -
             | 
| 276 | 
            +
             | 
| 267 277 | 
             
                    try:
         | 
| 268 278 | 
             
                        # Create backup first
         | 
| 269 279 | 
             
                        archive_dir = Path.home() / ".claude-mpm" / "archives"
         | 
| 270 280 | 
             
                        archive_dir.mkdir(parents=True, exist_ok=True)
         | 
| 271 | 
            -
             | 
| 281 | 
            +
             | 
| 272 282 | 
             
                        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
         | 
| 273 283 | 
             
                        backup_name = f"claude_json_backup_{timestamp}.json.gz"
         | 
| 274 284 | 
             
                        backup_path = archive_dir / backup_name
         | 
| 275 | 
            -
             | 
| 285 | 
            +
             | 
| 276 286 | 
             
                        # Compress and backup current file
         | 
| 277 | 
            -
                        with open(claude_json_path,  | 
| 278 | 
            -
                            with gzip.open(backup_path,  | 
| 287 | 
            +
                        with open(claude_json_path, "rb") as f_in:
         | 
| 288 | 
            +
                            with gzip.open(backup_path, "wb") as f_out:
         | 
| 279 289 | 
             
                                shutil.copyfileobj(f_in, f_out)
         | 
| 280 | 
            -
             | 
| 290 | 
            +
             | 
| 281 291 | 
             
                        logger.info(f"Created backup at {backup_path}")
         | 
| 282 | 
            -
             | 
| 292 | 
            +
             | 
| 283 293 | 
             
                        # For now, we don't modify the original .claude.json
         | 
| 284 294 | 
             
                        # as we don't know its exact structure.
         | 
| 285 295 | 
             
                        # The cleanup command handles this.
         | 
| 286 | 
            -
             | 
| 296 | 
            +
             | 
| 287 297 | 
             
                        return True
         | 
| 288 | 
            -
             | 
| 298 | 
            +
             | 
| 289 299 | 
             
                    except Exception as e:
         | 
| 290 300 | 
             
                        logger.error(f"Failed to archive .claude.json: {e}")
         | 
| 291 301 | 
             
                        return False
         | 
| @@ -293,10 +303,10 @@ class SessionManager: | |
| 293 303 |  | 
| 294 304 | 
             
            class OrchestrationSession:
         | 
| 295 305 | 
             
                """Context manager for orchestration sessions."""
         | 
| 296 | 
            -
             | 
| 306 | 
            +
             | 
| 297 307 | 
             
                def __init__(self, session_manager: SessionManager, context: str = "orchestration"):
         | 
| 298 308 | 
             
                    """Initialize orchestration session.
         | 
| 299 | 
            -
             | 
| 309 | 
            +
             | 
| 300 310 | 
             
                    Args:
         | 
| 301 311 | 
             
                        session_manager: SessionManager instance
         | 
| 302 312 | 
             
                        context: Session context
         | 
| @@ -304,12 +314,12 @@ class OrchestrationSession: | |
| 304 314 | 
             
                    self.session_manager = session_manager
         | 
| 305 315 | 
             
                    self.context = context
         | 
| 306 316 | 
             
                    self.session_id: Optional[str] = None
         | 
| 307 | 
            -
             | 
| 317 | 
            +
             | 
| 308 318 | 
             
                def __enter__(self) -> str:
         | 
| 309 319 | 
             
                    """Enter session context, return session ID."""
         | 
| 310 320 | 
             
                    self.session_id = self.session_manager.get_or_create_session(self.context)
         | 
| 311 321 | 
             
                    return self.session_id
         | 
| 312 | 
            -
             | 
| 322 | 
            +
             | 
| 313 323 | 
             
                def __exit__(self, exc_type, exc_val, exc_tb):
         | 
| 314 324 | 
             
                    """Exit session context."""
         | 
| 315 325 | 
             
                    # Could add cleanup here if needed
         | 
| @@ -328,7 +338,7 @@ with OrchestrationSession(session_manager, "pm_delegation") as session_id: | |
| 328 338 | 
             
                    session_id=session_id,  # First call creates context
         | 
| 329 339 | 
             
                    timeout=30
         | 
| 330 340 | 
             
                )
         | 
| 331 | 
            -
             | 
| 341 | 
            +
             | 
| 332 342 | 
             
                # Run agents with same session (reuses context)
         | 
| 333 343 | 
             
                for agent, task in delegations:
         | 
| 334 344 | 
             
                    stdout, stderr, returncode = self.launcher.launch_oneshot(
         | 
| @@ -337,4 +347,4 @@ with OrchestrationSession(session_manager, "pm_delegation") as session_id: | |
| 337 347 | 
             
                        timeout=60
         | 
| 338 348 | 
             
                    )
         | 
| 339 349 | 
             
                    session_manager.record_agent_use(session_id, agent, task)
         | 
| 340 | 
            -
            """
         | 
| 350 | 
            +
            """
         |