claude-mpm 4.7.4__py3-none-any.whl → 4.18.2__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/agents/BASE_AGENT_TEMPLATE.md +118 -0
- claude_mpm/agents/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +106 -1
- claude_mpm/agents/OUTPUT_STYLE.md +329 -11
- claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
- claude_mpm/agents/agent_loader.py +17 -5
- claude_mpm/agents/frontmatter_validator.py +284 -253
- claude_mpm/agents/templates/README.md +465 -0
- claude_mpm/agents/templates/agent-manager.json +4 -1
- claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
- claude_mpm/agents/templates/api_qa.json +11 -2
- claude_mpm/agents/templates/circuit_breakers.md +638 -0
- claude_mpm/agents/templates/clerk-ops.json +12 -2
- claude_mpm/agents/templates/code_analyzer.json +8 -2
- claude_mpm/agents/templates/content-agent.json +358 -0
- claude_mpm/agents/templates/dart_engineer.json +15 -2
- claude_mpm/agents/templates/data_engineer.json +15 -2
- claude_mpm/agents/templates/documentation.json +10 -2
- claude_mpm/agents/templates/engineer.json +21 -1
- claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
- claude_mpm/agents/templates/git_file_tracking.md +584 -0
- claude_mpm/agents/templates/golang_engineer.json +270 -0
- claude_mpm/agents/templates/imagemagick.json +4 -1
- claude_mpm/agents/templates/java_engineer.json +346 -0
- claude_mpm/agents/templates/local_ops_agent.json +1227 -6
- claude_mpm/agents/templates/memory_manager.json +4 -1
- claude_mpm/agents/templates/nextjs_engineer.json +141 -133
- claude_mpm/agents/templates/ops.json +12 -2
- claude_mpm/agents/templates/php-engineer.json +270 -174
- claude_mpm/agents/templates/pm_examples.md +474 -0
- claude_mpm/agents/templates/pm_red_flags.md +240 -0
- claude_mpm/agents/templates/product_owner.json +338 -0
- claude_mpm/agents/templates/project_organizer.json +14 -4
- claude_mpm/agents/templates/prompt-engineer.json +13 -2
- claude_mpm/agents/templates/python_engineer.json +174 -81
- claude_mpm/agents/templates/qa.json +11 -2
- claude_mpm/agents/templates/react_engineer.json +16 -3
- claude_mpm/agents/templates/refactoring_engineer.json +12 -2
- claude_mpm/agents/templates/research.json +34 -21
- claude_mpm/agents/templates/response_format.md +583 -0
- claude_mpm/agents/templates/ruby-engineer.json +129 -192
- claude_mpm/agents/templates/rust_engineer.json +270 -0
- claude_mpm/agents/templates/security.json +10 -2
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/agents/templates/ticketing.json +10 -2
- claude_mpm/agents/templates/typescript_engineer.json +116 -125
- claude_mpm/agents/templates/validation_templates.md +312 -0
- claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
- claude_mpm/agents/templates/version_control.json +12 -2
- claude_mpm/agents/templates/web_qa.json +11 -2
- claude_mpm/agents/templates/web_ui.json +15 -2
- claude_mpm/cli/__init__.py +34 -614
- claude_mpm/cli/commands/agent_manager.py +25 -12
- claude_mpm/cli/commands/agent_state_manager.py +186 -0
- claude_mpm/cli/commands/agents.py +235 -148
- claude_mpm/cli/commands/agents_detect.py +380 -0
- claude_mpm/cli/commands/agents_recommend.py +309 -0
- claude_mpm/cli/commands/aggregate.py +7 -3
- claude_mpm/cli/commands/analyze.py +9 -4
- claude_mpm/cli/commands/analyze_code.py +7 -2
- claude_mpm/cli/commands/auto_configure.py +570 -0
- claude_mpm/cli/commands/config.py +47 -13
- claude_mpm/cli/commands/configure.py +419 -1571
- claude_mpm/cli/commands/configure_agent_display.py +261 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +167 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/local_deploy.py +537 -0
- claude_mpm/cli/commands/memory.py +54 -20
- claude_mpm/cli/commands/mpm_init.py +585 -196
- claude_mpm/cli/commands/mpm_init_handler.py +37 -3
- claude_mpm/cli/commands/search.py +170 -4
- claude_mpm/cli/commands/upgrade.py +152 -0
- claude_mpm/cli/executor.py +202 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +3 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parsers/__init__.py +7 -1
- claude_mpm/cli/parsers/agents_parser.py +9 -0
- claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
- claude_mpm/cli/parsers/base_parser.py +110 -3
- claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
- claude_mpm/cli/shared/output_formatters.py +28 -19
- claude_mpm/cli/startup.py +481 -0
- claude_mpm/cli/utils.py +52 -1
- claude_mpm/commands/mpm-agents-detect.md +168 -0
- claude_mpm/commands/mpm-agents-recommend.md +214 -0
- claude_mpm/commands/mpm-agents.md +75 -1
- claude_mpm/commands/mpm-auto-configure.md +217 -0
- claude_mpm/commands/mpm-help.md +163 -0
- claude_mpm/commands/mpm-init.md +148 -3
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +1 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/config/model_config.py +428 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/base_service.py +13 -12
- claude_mpm/core/enums.py +452 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/instruction_reinforcement_hook.py +2 -1
- claude_mpm/core/interactive_session.py +9 -3
- claude_mpm/core/log_manager.py +2 -0
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/oneshot_session.py +8 -4
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/core/output_style_manager.py +12 -192
- claude_mpm/core/service_registry.py +5 -1
- claude_mpm/core/types.py +2 -9
- claude_mpm/core/typing_utils.py +7 -6
- claude_mpm/dashboard/static/js/dashboard.js +0 -14
- claude_mpm/dashboard/templates/index.html +3 -41
- claude_mpm/hooks/__init__.py +20 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
- claude_mpm/hooks/failure_learning/__init__.py +60 -0
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
- claude_mpm/hooks/instruction_reinforcement.py +7 -2
- claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
- claude_mpm/hooks/kuzu_memory_hook.py +37 -12
- claude_mpm/hooks/kuzu_response_hook.py +183 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/__init__.py +18 -5
- claude_mpm/services/agents/auto_config_manager.py +796 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
- claude_mpm/services/agents/observers.py +547 -0
- claude_mpm/services/agents/recommender.py +568 -0
- claude_mpm/services/agents/registry/modification_tracker.py +5 -2
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/__init__.py +33 -1
- claude_mpm/services/core/interfaces/__init__.py +90 -3
- claude_mpm/services/core/interfaces/agent.py +184 -0
- claude_mpm/services/core/interfaces/health.py +172 -0
- claude_mpm/services/core/interfaces/model.py +281 -0
- claude_mpm/services/core/interfaces/process.py +372 -0
- claude_mpm/services/core/interfaces/project.py +121 -0
- claude_mpm/services/core/interfaces/restart.py +307 -0
- claude_mpm/services/core/interfaces/stability.py +260 -0
- claude_mpm/services/core/memory_manager.py +11 -24
- claude_mpm/services/core/models/__init__.py +79 -0
- claude_mpm/services/core/models/agent_config.py +381 -0
- claude_mpm/services/core/models/health.py +162 -0
- claude_mpm/services/core/models/process.py +235 -0
- claude_mpm/services/core/models/restart.py +302 -0
- claude_mpm/services/core/models/stability.py +264 -0
- claude_mpm/services/core/models/toolchain.py +306 -0
- claude_mpm/services/core/path_resolver.py +23 -7
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
- claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
- claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
- claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
- claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
- claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
- claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
- claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
- claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
- claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
- claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
- claude_mpm/services/diagnostics/models.py +19 -24
- claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
- claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
- claude_mpm/services/infrastructure/monitoring/base.py +5 -13
- claude_mpm/services/infrastructure/monitoring/network.py +7 -6
- claude_mpm/services/infrastructure/monitoring/process.py +13 -12
- claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/local_ops/__init__.py +163 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
- claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
- claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
- claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
- claude_mpm/services/local_ops/health_manager.py +430 -0
- claude_mpm/services/local_ops/log_monitor.py +396 -0
- claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
- claude_mpm/services/local_ops/process_manager.py +595 -0
- claude_mpm/services/local_ops/resource_monitor.py +331 -0
- claude_mpm/services/local_ops/restart_manager.py +401 -0
- claude_mpm/services/local_ops/restart_policy.py +387 -0
- claude_mpm/services/local_ops/state_manager.py +372 -0
- claude_mpm/services/local_ops/unified_manager.py +600 -0
- claude_mpm/services/mcp_config_manager.py +9 -4
- claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
- claude_mpm/services/mcp_gateway/core/base.py +18 -31
- claude_mpm/services/mcp_gateway/main.py +30 -0
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
- claude_mpm/services/mcp_service_verifier.py +1 -1
- claude_mpm/services/memory/failure_tracker.py +563 -0
- claude_mpm/services/memory_hook_service.py +165 -4
- claude_mpm/services/model/__init__.py +147 -0
- claude_mpm/services/model/base_provider.py +365 -0
- claude_mpm/services/model/claude_provider.py +412 -0
- claude_mpm/services/model/model_router.py +453 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/daemon_manager.py +3 -2
- claude_mpm/services/monitor/handlers/dashboard.py +2 -1
- claude_mpm/services/monitor/handlers/hooks.py +2 -1
- claude_mpm/services/monitor/management/lifecycle.py +3 -2
- claude_mpm/services/monitor/server.py +2 -1
- claude_mpm/services/project/__init__.py +23 -0
- claude_mpm/services/project/detection_strategies.py +719 -0
- claude_mpm/services/project/toolchain_analyzer.py +581 -0
- claude_mpm/services/self_upgrade_service.py +342 -0
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/session_manager.py +205 -1
- claude_mpm/services/shared/async_service_base.py +16 -27
- claude_mpm/services/shared/lifecycle_service_base.py +1 -14
- claude_mpm/services/socketio/handlers/__init__.py +5 -2
- claude_mpm/services/socketio/handlers/hook.py +13 -2
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/server/main.py +10 -8
- claude_mpm/services/subprocess_launcher_service.py +14 -5
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
- claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
- claude_mpm/services/unified/deployment_strategies/local.py +6 -5
- claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
- claude_mpm/services/unified/interfaces.py +3 -1
- claude_mpm/services/unified/unified_analyzer.py +14 -10
- claude_mpm/services/unified/unified_config.py +2 -1
- claude_mpm/services/unified/unified_deployment.py +9 -4
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +21 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +286 -0
- claude_mpm/skills/skill_manager.py +310 -0
- claude_mpm/storage/state_storage.py +15 -15
- claude_mpm/tools/code_tree_analyzer.py +177 -141
- claude_mpm/tools/code_tree_events.py +4 -2
- claude_mpm/utils/agent_dependency_loader.py +40 -20
- claude_mpm/utils/display_helper.py +260 -0
- claude_mpm/utils/git_analyzer.py +407 -0
- claude_mpm/utils/robust_installer.py +73 -19
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
- claude_mpm/dashboard/static/css/code-tree.css +0 -1639
- claude_mpm/dashboard/static/index-hub-backup.html +0 -713
- claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
- claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
- claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
- claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
- claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
- claude_mpm/services/project/analyzer_refactored.py +0 -450
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""Agent display and table rendering for configure command.
|
|
2
|
+
|
|
3
|
+
WHY: Separate agent display logic from main configure command to improve
|
|
4
|
+
modularity and reduce complexity. Agent display includes table rendering,
|
|
5
|
+
status indicators, and detailed agent information views.
|
|
6
|
+
|
|
7
|
+
DESIGN DECISIONS:
|
|
8
|
+
- Use Rich library for modern table formatting
|
|
9
|
+
- Support pending state visualization (enable/disable arrows)
|
|
10
|
+
- Show truncated descriptions in tables, full details in views
|
|
11
|
+
- Display template metadata when available
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
from typing import List
|
|
16
|
+
|
|
17
|
+
from rich.box import ROUNDED
|
|
18
|
+
from rich.console import Console
|
|
19
|
+
from rich.panel import Panel
|
|
20
|
+
from rich.prompt import Prompt
|
|
21
|
+
from rich.table import Table
|
|
22
|
+
from rich.text import Text
|
|
23
|
+
|
|
24
|
+
from .configure_models import AgentConfig
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AgentDisplay:
|
|
28
|
+
"""Handle agent display and table rendering.
|
|
29
|
+
|
|
30
|
+
This class manages the visual presentation of agents in various formats:
|
|
31
|
+
- Summary tables with status indicators
|
|
32
|
+
- Pending state visualization with arrows
|
|
33
|
+
- Detailed agent information panels
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
console: Console,
|
|
39
|
+
agent_manager, # SimpleAgentManager instance
|
|
40
|
+
get_template_path_fn, # Function to get template path for an agent
|
|
41
|
+
display_header_fn, # Function to display configure header
|
|
42
|
+
):
|
|
43
|
+
"""Initialize agent display handler.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
console: Rich console for output
|
|
47
|
+
agent_manager: SimpleAgentManager instance for state queries
|
|
48
|
+
get_template_path_fn: Function(agent_name) -> Path to get template path
|
|
49
|
+
display_header_fn: Function() -> None to display configure header
|
|
50
|
+
"""
|
|
51
|
+
self.console = console
|
|
52
|
+
self.agent_manager = agent_manager
|
|
53
|
+
self._get_agent_template_path = get_template_path_fn
|
|
54
|
+
self._display_header = display_header_fn
|
|
55
|
+
|
|
56
|
+
def display_agents_table(self, agents: List[AgentConfig]) -> None:
|
|
57
|
+
"""Display a table of available agents with status and metadata.
|
|
58
|
+
|
|
59
|
+
Shows:
|
|
60
|
+
- Agent ID (for selection)
|
|
61
|
+
- Name and description
|
|
62
|
+
- Enable/disable status
|
|
63
|
+
- Model or tools information
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
agents: List of agent configurations to display
|
|
67
|
+
"""
|
|
68
|
+
table = Table(
|
|
69
|
+
title=f"Available Agents ({len(agents)} total)",
|
|
70
|
+
box=ROUNDED,
|
|
71
|
+
show_lines=True,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
table.add_column("ID", style="dim", width=3)
|
|
75
|
+
table.add_column("Name", style="bold blue", width=22)
|
|
76
|
+
table.add_column("Status", width=12)
|
|
77
|
+
table.add_column("Description", style="bold", width=45)
|
|
78
|
+
table.add_column("Model/Tools", style="dim", width=20)
|
|
79
|
+
|
|
80
|
+
for idx, agent in enumerate(agents, 1):
|
|
81
|
+
# Check if agent is enabled
|
|
82
|
+
is_enabled = self.agent_manager.is_agent_enabled(agent.name)
|
|
83
|
+
status = (
|
|
84
|
+
"[green]✓ Enabled[/green]" if is_enabled else "[red]✗ Disabled[/red]"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Format tools/dependencies - show first 2 tools
|
|
88
|
+
tools_display = ""
|
|
89
|
+
if agent.dependencies:
|
|
90
|
+
if len(agent.dependencies) > 2:
|
|
91
|
+
tools_display = f"{', '.join(agent.dependencies[:2])}..."
|
|
92
|
+
else:
|
|
93
|
+
tools_display = ", ".join(agent.dependencies)
|
|
94
|
+
else:
|
|
95
|
+
# Try to get model from template
|
|
96
|
+
try:
|
|
97
|
+
template_path = self._get_agent_template_path(agent.name)
|
|
98
|
+
if template_path.exists():
|
|
99
|
+
with template_path.open() as f:
|
|
100
|
+
template = json.load(f)
|
|
101
|
+
model = template.get("capabilities", {}).get("model", "default")
|
|
102
|
+
tools_display = f"Model: {model}"
|
|
103
|
+
else:
|
|
104
|
+
tools_display = "Default"
|
|
105
|
+
except Exception:
|
|
106
|
+
tools_display = "Default"
|
|
107
|
+
|
|
108
|
+
# Truncate description for table display with bright styling
|
|
109
|
+
if len(agent.description) > 42:
|
|
110
|
+
desc_display = f"[cyan]{agent.description[:42]}[/cyan][dim]...[/dim]"
|
|
111
|
+
else:
|
|
112
|
+
desc_display = f"[cyan]{agent.description}[/cyan]"
|
|
113
|
+
|
|
114
|
+
table.add_row(str(idx), agent.name, status, desc_display, tools_display)
|
|
115
|
+
|
|
116
|
+
self.console.print(table)
|
|
117
|
+
|
|
118
|
+
def display_agents_with_pending_states(self, agents: List[AgentConfig]) -> None:
|
|
119
|
+
"""Display agents table with pending state indicators.
|
|
120
|
+
|
|
121
|
+
Shows arrows (→) for agents with pending state changes:
|
|
122
|
+
- "✗ Disabled → ✓ Enabled" for pending enable
|
|
123
|
+
- "✓ Enabled → ✗ Disabled" for pending disable
|
|
124
|
+
|
|
125
|
+
Useful for batch operations where changes are deferred until save.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
agents: List of agent configurations to display
|
|
129
|
+
"""
|
|
130
|
+
has_pending = self.agent_manager.has_pending_changes()
|
|
131
|
+
pending_count = len(self.agent_manager.deferred_changes) if has_pending else 0
|
|
132
|
+
|
|
133
|
+
title = f"Available Agents ({len(agents)} total)"
|
|
134
|
+
if has_pending:
|
|
135
|
+
title += f" [yellow]({pending_count} change{'s' if pending_count != 1 else ''} pending)[/yellow]"
|
|
136
|
+
|
|
137
|
+
table = Table(title=title, box=ROUNDED, show_lines=True, expand=True)
|
|
138
|
+
table.add_column("ID", justify="right", style="bold blue", width=5)
|
|
139
|
+
table.add_column("Name", style="bold", width=22)
|
|
140
|
+
table.add_column("Status", width=20)
|
|
141
|
+
table.add_column("Description", style="bold", width=45)
|
|
142
|
+
|
|
143
|
+
for idx, agent in enumerate(agents, 1):
|
|
144
|
+
current_state = self.agent_manager.is_agent_enabled(agent.name)
|
|
145
|
+
pending_state = self.agent_manager.get_pending_state(agent.name)
|
|
146
|
+
|
|
147
|
+
# Show pending status with arrow
|
|
148
|
+
if current_state != pending_state:
|
|
149
|
+
if pending_state:
|
|
150
|
+
status = "[yellow]✗ Disabled → ✓ Enabled[/yellow]"
|
|
151
|
+
else:
|
|
152
|
+
status = "[yellow]✓ Enabled → ✗ Disabled[/yellow]"
|
|
153
|
+
else:
|
|
154
|
+
status = (
|
|
155
|
+
"[green]✓ Enabled[/green]"
|
|
156
|
+
if current_state
|
|
157
|
+
else "[dim]✗ Disabled[/dim]"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
desc_display = Text()
|
|
161
|
+
desc_display.append(
|
|
162
|
+
(
|
|
163
|
+
agent.description[:42] + "..."
|
|
164
|
+
if len(agent.description) > 42
|
|
165
|
+
else agent.description
|
|
166
|
+
),
|
|
167
|
+
style="",
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
table.add_row(str(idx), agent.name, status, desc_display)
|
|
171
|
+
|
|
172
|
+
self.console.print(table)
|
|
173
|
+
|
|
174
|
+
def view_agent_details(self, agents: List[AgentConfig]) -> None:
|
|
175
|
+
"""View detailed information about a selected agent.
|
|
176
|
+
|
|
177
|
+
Displays comprehensive agent information in a panel:
|
|
178
|
+
- Name, status, template path
|
|
179
|
+
- Full description (not truncated)
|
|
180
|
+
- Model and version information
|
|
181
|
+
- Tags and tools
|
|
182
|
+
- Whether it's a system or custom template
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
agents: List of available agents for selection
|
|
186
|
+
"""
|
|
187
|
+
agent_id = Prompt.ask("Enter agent ID to view")
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
idx = int(agent_id) - 1
|
|
191
|
+
if 0 <= idx < len(agents):
|
|
192
|
+
agent = agents[idx]
|
|
193
|
+
|
|
194
|
+
self.console.clear()
|
|
195
|
+
self._display_header()
|
|
196
|
+
|
|
197
|
+
# Try to load full template for more details
|
|
198
|
+
template_path = self._get_agent_template_path(agent.name)
|
|
199
|
+
extra_info = ""
|
|
200
|
+
|
|
201
|
+
if template_path.exists():
|
|
202
|
+
try:
|
|
203
|
+
with template_path.open() as f:
|
|
204
|
+
template = json.load(f)
|
|
205
|
+
|
|
206
|
+
# Extract additional information
|
|
207
|
+
metadata = template.get("metadata", {})
|
|
208
|
+
capabilities = template.get("capabilities", {})
|
|
209
|
+
|
|
210
|
+
# Get full description if available
|
|
211
|
+
full_desc = metadata.get("description", agent.description)
|
|
212
|
+
|
|
213
|
+
# Get model and tools
|
|
214
|
+
model = capabilities.get("model", "default")
|
|
215
|
+
tools = capabilities.get("tools", [])
|
|
216
|
+
|
|
217
|
+
# Get tags
|
|
218
|
+
tags = metadata.get("tags", [])
|
|
219
|
+
|
|
220
|
+
# Get version info
|
|
221
|
+
agent_version = template.get("agent_version", "N/A")
|
|
222
|
+
schema_version = template.get("schema_version", "N/A")
|
|
223
|
+
|
|
224
|
+
extra_info = f"""
|
|
225
|
+
[bold]Full Description:[/bold]
|
|
226
|
+
{full_desc}
|
|
227
|
+
|
|
228
|
+
[bold]Model:[/bold] {model}
|
|
229
|
+
[bold]Agent Version:[/bold] {agent_version}
|
|
230
|
+
[bold]Schema Version:[/bold] {schema_version}
|
|
231
|
+
[bold]Tags:[/bold] {', '.join(tags) if tags else 'None'}
|
|
232
|
+
[bold]Tools:[/bold] {', '.join(tools[:5]) if tools else 'None'}{'...' if len(tools) > 5 else ''}
|
|
233
|
+
"""
|
|
234
|
+
except Exception:
|
|
235
|
+
pass
|
|
236
|
+
|
|
237
|
+
# Create detail panel
|
|
238
|
+
detail_text = f"""
|
|
239
|
+
[bold]Name:[/bold] {agent.name}
|
|
240
|
+
[bold]Status:[/bold] {'[green]Enabled[/green]' if self.agent_manager.is_agent_enabled(agent.name) else '[red]Disabled[/red]'}
|
|
241
|
+
[bold]Template Path:[/bold] {template_path}
|
|
242
|
+
[bold]Is System Template:[/bold] {'Yes' if str(template_path).startswith(str(self.agent_manager.templates_dir)) else 'No (Custom)'}
|
|
243
|
+
{extra_info}
|
|
244
|
+
"""
|
|
245
|
+
|
|
246
|
+
panel = Panel(
|
|
247
|
+
detail_text.strip(),
|
|
248
|
+
title=f"[bold]{agent.name} Details[/bold]",
|
|
249
|
+
box=ROUNDED,
|
|
250
|
+
style="blue",
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
self.console.print(panel)
|
|
254
|
+
|
|
255
|
+
else:
|
|
256
|
+
self.console.print("[red]Invalid agent ID.[/red]")
|
|
257
|
+
|
|
258
|
+
except ValueError:
|
|
259
|
+
self.console.print("[red]Invalid input. Please enter a number.[/red]")
|
|
260
|
+
|
|
261
|
+
Prompt.ask("\nPress Enter to continue")
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""Behavior file management for configure command.
|
|
2
|
+
|
|
3
|
+
This module handles operations on behavior configuration files including
|
|
4
|
+
identity and workflow configurations.
|
|
5
|
+
|
|
6
|
+
Extracted from configure.py (Phase 5/9) to reduce God Object complexity.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import shutil
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Optional
|
|
12
|
+
|
|
13
|
+
from rich.box import ROUNDED
|
|
14
|
+
from rich.console import Console
|
|
15
|
+
from rich.prompt import Prompt
|
|
16
|
+
from rich.table import Table
|
|
17
|
+
from rich.text import Text
|
|
18
|
+
|
|
19
|
+
from ...utils.console import console as default_console
|
|
20
|
+
from ..shared import CommandResult
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class BehaviorManager:
|
|
24
|
+
"""Manage behavior configuration files.
|
|
25
|
+
|
|
26
|
+
Handles:
|
|
27
|
+
- Displaying available behavior files
|
|
28
|
+
- Editing identity and workflow configs
|
|
29
|
+
- Importing/exporting behavior files
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
config_dir: Path,
|
|
35
|
+
current_scope: str = "project",
|
|
36
|
+
console: Optional[Console] = None,
|
|
37
|
+
):
|
|
38
|
+
"""Initialize behavior manager.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
config_dir: Path to configuration directory
|
|
42
|
+
current_scope: Current scope (project or user)
|
|
43
|
+
console: Rich console for output (optional)
|
|
44
|
+
"""
|
|
45
|
+
self.config_dir = config_dir
|
|
46
|
+
self.current_scope = current_scope
|
|
47
|
+
self.behaviors_dir = config_dir / "behaviors"
|
|
48
|
+
self.console = console or default_console
|
|
49
|
+
|
|
50
|
+
# Ensure behaviors directory exists
|
|
51
|
+
self.behaviors_dir.mkdir(parents=True, exist_ok=True)
|
|
52
|
+
|
|
53
|
+
def manage_behaviors(self) -> None:
|
|
54
|
+
"""Interactive behavior file management interface.
|
|
55
|
+
|
|
56
|
+
Extracted from ConfigureCommand._manage_behaviors()
|
|
57
|
+
"""
|
|
58
|
+
while True:
|
|
59
|
+
self.console.clear()
|
|
60
|
+
# Note: _display_header() is called from parent
|
|
61
|
+
# We skip it here since it's a parent responsibility
|
|
62
|
+
|
|
63
|
+
self.console.print("[bold]Behavior File Management[/bold]\n")
|
|
64
|
+
|
|
65
|
+
# Display current behavior files
|
|
66
|
+
self.display_behavior_files()
|
|
67
|
+
|
|
68
|
+
# Show behavior menu
|
|
69
|
+
self.console.print("\n[bold]Options:[/bold]")
|
|
70
|
+
|
|
71
|
+
text_1 = Text(" ")
|
|
72
|
+
text_1.append("[1]", style="bold blue")
|
|
73
|
+
text_1.append(" Edit identity configuration")
|
|
74
|
+
self.console.print(text_1)
|
|
75
|
+
|
|
76
|
+
text_2 = Text(" ")
|
|
77
|
+
text_2.append("[2]", style="bold blue")
|
|
78
|
+
text_2.append(" Edit workflow configuration")
|
|
79
|
+
self.console.print(text_2)
|
|
80
|
+
|
|
81
|
+
text_3 = Text(" ")
|
|
82
|
+
text_3.append("[3]", style="bold blue")
|
|
83
|
+
text_3.append(" Import behavior file")
|
|
84
|
+
self.console.print(text_3)
|
|
85
|
+
|
|
86
|
+
text_4 = Text(" ")
|
|
87
|
+
text_4.append("[4]", style="bold blue")
|
|
88
|
+
text_4.append(" Export behavior file")
|
|
89
|
+
self.console.print(text_4)
|
|
90
|
+
|
|
91
|
+
text_b = Text(" ")
|
|
92
|
+
text_b.append("[b]", style="bold blue")
|
|
93
|
+
text_b.append(" Back to main menu")
|
|
94
|
+
self.console.print(text_b)
|
|
95
|
+
|
|
96
|
+
self.console.print()
|
|
97
|
+
|
|
98
|
+
choice = Prompt.ask("[bold blue]Select an option[/bold blue]", default="b")
|
|
99
|
+
|
|
100
|
+
if choice == "b":
|
|
101
|
+
break
|
|
102
|
+
if choice == "1":
|
|
103
|
+
self.edit_identity_config()
|
|
104
|
+
elif choice == "2":
|
|
105
|
+
self.edit_workflow_config()
|
|
106
|
+
elif choice == "3":
|
|
107
|
+
self.import_behavior_file()
|
|
108
|
+
elif choice == "4":
|
|
109
|
+
self.export_behavior_file()
|
|
110
|
+
else:
|
|
111
|
+
self.console.print("[red]Invalid choice.[/red]")
|
|
112
|
+
Prompt.ask("Press Enter to continue")
|
|
113
|
+
|
|
114
|
+
def display_behavior_files(self) -> None:
|
|
115
|
+
"""Display current behavior files.
|
|
116
|
+
|
|
117
|
+
Extracted from ConfigureCommand._display_behavior_files()
|
|
118
|
+
"""
|
|
119
|
+
table = Table(title="Behavior Files", box=ROUNDED)
|
|
120
|
+
table.add_column("File", style="bold blue", width=30)
|
|
121
|
+
table.add_column("Size", style="dim", width=10)
|
|
122
|
+
table.add_column("Modified", style="", width=20)
|
|
123
|
+
|
|
124
|
+
identity_file = self.behaviors_dir / "identity.yaml"
|
|
125
|
+
workflow_file = self.behaviors_dir / "workflow.yaml"
|
|
126
|
+
|
|
127
|
+
for file_path in [identity_file, workflow_file]:
|
|
128
|
+
if file_path.exists():
|
|
129
|
+
stat = file_path.stat()
|
|
130
|
+
size = f"{stat.st_size} bytes"
|
|
131
|
+
modified = f"{stat.st_mtime:.0f}" # Simplified timestamp
|
|
132
|
+
table.add_row(file_path.name, size, modified)
|
|
133
|
+
else:
|
|
134
|
+
table.add_row(file_path.name, "[dim]Not found[/dim]", "-")
|
|
135
|
+
|
|
136
|
+
self.console.print(table)
|
|
137
|
+
|
|
138
|
+
def edit_identity_config(self) -> None:
|
|
139
|
+
"""Edit identity configuration.
|
|
140
|
+
|
|
141
|
+
Extracted from ConfigureCommand._edit_identity_config()
|
|
142
|
+
"""
|
|
143
|
+
self.console.print(
|
|
144
|
+
"[yellow]Identity configuration editor - Coming soon![/yellow]"
|
|
145
|
+
)
|
|
146
|
+
Prompt.ask("Press Enter to continue")
|
|
147
|
+
|
|
148
|
+
def edit_workflow_config(self) -> None:
|
|
149
|
+
"""Edit workflow configuration.
|
|
150
|
+
|
|
151
|
+
Extracted from ConfigureCommand._edit_workflow_config()
|
|
152
|
+
"""
|
|
153
|
+
self.console.print(
|
|
154
|
+
"[yellow]Workflow configuration editor - Coming soon![/yellow]"
|
|
155
|
+
)
|
|
156
|
+
Prompt.ask("Press Enter to continue")
|
|
157
|
+
|
|
158
|
+
def import_behavior_file(self) -> None:
|
|
159
|
+
"""Import a behavior file.
|
|
160
|
+
|
|
161
|
+
Extracted from ConfigureCommand._import_behavior_file()
|
|
162
|
+
"""
|
|
163
|
+
file_path = Prompt.ask("Enter path to behavior file to import")
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
source = Path(file_path)
|
|
167
|
+
if not source.exists():
|
|
168
|
+
self.console.print(f"[red]File not found: {file_path}[/red]")
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
# Copy file
|
|
172
|
+
target = self.behaviors_dir / source.name
|
|
173
|
+
shutil.copy2(source, target)
|
|
174
|
+
|
|
175
|
+
self.console.print(f"[green]Successfully imported {source.name}![/green]")
|
|
176
|
+
|
|
177
|
+
except Exception as e:
|
|
178
|
+
self.console.print(f"[red]Error importing file: {e}[/red]")
|
|
179
|
+
|
|
180
|
+
Prompt.ask("Press Enter to continue")
|
|
181
|
+
|
|
182
|
+
def export_behavior_file(self) -> None:
|
|
183
|
+
"""Export a behavior file.
|
|
184
|
+
|
|
185
|
+
Extracted from ConfigureCommand._export_behavior_file()
|
|
186
|
+
"""
|
|
187
|
+
self.console.print("[yellow]Behavior file export - Coming soon![/yellow]")
|
|
188
|
+
Prompt.ask("Press Enter to continue")
|
|
189
|
+
|
|
190
|
+
def run_behavior_management(self) -> CommandResult:
|
|
191
|
+
"""Run behavior management interface.
|
|
192
|
+
|
|
193
|
+
Extracted from ConfigureCommand._run_behavior_management()
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
CommandResult with status
|
|
197
|
+
"""
|
|
198
|
+
try:
|
|
199
|
+
self.manage_behaviors()
|
|
200
|
+
return CommandResult.success_result("Behavior management completed")
|
|
201
|
+
except KeyboardInterrupt:
|
|
202
|
+
return CommandResult.success_result("Behavior management cancelled")
|
|
203
|
+
except Exception as e:
|
|
204
|
+
return CommandResult.error_result(f"Behavior management failed: {e}")
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""Git hook installation and management for configure command.
|
|
2
|
+
|
|
3
|
+
This module handles installation, verification, and removal of git hooks
|
|
4
|
+
used by Claude MPM for automated workflows.
|
|
5
|
+
|
|
6
|
+
Extracted from configure.py (Phase 7/9) to reduce God Object complexity.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.prompt import Confirm
|
|
11
|
+
|
|
12
|
+
from ...utils.console import console as default_console
|
|
13
|
+
from ..shared import CommandResult
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class HookManager:
|
|
17
|
+
"""Manage git hook installation and verification.
|
|
18
|
+
|
|
19
|
+
Handles:
|
|
20
|
+
- Installing Claude Code integration hooks
|
|
21
|
+
- Verifying hook installation status
|
|
22
|
+
- Uninstalling hooks when requested
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, console: Console = None):
|
|
26
|
+
"""Initialize hook manager.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
console: Rich console for output (optional, defaults to shared console)
|
|
30
|
+
"""
|
|
31
|
+
self.console = console or default_console
|
|
32
|
+
self.logger = None # Will be set from parent if needed
|
|
33
|
+
|
|
34
|
+
def install_hooks(self, force: bool = False) -> CommandResult:
|
|
35
|
+
"""Install Claude MPM hooks for Claude Code integration.
|
|
36
|
+
|
|
37
|
+
Extracted from ConfigureCommand._install_hooks() (CC=11)
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
force: Force reinstallation even if hooks exist
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
CommandResult with installation status
|
|
44
|
+
"""
|
|
45
|
+
try:
|
|
46
|
+
from ...hooks.claude_hooks.installer import HookInstaller
|
|
47
|
+
|
|
48
|
+
installer = HookInstaller()
|
|
49
|
+
|
|
50
|
+
# Check Claude Code version compatibility first
|
|
51
|
+
is_compatible, version_message = installer.is_version_compatible()
|
|
52
|
+
self.console.print("[cyan]Checking Claude Code version...[/cyan]")
|
|
53
|
+
self.console.print(version_message)
|
|
54
|
+
|
|
55
|
+
if not is_compatible:
|
|
56
|
+
self.console.print(
|
|
57
|
+
"\n[yellow]⚠ Hook monitoring is not available for your Claude Code version.[/yellow]"
|
|
58
|
+
)
|
|
59
|
+
self.console.print(
|
|
60
|
+
"The dashboard and other features will work without real-time monitoring."
|
|
61
|
+
)
|
|
62
|
+
self.console.print(
|
|
63
|
+
f"\n[dim]To enable monitoring, upgrade Claude Code to version {installer.MIN_CLAUDE_VERSION} or higher.[/dim]"
|
|
64
|
+
)
|
|
65
|
+
return CommandResult.success_result(
|
|
66
|
+
"Version incompatible with hook monitoring",
|
|
67
|
+
data={"compatible": False, "message": version_message},
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Check current status
|
|
71
|
+
status = installer.get_status()
|
|
72
|
+
if status["installed"] and not force:
|
|
73
|
+
self.console.print("[yellow]Hooks are already installed.[/yellow]")
|
|
74
|
+
self.console.print("Use --force to reinstall.")
|
|
75
|
+
|
|
76
|
+
if not status["valid"]:
|
|
77
|
+
self.console.print("\n[red]However, there are issues:[/red]")
|
|
78
|
+
for issue in status["issues"]:
|
|
79
|
+
self.console.print(f" - {issue}")
|
|
80
|
+
|
|
81
|
+
return CommandResult.success_result(
|
|
82
|
+
"Hooks already installed", data=status
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Install hooks
|
|
86
|
+
self.console.print("[cyan]Installing Claude MPM hooks...[/cyan]")
|
|
87
|
+
success = installer.install_hooks(force=force)
|
|
88
|
+
|
|
89
|
+
if success:
|
|
90
|
+
self.console.print("[green]✓ Hooks installed successfully![/green]")
|
|
91
|
+
self.console.print("\nYou can now use /mpm commands in Claude Code:")
|
|
92
|
+
self.console.print(" /mpm - Show help")
|
|
93
|
+
self.console.print(" /mpm status - Show claude-mpm status")
|
|
94
|
+
|
|
95
|
+
# Verify installation
|
|
96
|
+
is_valid, issues = installer.verify_hooks()
|
|
97
|
+
if not is_valid:
|
|
98
|
+
self.console.print(
|
|
99
|
+
"\n[yellow]Warning: Installation completed but verification found issues:[/yellow]"
|
|
100
|
+
)
|
|
101
|
+
for issue in issues:
|
|
102
|
+
self.console.print(f" - {issue}")
|
|
103
|
+
|
|
104
|
+
return CommandResult.success_result("Hooks installed successfully")
|
|
105
|
+
self.console.print("[red]✗ Hook installation failed[/red]")
|
|
106
|
+
return CommandResult.error_result("Hook installation failed")
|
|
107
|
+
|
|
108
|
+
except ImportError:
|
|
109
|
+
self.console.print("[red]Error: HookInstaller module not found[/red]")
|
|
110
|
+
self.console.print("Please ensure claude-mpm is properly installed.")
|
|
111
|
+
return CommandResult.error_result("HookInstaller module not found")
|
|
112
|
+
except Exception as e:
|
|
113
|
+
if self.logger:
|
|
114
|
+
self.logger.error(f"Hook installation error: {e}", exc_info=True)
|
|
115
|
+
return CommandResult.error_result(f"Hook installation failed: {e}")
|
|
116
|
+
|
|
117
|
+
def verify_hooks(self) -> CommandResult:
|
|
118
|
+
"""Verify that Claude MPM hooks are properly installed.
|
|
119
|
+
|
|
120
|
+
Extracted from ConfigureCommand._verify_hooks() (CC=10)
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
CommandResult with verification status
|
|
124
|
+
"""
|
|
125
|
+
try:
|
|
126
|
+
from ...hooks.claude_hooks.installer import HookInstaller
|
|
127
|
+
|
|
128
|
+
installer = HookInstaller()
|
|
129
|
+
status = installer.get_status()
|
|
130
|
+
|
|
131
|
+
self.console.print("[bold]Hook Installation Status[/bold]\n")
|
|
132
|
+
|
|
133
|
+
# Show Claude Code version and compatibility
|
|
134
|
+
if status.get("claude_version"):
|
|
135
|
+
self.console.print(f"Claude Code Version: {status['claude_version']}")
|
|
136
|
+
if status.get("version_compatible"):
|
|
137
|
+
self.console.print(
|
|
138
|
+
"[green]✓[/green] Version compatible with hook monitoring"
|
|
139
|
+
)
|
|
140
|
+
else:
|
|
141
|
+
self.console.print(
|
|
142
|
+
f"[yellow]⚠[/yellow] {status.get('version_message', 'Version incompatible')}"
|
|
143
|
+
)
|
|
144
|
+
self.console.print()
|
|
145
|
+
else:
|
|
146
|
+
self.console.print(
|
|
147
|
+
"[yellow]Claude Code version could not be detected[/yellow]"
|
|
148
|
+
)
|
|
149
|
+
self.console.print()
|
|
150
|
+
|
|
151
|
+
if status["installed"]:
|
|
152
|
+
self.console.print(
|
|
153
|
+
f"[green]✓[/green] Hooks installed at: {status['hook_script']}"
|
|
154
|
+
)
|
|
155
|
+
else:
|
|
156
|
+
self.console.print("[red]✗[/red] Hooks not installed")
|
|
157
|
+
|
|
158
|
+
if status["settings_file"]:
|
|
159
|
+
self.console.print(
|
|
160
|
+
f"[green]✓[/green] Settings file: {status['settings_file']}"
|
|
161
|
+
)
|
|
162
|
+
else:
|
|
163
|
+
self.console.print("[red]✗[/red] Settings file not found")
|
|
164
|
+
|
|
165
|
+
if status.get("configured_events"):
|
|
166
|
+
self.console.print(
|
|
167
|
+
f"[green]✓[/green] Configured events: {', '.join(status['configured_events'])}"
|
|
168
|
+
)
|
|
169
|
+
else:
|
|
170
|
+
self.console.print("[red]✗[/red] No events configured")
|
|
171
|
+
|
|
172
|
+
if status["valid"]:
|
|
173
|
+
self.console.print("\n[green]All checks passed![/green]")
|
|
174
|
+
else:
|
|
175
|
+
self.console.print("\n[red]Issues found:[/red]")
|
|
176
|
+
for issue in status["issues"]:
|
|
177
|
+
self.console.print(f" - {issue}")
|
|
178
|
+
|
|
179
|
+
return CommandResult.success_result(
|
|
180
|
+
"Hook verification complete", data=status
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
except ImportError:
|
|
184
|
+
self.console.print("[red]Error: HookInstaller module not found[/red]")
|
|
185
|
+
return CommandResult.error_result("HookInstaller module not found")
|
|
186
|
+
except Exception as e:
|
|
187
|
+
if self.logger:
|
|
188
|
+
self.logger.error(f"Hook verification error: {e}", exc_info=True)
|
|
189
|
+
return CommandResult.error_result(f"Hook verification failed: {e}")
|
|
190
|
+
|
|
191
|
+
def uninstall_hooks(self) -> CommandResult:
|
|
192
|
+
"""Uninstall Claude MPM hooks.
|
|
193
|
+
|
|
194
|
+
Extracted from ConfigureCommand._uninstall_hooks() (CC=5)
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
CommandResult with uninstallation status
|
|
198
|
+
"""
|
|
199
|
+
try:
|
|
200
|
+
from ...hooks.claude_hooks.installer import HookInstaller
|
|
201
|
+
|
|
202
|
+
installer = HookInstaller()
|
|
203
|
+
|
|
204
|
+
# Confirm uninstallation
|
|
205
|
+
if not Confirm.ask(
|
|
206
|
+
"[yellow]Are you sure you want to uninstall Claude MPM hooks?[/yellow]"
|
|
207
|
+
):
|
|
208
|
+
return CommandResult.success_result("Uninstallation cancelled")
|
|
209
|
+
|
|
210
|
+
self.console.print("[cyan]Uninstalling Claude MPM hooks...[/cyan]")
|
|
211
|
+
success = installer.uninstall_hooks()
|
|
212
|
+
|
|
213
|
+
if success:
|
|
214
|
+
self.console.print("[green]✓ Hooks uninstalled successfully![/green]")
|
|
215
|
+
return CommandResult.success_result("Hooks uninstalled successfully")
|
|
216
|
+
self.console.print("[red]✗ Hook uninstallation failed[/red]")
|
|
217
|
+
return CommandResult.error_result("Hook uninstallation failed")
|
|
218
|
+
|
|
219
|
+
except ImportError:
|
|
220
|
+
self.console.print("[red]Error: HookInstaller module not found[/red]")
|
|
221
|
+
return CommandResult.error_result("HookInstaller module not found")
|
|
222
|
+
except Exception as e:
|
|
223
|
+
if self.logger:
|
|
224
|
+
self.logger.error(f"Hook uninstallation error: {e}", exc_info=True)
|
|
225
|
+
return CommandResult.error_result(f"Hook uninstallation failed: {e}")
|