claude-mpm 4.0.22__py3-none-any.whl → 4.0.25__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/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +4 -1
- claude_mpm/agents/BASE_PM.md +3 -0
- claude_mpm/agents/templates/code_analyzer.json +3 -3
- claude_mpm/agents/templates/data_engineer.json +2 -2
- claude_mpm/agents/templates/documentation.json +36 -9
- claude_mpm/agents/templates/engineer.json +2 -2
- claude_mpm/agents/templates/ops.json +2 -2
- claude_mpm/agents/templates/qa.json +2 -2
- claude_mpm/agents/templates/refactoring_engineer.json +65 -43
- claude_mpm/agents/templates/security.json +2 -2
- claude_mpm/agents/templates/version_control.json +2 -2
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/commands/agents.py +453 -113
- claude_mpm/cli/commands/aggregate.py +107 -15
- claude_mpm/cli/commands/cleanup.py +142 -10
- claude_mpm/cli/commands/config.py +358 -224
- claude_mpm/cli/commands/info.py +184 -75
- claude_mpm/cli/commands/mcp_command_router.py +5 -76
- claude_mpm/cli/commands/mcp_install_commands.py +68 -36
- claude_mpm/cli/commands/mcp_server_commands.py +30 -37
- claude_mpm/cli/commands/memory.py +331 -61
- claude_mpm/cli/commands/monitor.py +101 -7
- claude_mpm/cli/commands/run.py +368 -8
- claude_mpm/cli/commands/tickets.py +206 -24
- claude_mpm/cli/parsers/mcp_parser.py +3 -0
- claude_mpm/cli/shared/__init__.py +40 -0
- claude_mpm/cli/shared/argument_patterns.py +212 -0
- claude_mpm/cli/shared/command_base.py +234 -0
- claude_mpm/cli/shared/error_handling.py +238 -0
- claude_mpm/cli/shared/output_formatters.py +231 -0
- claude_mpm/config/agent_config.py +29 -8
- claude_mpm/core/container.py +6 -4
- claude_mpm/core/framework_loader.py +32 -9
- claude_mpm/core/service_registry.py +4 -2
- claude_mpm/core/shared/__init__.py +17 -0
- claude_mpm/core/shared/config_loader.py +320 -0
- claude_mpm/core/shared/path_resolver.py +277 -0
- claude_mpm/core/shared/singleton_manager.py +208 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +4 -2
- claude_mpm/hooks/claude_hooks/response_tracking.py +14 -3
- claude_mpm/hooks/memory_integration_hook.py +11 -2
- claude_mpm/services/agents/deployment/agent_deployment.py +43 -23
- claude_mpm/services/agents/deployment/deployment_wrapper.py +71 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +1 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +43 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +4 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +1 -1
- claude_mpm/services/agents/loading/base_agent_manager.py +11 -3
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +14 -5
- claude_mpm/services/event_aggregator.py +4 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +89 -28
- claude_mpm/services/mcp_gateway/config/configuration.py +29 -0
- claude_mpm/services/mcp_gateway/registry/service_registry.py +22 -5
- claude_mpm/services/memory/builder.py +6 -1
- claude_mpm/services/response_tracker.py +3 -1
- claude_mpm/services/runner_configuration_service.py +15 -6
- claude_mpm/services/shared/__init__.py +20 -0
- claude_mpm/services/shared/async_service_base.py +219 -0
- claude_mpm/services/shared/config_service_base.py +292 -0
- claude_mpm/services/shared/lifecycle_service_base.py +317 -0
- claude_mpm/services/shared/manager_base.py +303 -0
- claude_mpm/services/shared/service_factory.py +308 -0
- {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.dist-info}/METADATA +19 -13
- {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.dist-info}/RECORD +70 -54
- {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.dist-info}/WHEEL +0 -0
- {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.0.22.dist-info → claude_mpm-4.0.25.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
|
|
3
1
|
"""
|
|
4
2
|
Configuration management commands for claude-mpm CLI.
|
|
5
3
|
|
|
@@ -8,13 +6,15 @@ the command line. This module provides commands for configuration validation,
|
|
|
8
6
|
viewing, and troubleshooting.
|
|
9
7
|
|
|
10
8
|
DESIGN DECISIONS:
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
9
|
+
- Use BaseCommand for consistent CLI patterns
|
|
10
|
+
- Leverage shared utilities for argument parsing and output formatting
|
|
11
|
+
- Provide clear, actionable output with standardized error handling
|
|
12
|
+
- Support multiple output formats (json, yaml, table, text)
|
|
15
13
|
"""
|
|
16
14
|
|
|
17
15
|
import json
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Dict, Any
|
|
18
18
|
|
|
19
19
|
import yaml
|
|
20
20
|
from rich.panel import Panel
|
|
@@ -22,273 +22,407 @@ from rich.syntax import Syntax
|
|
|
22
22
|
from rich.table import Table
|
|
23
23
|
|
|
24
24
|
from ...core.config import Config
|
|
25
|
-
from ...core.logger import get_logger
|
|
26
25
|
from ...utils.console import console
|
|
26
|
+
from ..shared import BaseCommand, CommandResult, add_config_arguments, add_output_arguments
|
|
27
27
|
|
|
28
|
-
logger = get_logger(__name__)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def manage_config(args) -> int:
|
|
32
|
-
"""Main entry point for configuration management commands.
|
|
33
|
-
|
|
34
|
-
WHY: This dispatcher handles different configuration subcommands,
|
|
35
|
-
routing to the appropriate handler based on user input.
|
|
36
|
-
|
|
37
|
-
Args:
|
|
38
|
-
args: Parsed command line arguments
|
|
39
28
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"""
|
|
43
|
-
if args.config_command == "validate":
|
|
44
|
-
return validate_config(args)
|
|
45
|
-
elif args.config_command == "view":
|
|
46
|
-
return view_config(args)
|
|
47
|
-
elif args.config_command == "status":
|
|
48
|
-
return show_config_status(args)
|
|
49
|
-
else:
|
|
50
|
-
console.print(f"[red]Unknown config command: {args.config_command}[/red]")
|
|
51
|
-
return 1
|
|
29
|
+
class ConfigCommand(BaseCommand):
|
|
30
|
+
"""Configuration management command using shared utilities."""
|
|
52
31
|
|
|
32
|
+
def __init__(self):
|
|
33
|
+
super().__init__("config")
|
|
53
34
|
|
|
54
|
-
def
|
|
55
|
-
|
|
35
|
+
def validate_args(self, args) -> str:
|
|
36
|
+
"""Validate command arguments."""
|
|
37
|
+
if not hasattr(args, 'config_command') or not args.config_command:
|
|
38
|
+
return "No config command specified"
|
|
56
39
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Args:
|
|
61
|
-
args: Command line arguments including config file path
|
|
62
|
-
|
|
63
|
-
Returns:
|
|
64
|
-
Exit code (0=valid, 1=errors, 2=warnings in strict mode)
|
|
65
|
-
"""
|
|
66
|
-
config_file = args.config_file or Path(".claude-mpm/configuration.yaml")
|
|
40
|
+
valid_commands = ["validate", "view", "status"]
|
|
41
|
+
if args.config_command not in valid_commands:
|
|
42
|
+
return f"Unknown config command: {args.config_command}. Valid commands: {', '.join(valid_commands)}"
|
|
67
43
|
|
|
68
|
-
|
|
44
|
+
return None
|
|
69
45
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
try:
|
|
79
|
-
# Try to load configuration
|
|
80
|
-
config = Config(config_file=config_file)
|
|
81
|
-
|
|
82
|
-
# Validate configuration
|
|
83
|
-
is_valid, errors, warnings = config.validate_configuration()
|
|
84
|
-
|
|
85
|
-
# Display results
|
|
86
|
-
if errors:
|
|
87
|
-
console.print("[bold red]ERRORS:[/bold red]")
|
|
88
|
-
for error in errors:
|
|
89
|
-
console.print(f" [red]✗ {error}[/red]")
|
|
90
|
-
|
|
91
|
-
if warnings:
|
|
92
|
-
console.print("\n[bold yellow]WARNINGS:[/bold yellow]")
|
|
93
|
-
for warning in warnings:
|
|
94
|
-
console.print(f" [yellow]⚠ {warning}[/yellow]")
|
|
95
|
-
|
|
96
|
-
# Show summary
|
|
97
|
-
if is_valid and not warnings:
|
|
98
|
-
console.print("\n[green]✓ Configuration is valid[/green]")
|
|
99
|
-
return 0
|
|
100
|
-
elif is_valid and warnings:
|
|
101
|
-
console.print(
|
|
102
|
-
f"\n[green]✓ Configuration is valid with {len(warnings)} warning(s)[/green]"
|
|
103
|
-
)
|
|
104
|
-
return 2 if args.strict else 0
|
|
46
|
+
def run(self, args) -> CommandResult:
|
|
47
|
+
"""Execute the configuration command."""
|
|
48
|
+
if args.config_command == "validate":
|
|
49
|
+
return self._validate_config(args)
|
|
50
|
+
elif args.config_command == "view":
|
|
51
|
+
return self._view_config(args)
|
|
52
|
+
elif args.config_command == "status":
|
|
53
|
+
return self._show_config_status(args)
|
|
105
54
|
else:
|
|
106
|
-
|
|
107
|
-
f"\n[red]✗ Configuration validation failed with {len(errors)} error(s)[/red]"
|
|
108
|
-
)
|
|
109
|
-
console.print(
|
|
110
|
-
"\n[yellow]Run 'python scripts/validate_configuration.py' for detailed analysis[/yellow]"
|
|
111
|
-
)
|
|
112
|
-
return 1
|
|
55
|
+
return CommandResult.error_result(f"Unknown config command: {args.config_command}")
|
|
113
56
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return 1
|
|
57
|
+
def _validate_config(self, args) -> CommandResult:
|
|
58
|
+
"""Validate configuration file."""
|
|
59
|
+
config_file = getattr(args, 'config_file', None) or Path(".claude-mpm/configuration.yaml")
|
|
118
60
|
|
|
61
|
+
# Check if file exists
|
|
62
|
+
if not config_file.exists():
|
|
63
|
+
error_msg = f"Configuration file not found: {config_file}"
|
|
64
|
+
suggestion = f"Create with: mkdir -p {config_file.parent} && touch {config_file}"
|
|
119
65
|
|
|
120
|
-
|
|
121
|
-
|
|
66
|
+
if getattr(args, 'format', 'text') in ['json', 'yaml']:
|
|
67
|
+
return CommandResult.error_result(
|
|
68
|
+
error_msg,
|
|
69
|
+
data={"suggestion": suggestion, "config_file": str(config_file)}
|
|
70
|
+
)
|
|
71
|
+
else:
|
|
72
|
+
console.print(f"[red]✗ {error_msg}[/red]")
|
|
73
|
+
console.print(f"[yellow]→ {suggestion}[/yellow]")
|
|
74
|
+
return CommandResult.error_result(error_msg)
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
# Load and validate configuration
|
|
78
|
+
if config_file != Path(".claude-mpm/configuration.yaml"):
|
|
79
|
+
# Use specific config file
|
|
80
|
+
config = Config(config_file=config_file)
|
|
81
|
+
else:
|
|
82
|
+
# Use default config
|
|
83
|
+
config = self.config
|
|
84
|
+
is_valid, errors, warnings = config.validate_configuration()
|
|
85
|
+
|
|
86
|
+
# Prepare result data
|
|
87
|
+
result_data = {
|
|
88
|
+
"config_file": str(config_file),
|
|
89
|
+
"valid": is_valid,
|
|
90
|
+
"errors": errors,
|
|
91
|
+
"warnings": warnings,
|
|
92
|
+
"error_count": len(errors),
|
|
93
|
+
"warning_count": len(warnings)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# Handle output format
|
|
97
|
+
output_format = getattr(args, 'format', 'text')
|
|
98
|
+
if output_format in ['json', 'yaml']:
|
|
99
|
+
if is_valid and not warnings:
|
|
100
|
+
return CommandResult.success_result("Configuration is valid", data=result_data)
|
|
101
|
+
elif is_valid and warnings:
|
|
102
|
+
message = f"Configuration is valid with {len(warnings)} warning(s)"
|
|
103
|
+
exit_code = 2 if getattr(args, 'strict', False) else 0
|
|
104
|
+
return CommandResult(success=True, exit_code=exit_code, message=message, data=result_data)
|
|
105
|
+
else:
|
|
106
|
+
return CommandResult.error_result(
|
|
107
|
+
f"Configuration validation failed with {len(errors)} error(s)",
|
|
108
|
+
data=result_data
|
|
109
|
+
)
|
|
110
|
+
else:
|
|
111
|
+
# Rich console output for text format
|
|
112
|
+
console.print(f"\n[bold blue]Validating configuration: {config_file}[/bold blue]\n")
|
|
113
|
+
|
|
114
|
+
if errors:
|
|
115
|
+
console.print("[bold red]ERRORS:[/bold red]")
|
|
116
|
+
for error in errors:
|
|
117
|
+
console.print(f" [red]✗ {error}[/red]")
|
|
118
|
+
|
|
119
|
+
if warnings:
|
|
120
|
+
console.print("\n[bold yellow]WARNINGS:[/bold yellow]")
|
|
121
|
+
for warning in warnings:
|
|
122
|
+
console.print(f" [yellow]⚠ {warning}[/yellow]")
|
|
123
|
+
|
|
124
|
+
# Show summary
|
|
125
|
+
if is_valid and not warnings:
|
|
126
|
+
console.print("\n[green]✓ Configuration is valid[/green]")
|
|
127
|
+
return CommandResult.success_result("Configuration is valid")
|
|
128
|
+
elif is_valid and warnings:
|
|
129
|
+
console.print(f"\n[green]✓ Configuration is valid with {len(warnings)} warning(s)[/green]")
|
|
130
|
+
exit_code = 2 if getattr(args, 'strict', False) else 0
|
|
131
|
+
return CommandResult(success=True, exit_code=exit_code, message="Configuration valid with warnings")
|
|
132
|
+
else:
|
|
133
|
+
console.print(f"\n[red]✗ Configuration validation failed with {len(errors)} error(s)[/red]")
|
|
134
|
+
console.print("\n[yellow]Run 'python scripts/validate_configuration.py' for detailed analysis[/yellow]")
|
|
135
|
+
return CommandResult.error_result("Configuration validation failed")
|
|
136
|
+
|
|
137
|
+
except Exception as e:
|
|
138
|
+
self.logger.error(f"Configuration validation error: {e}", exc_info=True)
|
|
139
|
+
|
|
140
|
+
if getattr(args, 'format', 'text') in ['json', 'yaml']:
|
|
141
|
+
return CommandResult.error_result(
|
|
142
|
+
f"Failed to validate configuration: {e}",
|
|
143
|
+
data={"config_file": str(config_file), "exception": str(e)}
|
|
144
|
+
)
|
|
145
|
+
else:
|
|
146
|
+
console.print(f"[red]Failed to validate configuration: {e}[/red]")
|
|
147
|
+
return CommandResult.error_result(f"Failed to validate configuration: {e}")
|
|
148
|
+
|
|
149
|
+
def _view_config(self, args) -> CommandResult:
|
|
150
|
+
"""View current configuration."""
|
|
151
|
+
try:
|
|
152
|
+
# Load configuration
|
|
153
|
+
config_file = getattr(args, 'config_file', None)
|
|
154
|
+
config = Config(config_file=config_file)
|
|
155
|
+
|
|
156
|
+
# Get configuration as dictionary
|
|
157
|
+
config_dict = config.to_dict()
|
|
158
|
+
|
|
159
|
+
# Filter by section if specified
|
|
160
|
+
section = getattr(args, 'section', None)
|
|
161
|
+
if section:
|
|
162
|
+
if section in config_dict:
|
|
163
|
+
config_dict = {section: config_dict[section]}
|
|
164
|
+
else:
|
|
165
|
+
error_msg = f"Section '{section}' not found in configuration"
|
|
166
|
+
available_sections = list(config_dict.keys())
|
|
167
|
+
|
|
168
|
+
if getattr(args, 'format', 'text') in ['json', 'yaml']:
|
|
169
|
+
return CommandResult.error_result(
|
|
170
|
+
error_msg,
|
|
171
|
+
data={"available_sections": available_sections}
|
|
172
|
+
)
|
|
173
|
+
else:
|
|
174
|
+
console.print(f"[red]{error_msg}[/red]")
|
|
175
|
+
console.print(f"[yellow]Available sections: {', '.join(available_sections)}[/yellow]")
|
|
176
|
+
return CommandResult.error_result(error_msg)
|
|
177
|
+
|
|
178
|
+
# Handle output format
|
|
179
|
+
output_format = getattr(args, 'format', 'text')
|
|
180
|
+
|
|
181
|
+
if output_format == "json":
|
|
182
|
+
if hasattr(args, 'output') and args.output:
|
|
183
|
+
# Use shared output handling
|
|
184
|
+
return CommandResult.success_result("Configuration retrieved", data=config_dict)
|
|
185
|
+
else:
|
|
186
|
+
# Direct console output with syntax highlighting
|
|
187
|
+
output = json.dumps(config_dict, indent=2)
|
|
188
|
+
syntax = Syntax(output, "json", theme="monokai", line_numbers=False)
|
|
189
|
+
console.print(syntax)
|
|
190
|
+
return CommandResult.success_result("Configuration displayed", data=config_dict)
|
|
191
|
+
|
|
192
|
+
elif output_format == "yaml":
|
|
193
|
+
if hasattr(args, 'output') and args.output:
|
|
194
|
+
# Use shared output handling
|
|
195
|
+
return CommandResult.success_result("Configuration retrieved", data=config_dict)
|
|
196
|
+
else:
|
|
197
|
+
# Direct console output with syntax highlighting
|
|
198
|
+
output = yaml.dump(config_dict, default_flow_style=False, sort_keys=False)
|
|
199
|
+
syntax = Syntax(output, "yaml", theme="monokai", line_numbers=False)
|
|
200
|
+
console.print(syntax)
|
|
201
|
+
return CommandResult.success_result("Configuration displayed")
|
|
202
|
+
|
|
203
|
+
elif output_format == "table":
|
|
204
|
+
self._display_config_table(config_dict)
|
|
205
|
+
return CommandResult.success_result("Configuration displayed")
|
|
206
|
+
|
|
207
|
+
else: # text format
|
|
208
|
+
self._display_config_table(config_dict)
|
|
209
|
+
return CommandResult.success_result("Configuration displayed")
|
|
210
|
+
|
|
211
|
+
except Exception as e:
|
|
212
|
+
self.logger.error(f"Configuration view error: {e}", exc_info=True)
|
|
213
|
+
|
|
214
|
+
if getattr(args, 'format', 'text') in ['json', 'yaml']:
|
|
215
|
+
return CommandResult.error_result(
|
|
216
|
+
f"Failed to view configuration: {e}",
|
|
217
|
+
data={"exception": str(e)}
|
|
218
|
+
)
|
|
219
|
+
else:
|
|
220
|
+
console.print(f"[red]Failed to view configuration: {e}[/red]")
|
|
221
|
+
return CommandResult.error_result(f"Failed to view configuration: {e}")
|
|
122
222
|
|
|
123
|
-
|
|
124
|
-
|
|
223
|
+
def _show_config_status(self, args) -> CommandResult:
|
|
224
|
+
"""Show configuration status and health."""
|
|
225
|
+
try:
|
|
226
|
+
# Load configuration
|
|
227
|
+
config_file = getattr(args, 'config_file', None)
|
|
228
|
+
config = Config(config_file=config_file)
|
|
125
229
|
|
|
126
|
-
|
|
127
|
-
|
|
230
|
+
# Get status
|
|
231
|
+
status = config.get_configuration_status()
|
|
128
232
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
"""
|
|
132
|
-
try:
|
|
133
|
-
# Load configuration
|
|
134
|
-
config_file = args.config_file
|
|
135
|
-
config = Config(config_file=config_file)
|
|
136
|
-
|
|
137
|
-
# Get configuration as dictionary
|
|
138
|
-
config_dict = config.to_dict()
|
|
139
|
-
|
|
140
|
-
# Filter by section if specified
|
|
141
|
-
if args.section:
|
|
142
|
-
if args.section in config_dict:
|
|
143
|
-
config_dict = {args.section: config_dict[args.section]}
|
|
144
|
-
else:
|
|
145
|
-
console.print(
|
|
146
|
-
f"[red]Section '{args.section}' not found in configuration[/red]"
|
|
147
|
-
)
|
|
148
|
-
return 1
|
|
233
|
+
# Handle output format
|
|
234
|
+
output_format = getattr(args, 'format', 'text')
|
|
149
235
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
syntax = Syntax(output, "json", theme="monokai", line_numbers=False)
|
|
154
|
-
console.print(syntax)
|
|
155
|
-
elif args.format == "yaml":
|
|
156
|
-
output = yaml.dump(config_dict, default_flow_style=False, sort_keys=False)
|
|
157
|
-
syntax = Syntax(output, "yaml", theme="monokai", line_numbers=False)
|
|
158
|
-
console.print(syntax)
|
|
159
|
-
else: # table format
|
|
160
|
-
display_config_table(config_dict)
|
|
236
|
+
if output_format in ['json', 'yaml']:
|
|
237
|
+
# Structured output
|
|
238
|
+
result_data = status.copy()
|
|
161
239
|
|
|
162
|
-
|
|
240
|
+
# Add response logging details if requested
|
|
241
|
+
if getattr(args, 'check_response_logging', False):
|
|
242
|
+
result_data['response_logging_config'] = config.get("response_logging", {})
|
|
163
243
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
244
|
+
if status["valid"]:
|
|
245
|
+
return CommandResult.success_result("Configuration status retrieved", data=result_data)
|
|
246
|
+
else:
|
|
247
|
+
return CommandResult.error_result("Configuration has issues", data=result_data)
|
|
168
248
|
|
|
249
|
+
else:
|
|
250
|
+
# Rich console output for text format
|
|
251
|
+
self._display_status_panel(status)
|
|
169
252
|
|
|
170
|
-
|
|
171
|
-
|
|
253
|
+
# Show detailed errors/warnings if verbose
|
|
254
|
+
if getattr(args, 'verbose', False):
|
|
255
|
+
self._display_detailed_status(status)
|
|
172
256
|
|
|
173
|
-
|
|
174
|
-
|
|
257
|
+
# Check response logging specifically
|
|
258
|
+
if getattr(args, 'check_response_logging', False):
|
|
259
|
+
self._display_response_logging_config(config)
|
|
175
260
|
|
|
176
|
-
|
|
177
|
-
args: Command line arguments
|
|
261
|
+
return CommandResult.success_result("Configuration status displayed") if status["valid"] else CommandResult.error_result("Configuration has issues")
|
|
178
262
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
"""
|
|
182
|
-
try:
|
|
183
|
-
# Load configuration
|
|
184
|
-
config = Config(config_file=args.config_file)
|
|
263
|
+
except Exception as e:
|
|
264
|
+
self.logger.error(f"Configuration status error: {e}", exc_info=True)
|
|
185
265
|
|
|
186
|
-
|
|
187
|
-
|
|
266
|
+
if getattr(args, 'format', 'text') in ['json', 'yaml']:
|
|
267
|
+
return CommandResult.error_result(
|
|
268
|
+
f"Failed to get configuration status: {e}",
|
|
269
|
+
data={"exception": str(e)}
|
|
270
|
+
)
|
|
271
|
+
else:
|
|
272
|
+
console.print(f"[red]Failed to get configuration status: {e}[/red]")
|
|
273
|
+
return CommandResult.error_result(f"Failed to get configuration status: {e}")
|
|
188
274
|
|
|
189
|
-
|
|
275
|
+
def _display_status_panel(self, status: Dict[str, Any]) -> None:
|
|
276
|
+
"""Display configuration status panel."""
|
|
190
277
|
panel_content = []
|
|
191
278
|
|
|
192
279
|
# Basic info
|
|
193
280
|
panel_content.append(f"[bold]Configuration Status[/bold]")
|
|
194
|
-
panel_content.append(f"Valid: {'✓' if status
|
|
281
|
+
panel_content.append(f"Valid: {'✓' if status.get('valid', False) else '✗'}")
|
|
195
282
|
panel_content.append(f"Loaded from: {status.get('loaded_from', 'defaults')}")
|
|
196
|
-
panel_content.append(f"Total keys: {status
|
|
197
|
-
|
|
198
|
-
# Feature status
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
283
|
+
panel_content.append(f"Total keys: {status.get('key_count', 'unknown')}")
|
|
284
|
+
|
|
285
|
+
# Feature status (only if available)
|
|
286
|
+
if 'response_logging_enabled' in status or 'memory_enabled' in status:
|
|
287
|
+
panel_content.append("\n[bold]Features:[/bold]")
|
|
288
|
+
if 'response_logging_enabled' in status:
|
|
289
|
+
panel_content.append(
|
|
290
|
+
f"Response Logging: {'✓ Enabled' if status['response_logging_enabled'] else '✗ Disabled'}"
|
|
291
|
+
)
|
|
292
|
+
if 'memory_enabled' in status:
|
|
293
|
+
panel_content.append(
|
|
294
|
+
f"Memory System: {'✓ Enabled' if status['memory_enabled'] else '✗ Disabled'}"
|
|
295
|
+
)
|
|
206
296
|
|
|
207
|
-
# Errors and warnings
|
|
208
|
-
if status
|
|
297
|
+
# Errors and warnings (only if available)
|
|
298
|
+
if status.get("errors"):
|
|
209
299
|
panel_content.append(f"\n[red]Errors: {len(status['errors'])}[/red]")
|
|
210
|
-
if status
|
|
211
|
-
panel_content.append(
|
|
212
|
-
f"\n[yellow]Warnings: {len(status['warnings'])}[/yellow]"
|
|
213
|
-
)
|
|
300
|
+
if status.get("warnings"):
|
|
301
|
+
panel_content.append(f"\n[yellow]Warnings: {len(status['warnings'])}[/yellow]")
|
|
214
302
|
|
|
215
303
|
# Display panel
|
|
216
304
|
panel = Panel(
|
|
217
305
|
"\n".join(panel_content),
|
|
218
306
|
title="Configuration Status",
|
|
219
|
-
border_style="green" if status
|
|
307
|
+
border_style="green" if status.get("valid", False) else "red",
|
|
220
308
|
)
|
|
221
309
|
console.print(panel)
|
|
222
310
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
311
|
+
def _display_detailed_status(self, status: Dict[str, Any]) -> None:
|
|
312
|
+
"""Display detailed errors and warnings."""
|
|
313
|
+
if status.get("errors"):
|
|
314
|
+
console.print("\n[bold red]Errors:[/bold red]")
|
|
315
|
+
for error in status["errors"]:
|
|
316
|
+
console.print(f" [red]• {error}[/red]")
|
|
317
|
+
|
|
318
|
+
if status.get("warnings"):
|
|
319
|
+
console.print("\n[bold yellow]Warnings:[/bold yellow]")
|
|
320
|
+
for warning in status["warnings"]:
|
|
321
|
+
console.print(f" [yellow]• {warning}[/yellow]")
|
|
322
|
+
|
|
323
|
+
def _display_response_logging_config(self, config: Config) -> None:
|
|
324
|
+
"""Display response logging configuration table."""
|
|
325
|
+
console.print("\n[bold]Response Logging Configuration:[/bold]")
|
|
326
|
+
rl_config = config.get("response_logging", {})
|
|
327
|
+
|
|
328
|
+
table = Table(show_header=True)
|
|
329
|
+
table.add_column("Setting", style="cyan")
|
|
330
|
+
table.add_column("Value", style="white")
|
|
331
|
+
|
|
332
|
+
table.add_row("Enabled", str(rl_config.get("enabled", False)))
|
|
333
|
+
table.add_row("Format", rl_config.get("format", "json"))
|
|
334
|
+
table.add_row("Use Async", str(rl_config.get("use_async", True)))
|
|
335
|
+
table.add_row(
|
|
336
|
+
"Session Directory",
|
|
337
|
+
rl_config.get("session_directory", ".claude-mpm/responses"),
|
|
338
|
+
)
|
|
339
|
+
table.add_row(
|
|
340
|
+
"Compression", str(rl_config.get("enable_compression", False))
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
console.print(table)
|
|
344
|
+
|
|
345
|
+
def _display_config_table(self, config_dict: dict, prefix: str = "") -> None:
|
|
346
|
+
"""Display configuration as a formatted table."""
|
|
347
|
+
table = Table(show_header=True, title="Configuration")
|
|
348
|
+
table.add_column("Key", style="cyan", no_wrap=True)
|
|
349
|
+
table.add_column("Value", style="white")
|
|
350
|
+
table.add_column("Type", style="dim")
|
|
351
|
+
|
|
352
|
+
def add_items(d: dict, prefix: str = ""):
|
|
353
|
+
for key, value in d.items():
|
|
354
|
+
full_key = f"{prefix}.{key}" if prefix else key
|
|
355
|
+
|
|
356
|
+
if isinstance(value, dict) and value:
|
|
357
|
+
# Add nested items
|
|
358
|
+
add_items(value, full_key)
|
|
359
|
+
else:
|
|
360
|
+
# Add leaf value
|
|
361
|
+
value_str = str(value)
|
|
362
|
+
if len(value_str) > 50:
|
|
363
|
+
value_str = value_str[:47] + "..."
|
|
364
|
+
|
|
365
|
+
type_str = type(value).__name__
|
|
366
|
+
table.add_row(full_key, value_str, type_str)
|
|
367
|
+
|
|
368
|
+
add_items(config_dict)
|
|
369
|
+
console.print(table)
|
|
370
|
+
|
|
371
|
+
def _flatten_config(self, config: dict, prefix: str = "") -> dict:
|
|
372
|
+
"""Flatten nested configuration dictionary."""
|
|
373
|
+
flattened = {}
|
|
374
|
+
|
|
375
|
+
for key, value in config.items():
|
|
376
|
+
new_key = f"{prefix}.{key}" if prefix else key
|
|
377
|
+
|
|
378
|
+
if isinstance(value, dict):
|
|
379
|
+
flattened.update(self._flatten_config(value, new_key))
|
|
380
|
+
elif isinstance(value, list):
|
|
381
|
+
flattened[new_key] = str(value)
|
|
382
|
+
else:
|
|
383
|
+
flattened[new_key] = value
|
|
229
384
|
|
|
230
|
-
|
|
231
|
-
console.print("\n[bold yellow]Warnings:[/bold yellow]")
|
|
232
|
-
for warning in status["warnings"]:
|
|
233
|
-
console.print(f" [yellow]• {warning}[/yellow]")
|
|
385
|
+
return flattened
|
|
234
386
|
|
|
235
|
-
# Check response logging specifically
|
|
236
|
-
if args.check_response_logging:
|
|
237
|
-
console.print("\n[bold]Response Logging Configuration:[/bold]")
|
|
238
|
-
rl_config = config.get("response_logging", {})
|
|
239
387
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
table.add_column("Value", style="white")
|
|
388
|
+
def manage_config(args) -> int:
|
|
389
|
+
"""Main entry point for configuration management commands.
|
|
243
390
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
"Session Directory",
|
|
249
|
-
rl_config.get("session_directory", ".claude-mpm/responses"),
|
|
250
|
-
)
|
|
251
|
-
table.add_row(
|
|
252
|
-
"Compression", str(rl_config.get("enable_compression", False))
|
|
253
|
-
)
|
|
391
|
+
This function maintains backward compatibility while using the new BaseCommand pattern.
|
|
392
|
+
"""
|
|
393
|
+
command = ConfigCommand()
|
|
394
|
+
result = command.execute(args)
|
|
254
395
|
|
|
255
|
-
|
|
396
|
+
# Print result if not already handled
|
|
397
|
+
if hasattr(args, 'format') and args.format in ['json', 'yaml']:
|
|
398
|
+
command.print_result(result, args)
|
|
256
399
|
|
|
257
|
-
|
|
400
|
+
return result.exit_code
|
|
258
401
|
|
|
259
|
-
except Exception as e:
|
|
260
|
-
console.print(f"[red]Failed to get configuration status: {e}[/red]")
|
|
261
|
-
logger.exception("Configuration status error")
|
|
262
|
-
return 1
|
|
263
402
|
|
|
403
|
+
# Legacy function for backward compatibility
|
|
404
|
+
def validate_config(args) -> int:
|
|
405
|
+
"""Legacy function for backward compatibility."""
|
|
406
|
+
command = ConfigCommand()
|
|
407
|
+
result = command.execute(args)
|
|
408
|
+
return result.exit_code
|
|
264
409
|
|
|
265
|
-
def display_config_table(config_dict: dict, prefix: str = "") -> None:
|
|
266
|
-
"""Display configuration as a formatted table.
|
|
267
410
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if isinstance(value, dict) and value:
|
|
282
|
-
# Add nested items
|
|
283
|
-
add_items(value, full_key)
|
|
284
|
-
else:
|
|
285
|
-
# Add leaf value
|
|
286
|
-
value_str = str(value)
|
|
287
|
-
if len(value_str) > 50:
|
|
288
|
-
value_str = value_str[:47] + "..."
|
|
411
|
+
def view_config(args) -> int:
|
|
412
|
+
"""Legacy function for backward compatibility."""
|
|
413
|
+
command = ConfigCommand()
|
|
414
|
+
result = command.execute(args)
|
|
415
|
+
return result.exit_code
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def show_config_status(args) -> int:
|
|
419
|
+
"""Legacy function for backward compatibility."""
|
|
420
|
+
command = ConfigCommand()
|
|
421
|
+
result = command.execute(args)
|
|
422
|
+
return result.exit_code
|
|
289
423
|
|
|
290
|
-
type_str = type(value).__name__
|
|
291
|
-
table.add_row(full_key, value_str, type_str)
|
|
292
424
|
|
|
293
|
-
|
|
294
|
-
|
|
425
|
+
def display_config_table(config_dict: dict, prefix: str = "") -> None:
|
|
426
|
+
"""Legacy function for backward compatibility."""
|
|
427
|
+
command = ConfigCommand()
|
|
428
|
+
command._display_config_table(config_dict, prefix)
|