claude-mpm 4.4.3__py3-none-any.whl → 4.4.4__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.
Files changed (118) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/agent_loader.py +3 -2
  3. claude_mpm/agents/agent_loader_integration.py +2 -1
  4. claude_mpm/agents/async_agent_loader.py +2 -2
  5. claude_mpm/agents/base_agent_loader.py +2 -2
  6. claude_mpm/agents/frontmatter_validator.py +1 -0
  7. claude_mpm/agents/system_agent_config.py +2 -1
  8. claude_mpm/cli/commands/doctor.py +44 -5
  9. claude_mpm/cli/commands/mpm_init.py +116 -62
  10. claude_mpm/cli/parsers/configure_parser.py +3 -1
  11. claude_mpm/cli/startup_logging.py +1 -3
  12. claude_mpm/config/agent_config.py +1 -1
  13. claude_mpm/config/paths.py +2 -1
  14. claude_mpm/core/agent_name_normalizer.py +1 -0
  15. claude_mpm/core/config.py +2 -1
  16. claude_mpm/core/config_aliases.py +2 -1
  17. claude_mpm/core/file_utils.py +0 -1
  18. claude_mpm/core/framework/__init__.py +6 -6
  19. claude_mpm/core/framework/formatters/__init__.py +2 -2
  20. claude_mpm/core/framework/formatters/capability_generator.py +19 -8
  21. claude_mpm/core/framework/formatters/content_formatter.py +8 -3
  22. claude_mpm/core/framework/formatters/context_generator.py +7 -3
  23. claude_mpm/core/framework/loaders/__init__.py +3 -3
  24. claude_mpm/core/framework/loaders/agent_loader.py +7 -3
  25. claude_mpm/core/framework/loaders/file_loader.py +16 -6
  26. claude_mpm/core/framework/loaders/instruction_loader.py +16 -6
  27. claude_mpm/core/framework/loaders/packaged_loader.py +36 -12
  28. claude_mpm/core/framework/processors/__init__.py +2 -2
  29. claude_mpm/core/framework/processors/memory_processor.py +14 -6
  30. claude_mpm/core/framework/processors/metadata_processor.py +5 -5
  31. claude_mpm/core/framework/processors/template_processor.py +12 -6
  32. claude_mpm/core/framework_loader.py +44 -20
  33. claude_mpm/core/log_manager.py +2 -1
  34. claude_mpm/core/tool_access_control.py +1 -0
  35. claude_mpm/core/unified_agent_registry.py +2 -1
  36. claude_mpm/core/unified_paths.py +1 -0
  37. claude_mpm/experimental/cli_enhancements.py +1 -0
  38. claude_mpm/hooks/base_hook.py +1 -0
  39. claude_mpm/hooks/instruction_reinforcement.py +1 -0
  40. claude_mpm/hooks/kuzu_memory_hook.py +20 -13
  41. claude_mpm/hooks/validation_hooks.py +1 -1
  42. claude_mpm/scripts/mpm_doctor.py +1 -0
  43. claude_mpm/services/agents/loading/agent_profile_loader.py +1 -1
  44. claude_mpm/services/agents/loading/base_agent_manager.py +1 -1
  45. claude_mpm/services/agents/loading/framework_agent_loader.py +1 -1
  46. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -0
  47. claude_mpm/services/agents/management/agent_management_service.py +1 -1
  48. claude_mpm/services/agents/memory/memory_categorization_service.py +0 -1
  49. claude_mpm/services/agents/memory/memory_file_service.py +6 -2
  50. claude_mpm/services/agents/memory/memory_format_service.py +0 -1
  51. claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
  52. claude_mpm/services/async_session_logger.py +1 -1
  53. claude_mpm/services/claude_session_logger.py +1 -0
  54. claude_mpm/services/core/path_resolver.py +1 -0
  55. claude_mpm/services/diagnostics/checks/__init__.py +2 -0
  56. claude_mpm/services/diagnostics/checks/installation_check.py +126 -25
  57. claude_mpm/services/diagnostics/checks/mcp_services_check.py +399 -0
  58. claude_mpm/services/diagnostics/diagnostic_runner.py +3 -0
  59. claude_mpm/services/diagnostics/doctor_reporter.py +259 -32
  60. claude_mpm/services/event_bus/direct_relay.py +2 -1
  61. claude_mpm/services/event_bus/event_bus.py +1 -0
  62. claude_mpm/services/event_bus/relay.py +3 -2
  63. claude_mpm/services/framework_claude_md_generator/content_assembler.py +1 -1
  64. claude_mpm/services/infrastructure/daemon_manager.py +1 -1
  65. claude_mpm/services/mcp_config_manager.py +10 -10
  66. claude_mpm/services/mcp_gateway/core/process_pool.py +62 -23
  67. claude_mpm/services/mcp_gateway/tools/__init__.py +6 -5
  68. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +3 -1
  69. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +16 -31
  70. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  71. claude_mpm/services/project/archive_manager.py +159 -96
  72. claude_mpm/services/project/documentation_manager.py +64 -45
  73. claude_mpm/services/project/enhanced_analyzer.py +132 -89
  74. claude_mpm/services/project/project_organizer.py +225 -131
  75. claude_mpm/services/response_tracker.py +1 -1
  76. claude_mpm/services/socketio/server/eventbus_integration.py +1 -1
  77. claude_mpm/services/unified/__init__.py +1 -1
  78. claude_mpm/services/unified/analyzer_strategies/__init__.py +3 -3
  79. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +97 -53
  80. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +81 -40
  81. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +277 -178
  82. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +196 -112
  83. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +83 -49
  84. claude_mpm/services/unified/config_strategies/__init__.py +111 -126
  85. claude_mpm/services/unified/config_strategies/config_schema.py +157 -111
  86. claude_mpm/services/unified/config_strategies/context_strategy.py +91 -89
  87. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +183 -173
  88. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +160 -152
  89. claude_mpm/services/unified/config_strategies/unified_config_service.py +124 -112
  90. claude_mpm/services/unified/config_strategies/validation_strategy.py +298 -259
  91. claude_mpm/services/unified/deployment_strategies/__init__.py +7 -7
  92. claude_mpm/services/unified/deployment_strategies/base.py +24 -28
  93. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +168 -88
  94. claude_mpm/services/unified/deployment_strategies/local.py +49 -34
  95. claude_mpm/services/unified/deployment_strategies/utils.py +39 -43
  96. claude_mpm/services/unified/deployment_strategies/vercel.py +30 -24
  97. claude_mpm/services/unified/interfaces.py +0 -26
  98. claude_mpm/services/unified/migration.py +17 -40
  99. claude_mpm/services/unified/strategies.py +9 -26
  100. claude_mpm/services/unified/unified_analyzer.py +48 -44
  101. claude_mpm/services/unified/unified_config.py +21 -19
  102. claude_mpm/services/unified/unified_deployment.py +21 -26
  103. claude_mpm/storage/state_storage.py +1 -0
  104. claude_mpm/utils/agent_dependency_loader.py +18 -6
  105. claude_mpm/utils/common.py +14 -12
  106. claude_mpm/utils/database_connector.py +15 -12
  107. claude_mpm/utils/error_handler.py +1 -0
  108. claude_mpm/utils/log_cleanup.py +1 -0
  109. claude_mpm/utils/path_operations.py +1 -0
  110. claude_mpm/utils/session_logging.py +1 -1
  111. claude_mpm/utils/subprocess_utils.py +1 -0
  112. claude_mpm/validation/agent_validator.py +1 -1
  113. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/METADATA +9 -3
  114. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/RECORD +118 -117
  115. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/WHEEL +0 -0
  116. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/entry_points.txt +0 -0
  117. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/licenses/LICENSE +0 -0
  118. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/top_level.txt +0 -0
@@ -242,40 +242,74 @@ class DoctorReporter:
242
242
  print(json.dumps(output, indent=2))
243
243
 
244
244
  def _report_markdown(self, summary: DiagnosticSummary):
245
- """Generate Markdown-formatted report."""
246
- print("# Claude MPM Doctor Report\n")
247
-
248
- # Summary table
249
- print("## Summary\n")
250
- print("| Status | Count |")
251
- print("|--------|-------|")
252
- print(f"| ✅ OK | {summary.ok_count} |")
253
- print(f"| ⚠️ Warning | {summary.warning_count} |")
254
- print(f"| ❌ Error | {summary.error_count} |")
255
- print(f"| ⏭️ Skipped | {summary.skipped_count} |")
245
+ """Generate comprehensive Markdown-formatted report."""
246
+ import datetime
247
+
248
+ # Header with timestamp
249
+ print("# Claude MPM Doctor Report")
250
+ print(
251
+ f"\n**Generated:** {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
252
+ )
253
+ print(f"**Version:** {self._get_version()}\n")
254
+ print("---\n")
255
+
256
+ # System Overview
257
+ print("## System Overview\n")
258
+ self._print_system_overview_markdown(summary)
256
259
  print()
257
260
 
258
- # Detailed results
259
- print("## Diagnostic Results\n")
261
+ # Summary Statistics
262
+ print("## Summary Statistics\n")
263
+ print("| Status | Count | Percentage |")
264
+ print("|--------|-------|------------|")
265
+ total = (
266
+ summary.ok_count
267
+ + summary.warning_count
268
+ + summary.error_count
269
+ + summary.skipped_count
270
+ )
271
+ if total > 0:
272
+ print(f"| ✅ OK | {summary.ok_count} | {summary.ok_count*100//total}% |")
273
+ print(
274
+ f"| ⚠️ Warning | {summary.warning_count} | {summary.warning_count*100//total}% |"
275
+ )
276
+ print(
277
+ f"| ❌ Error | {summary.error_count} | {summary.error_count*100//total}% |"
278
+ )
279
+ print(
280
+ f"| ⏭️ Skipped | {summary.skipped_count} | {summary.skipped_count*100//total}% |"
281
+ )
282
+ print()
283
+
284
+ # Overall Health Status
285
+ overall = summary.overall_status
286
+ if overall == DiagnosticStatus.OK:
287
+ print("### 🎉 Overall Status: **Healthy**")
288
+ print("Your Claude MPM installation is functioning properly.\n")
289
+ elif overall == DiagnosticStatus.WARNING:
290
+ print("### ⚠️ Overall Status: **Needs Attention**")
291
+ print("Your installation has minor issues that should be addressed.\n")
292
+ else:
293
+ print("### ❌ Overall Status: **Critical Issues**")
294
+ print(
295
+ "Your installation has critical issues that need immediate attention.\n"
296
+ )
297
+
298
+ # MCP Services Status (if available)
299
+ self._print_mcp_services_markdown(summary)
260
300
 
301
+ # Installation Details
302
+ self._print_installation_details_markdown(summary)
303
+
304
+ # Detailed Diagnostic Results
305
+ print("## Detailed Diagnostic Results\n")
261
306
  for result in summary.results:
262
- symbol = self.STATUS_SYMBOLS.get(result.status, "?")
263
- print(f"### {symbol} {result.category}\n")
264
- print(f"**Status:** {result.status.value}")
265
- print(f"**Message:** {result.message}\n")
266
-
267
- if result.fix_command:
268
- print(f"**Fix:** `{result.fix_command}`")
269
- if result.fix_description:
270
- print(f"_{result.fix_description}_\n")
271
-
272
- if self.verbose and result.details:
273
- print("**Details:**")
274
- for key, value in result.details.items():
275
- print(f"- {key}: {value}")
276
- print()
307
+ self._print_result_markdown(result)
277
308
 
278
- # Fixes section
309
+ # Recommendations Section
310
+ self._print_recommendations_markdown(summary)
311
+
312
+ # Fixes Section
279
313
  fixes = [
280
314
  (r.category, r.fix_command, r.fix_description)
281
315
  for r in summary.results
@@ -283,13 +317,24 @@ class DoctorReporter:
283
317
  ]
284
318
 
285
319
  if fixes:
286
- print("## Suggested Fixes\n")
320
+ print("## 🔧 Suggested Fixes\n")
321
+ print("Run these commands to fix identified issues:\n")
322
+ print("```bash")
287
323
  for category, command, description in fixes:
288
- print(f"- **{category}:** `{command}`")
324
+ print(f"# Fix: {category}")
289
325
  if description:
290
- print(f" - {description}")
326
+ print(f"# {description}")
327
+ print(command)
328
+ print()
329
+ print("```")
291
330
  print()
292
331
 
332
+ # Footer
333
+ print("---")
334
+ print(
335
+ "\n*For more information, run `claude-mpm doctor --verbose` or visit the [documentation](https://github.com/bobmatnyc/claude-mpm).*"
336
+ )
337
+
293
338
  def _color(self, text: str, color: str) -> str:
294
339
  """Apply color to text if colors are enabled."""
295
340
  if not self.use_color:
@@ -318,3 +363,185 @@ class DoctorReporter:
318
363
  return service.get_version()
319
364
  except Exception:
320
365
  return "unknown"
366
+
367
+ def _print_system_overview_markdown(self, summary: DiagnosticSummary):
368
+ """Print system overview in markdown format."""
369
+ import platform
370
+ import sys
371
+
372
+ print("| Component | Value |")
373
+ print("|-----------|-------|")
374
+ print(f"| Platform | {platform.system()} {platform.release()} |")
375
+ print(f"| Python Version | {sys.version.split()[0]} |")
376
+
377
+ # Extract key details from results
378
+ for result in summary.results:
379
+ if result.category == "Installation":
380
+ if result.details.get("claude_mpm_version"):
381
+ print(
382
+ f"| Claude MPM Version | {result.details['claude_mpm_version']} |"
383
+ )
384
+ if result.details.get("installation_method"):
385
+ print(
386
+ f"| Installation Method | {result.details['installation_method']} |"
387
+ )
388
+ elif result.category == "Claude Desktop":
389
+ if result.details.get("version"):
390
+ print(f"| Claude Desktop | {result.details['version']} |")
391
+
392
+ def _print_mcp_services_markdown(self, summary: DiagnosticSummary):
393
+ """Print MCP services status table in markdown."""
394
+ # Find MCP Services result
395
+ mcp_services_result = None
396
+ for result in summary.results:
397
+ if result.category == "MCP Services":
398
+ mcp_services_result = result
399
+ break
400
+
401
+ if not mcp_services_result or not mcp_services_result.details.get("services"):
402
+ return
403
+
404
+ print("## MCP Services Status\n")
405
+ print("| Service | Installed | Accessible | Version | Status |")
406
+ print("|---------|-----------|------------|---------|--------|")
407
+
408
+ services = mcp_services_result.details.get("services", {})
409
+ for service_name, service_info in services.items():
410
+ installed = "✅" if service_info.get("installed") else "❌"
411
+ accessible = "✅" if service_info.get("accessible") else "❌"
412
+ version = service_info.get("version")
413
+ if version:
414
+ version = str(version)[:20] # Truncate long versions
415
+ else:
416
+ version = "N/A"
417
+ status = service_info.get("status", "unknown")
418
+
419
+ # Map status to emoji
420
+ if status == "ok":
421
+ status_emoji = "✅"
422
+ elif status == "warning":
423
+ status_emoji = "⚠️"
424
+ elif status == "error":
425
+ status_emoji = "❌"
426
+ else:
427
+ status_emoji = "❓"
428
+
429
+ print(
430
+ f"| {service_name} | {installed} | {accessible} | {version} | {status_emoji} |"
431
+ )
432
+ print()
433
+
434
+ def _print_installation_details_markdown(self, summary: DiagnosticSummary):
435
+ """Print installation details in markdown."""
436
+ # Find installation result
437
+ install_result = None
438
+ for result in summary.results:
439
+ if result.category == "Installation":
440
+ install_result = result
441
+ break
442
+
443
+ if not install_result:
444
+ return
445
+
446
+ print("## Installation Details\n")
447
+
448
+ # Print sub-results if available
449
+ if install_result.sub_results and self.verbose:
450
+ for sub in install_result.sub_results:
451
+ if sub.category == "Python Version":
452
+ print("### Python Environment")
453
+ print(f"- **Version:** {sub.message}")
454
+ elif sub.category == "Installation Method":
455
+ print("### Installation Method")
456
+ print(f"- **Method:** {sub.message}")
457
+ if sub.details.get("container_type"):
458
+ print(f"- **Container:** {sub.details['container_type']}")
459
+ if sub.details.get("pipx_metadata"):
460
+ metadata = sub.details["pipx_metadata"]
461
+ if metadata.get("version"):
462
+ print(f"- **Pipx Version:** {metadata['version']}")
463
+ elif sub.category == "Dependencies":
464
+ print("### Dependencies")
465
+ print(f"- **Status:** {sub.message}")
466
+ if sub.details.get("installed"):
467
+ print(
468
+ f"- **Installed Packages:** {len(sub.details['installed'])}"
469
+ )
470
+ print()
471
+
472
+ def _print_result_markdown(self, result: DiagnosticResult):
473
+ """Print a single result in markdown format."""
474
+ symbol = self.STATUS_SYMBOLS.get(result.status, "?")
475
+ print(f"### {symbol} {result.category}\n")
476
+
477
+ # Status badge
478
+ status_badge = {
479
+ DiagnosticStatus.OK: "![OK](https://img.shields.io/badge/status-OK-green)",
480
+ DiagnosticStatus.WARNING: "![Warning](https://img.shields.io/badge/status-Warning-yellow)",
481
+ DiagnosticStatus.ERROR: "![Error](https://img.shields.io/badge/status-Error-red)",
482
+ DiagnosticStatus.SKIPPED: "![Skipped](https://img.shields.io/badge/status-Skipped-gray)",
483
+ }.get(result.status, "")
484
+
485
+ print(f"{status_badge}")
486
+ print(f"\n**Message:** {result.message}\n")
487
+
488
+ if result.fix_command:
489
+ print("**Fix Available:**")
490
+ print("```bash")
491
+ print(result.fix_command)
492
+ print("```")
493
+ if result.fix_description:
494
+ print(f"*{result.fix_description}*\n")
495
+
496
+ if self.verbose and result.details:
497
+ print("<details>")
498
+ print("<summary>Details</summary>\n")
499
+ print("```json")
500
+ import json
501
+
502
+ print(json.dumps(result.details, indent=2, default=str))
503
+ print("```")
504
+ print("</details>\n")
505
+
506
+ def _print_recommendations_markdown(self, summary: DiagnosticSummary):
507
+ """Print recommendations based on diagnostic results."""
508
+ recommendations = []
509
+
510
+ # Analyze results for recommendations
511
+ has_errors = summary.error_count > 0
512
+ has_warnings = summary.warning_count > 0
513
+
514
+ # Check specific conditions
515
+ for result in summary.results:
516
+ if (
517
+ result.category == "Installation"
518
+ and result.status != DiagnosticStatus.OK
519
+ ):
520
+ if "pipx" not in str(result.details.get("installation_method", "")):
521
+ recommendations.append(
522
+ "Consider using pipx for isolated installation: `pipx install claude-mpm`"
523
+ )
524
+
525
+ if result.category == "MCP Services":
526
+ services = result.details.get("services", {})
527
+ missing = [
528
+ s for s, info in services.items() if not info.get("installed")
529
+ ]
530
+ if missing:
531
+ recommendations.append(
532
+ f"Install missing MCP services for enhanced features: {', '.join(missing)}"
533
+ )
534
+
535
+ if (
536
+ result.category == "Claude Desktop"
537
+ and result.status == DiagnosticStatus.WARNING
538
+ ):
539
+ recommendations.append(
540
+ "Update Claude Desktop to the latest version for best compatibility"
541
+ )
542
+
543
+ if recommendations:
544
+ print("## 📋 Recommendations\n")
545
+ for i, rec in enumerate(recommendations, 1):
546
+ print(f"{i}. {rec}")
547
+ print()
@@ -18,9 +18,10 @@ import logging
18
18
  from datetime import datetime, timezone
19
19
  from typing import Any
20
20
 
21
+ from claude_mpm.core.logging_utils import get_logger
22
+
21
23
  from .event_bus import EventBus
22
24
 
23
- from claude_mpm.core.logging_utils import get_logger
24
25
  logger = get_logger(__name__)
25
26
 
26
27
 
@@ -18,6 +18,7 @@ from pyee.asyncio import AsyncIOEventEmitter
18
18
 
19
19
  # Configure logger
20
20
  from claude_mpm.core.logging_utils import get_logger
21
+
21
22
  logger = get_logger(__name__)
22
23
 
23
24
 
@@ -24,10 +24,11 @@ except ImportError:
24
24
 
25
25
  import contextlib
26
26
 
27
- from .event_bus import EventBus
28
-
29
27
  # Configure logger
30
28
  from claude_mpm.core.logging_utils import get_logger
29
+
30
+ from .event_bus import EventBus
31
+
31
32
  logger = get_logger(__name__)
32
33
 
33
34
 
@@ -9,10 +9,10 @@ from collections import OrderedDict
9
9
  from datetime import datetime, timezone
10
10
  from typing import Any, Dict, Optional
11
11
 
12
+ from claude_mpm.core.logging_utils import get_logger
12
13
  from claude_mpm.services.agents.management import AgentCapabilitiesGenerator
13
14
  from claude_mpm.services.agents.registry import DeployedAgentDiscovery
14
15
 
15
- from claude_mpm.core.logging_utils import get_logger
16
16
  logger = get_logger(__name__)
17
17
 
18
18
 
@@ -31,9 +31,9 @@ except ImportError:
31
31
  import psutil
32
32
 
33
33
  # from claude_mpm.core.base_service import BaseService
34
+ from claude_mpm.core.logging_utils import get_logger
34
35
  from claude_mpm.services.socketio.server.main import SocketIOServer
35
36
 
36
- from claude_mpm.core.logging_utils import get_logger
37
37
  logger = get_logger(__name__)
38
38
 
39
39
 
@@ -76,6 +76,7 @@ class MCPConfigManager:
76
76
 
77
77
  # Check system PATH (including homebrew)
78
78
  import shutil
79
+
79
80
  system_path = shutil.which(service_name)
80
81
  if system_path and system_path not in candidates:
81
82
  candidates.append(system_path)
@@ -84,14 +85,13 @@ class MCPConfigManager:
84
85
  for path in candidates:
85
86
  try:
86
87
  result = subprocess.run(
87
- [path, "--help"],
88
- capture_output=True,
89
- text=True,
90
- timeout=5
88
+ [path, "--help"], capture_output=True, text=True, timeout=5, check=False
91
89
  )
92
90
  # Check if this version has MCP support
93
91
  if "claude" in result.stdout or "mcp" in result.stdout:
94
- self.logger.debug(f"Found kuzu-memory with MCP support at {path}")
92
+ self.logger.debug(
93
+ f"Found kuzu-memory with MCP support at {path}"
94
+ )
95
95
  return path
96
96
  except:
97
97
  pass
@@ -125,7 +125,9 @@ class MCPConfigManager:
125
125
  )
126
126
  return local_path
127
127
 
128
- self.logger.debug(f"Service {service_name} not found - will auto-install when needed")
128
+ self.logger.debug(
129
+ f"Service {service_name} not found - will auto-install when needed"
130
+ )
129
131
  return None
130
132
 
131
133
  def _check_pipx_installation(self, service_name: str) -> Optional[str]:
@@ -224,12 +226,10 @@ class MCPConfigManager:
224
226
  # Check kuzu-memory version to determine correct command
225
227
  # v1.1.0+ has "claude mcp-server", v1.0.0 has "serve"
226
228
  import subprocess
229
+
227
230
  try:
228
231
  result = subprocess.run(
229
- [service_path, "--help"],
230
- capture_output=True,
231
- text=True,
232
- timeout=10
232
+ [service_path, "--help"], capture_output=True, text=True, timeout=10, check=False
233
233
  )
234
234
  if "claude" in result.stdout:
235
235
  # v1.1.0+ with claude command
@@ -395,6 +395,7 @@ async def auto_initialize_vector_search():
395
395
  try:
396
396
  # Import MCPConfigManager to handle installation
397
397
  from claude_mpm.services.mcp_config_manager import MCPConfigManager
398
+
398
399
  config_manager = MCPConfigManager()
399
400
 
400
401
  # Check if mcp-vector-search is already installed
@@ -411,7 +412,9 @@ async def auto_initialize_vector_search():
411
412
  import subprocess
412
413
 
413
414
  if not shutil.which("pipx"):
414
- logger.warning("⚠️ pipx not found. Please install pipx to enable automatic mcp-vector-search installation")
415
+ logger.warning(
416
+ "⚠️ pipx not found. Please install pipx to enable automatic mcp-vector-search installation"
417
+ )
415
418
  logger.info(" Install pipx with: python -m pip install --user pipx")
416
419
  return
417
420
 
@@ -420,26 +423,34 @@ async def auto_initialize_vector_search():
420
423
  ["pipx", "install", "mcp-vector-search"],
421
424
  capture_output=True,
422
425
  text=True,
423
- timeout=60 # 1 minute timeout for installation
426
+ timeout=60, check=False, # 1 minute timeout for installation
424
427
  )
425
428
 
426
429
  if result.returncode == 0:
427
430
  logger.info("✅ mcp-vector-search installed successfully")
428
431
  # Detect the newly installed path
429
- vector_search_path = config_manager.detect_service_path("mcp-vector-search")
432
+ vector_search_path = config_manager.detect_service_path(
433
+ "mcp-vector-search"
434
+ )
430
435
  if not vector_search_path:
431
- logger.warning("mcp-vector-search installed but command not found in PATH")
436
+ logger.warning(
437
+ "mcp-vector-search installed but command not found in PATH"
438
+ )
432
439
  return
433
440
 
434
441
  # Update the Claude configuration to include the newly installed service
435
442
  logger.info("📝 Updating Claude configuration...")
436
- config_success, config_msg = config_manager.ensure_mcp_services_configured()
443
+ config_success, config_msg = (
444
+ config_manager.ensure_mcp_services_configured()
445
+ )
437
446
  if config_success:
438
447
  logger.info(f"✅ {config_msg}")
439
448
  else:
440
449
  logger.warning(f"⚠️ Configuration update issue: {config_msg}")
441
450
  else:
442
- logger.warning(f"Failed to install mcp-vector-search: {result.stderr}")
451
+ logger.warning(
452
+ f"Failed to install mcp-vector-search: {result.stderr}"
453
+ )
443
454
  return
444
455
 
445
456
  except subprocess.TimeoutExpired:
@@ -452,10 +463,14 @@ async def auto_initialize_vector_search():
452
463
  # At this point, mcp-vector-search should be available
453
464
  # Get the actual command to use
454
465
  import shutil
466
+
455
467
  vector_search_cmd = shutil.which("mcp-vector-search")
456
468
  if not vector_search_cmd:
457
469
  # Try pipx installation path as fallback
458
- pipx_path = Path.home() / ".local/pipx/venvs/mcp-vector-search/bin/mcp-vector-search"
470
+ pipx_path = (
471
+ Path.home()
472
+ / ".local/pipx/venvs/mcp-vector-search/bin/mcp-vector-search"
473
+ )
459
474
  if pipx_path.exists():
460
475
  vector_search_cmd = str(pipx_path)
461
476
  else:
@@ -477,10 +492,13 @@ async def auto_initialize_vector_search():
477
492
  if chroma_db.exists() and chroma_db.stat().st_size > 0:
478
493
  logger.info("✓ Vector search index is healthy and ready")
479
494
  return
480
- else:
481
- logger.info("⚠️ Vector search index may be corrupted, rebuilding...")
495
+ logger.info(
496
+ "⚠️ Vector search index may be corrupted, rebuilding..."
497
+ )
482
498
  except Exception as e:
483
- logger.debug(f"Vector search health check failed: {e}, will attempt to rebuild")
499
+ logger.debug(
500
+ f"Vector search health check failed: {e}, will attempt to rebuild"
501
+ )
484
502
 
485
503
  # Initialize or reinitialize the project
486
504
  logger.info(f"🎯 Initializing vector search for project: {current_dir}")
@@ -488,12 +506,13 @@ async def auto_initialize_vector_search():
488
506
  # Initialize the project (this creates the config)
489
507
  # Note: mcp-vector-search operates on the current directory
490
508
  import subprocess
509
+
491
510
  proc = subprocess.run(
492
511
  [vector_search_cmd, "init"],
493
512
  capture_output=True,
494
513
  text=True,
495
514
  timeout=30,
496
- cwd=str(current_dir) # Run in the project directory
515
+ cwd=str(current_dir), check=False, # Run in the project directory
497
516
  )
498
517
 
499
518
  if proc.returncode == 0:
@@ -508,29 +527,36 @@ async def auto_initialize_vector_search():
508
527
  capture_output=True,
509
528
  text=True,
510
529
  timeout=300, # 5 minute timeout for indexing
511
- cwd=str(current_dir) # Run in the project directory
530
+ cwd=str(current_dir), check=False, # Run in the project directory
512
531
  )
513
532
  if index_proc.returncode == 0:
514
533
  logger.info("✅ Project indexing completed successfully")
515
534
  # Parse output to show statistics if available
516
535
  if "indexed" in index_proc.stdout.lower():
517
536
  # Extract and log indexing statistics
518
- lines = index_proc.stdout.strip().split('\n')
537
+ lines = index_proc.stdout.strip().split("\n")
519
538
  for line in lines:
520
539
  if "indexed" in line.lower() or "files" in line.lower():
521
540
  logger.info(f" {line.strip()}")
522
541
  else:
523
- logger.warning(f"⚠️ Project indexing failed: {index_proc.stderr}")
542
+ logger.warning(
543
+ f"⚠️ Project indexing failed: {index_proc.stderr}"
544
+ )
524
545
  except subprocess.TimeoutExpired:
525
- logger.warning("⚠️ Project indexing timed out (will continue in background)")
546
+ logger.warning(
547
+ "⚠️ Project indexing timed out (will continue in background)"
548
+ )
526
549
  except Exception as e:
527
550
  logger.debug(f"Background indexing error (non-critical): {e}")
528
551
 
529
552
  # Run indexing in background thread
530
553
  import threading
554
+
531
555
  index_thread = threading.Thread(target=background_index, daemon=True)
532
556
  index_thread.start()
533
- logger.info("📚 Background indexing started - vector search will be available shortly")
557
+ logger.info(
558
+ "📚 Background indexing started - vector search will be available shortly"
559
+ )
534
560
 
535
561
  else:
536
562
  logger.warning(f"⚠️ Vector search initialization failed: {proc.stderr}")
@@ -556,6 +582,7 @@ async def auto_initialize_kuzu_memory():
556
582
  try:
557
583
  # Import MCPConfigManager to handle installation
558
584
  from claude_mpm.services.mcp_config_manager import MCPConfigManager
585
+
559
586
  config_manager = MCPConfigManager()
560
587
 
561
588
  # Check if kuzu-memory is already installed
@@ -572,7 +599,9 @@ async def auto_initialize_kuzu_memory():
572
599
  import subprocess
573
600
 
574
601
  if not shutil.which("pipx"):
575
- logger.warning("⚠️ pipx not found. Please install pipx to enable automatic kuzu-memory installation")
602
+ logger.warning(
603
+ "⚠️ pipx not found. Please install pipx to enable automatic kuzu-memory installation"
604
+ )
576
605
  logger.info(" Install pipx with: python -m pip install --user pipx")
577
606
  return
578
607
 
@@ -581,7 +610,7 @@ async def auto_initialize_kuzu_memory():
581
610
  ["pipx", "install", "kuzu-memory"],
582
611
  capture_output=True,
583
612
  text=True,
584
- timeout=60 # 1 minute timeout for installation
613
+ timeout=60, check=False, # 1 minute timeout for installation
585
614
  )
586
615
 
587
616
  if result.returncode == 0:
@@ -589,12 +618,16 @@ async def auto_initialize_kuzu_memory():
589
618
  # Detect the newly installed path
590
619
  kuzu_memory_path = config_manager.detect_service_path("kuzu-memory")
591
620
  if not kuzu_memory_path:
592
- logger.warning("kuzu-memory installed but command not found in PATH")
621
+ logger.warning(
622
+ "kuzu-memory installed but command not found in PATH"
623
+ )
593
624
  return
594
625
 
595
626
  # Update the Claude configuration to include the newly installed service
596
627
  logger.info("📝 Updating Claude configuration...")
597
- config_success, config_msg = config_manager.ensure_mcp_services_configured()
628
+ config_success, config_msg = (
629
+ config_manager.ensure_mcp_services_configured()
630
+ )
598
631
  if config_success:
599
632
  logger.info(f"✅ {config_msg}")
600
633
  else:
@@ -613,6 +646,7 @@ async def auto_initialize_kuzu_memory():
613
646
  # At this point, kuzu-memory should be available
614
647
  # Get the actual command to use
615
648
  import shutil
649
+
616
650
  kuzu_memory_cmd = shutil.which("kuzu-memory")
617
651
  if not kuzu_memory_cmd:
618
652
  # Try pipx installation path as fallback
@@ -629,18 +663,23 @@ async def auto_initialize_kuzu_memory():
629
663
 
630
664
  # Check if database is already initialized
631
665
  if kuzu_memories_dir.exists():
632
- logger.debug(f"Kuzu-memory database already initialized at {kuzu_memories_dir}")
666
+ logger.debug(
667
+ f"Kuzu-memory database already initialized at {kuzu_memories_dir}"
668
+ )
633
669
  else:
634
- logger.info(f"🎯 Initializing kuzu-memory database for project: {current_dir}")
670
+ logger.info(
671
+ f"🎯 Initializing kuzu-memory database for project: {current_dir}"
672
+ )
635
673
 
636
674
  # Initialize the database in current project directory
637
675
  import subprocess
676
+
638
677
  proc = subprocess.run(
639
678
  [kuzu_memory_cmd, "init"],
640
679
  capture_output=True,
641
680
  text=True,
642
681
  timeout=30,
643
- cwd=str(current_dir),
682
+ cwd=str(current_dir), check=False,
644
683
  )
645
684
 
646
685
  if proc.returncode == 0: