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,539 +1,25 @@ | |
| 1 | 
            -
            """Ticket  | 
| 1 | 
            +
            """Ticket manager stub for backward compatibility."""
         | 
| 2 2 |  | 
| 3 | 
            -
            from pathlib import Path
         | 
| 4 | 
            -
            from typing import Optional, Dict, Any, List
         | 
| 5 | 
            -
            from datetime import datetime
         | 
| 6 3 |  | 
| 7 | 
            -
             | 
| 4 | 
            +
            class TicketManager:
         | 
| 5 | 
            +
                """Stub TicketManager class for backward compatibility."""
         | 
| 8 6 |  | 
| 9 | 
            -
             | 
| 7 | 
            +
                def create_task(self, *args, **kwargs):
         | 
| 8 | 
            +
                    """Stub method."""
         | 
| 9 | 
            +
                    return None
         | 
| 10 10 |  | 
| 11 | 
            +
                def list_recent_tickets(self, *args, **kwargs):
         | 
| 12 | 
            +
                    """Stub method."""
         | 
| 13 | 
            +
                    return []
         | 
| 11 14 |  | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
                
         | 
| 16 | 
            -
                This wraps the ai-trackdown-pytools API for creating tickets
         | 
| 17 | 
            -
                in the standard tickets/ directory structure.
         | 
| 18 | 
            -
                """
         | 
| 19 | 
            -
                
         | 
| 20 | 
            -
                def __init__(self, project_path: Optional[Path] = None):
         | 
| 21 | 
            -
                    """
         | 
| 22 | 
            -
                    Initialize ticket manager.
         | 
| 23 | 
            -
                    
         | 
| 24 | 
            -
                    Args:
         | 
| 25 | 
            -
                        project_path: Project root (defaults to current directory)
         | 
| 26 | 
            -
                    """
         | 
| 27 | 
            -
                    self.logger = get_logger(__name__)
         | 
| 28 | 
            -
                    self.project_path = project_path or Path.cwd()
         | 
| 29 | 
            -
                    self.task_manager = self._init_task_manager()
         | 
| 30 | 
            -
                    
         | 
| 31 | 
            -
                def _init_task_manager(self):
         | 
| 32 | 
            -
                    """Initialize ai-trackdown-pytools TicketManager."""
         | 
| 33 | 
            -
                    try:
         | 
| 34 | 
            -
                        from ai_trackdown_pytools.core.task import TicketManager as AITicketManager
         | 
| 35 | 
            -
                        from ai_trackdown_pytools import Config, Project
         | 
| 36 | 
            -
                        
         | 
| 37 | 
            -
                        # First, ensure tickets directory exists
         | 
| 38 | 
            -
                        tickets_dir = self.project_path / "tickets"
         | 
| 39 | 
            -
                        if not tickets_dir.exists():
         | 
| 40 | 
            -
                            tickets_dir.mkdir(exist_ok=True)
         | 
| 41 | 
            -
                            (tickets_dir / "epics").mkdir(exist_ok=True)
         | 
| 42 | 
            -
                            (tickets_dir / "issues").mkdir(exist_ok=True)
         | 
| 43 | 
            -
                            (tickets_dir / "tasks").mkdir(exist_ok=True)
         | 
| 44 | 
            -
                            self.logger.info(f"Created tickets directory structure at: {tickets_dir}")
         | 
| 45 | 
            -
                        
         | 
| 46 | 
            -
                        # Use standardized config format (.trackdown.yaml)
         | 
| 47 | 
            -
                        config_file = self.project_path / ".trackdown.yaml"
         | 
| 48 | 
            -
                        
         | 
| 49 | 
            -
                        # Check if config exists, create if needed
         | 
| 50 | 
            -
                        if not config_file.exists():
         | 
| 51 | 
            -
                            try:
         | 
| 52 | 
            -
                                config = Config.create_default(config_file)  # Pass Path object directly
         | 
| 53 | 
            -
                                config.set("paths.tickets_dir", "tickets")
         | 
| 54 | 
            -
                                config.set("paths.epics_dir", "tickets/epics")
         | 
| 55 | 
            -
                                config.set("paths.issues_dir", "tickets/issues")
         | 
| 56 | 
            -
                                config.set("paths.tasks_dir", "tickets/tasks")
         | 
| 57 | 
            -
                                config.save()
         | 
| 58 | 
            -
                                self.logger.info("Created .trackdown.yaml configuration")
         | 
| 59 | 
            -
                            except Exception as config_error:
         | 
| 60 | 
            -
                                self.logger.warning(f"Could not create config file: {config_error}")
         | 
| 61 | 
            -
                                self.logger.info("Proceeding without config file - using defaults")
         | 
| 62 | 
            -
                        else:
         | 
| 63 | 
            -
                            self.logger.info(f"Using configuration from: {config_file}")
         | 
| 64 | 
            -
                        
         | 
| 65 | 
            -
                        # Initialize TicketManager directly with the project path
         | 
| 66 | 
            -
                        # TicketManager will handle project initialization internally
         | 
| 67 | 
            -
                        task_manager = AITicketManager(self.project_path)  # Pass Path object directly
         | 
| 15 | 
            +
                def get_ticket(self, *args, **kwargs):
         | 
| 16 | 
            +
                    """Stub method."""
         | 
| 17 | 
            +
                    return None
         | 
| 68 18 |  | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
                        
         | 
| 77 | 
            -
                    except ImportError as e:
         | 
| 78 | 
            -
                        import_msg = str(e)
         | 
| 79 | 
            -
                        if "ai_trackdown_pytools" in import_msg.lower():
         | 
| 80 | 
            -
                            self.logger.error("ai-trackdown-pytools is not installed")
         | 
| 81 | 
            -
                            self.logger.info("Install with: pip install ai-trackdown-pytools")
         | 
| 82 | 
            -
                        else:
         | 
| 83 | 
            -
                            self.logger.error(f"Missing dependency: {import_msg}")
         | 
| 84 | 
            -
                            self.logger.info("Ensure all required packages are installed")
         | 
| 85 | 
            -
                        self.logger.debug(f"Import error details: {import_msg}")
         | 
| 86 | 
            -
                        return None
         | 
| 87 | 
            -
                    except AttributeError as e:
         | 
| 88 | 
            -
                        attr_msg = str(e)
         | 
| 89 | 
            -
                        if "TaskManager" in attr_msg:
         | 
| 90 | 
            -
                            self.logger.error("TaskManager class not found in ai-trackdown-pytools")
         | 
| 91 | 
            -
                            self.logger.info("This may indicate an incompatible version")
         | 
| 92 | 
            -
                        else:
         | 
| 93 | 
            -
                            self.logger.error(f"ai-trackdown-pytools API mismatch: {attr_msg}")
         | 
| 94 | 
            -
                        self.logger.info("Try updating: pip install --upgrade ai-trackdown-pytools")
         | 
| 95 | 
            -
                        return None
         | 
| 96 | 
            -
                    except FileNotFoundError as e:
         | 
| 97 | 
            -
                        self.logger.error(f"Required file or directory not found: {e}")
         | 
| 98 | 
            -
                        self.logger.info("Ensure the project directory exists and is accessible")
         | 
| 99 | 
            -
                        return None
         | 
| 100 | 
            -
                    except PermissionError as e:
         | 
| 101 | 
            -
                        self.logger.error(f"Permission denied accessing ticket files: {e}")
         | 
| 102 | 
            -
                        self.logger.info("Check file permissions in the tickets/ directory")
         | 
| 103 | 
            -
                        self.logger.info("You may need to run with appropriate permissions")
         | 
| 104 | 
            -
                        return None
         | 
| 105 | 
            -
                    except Exception as e:
         | 
| 106 | 
            -
                        self.logger.error(f"Unexpected error initializing TaskManager: {e.__class__.__name__}: {e}")
         | 
| 107 | 
            -
                        self.logger.info("This could be due to:")
         | 
| 108 | 
            -
                        self.logger.info("  - Corrupted configuration files")
         | 
| 109 | 
            -
                        self.logger.info("  - Incompatible ai-trackdown-pytools version")
         | 
| 110 | 
            -
                        self.logger.info("  - Missing dependencies")
         | 
| 111 | 
            -
                        self.logger.debug(f"Full error details:", exc_info=True)
         | 
| 112 | 
            -
                        return None
         | 
| 113 | 
            -
                
         | 
| 114 | 
            -
                def create_ticket(
         | 
| 115 | 
            -
                    self,
         | 
| 116 | 
            -
                    title: str,
         | 
| 117 | 
            -
                    ticket_type: str = "task",
         | 
| 118 | 
            -
                    description: str = "",
         | 
| 119 | 
            -
                    priority: str = "medium",
         | 
| 120 | 
            -
                    tags: Optional[List[str]] = None,
         | 
| 121 | 
            -
                    source: str = "claude-mpm",
         | 
| 122 | 
            -
                    parent_epic: Optional[str] = None,
         | 
| 123 | 
            -
                    parent_issue: Optional[str] = None,
         | 
| 124 | 
            -
                    **kwargs
         | 
| 125 | 
            -
                ) -> Optional[str]:
         | 
| 126 | 
            -
                    """
         | 
| 127 | 
            -
                    Create a ticket using ai-trackdown-pytools.
         | 
| 128 | 
            -
                    
         | 
| 129 | 
            -
                    Args:
         | 
| 130 | 
            -
                        title: Ticket title
         | 
| 131 | 
            -
                        ticket_type: Type (task, bug, feature, etc.)
         | 
| 132 | 
            -
                        description: Detailed description
         | 
| 133 | 
            -
                        priority: Priority level (low, medium, high, critical)
         | 
| 134 | 
            -
                        tags: List of tags/labels
         | 
| 135 | 
            -
                        source: Source identifier
         | 
| 136 | 
            -
                        parent_epic: Parent epic ID (optional)
         | 
| 137 | 
            -
                        parent_issue: Parent issue ID (optional)
         | 
| 138 | 
            -
                        **kwargs: Additional metadata
         | 
| 139 | 
            -
                        
         | 
| 140 | 
            -
                    Returns:
         | 
| 141 | 
            -
                        Ticket ID if created, None on failure
         | 
| 142 | 
            -
                    """
         | 
| 143 | 
            -
                    if not self.task_manager:
         | 
| 144 | 
            -
                        self.logger.error("TaskManager not available - cannot create ticket")
         | 
| 145 | 
            -
                        self.logger.info("Please ensure ai-trackdown-pytools is installed and properly configured")
         | 
| 146 | 
            -
                        self.logger.info("Run: pip install ai-trackdown-pytools")
         | 
| 147 | 
            -
                        return None
         | 
| 148 | 
            -
                    
         | 
| 149 | 
            -
                    try:
         | 
| 150 | 
            -
                        # Validate input
         | 
| 151 | 
            -
                        if not title or not title.strip():
         | 
| 152 | 
            -
                            self.logger.error("Cannot create ticket with empty title")
         | 
| 153 | 
            -
                            return None
         | 
| 154 | 
            -
                        
         | 
| 155 | 
            -
                        # Validate priority
         | 
| 156 | 
            -
                        valid_priorities = ['low', 'medium', 'high', 'critical']
         | 
| 157 | 
            -
                        if priority.lower() not in valid_priorities:
         | 
| 158 | 
            -
                            self.logger.warning(f"Invalid priority '{priority}', using 'medium'")
         | 
| 159 | 
            -
                            self.logger.info(f"Valid priorities are: {', '.join(valid_priorities)}")
         | 
| 160 | 
            -
                            priority = 'medium'
         | 
| 161 | 
            -
                        
         | 
| 162 | 
            -
                        # Validate ticket type
         | 
| 163 | 
            -
                        valid_types = ['task', 'bug', 'feature', 'issue', 'enhancement', 'documentation']
         | 
| 164 | 
            -
                        if ticket_type.lower() not in valid_types:
         | 
| 165 | 
            -
                            self.logger.warning(f"Non-standard ticket type '{ticket_type}'")
         | 
| 166 | 
            -
                            self.logger.info(f"Common types are: {', '.join(valid_types)}")
         | 
| 167 | 
            -
                        
         | 
| 168 | 
            -
                        # Prepare tags
         | 
| 169 | 
            -
                        if tags is None:
         | 
| 170 | 
            -
                            tags = []
         | 
| 171 | 
            -
                        
         | 
| 172 | 
            -
                        # Add type and source tags
         | 
| 173 | 
            -
                        tags.extend([ticket_type, f"source:{source}", "auto-extracted"])
         | 
| 174 | 
            -
                        
         | 
| 175 | 
            -
                        # Remove duplicates
         | 
| 176 | 
            -
                        tags = list(set(tags))
         | 
| 177 | 
            -
                        
         | 
| 178 | 
            -
                        # Prepare task data
         | 
| 179 | 
            -
                        task_data = {
         | 
| 180 | 
            -
                            'title': title.strip(),
         | 
| 181 | 
            -
                            'description': description or f"Auto-extracted {ticket_type} from Claude MPM session",
         | 
| 182 | 
            -
                            'status': 'open',
         | 
| 183 | 
            -
                            'priority': priority.lower(),
         | 
| 184 | 
            -
                            'assignees': [],
         | 
| 185 | 
            -
                            'tags': tags,
         | 
| 186 | 
            -
                            'metadata': {
         | 
| 187 | 
            -
                                'source': source,
         | 
| 188 | 
            -
                                'ticket_type': ticket_type,
         | 
| 189 | 
            -
                                'created_by': 'claude-mpm',
         | 
| 190 | 
            -
                                'extracted_at': datetime.now().isoformat(),
         | 
| 191 | 
            -
                                **kwargs
         | 
| 192 | 
            -
                            }
         | 
| 193 | 
            -
                        }
         | 
| 194 | 
            -
                        
         | 
| 195 | 
            -
                        # Add parent references if provided
         | 
| 196 | 
            -
                        if parent_epic:
         | 
| 197 | 
            -
                            task_data['metadata']['parent_epic'] = parent_epic
         | 
| 198 | 
            -
                            self.logger.debug(f"Linking to parent epic: {parent_epic}")
         | 
| 199 | 
            -
                        if parent_issue:
         | 
| 200 | 
            -
                            task_data['metadata']['parent_issue'] = parent_issue
         | 
| 201 | 
            -
                            self.logger.debug(f"Linking to parent issue: {parent_issue}")
         | 
| 202 | 
            -
                        
         | 
| 203 | 
            -
                        # Create the task
         | 
| 204 | 
            -
                        task = self.task_manager.create_task(**task_data)
         | 
| 205 | 
            -
                        
         | 
| 206 | 
            -
                        if task and hasattr(task, 'id'):
         | 
| 207 | 
            -
                            self.logger.info(f"Successfully created ticket: {task.id} - {title}")
         | 
| 208 | 
            -
                            return task.id
         | 
| 209 | 
            -
                        else:
         | 
| 210 | 
            -
                            self.logger.error(f"Task creation failed - no ID returned")
         | 
| 211 | 
            -
                            self.logger.info("The task may have been created but without proper ID assignment")
         | 
| 212 | 
            -
                            return None
         | 
| 213 | 
            -
                        
         | 
| 214 | 
            -
                    except AttributeError as e:
         | 
| 215 | 
            -
                        attr_msg = str(e)
         | 
| 216 | 
            -
                        if "create_task" in attr_msg:
         | 
| 217 | 
            -
                            self.logger.error("create_task method not found in TaskManager")
         | 
| 218 | 
            -
                            self.logger.info("The ai-trackdown-pytools API may have changed")
         | 
| 219 | 
            -
                            self.logger.info("Check for updates or API documentation")
         | 
| 220 | 
            -
                        else:
         | 
| 221 | 
            -
                            self.logger.error(f"API mismatch when creating ticket: {attr_msg}")
         | 
| 222 | 
            -
                        return None
         | 
| 223 | 
            -
                    except ValueError as e:
         | 
| 224 | 
            -
                        self.logger.error(f"Invalid data provided for ticket: {e}")
         | 
| 225 | 
            -
                        self.logger.info("Check that all required fields are provided correctly")
         | 
| 226 | 
            -
                        return None
         | 
| 227 | 
            -
                    except PermissionError as e:
         | 
| 228 | 
            -
                        self.logger.error(f"Permission denied when creating ticket: {e}")
         | 
| 229 | 
            -
                        self.logger.info("Check write permissions for the tickets/ directory")
         | 
| 230 | 
            -
                        return None
         | 
| 231 | 
            -
                    except Exception as e:
         | 
| 232 | 
            -
                        self.logger.error(f"Unexpected error creating ticket: {e.__class__.__name__}: {e}")
         | 
| 233 | 
            -
                        self.logger.info("This could be due to:")
         | 
| 234 | 
            -
                        self.logger.info("  - Disk full or quota exceeded")
         | 
| 235 | 
            -
                        self.logger.info("  - Invalid characters in title or description")
         | 
| 236 | 
            -
                        self.logger.info("  - Network issues (if using remote storage)")
         | 
| 237 | 
            -
                        self.logger.debug("Full error details:", exc_info=True)
         | 
| 238 | 
            -
                        return None
         | 
| 239 | 
            -
                
         | 
| 240 | 
            -
                def list_recent_tickets(self, limit: int = 10) -> List[Dict[str, Any]]:
         | 
| 241 | 
            -
                    """
         | 
| 242 | 
            -
                    List recent tickets.
         | 
| 243 | 
            -
                    
         | 
| 244 | 
            -
                    Args:
         | 
| 245 | 
            -
                        limit: Maximum number of tickets to return
         | 
| 246 | 
            -
                        
         | 
| 247 | 
            -
                    Returns:
         | 
| 248 | 
            -
                        List of ticket summaries
         | 
| 249 | 
            -
                    """
         | 
| 250 | 
            -
                    if not self.task_manager:
         | 
| 251 | 
            -
                        self.logger.warning("TaskManager not available - cannot list tickets")
         | 
| 252 | 
            -
                        self.logger.info("Run: pip install ai-trackdown-pytools")
         | 
| 253 | 
            -
                        return []
         | 
| 254 | 
            -
                    
         | 
| 255 | 
            -
                    try:
         | 
| 256 | 
            -
                        # Validate limit
         | 
| 257 | 
            -
                        if limit < 1:
         | 
| 258 | 
            -
                            self.logger.warning(f"Invalid limit {limit}, using 10")
         | 
| 259 | 
            -
                            limit = 10
         | 
| 260 | 
            -
                        elif limit > 100:
         | 
| 261 | 
            -
                            self.logger.warning(f"Limit {limit} too high, capping at 100")
         | 
| 262 | 
            -
                            limit = 100
         | 
| 263 | 
            -
                        
         | 
| 264 | 
            -
                        tasks = self.task_manager.get_recent_tasks(limit=limit)
         | 
| 265 | 
            -
                        
         | 
| 266 | 
            -
                        if not tasks:
         | 
| 267 | 
            -
                            self.logger.info("No tickets found in the system")
         | 
| 268 | 
            -
                            return []
         | 
| 269 | 
            -
                        
         | 
| 270 | 
            -
                        tickets = []
         | 
| 271 | 
            -
                        for task in tasks:
         | 
| 272 | 
            -
                            try:
         | 
| 273 | 
            -
                                ticket_data = {
         | 
| 274 | 
            -
                                    'id': getattr(task, 'id', 'UNKNOWN'),
         | 
| 275 | 
            -
                                    'title': getattr(task, 'title', 'Untitled'),
         | 
| 276 | 
            -
                                    'status': getattr(task, 'status', 'unknown'),
         | 
| 277 | 
            -
                                    'priority': getattr(task, 'priority', 'medium'),
         | 
| 278 | 
            -
                                    'tags': getattr(task, 'tags', []),
         | 
| 279 | 
            -
                                    'created_at': getattr(task, 'created_at', 'N/A'),
         | 
| 280 | 
            -
                                }
         | 
| 281 | 
            -
                                tickets.append(ticket_data)
         | 
| 282 | 
            -
                            except Exception as task_error:
         | 
| 283 | 
            -
                                self.logger.warning(f"Error processing task: {task_error}")
         | 
| 284 | 
            -
                                self.logger.debug(f"Task object type: {type(task)}")
         | 
| 285 | 
            -
                                continue
         | 
| 286 | 
            -
                        
         | 
| 287 | 
            -
                        self.logger.info(f"Retrieved {len(tickets)} tickets")
         | 
| 288 | 
            -
                        return tickets
         | 
| 289 | 
            -
                        
         | 
| 290 | 
            -
                    except AttributeError as e:
         | 
| 291 | 
            -
                        attr_msg = str(e)
         | 
| 292 | 
            -
                        if "get_recent_tasks" in attr_msg:
         | 
| 293 | 
            -
                            self.logger.error("get_recent_tasks method not found in TaskManager")
         | 
| 294 | 
            -
                            self.logger.info("This method may not be available in your version")
         | 
| 295 | 
            -
                            self.logger.info("Try using the CLI directly: aitrackdown task list")
         | 
| 296 | 
            -
                        else:
         | 
| 297 | 
            -
                            self.logger.error(f"API mismatch when listing tickets: {attr_msg}")
         | 
| 298 | 
            -
                        return []
         | 
| 299 | 
            -
                    except FileNotFoundError as e:
         | 
| 300 | 
            -
                        self.logger.error(f"Tickets directory not found: {e}")
         | 
| 301 | 
            -
                        self.logger.info("Ensure the tickets/ directory exists")
         | 
| 302 | 
            -
                        return []
         | 
| 303 | 
            -
                    except PermissionError as e:
         | 
| 304 | 
            -
                        self.logger.error(f"Permission denied reading tickets: {e}")
         | 
| 305 | 
            -
                        self.logger.info("Check read permissions for the tickets/ directory")
         | 
| 306 | 
            -
                        return []
         | 
| 307 | 
            -
                    except Exception as e:
         | 
| 308 | 
            -
                        self.logger.error(f"Failed to list tickets: {e.__class__.__name__}: {e}")
         | 
| 309 | 
            -
                        self.logger.info("Try using the CLI directly: aitrackdown task list")
         | 
| 310 | 
            -
                        self.logger.debug("Full error details:", exc_info=True)
         | 
| 311 | 
            -
                        return []
         | 
| 312 | 
            -
                
         | 
| 313 | 
            -
                def get_ticket(self, ticket_id: str) -> Optional[Dict[str, Any]]:
         | 
| 314 | 
            -
                    """
         | 
| 315 | 
            -
                    Get a specific ticket.
         | 
| 316 | 
            -
                    
         | 
| 317 | 
            -
                    Args:
         | 
| 318 | 
            -
                        ticket_id: Ticket ID
         | 
| 319 | 
            -
                        
         | 
| 320 | 
            -
                    Returns:
         | 
| 321 | 
            -
                        Ticket data or None
         | 
| 322 | 
            -
                    """
         | 
| 323 | 
            -
                    if not self.task_manager:
         | 
| 324 | 
            -
                        self.logger.error("TaskManager not available - cannot retrieve ticket")
         | 
| 325 | 
            -
                        self.logger.info("Run: pip install ai-trackdown-pytools")
         | 
| 326 | 
            -
                        return None
         | 
| 327 | 
            -
                    
         | 
| 328 | 
            -
                    if not ticket_id or not ticket_id.strip():
         | 
| 329 | 
            -
                        self.logger.error("Invalid ticket ID provided")
         | 
| 330 | 
            -
                        return None
         | 
| 331 | 
            -
                    
         | 
| 332 | 
            -
                    try:
         | 
| 333 | 
            -
                        task = self.task_manager.load_task(ticket_id.strip())
         | 
| 334 | 
            -
                        
         | 
| 335 | 
            -
                        if not task:
         | 
| 336 | 
            -
                            self.logger.warning(f"Ticket {ticket_id} not found")
         | 
| 337 | 
            -
                            return None
         | 
| 338 | 
            -
                        
         | 
| 339 | 
            -
                        # Safely extract all fields with defaults
         | 
| 340 | 
            -
                        ticket_data = {
         | 
| 341 | 
            -
                            'id': getattr(task, 'id', ticket_id),
         | 
| 342 | 
            -
                            'title': getattr(task, 'title', 'Untitled'),
         | 
| 343 | 
            -
                            'description': getattr(task, 'description', ''),
         | 
| 344 | 
            -
                            'status': getattr(task, 'status', 'unknown'),
         | 
| 345 | 
            -
                            'priority': getattr(task, 'priority', 'medium'),
         | 
| 346 | 
            -
                            'tags': getattr(task, 'tags', []),
         | 
| 347 | 
            -
                            'assignees': getattr(task, 'assignees', []),
         | 
| 348 | 
            -
                            'created_at': getattr(task, 'created_at', 'N/A'),
         | 
| 349 | 
            -
                            'updated_at': getattr(task, 'updated_at', 'N/A'),
         | 
| 350 | 
            -
                            'metadata': getattr(task, 'metadata', {}),
         | 
| 351 | 
            -
                        }
         | 
| 352 | 
            -
                        
         | 
| 353 | 
            -
                        self.logger.info(f"Successfully retrieved ticket: {ticket_id}")
         | 
| 354 | 
            -
                        return ticket_data
         | 
| 355 | 
            -
                        
         | 
| 356 | 
            -
                    except AttributeError as e:
         | 
| 357 | 
            -
                        attr_msg = str(e)
         | 
| 358 | 
            -
                        if "load_task" in attr_msg:
         | 
| 359 | 
            -
                            self.logger.error("load_task method not found in TaskManager")
         | 
| 360 | 
            -
                            self.logger.info("The API may have changed or this method is not available")
         | 
| 361 | 
            -
                        else:
         | 
| 362 | 
            -
                            self.logger.error(f"Error accessing ticket attributes: {attr_msg}")
         | 
| 363 | 
            -
                        return None
         | 
| 364 | 
            -
                    except FileNotFoundError as e:
         | 
| 365 | 
            -
                        self.logger.error(f"Ticket file not found: {ticket_id}")
         | 
| 366 | 
            -
                        self.logger.info(f"The ticket may have been deleted or the ID is incorrect")
         | 
| 367 | 
            -
                        return None
         | 
| 368 | 
            -
                    except PermissionError as e:
         | 
| 369 | 
            -
                        self.logger.error(f"Permission denied reading ticket {ticket_id}: {e}")
         | 
| 370 | 
            -
                        return None
         | 
| 371 | 
            -
                    except Exception as e:
         | 
| 372 | 
            -
                        self.logger.error(f"Failed to get ticket {ticket_id}: {e.__class__.__name__}: {e}")
         | 
| 373 | 
            -
                        self.logger.info(f"Try using the CLI: aitrackdown show {ticket_id}")
         | 
| 374 | 
            -
                        self.logger.debug("Full error details:", exc_info=True)
         | 
| 375 | 
            -
                        return None
         | 
| 376 | 
            -
                
         | 
| 377 | 
            -
                # ================================================================================
         | 
| 378 | 
            -
                # Interface Adapter Methods
         | 
| 379 | 
            -
                # ================================================================================
         | 
| 380 | 
            -
                # These methods adapt the existing implementation to comply with TicketManagerInterface
         | 
| 381 | 
            -
                
         | 
| 382 | 
            -
                def create_task(self, title: str, description: str, **kwargs) -> Optional[str]:
         | 
| 383 | 
            -
                    """Create a new task ticket.
         | 
| 384 | 
            -
                    
         | 
| 385 | 
            -
                    WHY: This adapter method provides interface compliance by wrapping
         | 
| 386 | 
            -
                    the underlying task manager's create functionality.
         | 
| 387 | 
            -
                    
         | 
| 388 | 
            -
                    Args:
         | 
| 389 | 
            -
                        title: Task title
         | 
| 390 | 
            -
                        description: Task description
         | 
| 391 | 
            -
                        **kwargs: Additional task properties
         | 
| 392 | 
            -
                        
         | 
| 393 | 
            -
                    Returns:
         | 
| 394 | 
            -
                        Task ID if created successfully, None otherwise
         | 
| 395 | 
            -
                    """
         | 
| 396 | 
            -
                    if not self.task_manager:
         | 
| 397 | 
            -
                        self.logger.error("Task manager not initialized")
         | 
| 398 | 
            -
                        return None
         | 
| 399 | 
            -
                    
         | 
| 400 | 
            -
                    try:
         | 
| 401 | 
            -
                        # Create task using ai-trackdown-pytools
         | 
| 402 | 
            -
                        from ai_trackdown_pytools.core.task import Task
         | 
| 403 | 
            -
                        
         | 
| 404 | 
            -
                        task = Task(
         | 
| 405 | 
            -
                            title=title,
         | 
| 406 | 
            -
                            description=description,
         | 
| 407 | 
            -
                            status=kwargs.get('status', 'open'),
         | 
| 408 | 
            -
                            priority=kwargs.get('priority', 'medium'),
         | 
| 409 | 
            -
                            tags=kwargs.get('tags', []),
         | 
| 410 | 
            -
                            assignees=kwargs.get('assignees', [])
         | 
| 411 | 
            -
                        )
         | 
| 412 | 
            -
                        
         | 
| 413 | 
            -
                        # Save the task
         | 
| 414 | 
            -
                        task_id = self.task_manager.create_task(task)
         | 
| 415 | 
            -
                        self.logger.info(f"Created task {task_id}: {title}")
         | 
| 416 | 
            -
                        return task_id
         | 
| 417 | 
            -
                        
         | 
| 418 | 
            -
                    except ImportError:
         | 
| 419 | 
            -
                        self.logger.error("ai-trackdown-pytools not available")
         | 
| 420 | 
            -
                        return None
         | 
| 421 | 
            -
                    except Exception as e:
         | 
| 422 | 
            -
                        self.logger.error(f"Failed to create task: {e}")
         | 
| 423 | 
            -
                        return None
         | 
| 424 | 
            -
                
         | 
| 425 | 
            -
                def update_task(self, task_id: str, **updates) -> bool:
         | 
| 426 | 
            -
                    """Update an existing task.
         | 
| 427 | 
            -
                    
         | 
| 428 | 
            -
                    WHY: This adapter method provides interface compliance by wrapping
         | 
| 429 | 
            -
                    task update operations.
         | 
| 430 | 
            -
                    
         | 
| 431 | 
            -
                    Args:
         | 
| 432 | 
            -
                        task_id: ID of task to update
         | 
| 433 | 
            -
                        **updates: Fields to update
         | 
| 434 | 
            -
                        
         | 
| 435 | 
            -
                    Returns:
         | 
| 436 | 
            -
                        True if update successful
         | 
| 437 | 
            -
                    """
         | 
| 438 | 
            -
                    if not self.task_manager:
         | 
| 439 | 
            -
                        self.logger.error("Task manager not initialized")
         | 
| 440 | 
            -
                        return False
         | 
| 441 | 
            -
                    
         | 
| 442 | 
            -
                    try:
         | 
| 443 | 
            -
                        # Get the existing task
         | 
| 444 | 
            -
                        task = self.task_manager.get_task(task_id)
         | 
| 445 | 
            -
                        if not task:
         | 
| 446 | 
            -
                            self.logger.error(f"Task {task_id} not found")
         | 
| 447 | 
            -
                            return False
         | 
| 448 | 
            -
                        
         | 
| 449 | 
            -
                        # Apply updates
         | 
| 450 | 
            -
                        for key, value in updates.items():
         | 
| 451 | 
            -
                            if hasattr(task, key):
         | 
| 452 | 
            -
                                setattr(task, key, value)
         | 
| 453 | 
            -
                        
         | 
| 454 | 
            -
                        # Save the updated task
         | 
| 455 | 
            -
                        self.task_manager.update_task(task)
         | 
| 456 | 
            -
                        self.logger.info(f"Updated task {task_id}")
         | 
| 457 | 
            -
                        return True
         | 
| 458 | 
            -
                        
         | 
| 459 | 
            -
                    except Exception as e:
         | 
| 460 | 
            -
                        self.logger.error(f"Failed to update task {task_id}: {e}")
         | 
| 461 | 
            -
                        return False
         | 
| 462 | 
            -
                
         | 
| 463 | 
            -
                def get_task(self, task_id: str) -> Optional[Dict[str, Any]]:
         | 
| 464 | 
            -
                    """Get task details.
         | 
| 465 | 
            -
                    
         | 
| 466 | 
            -
                    WHY: This adapter method provides interface compliance by wrapping
         | 
| 467 | 
            -
                    the existing get_ticket method.
         | 
| 468 | 
            -
                    
         | 
| 469 | 
            -
                    Args:
         | 
| 470 | 
            -
                        task_id: ID of task to retrieve
         | 
| 471 | 
            -
                        
         | 
| 472 | 
            -
                    Returns:
         | 
| 473 | 
            -
                        Task data dictionary or None if not found
         | 
| 474 | 
            -
                    """
         | 
| 475 | 
            -
                    # Use existing get_ticket method which already returns dict format
         | 
| 476 | 
            -
                    return self.get_ticket(task_id)
         | 
| 477 | 
            -
                
         | 
| 478 | 
            -
                def list_tasks(self, status: Optional[str] = None, **filters) -> List[Dict[str, Any]]:
         | 
| 479 | 
            -
                    """List tasks with optional filtering.
         | 
| 480 | 
            -
                    
         | 
| 481 | 
            -
                    WHY: This adapter method provides interface compliance by wrapping
         | 
| 482 | 
            -
                    task listing operations.
         | 
| 483 | 
            -
                    
         | 
| 484 | 
            -
                    Args:
         | 
| 485 | 
            -
                        status: Optional status filter
         | 
| 486 | 
            -
                        **filters: Additional filter criteria
         | 
| 487 | 
            -
                        
         | 
| 488 | 
            -
                    Returns:
         | 
| 489 | 
            -
                        List of task dictionaries
         | 
| 490 | 
            -
                    """
         | 
| 491 | 
            -
                    if not self.task_manager:
         | 
| 492 | 
            -
                        self.logger.error("Task manager not initialized")
         | 
| 493 | 
            -
                        return []
         | 
| 494 | 
            -
                    
         | 
| 495 | 
            -
                    try:
         | 
| 496 | 
            -
                        # Get all tasks
         | 
| 497 | 
            -
                        tasks = self.task_manager.list_tasks()
         | 
| 498 | 
            -
                        
         | 
| 499 | 
            -
                        # Apply filters
         | 
| 500 | 
            -
                        filtered_tasks = []
         | 
| 501 | 
            -
                        for task in tasks:
         | 
| 502 | 
            -
                            # Check status filter
         | 
| 503 | 
            -
                            if status and task.get('status') != status:
         | 
| 504 | 
            -
                                continue
         | 
| 505 | 
            -
                            
         | 
| 506 | 
            -
                            # Check additional filters
         | 
| 507 | 
            -
                            match = True
         | 
| 508 | 
            -
                            for key, value in filters.items():
         | 
| 509 | 
            -
                                if task.get(key) != value:
         | 
| 510 | 
            -
                                    match = False
         | 
| 511 | 
            -
                                    break
         | 
| 512 | 
            -
                            
         | 
| 513 | 
            -
                            if match:
         | 
| 514 | 
            -
                                filtered_tasks.append(task)
         | 
| 515 | 
            -
                        
         | 
| 516 | 
            -
                        return filtered_tasks
         | 
| 517 | 
            -
                        
         | 
| 518 | 
            -
                    except Exception as e:
         | 
| 519 | 
            -
                        self.logger.error(f"Failed to list tasks: {e}")
         | 
| 520 | 
            -
                        return []
         | 
| 521 | 
            -
                
         | 
| 522 | 
            -
                def close_task(self, task_id: str, resolution: Optional[str] = None) -> bool:
         | 
| 523 | 
            -
                    """Close a task.
         | 
| 524 | 
            -
                    
         | 
| 525 | 
            -
                    WHY: This adapter method provides interface compliance by updating
         | 
| 526 | 
            -
                    task status to closed.
         | 
| 527 | 
            -
                    
         | 
| 528 | 
            -
                    Args:
         | 
| 529 | 
            -
                        task_id: ID of task to close
         | 
| 530 | 
            -
                        resolution: Optional resolution description
         | 
| 531 | 
            -
                        
         | 
| 532 | 
            -
                    Returns:
         | 
| 533 | 
            -
                        True if close successful
         | 
| 534 | 
            -
                    """
         | 
| 535 | 
            -
                    updates = {'status': 'closed'}
         | 
| 536 | 
            -
                    if resolution:
         | 
| 537 | 
            -
                        updates['resolution'] = resolution
         | 
| 538 | 
            -
                    
         | 
| 539 | 
            -
                    return self.update_task(task_id, **updates)
         | 
| 19 | 
            +
                def update_task(self, *args, **kwargs):
         | 
| 20 | 
            +
                    """Stub method."""
         | 
| 21 | 
            +
                    return False
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def close_task(self, *args, **kwargs):
         | 
| 24 | 
            +
                    """Stub method."""
         | 
| 25 | 
            +
                    return False
         |