claude-mpm 4.14.2__py3-none-any.whl → 4.14.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

claude_mpm/VERSION CHANGED
@@ -1 +1 @@
1
- 4.14.2
1
+ 4.14.3
@@ -677,7 +677,8 @@ def _execute_command(command: str, args) -> int:
677
677
  lazily to avoid loading unnecessary code.
678
678
 
679
679
  DESIGN DECISION: run_guarded is imported only when needed to maintain
680
- separation between stable and experimental features.
680
+ separation between stable and experimental features. Command suggestions
681
+ are provided for unknown commands to improve user experience.
681
682
 
682
683
  Args:
683
684
  command: The command name to execute
@@ -768,9 +769,32 @@ def _execute_command(command: str, args) -> int:
768
769
  result = command_map[command](args)
769
770
  # Commands may return None (success) or an exit code
770
771
  return result if result is not None else 0
771
- # Unknown command - this shouldn't happen with argparse
772
- # but we handle it for completeness
773
- print(f"Unknown command: {command}")
772
+
773
+ # Unknown command - provide suggestions
774
+ from rich.console import Console
775
+
776
+ from .utils import suggest_similar_commands
777
+
778
+ console = Console(stderr=True)
779
+
780
+ console.print(f"\n[red]Error:[/red] Unknown command: {command}\n", style="bold")
781
+
782
+ # Get all valid commands for suggestions
783
+ all_commands = [
784
+ *command_map.keys(),
785
+ "run-guarded",
786
+ "uninstall",
787
+ "verify",
788
+ "auto-configure",
789
+ "local-deploy",
790
+ ]
791
+
792
+ suggestion = suggest_similar_commands(command, all_commands)
793
+ if suggestion:
794
+ console.print(f"[yellow]{suggestion}[/yellow]\n")
795
+
796
+ console.print("[dim]Run 'claude-mpm --help' for usage information.[/dim]\n")
797
+
774
798
  return 1
775
799
 
776
800
 
@@ -18,10 +18,16 @@ DESIGN DECISION: Each parser module handles a specific command domain:
18
18
  - mcp_parser.py: MCP Gateway commands
19
19
  """
20
20
 
21
- from .base_parser import add_common_arguments, create_parser, preprocess_args
21
+ from .base_parser import (
22
+ SuggestingArgumentParser,
23
+ add_common_arguments,
24
+ create_parser,
25
+ preprocess_args,
26
+ )
22
27
  from .run_parser import add_run_arguments
23
28
 
24
29
  __all__ = [
30
+ "SuggestingArgumentParser",
25
31
  "add_common_arguments",
26
32
  "add_run_arguments",
27
33
  "create_parser",
@@ -11,11 +11,96 @@ and reduce duplication across command parsers.
11
11
  """
12
12
 
13
13
  import argparse
14
+ import sys
14
15
  from typing import List, Optional
15
16
 
16
17
  from ...constants import CLICommands, CLIPrefix, LogLevel
17
18
 
18
19
 
20
+ class SuggestingArgumentParser(argparse.ArgumentParser):
21
+ """
22
+ Custom ArgumentParser that suggests similar commands on error.
23
+
24
+ WHY: Provides better user experience by suggesting corrections for typos
25
+ and invalid commands instead of just showing an error message.
26
+
27
+ DESIGN DECISION: Extends ArgumentParser.error() to add suggestions before
28
+ exiting. This catches all parser errors including invalid subcommands and
29
+ invalid options.
30
+ """
31
+
32
+ def error(self, message: str) -> None:
33
+ """
34
+ Override error method to add command suggestions.
35
+
36
+ Args:
37
+ message: Error message from argparse
38
+ """
39
+ from ..utils import suggest_similar_commands
40
+
41
+ # Try to extract the invalid command/option from the error message
42
+ invalid_value = None
43
+ valid_choices = []
44
+
45
+ # Handle invalid subcommand errors
46
+ # Format: "argument COMMAND: invalid choice: 'tickts' (choose from ...)"
47
+ if "invalid choice:" in message:
48
+ try:
49
+ # Extract the invalid choice
50
+ parts = message.split("invalid choice: '")
51
+ if len(parts) > 1:
52
+ invalid_value = parts[1].split("'")[0]
53
+
54
+ # Extract valid choices
55
+ if "(choose from" in message:
56
+ choices_part = message.split("(choose from")[1]
57
+ # Remove trailing parenthesis and split
58
+ choices_str = choices_part.rstrip(")")
59
+ # Parse choices - they may be quoted or unquoted
60
+ valid_choices = [
61
+ c.strip().strip("'\"")
62
+ for c in choices_str.split(",")
63
+ if c.strip()
64
+ ]
65
+ except (IndexError, ValueError):
66
+ pass
67
+
68
+ # Handle unrecognized arguments (invalid options)
69
+ # Format: "unrecognized arguments: --verbos"
70
+ elif "unrecognized arguments:" in message:
71
+ try:
72
+ parts = message.split("unrecognized arguments:")
73
+ if len(parts) > 1:
74
+ invalid_value = parts[1].strip().split()[0]
75
+
76
+ # Get common options from parser
77
+ valid_choices = []
78
+ for action in self._actions:
79
+ for option in action.option_strings:
80
+ valid_choices.append(option)
81
+ except (IndexError, ValueError):
82
+ pass
83
+
84
+ # Build error message with suggestions
85
+ from rich.console import Console
86
+
87
+ console = Console(stderr=True)
88
+
89
+ console.print(f"\n[red]Error:[/red] {message}\n", style="bold")
90
+
91
+ # Add suggestions if we found valid choices
92
+ if invalid_value and valid_choices:
93
+ suggestion = suggest_similar_commands(invalid_value, valid_choices)
94
+ if suggestion:
95
+ console.print(f"[yellow]{suggestion}[/yellow]\n")
96
+
97
+ # Show help hint
98
+ console.print(f"[dim]Run '{self.prog} --help' for usage information.[/dim]\n")
99
+
100
+ # Exit with error code
101
+ sys.exit(2)
102
+
103
+
19
104
  def _get_enhanced_version(base_version: str) -> str:
20
105
  """
21
106
  Get enhanced version string with build number if available.
@@ -111,15 +196,18 @@ def create_main_parser(
111
196
  WHY: This creates the foundation parser that other modules will extend
112
197
  with their specific subcommands and arguments.
113
198
 
199
+ DESIGN DECISION: Uses SuggestingArgumentParser to provide helpful suggestions
200
+ for typos and invalid commands, improving user experience.
201
+
114
202
  Args:
115
203
  prog_name: The program name to use
116
204
  version: The version string to display
117
205
 
118
206
  Returns:
119
- Configured ArgumentParser instance ready for subparser addition
207
+ Configured SuggestingArgumentParser instance ready for subparser addition
120
208
  """
121
- # Main parser
122
- parser = argparse.ArgumentParser(
209
+ # Main parser with suggestion support
210
+ parser = SuggestingArgumentParser(
123
211
  prog=prog_name,
124
212
  description=f"Claude Multi-Agent Project Manager v{version} - Orchestrate Claude with agent delegation and ticket tracking",
125
213
  epilog="By default, runs an orchestrated Claude session. Use 'claude-mpm' for interactive mode or 'claude-mpm -i \"prompt\"' for non-interactive mode.\n\nTo pass arguments to Claude CLI, use -- separator: claude-mpm run -- --model sonnet --temperature 0.1",
claude_mpm/cli/utils.py CHANGED
@@ -6,9 +6,10 @@ Centralizing these functions reduces code duplication and provides a single plac
6
6
  for common CLI operations.
7
7
  """
8
8
 
9
+ import difflib
9
10
  import sys
10
11
  from pathlib import Path
11
- from typing import Optional
12
+ from typing import List, Optional
12
13
 
13
14
  from ..core.logger import get_logger
14
15
 
@@ -207,3 +208,53 @@ def ensure_directories() -> None:
207
208
  # Continue even if initialization fails
208
209
  # The individual commands will handle missing directories as needed
209
210
  pass
211
+
212
+
213
+ def suggest_similar_commands(
214
+ invalid_command: str,
215
+ valid_commands: List[str],
216
+ cutoff: float = 0.6,
217
+ max_suggestions: int = 3,
218
+ ) -> Optional[str]:
219
+ """
220
+ Suggest similar commands for an invalid command using fuzzy matching.
221
+
222
+ WHY: Helps users quickly identify typos and discover correct command names
223
+ by suggesting the most similar valid commands. Uses stdlib difflib for
224
+ zero-dependency fuzzy matching.
225
+
226
+ DESIGN DECISION: Using difflib.get_close_matches provides good results for
227
+ typos and partial matches while being simple and lightweight (no external deps).
228
+
229
+ Args:
230
+ invalid_command: The invalid command the user typed
231
+ valid_commands: List of valid commands to match against
232
+ cutoff: Similarity threshold (0.0-1.0), default 0.6
233
+ max_suggestions: Maximum number of suggestions to return, default 3
234
+
235
+ Returns:
236
+ Formatted suggestion string or None if no good matches found
237
+
238
+ Examples:
239
+ >>> suggest_similar_commands("tickts", ["tickets", "run", "agents"])
240
+ "Did you mean 'tickets'?"
241
+
242
+ >>> suggest_similar_commands("mem", ["memory", "monitor", "mcp"])
243
+ "Did you mean one of these?\n memory\n monitor\n mcp"
244
+
245
+ >>> suggest_similar_commands("xyz", ["tickets", "run"])
246
+ None # No good matches
247
+ """
248
+ # Use difflib to find close matches
249
+ matches = difflib.get_close_matches(
250
+ invalid_command, valid_commands, n=max_suggestions, cutoff=cutoff
251
+ )
252
+
253
+ if not matches:
254
+ return None
255
+
256
+ # Format suggestion message
257
+ if len(matches) == 1:
258
+ return f"Did you mean '{matches[0]}'?"
259
+ suggestions = "\n ".join(matches)
260
+ return f"Did you mean one of these?\n {suggestions}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.14.2
3
+ Version: 4.14.3
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team
@@ -1,5 +1,5 @@
1
1
  claude_mpm/BUILD_NUMBER,sha256=9JfxhnDtr-8l3kCP2U5TVXSErptHoga8m7XA8zqgGOc,4
2
- claude_mpm/VERSION,sha256=rbLlIbQiWCgMPTPwuqeiHsgsiTRD_NG0Tr2g6Sr13S0,7
2
+ claude_mpm/VERSION,sha256=7oWlBGWd7V4lGnco4r7qGl9xG9jxdiZYnWOZLOTq-W8,7
3
3
  claude_mpm/__init__.py,sha256=UCw6j9e_tZQ3kJtTqmdfNv7MHyw9nD1jkj80WurwM2g,2064
4
4
  claude_mpm/__main__.py,sha256=Ro5UBWBoQaSAIoSqWAr7zkbLyvi4sSy28WShqAhKJG0,723
5
5
  claude_mpm/constants.py,sha256=sLjJF6Kw7H4V9WWeaEYltM-77TgXqzEMX5vx4ukM5-0,5977
@@ -76,12 +76,12 @@ claude_mpm/agents/templates/.claude-mpm/memories/README.md,sha256=vEiG7cPjHRZfwX
76
76
  claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md,sha256=KMZSJrQi-wHOwfl2C0m3A4PpC4QuBtDolAtVybGahKc,77
77
77
  claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md,sha256=UBm4BycXtdaa-_l1VCh0alTGGOUSsnCbpKwbFuI-mUY,2219
78
78
  claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md,sha256=oPvFSYFnmJ4TkbTe4AZnNHWaJMJ-xqZP2WM6scUKQKo,13089
79
- claude_mpm/cli/__init__.py,sha256=GHKbVPW76UTMKENKvHKBn4vMDTqlx-Xp1f6TxSj7hr4,30107
79
+ claude_mpm/cli/__init__.py,sha256=hUzId4sZmUQHvbuxsgbyYetpdhvAq_cMz_uyhXjRLxw,30745
80
80
  claude_mpm/cli/__main__.py,sha256=WnVGBwe10InxuZjJRFdwuMF6Gh16aXox6zFgxr0sRXk,847
81
81
  claude_mpm/cli/parser.py,sha256=Vqx9n-6Xo1uNhXR4rThmgWpZXTr0nOtkgDf3oMS9b0g,5855
82
82
  claude_mpm/cli/startup_logging.py,sha256=RTuyd6CbhiFQz7Z07LDDhK_ZAnZfuJ9B0NghVSntHFI,29390
83
83
  claude_mpm/cli/ticket_cli.py,sha256=Cco0riIeo-PuzBslX3-5LAtLUcsLvexSRtVlheb7-cQ,916
84
- claude_mpm/cli/utils.py,sha256=T0jLFCeMQoq3PF4nNxNdflgoOHlceIdqawE1c_D9-E0,7033
84
+ claude_mpm/cli/utils.py,sha256=CZeqOhzMxiOI0odyzqyvN-1VaqlJSdBCSigIZsfoNn4,8786
85
85
  claude_mpm/cli/commands/__init__.py,sha256=1EJpBPxZMYQlMUbguqC6QCET8tv6yqY-_FOg814Xxp0,1226
86
86
  claude_mpm/cli/commands/agent_manager.py,sha256=PjcUJ83Fhb4LxNCObb1wvh66TtJZLOtbF2lHlebSl64,56126
87
87
  claude_mpm/cli/commands/agents.py,sha256=_R0JfewWRNOlf3PhhPkpkhpvCWc3O51kYTbTgn94j4k,59945
@@ -122,13 +122,13 @@ claude_mpm/cli/commands/upgrade.py,sha256=NYMVONNlj78WHoQ6eyVInroE95AeQxUY2_TpjY
122
122
  claude_mpm/cli/commands/verify.py,sha256=wmu2UYINK15q2e34TdlTyamvtLDE7r3Oj_XT9zpT5Kk,3687
123
123
  claude_mpm/cli/interactive/__init__.py,sha256=vQqUCgPFvLYA1Vkq-5pnY7Ow3A-IgdM0SByfNL1ZLTk,433
124
124
  claude_mpm/cli/interactive/agent_wizard.py,sha256=v3nKcLusU49ewjCqvgUWsG35UGc82pC7_Uv-ZzAHZ-c,36201
125
- claude_mpm/cli/parsers/__init__.py,sha256=f0Fm1DDXorlVOZPLxUpjC-GIvLh01G-FZOK7TEV1L3I,1005
125
+ claude_mpm/cli/parsers/__init__.py,sha256=B-p07lgtefapDHt0SZm7XkSBtXH51uegUWvoDcFtjhw,1084
126
126
  claude_mpm/cli/parsers/agent_manager_parser.py,sha256=TQEIm638ELM4X_AAGcn6WrJxlti9wFLfEkHjr-6AtZA,13761
127
127
  claude_mpm/cli/parsers/agents_parser.py,sha256=ztzbYFsu4q49MqNKC3oWBPwGPzs5JX4lx9UdDC8h298,9326
128
128
  claude_mpm/cli/parsers/analyze_code_parser.py,sha256=cpJSMFbc3mqB4qrMBIEZiikzPekC2IQX-cjt9U2fHW4,5356
129
129
  claude_mpm/cli/parsers/analyze_parser.py,sha256=E00Ao0zwzbJPchs_AJt-aoQ7LQEtJPXRCNQ6Piivb4o,3908
130
130
  claude_mpm/cli/parsers/auto_configure_parser.py,sha256=NZWZRb00bsGU7_wgiYiPm2ZcPx1E9zy4Gp7MPecQmUA,7264
131
- claude_mpm/cli/parsers/base_parser.py,sha256=u6Mni33UZHHgiw8b6SwzkaJybVT_1z1nY9WmMFcucAg,14630
131
+ claude_mpm/cli/parsers/base_parser.py,sha256=GLnuZW28EXHHX9iiafaiFeC1nm27b55tX8ksr2qe9bg,17939
132
132
  claude_mpm/cli/parsers/config_parser.py,sha256=wp6NbV8_p9txP28MXFcQrri0JDIfGFM7u4aJbYJXcYQ,2699
133
133
  claude_mpm/cli/parsers/configure_parser.py,sha256=t3cwAQX3BfljDDRJH3i0LplpRprw5jdKcI9Uy3M8xtE,4382
134
134
  claude_mpm/cli/parsers/dashboard_parser.py,sha256=JBCM6v_iZhADr_Fwtk_d3up9AOod1avMab-vkNE61gE,3460
@@ -854,9 +854,9 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
854
854
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
855
855
  claude_mpm/validation/agent_validator.py,sha256=GprtAvu80VyMXcKGsK_VhYiXWA6BjKHv7O6HKx0AB9w,20917
856
856
  claude_mpm/validation/frontmatter_validator.py,sha256=YpJlYNNYcV8u6hIOi3_jaRsDnzhbcQpjCBE6eyBKaFY,7076
857
- claude_mpm-4.14.2.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
858
- claude_mpm-4.14.2.dist-info/METADATA,sha256=Df7_gDbERLNbITmqxjLckk7YBJ8JMa50aG31QyxXxss,17967
859
- claude_mpm-4.14.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
860
- claude_mpm-4.14.2.dist-info/entry_points.txt,sha256=Vlw3GNi-OtTpKSrez04iNrPmxNxYDpIWxmJCxiZ5Tx8,526
861
- claude_mpm-4.14.2.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
862
- claude_mpm-4.14.2.dist-info/RECORD,,
857
+ claude_mpm-4.14.3.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
858
+ claude_mpm-4.14.3.dist-info/METADATA,sha256=k0U40o3Amwo591JVys273VyI_mUHl0wqwcTLcnm29Zw,17967
859
+ claude_mpm-4.14.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
860
+ claude_mpm-4.14.3.dist-info/entry_points.txt,sha256=Vlw3GNi-OtTpKSrez04iNrPmxNxYDpIWxmJCxiZ5Tx8,526
861
+ claude_mpm-4.14.3.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
862
+ claude_mpm-4.14.3.dist-info/RECORD,,