claude-mpm 4.0.28__py3-none-any.whl → 4.0.30__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/agents/BASE_AGENT_TEMPLATE.md +48 -3
- claude_mpm/agents/BASE_PM.md +20 -15
- claude_mpm/agents/INSTRUCTIONS.md +12 -2
- claude_mpm/agents/templates/agent-manager.json +24 -0
- claude_mpm/agents/templates/agent-manager.md +304 -0
- claude_mpm/agents/templates/documentation.json +16 -3
- claude_mpm/agents/templates/engineer.json +19 -5
- claude_mpm/agents/templates/ops.json +19 -5
- claude_mpm/agents/templates/qa.json +16 -3
- claude_mpm/agents/templates/refactoring_engineer.json +25 -7
- claude_mpm/agents/templates/research.json +19 -5
- claude_mpm/cli/__init__.py +4 -0
- claude_mpm/cli/commands/__init__.py +4 -0
- claude_mpm/cli/commands/agent_manager.py +521 -0
- claude_mpm/cli/commands/agents.py +2 -1
- claude_mpm/cli/commands/cleanup.py +1 -1
- claude_mpm/cli/commands/doctor.py +209 -0
- claude_mpm/cli/commands/mcp.py +3 -3
- claude_mpm/cli/commands/mcp_install_commands.py +12 -30
- claude_mpm/cli/commands/mcp_server_commands.py +9 -9
- claude_mpm/cli/commands/memory.py +1 -1
- claude_mpm/cli/commands/run.py +31 -2
- claude_mpm/cli/commands/run_config_checker.py +1 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +247 -0
- claude_mpm/cli/parsers/base_parser.py +12 -1
- claude_mpm/cli/parsers/mcp_parser.py +1 -1
- claude_mpm/cli/parsers/run_parser.py +1 -1
- claude_mpm/cli/shared/__init__.py +1 -1
- claude_mpm/cli/startup_logging.py +463 -0
- claude_mpm/constants.py +2 -0
- claude_mpm/core/claude_runner.py +81 -2
- claude_mpm/core/constants.py +2 -2
- claude_mpm/core/framework_loader.py +45 -11
- claude_mpm/core/interactive_session.py +82 -3
- claude_mpm/core/output_style_manager.py +6 -6
- claude_mpm/core/socketio_pool.py +2 -2
- claude_mpm/core/unified_paths.py +128 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/built/dashboard.js +1 -1
- claude_mpm/dashboard/static/built/socket-client.js +1 -1
- claude_mpm/dashboard/static/css/dashboard.css +170 -0
- claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/dashboard.js +1 -1
- claude_mpm/dashboard/static/dist/socket-client.js +1 -1
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +21 -3
- claude_mpm/dashboard/static/js/components/module-viewer.js +129 -1
- claude_mpm/dashboard/static/js/dashboard.js +116 -0
- claude_mpm/dashboard/static/js/socket-client.js +0 -1
- claude_mpm/hooks/claude_hooks/connection_pool.py +1 -1
- claude_mpm/hooks/claude_hooks/hook_handler.py +1 -1
- claude_mpm/scripts/mcp_server.py +2 -2
- claude_mpm/services/agents/agent_builder.py +455 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +10 -3
- claude_mpm/services/agents/deployment/agent_validator.py +1 -0
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +69 -1
- claude_mpm/services/diagnostics/__init__.py +18 -0
- claude_mpm/services/diagnostics/checks/__init__.py +30 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +319 -0
- claude_mpm/services/diagnostics/checks/base_check.py +64 -0
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +283 -0
- claude_mpm/services/diagnostics/checks/common_issues_check.py +354 -0
- claude_mpm/services/diagnostics/checks/configuration_check.py +300 -0
- claude_mpm/services/diagnostics/checks/filesystem_check.py +233 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +255 -0
- claude_mpm/services/diagnostics/checks/mcp_check.py +315 -0
- claude_mpm/services/diagnostics/checks/monitor_check.py +282 -0
- claude_mpm/services/diagnostics/checks/startup_log_check.py +322 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +247 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +283 -0
- claude_mpm/services/diagnostics/models.py +120 -0
- claude_mpm/services/mcp_gateway/core/interfaces.py +1 -1
- claude_mpm/services/mcp_gateway/main.py +1 -1
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +3 -3
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
- claude_mpm/services/mcp_gateway/server/stdio_server.py +3 -3
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +2 -2
- claude_mpm/services/memory/__init__.py +2 -0
- claude_mpm/services/socketio/handlers/connection.py +27 -33
- claude_mpm/services/socketio/handlers/registry.py +39 -7
- claude_mpm/services/socketio/server/core.py +72 -22
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/METADATA +4 -1
- {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/RECORD +89 -67
- /claude_mpm/cli/shared/{command_base.py → base_command.py} +0 -0
- {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/WHEEL +0 -0
- {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Doctor command implementation for claude-mpm.
|
|
3
|
+
|
|
4
|
+
WHY: Provide a comprehensive diagnostic tool to help users identify and fix
|
|
5
|
+
common issues with their claude-mpm installation and configuration.
|
|
6
|
+
|
|
7
|
+
DESIGN DECISIONS:
|
|
8
|
+
- Use diagnostic runner for orchestration
|
|
9
|
+
- Support multiple output formats (terminal, JSON, markdown)
|
|
10
|
+
- Provide verbose mode for detailed diagnostics
|
|
11
|
+
- Future: Support --fix flag for automatic remediation
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from ...services.diagnostics import DiagnosticRunner, DoctorReporter
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def add_doctor_parser(subparsers):
|
|
22
|
+
"""Add doctor command parser.
|
|
23
|
+
|
|
24
|
+
WHY: This command helps users diagnose and fix issues with their
|
|
25
|
+
claude-mpm installation, providing clear actionable feedback.
|
|
26
|
+
"""
|
|
27
|
+
parser = subparsers.add_parser(
|
|
28
|
+
"doctor",
|
|
29
|
+
aliases=["diagnose", "check-health"],
|
|
30
|
+
help="Run comprehensive diagnostics on claude-mpm installation",
|
|
31
|
+
description="Run comprehensive health checks on your claude-mpm installation and configuration"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
parser.add_argument(
|
|
35
|
+
"--verbose",
|
|
36
|
+
"-v",
|
|
37
|
+
action="store_true",
|
|
38
|
+
help="Show detailed diagnostic information"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"--json",
|
|
43
|
+
action="store_true",
|
|
44
|
+
help="Output results in JSON format"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"--markdown",
|
|
49
|
+
action="store_true",
|
|
50
|
+
help="Output results in Markdown format"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
parser.add_argument(
|
|
54
|
+
"--fix",
|
|
55
|
+
action="store_true",
|
|
56
|
+
help="Attempt to fix issues automatically (experimental)"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"--checks",
|
|
61
|
+
nargs="+",
|
|
62
|
+
choices=[
|
|
63
|
+
"installation", "configuration", "filesystem",
|
|
64
|
+
"claude", "agents", "mcp", "monitor", "common"
|
|
65
|
+
],
|
|
66
|
+
help="Run only specific checks"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
parser.add_argument(
|
|
70
|
+
"--parallel",
|
|
71
|
+
action="store_true",
|
|
72
|
+
help="Run checks in parallel for faster execution"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
parser.add_argument(
|
|
76
|
+
"--no-color",
|
|
77
|
+
action="store_true",
|
|
78
|
+
help="Disable colored output"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
parser.add_argument(
|
|
82
|
+
"--output",
|
|
83
|
+
"-o",
|
|
84
|
+
type=Path,
|
|
85
|
+
help="Save output to file"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
parser.set_defaults(func=doctor_command)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def run_doctor(args):
|
|
92
|
+
"""Main entry point for doctor command (used by CLI).
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
args: Parsed command-line arguments
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
Exit code (0 for success, 1 for warnings, 2 for errors)
|
|
99
|
+
"""
|
|
100
|
+
return doctor_command(args)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def doctor_command(args):
|
|
104
|
+
"""Execute the doctor command.
|
|
105
|
+
|
|
106
|
+
WHY: Provides a single entry point for system diagnostics, helping users
|
|
107
|
+
quickly identify and resolve issues with their claude-mpm setup.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
args: Parsed command-line arguments
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
Exit code (0 for success, 1 for warnings, 2 for errors)
|
|
114
|
+
"""
|
|
115
|
+
# Configure logging
|
|
116
|
+
logger = logging.getLogger(__name__)
|
|
117
|
+
|
|
118
|
+
# Determine output format
|
|
119
|
+
if args.json:
|
|
120
|
+
output_format = "json"
|
|
121
|
+
elif args.markdown:
|
|
122
|
+
output_format = "markdown"
|
|
123
|
+
else:
|
|
124
|
+
output_format = "terminal"
|
|
125
|
+
|
|
126
|
+
# Create diagnostic runner
|
|
127
|
+
runner = DiagnosticRunner(
|
|
128
|
+
verbose=args.verbose,
|
|
129
|
+
fix=args.fix
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Run diagnostics
|
|
133
|
+
try:
|
|
134
|
+
if args.checks:
|
|
135
|
+
# Run specific checks
|
|
136
|
+
logger.info(f"Running specific checks: {', '.join(args.checks)}")
|
|
137
|
+
summary = runner.run_specific_checks(args.checks)
|
|
138
|
+
elif args.parallel:
|
|
139
|
+
# Run all checks in parallel
|
|
140
|
+
logger.info("Running diagnostics in parallel mode")
|
|
141
|
+
summary = runner.run_diagnostics_parallel()
|
|
142
|
+
else:
|
|
143
|
+
# Run all checks sequentially
|
|
144
|
+
logger.info("Running comprehensive diagnostics")
|
|
145
|
+
summary = runner.run_diagnostics()
|
|
146
|
+
|
|
147
|
+
except KeyboardInterrupt:
|
|
148
|
+
print("\nDiagnostics interrupted by user")
|
|
149
|
+
return 130
|
|
150
|
+
except Exception as e:
|
|
151
|
+
logger.error(f"Diagnostic failed: {e}")
|
|
152
|
+
print(f"\n❌ Diagnostic failed: {str(e)}")
|
|
153
|
+
if args.verbose:
|
|
154
|
+
import traceback
|
|
155
|
+
traceback.print_exc()
|
|
156
|
+
return 2
|
|
157
|
+
|
|
158
|
+
# Create reporter
|
|
159
|
+
reporter = DoctorReporter(
|
|
160
|
+
use_color=not args.no_color,
|
|
161
|
+
verbose=args.verbose
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Output results
|
|
165
|
+
if args.output:
|
|
166
|
+
# Save to file
|
|
167
|
+
try:
|
|
168
|
+
import sys
|
|
169
|
+
original_stdout = sys.stdout
|
|
170
|
+
with open(args.output, 'w') as f:
|
|
171
|
+
sys.stdout = f
|
|
172
|
+
reporter.report(summary, format=output_format)
|
|
173
|
+
sys.stdout = original_stdout
|
|
174
|
+
print(f"Report saved to: {args.output}")
|
|
175
|
+
except Exception as e:
|
|
176
|
+
logger.error(f"Failed to save report: {e}")
|
|
177
|
+
print(f"❌ Failed to save report: {str(e)}")
|
|
178
|
+
# Still output to terminal
|
|
179
|
+
reporter.report(summary, format=output_format)
|
|
180
|
+
else:
|
|
181
|
+
# Output to terminal
|
|
182
|
+
reporter.report(summary, format=output_format)
|
|
183
|
+
|
|
184
|
+
# Determine exit code based on results
|
|
185
|
+
if summary.error_count > 0:
|
|
186
|
+
return 2 # Errors found
|
|
187
|
+
elif summary.warning_count > 0:
|
|
188
|
+
return 1 # Warnings found
|
|
189
|
+
else:
|
|
190
|
+
return 0 # All OK
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
# Optional: Standalone execution for testing
|
|
194
|
+
if __name__ == "__main__":
|
|
195
|
+
import argparse
|
|
196
|
+
|
|
197
|
+
parser = argparse.ArgumentParser(description="Claude MPM Doctor")
|
|
198
|
+
parser.add_argument("--verbose", "-v", action="store_true")
|
|
199
|
+
parser.add_argument("--json", action="store_true")
|
|
200
|
+
parser.add_argument("--fix", action="store_true")
|
|
201
|
+
parser.add_argument("--no-color", action="store_true")
|
|
202
|
+
parser.add_argument("--checks", nargs="+")
|
|
203
|
+
parser.add_argument("--parallel", action="store_true")
|
|
204
|
+
|
|
205
|
+
args = parser.parse_args()
|
|
206
|
+
args.markdown = False
|
|
207
|
+
args.output = None
|
|
208
|
+
|
|
209
|
+
sys.exit(doctor_command(args))
|
claude_mpm/cli/commands/mcp.py
CHANGED
|
@@ -157,7 +157,7 @@ def _show_status(
|
|
|
157
157
|
else:
|
|
158
158
|
print(f" No config file at {config_path}")
|
|
159
159
|
|
|
160
|
-
# Show Claude
|
|
160
|
+
# Show Claude Code configuration
|
|
161
161
|
claude_config = (
|
|
162
162
|
Path.home()
|
|
163
163
|
/ "Library"
|
|
@@ -166,7 +166,7 @@ def _show_status(
|
|
|
166
166
|
/ "claude_desktop_config.json"
|
|
167
167
|
)
|
|
168
168
|
if claude_config.exists():
|
|
169
|
-
print(f"\n🖥️ Claude
|
|
169
|
+
print(f"\n🖥️ Claude Code Config: {claude_config}")
|
|
170
170
|
try:
|
|
171
171
|
with open(claude_config) as f:
|
|
172
172
|
config = json.load(f)
|
|
@@ -179,7 +179,7 @@ def _show_status(
|
|
|
179
179
|
except Exception as e:
|
|
180
180
|
print(f" ⚠️ Error reading config: {e}")
|
|
181
181
|
else:
|
|
182
|
-
print("\n🖥️ Claude
|
|
182
|
+
print("\n🖥️ Claude Code not configured for MCP")
|
|
183
183
|
print(" Run: claude-mpm mcp start (for instructions)")
|
|
184
184
|
|
|
185
185
|
# Show available tools count
|
|
@@ -159,48 +159,30 @@ class MCPInstallCommands:
|
|
|
159
159
|
|
|
160
160
|
DESIGN DECISION: We prioritize in this order:
|
|
161
161
|
1. System-installed claude-mpm (most reliable)
|
|
162
|
-
2.
|
|
163
|
-
3.
|
|
162
|
+
2. pipx-installed claude-mpm (detected via deployment context)
|
|
163
|
+
3. Virtual environment claude-mpm (development)
|
|
164
|
+
4. Python module invocation (fallback)
|
|
164
165
|
|
|
165
166
|
Returns:
|
|
166
167
|
str or None: Path to claude-mpm executable
|
|
167
168
|
"""
|
|
168
|
-
import shutil
|
|
169
169
|
import sys
|
|
170
|
-
import
|
|
171
|
-
|
|
172
|
-
#
|
|
173
|
-
|
|
174
|
-
if
|
|
175
|
-
print(f" Found claude-mpm: {
|
|
176
|
-
return
|
|
177
|
-
|
|
178
|
-
#
|
|
179
|
-
if hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
|
|
180
|
-
# We're in a virtual environment
|
|
181
|
-
venv_bin = Path(sys.prefix) / ("Scripts" if sys.platform == "win32" else "bin")
|
|
182
|
-
venv_claude_mpm = venv_bin / "claude-mpm"
|
|
183
|
-
if venv_claude_mpm.exists():
|
|
184
|
-
print(f" Found claude-mpm in venv: {venv_claude_mpm}")
|
|
185
|
-
return str(venv_claude_mpm)
|
|
186
|
-
|
|
187
|
-
# 3. Check if claude_mpm module is installed and use Python to run it
|
|
170
|
+
from ...core.unified_paths import get_executable_path
|
|
171
|
+
|
|
172
|
+
# Use the enhanced unified path manager for executable detection
|
|
173
|
+
executable_path = get_executable_path()
|
|
174
|
+
if executable_path:
|
|
175
|
+
print(f" Found claude-mpm: {executable_path}")
|
|
176
|
+
return str(executable_path)
|
|
177
|
+
|
|
178
|
+
# Fallback: Use Python module invocation if no executable found
|
|
188
179
|
try:
|
|
189
180
|
import claude_mpm
|
|
190
|
-
# Return the Python executable - we'll handle the -m args separately
|
|
191
181
|
print(f" Using Python module: {sys.executable} -m claude_mpm")
|
|
192
182
|
return sys.executable
|
|
193
183
|
except ImportError:
|
|
194
184
|
pass
|
|
195
185
|
|
|
196
|
-
# 4. Last resort: check project's local venv (development mode)
|
|
197
|
-
project_root = Path(__file__).parent.parent.parent.parent.parent
|
|
198
|
-
local_venv_bin = project_root / "venv" / ("Scripts" if sys.platform == "win32" else "bin")
|
|
199
|
-
local_claude_mpm = local_venv_bin / "claude-mpm"
|
|
200
|
-
if local_claude_mpm.exists():
|
|
201
|
-
print(f" Found claude-mpm in project venv: {local_claude_mpm}")
|
|
202
|
-
return str(local_claude_mpm)
|
|
203
|
-
|
|
204
186
|
return None
|
|
205
187
|
|
|
206
188
|
def _load_or_create_config(self, config_path, force=False):
|
|
@@ -22,11 +22,11 @@ class MCPServerCommands:
|
|
|
22
22
|
"""Start MCP server command.
|
|
23
23
|
|
|
24
24
|
WHY: This command starts the MCP server using the proper stdio-based
|
|
25
|
-
implementation that Claude
|
|
26
|
-
NOTE: MCP is for Claude
|
|
25
|
+
implementation that Claude Code can communicate with.
|
|
26
|
+
NOTE: MCP is specifically for Claude Code features.
|
|
27
27
|
|
|
28
28
|
DESIGN DECISION: Run the server directly in the same process to ensure
|
|
29
|
-
Claude
|
|
29
|
+
Claude Code sees the correct command path, not a wrapper script.
|
|
30
30
|
"""
|
|
31
31
|
self.logger.info("MCP server start command called")
|
|
32
32
|
|
|
@@ -39,18 +39,18 @@ class MCPServerCommands:
|
|
|
39
39
|
# Daemon mode - not recommended for MCP
|
|
40
40
|
print("⚠️ MCP servers are designed to be spawned by Claude Code")
|
|
41
41
|
print(" Running as a daemon is not recommended.")
|
|
42
|
-
print(" Note: MCP is
|
|
42
|
+
print(" Note: MCP is specifically for Claude Code.")
|
|
43
43
|
return 1
|
|
44
44
|
|
|
45
45
|
if show_instructions:
|
|
46
46
|
# Show configuration instructions
|
|
47
|
-
print("🚀 MCP Server Setup Instructions for Claude
|
|
47
|
+
print("🚀 MCP Server Setup Instructions for Claude Code")
|
|
48
48
|
print("=" * 50)
|
|
49
|
-
print("\nThe MCP server enables Claude
|
|
49
|
+
print("\nThe MCP server enables Claude Code to use tools and integrations.")
|
|
50
50
|
print("\nTo configure the MCP server:")
|
|
51
51
|
print("\n1. Run the configuration script:")
|
|
52
52
|
print(" python scripts/configure_mcp_server.py")
|
|
53
|
-
print("\n2. Or manually configure Claude
|
|
53
|
+
print("\n2. Or manually configure Claude Code:")
|
|
54
54
|
|
|
55
55
|
# Find project root for paths
|
|
56
56
|
project_root = Path(__file__).parent.parent.parent.parent.parent
|
|
@@ -62,7 +62,7 @@ class MCPServerCommands:
|
|
|
62
62
|
# Fallback to current executable
|
|
63
63
|
claude_mpm_path = sys.executable.replace("python", "claude-mpm")
|
|
64
64
|
|
|
65
|
-
print("\n Add this to your Claude
|
|
65
|
+
print("\n Add this to your Claude Code configuration:")
|
|
66
66
|
print(" (~/Library/Application Support/Claude/claude_desktop_config.json on macOS)")
|
|
67
67
|
print("\n {")
|
|
68
68
|
print(' "mcpServers": {')
|
|
@@ -73,7 +73,7 @@ class MCPServerCommands:
|
|
|
73
73
|
print(' }')
|
|
74
74
|
print(' }')
|
|
75
75
|
print(' }')
|
|
76
|
-
print("\n3. Restart Claude
|
|
76
|
+
print("\n3. Restart Claude Code to load the MCP server")
|
|
77
77
|
print("\nTo test the server directly:")
|
|
78
78
|
print(" claude-mpm mcp server")
|
|
79
79
|
print("\nTo check running MCP processes:")
|
|
@@ -23,7 +23,7 @@ from ...core.config import Config
|
|
|
23
23
|
from ...core.logger import get_logger
|
|
24
24
|
from ...core.shared.config_loader import ConfigLoader
|
|
25
25
|
from ...services.agents.memory import AgentMemoryManager
|
|
26
|
-
from ..shared.
|
|
26
|
+
from ..shared.base_command import MemoryCommand, CommandResult
|
|
27
27
|
from ..shared.argument_patterns import add_memory_arguments, add_output_arguments
|
|
28
28
|
|
|
29
29
|
|
claude_mpm/cli/commands/run.py
CHANGED
|
@@ -30,6 +30,11 @@ from ...core.unified_paths import get_package_root, get_scripts_dir
|
|
|
30
30
|
from ...services.port_manager import PortManager
|
|
31
31
|
from ...utils.dependency_manager import ensure_socketio_dependencies
|
|
32
32
|
from ..shared import BaseCommand, CommandResult
|
|
33
|
+
from ..startup_logging import (
|
|
34
|
+
log_startup_status,
|
|
35
|
+
setup_startup_logging,
|
|
36
|
+
cleanup_old_startup_logs
|
|
37
|
+
)
|
|
33
38
|
from ..utils import get_user_input, list_agent_versions_at_startup
|
|
34
39
|
|
|
35
40
|
|
|
@@ -232,6 +237,12 @@ class RunCommand(BaseCommand):
|
|
|
232
237
|
if args.logging != LogLevel.OFF.value:
|
|
233
238
|
self.logger.info("Starting Claude MPM session")
|
|
234
239
|
|
|
240
|
+
# Log MCP and monitor startup status
|
|
241
|
+
if args.logging != LogLevel.OFF.value:
|
|
242
|
+
monitor_mode = getattr(args, "monitor", False)
|
|
243
|
+
websocket_port = getattr(args, "websocket_port", 8765)
|
|
244
|
+
log_startup_status(monitor_mode, websocket_port)
|
|
245
|
+
|
|
235
246
|
# Perform startup checks
|
|
236
247
|
self._check_configuration_health()
|
|
237
248
|
self._check_claude_json_memory(args)
|
|
@@ -549,9 +560,27 @@ def run_session_legacy(args):
|
|
|
549
560
|
Args:
|
|
550
561
|
args: Parsed command line arguments
|
|
551
562
|
"""
|
|
563
|
+
# Set up startup logging to file early in the process
|
|
564
|
+
startup_log_file = setup_startup_logging(Path.cwd())
|
|
565
|
+
|
|
552
566
|
logger = get_logger("cli")
|
|
553
567
|
if args.logging != LogLevel.OFF.value:
|
|
554
568
|
logger.info("Starting Claude MPM session")
|
|
569
|
+
logger.info(f"Startup log: {startup_log_file}")
|
|
570
|
+
|
|
571
|
+
# Clean up old startup logs (keep last 7 days or minimum 10 files)
|
|
572
|
+
try:
|
|
573
|
+
deleted_count = cleanup_old_startup_logs(Path.cwd())
|
|
574
|
+
if deleted_count > 0:
|
|
575
|
+
logger.debug(f"Cleaned up {deleted_count} old startup log files")
|
|
576
|
+
except Exception as e:
|
|
577
|
+
logger.debug(f"Failed to clean up old logs: {e}")
|
|
578
|
+
|
|
579
|
+
# Log MCP and monitor startup status
|
|
580
|
+
if args.logging != LogLevel.OFF.value:
|
|
581
|
+
monitor_mode = getattr(args, "monitor", False)
|
|
582
|
+
websocket_port = getattr(args, "websocket_port", 8765)
|
|
583
|
+
log_startup_status(monitor_mode, websocket_port)
|
|
555
584
|
|
|
556
585
|
# Perform startup configuration check
|
|
557
586
|
_check_configuration_health(logger)
|
|
@@ -1102,7 +1131,7 @@ def _check_claude_json_memory(args, logger):
|
|
|
1102
1131
|
"""Check .claude.json file size and warn about memory issues.
|
|
1103
1132
|
|
|
1104
1133
|
WHY: Large .claude.json files (>500KB) cause significant memory issues when
|
|
1105
|
-
using --resume. Claude
|
|
1134
|
+
using --resume. Claude Code loads the entire conversation history into
|
|
1106
1135
|
memory, leading to 2GB+ memory consumption.
|
|
1107
1136
|
|
|
1108
1137
|
DESIGN DECISIONS:
|
|
@@ -1159,7 +1188,7 @@ def _check_claude_json_memory(args, logger):
|
|
|
1159
1188
|
f"\n⚠️ CRITICAL: Large .claude.json file detected ({format_size(file_size)})"
|
|
1160
1189
|
)
|
|
1161
1190
|
print(f" This WILL cause memory issues when using --resume")
|
|
1162
|
-
print(f" Claude
|
|
1191
|
+
print(f" Claude Code may consume 2GB+ of memory\n")
|
|
1163
1192
|
|
|
1164
1193
|
if not getattr(args, "force", False):
|
|
1165
1194
|
print(" Recommended actions:")
|
|
@@ -21,7 +21,7 @@ class RunConfigChecker:
|
|
|
21
21
|
"""Check .claude.json file size and warn about memory issues.
|
|
22
22
|
|
|
23
23
|
WHY: Large .claude.json files (>500KB) cause significant memory issues when
|
|
24
|
-
using --resume. Claude
|
|
24
|
+
using --resume. Claude Code loads the entire conversation history into
|
|
25
25
|
memory, leading to 2GB+ memory consumption.
|
|
26
26
|
"""
|
|
27
27
|
try:
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Manager parser module for claude-mpm CLI.
|
|
3
|
+
|
|
4
|
+
This module defines the argument parser for the agent-manager command,
|
|
5
|
+
which provides comprehensive agent lifecycle management capabilities.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def add_agent_manager_subparser(subparsers: argparse._SubParsersAction) -> None:
|
|
12
|
+
"""
|
|
13
|
+
Add the agent-manager subcommand to the parser.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
subparsers: The subparsers object to add to
|
|
17
|
+
"""
|
|
18
|
+
# Create the agent-manager parser
|
|
19
|
+
agent_manager_parser = subparsers.add_parser(
|
|
20
|
+
"agent-manager",
|
|
21
|
+
help="Manage agent creation, customization, and deployment",
|
|
22
|
+
description="Comprehensive agent lifecycle management for Claude MPM",
|
|
23
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
24
|
+
epilog="""
|
|
25
|
+
Examples:
|
|
26
|
+
claude-mpm agent-manager list # List all agents across tiers
|
|
27
|
+
claude-mpm agent-manager create # Interactive agent creation
|
|
28
|
+
claude-mpm agent-manager create --id my-agent # Create agent with ID
|
|
29
|
+
claude-mpm agent-manager variant --base research # Create research variant
|
|
30
|
+
claude-mpm agent-manager deploy --id my-agent --tier user # Deploy to user tier
|
|
31
|
+
claude-mpm agent-manager customize-pm --level project # Edit .claude-mpm/INSTRUCTIONS.md
|
|
32
|
+
claude-mpm agent-manager show --id engineer # Show agent details
|
|
33
|
+
claude-mpm agent-manager test --id my-agent # Test agent configuration
|
|
34
|
+
claude-mpm agent-manager templates # List available templates
|
|
35
|
+
"""
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Create subcommands for agent-manager
|
|
39
|
+
agent_subparsers = agent_manager_parser.add_subparsers(
|
|
40
|
+
dest="agent_manager_command",
|
|
41
|
+
help="Agent management operations",
|
|
42
|
+
metavar="OPERATION"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# List command
|
|
46
|
+
list_parser = agent_subparsers.add_parser(
|
|
47
|
+
"list",
|
|
48
|
+
help="List all agents across tiers with hierarchy"
|
|
49
|
+
)
|
|
50
|
+
list_parser.add_argument(
|
|
51
|
+
"--format",
|
|
52
|
+
choices=["text", "json", "yaml"],
|
|
53
|
+
default="text",
|
|
54
|
+
help="Output format (default: text)"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Create command
|
|
58
|
+
create_parser = agent_subparsers.add_parser(
|
|
59
|
+
"create",
|
|
60
|
+
help="Create a new agent (interactive or with arguments)"
|
|
61
|
+
)
|
|
62
|
+
create_parser.add_argument(
|
|
63
|
+
"--id",
|
|
64
|
+
dest="agent_id",
|
|
65
|
+
help="Agent ID (lowercase, hyphens only)"
|
|
66
|
+
)
|
|
67
|
+
create_parser.add_argument(
|
|
68
|
+
"--name",
|
|
69
|
+
help="Display name for the agent"
|
|
70
|
+
)
|
|
71
|
+
create_parser.add_argument(
|
|
72
|
+
"--description",
|
|
73
|
+
help="Agent purpose and capabilities"
|
|
74
|
+
)
|
|
75
|
+
create_parser.add_argument(
|
|
76
|
+
"--model",
|
|
77
|
+
choices=["sonnet", "opus", "haiku"],
|
|
78
|
+
default="sonnet",
|
|
79
|
+
help="LLM model to use (default: sonnet)"
|
|
80
|
+
)
|
|
81
|
+
create_parser.add_argument(
|
|
82
|
+
"--tool-choice",
|
|
83
|
+
choices=["auto", "required", "any", "none"],
|
|
84
|
+
default="auto",
|
|
85
|
+
help="Tool selection strategy (default: auto)"
|
|
86
|
+
)
|
|
87
|
+
create_parser.add_argument(
|
|
88
|
+
"--template",
|
|
89
|
+
help="Base template to extend from"
|
|
90
|
+
)
|
|
91
|
+
create_parser.add_argument(
|
|
92
|
+
"--format",
|
|
93
|
+
choices=["text", "json"],
|
|
94
|
+
default="text",
|
|
95
|
+
help="Output format (default: text)"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Variant command
|
|
99
|
+
variant_parser = agent_subparsers.add_parser(
|
|
100
|
+
"variant",
|
|
101
|
+
help="Create an agent variant based on existing agent"
|
|
102
|
+
)
|
|
103
|
+
variant_parser.add_argument(
|
|
104
|
+
"--base",
|
|
105
|
+
dest="base_agent",
|
|
106
|
+
required=True,
|
|
107
|
+
help="Base agent ID to create variant from"
|
|
108
|
+
)
|
|
109
|
+
variant_parser.add_argument(
|
|
110
|
+
"--id",
|
|
111
|
+
dest="variant_id",
|
|
112
|
+
required=True,
|
|
113
|
+
help="Variant agent ID"
|
|
114
|
+
)
|
|
115
|
+
variant_parser.add_argument(
|
|
116
|
+
"--name",
|
|
117
|
+
help="Display name for the variant"
|
|
118
|
+
)
|
|
119
|
+
variant_parser.add_argument(
|
|
120
|
+
"--model",
|
|
121
|
+
choices=["sonnet", "opus", "haiku"],
|
|
122
|
+
help="Override model for variant"
|
|
123
|
+
)
|
|
124
|
+
variant_parser.add_argument(
|
|
125
|
+
"--tool-choice",
|
|
126
|
+
choices=["auto", "required", "any", "none"],
|
|
127
|
+
help="Override tool choice for variant"
|
|
128
|
+
)
|
|
129
|
+
variant_parser.add_argument(
|
|
130
|
+
"--instructions",
|
|
131
|
+
help="Additional instructions to append for variant"
|
|
132
|
+
)
|
|
133
|
+
variant_parser.add_argument(
|
|
134
|
+
"--format",
|
|
135
|
+
choices=["text", "json"],
|
|
136
|
+
default="text",
|
|
137
|
+
help="Output format (default: text)"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Deploy command
|
|
141
|
+
deploy_parser = agent_subparsers.add_parser(
|
|
142
|
+
"deploy",
|
|
143
|
+
help="Deploy agent to specified tier"
|
|
144
|
+
)
|
|
145
|
+
deploy_parser.add_argument(
|
|
146
|
+
"--id",
|
|
147
|
+
dest="agent_id",
|
|
148
|
+
required=True,
|
|
149
|
+
help="Agent ID to deploy"
|
|
150
|
+
)
|
|
151
|
+
deploy_parser.add_argument(
|
|
152
|
+
"--tier",
|
|
153
|
+
choices=["project", "user"],
|
|
154
|
+
default="user",
|
|
155
|
+
help="Deployment tier (default: user)"
|
|
156
|
+
)
|
|
157
|
+
deploy_parser.add_argument(
|
|
158
|
+
"--force",
|
|
159
|
+
action="store_true",
|
|
160
|
+
help="Force deployment even if agent exists"
|
|
161
|
+
)
|
|
162
|
+
deploy_parser.add_argument(
|
|
163
|
+
"--format",
|
|
164
|
+
choices=["text", "json"],
|
|
165
|
+
default="text",
|
|
166
|
+
help="Output format (default: text)"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# Customize PM command
|
|
170
|
+
pm_parser = agent_subparsers.add_parser(
|
|
171
|
+
"customize-pm",
|
|
172
|
+
help="Customize PM instructions via .claude-mpm/INSTRUCTIONS.md"
|
|
173
|
+
)
|
|
174
|
+
pm_parser.add_argument(
|
|
175
|
+
"--level",
|
|
176
|
+
choices=["user", "project"],
|
|
177
|
+
default="user",
|
|
178
|
+
help="PM instruction level - user (~/.claude-mpm) or project (./.claude-mpm) (default: user)"
|
|
179
|
+
)
|
|
180
|
+
pm_parser.add_argument(
|
|
181
|
+
"--template",
|
|
182
|
+
help="Use predefined PM template"
|
|
183
|
+
)
|
|
184
|
+
pm_parser.add_argument(
|
|
185
|
+
"--patterns",
|
|
186
|
+
nargs="+",
|
|
187
|
+
help="Custom delegation patterns"
|
|
188
|
+
)
|
|
189
|
+
pm_parser.add_argument(
|
|
190
|
+
"--rules",
|
|
191
|
+
nargs="+",
|
|
192
|
+
help="Additional PM rules"
|
|
193
|
+
)
|
|
194
|
+
pm_parser.add_argument(
|
|
195
|
+
"--format",
|
|
196
|
+
choices=["text", "json"],
|
|
197
|
+
default="text",
|
|
198
|
+
help="Output format (default: text)"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# Show command
|
|
202
|
+
show_parser = agent_subparsers.add_parser(
|
|
203
|
+
"show",
|
|
204
|
+
help="Display detailed agent information"
|
|
205
|
+
)
|
|
206
|
+
show_parser.add_argument(
|
|
207
|
+
"--id",
|
|
208
|
+
dest="agent_id",
|
|
209
|
+
required=True,
|
|
210
|
+
help="Agent ID to show"
|
|
211
|
+
)
|
|
212
|
+
show_parser.add_argument(
|
|
213
|
+
"--format",
|
|
214
|
+
choices=["text", "json", "yaml"],
|
|
215
|
+
default="text",
|
|
216
|
+
help="Output format (default: text)"
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# Test command
|
|
220
|
+
test_parser = agent_subparsers.add_parser(
|
|
221
|
+
"test",
|
|
222
|
+
help="Test and validate agent configuration"
|
|
223
|
+
)
|
|
224
|
+
test_parser.add_argument(
|
|
225
|
+
"--id",
|
|
226
|
+
dest="agent_id",
|
|
227
|
+
required=True,
|
|
228
|
+
help="Agent ID to test"
|
|
229
|
+
)
|
|
230
|
+
test_parser.add_argument(
|
|
231
|
+
"--format",
|
|
232
|
+
choices=["text", "json"],
|
|
233
|
+
default="text",
|
|
234
|
+
help="Output format (default: text)"
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
# Templates command
|
|
238
|
+
templates_parser = agent_subparsers.add_parser(
|
|
239
|
+
"templates",
|
|
240
|
+
help="List available agent templates"
|
|
241
|
+
)
|
|
242
|
+
templates_parser.add_argument(
|
|
243
|
+
"--format",
|
|
244
|
+
choices=["text", "json", "yaml"],
|
|
245
|
+
default="text",
|
|
246
|
+
help="Output format (default: text)"
|
|
247
|
+
)
|