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
|
@@ -428,7 +428,7 @@ main "$@"
|
|
|
428
428
|
return
|
|
429
429
|
|
|
430
430
|
try:
|
|
431
|
-
with
|
|
431
|
+
with self.old_settings_file.open() as f:
|
|
432
432
|
old_settings = json.load(f)
|
|
433
433
|
|
|
434
434
|
# Remove hooks section if present
|
|
@@ -437,7 +437,7 @@ main "$@"
|
|
|
437
437
|
self.logger.info(f"Removing hooks from {self.old_settings_file}")
|
|
438
438
|
|
|
439
439
|
# Write back the cleaned settings
|
|
440
|
-
with
|
|
440
|
+
with self.old_settings_file.open("w") as f:
|
|
441
441
|
json.dump(old_settings, f, indent=2)
|
|
442
442
|
|
|
443
443
|
self.logger.info(f"Cleaned up hooks from {self.old_settings_file}")
|
|
@@ -450,7 +450,7 @@ main "$@"
|
|
|
450
450
|
|
|
451
451
|
# Load existing settings.json or create new
|
|
452
452
|
if self.settings_file.exists():
|
|
453
|
-
with
|
|
453
|
+
with self.settings_file.open() as f:
|
|
454
454
|
settings = json.load(f)
|
|
455
455
|
self.logger.info(f"Found existing Claude settings at {self.settings_file}")
|
|
456
456
|
else:
|
|
@@ -490,7 +490,7 @@ main "$@"
|
|
|
490
490
|
]
|
|
491
491
|
|
|
492
492
|
# Write settings to settings.json
|
|
493
|
-
with
|
|
493
|
+
with self.settings_file.open("w") as f:
|
|
494
494
|
json.dump(settings, f, indent=2)
|
|
495
495
|
|
|
496
496
|
self.logger.info(f"Updated Claude settings at {self.settings_file}")
|
|
@@ -564,7 +564,7 @@ main "$@"
|
|
|
564
564
|
issues.append(f"Claude settings file not found at {self.settings_file}")
|
|
565
565
|
else:
|
|
566
566
|
try:
|
|
567
|
-
with
|
|
567
|
+
with self.settings_file.open() as f:
|
|
568
568
|
settings = json.load(f)
|
|
569
569
|
|
|
570
570
|
if "hooks" not in settings:
|
|
@@ -615,7 +615,7 @@ main "$@"
|
|
|
615
615
|
# Remove from Claude settings (both old and new locations)
|
|
616
616
|
for settings_path in [self.settings_file, self.old_settings_file]:
|
|
617
617
|
if settings_path.exists():
|
|
618
|
-
with open(
|
|
618
|
+
with settings_path.open() as f:
|
|
619
619
|
settings = json.load(f)
|
|
620
620
|
|
|
621
621
|
if "hooks" in settings:
|
|
@@ -655,7 +655,7 @@ main "$@"
|
|
|
655
655
|
del settings["hooks"]
|
|
656
656
|
|
|
657
657
|
# Write back settings
|
|
658
|
-
with open(
|
|
658
|
+
with settings_path.open("w") as f:
|
|
659
659
|
json.dump(settings, f, indent=2)
|
|
660
660
|
|
|
661
661
|
self.logger.info(f"Removed hooks from {settings_path}")
|
|
@@ -709,7 +709,7 @@ main "$@"
|
|
|
709
709
|
|
|
710
710
|
if self.settings_file.exists():
|
|
711
711
|
try:
|
|
712
|
-
with
|
|
712
|
+
with self.settings_file.open() as f:
|
|
713
713
|
settings = json.load(f)
|
|
714
714
|
if "hooks" in settings:
|
|
715
715
|
status["configured_events"] = list(settings["hooks"].keys())
|
|
@@ -720,7 +720,7 @@ main "$@"
|
|
|
720
720
|
# Also check old settings file
|
|
721
721
|
if self.old_settings_file.exists():
|
|
722
722
|
try:
|
|
723
|
-
with
|
|
723
|
+
with self.old_settings_file.open() as f:
|
|
724
724
|
old_settings = json.load(f)
|
|
725
725
|
if "hooks" in old_settings:
|
|
726
726
|
status["old_file_has_hooks"] = True
|
|
@@ -76,6 +76,9 @@ class ConnectionManagerService:
|
|
|
76
76
|
# For backward compatibility with tests
|
|
77
77
|
self.connection_pool = None # No longer used
|
|
78
78
|
|
|
79
|
+
# Track async emit tasks to prevent garbage collection
|
|
80
|
+
self._emit_tasks: set = set()
|
|
81
|
+
|
|
79
82
|
if DEBUG:
|
|
80
83
|
print(
|
|
81
84
|
f"✅ HTTP connection manager initialized - endpoint: {self.http_endpoint}",
|
|
@@ -141,8 +144,10 @@ class ConnectionManagerService:
|
|
|
141
144
|
pass
|
|
142
145
|
|
|
143
146
|
if loop:
|
|
144
|
-
# We're in an async context, create a task
|
|
145
|
-
loop.create_task(self._async_emit(namespace, event, data))
|
|
147
|
+
# We're in an async context, create a task with tracking
|
|
148
|
+
task = loop.create_task(self._async_emit(namespace, event, data))
|
|
149
|
+
self._emit_tasks.add(task)
|
|
150
|
+
task.add_done_callback(self._emit_tasks.discard)
|
|
146
151
|
# Don't wait for completion to maintain low latency
|
|
147
152
|
if DEBUG:
|
|
148
153
|
print(f"✅ Async emit scheduled: {event}", file=sys.stderr)
|
|
@@ -138,7 +138,7 @@ def summarize_todos(todos: list) -> dict:
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
|
|
141
|
-
def classify_tool_operation(tool_name: str, tool_input: dict) -> str:
|
|
141
|
+
def classify_tool_operation(tool_name: str, tool_input: dict) -> str:
|
|
142
142
|
"""Classify the type of operation being performed."""
|
|
143
143
|
if tool_name in ["Read", "LS", "Glob", "Grep", "NotebookRead"]:
|
|
144
144
|
return "read"
|
|
@@ -155,7 +155,7 @@ def classify_tool_operation(tool_name: str, tool_input: dict) -> str: # noqa: P
|
|
|
155
155
|
return "other"
|
|
156
156
|
|
|
157
157
|
|
|
158
|
-
def assess_security_risk(tool_name: str, tool_input: dict) -> str:
|
|
158
|
+
def assess_security_risk(tool_name: str, tool_input: dict) -> str:
|
|
159
159
|
"""Assess the security risk level of the tool operation."""
|
|
160
160
|
if tool_name == "Bash":
|
|
161
161
|
command = tool_input.get("command", "").lower()
|
|
@@ -234,7 +234,7 @@ class MemoryPostDelegationHook(PostDelegationHook):
|
|
|
234
234
|
"context": "context", # Current Technical Context
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
def execute(self, context: HookContext) -> HookResult:
|
|
237
|
+
def execute(self, context: HookContext) -> HookResult:
|
|
238
238
|
"""Extract and store learnings from delegation result.
|
|
239
239
|
|
|
240
240
|
WHY: Capturing learnings immediately after task completion ensures we
|
|
@@ -118,7 +118,7 @@ async def validate_agent_dependencies(profile_path: Path) -> ValidationResult:
|
|
|
118
118
|
result = ValidationResult(is_valid=True)
|
|
119
119
|
|
|
120
120
|
try:
|
|
121
|
-
with open(
|
|
121
|
+
with profile_path.open() as f:
|
|
122
122
|
profile_data = yaml.safe_load(f)
|
|
123
123
|
|
|
124
124
|
# Check for circular dependencies
|
claude_mpm/init.py
CHANGED
|
@@ -270,11 +270,11 @@ class ProjectInitializer:
|
|
|
270
270
|
"""
|
|
271
271
|
try:
|
|
272
272
|
# Read existing JSON configuration
|
|
273
|
-
with open(
|
|
273
|
+
with old_file.open() as f:
|
|
274
274
|
config = json.load(f)
|
|
275
275
|
|
|
276
276
|
# Write as YAML
|
|
277
|
-
with open(
|
|
277
|
+
with new_file.open("w") as f:
|
|
278
278
|
yaml.dump(config, f, default_flow_style=False, sort_keys=False)
|
|
279
279
|
|
|
280
280
|
self.logger.info(
|
|
@@ -310,7 +310,7 @@ class ProjectInitializer:
|
|
|
310
310
|
},
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
with open(
|
|
313
|
+
with config_file.open("w") as f:
|
|
314
314
|
yaml.dump(default_config, f, default_flow_style=False, sort_keys=False)
|
|
315
315
|
|
|
316
316
|
def _create_project_config(self, config_file: Path):
|
|
@@ -322,7 +322,7 @@ class ProjectInitializer:
|
|
|
322
322
|
"tickets": {"auto_create": True, "prefix": "TSK"},
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
with open(
|
|
325
|
+
with config_file.open("w") as f:
|
|
326
326
|
json.dump(project_config, f, indent=2)
|
|
327
327
|
|
|
328
328
|
def _copy_agent_templates(self):
|
|
@@ -448,7 +448,7 @@ class AgentSession:
|
|
|
448
448
|
filepath = directory / filename
|
|
449
449
|
|
|
450
450
|
# Save to file
|
|
451
|
-
with open(
|
|
451
|
+
with filepath.open("w", encoding="utf-8") as f:
|
|
452
452
|
json.dump(self.to_dict(), f, indent=2, ensure_ascii=False)
|
|
453
453
|
|
|
454
454
|
return str(filepath)
|
|
@@ -37,7 +37,7 @@ def is_running(pid_file: Path) -> bool:
|
|
|
37
37
|
return False
|
|
38
38
|
|
|
39
39
|
try:
|
|
40
|
-
with open(
|
|
40
|
+
with pid_file.open() as f:
|
|
41
41
|
pid = int(f.read().strip())
|
|
42
42
|
|
|
43
43
|
# Check if process exists
|
|
@@ -85,7 +85,7 @@ def start_server(port: int = DEFAULT_PORT, daemon: bool = True) -> bool:
|
|
|
85
85
|
logger.info(f"Socket.IO daemon started on port {actual_port}")
|
|
86
86
|
# Save the port for clients to discover
|
|
87
87
|
port_file = pid_file.parent / "socketio-port"
|
|
88
|
-
with open(
|
|
88
|
+
with port_file.open("w") as f:
|
|
89
89
|
f.write(str(actual_port))
|
|
90
90
|
else:
|
|
91
91
|
logger.error("Failed to start Socket.IO daemon")
|
|
@@ -102,7 +102,7 @@ def stop_server() -> bool:
|
|
|
102
102
|
return False
|
|
103
103
|
|
|
104
104
|
try:
|
|
105
|
-
with open(
|
|
105
|
+
with pid_file.open() as f:
|
|
106
106
|
pid = int(f.read().strip())
|
|
107
107
|
|
|
108
108
|
# Send SIGTERM for graceful shutdown
|
|
@@ -155,12 +155,12 @@ def status_server() -> bool:
|
|
|
155
155
|
|
|
156
156
|
if is_running(pid_file):
|
|
157
157
|
try:
|
|
158
|
-
with open(
|
|
158
|
+
with pid_file.open() as f:
|
|
159
159
|
pid = int(f.read().strip())
|
|
160
160
|
|
|
161
161
|
port = DEFAULT_PORT
|
|
162
162
|
if port_file.exists():
|
|
163
|
-
with open(
|
|
163
|
+
with port_file.open() as f:
|
|
164
164
|
port = int(f.read().strip())
|
|
165
165
|
|
|
166
166
|
print(f"Socket.IO daemon is running (PID: {pid}, Port: {port})")
|
claude_mpm/services/__init__.py
CHANGED
|
@@ -144,8 +144,8 @@ def __getattr__(name):
|
|
|
144
144
|
try:
|
|
145
145
|
module = import_module("claude_mpm.services.recovery_manager")
|
|
146
146
|
return module.RecoveryManager
|
|
147
|
-
except ImportError:
|
|
148
|
-
raise AttributeError(f"Recovery management not available: {name}")
|
|
147
|
+
except ImportError as e:
|
|
148
|
+
raise AttributeError(f"Recovery management not available: {name}") from e
|
|
149
149
|
|
|
150
150
|
# Handle MCP interfaces (names starting with "IMCP")
|
|
151
151
|
if name.startswith("IMCP"):
|
|
@@ -215,7 +215,7 @@ class AgentCapabilitiesService(BaseService, AgentCapabilitiesInterface):
|
|
|
215
215
|
self.logger.debug(f"Could not parse agent {agent_file}: {e}")
|
|
216
216
|
continue
|
|
217
217
|
|
|
218
|
-
def _categorize_agent(self, agent_id: str, content: str) -> str:
|
|
218
|
+
def _categorize_agent(self, agent_id: str, content: str) -> str:
|
|
219
219
|
"""Categorize an agent based on its ID and content."""
|
|
220
220
|
agent_id_lower = agent_id.lower()
|
|
221
221
|
content_lower = content.lower()
|
|
@@ -287,7 +287,7 @@ class AgentBuilderService:
|
|
|
287
287
|
|
|
288
288
|
for template_file in self.templates_dir.glob("*.json"):
|
|
289
289
|
try:
|
|
290
|
-
with open(
|
|
290
|
+
with template_file.open() as f:
|
|
291
291
|
config = json.load(f)
|
|
292
292
|
|
|
293
293
|
# Use filename stem as ID if not specified in config
|
|
@@ -377,12 +377,12 @@ class AgentBuilderService:
|
|
|
377
377
|
raise AgentDeploymentError(f"Template '{template_id}' not found")
|
|
378
378
|
|
|
379
379
|
try:
|
|
380
|
-
with open(
|
|
380
|
+
with template_file.open() as f:
|
|
381
381
|
config = json.load(f)
|
|
382
382
|
self._template_cache[template_id] = config
|
|
383
383
|
return config.copy()
|
|
384
384
|
except Exception as e:
|
|
385
|
-
raise AgentDeploymentError(f"Failed to load template '{template_id}': {e}")
|
|
385
|
+
raise AgentDeploymentError(f"Failed to load template '{template_id}': {e}") from e
|
|
386
386
|
|
|
387
387
|
def _load_instructions(self, agent_id: str) -> str:
|
|
388
388
|
"""Load agent instructions.
|
|
@@ -406,7 +406,7 @@ class AgentBuilderService:
|
|
|
406
406
|
for instructions_file in possible_files:
|
|
407
407
|
if instructions_file.exists():
|
|
408
408
|
try:
|
|
409
|
-
with open(
|
|
409
|
+
with instructions_file.open() as f:
|
|
410
410
|
return f.read()
|
|
411
411
|
except Exception as e:
|
|
412
412
|
self.logger.warning(
|
|
@@ -272,7 +272,7 @@ class AgentLifecycleManager(BaseService):
|
|
|
272
272
|
# First convert to JSON string with custom encoder, then save
|
|
273
273
|
json_str = json.dumps(data, indent=2, default=str)
|
|
274
274
|
records_file.parent.mkdir(parents=True, exist_ok=True)
|
|
275
|
-
with open(
|
|
275
|
+
with records_file.open("w", encoding="utf-8") as f:
|
|
276
276
|
f.write(json_str)
|
|
277
277
|
|
|
278
278
|
self.logger.debug(f"Saved {len(self.agent_records)} agent records")
|
|
@@ -227,7 +227,7 @@ class AgentMetricsCollector:
|
|
|
227
227
|
return "validation_error"
|
|
228
228
|
return "other_error"
|
|
229
229
|
|
|
230
|
-
def _extract_agent_type(self, agent_name: str) -> str:
|
|
230
|
+
def _extract_agent_type(self, agent_name: str) -> str:
|
|
231
231
|
"""
|
|
232
232
|
Extract agent type from agent name for categorization.
|
|
233
233
|
|
|
@@ -80,7 +80,7 @@ class AgentRecordService(BaseService):
|
|
|
80
80
|
json_str = json.dumps(data, indent=2, default=str)
|
|
81
81
|
self.records_file.parent.mkdir(parents=True, exist_ok=True)
|
|
82
82
|
|
|
83
|
-
with
|
|
83
|
+
with self.records_file.open("w", encoding="utf-8") as f:
|
|
84
84
|
f.write(json_str)
|
|
85
85
|
|
|
86
86
|
self.logger.debug(f"Saved {len(records)} agent records")
|
|
@@ -149,7 +149,7 @@ class AgentRecordService(BaseService):
|
|
|
149
149
|
json_str = json.dumps(data, indent=2, default=str)
|
|
150
150
|
self.history_file.parent.mkdir(parents=True, exist_ok=True)
|
|
151
151
|
|
|
152
|
-
with
|
|
152
|
+
with self.history_file.open("w", encoding="utf-8") as f:
|
|
153
153
|
f.write(json_str)
|
|
154
154
|
|
|
155
155
|
self.logger.debug(f"Saved {len(history)} operation history entries")
|
|
@@ -255,7 +255,7 @@ class AgentRecordService(BaseService):
|
|
|
255
255
|
|
|
256
256
|
# Write to output path
|
|
257
257
|
json_str = json.dumps(data, indent=2, default=str)
|
|
258
|
-
with open(
|
|
258
|
+
with output_path.open("w", encoding="utf-8") as f:
|
|
259
259
|
f.write(json_str)
|
|
260
260
|
|
|
261
261
|
elif format == "csv":
|
|
@@ -48,10 +48,10 @@ class TargetDirectorySetupStep(BaseDeploymentStep):
|
|
|
48
48
|
try:
|
|
49
49
|
test_file.write_text("test")
|
|
50
50
|
test_file.unlink()
|
|
51
|
-
except Exception:
|
|
51
|
+
except Exception as e:
|
|
52
52
|
raise PermissionError(
|
|
53
53
|
f"Target directory is not writable: {context.actual_target_dir}"
|
|
54
|
-
)
|
|
54
|
+
) from e
|
|
55
55
|
|
|
56
56
|
self.logger.info(f"Target directory set up: {context.actual_target_dir}")
|
|
57
57
|
|
|
@@ -457,7 +457,7 @@ class AgentProfileLoader(BaseService):
|
|
|
457
457
|
|
|
458
458
|
if prompt_file.exists():
|
|
459
459
|
try:
|
|
460
|
-
with open(
|
|
460
|
+
with prompt_file.open() as f:
|
|
461
461
|
data = json.load(f)
|
|
462
462
|
for prompt_data in data:
|
|
463
463
|
prompt = ImprovedPrompt(
|
|
@@ -500,7 +500,7 @@ class AgentProfileLoader(BaseService):
|
|
|
500
500
|
|
|
501
501
|
# Save to file
|
|
502
502
|
prompt_file = self.improved_prompts_path / f"{agent_name}_prompts.json"
|
|
503
|
-
with open(
|
|
503
|
+
with prompt_file.open("w") as f:
|
|
504
504
|
json.dump(
|
|
505
505
|
[
|
|
506
506
|
{
|
|
@@ -195,7 +195,7 @@ class LocalAgentTemplateManager:
|
|
|
195
195
|
"""
|
|
196
196
|
for template_file in directory.glob("*.json"):
|
|
197
197
|
try:
|
|
198
|
-
with open(
|
|
198
|
+
with template_file.open() as f:
|
|
199
199
|
data = json.load(f)
|
|
200
200
|
|
|
201
201
|
# Create LocalAgentTemplate
|
|
@@ -307,7 +307,7 @@ class LocalAgentTemplateManager:
|
|
|
307
307
|
|
|
308
308
|
# Save to JSON file
|
|
309
309
|
template_file = target_dir / f"{template.agent_id}.json"
|
|
310
|
-
with open(
|
|
310
|
+
with template_file.open("w") as f:
|
|
311
311
|
json.dump(template.to_json(), f, indent=2)
|
|
312
312
|
|
|
313
313
|
# Invalidate cache
|
|
@@ -628,7 +628,7 @@ class LocalAgentTemplateManager:
|
|
|
628
628
|
|
|
629
629
|
# Save current version
|
|
630
630
|
old_version_file = versions_dir / f"{template.agent_version}.json"
|
|
631
|
-
with open(
|
|
631
|
+
with old_version_file.open("w") as f:
|
|
632
632
|
json.dump(template.to_json(), f, indent=2)
|
|
633
633
|
|
|
634
634
|
# Update template version
|
|
@@ -691,7 +691,7 @@ class LocalAgentTemplateManager:
|
|
|
691
691
|
count = 0
|
|
692
692
|
for agent_id, template in templates.items():
|
|
693
693
|
output_file = output_dir / f"{agent_id}.json"
|
|
694
|
-
with open(
|
|
694
|
+
with output_file.open("w") as f:
|
|
695
695
|
json.dump(template.to_json(), f, indent=2)
|
|
696
696
|
count += 1
|
|
697
697
|
|
|
@@ -715,7 +715,7 @@ class LocalAgentTemplateManager:
|
|
|
715
715
|
count = 0
|
|
716
716
|
for template_file in input_dir.glob("*.json"):
|
|
717
717
|
try:
|
|
718
|
-
with open(
|
|
718
|
+
with template_file.open() as f:
|
|
719
719
|
data = json.load(f)
|
|
720
720
|
|
|
721
721
|
template = LocalAgentTemplate.from_json(data)
|
|
@@ -166,7 +166,7 @@ class DeployedAgentDiscovery(ConfigServiceBase):
|
|
|
166
166
|
try:
|
|
167
167
|
path = Path(agent_path)
|
|
168
168
|
if path.exists() and path.suffix == ".json":
|
|
169
|
-
with open(
|
|
169
|
+
with path.open() as f:
|
|
170
170
|
return json.load(f)
|
|
171
171
|
except Exception as e:
|
|
172
172
|
logger.warning(f"Failed to load full agent data from {agent_path}: {e}")
|
|
@@ -156,12 +156,19 @@ class AgentFileSystemHandler(FileSystemEventHandler):
|
|
|
156
156
|
def __init__(self, tracker: "AgentModificationTracker"):
|
|
157
157
|
self.tracker = tracker
|
|
158
158
|
|
|
159
|
+
def _create_tracked_task(self, coro):
|
|
160
|
+
"""Create a task with automatic tracking and cleanup."""
|
|
161
|
+
task = asyncio.create_task(coro)
|
|
162
|
+
self.tracker._file_event_tasks.add(task)
|
|
163
|
+
task.add_done_callback(self.tracker._file_event_tasks.discard)
|
|
164
|
+
return task
|
|
165
|
+
|
|
159
166
|
def on_created(self, event: FileSystemEvent) -> None:
|
|
160
167
|
"""Handle file creation events."""
|
|
161
168
|
if not event.is_directory and event.src_path.endswith(
|
|
162
169
|
(".md", ".json", ".yaml")
|
|
163
170
|
):
|
|
164
|
-
|
|
171
|
+
self._create_tracked_task(
|
|
165
172
|
self.tracker._handle_file_modification(
|
|
166
173
|
event.src_path, ModificationType.CREATE
|
|
167
174
|
)
|
|
@@ -172,7 +179,7 @@ class AgentFileSystemHandler(FileSystemEventHandler):
|
|
|
172
179
|
if not event.is_directory and event.src_path.endswith(
|
|
173
180
|
(".md", ".json", ".yaml")
|
|
174
181
|
):
|
|
175
|
-
|
|
182
|
+
self._create_tracked_task(
|
|
176
183
|
self.tracker._handle_file_modification(
|
|
177
184
|
event.src_path, ModificationType.MODIFY
|
|
178
185
|
)
|
|
@@ -183,7 +190,7 @@ class AgentFileSystemHandler(FileSystemEventHandler):
|
|
|
183
190
|
if not event.is_directory and event.src_path.endswith(
|
|
184
191
|
(".md", ".json", ".yaml")
|
|
185
192
|
):
|
|
186
|
-
|
|
193
|
+
self._create_tracked_task(
|
|
187
194
|
self.tracker._handle_file_modification(
|
|
188
195
|
event.src_path, ModificationType.DELETE
|
|
189
196
|
)
|
|
@@ -194,7 +201,7 @@ class AgentFileSystemHandler(FileSystemEventHandler):
|
|
|
194
201
|
if not event.is_directory and event.src_path.endswith(
|
|
195
202
|
(".md", ".json", ".yaml")
|
|
196
203
|
):
|
|
197
|
-
|
|
204
|
+
self._create_tracked_task(
|
|
198
205
|
self.tracker._handle_file_move(event.src_path, event.dest_path)
|
|
199
206
|
)
|
|
200
207
|
|
|
@@ -248,6 +255,7 @@ class AgentModificationTracker(BaseService):
|
|
|
248
255
|
# Background tasks
|
|
249
256
|
self._persistence_task: Optional[asyncio.Task] = None
|
|
250
257
|
self._cleanup_task: Optional[asyncio.Task] = None
|
|
258
|
+
self._file_event_tasks: Set[asyncio.Task] = set() # Track file event tasks
|
|
251
259
|
|
|
252
260
|
# Callbacks
|
|
253
261
|
self.modification_callbacks: List[Callable[[AgentModification], None]] = []
|
|
@@ -473,7 +481,7 @@ class AgentModificationTracker(BaseService):
|
|
|
473
481
|
metadata["file_size_after"] = path.stat().st_size
|
|
474
482
|
|
|
475
483
|
# File hash
|
|
476
|
-
with open(
|
|
484
|
+
with path.open("rb") as f:
|
|
477
485
|
metadata["file_hash_after"] = hashlib.sha256(f.read()).hexdigest()
|
|
478
486
|
|
|
479
487
|
# File type
|
|
@@ -512,7 +520,7 @@ class AgentModificationTracker(BaseService):
|
|
|
512
520
|
}
|
|
513
521
|
|
|
514
522
|
metadata_path = backup_dir / "metadata.json"
|
|
515
|
-
with open(
|
|
523
|
+
with metadata_path.open("w") as f:
|
|
516
524
|
json.dump(metadata, f, indent=2)
|
|
517
525
|
|
|
518
526
|
return str(backup_path)
|
|
@@ -661,7 +669,7 @@ class AgentModificationTracker(BaseService):
|
|
|
661
669
|
# Load active modifications
|
|
662
670
|
active_path = self.persistence_root / "active_modifications.json"
|
|
663
671
|
if active_path.exists():
|
|
664
|
-
with open(
|
|
672
|
+
with active_path.open() as f:
|
|
665
673
|
data = json.load(f)
|
|
666
674
|
self.active_modifications = {
|
|
667
675
|
k: AgentModification.from_dict(v) for k, v in data.items()
|
|
@@ -669,7 +677,7 @@ class AgentModificationTracker(BaseService):
|
|
|
669
677
|
|
|
670
678
|
# Load modification history
|
|
671
679
|
for history_file in self.history_root.glob("*.json"):
|
|
672
|
-
with open(
|
|
680
|
+
with history_file.open() as f:
|
|
673
681
|
data = json.load(f)
|
|
674
682
|
agent_name = data["agent_name"]
|
|
675
683
|
history = ModificationHistory(agent_name=agent_name)
|
|
@@ -699,7 +707,7 @@ class AgentModificationTracker(BaseService):
|
|
|
699
707
|
active_data = {k: v.to_dict() for k, v in self.active_modifications.items()}
|
|
700
708
|
active_path = self.persistence_root / "active_modifications.json"
|
|
701
709
|
|
|
702
|
-
with open(
|
|
710
|
+
with active_path.open("w") as f:
|
|
703
711
|
json.dump(active_data, f, indent=2)
|
|
704
712
|
|
|
705
713
|
# Save modification history
|
|
@@ -714,7 +722,7 @@ class AgentModificationTracker(BaseService):
|
|
|
714
722
|
}
|
|
715
723
|
|
|
716
724
|
history_path = self.history_root / f"{agent_name}_history.json"
|
|
717
|
-
with open(
|
|
725
|
+
with history_path.open("w") as f:
|
|
718
726
|
json.dump(history_data, f, indent=2)
|
|
719
727
|
|
|
720
728
|
self.logger.debug("Saved modification history to disk")
|
|
@@ -767,7 +775,7 @@ class AgentModificationTracker(BaseService):
|
|
|
767
775
|
if backup_dir.is_dir():
|
|
768
776
|
metadata_path = backup_dir / "metadata.json"
|
|
769
777
|
if metadata_path.exists():
|
|
770
|
-
with open(
|
|
778
|
+
with metadata_path.open() as f:
|
|
771
779
|
metadata = json.load(f)
|
|
772
780
|
if metadata.get("backup_time", 0) < cutoff_time:
|
|
773
781
|
shutil.rmtree(backup_dir)
|
|
@@ -336,7 +336,7 @@ class AsyncSessionLogger:
|
|
|
336
336
|
with gzip.open(file_path, "wt", encoding="utf-8") as f:
|
|
337
337
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
338
338
|
else:
|
|
339
|
-
with open(
|
|
339
|
+
with file_path.open("w", encoding="utf-8") as f:
|
|
340
340
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
341
341
|
|
|
342
342
|
logger.debug(f"Wrote log entry to {file_path}")
|
|
@@ -224,7 +224,7 @@ class ClaudeSessionLogger:
|
|
|
224
224
|
|
|
225
225
|
# Save response
|
|
226
226
|
try:
|
|
227
|
-
with open(
|
|
227
|
+
with file_path.open("w", encoding="utf-8") as f:
|
|
228
228
|
json.dump(response_data, f, indent=2, ensure_ascii=False)
|
|
229
229
|
|
|
230
230
|
logger.debug(f"Logged response to {filename} for session {self.session_id}")
|
|
@@ -169,8 +169,8 @@ class AgentListingService(IAgentListingService):
|
|
|
169
169
|
|
|
170
170
|
base_service = AgentDeploymentService()
|
|
171
171
|
self._deployment_service = DeploymentServiceWrapper(base_service)
|
|
172
|
-
except ImportError:
|
|
173
|
-
raise ImportError("Agent deployment service not available")
|
|
172
|
+
except ImportError as e:
|
|
173
|
+
raise ImportError("Agent deployment service not available") from e
|
|
174
174
|
return self._deployment_service
|
|
175
175
|
|
|
176
176
|
@property
|
|
@@ -364,7 +364,7 @@ class AgentListingService(IAgentListingService):
|
|
|
364
364
|
if not agent_path.exists():
|
|
365
365
|
return None
|
|
366
366
|
|
|
367
|
-
with open(
|
|
367
|
+
with agent_path.open() as f:
|
|
368
368
|
content = f.read()
|
|
369
369
|
|
|
370
370
|
details = {
|
|
@@ -72,7 +72,7 @@ class AgentValidationService(IAgentValidationService):
|
|
|
72
72
|
self._registry = adapter.registry
|
|
73
73
|
except Exception as e:
|
|
74
74
|
self.logger.error(f"Failed to initialize agent registry: {e}")
|
|
75
|
-
raise RuntimeError(f"Could not initialize agent registry: {e}")
|
|
75
|
+
raise RuntimeError(f"Could not initialize agent registry: {e}") from e
|
|
76
76
|
return self._registry
|
|
77
77
|
|
|
78
78
|
def validate_agent(self, agent_name: str) -> Dict[str, Any]:
|
|
@@ -449,7 +449,7 @@ class SessionManager(ISessionManager):
|
|
|
449
449
|
sessions_dict = {
|
|
450
450
|
sid: session.to_dict() for sid, session in self._sessions_cache.items()
|
|
451
451
|
}
|
|
452
|
-
with open(
|
|
452
|
+
with session_file.open("w") as f:
|
|
453
453
|
json.dump(sessions_dict, f, indent=2)
|
|
454
454
|
except Exception as e:
|
|
455
455
|
self.logger.error(f"Failed to save sessions: {e}")
|
|
@@ -464,7 +464,7 @@ class SessionManager(ISessionManager):
|
|
|
464
464
|
return
|
|
465
465
|
|
|
466
466
|
try:
|
|
467
|
-
with open(
|
|
467
|
+
with session_file.open() as f:
|
|
468
468
|
sessions_dict = json.load(f)
|
|
469
469
|
|
|
470
470
|
self._sessions_cache = {
|
|
@@ -166,7 +166,7 @@ class PathResolver(IPathResolver):
|
|
|
166
166
|
self.logger.debug(f"No project root found from {start_path}")
|
|
167
167
|
return None
|
|
168
168
|
|
|
169
|
-
def detect_framework_path(self) -> Optional[Path]:
|
|
169
|
+
def detect_framework_path(self) -> Optional[Path]:
|
|
170
170
|
"""
|
|
171
171
|
Auto-detect claude-mpm framework using unified path management.
|
|
172
172
|
|
|
@@ -187,7 +187,7 @@ class ClaudeCodeCheck(BaseDiagnosticCheck):
|
|
|
187
187
|
|
|
188
188
|
# Check if it's up to date
|
|
189
189
|
try:
|
|
190
|
-
with open(
|
|
190
|
+
with style_path.open() as f:
|
|
191
191
|
content = f.read()
|
|
192
192
|
if "Claude MPM Output Style" in content:
|
|
193
193
|
return DiagnosticResult(
|
|
@@ -232,7 +232,7 @@ class ClaudeCodeCheck(BaseDiagnosticCheck):
|
|
|
232
232
|
)
|
|
233
233
|
|
|
234
234
|
try:
|
|
235
|
-
with open(
|
|
235
|
+
with config_path.open() as f:
|
|
236
236
|
config = json.load(f)
|
|
237
237
|
|
|
238
238
|
mcp_servers = config.get("mcpServers", {})
|