claude-mpm 4.14.7__py3-none-any.whl → 4.14.9__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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (79) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/agent_loader.py +13 -1
  3. claude_mpm/agents/frontmatter_validator.py +284 -253
  4. claude_mpm/cli/__init__.py +34 -740
  5. claude_mpm/cli/commands/agent_manager.py +25 -12
  6. claude_mpm/cli/commands/agent_state_manager.py +186 -0
  7. claude_mpm/cli/commands/agents.py +204 -148
  8. claude_mpm/cli/commands/aggregate.py +7 -3
  9. claude_mpm/cli/commands/analyze.py +9 -4
  10. claude_mpm/cli/commands/analyze_code.py +7 -2
  11. claude_mpm/cli/commands/config.py +47 -13
  12. claude_mpm/cli/commands/configure.py +159 -1801
  13. claude_mpm/cli/commands/configure_agent_display.py +261 -0
  14. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  15. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  16. claude_mpm/cli/commands/configure_models.py +18 -0
  17. claude_mpm/cli/commands/configure_navigation.py +165 -0
  18. claude_mpm/cli/commands/configure_paths.py +104 -0
  19. claude_mpm/cli/commands/configure_persistence.py +254 -0
  20. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  21. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  22. claude_mpm/cli/commands/configure_validators.py +73 -0
  23. claude_mpm/cli/commands/memory.py +54 -20
  24. claude_mpm/cli/commands/mpm_init.py +35 -21
  25. claude_mpm/cli/executor.py +202 -0
  26. claude_mpm/cli/helpers.py +105 -0
  27. claude_mpm/cli/shared/output_formatters.py +28 -19
  28. claude_mpm/cli/startup.py +455 -0
  29. claude_mpm/core/enums.py +399 -0
  30. claude_mpm/core/instruction_reinforcement_hook.py +2 -1
  31. claude_mpm/core/interactive_session.py +6 -3
  32. claude_mpm/core/logging_config.py +6 -2
  33. claude_mpm/core/oneshot_session.py +8 -4
  34. claude_mpm/core/service_registry.py +5 -1
  35. claude_mpm/core/typing_utils.py +7 -6
  36. claude_mpm/hooks/instruction_reinforcement.py +7 -2
  37. claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
  38. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +3 -2
  39. claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
  40. claude_mpm/services/diagnostics/checks/installation_check.py +3 -2
  41. claude_mpm/services/diagnostics/checks/mcp_check.py +20 -6
  42. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +8 -7
  43. claude_mpm/services/memory_hook_service.py +4 -1
  44. claude_mpm/services/monitor/daemon_manager.py +3 -2
  45. claude_mpm/services/monitor/handlers/dashboard.py +2 -1
  46. claude_mpm/services/monitor/handlers/hooks.py +2 -1
  47. claude_mpm/services/monitor/management/lifecycle.py +3 -2
  48. claude_mpm/services/monitor/server.py +2 -1
  49. claude_mpm/services/session_management_service.py +3 -2
  50. claude_mpm/services/socketio/handlers/hook.py +3 -2
  51. claude_mpm/services/socketio/server/main.py +3 -1
  52. claude_mpm/services/subprocess_launcher_service.py +14 -5
  53. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +6 -5
  54. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
  55. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
  56. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +5 -4
  57. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
  58. claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
  59. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
  60. claude_mpm/services/unified/deployment_strategies/local.py +3 -2
  61. claude_mpm/services/unified/deployment_strategies/utils.py +2 -1
  62. claude_mpm/services/unified/deployment_strategies/vercel.py +2 -1
  63. claude_mpm/services/unified/interfaces.py +3 -1
  64. claude_mpm/services/unified/unified_analyzer.py +7 -6
  65. claude_mpm/services/unified/unified_config.py +2 -1
  66. claude_mpm/services/unified/unified_deployment.py +7 -2
  67. claude_mpm/tools/code_tree_analyzer.py +177 -141
  68. claude_mpm/tools/code_tree_events.py +4 -2
  69. {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.9.dist-info}/METADATA +1 -1
  70. {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.9.dist-info}/RECORD +74 -64
  71. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
  72. claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
  73. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
  74. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
  75. claude_mpm/services/project/analyzer_refactored.py +0 -450
  76. {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.9.dist-info}/WHEEL +0 -0
  77. {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.9.dist-info}/entry_points.txt +0 -0
  78. {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.9.dist-info}/licenses/LICENSE +0 -0
  79. {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,105 @@
1
+ """
2
+ CLI Helper Utilities
3
+ ====================
4
+
5
+ This module provides helper functions for the CLI, including configuration
6
+ checks and user prompts.
7
+
8
+ Part of cli/__init__.py refactoring to reduce file size and improve modularity.
9
+ """
10
+
11
+ import sys
12
+ from pathlib import Path
13
+
14
+
15
+ def has_configuration_file() -> bool:
16
+ """Check if any configuration file exists in standard locations."""
17
+ config_paths = [
18
+ Path.cwd() / ".claude-mpm" / "configuration.yaml",
19
+ Path.cwd() / ".claude-mpm" / "configuration.yml",
20
+ Path.home() / ".claude-mpm" / "configuration.yaml",
21
+ Path.home() / ".claude-mpm" / "configuration.yml",
22
+ ]
23
+ return any(path.exists() for path in config_paths)
24
+
25
+
26
+ def is_interactive_session() -> bool:
27
+ """Check if running in an interactive terminal."""
28
+ return sys.stdin.isatty() and sys.stdout.isatty()
29
+
30
+
31
+ def should_skip_config_check(command: str | None) -> bool:
32
+ """Check if command should skip configuration check."""
33
+ skip_commands = ["configure", "doctor", "info", "mcp", "config"]
34
+ return command in skip_commands if command else False
35
+
36
+
37
+ def prompt_for_configuration() -> bool:
38
+ """Prompt user to run configuration wizard.
39
+
40
+ Returns:
41
+ bool: True if user wants to configure, False otherwise
42
+ """
43
+ from rich.console import Console as RichConsole
44
+ from rich.prompt import Confirm
45
+
46
+ console = RichConsole()
47
+
48
+ console.print()
49
+ console.print("[yellow]⚙️ Configuration Recommended[/yellow]")
50
+ console.print()
51
+ console.print("Claude MPM works best with proper configuration.")
52
+ console.print("The configurator helps you:")
53
+ console.print(" • Enable/disable MCP services (ticketer, browser, vector-search)")
54
+ console.print(" • Configure hook services (monitor, dashboard)")
55
+ console.print(" • Select system agents to use")
56
+ console.print()
57
+
58
+ return Confirm.ask("Would you like to run the configurator now?", default=True)
59
+
60
+
61
+ def handle_missing_configuration():
62
+ """Handle missing configuration file by prompting user to configure.
63
+
64
+ WHY: Centralizes the logic for handling missing configuration files,
65
+ keeping main() cleaner and more focused.
66
+ """
67
+ if is_interactive_session():
68
+ # Interactive: Offer to run configurator
69
+ if prompt_for_configuration():
70
+ from rich.console import Console as RichConsole
71
+
72
+ # Import configure command only when needed
73
+ from .commands.configure import ConfigureCommand
74
+
75
+ console = RichConsole()
76
+ config_cmd = ConfigureCommand()
77
+ try:
78
+ config_cmd.execute({})
79
+ console.print(
80
+ "\n[green]✓[/green] Configuration complete! "
81
+ "Continuing with command...\n"
82
+ )
83
+ except Exception as e:
84
+ console.print(f"\n[yellow]⚠[/yellow] Configuration error: {e}")
85
+ console.print(
86
+ "[yellow]Continuing with default configuration...\n[/yellow]"
87
+ )
88
+ else:
89
+ from rich.console import Console as RichConsole
90
+
91
+ console = RichConsole()
92
+ console.print("\n[dim]Using default configuration.[/dim]")
93
+ console.print(
94
+ "[dim]Run 'claude-mpm configure' anytime to set up your "
95
+ "preferences.\n[/dim]"
96
+ )
97
+ else:
98
+ # Non-interactive: Log message only
99
+ import logging
100
+
101
+ logger = logging.getLogger(__name__)
102
+ logger.info(
103
+ "Configuration file not found, using defaults. "
104
+ "Run 'claude-mpm configure' to customize."
105
+ )
@@ -7,6 +7,8 @@ from typing import Any, Dict, List, Optional, Union
7
7
 
8
8
  import yaml
9
9
 
10
+ from claude_mpm.core.enums import OutputFormat
11
+
10
12
 
11
13
  class OutputFormatter:
12
14
  """Handles formatting output in different formats."""
@@ -104,13 +106,13 @@ class OutputFormatter:
104
106
  return str(data)
105
107
 
106
108
 
107
- def format_output(data: Any, format_type: str = "text", **kwargs) -> str:
109
+ def format_output(data: Any, format_type: str = OutputFormat.TEXT, **kwargs) -> str:
108
110
  """
109
111
  Format data according to the specified format.
110
112
 
111
113
  Args:
112
114
  data: Data to format
113
- format_type: Output format ('json', 'yaml', 'table', 'text')
115
+ format_type: Output format (use OutputFormat enum or string)
114
116
  **kwargs: Additional formatting options
115
117
 
116
118
  Returns:
@@ -118,20 +120,23 @@ def format_output(data: Any, format_type: str = "text", **kwargs) -> str:
118
120
  """
119
121
  formatter = OutputFormatter()
120
122
 
121
- if format_type == "json":
123
+ # Convert to string for comparison (handles both enum and string inputs)
124
+ fmt = str(format_type).lower()
125
+
126
+ if fmt == OutputFormat.JSON:
122
127
  return formatter.format_json(data, **kwargs)
123
- if format_type == "yaml":
128
+ if fmt == OutputFormat.YAML:
124
129
  return formatter.format_yaml(data)
125
- if format_type == "table":
130
+ if fmt == OutputFormat.TABLE:
126
131
  return formatter.format_table(data, **kwargs)
127
- if format_type == "text":
132
+ if fmt == OutputFormat.TEXT:
128
133
  return formatter.format_text(data)
129
134
  # Fallback to text format
130
135
  return formatter.format_text(data)
131
136
 
132
137
 
133
138
  def format_success_message(
134
- message: str, data: Any = None, format_type: str = "text"
139
+ message: str, data: Any = None, format_type: str = OutputFormat.TEXT
135
140
  ) -> str:
136
141
  """
137
142
  Format a success message with optional data.
@@ -139,12 +144,13 @@ def format_success_message(
139
144
  Args:
140
145
  message: Success message
141
146
  data: Optional data to include
142
- format_type: Output format
147
+ format_type: Output format (use OutputFormat enum or string)
143
148
 
144
149
  Returns:
145
150
  Formatted success message
146
151
  """
147
- if format_type in ("json", "yaml"):
152
+ fmt = str(format_type).lower()
153
+ if fmt in (OutputFormat.JSON, OutputFormat.YAML):
148
154
  result = {"success": True, "message": message}
149
155
  if data is not None:
150
156
  result["data"] = data
@@ -158,7 +164,7 @@ def format_success_message(
158
164
 
159
165
 
160
166
  def format_error_message(
161
- message: str, details: Any = None, format_type: str = "text"
167
+ message: str, details: Any = None, format_type: str = OutputFormat.TEXT
162
168
  ) -> str:
163
169
  """
164
170
  Format an error message with optional details.
@@ -166,12 +172,13 @@ def format_error_message(
166
172
  Args:
167
173
  message: Error message
168
174
  details: Optional error details
169
- format_type: Output format
175
+ format_type: Output format (use OutputFormat enum or string)
170
176
 
171
177
  Returns:
172
178
  Formatted error message
173
179
  """
174
- if format_type in ("json", "yaml"):
180
+ fmt = str(format_type).lower()
181
+ if fmt in (OutputFormat.JSON, OutputFormat.YAML):
175
182
  result = {"success": False, "error": message}
176
183
  if details is not None:
177
184
  result["details"] = details
@@ -187,7 +194,7 @@ def format_error_message(
187
194
  def format_list_output(
188
195
  items: List[Any],
189
196
  title: Optional[str] = None,
190
- format_type: str = "text",
197
+ format_type: str = OutputFormat.TEXT,
191
198
  headers: Optional[List[str]] = None,
192
199
  ) -> str:
193
200
  """
@@ -196,29 +203,31 @@ def format_list_output(
196
203
  Args:
197
204
  items: List of items to format
198
205
  title: Optional title for the list
199
- format_type: Output format
206
+ format_type: Output format (use OutputFormat enum or string)
200
207
  headers: Optional headers for table format
201
208
 
202
209
  Returns:
203
210
  Formatted list output
204
211
  """
212
+ fmt = str(format_type).lower()
213
+
205
214
  if not items:
206
215
  empty_msg = f"No {title.lower() if title else 'items'} found"
207
- if format_type in ("json", "yaml"):
216
+ if fmt in (OutputFormat.JSON, OutputFormat.YAML):
208
217
  return format_output({"items": [], "message": empty_msg}, format_type)
209
218
  return empty_msg
210
219
 
211
- if format_type in ("json", "yaml"):
220
+ if fmt in (OutputFormat.JSON, OutputFormat.YAML):
212
221
  result = {"items": items}
213
222
  if title:
214
223
  result["title"] = title
215
224
  return format_output(result, format_type)
216
225
 
217
- if format_type == "table":
226
+ if fmt == OutputFormat.TABLE:
218
227
  output = ""
219
228
  if title:
220
229
  output += f"{title}\n{'=' * len(title)}\n\n"
221
- output += format_output(items, "table", headers=headers)
230
+ output += format_output(items, OutputFormat.TABLE, headers=headers)
222
231
  return output
223
232
 
224
233
  # Text format
@@ -228,5 +237,5 @@ def format_list_output(
228
237
  lines.append("=" * len(title))
229
238
  lines.append("")
230
239
 
231
- lines.append(format_output(items, "text"))
240
+ lines.append(format_output(items, OutputFormat.TEXT))
232
241
  return "\n".join(lines)