claude-mpm 4.3.11__py3-none-any.whl → 4.3.13__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/VERSION +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +390 -28
- claude_mpm/agents/templates/data_engineer.json +39 -14
- claude_mpm/agents/templates/research.json +20 -8
- claude_mpm/agents/templates/web_qa.json +25 -10
- claude_mpm/cli/__init__.py +1 -0
- claude_mpm/cli/commands/agent_manager.py +3 -3
- claude_mpm/cli/commands/agents.py +2 -2
- claude_mpm/cli/commands/aggregate.py +1 -1
- claude_mpm/cli/commands/config.py +2 -2
- claude_mpm/cli/commands/configure.py +5 -5
- claude_mpm/cli/commands/configure_tui.py +7 -7
- claude_mpm/cli/commands/dashboard.py +1 -1
- claude_mpm/cli/commands/debug.py +5 -5
- claude_mpm/cli/commands/mcp.py +1 -1
- claude_mpm/cli/commands/mcp_command_router.py +12 -1
- claude_mpm/cli/commands/mcp_config.py +154 -0
- claude_mpm/cli/commands/mcp_external_commands.py +249 -0
- claude_mpm/cli/commands/mcp_install_commands.py +93 -24
- claude_mpm/cli/commands/mcp_setup_external.py +870 -0
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init_handler.py +1 -1
- claude_mpm/cli/commands/run.py +114 -0
- claude_mpm/cli/commands/search.py +292 -0
- claude_mpm/cli/interactive/agent_wizard.py +2 -2
- claude_mpm/cli/parsers/base_parser.py +13 -0
- claude_mpm/cli/parsers/mcp_parser.py +15 -0
- claude_mpm/cli/parsers/run_parser.py +5 -0
- claude_mpm/cli/parsers/search_parser.py +245 -0
- claude_mpm/cli/startup_logging.py +3 -5
- claude_mpm/cli/utils.py +1 -1
- claude_mpm/constants.py +1 -0
- claude_mpm/core/agent_registry.py +12 -8
- claude_mpm/core/agent_session_manager.py +8 -8
- claude_mpm/core/api_validator.py +4 -4
- claude_mpm/core/base_service.py +10 -10
- claude_mpm/core/cache.py +5 -5
- claude_mpm/core/config_constants.py +1 -1
- claude_mpm/core/container.py +1 -1
- claude_mpm/core/error_handler.py +2 -2
- claude_mpm/core/file_utils.py +1 -1
- claude_mpm/core/framework_loader.py +3 -3
- claude_mpm/core/hook_manager.py +8 -6
- claude_mpm/core/instruction_reinforcement_hook.py +2 -2
- claude_mpm/core/interactive_session.py +1 -1
- claude_mpm/core/lazy.py +3 -3
- claude_mpm/core/log_manager.py +16 -12
- claude_mpm/core/logger.py +16 -11
- claude_mpm/core/logging_config.py +4 -2
- claude_mpm/core/oneshot_session.py +1 -1
- claude_mpm/core/optimized_agent_loader.py +6 -6
- claude_mpm/core/output_style_manager.py +1 -1
- claude_mpm/core/pm_hook_interceptor.py +3 -3
- claude_mpm/core/service_registry.py +1 -1
- claude_mpm/core/session_manager.py +11 -9
- claude_mpm/core/socketio_pool.py +13 -13
- claude_mpm/core/types.py +2 -2
- claude_mpm/core/unified_agent_registry.py +9 -2
- claude_mpm/core/unified_paths.py +1 -1
- claude_mpm/dashboard/analysis_runner.py +4 -4
- claude_mpm/dashboard/api/simple_directory.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +4 -2
- claude_mpm/hooks/base_hook.py +2 -2
- claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
- claude_mpm/hooks/claude_hooks/event_handlers.py +12 -12
- claude_mpm/hooks/claude_hooks/hook_handler.py +4 -4
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +3 -3
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +15 -14
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +4 -4
- claude_mpm/hooks/claude_hooks/installer.py +3 -3
- claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
- claude_mpm/hooks/claude_hooks/response_tracking.py +3 -3
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +5 -5
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +3 -3
- claude_mpm/hooks/claude_hooks/services/state_manager.py +8 -7
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
- claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/hooks/tool_call_interceptor.py +2 -2
- claude_mpm/models/agent_session.py +5 -5
- claude_mpm/services/__init__.py +1 -1
- claude_mpm/services/agent_capabilities_service.py +1 -1
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/deployment/agent_deployment.py +29 -13
- claude_mpm/services/agents/deployment/agent_discovery_service.py +22 -6
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +7 -5
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +3 -1
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
- claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_template_builder.py +1 -1
- claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +2 -3
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +6 -4
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +5 -3
- claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
- claude_mpm/services/agents/local_template_manager.py +6 -6
- claude_mpm/services/agents/management/agent_management_service.py +3 -3
- claude_mpm/services/agents/memory/content_manager.py +3 -3
- claude_mpm/services/agents/memory/memory_format_service.py +2 -2
- claude_mpm/services/agents/memory/template_generator.py +3 -3
- claude_mpm/services/agents/registry/__init__.py +1 -1
- claude_mpm/services/agents/registry/modification_tracker.py +2 -2
- claude_mpm/services/async_session_logger.py +3 -3
- claude_mpm/services/claude_session_logger.py +4 -4
- claude_mpm/services/cli/agent_cleanup_service.py +5 -0
- claude_mpm/services/cli/agent_listing_service.py +1 -1
- claude_mpm/services/cli/agent_validation_service.py +1 -0
- claude_mpm/services/cli/memory_crud_service.py +11 -6
- claude_mpm/services/cli/memory_output_formatter.py +1 -1
- claude_mpm/services/cli/session_manager.py +15 -11
- claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
- claude_mpm/services/core/memory_manager.py +81 -23
- claude_mpm/services/core/path_resolver.py +2 -2
- claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
- claude_mpm/services/event_aggregator.py +4 -2
- claude_mpm/services/event_bus/direct_relay.py +5 -3
- claude_mpm/services/event_bus/event_bus.py +3 -3
- claude_mpm/services/event_bus/relay.py +6 -4
- claude_mpm/services/events/consumers/dead_letter.py +5 -3
- claude_mpm/services/events/core.py +3 -3
- claude_mpm/services/events/producers/hook.py +6 -6
- claude_mpm/services/events/producers/system.py +8 -8
- claude_mpm/services/exceptions.py +5 -5
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
- claude_mpm/services/hook_installer_service.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +6 -4
- claude_mpm/services/infrastructure/daemon_manager.py +2 -2
- claude_mpm/services/infrastructure/logging.py +2 -2
- claude_mpm/services/mcp_config_manager.py +439 -0
- claude_mpm/services/mcp_gateway/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/auto_configure.py +3 -3
- claude_mpm/services/mcp_gateway/config/config_loader.py +1 -1
- claude_mpm/services/mcp_gateway/config/configuration.py +18 -1
- claude_mpm/services/mcp_gateway/core/base.py +2 -2
- claude_mpm/services/mcp_gateway/main.py +52 -0
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +10 -8
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
- claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -3
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +7 -5
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +443 -0
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +5 -5
- claude_mpm/services/mcp_gateway/tools/hello_world.py +9 -9
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +16 -16
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +17 -17
- claude_mpm/services/memory/builder.py +7 -5
- claude_mpm/services/memory/indexed_memory.py +4 -4
- claude_mpm/services/memory/optimizer.py +6 -6
- claude_mpm/services/memory/router.py +3 -3
- claude_mpm/services/monitor/daemon.py +1 -1
- claude_mpm/services/monitor/daemon_manager.py +6 -6
- claude_mpm/services/monitor/event_emitter.py +2 -2
- claude_mpm/services/monitor/handlers/file.py +1 -1
- claude_mpm/services/monitor/management/lifecycle.py +1 -1
- claude_mpm/services/monitor/server.py +4 -4
- claude_mpm/services/monitor_build_service.py +2 -2
- claude_mpm/services/port_manager.py +2 -2
- claude_mpm/services/response_tracker.py +2 -2
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/socketio/client_proxy.py +2 -2
- claude_mpm/services/socketio/dashboard_server.py +4 -3
- claude_mpm/services/socketio/event_normalizer.py +12 -8
- claude_mpm/services/socketio/handlers/base.py +2 -2
- claude_mpm/services/socketio/handlers/connection.py +10 -10
- claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
- claude_mpm/services/socketio/handlers/file.py +1 -1
- claude_mpm/services/socketio/handlers/git.py +1 -1
- claude_mpm/services/socketio/handlers/hook.py +16 -15
- claude_mpm/services/socketio/migration_utils.py +1 -1
- claude_mpm/services/socketio/monitor_client.py +5 -5
- claude_mpm/services/socketio/server/broadcaster.py +9 -7
- claude_mpm/services/socketio/server/connection_manager.py +2 -2
- claude_mpm/services/socketio/server/core.py +7 -5
- claude_mpm/services/socketio/server/eventbus_integration.py +18 -11
- claude_mpm/services/socketio/server/main.py +13 -13
- claude_mpm/services/socketio_client_manager.py +4 -4
- claude_mpm/services/system_instructions_service.py +2 -2
- claude_mpm/services/ticket_services/validation_service.py +1 -1
- claude_mpm/services/utility_service.py +5 -2
- claude_mpm/services/version_control/branch_strategy.py +2 -2
- claude_mpm/services/version_control/git_operations.py +22 -20
- claude_mpm/services/version_control/semantic_versioning.py +3 -3
- claude_mpm/services/version_control/version_parser.py +7 -5
- claude_mpm/services/visualization/mermaid_generator.py +1 -1
- claude_mpm/storage/state_storage.py +1 -1
- claude_mpm/tools/code_tree_analyzer.py +19 -18
- claude_mpm/tools/code_tree_builder.py +2 -2
- claude_mpm/tools/code_tree_events.py +10 -8
- claude_mpm/tools/socketio_debug.py +3 -3
- claude_mpm/utils/agent_dependency_loader.py +2 -2
- claude_mpm/utils/dependency_strategies.py +8 -3
- claude_mpm/utils/environment_context.py +2 -2
- claude_mpm/utils/error_handler.py +2 -2
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/imports.py +1 -1
- claude_mpm/utils/log_cleanup.py +21 -7
- claude_mpm/validation/agent_validator.py +2 -2
- {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/METADATA +4 -1
- {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/RECORD +207 -200
- {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/WHEEL +0 -0
- {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Search command parser for mcp-vector-search integration.
|
|
3
|
+
|
|
4
|
+
This module provides argument parsing for the /mpm-search command.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def add_search_subparser(
|
|
12
|
+
subparsers: argparse._SubParsersAction,
|
|
13
|
+
) -> argparse.ArgumentParser:
|
|
14
|
+
"""
|
|
15
|
+
Add the search command parser.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
subparsers: The subparsers action to add the search parser to.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
The created search parser.
|
|
22
|
+
"""
|
|
23
|
+
search_parser = subparsers.add_parser(
|
|
24
|
+
"mpm-search",
|
|
25
|
+
aliases=["search"],
|
|
26
|
+
help="Search codebase using semantic search",
|
|
27
|
+
description=(
|
|
28
|
+
"Search the codebase using semantic search powered by mcp-vector-search. "
|
|
29
|
+
"Can search by query, find similar code, search by context, or manage the search index."
|
|
30
|
+
),
|
|
31
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
32
|
+
epilog="""
|
|
33
|
+
Examples:
|
|
34
|
+
# Search for code by query
|
|
35
|
+
claude-mpm mpm-search "authentication logic"
|
|
36
|
+
|
|
37
|
+
# Find code similar to a file
|
|
38
|
+
claude-mpm mpm-search --similar src/auth.py
|
|
39
|
+
|
|
40
|
+
# Search by contextual description
|
|
41
|
+
claude-mpm mpm-search --context "find all API endpoints"
|
|
42
|
+
|
|
43
|
+
# Index the project (required before searching)
|
|
44
|
+
claude-mpm mpm-search --index
|
|
45
|
+
|
|
46
|
+
# Force reindex the project
|
|
47
|
+
claude-mpm mpm-search --index --force
|
|
48
|
+
|
|
49
|
+
# Check index status
|
|
50
|
+
claude-mpm mpm-search --status
|
|
51
|
+
|
|
52
|
+
# Search with filters
|
|
53
|
+
claude-mpm mpm-search "database" --language python --limit 20
|
|
54
|
+
|
|
55
|
+
# Search with multiple file extensions
|
|
56
|
+
claude-mpm mpm-search "test" --extensions .py --extensions .js
|
|
57
|
+
|
|
58
|
+
# Find similar code to a specific function
|
|
59
|
+
claude-mpm mpm-search --similar src/auth.py --function authenticate_user
|
|
60
|
+
|
|
61
|
+
# Search with context and focus areas
|
|
62
|
+
claude-mpm mpm-search --context "security vulnerabilities" --focus authentication --focus encryption
|
|
63
|
+
|
|
64
|
+
# Output as JSON for processing
|
|
65
|
+
claude-mpm mpm-search "api" --json
|
|
66
|
+
""",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Primary search modes (mutually exclusive)
|
|
70
|
+
search_mode = search_parser.add_mutually_exclusive_group()
|
|
71
|
+
|
|
72
|
+
search_mode.add_argument(
|
|
73
|
+
"query",
|
|
74
|
+
nargs="?",
|
|
75
|
+
help="Search query for semantic code search",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
search_mode.add_argument(
|
|
79
|
+
"--similar",
|
|
80
|
+
"-s",
|
|
81
|
+
metavar="FILE",
|
|
82
|
+
help="Find code similar to the specified file",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
search_mode.add_argument(
|
|
86
|
+
"--context",
|
|
87
|
+
"-c",
|
|
88
|
+
metavar="DESCRIPTION",
|
|
89
|
+
help="Search by contextual description of what you're looking for",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Index management options
|
|
93
|
+
search_parser.add_argument(
|
|
94
|
+
"--index",
|
|
95
|
+
action="store_true",
|
|
96
|
+
help="Index or reindex the project codebase",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
search_parser.add_argument(
|
|
100
|
+
"--status",
|
|
101
|
+
action="store_true",
|
|
102
|
+
help="Check project indexing status and statistics",
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Search filters and options
|
|
106
|
+
search_parser.add_argument(
|
|
107
|
+
"--limit",
|
|
108
|
+
"-l",
|
|
109
|
+
type=int,
|
|
110
|
+
default=10,
|
|
111
|
+
metavar="N",
|
|
112
|
+
help="Maximum number of results to return (default: 10, max: 50)",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
search_parser.add_argument(
|
|
116
|
+
"--threshold",
|
|
117
|
+
"-t",
|
|
118
|
+
type=float,
|
|
119
|
+
default=0.3,
|
|
120
|
+
metavar="SCORE",
|
|
121
|
+
help="Similarity threshold between 0.0 and 1.0 (default: 0.3)",
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
search_parser.add_argument(
|
|
125
|
+
"--language",
|
|
126
|
+
metavar="LANG",
|
|
127
|
+
help="Filter by programming language (e.g., python, javascript, go)",
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
search_parser.add_argument(
|
|
131
|
+
"--extensions",
|
|
132
|
+
action="append",
|
|
133
|
+
metavar="EXT",
|
|
134
|
+
help="Filter by file extensions (e.g., .py, .js). Can be specified multiple times",
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Options for --similar mode
|
|
138
|
+
search_parser.add_argument(
|
|
139
|
+
"--function",
|
|
140
|
+
"-f",
|
|
141
|
+
metavar="NAME",
|
|
142
|
+
help="Function name within the file (used with --similar)",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Options for --context mode
|
|
146
|
+
search_parser.add_argument(
|
|
147
|
+
"--focus",
|
|
148
|
+
action="append",
|
|
149
|
+
metavar="AREA",
|
|
150
|
+
help="Focus areas for contextual search (e.g., security, performance). Can be specified multiple times",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# Options for --index mode
|
|
154
|
+
search_parser.add_argument(
|
|
155
|
+
"--force",
|
|
156
|
+
action="store_true",
|
|
157
|
+
help="Force reindexing even if index already exists (used with --index)",
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Output options
|
|
161
|
+
search_parser.add_argument(
|
|
162
|
+
"--json",
|
|
163
|
+
action="store_true",
|
|
164
|
+
dest="output_json",
|
|
165
|
+
help="Output results as JSON instead of formatted text",
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# Additional filters
|
|
169
|
+
search_parser.add_argument(
|
|
170
|
+
"--class",
|
|
171
|
+
dest="class_name",
|
|
172
|
+
metavar="NAME",
|
|
173
|
+
help="Filter by class name",
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
search_parser.add_argument(
|
|
177
|
+
"--files",
|
|
178
|
+
metavar="PATTERN",
|
|
179
|
+
help="Filter by file patterns (e.g., '*.py' or 'src/*.js')",
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Verbose output
|
|
183
|
+
search_parser.add_argument(
|
|
184
|
+
"-v",
|
|
185
|
+
"--verbose",
|
|
186
|
+
action="store_true",
|
|
187
|
+
help="Enable verbose output with additional details",
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
return search_parser
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def validate_search_args(args: argparse.Namespace) -> Optional[str]: # noqa: PLR0911
|
|
194
|
+
"""
|
|
195
|
+
Validate search command arguments.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
args: Parsed command line arguments.
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Error message if validation fails, None otherwise.
|
|
202
|
+
"""
|
|
203
|
+
# Check threshold is in valid range
|
|
204
|
+
if hasattr(args, "threshold") and args.threshold is not None:
|
|
205
|
+
if not 0.0 <= args.threshold <= 1.0:
|
|
206
|
+
return "Similarity threshold must be between 0.0 and 1.0"
|
|
207
|
+
|
|
208
|
+
# Check limit is reasonable
|
|
209
|
+
if hasattr(args, "limit") and args.limit is not None:
|
|
210
|
+
if args.limit < 1:
|
|
211
|
+
return "Limit must be at least 1"
|
|
212
|
+
if args.limit > 50:
|
|
213
|
+
return "Limit cannot exceed 50"
|
|
214
|
+
|
|
215
|
+
# Check that function is only used with --similar
|
|
216
|
+
if (
|
|
217
|
+
hasattr(args, "function")
|
|
218
|
+
and args.function
|
|
219
|
+
and not getattr(args, "similar", None)
|
|
220
|
+
):
|
|
221
|
+
return "--function can only be used with --similar"
|
|
222
|
+
|
|
223
|
+
# Check that focus is only used with --context
|
|
224
|
+
if hasattr(args, "focus") and args.focus and not getattr(args, "context", None):
|
|
225
|
+
return "--focus can only be used with --context"
|
|
226
|
+
|
|
227
|
+
# Check that force is only used with --index
|
|
228
|
+
if hasattr(args, "force") and args.force and not getattr(args, "index", False):
|
|
229
|
+
return "--force can only be used with --index"
|
|
230
|
+
|
|
231
|
+
# Ensure at least one operation is specified
|
|
232
|
+
if hasattr(args, "command") and args.command in ["mpm-search", "search"]:
|
|
233
|
+
has_operation = any(
|
|
234
|
+
[
|
|
235
|
+
getattr(args, "query", None),
|
|
236
|
+
getattr(args, "similar", None),
|
|
237
|
+
getattr(args, "context", None),
|
|
238
|
+
getattr(args, "index", False),
|
|
239
|
+
getattr(args, "status", False),
|
|
240
|
+
]
|
|
241
|
+
)
|
|
242
|
+
if not has_operation:
|
|
243
|
+
return "No search operation specified. Use --help for options."
|
|
244
|
+
|
|
245
|
+
return None
|
|
@@ -69,7 +69,7 @@ def log_memory_stats(logger=None, prefix="Memory Usage"):
|
|
|
69
69
|
f"{prefix}: RSS={rss_mb:.1f}MB, System={memory_percent:.1f}%"
|
|
70
70
|
)
|
|
71
71
|
return {"rss_mb": rss_mb, "vms_mb": None, "percent": memory_percent}
|
|
72
|
-
except:
|
|
72
|
+
except Exception:
|
|
73
73
|
logger.info(f"{prefix}: RSS={rss_mb:.1f}MB")
|
|
74
74
|
return {"rss_mb": rss_mb, "vms_mb": None, "percent": None}
|
|
75
75
|
else:
|
|
@@ -82,7 +82,7 @@ def log_memory_stats(logger=None, prefix="Memory Usage"):
|
|
|
82
82
|
f"System={memory_percent:.1f}%"
|
|
83
83
|
)
|
|
84
84
|
return {"rss_mb": rss_mb, "vms_mb": vms_mb, "percent": memory_percent}
|
|
85
|
-
except:
|
|
85
|
+
except Exception:
|
|
86
86
|
logger.info(f"{prefix}: RSS={rss_mb:.1f}MB, VMS={vms_mb:.1f}MB")
|
|
87
87
|
return {"rss_mb": rss_mb, "vms_mb": vms_mb, "percent": None}
|
|
88
88
|
|
|
@@ -114,12 +114,10 @@ class StartupStatusLogger:
|
|
|
114
114
|
if mcp_executable:
|
|
115
115
|
self.logger.info(f"MCP Server: Installed at {mcp_executable}")
|
|
116
116
|
|
|
117
|
-
# Try to get version
|
|
117
|
+
# Try to get version (only log if version is found)
|
|
118
118
|
version = self._get_mcp_version(mcp_executable)
|
|
119
119
|
if version:
|
|
120
120
|
self.logger.info(f"MCP Server: Version {version}")
|
|
121
|
-
else:
|
|
122
|
-
self.logger.info("MCP Server: Version unknown")
|
|
123
121
|
else:
|
|
124
122
|
self.logger.info("MCP Server: Not found in PATH")
|
|
125
123
|
|
claude_mpm/cli/utils.py
CHANGED
claude_mpm/constants.py
CHANGED
|
@@ -14,23 +14,27 @@ This module provides:
|
|
|
14
14
|
import contextlib
|
|
15
15
|
import warnings
|
|
16
16
|
from dataclasses import dataclass
|
|
17
|
-
from datetime import datetime
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
from typing import Any, Dict, List, Optional, Set
|
|
20
20
|
|
|
21
21
|
# Import from the unified agent registry system
|
|
22
|
+
from .unified_agent_registry import AgentMetadata as UnifiedAgentMetadata
|
|
22
23
|
from .unified_agent_registry import (
|
|
23
|
-
AgentMetadata as UnifiedAgentMetadata,
|
|
24
24
|
AgentTier,
|
|
25
25
|
AgentType,
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
)
|
|
27
|
+
from .unified_agent_registry import discover_agents as unified_discover_agents
|
|
28
|
+
from .unified_agent_registry import get_agent as unified_get_agent
|
|
29
|
+
from .unified_agent_registry import (
|
|
28
30
|
get_agent_registry,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
)
|
|
32
|
+
from .unified_agent_registry import get_core_agents as unified_get_core_agents
|
|
33
|
+
from .unified_agent_registry import get_registry_stats as unified_get_registry_stats
|
|
34
|
+
from .unified_agent_registry import (
|
|
31
35
|
get_specialized_agents as unified_get_specialized_agents,
|
|
32
|
-
list_agents as unified_list_agents,
|
|
33
36
|
)
|
|
37
|
+
from .unified_agent_registry import list_agents as unified_list_agents
|
|
34
38
|
|
|
35
39
|
try:
|
|
36
40
|
from ..core.logger import get_logger
|
|
@@ -379,7 +383,7 @@ class AgentRegistryAdapter:
|
|
|
379
383
|
}
|
|
380
384
|
|
|
381
385
|
nickname = nicknames.get(agent_name, agent_name.title())
|
|
382
|
-
today = datetime.now().strftime("%Y-%m-%d")
|
|
386
|
+
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
383
387
|
|
|
384
388
|
return f"""**{nickname}**: {task}
|
|
385
389
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import json
|
|
4
4
|
import uuid
|
|
5
5
|
from collections import defaultdict
|
|
6
|
-
from datetime import datetime, timedelta
|
|
6
|
+
from datetime import datetime, timedelta, timezone
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Dict, Optional
|
|
9
9
|
|
|
@@ -53,10 +53,10 @@ class AgentSessionManager:
|
|
|
53
53
|
if not self.session_locks.get(session_id, False):
|
|
54
54
|
# Check if session is still fresh (not too old)
|
|
55
55
|
created = datetime.fromisoformat(session_data["created_at"])
|
|
56
|
-
if datetime.now() - created < timedelta(hours=1):
|
|
56
|
+
if datetime.now(timezone.utc) - created < timedelta(hours=1):
|
|
57
57
|
# Use this session
|
|
58
58
|
self.session_locks[session_id] = True
|
|
59
|
-
session_data["last_used"] = datetime.now().isoformat()
|
|
59
|
+
session_data["last_used"] = datetime.now(timezone.utc).isoformat()
|
|
60
60
|
session_data["use_count"] += 1
|
|
61
61
|
logger.info(f"Reusing session {session_id} for {agent_type} agent")
|
|
62
62
|
return session_id
|
|
@@ -85,8 +85,8 @@ class AgentSessionManager:
|
|
|
85
85
|
session_data = {
|
|
86
86
|
"id": session_id,
|
|
87
87
|
"agent_type": agent_type,
|
|
88
|
-
"created_at": datetime.now().isoformat(),
|
|
89
|
-
"last_used": datetime.now().isoformat(),
|
|
88
|
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
|
89
|
+
"last_used": datetime.now(timezone.utc).isoformat(),
|
|
90
90
|
"use_count": 0,
|
|
91
91
|
"tasks_completed": [],
|
|
92
92
|
}
|
|
@@ -122,7 +122,7 @@ class AgentSessionManager:
|
|
|
122
122
|
sessions[session_id]["tasks_completed"].append(
|
|
123
123
|
{
|
|
124
124
|
"task": task[:100], # Truncate long tasks
|
|
125
|
-
"timestamp": datetime.now().isoformat(),
|
|
125
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
126
126
|
"success": success,
|
|
127
127
|
}
|
|
128
128
|
)
|
|
@@ -135,7 +135,7 @@ class AgentSessionManager:
|
|
|
135
135
|
Args:
|
|
136
136
|
max_age_hours: Maximum age in hours
|
|
137
137
|
"""
|
|
138
|
-
now = datetime.now()
|
|
138
|
+
now = datetime.now(timezone.utc)
|
|
139
139
|
max_age = timedelta(hours=max_age_hours)
|
|
140
140
|
|
|
141
141
|
for agent_type in list(self.agent_sessions.keys()):
|
|
@@ -207,7 +207,7 @@ class AgentSessionManager:
|
|
|
207
207
|
try:
|
|
208
208
|
data = {
|
|
209
209
|
"agent_sessions": dict(self.agent_sessions),
|
|
210
|
-
"updated_at": datetime.now().isoformat(),
|
|
210
|
+
"updated_at": datetime.now(timezone.utc).isoformat(),
|
|
211
211
|
}
|
|
212
212
|
with open(session_file, "w") as f:
|
|
213
213
|
json.dump(data, f, indent=2)
|
claude_mpm/core/api_validator.py
CHANGED
|
@@ -84,7 +84,7 @@ class APIKeyValidator:
|
|
|
84
84
|
|
|
85
85
|
return not bool(self.errors), self.errors, self.warnings
|
|
86
86
|
|
|
87
|
-
def _validate_openai_key(self, api_key: str) -> bool:
|
|
87
|
+
def _validate_openai_key(self, api_key: str) -> bool: # noqa: PLR0911
|
|
88
88
|
"""Validate OpenAI API key.
|
|
89
89
|
|
|
90
90
|
Args:
|
|
@@ -133,7 +133,7 @@ class APIKeyValidator:
|
|
|
133
133
|
self.errors.append(f"❌ OpenAI API validation failed with error: {e}")
|
|
134
134
|
return False
|
|
135
135
|
|
|
136
|
-
def _validate_anthropic_key(self, api_key: str) -> bool:
|
|
136
|
+
def _validate_anthropic_key(self, api_key: str) -> bool: # noqa: PLR0911
|
|
137
137
|
"""Validate Anthropic API key.
|
|
138
138
|
|
|
139
139
|
Args:
|
|
@@ -196,7 +196,7 @@ class APIKeyValidator:
|
|
|
196
196
|
self.errors.append(f"❌ Anthropic API validation failed with error: {e}")
|
|
197
197
|
return False
|
|
198
198
|
|
|
199
|
-
def _validate_github_token(self, token: str) -> bool:
|
|
199
|
+
def _validate_github_token(self, token: str) -> bool: # noqa: PLR0911
|
|
200
200
|
"""Validate GitHub personal access token.
|
|
201
201
|
|
|
202
202
|
Args:
|
|
@@ -244,7 +244,7 @@ class APIKeyValidator:
|
|
|
244
244
|
self.errors.append(f"❌ GitHub token validation failed with error: {e}")
|
|
245
245
|
return False
|
|
246
246
|
|
|
247
|
-
def _validate_custom_api(self, api_name: str, validation_config: Dict) -> bool:
|
|
247
|
+
def _validate_custom_api(self, api_name: str, validation_config: Dict) -> bool: # noqa: PLR0911
|
|
248
248
|
"""Validate a custom API key based on configuration.
|
|
249
249
|
|
|
250
250
|
Args:
|
claude_mpm/core/base_service.py
CHANGED
|
@@ -26,7 +26,7 @@ import traceback
|
|
|
26
26
|
from abc import ABC, abstractmethod
|
|
27
27
|
from contextlib import asynccontextmanager
|
|
28
28
|
from dataclasses import dataclass, field
|
|
29
|
-
from datetime import datetime, timedelta
|
|
29
|
+
from datetime import datetime, timedelta, timezone
|
|
30
30
|
from pathlib import Path
|
|
31
31
|
from typing import Any, Dict, List, Optional
|
|
32
32
|
|
|
@@ -144,7 +144,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
144
144
|
self._health = ServiceHealth(
|
|
145
145
|
status="unknown",
|
|
146
146
|
message="Service not started",
|
|
147
|
-
timestamp=datetime.now().isoformat(),
|
|
147
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
148
148
|
)
|
|
149
149
|
self._metrics = ServiceMetrics()
|
|
150
150
|
self._last_health_check: Optional[float] = None
|
|
@@ -199,7 +199,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
199
199
|
def uptime(self) -> Optional[float]:
|
|
200
200
|
"""Get service uptime in seconds."""
|
|
201
201
|
if self._start_time and self._running:
|
|
202
|
-
return (datetime.now() - self._start_time).total_seconds()
|
|
202
|
+
return (datetime.now(timezone.utc) - self._start_time).total_seconds()
|
|
203
203
|
return None
|
|
204
204
|
|
|
205
205
|
@property
|
|
@@ -237,7 +237,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
237
237
|
self._health = ServiceHealth(
|
|
238
238
|
status="unhealthy",
|
|
239
239
|
message=f"Startup failed: {e!s}",
|
|
240
|
-
timestamp=datetime.now().isoformat(),
|
|
240
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
241
241
|
checks={"startup": False},
|
|
242
242
|
)
|
|
243
243
|
|
|
@@ -268,13 +268,13 @@ class BaseService(LoggerMixin, ABC):
|
|
|
268
268
|
|
|
269
269
|
# Mark as running
|
|
270
270
|
self._running = True
|
|
271
|
-
self._start_time = datetime.now()
|
|
271
|
+
self._start_time = datetime.now(timezone.utc)
|
|
272
272
|
|
|
273
273
|
# Update health status
|
|
274
274
|
self._health = ServiceHealth(
|
|
275
275
|
status="healthy",
|
|
276
276
|
message="Service started successfully",
|
|
277
|
-
timestamp=datetime.now().isoformat(),
|
|
277
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
278
278
|
checks={"startup": True},
|
|
279
279
|
metrics=self._get_health_metrics() if self._enable_enhanced else {},
|
|
280
280
|
)
|
|
@@ -338,7 +338,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
338
338
|
self._health = ServiceHealth(
|
|
339
339
|
status="unknown",
|
|
340
340
|
message="Service stopped",
|
|
341
|
-
timestamp=datetime.now().isoformat(),
|
|
341
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
342
342
|
checks={"running": False},
|
|
343
343
|
)
|
|
344
344
|
|
|
@@ -388,7 +388,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
388
388
|
self._health = ServiceHealth(
|
|
389
389
|
status=status,
|
|
390
390
|
message=message,
|
|
391
|
-
timestamp=datetime.now().isoformat(),
|
|
391
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
392
392
|
checks=checks,
|
|
393
393
|
metrics={
|
|
394
394
|
"uptime": self.uptime,
|
|
@@ -404,7 +404,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
404
404
|
self._health = ServiceHealth(
|
|
405
405
|
status="unhealthy",
|
|
406
406
|
message=f"Health check error: {e!s}",
|
|
407
|
-
timestamp=datetime.now().isoformat(),
|
|
407
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
408
408
|
checks={"health_check_error": True},
|
|
409
409
|
)
|
|
410
410
|
return self._health
|
|
@@ -586,7 +586,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
586
586
|
return ServiceHealth(
|
|
587
587
|
status="degraded",
|
|
588
588
|
message="Service circuit breaker is open",
|
|
589
|
-
timestamp=datetime.now().isoformat(),
|
|
589
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
590
590
|
checks={"circuit_breaker": False},
|
|
591
591
|
metrics=self._get_health_metrics(),
|
|
592
592
|
)
|
claude_mpm/core/cache.py
CHANGED
|
@@ -19,7 +19,7 @@ import pickle
|
|
|
19
19
|
import threading
|
|
20
20
|
from collections import OrderedDict
|
|
21
21
|
from dataclasses import dataclass, field
|
|
22
|
-
from datetime import datetime
|
|
22
|
+
from datetime import datetime, timezone
|
|
23
23
|
from typing import Any, Callable, Dict, Optional, TypeVar, Union
|
|
24
24
|
|
|
25
25
|
from ..core.logger import get_logger
|
|
@@ -43,12 +43,12 @@ class CacheEntry:
|
|
|
43
43
|
"""Check if entry has expired based on TTL."""
|
|
44
44
|
if self.ttl is None:
|
|
45
45
|
return False
|
|
46
|
-
age = (datetime.now() - self.created_at).total_seconds()
|
|
46
|
+
age = (datetime.now(timezone.utc) - self.created_at).total_seconds()
|
|
47
47
|
return age > self.ttl
|
|
48
48
|
|
|
49
49
|
def touch(self):
|
|
50
50
|
"""Update last access time and increment counter."""
|
|
51
|
-
self.last_accessed = datetime.now()
|
|
51
|
+
self.last_accessed = datetime.now(timezone.utc)
|
|
52
52
|
self.access_count += 1
|
|
53
53
|
|
|
54
54
|
|
|
@@ -129,13 +129,13 @@ class FileSystemCache:
|
|
|
129
129
|
# Rough estimate using JSON serialization
|
|
130
130
|
try:
|
|
131
131
|
return len(json.dumps(value))
|
|
132
|
-
except:
|
|
132
|
+
except Exception:
|
|
133
133
|
return 1000 # Default estimate
|
|
134
134
|
else:
|
|
135
135
|
# Use pickle for size estimation
|
|
136
136
|
try:
|
|
137
137
|
return len(pickle.dumps(value))
|
|
138
|
-
except:
|
|
138
|
+
except Exception:
|
|
139
139
|
return 100 # Default small size
|
|
140
140
|
|
|
141
141
|
def _evict_lru(self):
|
claude_mpm/core/container.py
CHANGED
|
@@ -636,7 +636,7 @@ class DIContainer(IServiceContainer):
|
|
|
636
636
|
if reg_type.__name__ == param_type:
|
|
637
637
|
param_type = reg_type
|
|
638
638
|
break
|
|
639
|
-
except:
|
|
639
|
+
except Exception:
|
|
640
640
|
# If we can't resolve, skip this parameter
|
|
641
641
|
if param.default != param.empty:
|
|
642
642
|
kwargs[param_name] = param.default
|
claude_mpm/core/error_handler.py
CHANGED
|
@@ -384,7 +384,7 @@ def with_error_handling(
|
|
|
384
384
|
if callable(fallback_value):
|
|
385
385
|
try:
|
|
386
386
|
fb_value = fallback_value(*args, **kwargs)
|
|
387
|
-
except:
|
|
387
|
+
except Exception:
|
|
388
388
|
fb_value = None
|
|
389
389
|
|
|
390
390
|
return handle_error(
|
|
@@ -428,7 +428,7 @@ def safe_operation(
|
|
|
428
428
|
if callable(fallback_value):
|
|
429
429
|
try:
|
|
430
430
|
return fallback_value(*args, **kwargs)
|
|
431
|
-
except:
|
|
431
|
+
except Exception:
|
|
432
432
|
return None
|
|
433
433
|
return fallback_value
|
|
434
434
|
|
claude_mpm/core/file_utils.py
CHANGED
|
@@ -6,7 +6,7 @@ import logging
|
|
|
6
6
|
import os
|
|
7
7
|
import platform
|
|
8
8
|
import time
|
|
9
|
-
from datetime import datetime
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Any, Dict, Optional
|
|
12
12
|
|
|
@@ -1432,7 +1432,7 @@ Extract tickets from these patterns:
|
|
|
1432
1432
|
|
|
1433
1433
|
try:
|
|
1434
1434
|
# Get current datetime with timezone awareness
|
|
1435
|
-
now = datetime.now()
|
|
1435
|
+
now = datetime.now(timezone.utc)
|
|
1436
1436
|
|
|
1437
1437
|
# Try to get timezone info - fallback to UTC offset if timezone name not available
|
|
1438
1438
|
try:
|
|
@@ -1470,7 +1470,7 @@ Extract tickets from these patterns:
|
|
|
1470
1470
|
# Fallback to basic date if enhanced datetime fails
|
|
1471
1471
|
self.logger.debug(f"Error generating enhanced datetime context: {e}")
|
|
1472
1472
|
context_lines.append(
|
|
1473
|
-
f"**Today's Date**: {datetime.now().strftime('%Y-%m-%d')}\n"
|
|
1473
|
+
f"**Today's Date**: {datetime.now(timezone.utc).strftime('%Y-%m-%d')}\n"
|
|
1474
1474
|
)
|
|
1475
1475
|
|
|
1476
1476
|
try:
|