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 +1 -1
- claude_mpm/cli/__init__.py +28 -4
- claude_mpm/cli/parsers/__init__.py +7 -1
- claude_mpm/cli/parsers/base_parser.py +91 -3
- claude_mpm/cli/utils.py +52 -1
- {claude_mpm-4.14.2.dist-info → claude_mpm-4.14.3.dist-info}/METADATA +1 -1
- {claude_mpm-4.14.2.dist-info → claude_mpm-4.14.3.dist-info}/RECORD +11 -11
- {claude_mpm-4.14.2.dist-info → claude_mpm-4.14.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.14.2.dist-info → claude_mpm-4.14.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.14.2.dist-info → claude_mpm-4.14.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.14.2.dist-info → claude_mpm-4.14.3.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.14.
|
|
1
|
+
4.14.3
|
claude_mpm/cli/__init__.py
CHANGED
|
@@ -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
|
-
|
|
772
|
-
#
|
|
773
|
-
|
|
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
|
|
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
|
|
207
|
+
Configured SuggestingArgumentParser instance ready for subparser addition
|
|
120
208
|
"""
|
|
121
|
-
# Main parser
|
|
122
|
-
parser =
|
|
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,5 +1,5 @@
|
|
|
1
1
|
claude_mpm/BUILD_NUMBER,sha256=9JfxhnDtr-8l3kCP2U5TVXSErptHoga8m7XA8zqgGOc,4
|
|
2
|
-
claude_mpm/VERSION,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
858
|
-
claude_mpm-4.14.
|
|
859
|
-
claude_mpm-4.14.
|
|
860
|
-
claude_mpm-4.14.
|
|
861
|
-
claude_mpm-4.14.
|
|
862
|
-
claude_mpm-4.14.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|