claude-mpm 4.5.8__py3-none-any.whl → 4.5.12__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/__init__.py +20 -5
- claude_mpm/agents/agent_loader.py +19 -2
- claude_mpm/agents/base_agent_loader.py +5 -5
- claude_mpm/agents/frontmatter_validator.py +4 -4
- claude_mpm/agents/templates/agent-manager.json +3 -3
- claude_mpm/agents/templates/agentic-coder-optimizer.json +3 -3
- claude_mpm/agents/templates/api_qa.json +1 -1
- claude_mpm/agents/templates/clerk-ops.json +3 -3
- claude_mpm/agents/templates/code_analyzer.json +3 -3
- claude_mpm/agents/templates/dart_engineer.json +294 -0
- claude_mpm/agents/templates/data_engineer.json +3 -3
- claude_mpm/agents/templates/documentation.json +2 -2
- claude_mpm/agents/templates/engineer.json +2 -2
- claude_mpm/agents/templates/gcp_ops_agent.json +2 -2
- claude_mpm/agents/templates/imagemagick.json +1 -1
- claude_mpm/agents/templates/local_ops_agent.json +319 -41
- claude_mpm/agents/templates/memory_manager.json +2 -2
- claude_mpm/agents/templates/nextjs_engineer.json +2 -2
- claude_mpm/agents/templates/ops.json +2 -2
- claude_mpm/agents/templates/php-engineer.json +1 -1
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/prompt-engineer.json +6 -4
- claude_mpm/agents/templates/python_engineer.json +2 -2
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/react_engineer.json +3 -3
- claude_mpm/agents/templates/refactoring_engineer.json +3 -3
- claude_mpm/agents/templates/research.json +2 -2
- claude_mpm/agents/templates/security.json +2 -2
- claude_mpm/agents/templates/ticketing.json +2 -2
- claude_mpm/agents/templates/typescript_engineer.json +2 -2
- claude_mpm/agents/templates/vercel_ops_agent.json +2 -2
- claude_mpm/agents/templates/version_control.json +2 -2
- claude_mpm/agents/templates/web_qa.json +6 -6
- claude_mpm/agents/templates/web_ui.json +3 -3
- claude_mpm/cli/__init__.py +49 -19
- claude_mpm/cli/commands/agent_manager.py +3 -3
- claude_mpm/cli/commands/agents.py +6 -6
- claude_mpm/cli/commands/aggregate.py +4 -4
- claude_mpm/cli/commands/analyze.py +2 -2
- claude_mpm/cli/commands/analyze_code.py +1 -1
- claude_mpm/cli/commands/cleanup.py +3 -3
- claude_mpm/cli/commands/config.py +2 -2
- claude_mpm/cli/commands/configure.py +605 -21
- claude_mpm/cli/commands/dashboard.py +1 -1
- claude_mpm/cli/commands/debug.py +3 -3
- claude_mpm/cli/commands/doctor.py +1 -1
- claude_mpm/cli/commands/mcp.py +7 -7
- claude_mpm/cli/commands/mcp_command_router.py +1 -1
- claude_mpm/cli/commands/mcp_config.py +2 -2
- claude_mpm/cli/commands/mcp_external_commands.py +2 -2
- claude_mpm/cli/commands/mcp_install_commands.py +3 -3
- claude_mpm/cli/commands/mcp_pipx_config.py +2 -2
- claude_mpm/cli/commands/mcp_setup_external.py +3 -3
- claude_mpm/cli/commands/monitor.py +1 -1
- claude_mpm/cli/commands/mpm_init_handler.py +1 -1
- claude_mpm/cli/interactive/agent_wizard.py +1 -1
- claude_mpm/cli/parsers/configure_parser.py +5 -0
- claude_mpm/cli/parsers/search_parser.py +1 -1
- claude_mpm/cli/shared/argument_patterns.py +2 -2
- claude_mpm/cli/shared/base_command.py +1 -1
- claude_mpm/cli/startup_logging.py +4 -4
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/socketio_config.py +2 -2
- claude_mpm/core/__init__.py +53 -17
- claude_mpm/core/agent_session_manager.py +2 -2
- claude_mpm/core/api_validator.py +3 -3
- claude_mpm/core/base_service.py +10 -1
- claude_mpm/core/cache.py +2 -2
- claude_mpm/core/config.py +5 -5
- claude_mpm/core/config_aliases.py +4 -4
- claude_mpm/core/config_constants.py +1 -1
- claude_mpm/core/error_handler.py +1 -1
- claude_mpm/core/file_utils.py +5 -5
- claude_mpm/core/framework/formatters/capability_generator.py +5 -5
- claude_mpm/core/framework/loaders/agent_loader.py +1 -1
- claude_mpm/core/framework/processors/metadata_processor.py +1 -1
- claude_mpm/core/framework/processors/template_processor.py +3 -3
- claude_mpm/core/framework_loader.py +2 -2
- claude_mpm/core/log_manager.py +11 -4
- claude_mpm/core/logger.py +2 -2
- claude_mpm/core/optimized_startup.py +1 -1
- claude_mpm/core/output_style_manager.py +1 -1
- claude_mpm/core/service_registry.py +2 -2
- claude_mpm/core/session_manager.py +3 -3
- claude_mpm/core/shared/config_loader.py +1 -1
- claude_mpm/core/socketio_pool.py +2 -2
- claude_mpm/core/unified_agent_registry.py +2 -2
- claude_mpm/core/unified_config.py +6 -6
- claude_mpm/core/unified_paths.py +2 -2
- claude_mpm/dashboard/api/simple_directory.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +1 -1
- claude_mpm/hooks/claude_hooks/event_handlers.py +2 -2
- claude_mpm/hooks/claude_hooks/installer.py +9 -9
- claude_mpm/hooks/claude_hooks/response_tracking.py +16 -11
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +16 -13
- claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/hooks/validation_hooks.py +1 -1
- claude_mpm/init.py +4 -4
- claude_mpm/models/agent_session.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +5 -5
- claude_mpm/services/__init__.py +145 -161
- claude_mpm/services/agent_capabilities_service.py +1 -1
- claude_mpm/services/agents/agent_builder.py +4 -4
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +3 -3
- claude_mpm/services/agents/deployment/deployment_config_loader.py +21 -0
- claude_mpm/services/agents/deployment/deployment_wrapper.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +2 -2
- claude_mpm/services/agents/loading/base_agent_manager.py +12 -2
- claude_mpm/services/agents/local_template_manager.py +5 -5
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
- claude_mpm/services/agents/registry/modification_tracker.py +19 -11
- 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 -3
- claude_mpm/services/cli/agent_validation_service.py +1 -1
- claude_mpm/services/cli/session_manager.py +2 -2
- claude_mpm/services/core/path_resolver.py +1 -1
- claude_mpm/services/diagnostics/checks/agent_check.py +1 -1
- claude_mpm/services/diagnostics/checks/claude_code_check.py +2 -2
- claude_mpm/services/diagnostics/checks/common_issues_check.py +3 -3
- claude_mpm/services/diagnostics/checks/configuration_check.py +2 -2
- claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
- claude_mpm/services/diagnostics/checks/mcp_check.py +1 -1
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +9 -9
- claude_mpm/services/diagnostics/checks/monitor_check.py +1 -1
- claude_mpm/services/diagnostics/doctor_reporter.py +1 -1
- claude_mpm/services/event_aggregator.py +1 -1
- claude_mpm/services/event_bus/event_bus.py +7 -2
- claude_mpm/services/events/consumers/dead_letter.py +2 -2
- claude_mpm/services/framework_claude_md_generator/__init__.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +3 -3
- claude_mpm/services/framework_claude_md_generator/version_manager.py +1 -1
- claude_mpm/services/hook_installer_service.py +7 -7
- claude_mpm/services/infrastructure/context_preservation.py +7 -7
- claude_mpm/services/infrastructure/daemon_manager.py +5 -5
- claude_mpm/services/mcp_config_manager.py +169 -48
- claude_mpm/services/mcp_gateway/__init__.py +98 -94
- claude_mpm/services/mcp_gateway/auto_configure.py +5 -5
- claude_mpm/services/mcp_gateway/config/config_loader.py +2 -2
- claude_mpm/services/mcp_gateway/config/configuration.py +3 -3
- claude_mpm/services/mcp_gateway/core/process_pool.py +3 -3
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +2 -2
- claude_mpm/services/mcp_gateway/core/startup_verification.py +1 -1
- claude_mpm/services/mcp_gateway/main.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +4 -2
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +2 -1
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +1 -1
- claude_mpm/services/mcp_gateway/tools/hello_world.py +1 -1
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +5 -5
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +2 -2
- claude_mpm/services/mcp_service_verifier.py +1 -1
- claude_mpm/services/memory/builder.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +2 -1
- claude_mpm/services/memory/indexed_memory.py +3 -3
- claude_mpm/services/monitor/daemon.py +1 -1
- claude_mpm/services/monitor/daemon_manager.py +9 -9
- claude_mpm/services/monitor/event_emitter.py +1 -1
- claude_mpm/services/monitor/handlers/file.py +1 -1
- claude_mpm/services/monitor/handlers/hooks.py +3 -3
- claude_mpm/services/monitor/management/lifecycle.py +7 -7
- claude_mpm/services/monitor/server.py +2 -2
- claude_mpm/services/orphan_detection.py +788 -0
- claude_mpm/services/port_manager.py +2 -2
- claude_mpm/services/project/analyzer.py +3 -3
- claude_mpm/services/project/archive_manager.py +13 -13
- claude_mpm/services/project/dependency_analyzer.py +4 -4
- claude_mpm/services/project/documentation_manager.py +4 -4
- claude_mpm/services/project/enhanced_analyzer.py +8 -8
- claude_mpm/services/project/registry.py +4 -4
- claude_mpm/services/project_port_allocator.py +597 -0
- claude_mpm/services/response_tracker.py +1 -1
- claude_mpm/services/session_management_service.py +1 -1
- claude_mpm/services/session_manager.py +6 -4
- claude_mpm/services/socketio/event_normalizer.py +1 -1
- claude_mpm/services/socketio/handlers/code_analysis.py +14 -12
- claude_mpm/services/socketio/handlers/file.py +1 -1
- claude_mpm/services/socketio/migration_utils.py +1 -1
- claude_mpm/services/socketio/server/core.py +1 -1
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +1 -1
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +4 -4
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +1 -1
- claude_mpm/services/unified/config_strategies/config_schema.py +4 -4
- claude_mpm/services/unified/config_strategies/context_strategy.py +6 -6
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +10 -10
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +5 -5
- claude_mpm/services/unified/config_strategies/unified_config_service.py +8 -8
- claude_mpm/services/unified/config_strategies/validation_strategy.py +15 -15
- claude_mpm/services/unified/deployment_strategies/base.py +4 -4
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +15 -15
- claude_mpm/services/unified/deployment_strategies/local.py +9 -9
- claude_mpm/services/unified/deployment_strategies/utils.py +9 -9
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -7
- claude_mpm/services/unified/unified_config.py +5 -5
- claude_mpm/services/unified/unified_deployment.py +2 -2
- claude_mpm/services/utility_service.py +1 -1
- claude_mpm/services/version_control/conflict_resolution.py +2 -2
- claude_mpm/services/version_control/git_operations.py +3 -3
- claude_mpm/services/version_control/semantic_versioning.py +13 -13
- claude_mpm/services/version_control/version_parser.py +1 -1
- claude_mpm/storage/state_storage.py +12 -13
- claude_mpm/tools/code_tree_analyzer.py +5 -5
- claude_mpm/tools/code_tree_builder.py +4 -4
- claude_mpm/tools/socketio_debug.py +1 -1
- claude_mpm/utils/agent_dependency_loader.py +4 -4
- claude_mpm/utils/common.py +2 -2
- claude_mpm/utils/config_manager.py +3 -3
- claude_mpm/utils/dependency_cache.py +2 -2
- claude_mpm/utils/dependency_strategies.py +6 -6
- claude_mpm/utils/file_utils.py +11 -11
- claude_mpm/utils/log_cleanup.py +1 -1
- claude_mpm/utils/path_operations.py +1 -1
- claude_mpm/validation/agent_validator.py +2 -2
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/METADATA +1 -1
- {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/RECORD +226 -223
- {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/WHEEL +0 -0
- {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.5.8.dist-info → claude_mpm-4.5.12.dist-info}/top_level.txt +0 -0
@@ -78,7 +78,7 @@ class MCPAutoConfigurator:
|
|
78
78
|
return False
|
79
79
|
|
80
80
|
try:
|
81
|
-
with
|
81
|
+
with self.claude_config_path.open() as f:
|
82
82
|
config = json.load(f)
|
83
83
|
|
84
84
|
# Check if claude-mpm-gateway is configured
|
@@ -131,7 +131,7 @@ class MCPAutoConfigurator:
|
|
131
131
|
return False
|
132
132
|
|
133
133
|
try:
|
134
|
-
with
|
134
|
+
with self.preference_file.open() as f:
|
135
135
|
prefs = json.load(f)
|
136
136
|
return prefs.get("asked", False)
|
137
137
|
except (OSError, json.JSONDecodeError):
|
@@ -148,7 +148,7 @@ class MCPAutoConfigurator:
|
|
148
148
|
}
|
149
149
|
|
150
150
|
try:
|
151
|
-
with
|
151
|
+
with self.preference_file.open("w") as f:
|
152
152
|
json.dump(prefs, f, indent=2)
|
153
153
|
except Exception as e:
|
154
154
|
self.logger.debug(f"Could not save preference: {e}")
|
@@ -244,7 +244,7 @@ class MCPAutoConfigurator:
|
|
244
244
|
}
|
245
245
|
|
246
246
|
# Save configuration
|
247
|
-
with
|
247
|
+
with self.claude_config_path.open("w") as f:
|
248
248
|
json.dump(config, f, indent=2)
|
249
249
|
|
250
250
|
print(f"✅ Configuration saved to: {self.claude_config_path}")
|
@@ -284,7 +284,7 @@ class MCPAutoConfigurator:
|
|
284
284
|
"""Load existing config or create new one."""
|
285
285
|
if self.claude_config_path.exists():
|
286
286
|
try:
|
287
|
-
with
|
287
|
+
with self.claude_config_path.open() as f:
|
288
288
|
return json.load(f)
|
289
289
|
except json.JSONDecodeError:
|
290
290
|
self.logger.warning("Existing config is invalid JSON, creating new")
|
@@ -97,7 +97,7 @@ class MCPConfigLoader:
|
|
97
97
|
self.logger.error(f"Configuration file not found: {expanded_path}")
|
98
98
|
return None
|
99
99
|
|
100
|
-
with open(
|
100
|
+
with expanded_path.open() as f:
|
101
101
|
config = yaml.safe_load(f)
|
102
102
|
|
103
103
|
self.logger.info(f"Configuration loaded from {expanded_path}")
|
@@ -271,7 +271,7 @@ class MCPConfigLoader:
|
|
271
271
|
expanded_path = path.expanduser()
|
272
272
|
expanded_path.parent.mkdir(parents=True, exist_ok=True)
|
273
273
|
|
274
|
-
with open(
|
274
|
+
with expanded_path.open("w") as f:
|
275
275
|
yaml.dump(
|
276
276
|
MCPConfiguration.DEFAULT_CONFIG,
|
277
277
|
f,
|
@@ -155,7 +155,7 @@ class MCPConfiguration(BaseMCPService, IMCPConfiguration):
|
|
155
155
|
self.log_warning(f"Configuration file not found: {config_path}")
|
156
156
|
return True # Not an error, use defaults
|
157
157
|
|
158
|
-
with open(
|
158
|
+
with config_path.open() as f:
|
159
159
|
if config_path.suffix in [".yaml", ".yml"]:
|
160
160
|
loaded_config = yaml.safe_load(f) or {}
|
161
161
|
else:
|
@@ -171,7 +171,7 @@ class MCPConfiguration(BaseMCPService, IMCPConfiguration):
|
|
171
171
|
return True
|
172
172
|
|
173
173
|
except yaml.YAMLError as e:
|
174
|
-
raise MCPConfigurationError(f"Failed to parse YAML configuration: {e}")
|
174
|
+
raise MCPConfigurationError(f"Failed to parse YAML configuration: {e}") from e
|
175
175
|
except Exception as e:
|
176
176
|
self.log_error(f"Failed to load configuration: {e}")
|
177
177
|
return False
|
@@ -364,7 +364,7 @@ class MCPConfiguration(BaseMCPService, IMCPConfiguration):
|
|
364
364
|
save_path = Path(save_path).expanduser()
|
365
365
|
save_path.parent.mkdir(parents=True, exist_ok=True)
|
366
366
|
|
367
|
-
with open(
|
367
|
+
with save_path.open("w") as f:
|
368
368
|
yaml.dump(
|
369
369
|
self._config_data, f, default_flow_style=False, sort_keys=True
|
370
370
|
)
|
@@ -190,7 +190,7 @@ class MCPProcessPool:
|
|
190
190
|
|
191
191
|
# Write process info to file for debugging
|
192
192
|
info_file = self.pool_dir / f"{server_name}_{process.pid}.json"
|
193
|
-
with open(
|
193
|
+
with info_file.open("w") as f:
|
194
194
|
json.dump(self._process_info[server_name], f, indent=2)
|
195
195
|
|
196
196
|
return process
|
@@ -934,7 +934,7 @@ async def pre_warm_mcp_servers():
|
|
934
934
|
#
|
935
935
|
# if claude_config_path.exists():
|
936
936
|
# try:
|
937
|
-
# with open(
|
937
|
+
# with claude_config_path.open() as f:
|
938
938
|
# config_data = json.load(f)
|
939
939
|
# mcp_servers = config_data.get("mcpServers", {})
|
940
940
|
# configs.update(mcp_servers)
|
@@ -945,7 +945,7 @@ async def pre_warm_mcp_servers():
|
|
945
945
|
# mcp_config_path = Path.cwd() / ".mcp.json"
|
946
946
|
# if mcp_config_path.exists():
|
947
947
|
# try:
|
948
|
-
# with open(
|
948
|
+
# with mcp_config_path.open() as f:
|
949
949
|
# config_data = json.load(f)
|
950
950
|
# mcp_servers = config_data.get("mcpServers", {})
|
951
951
|
# configs.update(mcp_servers)
|
@@ -149,7 +149,7 @@ class MCPGatewayManager:
|
|
149
149
|
return None
|
150
150
|
|
151
151
|
try:
|
152
|
-
with
|
152
|
+
with self.instance_file.open() as f:
|
153
153
|
instance_info = json.load(f)
|
154
154
|
|
155
155
|
# Validate PID is still running
|
@@ -195,7 +195,7 @@ class MCPGatewayManager:
|
|
195
195
|
"lock_file": str(self.lock_file),
|
196
196
|
}
|
197
197
|
|
198
|
-
with
|
198
|
+
with self.instance_file.open("w") as f:
|
199
199
|
json.dump(instance_info, f, indent=2)
|
200
200
|
|
201
201
|
self._current_instance = instance_info
|
@@ -63,7 +63,7 @@ except ImportError:
|
|
63
63
|
try:
|
64
64
|
from claude_mpm.services.mcp_gateway.server.mcp_gateway import MCPGateway
|
65
65
|
except ImportError as e:
|
66
|
-
raise ImportError(f"Critical: Cannot import MCPGateway server: {e}")
|
66
|
+
raise ImportError(f"Critical: Cannot import MCPGateway server: {e}") from e
|
67
67
|
|
68
68
|
try:
|
69
69
|
from claude_mpm.services.mcp_gateway.server.stdio_handler import StdioHandler
|
@@ -224,7 +224,8 @@ class MCPServiceRegistry(ManagerBase):
|
|
224
224
|
try:
|
225
225
|
import asyncio
|
226
226
|
|
227
|
-
asyncio.create_task(instance.stop())
|
227
|
+
_task = asyncio.create_task(instance.stop()) # noqa: RUF006
|
228
|
+
# Fire-and-forget shutdown during unregister
|
228
229
|
except Exception as e:
|
229
230
|
self.logger.warning(
|
230
231
|
f"Error stopping service {interface.__name__}: {e}"
|
@@ -335,7 +336,8 @@ class MCPServiceRegistry(ManagerBase):
|
|
335
336
|
try:
|
336
337
|
import asyncio
|
337
338
|
|
338
|
-
asyncio.create_task(instance.stop())
|
339
|
+
_task = asyncio.create_task(instance.stop()) # noqa: RUF006
|
340
|
+
# Fire-and-forget shutdown during clear
|
339
341
|
except Exception as e:
|
340
342
|
self.logger.warning(f"Error stopping service: {e}")
|
341
343
|
|
@@ -216,7 +216,8 @@ class ToolRegistry(BaseMCPService, IMCPToolRegistry):
|
|
216
216
|
|
217
217
|
# Shutdown adapter (outside lock to avoid deadlock)
|
218
218
|
try:
|
219
|
-
asyncio.create_task(adapter.shutdown())
|
219
|
+
_task = asyncio.create_task(adapter.shutdown()) # noqa: RUF006
|
220
|
+
# Fire-and-forget shutdown during tool unregister
|
220
221
|
except Exception as e:
|
221
222
|
self.log_warning(f"Error shutting down tool adapter {tool_name}: {e}")
|
222
223
|
|
@@ -139,7 +139,7 @@ class StdioHandler(BaseMCPService, IMCPCommunication):
|
|
139
139
|
self._metrics["errors"] += 1
|
140
140
|
raise
|
141
141
|
|
142
|
-
async def receive_message(self) -> Optional[Dict[str, Any]]:
|
142
|
+
async def receive_message(self) -> Optional[Dict[str, Any]]:
|
143
143
|
"""
|
144
144
|
Receive a message from the MCP client via stdin.
|
145
145
|
|
@@ -306,7 +306,7 @@ class DocumentSummarizerTool(BaseToolAdapter):
|
|
306
306
|
continue
|
307
307
|
|
308
308
|
# If all fail, read as binary and decode with errors='ignore'
|
309
|
-
with open(
|
309
|
+
with file_path.open("rb") as f:
|
310
310
|
content = f.read()
|
311
311
|
return content.decode("utf-8", errors="ignore")
|
312
312
|
|
@@ -204,7 +204,7 @@ class HelloWorldTool(BaseToolAdapter):
|
|
204
204
|
self.greeting_history: List[Dict[str, Any]] = []
|
205
205
|
self.max_history_size = 100
|
206
206
|
|
207
|
-
def validate_parameters(self, parameters: Dict[str, Any]) -> bool:
|
207
|
+
def validate_parameters(self, parameters: Dict[str, Any]) -> bool:
|
208
208
|
"""
|
209
209
|
Enhanced parameter validation with detailed error messages.
|
210
210
|
|
@@ -8,7 +8,7 @@ Provides non-blocking version checking for MCP tools like kuzu-memory.
|
|
8
8
|
|
9
9
|
import asyncio
|
10
10
|
import json
|
11
|
-
from datetime import datetime, timedelta
|
11
|
+
from datetime import datetime, timedelta, timezone
|
12
12
|
from pathlib import Path
|
13
13
|
from typing import Any, Dict, Optional
|
14
14
|
|
@@ -83,7 +83,7 @@ class PackageVersionChecker:
|
|
83
83
|
"latest": latest,
|
84
84
|
"update_available": version.parse(latest)
|
85
85
|
> version.parse(current_version),
|
86
|
-
"checked_at": datetime.now().isoformat(),
|
86
|
+
"checked_at": datetime.now(timezone.utc).isoformat(),
|
87
87
|
}
|
88
88
|
self._write_cache(cache_file, result)
|
89
89
|
return result
|
@@ -133,12 +133,12 @@ class PackageVersionChecker:
|
|
133
133
|
return None
|
134
134
|
|
135
135
|
try:
|
136
|
-
with open(
|
136
|
+
with cache_file.open() as f:
|
137
137
|
data = json.load(f)
|
138
138
|
|
139
139
|
# Check TTL
|
140
140
|
checked_at = datetime.fromisoformat(data["checked_at"])
|
141
|
-
if datetime.now() - checked_at < timedelta(seconds=ttl):
|
141
|
+
if datetime.now(timezone.utc) - checked_at < timedelta(seconds=ttl):
|
142
142
|
return data
|
143
143
|
except Exception as e:
|
144
144
|
self.logger.debug(f"Cache read error: {e}")
|
@@ -154,7 +154,7 @@ class PackageVersionChecker:
|
|
154
154
|
data: Data to cache
|
155
155
|
"""
|
156
156
|
try:
|
157
|
-
with open(
|
157
|
+
with cache_file.open("w") as f:
|
158
158
|
json.dump(data, f, indent=2)
|
159
159
|
except Exception as e:
|
160
160
|
self.logger.debug(f"Cache write failed: {e}")
|
@@ -36,7 +36,7 @@ class UpdatePreferences:
|
|
36
36
|
"""
|
37
37
|
if cls.PREFS_FILE.exists():
|
38
38
|
try:
|
39
|
-
with
|
39
|
+
with cls.PREFS_FILE.open() as f:
|
40
40
|
return json.load(f)
|
41
41
|
except (OSError, json.JSONDecodeError):
|
42
42
|
# Return empty dict if file is corrupted or unreadable
|
@@ -53,7 +53,7 @@ class UpdatePreferences:
|
|
53
53
|
"""
|
54
54
|
cls.PREFS_FILE.parent.mkdir(parents=True, exist_ok=True)
|
55
55
|
try:
|
56
|
-
with
|
56
|
+
with cls.PREFS_FILE.open("w") as f:
|
57
57
|
json.dump(prefs, f, indent=2)
|
58
58
|
except OSError:
|
59
59
|
# Silently fail if we can't write preferences
|
@@ -458,7 +458,7 @@ class MemoryBuilder(LoggerMixin):
|
|
458
458
|
import tomllib
|
459
459
|
except ImportError:
|
460
460
|
import tomli as tomllib
|
461
|
-
with open(
|
461
|
+
with file_path.open("rb") as f:
|
462
462
|
config_data = tomllib.load(f)
|
463
463
|
items = self._extract_from_toml_config(config_data, source)
|
464
464
|
extracted_items.extend(items)
|
@@ -194,7 +194,8 @@ class SharedPromptCache(BaseService):
|
|
194
194
|
with cls._lock:
|
195
195
|
if cls._instance is not None:
|
196
196
|
if cls._instance.running:
|
197
|
-
asyncio.create_task(cls._instance.stop())
|
197
|
+
_task = asyncio.create_task(cls._instance.stop()) # noqa: RUF006
|
198
|
+
# Fire-and-forget cleanup task during test reset
|
198
199
|
cls._instance = None
|
199
200
|
|
200
201
|
async def _initialize(self) -> None:
|
@@ -213,7 +213,7 @@ class InvertedIndex:
|
|
213
213
|
"doc_freqs": dict(self.doc_freqs),
|
214
214
|
"doc_count": self.doc_count,
|
215
215
|
}
|
216
|
-
with open(
|
216
|
+
with path.open("wb") as f:
|
217
217
|
pickle.dump(data, f)
|
218
218
|
|
219
219
|
def load(self, path: Path):
|
@@ -221,7 +221,7 @@ class InvertedIndex:
|
|
221
221
|
if not path.exists():
|
222
222
|
return
|
223
223
|
|
224
|
-
with open(
|
224
|
+
with path.open("rb") as f:
|
225
225
|
data = pickle.load(f)
|
226
226
|
|
227
227
|
self.index = defaultdict(set, {k: set(v) for k, v in data["index"].items()})
|
@@ -597,7 +597,7 @@ class IndexedMemoryService:
|
|
597
597
|
# Load other indexes
|
598
598
|
indexes_path = self.data_dir / "indexes.pkl"
|
599
599
|
if indexes_path.exists():
|
600
|
-
with open(
|
600
|
+
with indexes_path.open("rb") as f:
|
601
601
|
data = pickle.load(f)
|
602
602
|
|
603
603
|
self.memories = data.get("memories", {})
|
@@ -121,7 +121,7 @@ class UnifiedMonitorDaemon:
|
|
121
121
|
"""
|
122
122
|
return self.daemon_manager.cleanup_port_conflicts()
|
123
123
|
|
124
|
-
def _start_daemon(self, force_restart: bool = False) -> bool:
|
124
|
+
def _start_daemon(self, force_restart: bool = False) -> bool:
|
125
125
|
"""Start as background daemon process.
|
126
126
|
|
127
127
|
Args:
|
@@ -302,7 +302,7 @@ class DaemonManager:
|
|
302
302
|
if not self.pid_file.exists():
|
303
303
|
return True
|
304
304
|
|
305
|
-
with
|
305
|
+
with self.pid_file.open() as f:
|
306
306
|
pid = int(f.read().strip())
|
307
307
|
|
308
308
|
self.logger.info(f"Found PID {pid} in PID file")
|
@@ -397,7 +397,7 @@ class DaemonManager:
|
|
397
397
|
# First check PID file
|
398
398
|
if self.pid_file.exists():
|
399
399
|
try:
|
400
|
-
with
|
400
|
+
with self.pid_file.open() as f:
|
401
401
|
pid = int(f.read().strip())
|
402
402
|
|
403
403
|
# Verify process exists
|
@@ -604,7 +604,7 @@ class DaemonManager:
|
|
604
604
|
# Check if PID file was written
|
605
605
|
if self.pid_file.exists():
|
606
606
|
try:
|
607
|
-
with
|
607
|
+
with self.pid_file.open() as f:
|
608
608
|
written_pid = int(f.read().strip())
|
609
609
|
if written_pid == pid:
|
610
610
|
# PID file written correctly, check port
|
@@ -798,7 +798,7 @@ class DaemonManager:
|
|
798
798
|
if not self.pid_file.exists():
|
799
799
|
return None
|
800
800
|
|
801
|
-
with
|
801
|
+
with self.pid_file.open() as f:
|
802
802
|
return int(f.read().strip())
|
803
803
|
|
804
804
|
except Exception as e:
|
@@ -809,7 +809,7 @@ class DaemonManager:
|
|
809
809
|
"""Write current PID to PID file."""
|
810
810
|
try:
|
811
811
|
self.pid_file.parent.mkdir(parents=True, exist_ok=True)
|
812
|
-
with
|
812
|
+
with self.pid_file.open("w") as f:
|
813
813
|
f.write(str(os.getpid()))
|
814
814
|
self.logger.debug(f"PID file written: {self.pid_file}")
|
815
815
|
except Exception as e:
|
@@ -863,7 +863,7 @@ class DaemonManager:
|
|
863
863
|
|
864
864
|
# Redirect stdout and stderr to log file
|
865
865
|
self.log_file.parent.mkdir(parents=True, exist_ok=True)
|
866
|
-
with
|
866
|
+
with self.log_file.open("a") as log_out:
|
867
867
|
os.dup2(log_out.fileno(), sys.stdout.fileno())
|
868
868
|
os.dup2(log_out.fileno(), sys.stderr.fileno())
|
869
869
|
|
@@ -903,7 +903,7 @@ class DaemonManager:
|
|
903
903
|
continue
|
904
904
|
|
905
905
|
try:
|
906
|
-
with
|
906
|
+
with self.startup_status_file.open() as f:
|
907
907
|
status = f.read().strip()
|
908
908
|
|
909
909
|
if status == "success":
|
@@ -935,7 +935,7 @@ class DaemonManager:
|
|
935
935
|
try:
|
936
936
|
# Don't check if file exists - we need to write to it regardless
|
937
937
|
# The parent created it and is waiting for us to update it
|
938
|
-
with
|
938
|
+
with self.startup_status_file.open("w") as f:
|
939
939
|
f.write("success")
|
940
940
|
f.flush() # Ensure it's written immediately
|
941
941
|
os.fsync(f.fileno()) # Force write to disk
|
@@ -948,7 +948,7 @@ class DaemonManager:
|
|
948
948
|
if self.startup_status_file:
|
949
949
|
try:
|
950
950
|
# Don't check if file exists - we need to write to it regardless
|
951
|
-
with
|
951
|
+
with self.startup_status_file.open("w") as f:
|
952
952
|
f.write(f"error:{error}")
|
953
953
|
f.flush() # Ensure it's written immediately
|
954
954
|
os.fsync(f.fileno()) # Force write to disk
|
@@ -85,7 +85,7 @@ class AsyncEventEmitter:
|
|
85
85
|
},
|
86
86
|
)
|
87
87
|
|
88
|
-
self.logger.
|
88
|
+
self.logger.debug("AsyncEventEmitter initialized with connection pooling")
|
89
89
|
|
90
90
|
except Exception as e:
|
91
91
|
self.logger.error(f"Error initializing AsyncEventEmitter: {e}")
|
@@ -236,10 +236,10 @@ class HookHandler:
|
|
236
236
|
},
|
237
237
|
)
|
238
238
|
|
239
|
-
# Remove from active sessions after a delay
|
240
|
-
asyncio.create_task(
|
239
|
+
# Remove from active sessions after a delay (5 minutes)
|
240
|
+
_task = asyncio.create_task( # noqa: RUF006
|
241
241
|
self._cleanup_session(session_id, delay=300)
|
242
|
-
) #
|
242
|
+
) # Fire-and-forget cleanup task
|
243
243
|
|
244
244
|
self.logger.info(f"Claude Code session ended: {session_id}")
|
245
245
|
else:
|
@@ -127,14 +127,14 @@ class DaemonLifecycle:
|
|
127
127
|
# Redirect stdout and stderr
|
128
128
|
if self.log_file:
|
129
129
|
# Redirect to log file
|
130
|
-
with
|
130
|
+
with self.log_file.open("a") as log_out:
|
131
131
|
os.dup2(log_out.fileno(), sys.stdout.fileno())
|
132
132
|
os.dup2(log_out.fileno(), sys.stderr.fileno())
|
133
133
|
else:
|
134
134
|
# Default to a daemon log file instead of /dev/null for errors
|
135
135
|
default_log = Path.home() / ".claude-mpm" / "monitor-daemon.log"
|
136
136
|
default_log.parent.mkdir(parents=True, exist_ok=True)
|
137
|
-
with open(
|
137
|
+
with default_log.open("a") as log_out:
|
138
138
|
os.dup2(log_out.fileno(), sys.stdout.fileno())
|
139
139
|
os.dup2(log_out.fileno(), sys.stderr.fileno())
|
140
140
|
|
@@ -149,7 +149,7 @@ class DaemonLifecycle:
|
|
149
149
|
self.pid_file.parent.mkdir(parents=True, exist_ok=True)
|
150
150
|
|
151
151
|
# Write PID
|
152
|
-
with
|
152
|
+
with self.pid_file.open("w") as f:
|
153
153
|
f.write(str(os.getpid()))
|
154
154
|
|
155
155
|
self.logger.debug(f"PID file written: {self.pid_file}")
|
@@ -199,7 +199,7 @@ class DaemonLifecycle:
|
|
199
199
|
if not self.pid_file.exists():
|
200
200
|
return None
|
201
201
|
|
202
|
-
with
|
202
|
+
with self.pid_file.open() as f:
|
203
203
|
pid_str = f.read().strip()
|
204
204
|
return int(pid_str) if pid_str else None
|
205
205
|
|
@@ -385,7 +385,7 @@ class DaemonLifecycle:
|
|
385
385
|
try:
|
386
386
|
# Check if status file exists and read it
|
387
387
|
if self.startup_status_file and Path(self.startup_status_file).exists():
|
388
|
-
with
|
388
|
+
with self.startup_status_file.open() as f:
|
389
389
|
status = f.read().strip()
|
390
390
|
|
391
391
|
if status == "success":
|
@@ -437,7 +437,7 @@ class DaemonLifecycle:
|
|
437
437
|
"""Report successful startup to parent process."""
|
438
438
|
if self.startup_status_file:
|
439
439
|
try:
|
440
|
-
with
|
440
|
+
with self.startup_status_file.open("w") as f:
|
441
441
|
f.write("success")
|
442
442
|
except Exception as e:
|
443
443
|
self.logger.error(f"Failed to report startup success: {e}")
|
@@ -450,7 +450,7 @@ class DaemonLifecycle:
|
|
450
450
|
"""
|
451
451
|
if self.startup_status_file:
|
452
452
|
try:
|
453
|
-
with
|
453
|
+
with self.startup_status_file.open("w") as f:
|
454
454
|
f.write(f"error:{error_msg}")
|
455
455
|
except Exception:
|
456
456
|
pass # Can't report if file write fails
|
@@ -313,7 +313,7 @@ class UnifiedMonitorServer:
|
|
313
313
|
async def dashboard_index(request):
|
314
314
|
template_path = dashboard_dir / "templates" / "index.html"
|
315
315
|
if template_path.exists():
|
316
|
-
with open(
|
316
|
+
with template_path.open() as f:
|
317
317
|
content = f.read()
|
318
318
|
return web.Response(text=content, content_type="text/html")
|
319
319
|
return web.Response(text="Dashboard not found", status=404)
|
@@ -365,7 +365,7 @@ class UnifiedMonitorServer:
|
|
365
365
|
return web.Response(text=f"Error: {e!s}", status=500)
|
366
366
|
|
367
367
|
# File content endpoint for file viewer
|
368
|
-
async def api_file_handler(request):
|
368
|
+
async def api_file_handler(request):
|
369
369
|
"""Handle file content requests."""
|
370
370
|
import json
|
371
371
|
import os
|