claude-mpm 4.3.12__py3-none-any.whl → 4.3.14__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 +414 -28
- claude_mpm/agents/templates/data_engineer.json +39 -14
- claude_mpm/agents/templates/engineer.json +11 -3
- 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 +1 -1
- claude_mpm/cli/commands/mcp_config.py +7 -10
- claude_mpm/cli/commands/mcp_external_commands.py +40 -32
- claude_mpm/cli/commands/mcp_install_commands.py +38 -10
- claude_mpm/cli/commands/mcp_setup_external.py +143 -102
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init_handler.py +1 -1
- claude_mpm/cli/commands/run.py +54 -2
- claude_mpm/cli/commands/search.py +41 -34
- claude_mpm/cli/interactive/agent_wizard.py +6 -2
- claude_mpm/cli/parsers/mcp_parser.py +1 -3
- claude_mpm/cli/parsers/search_parser.py +10 -4
- claude_mpm/cli/startup_logging.py +158 -5
- claude_mpm/cli/utils.py +1 -1
- claude_mpm/core/agent_registry.py +2 -2
- claude_mpm/core/agent_session_manager.py +8 -8
- claude_mpm/core/api_validator.py +6 -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 +3 -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/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 +2 -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/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- 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/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +8 -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 +7 -5
- claude_mpm/scripts/mcp_server.py +0 -0
- claude_mpm/scripts/start_activity_logging.py +0 -0
- 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 +2 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +9 -3
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +5 -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/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/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_listing_service.py +3 -1
- claude_mpm/services/cli/agent_validation_service.py +2 -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/core/memory_manager.py +81 -23
- claude_mpm/services/core/path_resolver.py +1 -1
- 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 +175 -30
- 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 +1 -1
- claude_mpm/services/mcp_gateway/core/base.py +2 -2
- claude_mpm/services/mcp_gateway/main.py +21 -7
- 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 +5 -2
- 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 +190 -137
- 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 +16 -16
- 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/management/lifecycle.py +3 -1
- claude_mpm/services/monitor/server.py +4 -4
- claude_mpm/services/monitor_build_service.py +2 -2
- claude_mpm/services/port_manager.py +3 -1
- 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 +11 -7
- 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/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 -12
- 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/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 +3 -1
- claude_mpm/storage/state_storage.py +1 -1
- claude_mpm/tools/code_tree_analyzer.py +23 -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 +6 -2
- claude_mpm/utils/dependency_strategies.py +8 -3
- claude_mpm/utils/environment_context.py +1 -1
- claude_mpm/utils/error_handler.py +2 -2
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/log_cleanup.py +21 -7
- claude_mpm/validation/agent_validator.py +2 -2
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/METADATA +1 -1
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/RECORD +204 -191
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/WHEEL +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.14.dist-info}/top_level.txt +0 -0
|
@@ -34,6 +34,7 @@ class MCPSearchInterface:
|
|
|
34
34
|
"""Initialize the MCP gateway connection."""
|
|
35
35
|
try:
|
|
36
36
|
from claude_mpm.services.mcp_gateway import MCPGatewayService
|
|
37
|
+
|
|
37
38
|
self.mcp_gateway = self.container.resolve(MCPGatewayService)
|
|
38
39
|
if not self.mcp_gateway:
|
|
39
40
|
self.mcp_gateway = MCPGatewayService()
|
|
@@ -48,13 +49,13 @@ class MCPSearchInterface:
|
|
|
48
49
|
limit: int = 10,
|
|
49
50
|
similarity_threshold: float = 0.3,
|
|
50
51
|
file_extensions: Optional[list] = None,
|
|
51
|
-
language: Optional[str] = None
|
|
52
|
+
language: Optional[str] = None,
|
|
52
53
|
) -> Dict[str, Any]:
|
|
53
54
|
"""Search code using semantic similarity."""
|
|
54
55
|
params = {
|
|
55
56
|
"query": query,
|
|
56
57
|
"limit": limit,
|
|
57
|
-
"similarity_threshold": similarity_threshold
|
|
58
|
+
"similarity_threshold": similarity_threshold,
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
if file_extensions:
|
|
@@ -69,45 +70,43 @@ class MCPSearchInterface:
|
|
|
69
70
|
file_path: str,
|
|
70
71
|
function_name: Optional[str] = None,
|
|
71
72
|
limit: int = 10,
|
|
72
|
-
similarity_threshold: float = 0.3
|
|
73
|
+
similarity_threshold: float = 0.3,
|
|
73
74
|
) -> Dict[str, Any]:
|
|
74
75
|
"""Find code similar to a specific file or function."""
|
|
75
76
|
params = {
|
|
76
77
|
"file_path": file_path,
|
|
77
78
|
"limit": limit,
|
|
78
|
-
"similarity_threshold": similarity_threshold
|
|
79
|
+
"similarity_threshold": similarity_threshold,
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
if function_name:
|
|
82
83
|
params["function_name"] = function_name
|
|
83
84
|
|
|
84
|
-
return await self._call_mcp_tool(
|
|
85
|
+
return await self._call_mcp_tool(
|
|
86
|
+
"mcp__mcp-vector-search__search_similar", params
|
|
87
|
+
)
|
|
85
88
|
|
|
86
89
|
async def search_context(
|
|
87
|
-
self,
|
|
88
|
-
description: str,
|
|
89
|
-
focus_areas: Optional[list] = None,
|
|
90
|
-
limit: int = 10
|
|
90
|
+
self, description: str, focus_areas: Optional[list] = None, limit: int = 10
|
|
91
91
|
) -> Dict[str, Any]:
|
|
92
92
|
"""Search for code based on contextual description."""
|
|
93
|
-
params = {
|
|
94
|
-
"description": description,
|
|
95
|
-
"limit": limit
|
|
96
|
-
}
|
|
93
|
+
params = {"description": description, "limit": limit}
|
|
97
94
|
|
|
98
95
|
if focus_areas:
|
|
99
96
|
params["focus_areas"] = focus_areas
|
|
100
97
|
|
|
101
|
-
return await self._call_mcp_tool(
|
|
98
|
+
return await self._call_mcp_tool(
|
|
99
|
+
"mcp__mcp-vector-search__search_context", params
|
|
100
|
+
)
|
|
102
101
|
|
|
103
102
|
async def get_status(self) -> Dict[str, Any]:
|
|
104
103
|
"""Get project indexing status and statistics."""
|
|
105
|
-
return await self._call_mcp_tool(
|
|
104
|
+
return await self._call_mcp_tool(
|
|
105
|
+
"mcp__mcp-vector-search__get_project_status", {}
|
|
106
|
+
)
|
|
106
107
|
|
|
107
108
|
async def index_project(
|
|
108
|
-
self,
|
|
109
|
-
force: bool = False,
|
|
110
|
-
file_extensions: Optional[list] = None
|
|
109
|
+
self, force: bool = False, file_extensions: Optional[list] = None
|
|
111
110
|
) -> Dict[str, Any]:
|
|
112
111
|
"""Index or reindex the project codebase."""
|
|
113
112
|
params = {"force": force}
|
|
@@ -115,16 +114,19 @@ class MCPSearchInterface:
|
|
|
115
114
|
if file_extensions:
|
|
116
115
|
params["file_extensions"] = file_extensions
|
|
117
116
|
|
|
118
|
-
return await self._call_mcp_tool(
|
|
117
|
+
return await self._call_mcp_tool(
|
|
118
|
+
"mcp__mcp-vector-search__index_project", params
|
|
119
|
+
)
|
|
119
120
|
|
|
120
|
-
async def _call_mcp_tool(
|
|
121
|
+
async def _call_mcp_tool(
|
|
122
|
+
self, tool_name: str, params: Dict[str, Any]
|
|
123
|
+
) -> Dict[str, Any]:
|
|
121
124
|
"""Call an MCP tool through the gateway."""
|
|
122
125
|
if not self.mcp_gateway:
|
|
123
126
|
await self.initialize()
|
|
124
127
|
|
|
125
128
|
try:
|
|
126
|
-
|
|
127
|
-
return result
|
|
129
|
+
return await self.mcp_gateway.call_tool(tool_name, params)
|
|
128
130
|
except Exception as e:
|
|
129
131
|
return {"error": str(e)}
|
|
130
132
|
|
|
@@ -161,9 +163,11 @@ def display_search_results(results: Dict[str, Any], output_format: str = "rich")
|
|
|
161
163
|
# Show snippet if available
|
|
162
164
|
if result.get("snippet"):
|
|
163
165
|
snippet_panel = Panel(
|
|
164
|
-
Syntax(
|
|
166
|
+
Syntax(
|
|
167
|
+
result["snippet"], result.get("language", "python"), theme="monokai"
|
|
168
|
+
),
|
|
165
169
|
title=f"[cyan]{file_path}[/cyan]",
|
|
166
|
-
border_style="dim"
|
|
170
|
+
border_style="dim",
|
|
167
171
|
)
|
|
168
172
|
console.print(snippet_panel)
|
|
169
173
|
|
|
@@ -172,7 +176,7 @@ def display_search_results(results: Dict[str, Any], output_format: str = "rich")
|
|
|
172
176
|
# Show statistics if available
|
|
173
177
|
if "stats" in results:
|
|
174
178
|
stats = results["stats"]
|
|
175
|
-
console.print(
|
|
179
|
+
console.print("\n[bold]Statistics:[/bold]")
|
|
176
180
|
console.print(f" Total indexed files: {stats.get('total_files', 0)}")
|
|
177
181
|
console.print(f" Total indexed functions: {stats.get('total_functions', 0)}")
|
|
178
182
|
console.print(f" Index last updated: {stats.get('last_updated', 'Unknown')}")
|
|
@@ -206,7 +210,7 @@ async def search_command(
|
|
|
206
210
|
function: Optional[str],
|
|
207
211
|
focus: tuple,
|
|
208
212
|
force: bool,
|
|
209
|
-
output_json: bool
|
|
213
|
+
output_json: bool,
|
|
210
214
|
):
|
|
211
215
|
"""
|
|
212
216
|
Search the codebase using semantic search powered by mcp-vector-search.
|
|
@@ -228,8 +232,7 @@ async def search_command(
|
|
|
228
232
|
if index:
|
|
229
233
|
console.print("[cyan]Indexing project...[/cyan]")
|
|
230
234
|
result = await search.index_project(
|
|
231
|
-
force=force,
|
|
232
|
-
file_extensions=list(extensions) if extensions else None
|
|
235
|
+
force=force, file_extensions=list(extensions) if extensions else None
|
|
233
236
|
)
|
|
234
237
|
if "error" not in result:
|
|
235
238
|
console.print("[green]✓ Project indexed successfully[/green]")
|
|
@@ -244,7 +247,7 @@ async def search_command(
|
|
|
244
247
|
file_path=similar,
|
|
245
248
|
function_name=function,
|
|
246
249
|
limit=limit,
|
|
247
|
-
similarity_threshold=threshold
|
|
250
|
+
similarity_threshold=threshold,
|
|
248
251
|
)
|
|
249
252
|
display_search_results(result, output_format)
|
|
250
253
|
|
|
@@ -252,7 +255,7 @@ async def search_command(
|
|
|
252
255
|
result = await search.search_context(
|
|
253
256
|
description=context,
|
|
254
257
|
focus_areas=list(focus) if focus else None,
|
|
255
|
-
limit=limit
|
|
258
|
+
limit=limit,
|
|
256
259
|
)
|
|
257
260
|
display_search_results(result, output_format)
|
|
258
261
|
|
|
@@ -262,17 +265,21 @@ async def search_command(
|
|
|
262
265
|
limit=limit,
|
|
263
266
|
similarity_threshold=threshold,
|
|
264
267
|
file_extensions=list(extensions) if extensions else None,
|
|
265
|
-
language=language
|
|
268
|
+
language=language,
|
|
266
269
|
)
|
|
267
270
|
display_search_results(result, output_format)
|
|
268
271
|
|
|
269
272
|
else:
|
|
270
|
-
console.print(
|
|
273
|
+
console.print(
|
|
274
|
+
"[yellow]No search operation specified. Use --help for options.[/yellow]"
|
|
275
|
+
)
|
|
271
276
|
|
|
272
277
|
except Exception as e:
|
|
273
278
|
console.print(f"[red]Search failed: {e}[/red]")
|
|
274
279
|
if not output_json:
|
|
275
|
-
console.print(
|
|
280
|
+
console.print(
|
|
281
|
+
"[dim]Tip: Make sure the project is indexed with --index first[/dim]"
|
|
282
|
+
)
|
|
276
283
|
sys.exit(1)
|
|
277
284
|
|
|
278
285
|
|
|
@@ -282,4 +289,4 @@ def main():
|
|
|
282
289
|
|
|
283
290
|
|
|
284
291
|
if __name__ == "__main__":
|
|
285
|
-
main()
|
|
292
|
+
main()
|
|
@@ -600,7 +600,9 @@ class AgentWizard:
|
|
|
600
600
|
tier="project",
|
|
601
601
|
)
|
|
602
602
|
|
|
603
|
-
def _manage_single_agent(
|
|
603
|
+
def _manage_single_agent(
|
|
604
|
+
self, template: LocalAgentTemplate
|
|
605
|
+
) -> Tuple[bool, str]:
|
|
604
606
|
"""Manage a single agent."""
|
|
605
607
|
print(f"\n🔧 Managing Agent: {template.agent_id}")
|
|
606
608
|
print(f" Name: {template.metadata.get('name', template.agent_id)}")
|
|
@@ -815,7 +817,9 @@ class AgentWizard:
|
|
|
815
817
|
return self.manager.project_agents_dir / f"{template.agent_id}.json"
|
|
816
818
|
return self.manager.user_agents_dir / f"{template.agent_id}.json"
|
|
817
819
|
|
|
818
|
-
def _interactive_delete_menu(
|
|
820
|
+
def _interactive_delete_menu(
|
|
821
|
+
self, templates: list
|
|
822
|
+
) -> Tuple[bool, str]:
|
|
819
823
|
"""Interactive deletion menu for multiple agents."""
|
|
820
824
|
print("\n🗑️ Delete Agents")
|
|
821
825
|
print("=" * 50)
|
|
@@ -189,9 +189,7 @@ def add_mcp_subparser(subparsers) -> argparse.ArgumentParser:
|
|
|
189
189
|
help="External service action (default: list)",
|
|
190
190
|
)
|
|
191
191
|
external_mcp_parser.add_argument(
|
|
192
|
-
"--force",
|
|
193
|
-
action="store_true",
|
|
194
|
-
help="Force overwrite existing configuration"
|
|
192
|
+
"--force", action="store_true", help="Force overwrite existing configuration"
|
|
195
193
|
)
|
|
196
194
|
|
|
197
195
|
return mcp_parser
|
|
@@ -8,7 +8,9 @@ import argparse
|
|
|
8
8
|
from typing import Optional
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def add_search_subparser(
|
|
11
|
+
def add_search_subparser(
|
|
12
|
+
subparsers: argparse._SubParsersAction,
|
|
13
|
+
) -> argparse.ArgumentParser:
|
|
12
14
|
"""
|
|
13
15
|
Add the search command parser.
|
|
14
16
|
|
|
@@ -188,7 +190,7 @@ Examples:
|
|
|
188
190
|
return search_parser
|
|
189
191
|
|
|
190
192
|
|
|
191
|
-
def validate_search_args(args: argparse.Namespace) -> Optional[str]:
|
|
193
|
+
def validate_search_args(args: argparse.Namespace) -> Optional[str]: # noqa: PLR0911
|
|
192
194
|
"""
|
|
193
195
|
Validate search command arguments.
|
|
194
196
|
|
|
@@ -211,7 +213,11 @@ def validate_search_args(args: argparse.Namespace) -> Optional[str]:
|
|
|
211
213
|
return "Limit cannot exceed 50"
|
|
212
214
|
|
|
213
215
|
# Check that function is only used with --similar
|
|
214
|
-
if
|
|
216
|
+
if (
|
|
217
|
+
hasattr(args, "function")
|
|
218
|
+
and args.function
|
|
219
|
+
and not getattr(args, "similar", None)
|
|
220
|
+
):
|
|
215
221
|
return "--function can only be used with --similar"
|
|
216
222
|
|
|
217
223
|
# Check that focus is only used with --context
|
|
@@ -236,4 +242,4 @@ def validate_search_args(args: argparse.Namespace) -> Optional[str]:
|
|
|
236
242
|
if not has_operation:
|
|
237
243
|
return "No search operation specified. Use --help for options."
|
|
238
244
|
|
|
239
|
-
return None
|
|
245
|
+
return None
|
|
@@ -14,6 +14,7 @@ DESIGN DECISIONS:
|
|
|
14
14
|
- Capture all startup logs to timestamped files for analysis
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
+
import asyncio
|
|
17
18
|
import logging
|
|
18
19
|
import shutil
|
|
19
20
|
import subprocess
|
|
@@ -69,7 +70,7 @@ def log_memory_stats(logger=None, prefix="Memory Usage"):
|
|
|
69
70
|
f"{prefix}: RSS={rss_mb:.1f}MB, System={memory_percent:.1f}%"
|
|
70
71
|
)
|
|
71
72
|
return {"rss_mb": rss_mb, "vms_mb": None, "percent": memory_percent}
|
|
72
|
-
except:
|
|
73
|
+
except Exception:
|
|
73
74
|
logger.info(f"{prefix}: RSS={rss_mb:.1f}MB")
|
|
74
75
|
return {"rss_mb": rss_mb, "vms_mb": None, "percent": None}
|
|
75
76
|
else:
|
|
@@ -82,7 +83,7 @@ def log_memory_stats(logger=None, prefix="Memory Usage"):
|
|
|
82
83
|
f"System={memory_percent:.1f}%"
|
|
83
84
|
)
|
|
84
85
|
return {"rss_mb": rss_mb, "vms_mb": vms_mb, "percent": memory_percent}
|
|
85
|
-
except:
|
|
86
|
+
except Exception:
|
|
86
87
|
logger.info(f"{prefix}: RSS={rss_mb:.1f}MB, VMS={vms_mb:.1f}MB")
|
|
87
88
|
return {"rss_mb": rss_mb, "vms_mb": vms_mb, "percent": None}
|
|
88
89
|
|
|
@@ -114,12 +115,10 @@ class StartupStatusLogger:
|
|
|
114
115
|
if mcp_executable:
|
|
115
116
|
self.logger.info(f"MCP Server: Installed at {mcp_executable}")
|
|
116
117
|
|
|
117
|
-
# Try to get version
|
|
118
|
+
# Try to get version (only log if version is found)
|
|
118
119
|
version = self._get_mcp_version(mcp_executable)
|
|
119
120
|
if version:
|
|
120
121
|
self.logger.info(f"MCP Server: Version {version}")
|
|
121
|
-
else:
|
|
122
|
-
self.logger.info("MCP Server: Version unknown")
|
|
123
122
|
else:
|
|
124
123
|
self.logger.info("MCP Server: Not found in PATH")
|
|
125
124
|
|
|
@@ -632,6 +631,156 @@ def cleanup_old_startup_logs(
|
|
|
632
631
|
return deleted_count
|
|
633
632
|
|
|
634
633
|
|
|
634
|
+
async def trigger_vector_search_indexing(project_root: Optional[Path] = None) -> None:
|
|
635
|
+
"""
|
|
636
|
+
Trigger mcp-vector-search indexing in the background.
|
|
637
|
+
|
|
638
|
+
This function attempts to start the mcp-vector-search indexing process
|
|
639
|
+
asynchronously so it doesn't block startup. If the service is not available,
|
|
640
|
+
it fails silently.
|
|
641
|
+
|
|
642
|
+
Args:
|
|
643
|
+
project_root: Root directory for the project (defaults to cwd)
|
|
644
|
+
"""
|
|
645
|
+
logger = get_logger("cli")
|
|
646
|
+
|
|
647
|
+
if project_root is None:
|
|
648
|
+
project_root = Path.cwd()
|
|
649
|
+
|
|
650
|
+
try:
|
|
651
|
+
# Check if mcp-vector-search is available
|
|
652
|
+
from ..services.mcp_config_manager import MCPConfigManager
|
|
653
|
+
|
|
654
|
+
manager = MCPConfigManager()
|
|
655
|
+
vector_search_path = manager.detect_service_path("mcp-vector-search")
|
|
656
|
+
|
|
657
|
+
if not vector_search_path:
|
|
658
|
+
logger.debug("mcp-vector-search not found, skipping indexing")
|
|
659
|
+
return
|
|
660
|
+
|
|
661
|
+
# Build the command based on the service configuration
|
|
662
|
+
if "python" in vector_search_path:
|
|
663
|
+
# Using Python interpreter directly
|
|
664
|
+
cmd = [
|
|
665
|
+
vector_search_path,
|
|
666
|
+
"-m",
|
|
667
|
+
"mcp_vector_search.cli",
|
|
668
|
+
"index",
|
|
669
|
+
str(project_root),
|
|
670
|
+
]
|
|
671
|
+
else:
|
|
672
|
+
# Using installed binary
|
|
673
|
+
cmd = [vector_search_path, "index", str(project_root)]
|
|
674
|
+
|
|
675
|
+
logger.info(
|
|
676
|
+
"MCP Vector Search: Starting background indexing for improved code search"
|
|
677
|
+
)
|
|
678
|
+
|
|
679
|
+
# Start the indexing process in the background
|
|
680
|
+
# We use subprocess.Popen instead of run to avoid blocking
|
|
681
|
+
process = await asyncio.create_subprocess_exec(
|
|
682
|
+
*cmd,
|
|
683
|
+
stdout=asyncio.subprocess.DEVNULL,
|
|
684
|
+
stderr=asyncio.subprocess.DEVNULL,
|
|
685
|
+
cwd=str(project_root),
|
|
686
|
+
)
|
|
687
|
+
|
|
688
|
+
# Don't wait for completion - let it run in the background
|
|
689
|
+
logger.debug(
|
|
690
|
+
f"MCP Vector Search: Indexing process started (PID: {process.pid})"
|
|
691
|
+
)
|
|
692
|
+
|
|
693
|
+
except ImportError:
|
|
694
|
+
logger.debug(
|
|
695
|
+
"MCP config manager not available, skipping vector search indexing"
|
|
696
|
+
)
|
|
697
|
+
except Exception as e:
|
|
698
|
+
# Don't let indexing failures prevent startup
|
|
699
|
+
logger.debug(f"Failed to start vector search indexing: {e}")
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
def start_vector_search_indexing(project_root: Optional[Path] = None) -> None:
|
|
703
|
+
"""
|
|
704
|
+
Synchronous wrapper to trigger vector search indexing.
|
|
705
|
+
|
|
706
|
+
This creates a new event loop if needed to run the async indexing function.
|
|
707
|
+
Falls back to subprocess.Popen if async fails.
|
|
708
|
+
|
|
709
|
+
Args:
|
|
710
|
+
project_root: Root directory for the project (defaults to cwd)
|
|
711
|
+
"""
|
|
712
|
+
logger = get_logger("cli")
|
|
713
|
+
|
|
714
|
+
try:
|
|
715
|
+
# Try to get the current event loop
|
|
716
|
+
loop = asyncio.get_running_loop()
|
|
717
|
+
# If we're in an event loop, create a task
|
|
718
|
+
# Store reference to avoid RUF006 warning
|
|
719
|
+
_ = loop.create_task(trigger_vector_search_indexing(project_root))
|
|
720
|
+
except RuntimeError:
|
|
721
|
+
# No event loop running, try async approach first
|
|
722
|
+
try:
|
|
723
|
+
asyncio.run(trigger_vector_search_indexing(project_root))
|
|
724
|
+
except Exception as e:
|
|
725
|
+
# Fallback to simple subprocess approach
|
|
726
|
+
logger.debug(f"Async indexing failed, trying subprocess: {e}")
|
|
727
|
+
_start_vector_search_subprocess(project_root)
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
def _start_vector_search_subprocess(project_root: Optional[Path] = None) -> None:
|
|
731
|
+
"""
|
|
732
|
+
Fallback method to start vector search indexing using subprocess.Popen.
|
|
733
|
+
|
|
734
|
+
Args:
|
|
735
|
+
project_root: Root directory for the project (defaults to cwd)
|
|
736
|
+
"""
|
|
737
|
+
logger = get_logger("cli")
|
|
738
|
+
|
|
739
|
+
if project_root is None:
|
|
740
|
+
project_root = Path.cwd()
|
|
741
|
+
|
|
742
|
+
try:
|
|
743
|
+
from ..services.mcp_config_manager import MCPConfigManager
|
|
744
|
+
|
|
745
|
+
manager = MCPConfigManager()
|
|
746
|
+
vector_search_path = manager.detect_service_path("mcp-vector-search")
|
|
747
|
+
|
|
748
|
+
if not vector_search_path:
|
|
749
|
+
logger.debug("mcp-vector-search not found, skipping indexing")
|
|
750
|
+
return
|
|
751
|
+
|
|
752
|
+
# Build the command
|
|
753
|
+
if "python" in vector_search_path:
|
|
754
|
+
cmd = [
|
|
755
|
+
vector_search_path,
|
|
756
|
+
"-m",
|
|
757
|
+
"mcp_vector_search.cli",
|
|
758
|
+
"index",
|
|
759
|
+
str(project_root),
|
|
760
|
+
]
|
|
761
|
+
else:
|
|
762
|
+
cmd = [vector_search_path, "index", str(project_root)]
|
|
763
|
+
|
|
764
|
+
logger.info(
|
|
765
|
+
"MCP Vector Search: Starting background indexing for improved code search"
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
# Start the indexing process in the background
|
|
769
|
+
process = subprocess.Popen(
|
|
770
|
+
cmd,
|
|
771
|
+
stdout=subprocess.DEVNULL,
|
|
772
|
+
stderr=subprocess.DEVNULL,
|
|
773
|
+
cwd=str(project_root),
|
|
774
|
+
)
|
|
775
|
+
|
|
776
|
+
logger.debug(
|
|
777
|
+
f"MCP Vector Search: Indexing process started (PID: {process.pid})"
|
|
778
|
+
)
|
|
779
|
+
|
|
780
|
+
except Exception as e:
|
|
781
|
+
logger.debug(f"Failed to start vector search indexing: {e}")
|
|
782
|
+
|
|
783
|
+
|
|
635
784
|
def get_latest_startup_log(project_root: Optional[Path] = None) -> Optional[Path]:
|
|
636
785
|
"""
|
|
637
786
|
Get the path to the most recent startup log file.
|
|
@@ -680,6 +829,10 @@ def log_startup_status(monitor_mode: bool = False, websocket_port: int = 8765) -
|
|
|
680
829
|
# Log monitor setup status
|
|
681
830
|
status_logger.log_monitor_setup_status(monitor_mode, websocket_port)
|
|
682
831
|
|
|
832
|
+
# Trigger vector search indexing in the background after MCP is configured
|
|
833
|
+
# This will run asynchronously and not block startup
|
|
834
|
+
start_vector_search_indexing()
|
|
835
|
+
|
|
683
836
|
except Exception as e:
|
|
684
837
|
# Don't let logging failures prevent startup
|
|
685
838
|
logger = get_logger("cli")
|
claude_mpm/cli/utils.py
CHANGED
|
@@ -14,7 +14,7 @@ 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
|
|
|
@@ -379,7 +379,7 @@ class AgentRegistryAdapter:
|
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
nickname = nicknames.get(agent_name, agent_name.title())
|
|
382
|
-
today = datetime.now().strftime("%Y-%m-%d")
|
|
382
|
+
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
383
383
|
|
|
384
384
|
return f"""**{nickname}**: {task}
|
|
385
385
|
|
|
@@ -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,9 @@ 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(
|
|
247
|
+
def _validate_custom_api(
|
|
248
|
+
self, api_name: str, validation_config: Dict
|
|
249
|
+
) -> bool:
|
|
248
250
|
"""Validate a custom API key based on configuration.
|
|
249
251
|
|
|
250
252
|
Args:
|