claude-mpm 4.1.7__py3-none-any.whl → 4.1.10__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 (109) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/INSTRUCTIONS.md +26 -1
  3. claude_mpm/agents/OUTPUT_STYLE.md +73 -0
  4. claude_mpm/agents/agents_metadata.py +57 -0
  5. claude_mpm/agents/templates/.claude-mpm/memories/README.md +17 -0
  6. claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +3 -0
  7. claude_mpm/agents/templates/agent-manager.json +263 -17
  8. claude_mpm/agents/templates/agent-manager.md +248 -10
  9. claude_mpm/agents/templates/agentic_coder_optimizer.json +222 -0
  10. claude_mpm/agents/templates/code_analyzer.json +18 -8
  11. claude_mpm/agents/templates/engineer.json +1 -1
  12. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +39 -0
  13. claude_mpm/agents/templates/qa.json +1 -1
  14. claude_mpm/agents/templates/research.json +1 -1
  15. claude_mpm/cli/__init__.py +4 -0
  16. claude_mpm/cli/commands/__init__.py +6 -0
  17. claude_mpm/cli/commands/analyze.py +547 -0
  18. claude_mpm/cli/commands/analyze_code.py +524 -0
  19. claude_mpm/cli/commands/configure.py +223 -25
  20. claude_mpm/cli/commands/configure_tui.py +65 -61
  21. claude_mpm/cli/commands/debug.py +1387 -0
  22. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  23. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  24. claude_mpm/cli/parsers/base_parser.py +29 -0
  25. claude_mpm/cli/parsers/configure_parser.py +23 -0
  26. claude_mpm/cli/parsers/debug_parser.py +319 -0
  27. claude_mpm/config/socketio_config.py +21 -21
  28. claude_mpm/constants.py +3 -1
  29. claude_mpm/core/framework_loader.py +148 -6
  30. claude_mpm/core/log_manager.py +16 -13
  31. claude_mpm/core/logger.py +1 -1
  32. claude_mpm/core/unified_agent_registry.py +1 -1
  33. claude_mpm/dashboard/.claude-mpm/socketio-instances.json +1 -0
  34. claude_mpm/dashboard/analysis_runner.py +428 -0
  35. claude_mpm/dashboard/static/built/components/activity-tree.js +2 -0
  36. claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
  37. claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
  38. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
  39. claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
  40. claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
  41. claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
  42. claude_mpm/dashboard/static/built/dashboard.js +1 -1
  43. claude_mpm/dashboard/static/built/socket-client.js +1 -1
  44. claude_mpm/dashboard/static/css/activity.css +549 -0
  45. claude_mpm/dashboard/static/css/code-tree.css +846 -0
  46. claude_mpm/dashboard/static/css/dashboard.css +245 -0
  47. claude_mpm/dashboard/static/dist/components/activity-tree.js +2 -0
  48. claude_mpm/dashboard/static/dist/components/code-tree.js +2 -0
  49. claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
  50. claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
  51. claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
  52. claude_mpm/dashboard/static/dist/components/working-directory.js +1 -1
  53. claude_mpm/dashboard/static/dist/dashboard.js +1 -1
  54. claude_mpm/dashboard/static/dist/socket-client.js +1 -1
  55. claude_mpm/dashboard/static/js/components/activity-tree.js +1139 -0
  56. claude_mpm/dashboard/static/js/components/code-tree.js +1357 -0
  57. claude_mpm/dashboard/static/js/components/code-viewer.js +480 -0
  58. claude_mpm/dashboard/static/js/components/event-viewer.js +11 -0
  59. claude_mpm/dashboard/static/js/components/session-manager.js +40 -4
  60. claude_mpm/dashboard/static/js/components/socket-manager.js +12 -0
  61. claude_mpm/dashboard/static/js/components/ui-state-manager.js +4 -0
  62. claude_mpm/dashboard/static/js/components/working-directory.js +17 -1
  63. claude_mpm/dashboard/static/js/dashboard.js +39 -0
  64. claude_mpm/dashboard/static/js/socket-client.js +414 -20
  65. claude_mpm/dashboard/templates/index.html +184 -4
  66. claude_mpm/hooks/claude_hooks/hook_handler.py +182 -5
  67. claude_mpm/hooks/claude_hooks/installer.py +728 -0
  68. claude_mpm/scripts/claude-hook-handler.sh +161 -0
  69. claude_mpm/scripts/socketio_daemon.py +121 -8
  70. claude_mpm/services/agents/deployment/agent_config_provider.py +127 -27
  71. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +2 -2
  72. claude_mpm/services/agents/deployment/agent_record_service.py +1 -2
  73. claude_mpm/services/agents/memory/memory_format_service.py +1 -5
  74. claude_mpm/services/cli/agent_cleanup_service.py +1 -2
  75. claude_mpm/services/cli/agent_dependency_service.py +1 -1
  76. claude_mpm/services/cli/agent_validation_service.py +3 -4
  77. claude_mpm/services/cli/dashboard_launcher.py +2 -3
  78. claude_mpm/services/cli/startup_checker.py +0 -10
  79. claude_mpm/services/core/cache_manager.py +1 -2
  80. claude_mpm/services/core/path_resolver.py +1 -4
  81. claude_mpm/services/core/service_container.py +2 -2
  82. claude_mpm/services/diagnostics/checks/instructions_check.py +2 -5
  83. claude_mpm/services/event_bus/direct_relay.py +98 -20
  84. claude_mpm/services/infrastructure/monitoring/__init__.py +11 -11
  85. claude_mpm/services/infrastructure/monitoring.py +11 -11
  86. claude_mpm/services/project/architecture_analyzer.py +1 -1
  87. claude_mpm/services/project/dependency_analyzer.py +4 -4
  88. claude_mpm/services/project/language_analyzer.py +3 -3
  89. claude_mpm/services/project/metrics_collector.py +3 -6
  90. claude_mpm/services/socketio/handlers/__init__.py +2 -0
  91. claude_mpm/services/socketio/handlers/code_analysis.py +170 -0
  92. claude_mpm/services/socketio/handlers/registry.py +2 -0
  93. claude_mpm/services/socketio/server/connection_manager.py +95 -65
  94. claude_mpm/services/socketio/server/core.py +125 -17
  95. claude_mpm/services/socketio/server/main.py +44 -5
  96. claude_mpm/services/visualization/__init__.py +19 -0
  97. claude_mpm/services/visualization/mermaid_generator.py +938 -0
  98. claude_mpm/tools/__main__.py +208 -0
  99. claude_mpm/tools/code_tree_analyzer.py +778 -0
  100. claude_mpm/tools/code_tree_builder.py +632 -0
  101. claude_mpm/tools/code_tree_events.py +318 -0
  102. claude_mpm/tools/socketio_debug.py +671 -0
  103. {claude_mpm-4.1.7.dist-info → claude_mpm-4.1.10.dist-info}/METADATA +1 -1
  104. {claude_mpm-4.1.7.dist-info → claude_mpm-4.1.10.dist-info}/RECORD +108 -77
  105. claude_mpm/agents/schema/agent_schema.json +0 -314
  106. {claude_mpm-4.1.7.dist-info → claude_mpm-4.1.10.dist-info}/WHEEL +0 -0
  107. {claude_mpm-4.1.7.dist-info → claude_mpm-4.1.10.dist-info}/entry_points.txt +0 -0
  108. {claude_mpm-4.1.7.dist-info → claude_mpm-4.1.10.dist-info}/licenses/LICENSE +0 -0
  109. {claude_mpm-4.1.7.dist-info → claude_mpm-4.1.10.dist-info}/top_level.txt +0 -0
@@ -24,28 +24,25 @@ from claude_mpm.core.constants import NetworkConfig, RetryConfig, SystemLimits
24
24
  # Connection stability settings - MUST be consistent between client and server
25
25
  CONNECTION_CONFIG = {
26
26
  # Ping/pong intervals (milliseconds for client, seconds for server)
27
- 'ping_interval_ms': 45000, # 45 seconds (for client JavaScript)
28
- 'ping_interval': 45, # 45 seconds (for server Python)
29
- 'ping_timeout_ms': 20000, # 20 seconds (for client JavaScript)
30
- 'ping_timeout': 20, # 20 seconds (for server Python)
31
-
27
+ "ping_interval_ms": 25000, # 25 seconds (for client JavaScript)
28
+ "ping_interval": 25, # 25 seconds (for server Python) - reduced for stability
29
+ "ping_timeout_ms": 20000, # 20 seconds (for client JavaScript)
30
+ "ping_timeout": 20, # 20 seconds (for server Python)
32
31
  # Connection management
33
- 'stale_timeout': 180, # 3 minutes before considering connection stale
34
- 'health_check_interval': 30, # Health check every 30 seconds
35
- 'event_ttl': 300, # Keep events for 5 minutes for replay
36
-
32
+ "stale_timeout": 90, # 90 seconds before considering connection stale (was 180)
33
+ "health_check_interval": 30, # Health check every 30 seconds
34
+ "event_ttl": 300, # Keep events for 5 minutes for replay
35
+ "connection_timeout": 10, # 10 seconds for initial connection timeout
37
36
  # Client reconnection settings
38
- 'reconnection_attempts': 5, # Number of reconnection attempts
39
- 'reconnection_delay': 1000, # Initial delay in ms
40
- 'reconnection_delay_max': 5000, # Maximum delay in ms
41
-
37
+ "reconnection_attempts": 5, # Number of reconnection attempts
38
+ "reconnection_delay": 1000, # Initial delay in ms
39
+ "reconnection_delay_max": 5000, # Maximum delay in ms
42
40
  # Feature flags
43
- 'enable_extra_heartbeat': False, # Disable redundant heartbeats
44
- 'enable_health_monitoring': True, # Enable connection health monitoring
45
-
41
+ "enable_extra_heartbeat": False, # Disable redundant heartbeats
42
+ "enable_health_monitoring": True, # Enable connection health monitoring
46
43
  # Buffer settings
47
- 'max_events_buffer': 1000, # Maximum events to buffer per client
48
- 'max_http_buffer_size': 1e8, # 100MB max buffer for large payloads
44
+ "max_events_buffer": 1000, # Maximum events to buffer per client
45
+ "max_http_buffer_size": 1e8, # 100MB max buffer for large payloads
49
46
  }
50
47
 
51
48
 
@@ -60,9 +57,12 @@ class SocketIOConfig:
60
57
 
61
58
  # Connection settings - Use centralized config for consistency
62
59
  cors_allowed_origins: str = "*" # Configure properly for production
63
- ping_timeout: int = CONNECTION_CONFIG['ping_timeout'] # 20 seconds
64
- ping_interval: int = CONNECTION_CONFIG['ping_interval'] # 45 seconds
65
- max_http_buffer_size: int = int(CONNECTION_CONFIG['max_http_buffer_size'])
60
+ ping_timeout: int = CONNECTION_CONFIG["ping_timeout"] # 20 seconds
61
+ ping_interval: int = CONNECTION_CONFIG["ping_interval"] # 25 seconds (was 45)
62
+ max_http_buffer_size: int = int(CONNECTION_CONFIG["max_http_buffer_size"])
63
+ connection_timeout: int = CONNECTION_CONFIG.get(
64
+ "connection_timeout", 10
65
+ ) # 10 seconds
66
66
 
67
67
  # Compatibility settings
68
68
  min_client_version: str = "0.7.0"
claude_mpm/constants.py CHANGED
@@ -38,6 +38,8 @@ class CLICommands(str, Enum):
38
38
  CONFIG = "config"
39
39
  CONFIGURE = "configure"
40
40
  AGGREGATE = "aggregate"
41
+ ANALYZE = "analyze"
42
+ ANALYZE_CODE = "analyze-code"
41
43
  CLEANUP = "cleanup-memory"
42
44
  MCP = "mcp"
43
45
  DOCTOR = "doctor"
@@ -217,7 +219,7 @@ class Paths(str, Enum):
217
219
 
218
220
  CLAUDE_AGENTS_DIR = ".claude/agents"
219
221
  CLAUDE_CONFIG_DIR = ".claude"
220
- MPM_LOG_DIR = ".claude-mpm/logs"
222
+ MPM_LOG_DIR = "logs/mpm"
221
223
  MPM_SESSION_DIR = ".claude-mpm/session"
222
224
  MPM_PROMPTS_DIR = ".claude-mpm/prompts"
223
225
 
@@ -1,6 +1,10 @@
1
1
  """Framework loader for Claude MPM."""
2
2
 
3
+ import getpass
4
+ import locale
3
5
  import logging
6
+ import os
7
+ import platform
4
8
  import time
5
9
  from datetime import datetime
6
10
  from pathlib import Path
@@ -995,11 +999,8 @@ class FrameworkLoader:
995
999
  # Add dynamic agent capabilities section
996
1000
  instructions += self._generate_agent_capabilities_section()
997
1001
 
998
- # Add current date for temporal awareness
999
- instructions += f"\n\n## Temporal Context\n**Today's Date**: {datetime.now().strftime('%Y-%m-%d')}\n"
1000
- instructions += (
1001
- "Apply date awareness to all time-sensitive tasks and decisions.\n"
1002
- )
1002
+ # Add enhanced temporal and user context for better awareness
1003
+ instructions += self._generate_temporal_user_context()
1003
1004
 
1004
1005
  # Add BASE_PM.md framework requirements AFTER INSTRUCTIONS.md
1005
1006
  if self.framework_content.get("base_pm_instructions"):
@@ -1322,6 +1323,147 @@ Extract tickets from these patterns:
1322
1323
  self._agent_capabilities_cache_time = current_time
1323
1324
  return result
1324
1325
 
1326
+ def _generate_temporal_user_context(self) -> str:
1327
+ """Generate enhanced temporal and user context for better PM awareness.
1328
+
1329
+ Returns:
1330
+ str: Formatted context string with datetime, user, and system information
1331
+ """
1332
+ context_lines = ["\n\n## Temporal & User Context\n"]
1333
+
1334
+ try:
1335
+ # Get current datetime with timezone awareness
1336
+ now = datetime.now()
1337
+
1338
+ # Try to get timezone info - fallback to UTC offset if timezone name not available
1339
+ try:
1340
+ import time as time_module
1341
+
1342
+ if hasattr(time_module, "tzname"):
1343
+ tz_name = time_module.tzname[time_module.daylight]
1344
+ tz_offset = time_module.strftime("%z")
1345
+ if tz_offset:
1346
+ # Format UTC offset properly (e.g., -0800 to -08:00)
1347
+ tz_offset = (
1348
+ f"{tz_offset[:3]}:{tz_offset[3:]}"
1349
+ if len(tz_offset) >= 4
1350
+ else tz_offset
1351
+ )
1352
+ tz_info = f"{tz_name} (UTC{tz_offset})"
1353
+ else:
1354
+ tz_info = tz_name
1355
+ else:
1356
+ tz_info = "Local Time"
1357
+ except Exception:
1358
+ tz_info = "Local Time"
1359
+
1360
+ # Format datetime components
1361
+ date_str = now.strftime("%Y-%m-%d")
1362
+ time_str = now.strftime("%H:%M:%S")
1363
+ day_name = now.strftime("%A")
1364
+
1365
+ context_lines.append(
1366
+ f"**Current DateTime**: {date_str} {time_str} {tz_info}\n"
1367
+ )
1368
+ context_lines.append(f"**Day**: {day_name}\n")
1369
+
1370
+ except Exception as e:
1371
+ # Fallback to basic date if enhanced datetime fails
1372
+ self.logger.debug(f"Error generating enhanced datetime context: {e}")
1373
+ context_lines.append(
1374
+ f"**Today's Date**: {datetime.now().strftime('%Y-%m-%d')}\n"
1375
+ )
1376
+
1377
+ try:
1378
+ # Get user information with safe fallbacks
1379
+ username = None
1380
+
1381
+ # Try multiple methods to get username
1382
+ methods = [
1383
+ lambda: os.environ.get("USER"),
1384
+ lambda: os.environ.get("USERNAME"), # Windows fallback
1385
+ lambda: getpass.getuser(),
1386
+ ]
1387
+
1388
+ for method in methods:
1389
+ try:
1390
+ username = method()
1391
+ if username:
1392
+ break
1393
+ except Exception:
1394
+ continue
1395
+
1396
+ if username:
1397
+ context_lines.append(f"**User**: {username}\n")
1398
+
1399
+ # Add home directory if available
1400
+ try:
1401
+ home_dir = os.path.expanduser("~")
1402
+ if home_dir and home_dir != "~":
1403
+ context_lines.append(f"**Home Directory**: {home_dir}\n")
1404
+ except Exception:
1405
+ pass
1406
+
1407
+ except Exception as e:
1408
+ # User detection is optional, don't fail
1409
+ self.logger.debug(f"Could not detect user information: {e}")
1410
+
1411
+ try:
1412
+ # Get system information
1413
+ system_info = platform.system()
1414
+ if system_info:
1415
+ # Enhance system name for common platforms
1416
+ system_names = {
1417
+ "Darwin": "Darwin (macOS)",
1418
+ "Linux": "Linux",
1419
+ "Windows": "Windows",
1420
+ }
1421
+ system_display = system_names.get(system_info, system_info)
1422
+ context_lines.append(f"**System**: {system_display}\n")
1423
+
1424
+ # Add platform version if available
1425
+ try:
1426
+ platform_version = platform.release()
1427
+ if platform_version:
1428
+ context_lines.append(
1429
+ f"**System Version**: {platform_version}\n"
1430
+ )
1431
+ except Exception:
1432
+ pass
1433
+
1434
+ except Exception as e:
1435
+ # System info is optional
1436
+ self.logger.debug(f"Could not detect system information: {e}")
1437
+
1438
+ try:
1439
+ # Add current working directory
1440
+ cwd = os.getcwd()
1441
+ if cwd:
1442
+ context_lines.append(f"**Working Directory**: {cwd}\n")
1443
+ except Exception:
1444
+ pass
1445
+
1446
+ try:
1447
+ # Add locale information if available
1448
+ current_locale = locale.getlocale()
1449
+ if current_locale and current_locale[0]:
1450
+ context_lines.append(f"**Locale**: {current_locale[0]}\n")
1451
+ except Exception:
1452
+ # Locale is optional
1453
+ pass
1454
+
1455
+ # Add instruction for applying context
1456
+ context_lines.append(
1457
+ "\nApply temporal and user awareness to all tasks, "
1458
+ "decisions, and interactions.\n"
1459
+ )
1460
+ context_lines.append(
1461
+ "Use this context for personalized responses and "
1462
+ "time-sensitive operations.\n"
1463
+ )
1464
+
1465
+ return "".join(context_lines)
1466
+
1325
1467
  def _parse_agent_metadata(self, agent_file: Path) -> Optional[Dict[str, Any]]:
1326
1468
  """Parse agent metadata from deployed agent file.
1327
1469
  Uses caching based on file path and modification time.
@@ -1333,7 +1475,7 @@ Extract tickets from these patterns:
1333
1475
  # Check cache based on file path and modification time
1334
1476
  cache_key = str(agent_file)
1335
1477
  file_mtime = agent_file.stat().st_mtime
1336
- current_time = time.time()
1478
+ time.time()
1337
1479
 
1338
1480
  # Try to get from cache first
1339
1481
  cached_result = self._cache_manager.get_agent_metadata(cache_key)
@@ -101,9 +101,7 @@ class LogManager:
101
101
  }
102
102
 
103
103
  # Base directories
104
- self.base_log_dir = Path(
105
- logging_config.get("base_directory", ".claude-mpm/logs")
106
- )
104
+ self.base_log_dir = Path(logging_config.get("base_directory", "logs"))
107
105
  if not self.base_log_dir.is_absolute():
108
106
  self.base_log_dir = Path.cwd() / self.base_log_dir
109
107
 
@@ -352,27 +350,32 @@ class LogManager:
352
350
  """
353
351
  One-time migration to move existing MPM logs to new subdirectory.
354
352
 
355
- Moves mpm_*.log files from .claude-mpm/logs/ to .claude-mpm/logs/mpm/
353
+ Moves mpm_*.log files from .claude-mpm/logs/ to logs/mpm/
356
354
  """
357
355
  try:
358
- old_location = self.base_log_dir
356
+ # Check both old possible locations
357
+ old_locations = [
358
+ Path.cwd() / ".claude-mpm" / "logs", # Old default location
359
+ self.base_log_dir, # Current base location (logs/)
360
+ ]
359
361
  new_location = self.base_log_dir / "mpm"
360
362
 
361
- # Only proceed if old location exists and has MPM logs
362
- if not old_location.exists():
363
- return
364
-
365
- # Find all MPM log files in the old location
366
- mpm_logs = list(old_location.glob("mpm_*.log"))
363
+ # Collect all MPM logs from all old locations
364
+ all_mpm_logs = []
365
+ for old_location in old_locations:
366
+ if old_location.exists() and old_location != new_location:
367
+ # Find all MPM log files in this location
368
+ mpm_logs = list(old_location.glob("mpm_*.log"))
369
+ all_mpm_logs.extend(mpm_logs)
367
370
 
368
- if not mpm_logs:
371
+ if not all_mpm_logs:
369
372
  return # No logs to migrate
370
373
 
371
374
  # Ensure new directory exists
372
375
  new_location.mkdir(parents=True, exist_ok=True)
373
376
 
374
377
  migrated_count = 0
375
- for log_file in mpm_logs:
378
+ for log_file in all_mpm_logs:
376
379
  try:
377
380
  # Move file to new location
378
381
  new_path = new_location / log_file.name
claude_mpm/core/logger.py CHANGED
@@ -232,7 +232,7 @@ def setup_logging(
232
232
  if log_dir is None:
233
233
  # Use deployment root for logs to keep everything centralized
234
234
  deployment_root = get_project_root()
235
- log_dir = deployment_root / ".claude-mpm" / "logs"
235
+ log_dir = deployment_root / "logs" / "mpm"
236
236
 
237
237
  log_dir.mkdir(parents=True, exist_ok=True)
238
238
 
@@ -455,7 +455,7 @@ class UnifiedAgentRegistry:
455
455
  """Apply tier precedence rules to resolve conflicts."""
456
456
  # Group agents by their actual name (without tier suffix)
457
457
  agent_groups = {}
458
- for registry_key, metadata in self.registry.items():
458
+ for _registry_key, metadata in self.registry.items():
459
459
  # Extract the actual agent name (registry_key is "name_tier")
460
460
  agent_name = metadata.name # Use the actual name from metadata
461
461
  if agent_name not in agent_groups: