claude-mpm 4.6.0__py3-none-any.whl → 4.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_ENGINEER.md +206 -48
- claude_mpm/agents/BASE_PROMPT_ENGINEER.md +787 -0
- claude_mpm/agents/base_agent_loader.py +3 -1
- claude_mpm/agents/templates/engineer.json +10 -4
- claude_mpm/agents/templates/prompt-engineer.json +517 -87
- claude_mpm/cli/commands/cleanup.py +1 -1
- claude_mpm/cli/commands/mcp_setup_external.py +2 -2
- claude_mpm/cli/commands/memory.py +1 -1
- claude_mpm/cli/commands/mpm_init.py +5 -4
- claude_mpm/cli/commands/run.py +4 -4
- claude_mpm/cli/shared/argument_patterns.py +18 -11
- claude_mpm/cli/shared/base_command.py +1 -1
- claude_mpm/config/experimental_features.py +3 -3
- claude_mpm/config/socketio_config.py +1 -1
- claude_mpm/core/cache.py +2 -2
- claude_mpm/core/claude_runner.py +5 -7
- claude_mpm/core/container.py +10 -4
- claude_mpm/core/file_utils.py +10 -8
- claude_mpm/core/framework/formatters/context_generator.py +3 -2
- claude_mpm/core/framework/loaders/agent_loader.py +11 -7
- claude_mpm/core/injectable_service.py +11 -8
- claude_mpm/core/interactive_session.py +5 -4
- claude_mpm/core/oneshot_session.py +3 -2
- claude_mpm/core/pm_hook_interceptor.py +15 -9
- claude_mpm/core/unified_paths.py +6 -5
- claude_mpm/dashboard/api/simple_directory.py +16 -17
- claude_mpm/hooks/claude_hooks/event_handlers.py +3 -2
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +2 -2
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +2 -2
- claude_mpm/hooks/claude_hooks/installer.py +10 -10
- claude_mpm/hooks/claude_hooks/response_tracking.py +3 -2
- claude_mpm/hooks/claude_hooks/services/state_manager.py +3 -2
- claude_mpm/hooks/tool_call_interceptor.py +6 -3
- claude_mpm/models/agent_session.py +3 -1
- claude_mpm/scripts/mcp_server.py +3 -5
- claude_mpm/services/agents/agent_builder.py +4 -4
- claude_mpm/services/agents/deployment/deployment_type_detector.py +10 -14
- claude_mpm/services/agents/deployment/local_template_deployment.py +6 -3
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +15 -11
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +9 -6
- claude_mpm/services/agents/loading/agent_profile_loader.py +1 -2
- claude_mpm/services/agents/memory/agent_memory_manager.py +27 -27
- claude_mpm/services/agents/memory/content_manager.py +9 -4
- claude_mpm/services/claude_session_logger.py +5 -8
- claude_mpm/services/cli/memory_crud_service.py +1 -1
- claude_mpm/services/cli/memory_output_formatter.py +1 -1
- claude_mpm/services/cli/startup_checker.py +13 -10
- claude_mpm/services/cli/unified_dashboard_manager.py +10 -6
- claude_mpm/services/command_deployment_service.py +9 -7
- claude_mpm/services/core/path_resolver.py +8 -5
- claude_mpm/services/diagnostics/checks/agent_check.py +4 -7
- claude_mpm/services/diagnostics/checks/installation_check.py +19 -16
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +30 -28
- claude_mpm/services/diagnostics/checks/startup_log_check.py +5 -3
- claude_mpm/services/events/core.py +2 -3
- claude_mpm/services/framework_claude_md_generator/content_validator.py +2 -2
- claude_mpm/services/hook_installer_service.py +2 -3
- claude_mpm/services/hook_service.py +5 -6
- claude_mpm/services/mcp_gateway/auto_configure.py +4 -5
- claude_mpm/services/mcp_gateway/main.py +7 -4
- claude_mpm/services/mcp_gateway/server/stdio_server.py +3 -4
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -2
- claude_mpm/services/mcp_service_verifier.py +18 -17
- claude_mpm/services/memory/builder.py +1 -2
- claude_mpm/services/memory/indexed_memory.py +1 -1
- claude_mpm/services/memory/optimizer.py +1 -2
- claude_mpm/services/monitor/daemon_manager.py +3 -3
- claude_mpm/services/monitor/handlers/file.py +5 -4
- claude_mpm/services/monitor/management/lifecycle.py +1 -1
- claude_mpm/services/monitor/server.py +14 -12
- claude_mpm/services/project/architecture_analyzer.py +5 -5
- claude_mpm/services/project/metrics_collector.py +4 -4
- claude_mpm/services/project/project_organizer.py +4 -4
- claude_mpm/services/project/registry.py +9 -3
- claude_mpm/services/shared/config_service_base.py +2 -3
- claude_mpm/services/socketio/handlers/file.py +5 -4
- claude_mpm/services/socketio/handlers/git.py +7 -7
- claude_mpm/services/socketio/server/core.py +10 -10
- claude_mpm/services/subprocess_launcher_service.py +5 -10
- claude_mpm/services/ticket_services/formatter_service.py +1 -1
- claude_mpm/services/ticket_services/validation_service.py +5 -5
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +5 -5
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +4 -4
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +4 -4
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +4 -4
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +4 -4
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +6 -2
- claude_mpm/services/unified/config_strategies/unified_config_service.py +24 -13
- claude_mpm/services/version_control/conflict_resolution.py +6 -2
- claude_mpm/services/version_control/git_operations.py +1 -1
- claude_mpm/services/version_control/version_parser.py +1 -1
- claude_mpm/storage/state_storage.py +3 -3
- claude_mpm/tools/__main__.py +1 -1
- claude_mpm/tools/code_tree_analyzer.py +17 -14
- claude_mpm/tools/socketio_debug.py +7 -7
- claude_mpm/utils/common.py +6 -2
- claude_mpm/utils/config_manager.py +9 -3
- claude_mpm/utils/database_connector.py +4 -4
- claude_mpm/utils/dependency_strategies.py +1 -1
- claude_mpm/utils/environment_context.py +3 -2
- claude_mpm/utils/file_utils.py +1 -2
- claude_mpm/utils/path_operations.py +3 -1
- claude_mpm/utils/robust_installer.py +3 -4
- claude_mpm/validation/frontmatter_validator.py +4 -4
- {claude_mpm-4.6.0.dist-info → claude_mpm-4.7.0.dist-info}/METADATA +1 -1
- {claude_mpm-4.6.0.dist-info → claude_mpm-4.7.0.dist-info}/RECORD +111 -110
- {claude_mpm-4.6.0.dist-info → claude_mpm-4.7.0.dist-info}/WHEEL +0 -0
- {claude_mpm-4.6.0.dist-info → claude_mpm-4.7.0.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.6.0.dist-info → claude_mpm-4.7.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.6.0.dist-info → claude_mpm-4.7.0.dist-info}/top_level.txt +0 -0
@@ -246,7 +246,7 @@ class StartupCheckerService(IStartupChecker):
|
|
246
246
|
|
247
247
|
# Display info last
|
248
248
|
for warning in info:
|
249
|
-
print(f"
|
249
|
+
print(f"[INFO]️ {warning.message}")
|
250
250
|
if warning.suggestion:
|
251
251
|
print(f" {warning.suggestion}")
|
252
252
|
|
@@ -314,16 +314,19 @@ class StartupCheckerService(IStartupChecker):
|
|
314
314
|
try:
|
315
315
|
# Try to get config file path from config service
|
316
316
|
config_file = getattr(self.config_service, "config_file", None)
|
317
|
-
if
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
317
|
+
if (
|
318
|
+
config_file
|
319
|
+
and Path(config_file).exists()
|
320
|
+
and not os.access(config_file, os.R_OK)
|
321
|
+
):
|
322
|
+
warnings.append(
|
323
|
+
StartupWarning(
|
324
|
+
category="config",
|
325
|
+
message=f"Configuration file is not readable: {config_file}",
|
326
|
+
suggestion=f"Run: chmod 644 {config_file}",
|
327
|
+
severity="warning",
|
326
328
|
)
|
329
|
+
)
|
327
330
|
except Exception as e:
|
328
331
|
self.logger.debug(f"Config file access check failed: {e}")
|
329
332
|
|
@@ -334,14 +334,18 @@ class UnifiedDashboardManager(IUnifiedDashboardManager):
|
|
334
334
|
Returns:
|
335
335
|
Tuple of (dependencies_ok, error_message)
|
336
336
|
"""
|
337
|
-
|
338
|
-
|
339
|
-
|
337
|
+
import importlib.util
|
338
|
+
|
339
|
+
missing = []
|
340
|
+
if importlib.util.find_spec("aiohttp") is None:
|
341
|
+
missing.append("aiohttp")
|
342
|
+
if importlib.util.find_spec("socketio") is None:
|
343
|
+
missing.append("socketio")
|
340
344
|
|
341
|
-
|
342
|
-
|
343
|
-
error_msg = f"Required dependencies missing: {e}"
|
345
|
+
if missing:
|
346
|
+
error_msg = f"Required dependencies missing: {', '.join(missing)}"
|
344
347
|
return False, error_msg
|
348
|
+
return True, None
|
345
349
|
|
346
350
|
def find_available_port(self, preferred_port: int = 8765) -> int:
|
347
351
|
"""
|
@@ -84,13 +84,15 @@ class CommandDeploymentService(BaseService):
|
|
84
84
|
|
85
85
|
try:
|
86
86
|
# Check if file exists and if we should overwrite
|
87
|
-
if
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
87
|
+
if (
|
88
|
+
target_file.exists()
|
89
|
+
and not force
|
90
|
+
and source_file.stat().st_mtime <= target_file.stat().st_mtime
|
91
|
+
):
|
92
|
+
self.logger.debug(
|
93
|
+
f"Skipping {source_file.name} - target is up to date"
|
94
|
+
)
|
95
|
+
continue
|
94
96
|
|
95
97
|
# Copy the file
|
96
98
|
shutil.copy2(source_file, target_file)
|
@@ -431,11 +431,14 @@ class PathResolver(IPathResolver):
|
|
431
431
|
]
|
432
432
|
|
433
433
|
for candidate in candidates:
|
434
|
-
if
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
434
|
+
if (
|
435
|
+
candidate
|
436
|
+
and candidate.exists()
|
437
|
+
and (candidate / "src" / "claude_mpm" / "agents").exists()
|
438
|
+
):
|
439
|
+
# Found claude-mpm agents directory
|
440
|
+
self.logger.info(f"Found claude-mpm at: {candidate}")
|
441
|
+
return candidate
|
439
442
|
|
440
443
|
return None
|
441
444
|
|
@@ -111,10 +111,9 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
111
111
|
|
112
112
|
def _check_deployed_agents(self) -> DiagnosticResult:
|
113
113
|
"""Check deployed agents in both project and user directories."""
|
114
|
-
import os
|
115
114
|
|
116
115
|
# Check project-level agents first (preferred in development)
|
117
|
-
project_agents_dir = Path(
|
116
|
+
project_agents_dir = Path(Path.cwd()) / ".claude" / "agents"
|
118
117
|
user_agents_dir = Path.home() / ".claude" / "agents"
|
119
118
|
|
120
119
|
# Determine which directory to check
|
@@ -188,7 +187,6 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
188
187
|
def _check_agent_versions(self) -> DiagnosticResult:
|
189
188
|
"""Check if deployed agents are up-to-date."""
|
190
189
|
try:
|
191
|
-
import os
|
192
190
|
|
193
191
|
from ....services.agents.deployment.agent_version_manager import (
|
194
192
|
AgentVersionManager,
|
@@ -197,7 +195,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
197
195
|
version_manager = AgentVersionManager()
|
198
196
|
|
199
197
|
# Check both project and user directories
|
200
|
-
project_agents_dir = Path(
|
198
|
+
project_agents_dir = Path(Path.cwd()) / ".claude" / "agents"
|
201
199
|
user_agents_dir = Path.home() / ".claude" / "agents"
|
202
200
|
|
203
201
|
if project_agents_dir.exists():
|
@@ -259,14 +257,13 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
259
257
|
def _validate_agents(self) -> DiagnosticResult:
|
260
258
|
"""Validate agent configurations."""
|
261
259
|
try:
|
262
|
-
import os
|
263
260
|
|
264
261
|
from ....services.agents.deployment.agent_validator import AgentValidator
|
265
262
|
|
266
263
|
AgentValidator()
|
267
264
|
|
268
265
|
# Check both project and user directories
|
269
|
-
project_agents_dir = Path(
|
266
|
+
project_agents_dir = Path(Path.cwd()) / ".claude" / "agents"
|
270
267
|
user_agents_dir = Path.home() / ".claude" / "agents"
|
271
268
|
|
272
269
|
if project_agents_dir.exists():
|
@@ -331,7 +328,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
331
328
|
issues = []
|
332
329
|
|
333
330
|
# Check both project and user directories
|
334
|
-
project_agents_dir = Path(
|
331
|
+
project_agents_dir = Path(Path.cwd()) / ".claude" / "agents"
|
335
332
|
user_agents_dir = Path.home() / ".claude" / "agents"
|
336
333
|
|
337
334
|
if project_agents_dir.exists():
|
@@ -176,10 +176,11 @@ class InstallationCheck(BaseDiagnosticCheck):
|
|
176
176
|
|
177
177
|
# 5. Check if running from source (development mode)
|
178
178
|
claude_mpm_path = Path(__file__).parent.parent.parent.parent.parent
|
179
|
-
if (claude_mpm_path / "pyproject.toml").exists()
|
180
|
-
|
181
|
-
|
182
|
-
|
179
|
+
if (claude_mpm_path / "pyproject.toml").exists() and (
|
180
|
+
claude_mpm_path / ".git"
|
181
|
+
).exists():
|
182
|
+
methods_found.append("development")
|
183
|
+
details["source_path"] = str(claude_mpm_path)
|
183
184
|
|
184
185
|
# 6. Check Homebrew Python
|
185
186
|
if not in_venv and "/opt/homebrew" in exe_path:
|
@@ -191,21 +192,23 @@ class InstallationCheck(BaseDiagnosticCheck):
|
|
191
192
|
details["homebrew_python"] = exe_path
|
192
193
|
|
193
194
|
# 7. Check for system Python
|
194
|
-
if
|
195
|
-
|
196
|
-
|
197
|
-
|
195
|
+
if (
|
196
|
+
not in_venv
|
197
|
+
and not methods_found
|
198
|
+
and ("/usr/bin/python" in exe_path or "/usr/local/bin/python" in exe_path)
|
199
|
+
):
|
200
|
+
methods_found.append("system")
|
201
|
+
details["system_python"] = exe_path
|
198
202
|
|
199
203
|
# 8. Additional check for pipx if not detected via venv
|
200
204
|
if "pipx" not in methods_found:
|
201
205
|
pipx_check = self._check_pipx_installation_status()
|
202
|
-
if pipx_check:
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
)
|
206
|
+
if pipx_check and not is_pipx_venv:
|
207
|
+
# Pipx is installed but we're not running from it
|
208
|
+
details["pipx_installed"] = True
|
209
|
+
details["pipx_not_active"] = (
|
210
|
+
"claude-mpm is installed via pipx but not currently running from pipx environment"
|
211
|
+
)
|
209
212
|
|
210
213
|
# 9. Check pip installation status
|
211
214
|
try:
|
@@ -445,7 +448,7 @@ class InstallationCheck(BaseDiagnosticCheck):
|
|
445
448
|
|
446
449
|
# Check cgroup for container indicators
|
447
450
|
try:
|
448
|
-
with
|
451
|
+
with Path("/proc/1/cgroup").open() as f:
|
449
452
|
cgroup = f.read()
|
450
453
|
if "docker" in cgroup:
|
451
454
|
return "Docker"
|
@@ -444,11 +444,14 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
444
444
|
details["command_path"] = command_path
|
445
445
|
|
446
446
|
# If not directly accessible, try pipx run command
|
447
|
-
if
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
447
|
+
if (
|
448
|
+
not accessible
|
449
|
+
and "pipx_run_command" in config
|
450
|
+
and self._verify_command_works(config["pipx_run_command"])
|
451
|
+
):
|
452
|
+
accessible = True
|
453
|
+
details["accessible_via_pipx_run"] = True
|
454
|
+
details["pipx_run_available"] = True
|
452
455
|
|
453
456
|
# Check for installation in various locations
|
454
457
|
if not pipx_installed and not accessible:
|
@@ -690,35 +693,34 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
690
693
|
if any(
|
691
694
|
keyword in output
|
692
695
|
for keyword in ["version", "v1.", "v0.", "1.", "0."]
|
696
|
+
) and not any(
|
697
|
+
error in output
|
698
|
+
for error in [
|
699
|
+
"error",
|
700
|
+
"not found",
|
701
|
+
"no such",
|
702
|
+
"command not found",
|
703
|
+
]
|
693
704
|
):
|
694
|
-
|
695
|
-
if not any(
|
696
|
-
error in output
|
697
|
-
for error in [
|
698
|
-
"error",
|
699
|
-
"not found",
|
700
|
-
"no such",
|
701
|
-
"command not found",
|
702
|
-
]
|
703
|
-
):
|
704
|
-
return True
|
705
|
+
return True
|
705
706
|
|
706
707
|
# For some tools, non-zero return code is OK if version is shown
|
707
708
|
elif "--version" in command or "--help" in command:
|
708
709
|
output = (result.stdout + result.stderr).lower()
|
709
710
|
# Must have version info and no error indicators
|
710
|
-
if
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
711
|
+
if (
|
712
|
+
"version" in output or "v1." in output or "v0." in output
|
713
|
+
) and not any(
|
714
|
+
error in output
|
715
|
+
for error in [
|
716
|
+
"error",
|
717
|
+
"not found",
|
718
|
+
"no such",
|
719
|
+
"command not found",
|
720
|
+
"traceback",
|
721
|
+
]
|
722
|
+
):
|
723
|
+
return True
|
722
724
|
|
723
725
|
except (subprocess.SubprocessError, FileNotFoundError, OSError):
|
724
726
|
pass
|
@@ -15,7 +15,7 @@ DESIGN DECISIONS:
|
|
15
15
|
import re
|
16
16
|
from datetime import datetime
|
17
17
|
from pathlib import Path
|
18
|
-
from typing import Any, Dict, Optional
|
18
|
+
from typing import Any, ClassVar, Dict, Optional
|
19
19
|
|
20
20
|
from ..models import DiagnosticResult, DiagnosticStatus
|
21
21
|
from .base_check import BaseDiagnosticCheck
|
@@ -25,7 +25,7 @@ class StartupLogCheck(BaseDiagnosticCheck):
|
|
25
25
|
"""Analyze startup logs for errors and issues."""
|
26
26
|
|
27
27
|
# Common error patterns and their fixes
|
28
|
-
ERROR_PATTERNS = {
|
28
|
+
ERROR_PATTERNS: ClassVar[dict[str, dict[str, Any]]] = {
|
29
29
|
r"Agent deployment.*failed": (
|
30
30
|
"Agent deployment failure",
|
31
31
|
"Check agent configuration in .claude/agents/ and run 'claude-mpm deploy'",
|
@@ -186,7 +186,9 @@ class StartupLogCheck(BaseDiagnosticCheck):
|
|
186
186
|
}
|
187
187
|
|
188
188
|
try:
|
189
|
-
with
|
189
|
+
with Path(log_file).open(
|
190
|
+
encoding="utf-8",
|
191
|
+
) as f:
|
190
192
|
lines = f.readlines()
|
191
193
|
|
192
194
|
# Extract timestamp from filename or first line
|
@@ -412,9 +412,8 @@ class EventBus(IEventBus):
|
|
412
412
|
"""
|
413
413
|
try:
|
414
414
|
# Apply filter if configured
|
415
|
-
if consumer.config.filter_func:
|
416
|
-
|
417
|
-
return
|
415
|
+
if consumer.config.filter_func and not consumer.config.filter_func(event):
|
416
|
+
return
|
418
417
|
|
419
418
|
# Apply transformation if configured
|
420
419
|
if consumer.config.transform_func:
|
@@ -5,14 +5,14 @@ Validates generated content structure and completeness.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import re
|
8
|
-
from typing import List, Tuple
|
8
|
+
from typing import ClassVar, List, Tuple
|
9
9
|
|
10
10
|
|
11
11
|
class ContentValidator:
|
12
12
|
"""Validates framework CLAUDE.md content for completeness and correctness."""
|
13
13
|
|
14
14
|
# Required sections that must be present
|
15
|
-
REQUIRED_SECTIONS = [
|
15
|
+
REQUIRED_SECTIONS: ClassVar[list[str]] = [
|
16
16
|
(r"CLAUDE_MD_VERSION:", "Version metadata"),
|
17
17
|
(r"## 🤖 AI ASSISTANT ROLE DESIGNATION", "Role designation section"),
|
18
18
|
(r"## A\) AGENTS", "Agents section"),
|
@@ -5,7 +5,6 @@ to enable monitor event forwarding via Socket.IO.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import json
|
8
|
-
import os
|
9
8
|
import shutil
|
10
9
|
import stat
|
11
10
|
import sys
|
@@ -280,8 +279,8 @@ class HookInstallerService:
|
|
280
279
|
return False
|
281
280
|
|
282
281
|
# Make sure the script is executable
|
283
|
-
st =
|
284
|
-
|
282
|
+
st = Path(hook_script).stat()
|
283
|
+
Path(hook_script).chmod(st.st_mode | stat.S_IEXEC)
|
285
284
|
self.logger.debug(f"Made hook script executable: {hook_script}")
|
286
285
|
|
287
286
|
hook_script_path = str(hook_script.absolute())
|
@@ -278,12 +278,11 @@ class HookService(HookServiceInterface):
|
|
278
278
|
if hook_type in ["pre_delegation", "post_delegation"]:
|
279
279
|
# If any registered hooks are memory-related, check memory.enabled
|
280
280
|
for hook in getattr(self, f"{hook_type}_hooks", []):
|
281
|
-
if "memory" in hook.name.lower()
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
return False
|
281
|
+
if "memory" in hook.name.lower() and not self.config.get(
|
282
|
+
"memory.enabled", True
|
283
|
+
):
|
284
|
+
self.logger.debug("Memory hooks disabled via memory.enabled config")
|
285
|
+
return False
|
287
286
|
|
288
287
|
return True
|
289
288
|
|
@@ -176,13 +176,12 @@ class MCPAutoConfigurator:
|
|
176
176
|
print(f"(Auto-declining in {timeout} seconds)")
|
177
177
|
|
178
178
|
# Use threading for cross-platform timeout support
|
179
|
+
# Python 3.7+ has queue built-in - no need to check, we require 3.10+
|
180
|
+
import importlib.util
|
179
181
|
import threading
|
180
182
|
|
181
|
-
|
182
|
-
# Python 3.
|
183
|
-
import queue
|
184
|
-
except ImportError:
|
185
|
-
# Python 2.x fallback
|
183
|
+
if importlib.util.find_spec("queue") is None:
|
184
|
+
# Extremely unlikely in Python 3.10+, but for completeness
|
186
185
|
pass
|
187
186
|
|
188
187
|
user_input = None
|
@@ -179,10 +179,13 @@ class MCPGatewayOrchestrator:
|
|
179
179
|
|
180
180
|
# Load configuration
|
181
181
|
self.configuration = MCPConfiguration()
|
182
|
-
if
|
183
|
-
|
184
|
-
|
185
|
-
|
182
|
+
if (
|
183
|
+
self.config_path
|
184
|
+
and self.config_path.exists()
|
185
|
+
and not self.configuration.load_config(self.config_path)
|
186
|
+
):
|
187
|
+
self.logger.error("Failed to load configuration")
|
188
|
+
return False
|
186
189
|
|
187
190
|
# Initialize tool registry with error handling
|
188
191
|
try:
|
@@ -18,6 +18,7 @@ import os
|
|
18
18
|
import sys
|
19
19
|
import time
|
20
20
|
from datetime import timezone
|
21
|
+
from pathlib import Path
|
21
22
|
from typing import Any, Dict
|
22
23
|
|
23
24
|
# Import MCP SDK components
|
@@ -541,12 +542,10 @@ class SimpleMCPServer:
|
|
541
542
|
|
542
543
|
result = f"Python: {sys.version}"
|
543
544
|
elif info_type == "cwd":
|
544
|
-
import os
|
545
545
|
|
546
|
-
result = f"Working Directory: {
|
546
|
+
result = f"Working Directory: {Path.cwd()}"
|
547
547
|
elif info_type == "all":
|
548
548
|
import datetime
|
549
|
-
import os
|
550
549
|
import platform
|
551
550
|
import sys
|
552
551
|
|
@@ -554,7 +553,7 @@ class SimpleMCPServer:
|
|
554
553
|
f"=== System Status ===\n"
|
555
554
|
f"Platform: {platform.system()} {platform.release()}\n"
|
556
555
|
f"Python: {sys.version.split()[0]}\n"
|
557
|
-
f"Working Directory: {
|
556
|
+
f"Working Directory: {Path.cwd()}\n"
|
558
557
|
f"Server: {self.name} v{self.version}\n"
|
559
558
|
f"Timestamp: {datetime.datetime.now(timezone.utc).isoformat()}\n"
|
560
559
|
f"Tools Available: status, document_summarizer{', ticket' if self.unified_ticket_tool else ''}"
|
@@ -10,7 +10,6 @@ Part of ISS-0037: Document Summarizer Tool - Intelligent Document Processing
|
|
10
10
|
|
11
11
|
import hashlib
|
12
12
|
import mimetypes
|
13
|
-
import os
|
14
13
|
import re
|
15
14
|
from collections import OrderedDict
|
16
15
|
from datetime import datetime, timezone
|
@@ -240,7 +239,7 @@ class DocumentSummarizerTool(BaseToolAdapter):
|
|
240
239
|
|
241
240
|
def _get_file_hash(self, file_path: str) -> str:
|
242
241
|
"""Generate hash for file caching."""
|
243
|
-
stat =
|
242
|
+
stat = Path(file_path).stat()
|
244
243
|
hash_input = f"{file_path}:{stat.st_size}:{stat.st_mtime}"
|
245
244
|
return hashlib.md5(hash_input.encode()).hexdigest()
|
246
245
|
|
@@ -328,13 +328,11 @@ class MCPServiceVerifier:
|
|
328
328
|
if any(
|
329
329
|
word in output
|
330
330
|
for word in ["version", "usage", "help", service_name.lower()]
|
331
|
+
) and not any(
|
332
|
+
error in output
|
333
|
+
for error in ["error", "not found", "traceback", "no module"]
|
331
334
|
):
|
332
|
-
|
333
|
-
if not any(
|
334
|
-
error in output
|
335
|
-
for error in ["error", "not found", "traceback", "no module"]
|
336
|
-
):
|
337
|
-
return True
|
335
|
+
return True
|
338
336
|
|
339
337
|
# Try pipx run as fallback
|
340
338
|
if shutil.which("pipx"):
|
@@ -485,16 +483,19 @@ class MCPServiceVerifier:
|
|
485
483
|
}
|
486
484
|
else:
|
487
485
|
# Direct execution - command should be a valid path
|
488
|
-
if
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
486
|
+
if (
|
487
|
+
not Path(command).exists()
|
488
|
+
and command != installed_path
|
489
|
+
and not shutil.which(command)
|
490
|
+
):
|
491
|
+
# Command path does not exist and cannot be found
|
492
|
+
return {
|
493
|
+
"configured": True,
|
494
|
+
"correct": False,
|
495
|
+
"command": command,
|
496
|
+
"args": args,
|
497
|
+
"issue": f"Command path does not exist: {command}",
|
498
|
+
}
|
498
499
|
|
499
500
|
# Check required args
|
500
501
|
for req_arg in required_args:
|
@@ -615,7 +616,7 @@ class MCPServiceVerifier:
|
|
615
616
|
if diagnostic.fix_command.startswith("chmod "):
|
616
617
|
# Fix permissions
|
617
618
|
path = diagnostic.fix_command.replace("chmod +x ", "")
|
618
|
-
|
619
|
+
Path(path).chmod(0o755)
|
619
620
|
return True
|
620
621
|
|
621
622
|
if "claude-mpm configure" in diagnostic.fix_command:
|
@@ -22,7 +22,6 @@ documentation verbatim. Creates concise learnings that fit memory constraints
|
|
22
22
|
while preserving essential information.
|
23
23
|
"""
|
24
24
|
|
25
|
-
import os
|
26
25
|
import re
|
27
26
|
from datetime import datetime, timezone
|
28
27
|
from pathlib import Path
|
@@ -118,7 +117,7 @@ class MemoryBuilder(LoggerMixin):
|
|
118
117
|
self.config = config_loader.load_main_config()
|
119
118
|
self.project_root = get_path_manager().project_root
|
120
119
|
# Use current working directory by default, not project root
|
121
|
-
self.working_directory = working_directory or Path(
|
120
|
+
self.working_directory = working_directory or Path(Path.cwd())
|
122
121
|
self.memories_dir = self.working_directory / ".claude-mpm" / "memories"
|
123
122
|
self.router = MemoryRouter(config)
|
124
123
|
self.project_analyzer = ProjectAnalyzer(config, self.working_directory)
|
@@ -573,7 +573,7 @@ class IndexedMemoryService:
|
|
573
573
|
self.text_index.save(self.data_dir / "text_index.pkl")
|
574
574
|
|
575
575
|
# Save other indexes
|
576
|
-
with
|
576
|
+
with Path(self.data_dir / "indexes.pkl").open("wb") as f:
|
577
577
|
pickle.dump(
|
578
578
|
{
|
579
579
|
"memories": self.memories,
|
@@ -22,7 +22,6 @@ rather than aggressively removing content. Better to keep potentially useful
|
|
22
22
|
information than lose important insights.
|
23
23
|
"""
|
24
24
|
|
25
|
-
import os
|
26
25
|
import re
|
27
26
|
from datetime import datetime, timezone
|
28
27
|
from difflib import SequenceMatcher
|
@@ -79,7 +78,7 @@ class MemoryOptimizer(LoggerMixin):
|
|
79
78
|
self.config = config or Config()
|
80
79
|
self.project_root = get_path_manager().get_project_root()
|
81
80
|
# Use current working directory by default, not project root
|
82
|
-
self.working_directory = working_directory or Path(
|
81
|
+
self.working_directory = working_directory or Path(Path.cwd())
|
83
82
|
self.memories_dir = self.working_directory / ".claude-mpm" / "memories"
|
84
83
|
|
85
84
|
def optimize_agent_memory(self, agent_id: str) -> Dict[str, Any]:
|
@@ -561,7 +561,7 @@ class DaemonManager:
|
|
561
561
|
# Open log file for output redirection
|
562
562
|
log_file_handle = None
|
563
563
|
if self.log_file:
|
564
|
-
log_file_handle =
|
564
|
+
log_file_handle = Path(self.log_file).open("a")
|
565
565
|
log_file = log_file_handle
|
566
566
|
else:
|
567
567
|
log_file = subprocess.DEVNULL
|
@@ -858,7 +858,7 @@ class DaemonManager:
|
|
858
858
|
sys.stderr.flush()
|
859
859
|
|
860
860
|
# Redirect stdin to /dev/null
|
861
|
-
with
|
861
|
+
with Path("/dev/null").open() as null_in:
|
862
862
|
os.dup2(null_in.fileno(), sys.stdin.fileno())
|
863
863
|
|
864
864
|
# Redirect stdout and stderr to log file
|
@@ -955,7 +955,7 @@ class DaemonManager:
|
|
955
955
|
except Exception as e:
|
956
956
|
# Try to write error to a debug file since logging might not work
|
957
957
|
try:
|
958
|
-
with
|
958
|
+
with Path("/tmp/daemon_debug_error.txt").open("a") as debug:
|
959
959
|
debug.write(f"Error reporting error: {e}\n")
|
960
960
|
debug.write(f"Status file: {self.startup_status_file}\n")
|
961
961
|
except Exception:
|