claude-mpm 3.5.4__py3-none-any.whl → 3.6.0__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/.claude-mpm/logs/hooks_20250728.log +10 -0
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +96 -23
- claude_mpm/agents/BASE_PM.md +273 -0
- claude_mpm/agents/INSTRUCTIONS.md +114 -102
- claude_mpm/agents/agent-template.yaml +83 -0
- claude_mpm/agents/agent_loader.py +36 -1
- claude_mpm/agents/async_agent_loader.py +421 -0
- claude_mpm/agents/templates/code_analyzer.json +81 -0
- claude_mpm/agents/templates/data_engineer.json +18 -3
- claude_mpm/agents/templates/documentation.json +18 -3
- claude_mpm/agents/templates/engineer.json +19 -4
- claude_mpm/agents/templates/ops.json +18 -3
- claude_mpm/agents/templates/qa.json +20 -4
- claude_mpm/agents/templates/research.json +20 -4
- claude_mpm/agents/templates/security.json +18 -3
- claude_mpm/agents/templates/version_control.json +16 -3
- claude_mpm/cli/README.md +108 -0
- claude_mpm/cli/__init__.py +5 -1
- claude_mpm/cli/commands/__init__.py +5 -1
- claude_mpm/cli/commands/agents.py +233 -6
- claude_mpm/cli/commands/aggregate.py +462 -0
- claude_mpm/cli/commands/config.py +277 -0
- claude_mpm/cli/commands/run.py +228 -47
- claude_mpm/cli/parser.py +176 -1
- claude_mpm/cli/utils.py +9 -1
- claude_mpm/cli_module/refactoring_guide.md +253 -0
- claude_mpm/config/async_logging_config.yaml +145 -0
- claude_mpm/constants.py +19 -0
- claude_mpm/core/.claude-mpm/logs/hooks_20250730.log +34 -0
- claude_mpm/core/claude_runner.py +413 -76
- claude_mpm/core/config.py +161 -4
- claude_mpm/core/config_paths.py +0 -1
- claude_mpm/core/factories.py +9 -3
- claude_mpm/core/framework_loader.py +81 -0
- claude_mpm/dashboard/.claude-mpm/memories/README.md +36 -0
- claude_mpm/dashboard/README.md +121 -0
- claude_mpm/dashboard/static/js/dashboard.js.backup +1973 -0
- claude_mpm/dashboard/templates/.claude-mpm/memories/README.md +36 -0
- claude_mpm/dashboard/templates/.claude-mpm/memories/engineer_agent.md +39 -0
- claude_mpm/dashboard/templates/.claude-mpm/memories/version_control_agent.md +38 -0
- claude_mpm/hooks/README.md +96 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +391 -9
- claude_mpm/init.py +123 -18
- claude_mpm/models/agent_session.py +511 -0
- claude_mpm/schemas/agent_schema.json +435 -0
- claude_mpm/scripts/__init__.py +15 -0
- claude_mpm/scripts/start_activity_logging.py +86 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +326 -24
- claude_mpm/services/agents/deployment/async_agent_deployment.py +461 -0
- claude_mpm/services/agents/management/agent_management_service.py +2 -1
- claude_mpm/services/event_aggregator.py +547 -0
- claude_mpm/services/framework_claude_md_generator/README.md +92 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +3 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +2 -2
- claude_mpm/services/version_control/VERSION +1 -0
- claude_mpm/utils/agent_dependency_loader.py +655 -0
- claude_mpm/utils/console.py +11 -0
- claude_mpm/utils/dependency_cache.py +376 -0
- claude_mpm/utils/dependency_strategies.py +343 -0
- claude_mpm/utils/environment_context.py +310 -0
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/METADATA +87 -1
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/RECORD +67 -37
- claude_mpm/agents/templates/pm.json +0 -122
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/WHEEL +0 -0
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/top_level.txt +0 -0
    
        claude_mpm/cli/parser.py
    CHANGED
    
    | @@ -14,7 +14,7 @@ import argparse | |
| 14 14 | 
             
            from pathlib import Path
         | 
| 15 15 | 
             
            from typing import Optional, List
         | 
| 16 16 |  | 
| 17 | 
            -
            from ..constants import CLICommands, CLIPrefix, AgentCommands, MemoryCommands, MonitorCommands, LogLevel
         | 
| 17 | 
            +
            from ..constants import CLICommands, CLIPrefix, AgentCommands, MemoryCommands, MonitorCommands, LogLevel, ConfigCommands, AggregateCommands
         | 
| 18 18 |  | 
| 19 19 |  | 
| 20 20 | 
             
            def add_common_arguments(parser: argparse.ArgumentParser, version: str = None) -> None:
         | 
| @@ -127,6 +127,30 @@ def add_run_arguments(parser: argparse.ArgumentParser) -> None: | |
| 127 127 | 
             
                    help="Resume a session (last session if no ID specified, or specific session ID)"
         | 
| 128 128 | 
             
                )
         | 
| 129 129 |  | 
| 130 | 
            +
                # Dependency checking options
         | 
| 131 | 
            +
                dep_group = parser.add_argument_group('dependency options')
         | 
| 132 | 
            +
                dep_group.add_argument(
         | 
| 133 | 
            +
                    "--no-check-dependencies",
         | 
| 134 | 
            +
                    action="store_false",
         | 
| 135 | 
            +
                    dest="check_dependencies",
         | 
| 136 | 
            +
                    help="Skip agent dependency checking at startup"
         | 
| 137 | 
            +
                )
         | 
| 138 | 
            +
                dep_group.add_argument(
         | 
| 139 | 
            +
                    "--force-check-dependencies",
         | 
| 140 | 
            +
                    action="store_true",
         | 
| 141 | 
            +
                    help="Force dependency checking even if cached results exist"
         | 
| 142 | 
            +
                )
         | 
| 143 | 
            +
                dep_group.add_argument(
         | 
| 144 | 
            +
                    "--no-prompt",
         | 
| 145 | 
            +
                    action="store_true",
         | 
| 146 | 
            +
                    help="Never prompt for dependency installation (non-interactive mode)"
         | 
| 147 | 
            +
                )
         | 
| 148 | 
            +
                dep_group.add_argument(
         | 
| 149 | 
            +
                    "--force-prompt",
         | 
| 150 | 
            +
                    action="store_true",
         | 
| 151 | 
            +
                    help="Force interactive prompting even in non-TTY environments (use with caution)"
         | 
| 152 | 
            +
                )
         | 
| 153 | 
            +
                
         | 
| 130 154 | 
             
                # Input/output options
         | 
| 131 155 | 
             
                io_group = parser.add_argument_group('input/output options')
         | 
| 132 156 | 
             
                io_group.add_argument(
         | 
| @@ -229,6 +253,30 @@ def create_parser(prog_name: str = "claude-mpm", version: str = "0.0.0") -> argp | |
| 229 253 | 
             
                    help="Resume a session (last session if no ID specified, or specific session ID)"
         | 
| 230 254 | 
             
                )
         | 
| 231 255 |  | 
| 256 | 
            +
                # Dependency checking options (for backward compatibility at top level)
         | 
| 257 | 
            +
                dep_group_top = parser.add_argument_group('dependency options (when no command specified)')
         | 
| 258 | 
            +
                dep_group_top.add_argument(
         | 
| 259 | 
            +
                    "--no-check-dependencies",
         | 
| 260 | 
            +
                    action="store_false",
         | 
| 261 | 
            +
                    dest="check_dependencies",
         | 
| 262 | 
            +
                    help="Skip agent dependency checking at startup"
         | 
| 263 | 
            +
                )
         | 
| 264 | 
            +
                dep_group_top.add_argument(
         | 
| 265 | 
            +
                    "--force-check-dependencies",
         | 
| 266 | 
            +
                    action="store_true",
         | 
| 267 | 
            +
                    help="Force dependency checking even if cached results exist"
         | 
| 268 | 
            +
                )
         | 
| 269 | 
            +
                dep_group_top.add_argument(
         | 
| 270 | 
            +
                    "--no-prompt",
         | 
| 271 | 
            +
                    action="store_true",
         | 
| 272 | 
            +
                    help="Never prompt for dependency installation (non-interactive mode)"
         | 
| 273 | 
            +
                )
         | 
| 274 | 
            +
                dep_group_top.add_argument(
         | 
| 275 | 
            +
                    "--force-prompt",
         | 
| 276 | 
            +
                    action="store_true",
         | 
| 277 | 
            +
                    help="Force interactive prompting even in non-TTY environments (use with caution)"
         | 
| 278 | 
            +
                )
         | 
| 279 | 
            +
                
         | 
| 232 280 | 
             
                # Input/output options
         | 
| 233 281 | 
             
                io_group = parser.add_argument_group('input/output options (when no command specified)')
         | 
| 234 282 | 
             
                io_group.add_argument(
         | 
| @@ -353,6 +401,11 @@ def create_parser(prog_name: str = "claude-mpm", version: str = "0.0.0") -> argp | |
| 353 401 | 
             
                    type=Path,
         | 
| 354 402 | 
             
                    help="Target directory (default: .claude/agents/)"
         | 
| 355 403 | 
             
                )
         | 
| 404 | 
            +
                deploy_agents_parser.add_argument(
         | 
| 405 | 
            +
                    "--include-all",
         | 
| 406 | 
            +
                    action="store_true",
         | 
| 407 | 
            +
                    help="Include all agents, overriding exclusion configuration"
         | 
| 408 | 
            +
                )
         | 
| 356 409 |  | 
| 357 410 | 
             
                # Force deploy agents
         | 
| 358 411 | 
             
                force_deploy_parser = agents_subparsers.add_parser(
         | 
| @@ -364,6 +417,11 @@ def create_parser(prog_name: str = "claude-mpm", version: str = "0.0.0") -> argp | |
| 364 417 | 
             
                    type=Path,
         | 
| 365 418 | 
             
                    help="Target directory (default: .claude/agents/)"
         | 
| 366 419 | 
             
                )
         | 
| 420 | 
            +
                force_deploy_parser.add_argument(
         | 
| 421 | 
            +
                    "--include-all",
         | 
| 422 | 
            +
                    action="store_true",
         | 
| 423 | 
            +
                    help="Include all agents, overriding exclusion configuration"
         | 
| 424 | 
            +
                )
         | 
| 367 425 |  | 
| 368 426 | 
             
                # Clean agents
         | 
| 369 427 | 
             
                clean_agents_parser = agents_subparsers.add_parser(
         | 
| @@ -504,6 +562,119 @@ def create_parser(prog_name: str = "claude-mpm", version: str = "0.0.0") -> argp | |
| 504 562 | 
             
                    help="Output raw memory content in JSON format for programmatic processing"
         | 
| 505 563 | 
             
                )
         | 
| 506 564 |  | 
| 565 | 
            +
                # Add dependency management subcommands to agents
         | 
| 566 | 
            +
                deps_check_parser = agents_subparsers.add_parser(
         | 
| 567 | 
            +
                    'deps-check',
         | 
| 568 | 
            +
                    help='Check dependencies for deployed agents'
         | 
| 569 | 
            +
                )
         | 
| 570 | 
            +
                deps_check_parser.add_argument(
         | 
| 571 | 
            +
                    '--verbose',
         | 
| 572 | 
            +
                    action='store_true',
         | 
| 573 | 
            +
                    help='Enable verbose output'
         | 
| 574 | 
            +
                )
         | 
| 575 | 
            +
                deps_check_parser.add_argument(
         | 
| 576 | 
            +
                    '--agent',
         | 
| 577 | 
            +
                    type=str,
         | 
| 578 | 
            +
                    help='Check dependencies for a specific agent only'
         | 
| 579 | 
            +
                )
         | 
| 580 | 
            +
                
         | 
| 581 | 
            +
                deps_install_parser = agents_subparsers.add_parser(
         | 
| 582 | 
            +
                    'deps-install',
         | 
| 583 | 
            +
                    help='Install missing dependencies for deployed agents'
         | 
| 584 | 
            +
                )
         | 
| 585 | 
            +
                deps_install_parser.add_argument(
         | 
| 586 | 
            +
                    '--agent',
         | 
| 587 | 
            +
                    type=str,
         | 
| 588 | 
            +
                    help='Install dependencies for a specific agent only'
         | 
| 589 | 
            +
                )
         | 
| 590 | 
            +
                deps_install_parser.add_argument(
         | 
| 591 | 
            +
                    '--dry-run',
         | 
| 592 | 
            +
                    action='store_true',
         | 
| 593 | 
            +
                    help='Show what would be installed without actually installing'
         | 
| 594 | 
            +
                )
         | 
| 595 | 
            +
                
         | 
| 596 | 
            +
                deps_list_parser = agents_subparsers.add_parser(
         | 
| 597 | 
            +
                    'deps-list',
         | 
| 598 | 
            +
                    help='List all dependencies from deployed agents'
         | 
| 599 | 
            +
                )
         | 
| 600 | 
            +
                deps_list_parser.add_argument(
         | 
| 601 | 
            +
                    '--format',
         | 
| 602 | 
            +
                    choices=['text', 'pip', 'json'],
         | 
| 603 | 
            +
                    default='text',
         | 
| 604 | 
            +
                    help='Output format for dependency list'
         | 
| 605 | 
            +
                )
         | 
| 606 | 
            +
                
         | 
| 607 | 
            +
                # Config command with subcommands
         | 
| 608 | 
            +
                config_parser = subparsers.add_parser(
         | 
| 609 | 
            +
                    CLICommands.CONFIG.value,
         | 
| 610 | 
            +
                    help="Validate and manage configuration"
         | 
| 611 | 
            +
                )
         | 
| 612 | 
            +
                add_common_arguments(config_parser)
         | 
| 613 | 
            +
                
         | 
| 614 | 
            +
                config_subparsers = config_parser.add_subparsers(
         | 
| 615 | 
            +
                    dest="config_command",
         | 
| 616 | 
            +
                    help="Config commands",
         | 
| 617 | 
            +
                    metavar="SUBCOMMAND"
         | 
| 618 | 
            +
                )
         | 
| 619 | 
            +
                
         | 
| 620 | 
            +
                # Validate config
         | 
| 621 | 
            +
                validate_config_parser = config_subparsers.add_parser(
         | 
| 622 | 
            +
                    ConfigCommands.VALIDATE.value,
         | 
| 623 | 
            +
                    help="Validate configuration file"
         | 
| 624 | 
            +
                )
         | 
| 625 | 
            +
                validate_config_parser.add_argument(
         | 
| 626 | 
            +
                    "--config-file",
         | 
| 627 | 
            +
                    type=Path,
         | 
| 628 | 
            +
                    help="Path to configuration file (default: .claude-mpm/configuration.yaml)"
         | 
| 629 | 
            +
                )
         | 
| 630 | 
            +
                validate_config_parser.add_argument(
         | 
| 631 | 
            +
                    "--strict",
         | 
| 632 | 
            +
                    action="store_true",
         | 
| 633 | 
            +
                    help="Treat warnings as errors"
         | 
| 634 | 
            +
                )
         | 
| 635 | 
            +
                
         | 
| 636 | 
            +
                # View config
         | 
| 637 | 
            +
                view_config_parser = config_subparsers.add_parser(
         | 
| 638 | 
            +
                    ConfigCommands.VIEW.value,
         | 
| 639 | 
            +
                    help="View current configuration"
         | 
| 640 | 
            +
                )
         | 
| 641 | 
            +
                view_config_parser.add_argument(
         | 
| 642 | 
            +
                    "--config-file",
         | 
| 643 | 
            +
                    type=Path,
         | 
| 644 | 
            +
                    help="Path to configuration file"
         | 
| 645 | 
            +
                )
         | 
| 646 | 
            +
                view_config_parser.add_argument(
         | 
| 647 | 
            +
                    "--section",
         | 
| 648 | 
            +
                    help="View specific configuration section"
         | 
| 649 | 
            +
                )
         | 
| 650 | 
            +
                view_config_parser.add_argument(
         | 
| 651 | 
            +
                    "--format",
         | 
| 652 | 
            +
                    choices=["table", "json", "yaml"],
         | 
| 653 | 
            +
                    default="table",
         | 
| 654 | 
            +
                    help="Output format (default: table)"
         | 
| 655 | 
            +
                )
         | 
| 656 | 
            +
                
         | 
| 657 | 
            +
                # Config status
         | 
| 658 | 
            +
                status_config_parser = config_subparsers.add_parser(
         | 
| 659 | 
            +
                    ConfigCommands.STATUS.value,
         | 
| 660 | 
            +
                    help="Show configuration status and health"
         | 
| 661 | 
            +
                )
         | 
| 662 | 
            +
                status_config_parser.add_argument(
         | 
| 663 | 
            +
                    "--config-file",
         | 
| 664 | 
            +
                    type=Path,
         | 
| 665 | 
            +
                    help="Path to configuration file"
         | 
| 666 | 
            +
                )
         | 
| 667 | 
            +
                status_config_parser.add_argument(
         | 
| 668 | 
            +
                    "--check-response-logging",
         | 
| 669 | 
            +
                    action="store_true",
         | 
| 670 | 
            +
                    help="Show detailed response logging configuration"
         | 
| 671 | 
            +
                )
         | 
| 672 | 
            +
                status_config_parser.add_argument(
         | 
| 673 | 
            +
                    "--verbose",
         | 
| 674 | 
            +
                    action="store_true",
         | 
| 675 | 
            +
                    help="Show detailed errors and warnings"
         | 
| 676 | 
            +
                )
         | 
| 677 | 
            +
                
         | 
| 507 678 | 
             
                # Monitor command with subcommands
         | 
| 508 679 | 
             
                monitor_parser = subparsers.add_parser(
         | 
| 509 680 | 
             
                    CLICommands.MONITOR.value,
         | 
| @@ -572,6 +743,10 @@ def create_parser(prog_name: str = "claude-mpm", version: str = "0.0.0") -> argp | |
| 572 743 | 
             
                    help="Host to bind to (default: localhost)"
         | 
| 573 744 | 
             
                )
         | 
| 574 745 |  | 
| 746 | 
            +
                # Import and add aggregate command parser
         | 
| 747 | 
            +
                from .commands.aggregate import add_aggregate_parser
         | 
| 748 | 
            +
                add_aggregate_parser(subparsers)
         | 
| 749 | 
            +
                
         | 
| 575 750 | 
             
                return parser
         | 
| 576 751 |  | 
| 577 752 |  | 
    
        claude_mpm/cli/utils.py
    CHANGED
    
    | @@ -61,7 +61,15 @@ def get_agent_versions_display() -> Optional[str]: | |
| 61 61 | 
             
                """
         | 
| 62 62 | 
             
                try:
         | 
| 63 63 | 
             
                    from ..services import AgentDeploymentService
         | 
| 64 | 
            -
                     | 
| 64 | 
            +
                    import os
         | 
| 65 | 
            +
                    from pathlib import Path
         | 
| 66 | 
            +
                    
         | 
| 67 | 
            +
                    # Determine the user's working directory from environment
         | 
| 68 | 
            +
                    user_working_dir = None
         | 
| 69 | 
            +
                    if 'CLAUDE_MPM_USER_PWD' in os.environ:
         | 
| 70 | 
            +
                        user_working_dir = Path(os.environ['CLAUDE_MPM_USER_PWD'])
         | 
| 71 | 
            +
                    
         | 
| 72 | 
            +
                    deployment_service = AgentDeploymentService(working_directory=user_working_dir)
         | 
| 65 73 |  | 
| 66 74 | 
             
                    # Get deployed agents
         | 
| 67 75 | 
             
                    verification = deployment_service.verify_deployment()
         | 
| @@ -0,0 +1,253 @@ | |
| 1 | 
            +
            # CLI Refactoring Guide
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            This guide shows how to refactor the main() function in `/src/claude_mpm/cli.py` to reduce complexity from 16 to under 10.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## Current Issues
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            1. **High Cyclomatic Complexity (16)**
         | 
| 8 | 
            +
               - Multiple nested conditionals
         | 
| 9 | 
            +
               - Duplicate argument definitions
         | 
| 10 | 
            +
               - Mixed concerns in one function
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            2. **Code Duplication**
         | 
| 13 | 
            +
               - Arguments defined twice (global level + run subcommand)
         | 
| 14 | 
            +
               - Similar patterns repeated for each command
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            3. **Poor Maintainability**
         | 
| 17 | 
            +
               - Adding new commands requires multiple changes
         | 
| 18 | 
            +
               - Hard to test individual components
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            ## Refactoring Steps
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            ### Step 1: Update imports in cli.py
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            ```python
         | 
| 25 | 
            +
            # Add to imports
         | 
| 26 | 
            +
            from .cli import ArgumentRegistry, CommandRegistry, register_standard_commands
         | 
| 27 | 
            +
            ```
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            ### Step 2: Replace main() function
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            Replace the entire `main()` function with:
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            ```python
         | 
| 34 | 
            +
            def main(argv: Optional[list] = None):
         | 
| 35 | 
            +
                """Main CLI entry point with reduced complexity."""
         | 
| 36 | 
            +
                # Initialize registries
         | 
| 37 | 
            +
                arg_registry = ArgumentRegistry()
         | 
| 38 | 
            +
                cmd_registry = CommandRegistry(arg_registry)
         | 
| 39 | 
            +
                
         | 
| 40 | 
            +
                # Register standard commands
         | 
| 41 | 
            +
                register_standard_commands(cmd_registry)
         | 
| 42 | 
            +
                
         | 
| 43 | 
            +
                # Create parser
         | 
| 44 | 
            +
                parser = argparse.ArgumentParser(
         | 
| 45 | 
            +
                    prog="claude-mpm",
         | 
| 46 | 
            +
                    description=f"Claude Multi-Agent Project Manager v{__version__}",
         | 
| 47 | 
            +
                    epilog="By default, runs an orchestrated Claude session."
         | 
| 48 | 
            +
                )
         | 
| 49 | 
            +
                
         | 
| 50 | 
            +
                # Store version for ArgumentRegistry
         | 
| 51 | 
            +
                parser._version = f"claude-mpm {__version__}"
         | 
| 52 | 
            +
                
         | 
| 53 | 
            +
                # Apply global arguments
         | 
| 54 | 
            +
                arg_registry.apply_arguments(parser, groups=['global'])
         | 
| 55 | 
            +
                
         | 
| 56 | 
            +
                # Apply run arguments at top level (for default behavior)
         | 
| 57 | 
            +
                arg_registry.apply_arguments(parser, groups=['run'], exclude=['no_hooks'])
         | 
| 58 | 
            +
                
         | 
| 59 | 
            +
                # Set up subcommands
         | 
| 60 | 
            +
                cmd_registry.setup_subcommands(parser)
         | 
| 61 | 
            +
                
         | 
| 62 | 
            +
                # Parse arguments
         | 
| 63 | 
            +
                args = parser.parse_args(argv)
         | 
| 64 | 
            +
                
         | 
| 65 | 
            +
                # Set up logging
         | 
| 66 | 
            +
                _setup_logging(args)
         | 
| 67 | 
            +
                
         | 
| 68 | 
            +
                # Initialize hook service
         | 
| 69 | 
            +
                hook_manager = _initialize_hook_service(args)
         | 
| 70 | 
            +
                
         | 
| 71 | 
            +
                try:
         | 
| 72 | 
            +
                    # Execute command
         | 
| 73 | 
            +
                    result = cmd_registry.execute_command(args, hook_manager=hook_manager)
         | 
| 74 | 
            +
                    if result is None and not args.command:
         | 
| 75 | 
            +
                        parser.print_help()
         | 
| 76 | 
            +
                        return 1
         | 
| 77 | 
            +
                    return result or 0
         | 
| 78 | 
            +
                    
         | 
| 79 | 
            +
                except KeyboardInterrupt:
         | 
| 80 | 
            +
                    get_logger("cli").info("Session interrupted by user")
         | 
| 81 | 
            +
                    return 0
         | 
| 82 | 
            +
                except Exception as e:
         | 
| 83 | 
            +
                    logger = get_logger("cli")
         | 
| 84 | 
            +
                    logger.error(f"Error: {e}")
         | 
| 85 | 
            +
                    if args.debug:
         | 
| 86 | 
            +
                        import traceback
         | 
| 87 | 
            +
                        traceback.print_exc()
         | 
| 88 | 
            +
                    return 1
         | 
| 89 | 
            +
                finally:
         | 
| 90 | 
            +
                    if hook_manager:
         | 
| 91 | 
            +
                        hook_manager.stop_service()
         | 
| 92 | 
            +
            ```
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            ### Step 3: Extract helper functions
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            Add these helper functions after main():
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            ```python
         | 
| 99 | 
            +
            def _setup_logging(args):
         | 
| 100 | 
            +
                """Set up logging based on arguments."""
         | 
| 101 | 
            +
                if args.debug and args.logging == "OFF":
         | 
| 102 | 
            +
                    args.logging = "DEBUG"
         | 
| 103 | 
            +
                
         | 
| 104 | 
            +
                if args.logging != "OFF":
         | 
| 105 | 
            +
                    setup_logging(level=args.logging, log_dir=args.log_dir)
         | 
| 106 | 
            +
                else:
         | 
| 107 | 
            +
                    import logging
         | 
| 108 | 
            +
                    logger = logging.getLogger("cli")
         | 
| 109 | 
            +
                    logger.setLevel(logging.WARNING)
         | 
| 110 | 
            +
             | 
| 111 | 
            +
             | 
| 112 | 
            +
            def _initialize_hook_service(args):
         | 
| 113 | 
            +
                """Initialize hook service if enabled."""
         | 
| 114 | 
            +
                if getattr(args, 'no_hooks', False):
         | 
| 115 | 
            +
                    return None
         | 
| 116 | 
            +
                    
         | 
| 117 | 
            +
                try:
         | 
| 118 | 
            +
                    from .config.hook_config import HookConfig
         | 
| 119 | 
            +
                    
         | 
| 120 | 
            +
                    if not HookConfig.is_hooks_enabled():
         | 
| 121 | 
            +
                        get_logger("cli").info("Hooks disabled via configuration")
         | 
| 122 | 
            +
                        return None
         | 
| 123 | 
            +
                        
         | 
| 124 | 
            +
                    hook_manager = HookServiceManager(log_dir=args.log_dir)
         | 
| 125 | 
            +
                    if hook_manager.start_service():
         | 
| 126 | 
            +
                        logger = get_logger("cli")
         | 
| 127 | 
            +
                        logger.info(f"Hook service started on port {hook_manager.port}")
         | 
| 128 | 
            +
                        print(f"Hook service started on port {hook_manager.port}")
         | 
| 129 | 
            +
                        return hook_manager
         | 
| 130 | 
            +
                    else:
         | 
| 131 | 
            +
                        logger = get_logger("cli")
         | 
| 132 | 
            +
                        logger.warning("Failed to start hook service")
         | 
| 133 | 
            +
                        print("Failed to start hook service, continuing without hooks")
         | 
| 134 | 
            +
                        return None
         | 
| 135 | 
            +
                        
         | 
| 136 | 
            +
                except Exception as e:
         | 
| 137 | 
            +
                    get_logger("cli").warning(f"Hook service init failed: {e}")
         | 
| 138 | 
            +
                    return None
         | 
| 139 | 
            +
            ```
         | 
| 140 | 
            +
             | 
| 141 | 
            +
            ### Step 4: Update command handler signatures
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            Ensure all command handlers accept `**kwargs`:
         | 
| 144 | 
            +
             | 
| 145 | 
            +
            ```python
         | 
| 146 | 
            +
            def run_session(args, hook_manager=None, **kwargs):
         | 
| 147 | 
            +
                """Run an orchestrated Claude session."""
         | 
| 148 | 
            +
                # ... existing implementation
         | 
| 149 | 
            +
             | 
| 150 | 
            +
            def list_tickets(args, **kwargs):
         | 
| 151 | 
            +
                """List recent tickets."""
         | 
| 152 | 
            +
                # ... existing implementation
         | 
| 153 | 
            +
             | 
| 154 | 
            +
            def show_info(args, hook_manager=None, **kwargs):
         | 
| 155 | 
            +
                """Show framework and configuration information."""
         | 
| 156 | 
            +
                # ... existing implementation
         | 
| 157 | 
            +
            ```
         | 
| 158 | 
            +
             | 
| 159 | 
            +
            ## Benefits Achieved
         | 
| 160 | 
            +
             | 
| 161 | 
            +
            ### Complexity Reduction
         | 
| 162 | 
            +
            - **Before**: Cyclomatic complexity of 16
         | 
| 163 | 
            +
            - **After**: Cyclomatic complexity of ~8
         | 
| 164 | 
            +
             | 
| 165 | 
            +
            ### Code Organization
         | 
| 166 | 
            +
            - Centralized argument definitions
         | 
| 167 | 
            +
            - No duplicate argument definitions
         | 
| 168 | 
            +
            - Clear separation of concerns
         | 
| 169 | 
            +
            - Easier to add new commands
         | 
| 170 | 
            +
             | 
| 171 | 
            +
            ### Maintainability
         | 
| 172 | 
            +
            - New commands can be added with a single `register()` call
         | 
| 173 | 
            +
            - Arguments are defined once and reused
         | 
| 174 | 
            +
            - Helper functions are testable in isolation
         | 
| 175 | 
            +
            - Registry pattern allows for extension
         | 
| 176 | 
            +
             | 
| 177 | 
            +
            ## Adding New Commands
         | 
| 178 | 
            +
             | 
| 179 | 
            +
            With the registry system, adding a new command is simple:
         | 
| 180 | 
            +
             | 
| 181 | 
            +
            ```python
         | 
| 182 | 
            +
            # In your code or plugin
         | 
| 183 | 
            +
            def my_command(args, **kwargs):
         | 
| 184 | 
            +
                """Implementation of your command."""
         | 
| 185 | 
            +
                print(f"Running my command with args: {args}")
         | 
| 186 | 
            +
                return 0
         | 
| 187 | 
            +
             | 
| 188 | 
            +
            # Register it
         | 
| 189 | 
            +
            cmd_registry.register(
         | 
| 190 | 
            +
                name='mycommand',
         | 
| 191 | 
            +
                help_text='Description of my command',
         | 
| 192 | 
            +
                handler=my_command,
         | 
| 193 | 
            +
                argument_groups=['framework'],  # Reuse existing argument groups
         | 
| 194 | 
            +
                extra_args={
         | 
| 195 | 
            +
                    'custom_arg': {
         | 
| 196 | 
            +
                        'flags': ['--custom'],
         | 
| 197 | 
            +
                        'type': str,
         | 
| 198 | 
            +
                        'help': 'A custom argument for this command'
         | 
| 199 | 
            +
                    }
         | 
| 200 | 
            +
                }
         | 
| 201 | 
            +
            )
         | 
| 202 | 
            +
            ```
         | 
| 203 | 
            +
             | 
| 204 | 
            +
            ## Testing
         | 
| 205 | 
            +
             | 
| 206 | 
            +
            The refactored code is easier to test:
         | 
| 207 | 
            +
             | 
| 208 | 
            +
            ```python
         | 
| 209 | 
            +
            # Test argument registry
         | 
| 210 | 
            +
            def test_argument_registry():
         | 
| 211 | 
            +
                registry = ArgumentRegistry()
         | 
| 212 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 213 | 
            +
                registry.apply_arguments(parser, groups=['logging'])
         | 
| 214 | 
            +
                
         | 
| 215 | 
            +
                # Verify logging arguments were added
         | 
| 216 | 
            +
                args = parser.parse_args(['--logging', 'DEBUG'])
         | 
| 217 | 
            +
                assert args.logging == 'DEBUG'
         | 
| 218 | 
            +
             | 
| 219 | 
            +
            # Test command registry
         | 
| 220 | 
            +
            def test_command_registry():
         | 
| 221 | 
            +
                arg_reg = ArgumentRegistry()
         | 
| 222 | 
            +
                cmd_reg = CommandRegistry(arg_reg)
         | 
| 223 | 
            +
                
         | 
| 224 | 
            +
                called = False
         | 
| 225 | 
            +
                def test_handler(args, **kwargs):
         | 
| 226 | 
            +
                    nonlocal called
         | 
| 227 | 
            +
                    called = True
         | 
| 228 | 
            +
                    return 0
         | 
| 229 | 
            +
                
         | 
| 230 | 
            +
                cmd_reg.register('test', 'Test command', test_handler)
         | 
| 231 | 
            +
                
         | 
| 232 | 
            +
                parser = argparse.ArgumentParser()
         | 
| 233 | 
            +
                cmd_reg.setup_subcommands(parser)
         | 
| 234 | 
            +
                
         | 
| 235 | 
            +
                args = parser.parse_args(['test'])
         | 
| 236 | 
            +
                result = cmd_reg.execute_command(args)
         | 
| 237 | 
            +
                
         | 
| 238 | 
            +
                assert called
         | 
| 239 | 
            +
                assert result == 0
         | 
| 240 | 
            +
            ```
         | 
| 241 | 
            +
             | 
| 242 | 
            +
            ## Migration Checklist
         | 
| 243 | 
            +
             | 
| 244 | 
            +
            - [ ] Create `/src/claude_mpm/cli/` directory
         | 
| 245 | 
            +
            - [ ] Create `args.py` with ArgumentRegistry
         | 
| 246 | 
            +
            - [ ] Create `commands.py` with CommandRegistry
         | 
| 247 | 
            +
            - [ ] Create `__init__.py` to export classes
         | 
| 248 | 
            +
            - [ ] Update imports in `cli.py`
         | 
| 249 | 
            +
            - [ ] Replace main() function
         | 
| 250 | 
            +
            - [ ] Add helper functions
         | 
| 251 | 
            +
            - [ ] Update command handler signatures
         | 
| 252 | 
            +
            - [ ] Test the refactored CLI
         | 
| 253 | 
            +
            - [ ] Verify complexity is reduced to ≤10
         | 
| @@ -0,0 +1,145 @@ | |
| 1 | 
            +
            # Async Logging Configuration
         | 
| 2 | 
            +
            # Optimized logging configuration for high-performance scenarios
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            logging:
         | 
| 5 | 
            +
              # Enable async logging for improved performance
         | 
| 6 | 
            +
              async:
         | 
| 7 | 
            +
                enabled: true
         | 
| 8 | 
            +
                
         | 
| 9 | 
            +
                # Log format options: json, syslog, journald
         | 
| 10 | 
            +
                format: json
         | 
| 11 | 
            +
                
         | 
| 12 | 
            +
                # Maximum queue size for async writes
         | 
| 13 | 
            +
                max_queue_size: 10000
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                # Enable compression for JSON logs (reduces disk usage)
         | 
| 16 | 
            +
                compression: false
         | 
| 17 | 
            +
                
         | 
| 18 | 
            +
                # Worker threads for async processing
         | 
| 19 | 
            +
                worker_threads: 4
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                # Flush timeout in seconds
         | 
| 22 | 
            +
                flush_timeout: 5.0
         | 
| 23 | 
            +
              
         | 
| 24 | 
            +
              # Session logger settings
         | 
| 25 | 
            +
              session:
         | 
| 26 | 
            +
                # Base directory for logs
         | 
| 27 | 
            +
                base_dir: ".claude-mpm/responses"
         | 
| 28 | 
            +
                
         | 
| 29 | 
            +
                # Use timestamp-based filenames (eliminates race conditions)
         | 
| 30 | 
            +
                timestamp_filenames: true
         | 
| 31 | 
            +
                
         | 
| 32 | 
            +
                # Include microseconds in timestamps for uniqueness
         | 
| 33 | 
            +
                microsecond_precision: true
         | 
| 34 | 
            +
                
         | 
| 35 | 
            +
                # Filename format with available variables:
         | 
| 36 | 
            +
                # {agent} - Agent name
         | 
| 37 | 
            +
                # {timestamp} - ISO timestamp
         | 
| 38 | 
            +
                # {microseconds} - Microsecond component
         | 
| 39 | 
            +
                # {session} - Session ID
         | 
| 40 | 
            +
                filename_format: "{agent}_{timestamp}_{microseconds}.json"
         | 
| 41 | 
            +
              
         | 
| 42 | 
            +
              # OS-native logging options (for extreme performance)
         | 
| 43 | 
            +
              syslog:
         | 
| 44 | 
            +
                # Syslog address (auto-detected by default)
         | 
| 45 | 
            +
                # address: /var/run/syslog  # macOS
         | 
| 46 | 
            +
                # address: /dev/log         # Linux
         | 
| 47 | 
            +
                # address: ["localhost", 514]  # Network
         | 
| 48 | 
            +
                
         | 
| 49 | 
            +
                # Syslog facility
         | 
| 50 | 
            +
                facility: local0
         | 
| 51 | 
            +
                
         | 
| 52 | 
            +
                # Include structured data
         | 
| 53 | 
            +
                structured_data: true
         | 
| 54 | 
            +
              
         | 
| 55 | 
            +
              # Performance tuning
         | 
| 56 | 
            +
              performance:
         | 
| 57 | 
            +
                # Fire-and-forget mode (don't wait for write confirmation)
         | 
| 58 | 
            +
                fire_and_forget: true
         | 
| 59 | 
            +
                
         | 
| 60 | 
            +
                # Drop logs if queue is full (prevents blocking)
         | 
| 61 | 
            +
                drop_on_full: true
         | 
| 62 | 
            +
                
         | 
| 63 | 
            +
                # Batch writes for efficiency
         | 
| 64 | 
            +
                batch_writes: true
         | 
| 65 | 
            +
                batch_size: 10
         | 
| 66 | 
            +
                batch_timeout_ms: 100
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            # Hook system optimization
         | 
| 69 | 
            +
            hooks:
         | 
| 70 | 
            +
              # Enable hook system
         | 
| 71 | 
            +
              enabled: true
         | 
| 72 | 
            +
              
         | 
| 73 | 
            +
              # Optimization settings
         | 
| 74 | 
            +
              optimization:
         | 
| 75 | 
            +
                # Cache hook configurations at startup
         | 
| 76 | 
            +
                cache_configs: true
         | 
| 77 | 
            +
                
         | 
| 78 | 
            +
                # Lazy load hook implementations
         | 
| 79 | 
            +
                lazy_loading: true
         | 
| 80 | 
            +
                
         | 
| 81 | 
            +
                # Use singleton pattern for hook service
         | 
| 82 | 
            +
                singleton: true
         | 
| 83 | 
            +
                
         | 
| 84 | 
            +
                # Enable async hook execution
         | 
| 85 | 
            +
                async_execution: true
         | 
| 86 | 
            +
                
         | 
| 87 | 
            +
                # Maximum workers for parallel hook execution
         | 
| 88 | 
            +
                max_workers: 4
         | 
| 89 | 
            +
              
         | 
| 90 | 
            +
              # Pre-delegation hooks
         | 
| 91 | 
            +
              pre_delegation:
         | 
| 92 | 
            +
                enabled: true
         | 
| 93 | 
            +
                
         | 
| 94 | 
            +
                # Parallel execution for independent hooks
         | 
| 95 | 
            +
                parallel_safe_hooks:
         | 
| 96 | 
            +
                  - memory_context_hook
         | 
| 97 | 
            +
                  - validation_hook
         | 
| 98 | 
            +
                  - auth_hook
         | 
| 99 | 
            +
              
         | 
| 100 | 
            +
              # Post-delegation hooks
         | 
| 101 | 
            +
              post_delegation:
         | 
| 102 | 
            +
                enabled: true
         | 
| 103 | 
            +
                
         | 
| 104 | 
            +
                # Parallel execution for independent hooks
         | 
| 105 | 
            +
                parallel_safe_hooks:
         | 
| 106 | 
            +
                  - logging_hook
         | 
| 107 | 
            +
                  - metrics_hook
         | 
| 108 | 
            +
                  - cleanup_hook
         | 
| 109 | 
            +
              
         | 
| 110 | 
            +
              # Registered hooks with lazy loading
         | 
| 111 | 
            +
              registered:
         | 
| 112 | 
            +
                # NOTE: The builtin hooks have been deprecated and removed
         | 
| 113 | 
            +
                # These references are kept commented for historical reference
         | 
| 114 | 
            +
                # memory_context_hook:
         | 
| 115 | 
            +
                #   module: claude_mpm.hooks.builtin.memory_hooks
         | 
| 116 | 
            +
                #   class: MemoryContextHook
         | 
| 117 | 
            +
                #   priority: 10
         | 
| 118 | 
            +
                #   enabled: true
         | 
| 119 | 
            +
                #   params:
         | 
| 120 | 
            +
                #     cache_size: 1000
         | 
| 121 | 
            +
                # 
         | 
| 122 | 
            +
                # response_logger_hook:
         | 
| 123 | 
            +
                #   module: claude_mpm.hooks.builtin.logging_hooks
         | 
| 124 | 
            +
                #   class: ResponseLoggerHook
         | 
| 125 | 
            +
                #   priority: 90
         | 
| 126 | 
            +
                #   enabled: true
         | 
| 127 | 
            +
                #   params:
         | 
| 128 | 
            +
                #     async: true
         | 
| 129 | 
            +
                # 
         | 
| 130 | 
            +
                # metrics_hook:
         | 
| 131 | 
            +
                #   module: claude_mpm.hooks.builtin.metrics_hooks
         | 
| 132 | 
            +
                #   class: MetricsCollectorHook
         | 
| 133 | 
            +
                #   priority: 95
         | 
| 134 | 
            +
                #   enabled: true
         | 
| 135 | 
            +
                #   params:
         | 
| 136 | 
            +
                #     buffer_size: 100
         | 
| 137 | 
            +
             | 
| 138 | 
            +
            # Environment variable overrides
         | 
| 139 | 
            +
            # These can override any setting above:
         | 
| 140 | 
            +
            #
         | 
| 141 | 
            +
            # CLAUDE_USE_ASYNC_LOG=true        # Enable async logging
         | 
| 142 | 
            +
            # CLAUDE_LOG_FORMAT=syslog         # Use syslog format
         | 
| 143 | 
            +
            # CLAUDE_LOG_SYNC=true             # Disable async (for debugging)
         | 
| 144 | 
            +
            # CLAUDE_HOOKS_CACHE=true          # Enable hook caching
         | 
| 145 | 
            +
            # CLAUDE_HOOKS_ASYNC=true          # Enable async hooks
         | 
    
        claude_mpm/constants.py
    CHANGED
    
    | @@ -28,6 +28,8 @@ class CLICommands(str, Enum): | |
| 28 28 | 
             
                AGENTS = "agents"
         | 
| 29 29 | 
             
                MEMORY = "memory"
         | 
| 30 30 | 
             
                MONITOR = "monitor"
         | 
| 31 | 
            +
                CONFIG = "config"
         | 
| 32 | 
            +
                AGGREGATE = "aggregate"
         | 
| 31 33 |  | 
| 32 34 | 
             
                def with_prefix(self, prefix: CLIPrefix = CLIPrefix.MPM) -> str:
         | 
| 33 35 | 
             
                    """Get command with prefix."""
         | 
| @@ -80,6 +82,23 @@ class MonitorCommands(str, Enum): | |
| 80 82 | 
             
                PORT = "port"
         | 
| 81 83 |  | 
| 82 84 |  | 
| 85 | 
            +
            class ConfigCommands(str, Enum):
         | 
| 86 | 
            +
                """Config subcommand constants."""
         | 
| 87 | 
            +
                VALIDATE = "validate"
         | 
| 88 | 
            +
                VIEW = "view"
         | 
| 89 | 
            +
                STATUS = "status"
         | 
| 90 | 
            +
             | 
| 91 | 
            +
             | 
| 92 | 
            +
            class AggregateCommands(str, Enum):
         | 
| 93 | 
            +
                """Event aggregator subcommand constants."""
         | 
| 94 | 
            +
                START = "start"
         | 
| 95 | 
            +
                STOP = "stop"
         | 
| 96 | 
            +
                STATUS = "status"
         | 
| 97 | 
            +
                SESSIONS = "sessions"
         | 
| 98 | 
            +
                VIEW = "view"
         | 
| 99 | 
            +
                EXPORT = "export"
         | 
| 100 | 
            +
             | 
| 101 | 
            +
             | 
| 83 102 | 
             
            class CLIFlags(str, Enum):
         | 
| 84 103 | 
             
                """CLI flag constants (without prefix)."""
         | 
| 85 104 | 
             
                # Logging flags
         |