claude-mpm 4.5.11__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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/frontmatter_validator.py +4 -4
- 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 +14 -14
- 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/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/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 +4 -4
- 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 +4 -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/services/connection_manager_http.py +7 -2
- 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 +2 -2
- 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_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/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 +1 -1
- claude_mpm/services/claude_session_logger.py +1 -1
- 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 +10 -10
- 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/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 +13 -16
- 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 +7 -11
- claude_mpm/services/session_management_service.py +1 -1
- 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.11.dist-info → claude_mpm-4.5.12.dist-info}/METADATA +1 -1
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.12.dist-info}/RECORD +183 -183
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.12.dist-info}/WHEEL +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.12.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.12.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.12.dist-info}/top_level.txt +0 -0
|
@@ -114,7 +114,7 @@ class CommonIssuesCheck(BaseDiagnosticCheck):
|
|
|
114
114
|
# Try to count conversations
|
|
115
115
|
conversation_count = 0
|
|
116
116
|
try:
|
|
117
|
-
with open(
|
|
117
|
+
with claude_json_path.open() as f:
|
|
118
118
|
data = json.load(f)
|
|
119
119
|
if isinstance(data, dict) and "conversations" in data:
|
|
120
120
|
conversation_count = len(data["conversations"])
|
|
@@ -283,10 +283,10 @@ class CommonIssuesCheck(BaseDiagnosticCheck):
|
|
|
283
283
|
try:
|
|
284
284
|
import yaml
|
|
285
285
|
|
|
286
|
-
with open(
|
|
286
|
+
with user_config.open() as f:
|
|
287
287
|
user_data = yaml.safe_load(f) or {}
|
|
288
288
|
|
|
289
|
-
with open(
|
|
289
|
+
with project_config.open() as f:
|
|
290
290
|
project_data = yaml.safe_load(f) or {}
|
|
291
291
|
|
|
292
292
|
# Check for conflicting keys
|
|
@@ -91,7 +91,7 @@ class ConfigurationCheck(BaseDiagnosticCheck):
|
|
|
91
91
|
)
|
|
92
92
|
|
|
93
93
|
try:
|
|
94
|
-
with open(
|
|
94
|
+
with config_path.open() as f:
|
|
95
95
|
config = yaml.safe_load(f)
|
|
96
96
|
|
|
97
97
|
issues = self._validate_config_structure(config)
|
|
@@ -143,7 +143,7 @@ class ConfigurationCheck(BaseDiagnosticCheck):
|
|
|
143
143
|
)
|
|
144
144
|
|
|
145
145
|
try:
|
|
146
|
-
with open(
|
|
146
|
+
with config_path.open() as f:
|
|
147
147
|
config = yaml.safe_load(f)
|
|
148
148
|
|
|
149
149
|
issues = self._validate_config_structure(config)
|
|
@@ -138,7 +138,7 @@ class InstallationCheck(BaseDiagnosticCheck):
|
|
|
138
138
|
details={"error": str(e)},
|
|
139
139
|
)
|
|
140
140
|
|
|
141
|
-
def _check_installation_method(self) -> DiagnosticResult:
|
|
141
|
+
def _check_installation_method(self) -> DiagnosticResult:
|
|
142
142
|
"""Detect how claude-mpm was installed."""
|
|
143
143
|
methods_found = []
|
|
144
144
|
details = {}
|
|
@@ -369,7 +369,7 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
|
369
369
|
stderr_output = stderr_data.decode(
|
|
370
370
|
"utf-8", errors="ignore"
|
|
371
371
|
)[:200]
|
|
372
|
-
except:
|
|
372
|
+
except (asyncio.TimeoutError, OSError):
|
|
373
373
|
pass
|
|
374
374
|
|
|
375
375
|
if stderr_output:
|
|
@@ -391,7 +391,7 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
|
391
391
|
stderr_output = stderr_data.decode(
|
|
392
392
|
"utf-8", errors="ignore"
|
|
393
393
|
)[:200]
|
|
394
|
-
except:
|
|
394
|
+
except (asyncio.TimeoutError, OSError):
|
|
395
395
|
pass
|
|
396
396
|
|
|
397
397
|
if stderr_output:
|
|
@@ -778,7 +778,7 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
|
778
778
|
return None
|
|
779
779
|
|
|
780
780
|
try:
|
|
781
|
-
with open(
|
|
781
|
+
with claude_config_path.open() as f:
|
|
782
782
|
config = json.load(f)
|
|
783
783
|
|
|
784
784
|
mcp_servers = config.get("mcpServers", {})
|
|
@@ -869,7 +869,7 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
|
869
869
|
|
|
870
870
|
# Create backup
|
|
871
871
|
backup_path = config_path.with_suffix(".json.backup")
|
|
872
|
-
with open(
|
|
872
|
+
with backup_path.open("w") as f:
|
|
873
873
|
json.dump(config, f, indent=2)
|
|
874
874
|
|
|
875
875
|
# Update the configuration - ensure we're setting the exact new_args
|
|
@@ -884,11 +884,11 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
|
884
884
|
return False
|
|
885
885
|
|
|
886
886
|
# Write updated configuration
|
|
887
|
-
with open(
|
|
887
|
+
with config_path.open("w") as f:
|
|
888
888
|
json.dump(config, f, indent=2)
|
|
889
889
|
|
|
890
890
|
# Verify the file was written correctly
|
|
891
|
-
with open(
|
|
891
|
+
with config_path.open() as f:
|
|
892
892
|
verify_config = json.load(f)
|
|
893
893
|
verify_args = (
|
|
894
894
|
verify_config.get("mcpServers", {})
|
|
@@ -902,9 +902,9 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
|
902
902
|
f"Expected {new_args}, got {verify_args}"
|
|
903
903
|
)
|
|
904
904
|
# Restore backup
|
|
905
|
-
with open(
|
|
905
|
+
with backup_path.open() as bf:
|
|
906
906
|
backup_config = json.load(bf)
|
|
907
|
-
with open(
|
|
907
|
+
with config_path.open("w") as f:
|
|
908
908
|
json.dump(backup_config, f, indent=2)
|
|
909
909
|
return False
|
|
910
910
|
|
|
@@ -936,7 +936,7 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
|
936
936
|
fix_description="Initialize Claude configuration",
|
|
937
937
|
)
|
|
938
938
|
|
|
939
|
-
with open(
|
|
939
|
+
with config_file.open() as f:
|
|
940
940
|
config = json.load(f)
|
|
941
941
|
|
|
942
942
|
# Get the current project configuration
|
|
@@ -193,7 +193,7 @@ class MonitorCheck(BaseDiagnosticCheck):
|
|
|
193
193
|
for config_path in config_paths:
|
|
194
194
|
if config_path.exists():
|
|
195
195
|
try:
|
|
196
|
-
with open(
|
|
196
|
+
with config_path.open() as f:
|
|
197
197
|
config = yaml.safe_load(f)
|
|
198
198
|
if config and isinstance(config, dict):
|
|
199
199
|
response_config = config.get("response_logging", {})
|
|
@@ -248,7 +248,7 @@ class DoctorReporter:
|
|
|
248
248
|
# Header with timestamp
|
|
249
249
|
print("# Claude MPM Doctor Report")
|
|
250
250
|
print(
|
|
251
|
-
f"\n**Generated:** {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
|
251
|
+
f"\n**Generated:** {datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')}"
|
|
252
252
|
)
|
|
253
253
|
print(f"**Version:** {self._get_version()}\n")
|
|
254
254
|
print("---\n")
|
|
@@ -65,6 +65,9 @@ class EventBus:
|
|
|
65
65
|
self._event_history: List[Dict[str, Any]] = []
|
|
66
66
|
self._max_history_size = 100
|
|
67
67
|
|
|
68
|
+
# Track async handler tasks to prevent garbage collection
|
|
69
|
+
self._handler_tasks: Set[asyncio.Task] = set()
|
|
70
|
+
|
|
68
71
|
logger.info("EventBus initialized")
|
|
69
72
|
|
|
70
73
|
@classmethod
|
|
@@ -190,13 +193,15 @@ class EventBus:
|
|
|
190
193
|
try:
|
|
191
194
|
# Call with event_type and data for wildcard handlers
|
|
192
195
|
if asyncio.iscoroutinefunction(handler):
|
|
193
|
-
# Schedule async handlers
|
|
196
|
+
# Schedule async handlers with tracking
|
|
194
197
|
try:
|
|
195
198
|
loop = asyncio.get_event_loop()
|
|
196
199
|
if loop.is_running():
|
|
197
|
-
asyncio.create_task(
|
|
200
|
+
task = asyncio.create_task(
|
|
198
201
|
handler(event_type, data)
|
|
199
202
|
)
|
|
203
|
+
self._handler_tasks.add(task)
|
|
204
|
+
task.add_done_callback(self._handler_tasks.discard)
|
|
200
205
|
else:
|
|
201
206
|
loop.run_until_complete(
|
|
202
207
|
handler(event_type, data)
|
|
@@ -109,7 +109,7 @@ class DeadLetterConsumer(IEventConsumer):
|
|
|
109
109
|
self._rotate_file()
|
|
110
110
|
|
|
111
111
|
# Write to file
|
|
112
|
-
with
|
|
112
|
+
with self._current_file.open("a") as f:
|
|
113
113
|
f.write(event_json)
|
|
114
114
|
|
|
115
115
|
# Update metrics
|
|
@@ -165,7 +165,7 @@ class DeadLetterConsumer(IEventConsumer):
|
|
|
165
165
|
# Find files in time range
|
|
166
166
|
for file_path in sorted(self.output_dir.glob("dead-letter-*.jsonl")):
|
|
167
167
|
try:
|
|
168
|
-
with open(
|
|
168
|
+
with file_path.open() as f:
|
|
169
169
|
for line in f:
|
|
170
170
|
event_data = json.loads(line)
|
|
171
171
|
|
|
@@ -95,7 +95,7 @@ class DeploymentManager:
|
|
|
95
95
|
|
|
96
96
|
# Check if file exists and compare versions
|
|
97
97
|
if target_file.exists() and not force:
|
|
98
|
-
with open(
|
|
98
|
+
with target_file.open() as f:
|
|
99
99
|
existing_content = f.read()
|
|
100
100
|
existing_fw_ver = self.version_manager.parse_current_version(
|
|
101
101
|
existing_content
|
|
@@ -110,7 +110,7 @@ class DeploymentManager:
|
|
|
110
110
|
parent_path.mkdir(parents=True, exist_ok=True)
|
|
111
111
|
|
|
112
112
|
# Write content
|
|
113
|
-
with open(
|
|
113
|
+
with target_file.open("w") as f:
|
|
114
114
|
f.write(content)
|
|
115
115
|
|
|
116
116
|
# Get version info for success message
|
|
@@ -137,7 +137,7 @@ class DeploymentManager:
|
|
|
137
137
|
return True, f"{self.target_filename} does not exist"
|
|
138
138
|
|
|
139
139
|
try:
|
|
140
|
-
with open(
|
|
140
|
+
with target_file.open() as f:
|
|
141
141
|
existing_content = f.read()
|
|
142
142
|
existing_fw_ver = self.version_manager.parse_current_version(
|
|
143
143
|
existing_content
|
|
@@ -38,7 +38,7 @@ class VersionManager:
|
|
|
38
38
|
version_path = package_path.parent / "framework" / "VERSION"
|
|
39
39
|
|
|
40
40
|
if version_path.exists():
|
|
41
|
-
with open(
|
|
41
|
+
with version_path.open() as f:
|
|
42
42
|
version_content = f.read().strip()
|
|
43
43
|
# Framework VERSION file contains just the framework version number
|
|
44
44
|
try:
|
|
@@ -24,7 +24,7 @@ class HookInstallerService:
|
|
|
24
24
|
self.claude_dir = Path.home() / ".claude"
|
|
25
25
|
self.settings_file = self.claude_dir / "settings.json"
|
|
26
26
|
|
|
27
|
-
def is_hooks_configured(self) -> bool:
|
|
27
|
+
def is_hooks_configured(self) -> bool:
|
|
28
28
|
"""Check if hooks are configured in Claude settings.
|
|
29
29
|
|
|
30
30
|
Returns:
|
|
@@ -35,7 +35,7 @@ class HookInstallerService:
|
|
|
35
35
|
self.logger.debug("Claude settings file does not exist")
|
|
36
36
|
return False
|
|
37
37
|
|
|
38
|
-
with
|
|
38
|
+
with self.settings_file.open() as f:
|
|
39
39
|
settings = json.load(f)
|
|
40
40
|
|
|
41
41
|
# Check if hooks section exists
|
|
@@ -292,7 +292,7 @@ class HookInstallerService:
|
|
|
292
292
|
|
|
293
293
|
# Load existing settings or create new
|
|
294
294
|
if self.settings_file.exists():
|
|
295
|
-
with
|
|
295
|
+
with self.settings_file.open() as f:
|
|
296
296
|
settings = json.load(f)
|
|
297
297
|
self.logger.debug("Found existing Claude settings")
|
|
298
298
|
else:
|
|
@@ -320,7 +320,7 @@ class HookInstallerService:
|
|
|
320
320
|
settings["hooks"][event_type] = [hook_config]
|
|
321
321
|
|
|
322
322
|
# Write settings
|
|
323
|
-
with
|
|
323
|
+
with self.settings_file.open("w") as f:
|
|
324
324
|
json.dump(settings, f, indent=2)
|
|
325
325
|
|
|
326
326
|
self.logger.info(f"Updated Claude settings at: {self.settings_file}")
|
|
@@ -380,7 +380,7 @@ class HookInstallerService:
|
|
|
380
380
|
|
|
381
381
|
self.logger.info("Removing Claude Code hooks...")
|
|
382
382
|
|
|
383
|
-
with
|
|
383
|
+
with self.settings_file.open() as f:
|
|
384
384
|
settings = json.load(f)
|
|
385
385
|
|
|
386
386
|
hooks_removed = 0
|
|
@@ -422,7 +422,7 @@ class HookInstallerService:
|
|
|
422
422
|
del settings["hooks"]
|
|
423
423
|
|
|
424
424
|
# Write updated settings
|
|
425
|
-
with
|
|
425
|
+
with self.settings_file.open("w") as f:
|
|
426
426
|
json.dump(settings, f, indent=2)
|
|
427
427
|
|
|
428
428
|
if hooks_removed > 0:
|
|
@@ -469,7 +469,7 @@ class HookInstallerService:
|
|
|
469
469
|
|
|
470
470
|
try:
|
|
471
471
|
if self.settings_file.exists():
|
|
472
|
-
with
|
|
472
|
+
with self.settings_file.open() as f:
|
|
473
473
|
settings = json.load(f)
|
|
474
474
|
|
|
475
475
|
if "hooks" in settings:
|
|
@@ -151,7 +151,7 @@ class ContextPreservationService(BaseService):
|
|
|
151
151
|
return None
|
|
152
152
|
|
|
153
153
|
# Use streaming to find active conversation
|
|
154
|
-
with
|
|
154
|
+
with self.claude_json_path.open("rb") as f:
|
|
155
155
|
parser = ijson.parse(f)
|
|
156
156
|
|
|
157
157
|
active_conv_id = None
|
|
@@ -207,7 +207,7 @@ class ContextPreservationService(BaseService):
|
|
|
207
207
|
keep_recent_days * 86400
|
|
208
208
|
)
|
|
209
209
|
|
|
210
|
-
with
|
|
210
|
+
with self.claude_json_path.open() as f:
|
|
211
211
|
data = json.load(f)
|
|
212
212
|
|
|
213
213
|
original_count = len(data.get("conversations", []))
|
|
@@ -239,7 +239,7 @@ class ContextPreservationService(BaseService):
|
|
|
239
239
|
|
|
240
240
|
# Write compressed version
|
|
241
241
|
temp_path = self.claude_json_path.with_suffix(".tmp")
|
|
242
|
-
with open(
|
|
242
|
+
with temp_path.open("w") as f:
|
|
243
243
|
json.dump(data, f, separators=(",", ":")) # Compact format
|
|
244
244
|
|
|
245
245
|
# Replace original
|
|
@@ -316,7 +316,7 @@ class ContextPreservationService(BaseService):
|
|
|
316
316
|
# Use streaming to extract preferences
|
|
317
317
|
preferences = {}
|
|
318
318
|
|
|
319
|
-
with
|
|
319
|
+
with self.claude_json_path.open("rb") as f:
|
|
320
320
|
parser = ijson.parse(f)
|
|
321
321
|
|
|
322
322
|
for prefix, event, value in parser:
|
|
@@ -339,7 +339,7 @@ class ContextPreservationService(BaseService):
|
|
|
339
339
|
) -> ConversationState:
|
|
340
340
|
"""Parse Claude JSON using standard JSON parser."""
|
|
341
341
|
try:
|
|
342
|
-
with
|
|
342
|
+
with self.claude_json_path.open() as f:
|
|
343
343
|
data = json.load(f)
|
|
344
344
|
|
|
345
345
|
return await self._extract_conversation_state(data, extract_full)
|
|
@@ -357,7 +357,7 @@ class ContextPreservationService(BaseService):
|
|
|
357
357
|
preferences = {}
|
|
358
358
|
open_files = []
|
|
359
359
|
|
|
360
|
-
with
|
|
360
|
+
with self.claude_json_path.open("rb") as f:
|
|
361
361
|
parser = ijson.parse(f)
|
|
362
362
|
|
|
363
363
|
conversation_count = 0
|
|
@@ -527,7 +527,7 @@ class ContextPreservationService(BaseService):
|
|
|
527
527
|
backup_name += ".gz"
|
|
528
528
|
backup_path = self.claude_backup_dir / backup_name
|
|
529
529
|
|
|
530
|
-
with
|
|
530
|
+
with self.claude_json_path.open("rb") as f_in:
|
|
531
531
|
with gzip.open(backup_path, "wb") as f_out:
|
|
532
532
|
shutil.copyfileobj(f_in, f_out)
|
|
533
533
|
else:
|
|
@@ -80,7 +80,7 @@ class SocketIODaemonManager:
|
|
|
80
80
|
return False
|
|
81
81
|
|
|
82
82
|
try:
|
|
83
|
-
with
|
|
83
|
+
with self.pid_file.open() as f:
|
|
84
84
|
pid = int(f.read().strip())
|
|
85
85
|
|
|
86
86
|
# Check if process exists and is running
|
|
@@ -135,7 +135,7 @@ class SocketIODaemonManager:
|
|
|
135
135
|
pid = os.fork()
|
|
136
136
|
if pid > 0:
|
|
137
137
|
# Parent process - save PID and exit
|
|
138
|
-
with
|
|
138
|
+
with self.pid_file.open("w") as f:
|
|
139
139
|
f.write(str(pid))
|
|
140
140
|
logger.info(f"Socket.IO server started as daemon (PID: {pid})")
|
|
141
141
|
return True
|
|
@@ -155,7 +155,7 @@ class SocketIODaemonManager:
|
|
|
155
155
|
os.umask(0)
|
|
156
156
|
|
|
157
157
|
# Redirect stdout/stderr to log file
|
|
158
|
-
with
|
|
158
|
+
with self.log_file.open("a") as log:
|
|
159
159
|
os.dup2(log.fileno(), sys.stdout.fileno())
|
|
160
160
|
os.dup2(log.fileno(), sys.stderr.fileno())
|
|
161
161
|
|
|
@@ -199,7 +199,7 @@ class SocketIODaemonManager:
|
|
|
199
199
|
return False
|
|
200
200
|
|
|
201
201
|
try:
|
|
202
|
-
with
|
|
202
|
+
with self.pid_file.open() as f:
|
|
203
203
|
pid = int(f.read().strip())
|
|
204
204
|
|
|
205
205
|
logger.info(f"Stopping Socket.IO server (PID: {pid})")
|
|
@@ -254,7 +254,7 @@ class SocketIODaemonManager:
|
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
if status_info["running"]:
|
|
257
|
-
with
|
|
257
|
+
with self.pid_file.open() as f:
|
|
258
258
|
status_info["pid"] = int(f.read().strip())
|
|
259
259
|
|
|
260
260
|
# Check port accessibility
|
|
@@ -199,7 +199,7 @@ class MCPConfigManager:
|
|
|
199
199
|
f"Found kuzu-memory with MCP support at {path}"
|
|
200
200
|
)
|
|
201
201
|
return path
|
|
202
|
-
except:
|
|
202
|
+
except (subprocess.SubprocessError, subprocess.TimeoutExpired, OSError):
|
|
203
203
|
pass
|
|
204
204
|
|
|
205
205
|
# If no MCP-capable version found, log warning but return None
|
|
@@ -571,7 +571,7 @@ class MCPConfigManager:
|
|
|
571
571
|
if result.returncode == 0 or "version" in result.stdout.lower():
|
|
572
572
|
use_pipx_run = True
|
|
573
573
|
self.logger.debug(f"Will use 'pipx run' for {service_name}")
|
|
574
|
-
except:
|
|
574
|
+
except (subprocess.SubprocessError, subprocess.TimeoutExpired, OSError):
|
|
575
575
|
pass
|
|
576
576
|
|
|
577
577
|
# Try uvx if pipx run not available
|
|
@@ -587,7 +587,7 @@ class MCPConfigManager:
|
|
|
587
587
|
if result.returncode == 0 or "version" in result.stdout.lower():
|
|
588
588
|
use_uvx = True
|
|
589
589
|
self.logger.debug(f"Will use 'uvx' for {service_name}")
|
|
590
|
-
except:
|
|
590
|
+
except (subprocess.SubprocessError, subprocess.TimeoutExpired, OSError):
|
|
591
591
|
pass
|
|
592
592
|
|
|
593
593
|
# If neither work, try to find direct path
|
|
@@ -719,7 +719,7 @@ class MCPConfigManager:
|
|
|
719
719
|
claude_config = {}
|
|
720
720
|
if self.claude_config_path.exists():
|
|
721
721
|
try:
|
|
722
|
-
with
|
|
722
|
+
with self.claude_config_path.open() as f:
|
|
723
723
|
claude_config = json.load(f)
|
|
724
724
|
except Exception as e:
|
|
725
725
|
self.logger.error(f"Error reading {self.claude_config_path}: {e}")
|
|
@@ -832,7 +832,7 @@ class MCPConfigManager:
|
|
|
832
832
|
self.logger.debug(f"Created backup: {backup_path}")
|
|
833
833
|
|
|
834
834
|
# Write updated config
|
|
835
|
-
with
|
|
835
|
+
with self.claude_config_path.open("w") as f:
|
|
836
836
|
json.dump(claude_config, f, indent=2)
|
|
837
837
|
|
|
838
838
|
messages = []
|
|
@@ -884,7 +884,7 @@ class MCPConfigManager:
|
|
|
884
884
|
existing_config = {}
|
|
885
885
|
if mcp_config_path.exists():
|
|
886
886
|
try:
|
|
887
|
-
with open(
|
|
887
|
+
with mcp_config_path.open() as f:
|
|
888
888
|
existing_config = json.load(f)
|
|
889
889
|
except Exception as e:
|
|
890
890
|
self.logger.error(f"Error reading existing config: {e}")
|
|
@@ -912,7 +912,7 @@ class MCPConfigManager:
|
|
|
912
912
|
|
|
913
913
|
# Write the updated configuration
|
|
914
914
|
try:
|
|
915
|
-
with open(
|
|
915
|
+
with mcp_config_path.open("w") as f:
|
|
916
916
|
json.dump(new_config, f, indent=2)
|
|
917
917
|
|
|
918
918
|
if missing_services:
|
|
@@ -937,7 +937,7 @@ class MCPConfigManager:
|
|
|
937
937
|
mcp_config_path = self.project_root / ConfigLocation.PROJECT_MCP.value
|
|
938
938
|
if mcp_config_path.exists():
|
|
939
939
|
try:
|
|
940
|
-
with open(
|
|
940
|
+
with mcp_config_path.open() as f:
|
|
941
941
|
config = json.load(f)
|
|
942
942
|
results = {}
|
|
943
943
|
for service_name, service_config in config.get(
|
|
@@ -951,7 +951,7 @@ class MCPConfigManager:
|
|
|
951
951
|
return {}
|
|
952
952
|
|
|
953
953
|
try:
|
|
954
|
-
with
|
|
954
|
+
with self.claude_config_path.open() as f:
|
|
955
955
|
claude_config = json.load(f)
|
|
956
956
|
|
|
957
957
|
# Get project's MCP servers
|
|
@@ -1638,7 +1638,7 @@ class MCPConfigManager:
|
|
|
1638
1638
|
if result.returncode == 0 or "version" in result.stdout.lower():
|
|
1639
1639
|
self.logger.debug(f"{service_name} accessible via 'pipx run'")
|
|
1640
1640
|
return True
|
|
1641
|
-
except:
|
|
1641
|
+
except (subprocess.SubprocessError, subprocess.TimeoutExpired, OSError):
|
|
1642
1642
|
pass
|
|
1643
1643
|
return False
|
|
1644
1644
|
|
|
@@ -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
|