claude-mpm 4.3.12__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/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 +46 -2
- claude_mpm/cli/commands/search.py +41 -34
- claude_mpm/cli/interactive/agent_wizard.py +2 -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 +3 -5
- claude_mpm/cli/utils.py +1 -1
- 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 +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/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 +2 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +9 -3
- 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/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_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 +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 +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 +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 +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.12.dist-info → claude_mpm-4.3.13.dist-info}/METADATA +1 -1
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/RECORD +199 -199
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/WHEEL +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.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,7 @@ class AgentWizard:
|
|
|
600
600
|
tier="project",
|
|
601
601
|
)
|
|
602
602
|
|
|
603
|
-
def _manage_single_agent(self, template: LocalAgentTemplate) -> Tuple[bool, str]:
|
|
603
|
+
def _manage_single_agent(self, template: LocalAgentTemplate) -> Tuple[bool, str]: # noqa: PLR0911
|
|
604
604
|
"""Manage a single agent."""
|
|
605
605
|
print(f"\n🔧 Managing Agent: {template.agent_id}")
|
|
606
606
|
print(f" Name: {template.metadata.get('name', template.agent_id)}")
|
|
@@ -815,7 +815,7 @@ class AgentWizard:
|
|
|
815
815
|
return self.manager.project_agents_dir / f"{template.agent_id}.json"
|
|
816
816
|
return self.manager.user_agents_dir / f"{template.agent_id}.json"
|
|
817
817
|
|
|
818
|
-
def _interactive_delete_menu(self, templates: list) -> Tuple[bool, str]:
|
|
818
|
+
def _interactive_delete_menu(self, templates: list) -> Tuple[bool, str]: # noqa: PLR0911
|
|
819
819
|
"""Interactive deletion menu for multiple agents."""
|
|
820
820
|
print("\n🗑️ Delete Agents")
|
|
821
821
|
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
|
|
@@ -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
|
@@ -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:
|