claude-mpm 3.7.4__py3-none-any.whl → 3.8.1__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 (117) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_PM.md +0 -106
  3. claude_mpm/agents/INSTRUCTIONS.md +0 -78
  4. claude_mpm/agents/MEMORY.md +88 -0
  5. claude_mpm/agents/WORKFLOW.md +86 -0
  6. claude_mpm/agents/schema/agent_schema.json +1 -1
  7. claude_mpm/agents/templates/code_analyzer.json +26 -11
  8. claude_mpm/agents/templates/data_engineer.json +4 -7
  9. claude_mpm/agents/templates/documentation.json +2 -2
  10. claude_mpm/agents/templates/engineer.json +2 -2
  11. claude_mpm/agents/templates/ops.json +3 -8
  12. claude_mpm/agents/templates/qa.json +2 -3
  13. claude_mpm/agents/templates/research.json +2 -3
  14. claude_mpm/agents/templates/security.json +3 -6
  15. claude_mpm/agents/templates/ticketing.json +4 -9
  16. claude_mpm/agents/templates/version_control.json +3 -3
  17. claude_mpm/agents/templates/web_qa.json +4 -4
  18. claude_mpm/agents/templates/web_ui.json +4 -4
  19. claude_mpm/cli/__init__.py +2 -2
  20. claude_mpm/cli/commands/__init__.py +2 -1
  21. claude_mpm/cli/commands/agents.py +118 -1
  22. claude_mpm/cli/commands/tickets.py +596 -19
  23. claude_mpm/cli/parser.py +228 -5
  24. claude_mpm/config/__init__.py +30 -39
  25. claude_mpm/config/socketio_config.py +8 -5
  26. claude_mpm/constants.py +13 -0
  27. claude_mpm/core/__init__.py +8 -18
  28. claude_mpm/core/cache.py +596 -0
  29. claude_mpm/core/claude_runner.py +166 -622
  30. claude_mpm/core/config.py +5 -1
  31. claude_mpm/core/constants.py +339 -0
  32. claude_mpm/core/container.py +461 -22
  33. claude_mpm/core/exceptions.py +392 -0
  34. claude_mpm/core/framework_loader.py +208 -93
  35. claude_mpm/core/interactive_session.py +432 -0
  36. claude_mpm/core/interfaces.py +424 -0
  37. claude_mpm/core/lazy.py +467 -0
  38. claude_mpm/core/logging_config.py +444 -0
  39. claude_mpm/core/oneshot_session.py +465 -0
  40. claude_mpm/core/optimized_agent_loader.py +485 -0
  41. claude_mpm/core/optimized_startup.py +490 -0
  42. claude_mpm/core/service_registry.py +52 -26
  43. claude_mpm/core/socketio_pool.py +162 -5
  44. claude_mpm/core/types.py +292 -0
  45. claude_mpm/core/typing_utils.py +477 -0
  46. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +46 -2
  47. claude_mpm/dashboard/templates/index.html +5 -5
  48. claude_mpm/hooks/claude_hooks/hook_handler.py +213 -99
  49. claude_mpm/init.py +2 -1
  50. claude_mpm/services/__init__.py +78 -14
  51. claude_mpm/services/agent/__init__.py +24 -0
  52. claude_mpm/services/agent/deployment.py +2548 -0
  53. claude_mpm/services/agent/management.py +598 -0
  54. claude_mpm/services/agent/registry.py +813 -0
  55. claude_mpm/services/agents/deployment/agent_deployment.py +592 -269
  56. claude_mpm/services/agents/deployment/async_agent_deployment.py +5 -1
  57. claude_mpm/services/agents/management/agent_capabilities_generator.py +21 -11
  58. claude_mpm/services/agents/memory/agent_memory_manager.py +156 -1
  59. claude_mpm/services/async_session_logger.py +8 -3
  60. claude_mpm/services/communication/__init__.py +21 -0
  61. claude_mpm/services/communication/socketio.py +1933 -0
  62. claude_mpm/services/communication/websocket.py +479 -0
  63. claude_mpm/services/core/__init__.py +123 -0
  64. claude_mpm/services/core/base.py +247 -0
  65. claude_mpm/services/core/interfaces.py +951 -0
  66. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +23 -23
  67. claude_mpm/services/framework_claude_md_generator.py +3 -2
  68. claude_mpm/services/health_monitor.py +4 -3
  69. claude_mpm/services/hook_service.py +64 -4
  70. claude_mpm/services/infrastructure/__init__.py +21 -0
  71. claude_mpm/services/infrastructure/logging.py +202 -0
  72. claude_mpm/services/infrastructure/monitoring.py +893 -0
  73. claude_mpm/services/memory/indexed_memory.py +648 -0
  74. claude_mpm/services/project/__init__.py +21 -0
  75. claude_mpm/services/project/analyzer.py +864 -0
  76. claude_mpm/services/project/registry.py +608 -0
  77. claude_mpm/services/project_analyzer.py +95 -2
  78. claude_mpm/services/recovery_manager.py +15 -9
  79. claude_mpm/services/socketio/__init__.py +25 -0
  80. claude_mpm/services/socketio/handlers/__init__.py +25 -0
  81. claude_mpm/services/socketio/handlers/base.py +121 -0
  82. claude_mpm/services/socketio/handlers/connection.py +198 -0
  83. claude_mpm/services/socketio/handlers/file.py +213 -0
  84. claude_mpm/services/socketio/handlers/git.py +723 -0
  85. claude_mpm/services/socketio/handlers/memory.py +27 -0
  86. claude_mpm/services/socketio/handlers/project.py +25 -0
  87. claude_mpm/services/socketio/handlers/registry.py +145 -0
  88. claude_mpm/services/socketio_client_manager.py +12 -7
  89. claude_mpm/services/socketio_server.py +156 -30
  90. claude_mpm/services/ticket_manager.py +377 -51
  91. claude_mpm/utils/agent_dependency_loader.py +66 -15
  92. claude_mpm/utils/error_handler.py +1 -1
  93. claude_mpm/utils/robust_installer.py +587 -0
  94. claude_mpm/validation/agent_validator.py +27 -14
  95. claude_mpm/validation/frontmatter_validator.py +231 -0
  96. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/METADATA +74 -41
  97. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/RECORD +101 -76
  98. claude_mpm/.claude-mpm/logs/hooks_20250728.log +0 -10
  99. claude_mpm/agents/agent-template.yaml +0 -83
  100. claude_mpm/cli/README.md +0 -108
  101. claude_mpm/cli_module/refactoring_guide.md +0 -253
  102. claude_mpm/config/async_logging_config.yaml +0 -145
  103. claude_mpm/core/.claude-mpm/logs/hooks_20250730.log +0 -34
  104. claude_mpm/dashboard/.claude-mpm/memories/README.md +0 -36
  105. claude_mpm/dashboard/README.md +0 -121
  106. claude_mpm/dashboard/static/js/dashboard.js.backup +0 -1973
  107. claude_mpm/dashboard/templates/.claude-mpm/memories/README.md +0 -36
  108. claude_mpm/dashboard/templates/.claude-mpm/memories/engineer_agent.md +0 -39
  109. claude_mpm/dashboard/templates/.claude-mpm/memories/version_control_agent.md +0 -38
  110. claude_mpm/hooks/README.md +0 -96
  111. claude_mpm/schemas/agent_schema.json +0 -435
  112. claude_mpm/services/framework_claude_md_generator/README.md +0 -92
  113. claude_mpm/services/version_control/VERSION +0 -1
  114. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/WHEEL +0 -0
  115. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/entry_points.txt +0 -0
  116. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/licenses/LICENSE +0 -0
  117. {claude_mpm-3.7.4.dist-info → claude_mpm-3.8.1.dist-info}/top_level.txt +0 -0
@@ -462,10 +462,14 @@ class AsyncAgentDeploymentService:
462
462
  # IMPORTANT: No spaces after commas - Claude Code requires exact format
463
463
  tools_str = ','.join(tools) if isinstance(tools, list) else str(tools)
464
464
 
465
+ # Convert agent_id to Claude Code compatible name (replace underscores with hyphens)
466
+ # Claude Code requires name to match pattern: ^[a-z0-9]+(-[a-z0-9]+)*$
467
+ claude_code_name = agent_id.replace('_', '-').lower()
468
+
465
469
  # Build frontmatter with only the fields Claude Code uses
466
470
  frontmatter_lines = [
467
471
  "---",
468
- f"name: {agent_id}",
472
+ f"name: {claude_code_name}",
469
473
  f"description: {description}",
470
474
  f"version: {version_string}",
471
475
  f"base_version: {self._format_version_display(base_version)}",
@@ -116,9 +116,12 @@ class AgentCapabilitiesGenerator:
116
116
  if len(capability_text) > 100:
117
117
  capability_text = capability_text[:97] + '...'
118
118
 
119
+ # Clean up the agent name for TodoWrite usage
120
+ clean_name = agent['name'].replace(' Agent', '').replace('-', ' ')
121
+
119
122
  capabilities.append({
120
- 'name': agent['name'],
121
- 'id': agent['id'],
123
+ 'name': clean_name, # Clean name for TodoWrite
124
+ 'id': agent['id'], # Agent ID for Task tool
122
125
  'capability_text': capability_text,
123
126
  'tools': ', '.join(agent.get('tools', [])[:5]) # First 5 tools
124
127
  })
@@ -132,26 +135,33 @@ class AgentCapabilitiesGenerator:
132
135
  Configured Jinja2 template
133
136
  """
134
137
  template_content = """
135
- ## Agent Names & Capabilities
136
- **Core Agents**: {{ core_agents }}
138
+ ## Available Agent Capabilities
139
+
140
+ You have the following specialized agents available for delegation:
137
141
 
138
142
  {% if agents_by_tier.project %}
139
143
  ### Project-Specific Agents
140
144
  {% for agent in agents_by_tier.project %}
141
- - **{{ agent.name }}** ({{ agent.id }}): {{ agent.description }}
145
+ - **{{ agent.name|replace(' Agent', '')|replace('-', ' ') }}** (`{{ agent.id }}`): {{ agent.description }}
142
146
  {% endfor %}
143
147
 
144
148
  {% endif %}
145
- **Agent Capabilities**:
149
+ ### Engineering Agents
146
150
  {% for cap in detailed_capabilities %}
147
- - **{{ cap.name }}**: {{ cap.capability_text }}
151
+ {% if cap.id in ['engineer', 'data_engineer', 'documentation', 'ops', 'security', 'ticketing', 'version_control', 'web_ui'] %}
152
+ - **{{ cap.name }}** (`{{ cap.id }}`): {{ cap.capability_text }}
153
+ {% endif %}
148
154
  {% endfor %}
149
155
 
150
- **Agent Name Formats** (both valid):
151
- - Capitalized: {{ detailed_capabilities | map(attribute='name') | join('", "') }}
152
- - Lowercase-hyphenated: {{ detailed_capabilities | map(attribute='id') | join('", "') }}
156
+ ### Research Agents
157
+ {% for cap in detailed_capabilities %}
158
+ {% if cap.id in ['code_analyzer', 'qa', 'research', 'web_qa'] %}
159
+ - **{{ cap.name }}** (`{{ cap.id }}`): {{ cap.capability_text }}
160
+ {% endif %}
161
+ {% endfor %}
153
162
 
154
- *Generated from {{ total_agents }} deployed agents*
163
+ **Total Available Agents**: {{ total_agents }}
164
+ Use the agent ID in parentheses when delegating tasks via the Task tool.
155
165
  """.strip()
156
166
 
157
167
  return Template(template_content)
@@ -29,10 +29,11 @@ from claude_mpm.core.config import Config
29
29
  from claude_mpm.core.mixins import LoggerMixin
30
30
  from claude_mpm.utils.paths import PathResolver
31
31
  from claude_mpm.services.project_analyzer import ProjectAnalyzer
32
+ from claude_mpm.core.interfaces import MemoryServiceInterface
32
33
  # Socket.IO notifications are optional - we'll skip them if server is not available
33
34
 
34
35
 
35
- class AgentMemoryManager:
36
+ class AgentMemoryManager(MemoryServiceInterface):
36
37
  """Manages agent memory files with size limits and validation.
37
38
 
38
39
  WHY: Agents need to accumulate project-specific knowledge over time to become
@@ -1394,6 +1395,160 @@ Standard markdown with structured sections. Agents expect:
1394
1395
  except Exception as e:
1395
1396
  self.logger.error(f"Error ensuring memories directory: {e}")
1396
1397
  # Continue anyway - memory system should not block operations
1398
+
1399
+ # ================================================================================
1400
+ # Interface Adapter Methods
1401
+ # ================================================================================
1402
+ # These methods adapt the existing implementation to comply with MemoryServiceInterface
1403
+
1404
+ def load_memory(self, agent_id: str) -> Optional[str]:
1405
+ """Load memory for a specific agent.
1406
+
1407
+ WHY: This adapter method provides interface compliance by wrapping
1408
+ the existing load_agent_memory method.
1409
+
1410
+ Args:
1411
+ agent_id: Identifier of the agent
1412
+
1413
+ Returns:
1414
+ Memory content as string or None if not found
1415
+ """
1416
+ try:
1417
+ content = self.load_agent_memory(agent_id)
1418
+ return content if content else None
1419
+ except Exception as e:
1420
+ self.logger.error(f"Failed to load memory for {agent_id}: {e}")
1421
+ return None
1422
+
1423
+ def save_memory(self, agent_id: str, content: str) -> bool:
1424
+ """Save memory for a specific agent.
1425
+
1426
+ WHY: This adapter method provides interface compliance. The existing
1427
+ implementation uses update_agent_memory for modifications, so we
1428
+ implement a full save by writing directly to the file.
1429
+
1430
+ Args:
1431
+ agent_id: Identifier of the agent
1432
+ content: Memory content to save
1433
+
1434
+ Returns:
1435
+ True if save successful
1436
+ """
1437
+ try:
1438
+ memory_path = self.memories_dir / f"{agent_id}_agent.md"
1439
+
1440
+ # Validate size before saving
1441
+ is_valid, error_msg = self.validate_memory_size(content)
1442
+ if not is_valid:
1443
+ self.logger.error(f"Memory validation failed: {error_msg}")
1444
+ return False
1445
+
1446
+ # Write the content
1447
+ memory_path.write_text(content, encoding='utf-8')
1448
+ self.logger.info(f"Saved memory for agent {agent_id}")
1449
+ return True
1450
+
1451
+ except Exception as e:
1452
+ self.logger.error(f"Failed to save memory for {agent_id}: {e}")
1453
+ return False
1454
+
1455
+ def validate_memory_size(self, content: str) -> tuple[bool, Optional[str]]:
1456
+ """Validate memory content size and structure.
1457
+
1458
+ WHY: This adapter method provides interface compliance by implementing
1459
+ validation based on configured limits.
1460
+
1461
+ Args:
1462
+ content: Memory content to validate
1463
+
1464
+ Returns:
1465
+ Tuple of (is_valid, error_message)
1466
+ """
1467
+ try:
1468
+ # Check file size
1469
+ size_kb = len(content.encode('utf-8')) / 1024
1470
+ max_size_kb = self.memory_limits.get('max_file_size_kb', 8)
1471
+
1472
+ if size_kb > max_size_kb:
1473
+ return False, f"Memory size {size_kb:.1f}KB exceeds limit of {max_size_kb}KB"
1474
+
1475
+ # Check section count
1476
+ sections = re.findall(r'^##\s+(.+)$', content, re.MULTILINE)
1477
+ max_sections = self.memory_limits.get('max_sections', 10)
1478
+
1479
+ if len(sections) > max_sections:
1480
+ return False, f"Too many sections: {len(sections)} (max {max_sections})"
1481
+
1482
+ # Check for required sections
1483
+ required = set(self.REQUIRED_SECTIONS)
1484
+ found = set(sections)
1485
+ missing = required - found
1486
+
1487
+ if missing:
1488
+ return False, f"Missing required sections: {', '.join(missing)}"
1489
+
1490
+ return True, None
1491
+
1492
+ except Exception as e:
1493
+ return False, f"Validation error: {str(e)}"
1494
+
1495
+ def get_memory_metrics(self, agent_id: Optional[str] = None) -> Dict[str, Any]:
1496
+ """Get memory usage metrics.
1497
+
1498
+ WHY: This adapter method provides interface compliance by gathering
1499
+ metrics about memory usage.
1500
+
1501
+ Args:
1502
+ agent_id: Optional specific agent ID, or None for all
1503
+
1504
+ Returns:
1505
+ Dictionary with memory metrics
1506
+ """
1507
+ metrics = {
1508
+ "total_memories": 0,
1509
+ "total_size_kb": 0,
1510
+ "agent_metrics": {},
1511
+ "limits": self.memory_limits.copy()
1512
+ }
1513
+
1514
+ try:
1515
+ if agent_id:
1516
+ # Get metrics for specific agent
1517
+ memory_path = self.memories_dir / f"{agent_id}_agent.md"
1518
+ if memory_path.exists():
1519
+ content = memory_path.read_text(encoding='utf-8')
1520
+ size_kb = len(content.encode('utf-8')) / 1024
1521
+ sections = re.findall(r'^##\s+(.+)$', content, re.MULTILINE)
1522
+
1523
+ metrics["agent_metrics"][agent_id] = {
1524
+ "size_kb": round(size_kb, 2),
1525
+ "sections": len(sections),
1526
+ "exists": True
1527
+ }
1528
+ metrics["total_memories"] = 1
1529
+ metrics["total_size_kb"] = round(size_kb, 2)
1530
+ else:
1531
+ # Get metrics for all agents
1532
+ for memory_file in self.memories_dir.glob("*_agent.md"):
1533
+ agent_name = memory_file.stem.replace("_agent", "")
1534
+ content = memory_file.read_text(encoding='utf-8')
1535
+ size_kb = len(content.encode('utf-8')) / 1024
1536
+ sections = re.findall(r'^##\s+(.+)$', content, re.MULTILINE)
1537
+
1538
+ metrics["agent_metrics"][agent_name] = {
1539
+ "size_kb": round(size_kb, 2),
1540
+ "sections": len(sections),
1541
+ "exists": True
1542
+ }
1543
+ metrics["total_memories"] += 1
1544
+ metrics["total_size_kb"] += size_kb
1545
+
1546
+ metrics["total_size_kb"] = round(metrics["total_size_kb"], 2)
1547
+
1548
+ except Exception as e:
1549
+ self.logger.error(f"Failed to get memory metrics: {e}")
1550
+
1551
+ return metrics
1397
1552
 
1398
1553
 
1399
1554
  # Convenience functions for external use
@@ -27,6 +27,11 @@ import logging
27
27
  import logging.handlers
28
28
  from dataclasses import dataclass, asdict
29
29
  from enum import Enum
30
+ from claude_mpm.core.constants import (
31
+ SystemLimits,
32
+ TimeoutConfig,
33
+ PerformanceConfig
34
+ )
30
35
 
31
36
  # Import configuration manager
32
37
  from ..core.config import Config
@@ -108,7 +113,7 @@ class AsyncSessionLogger:
108
113
  else:
109
114
  self.log_format = LogFormat.JSON
110
115
 
111
- self.max_queue_size = max_queue_size if max_queue_size is not None else response_config.get('max_queue_size', 10000)
116
+ self.max_queue_size = max_queue_size if max_queue_size is not None else response_config.get('max_queue_size', SystemLimits.MAX_QUEUE_SIZE)
112
117
 
113
118
  # Handle async configuration with backward compatibility
114
119
  if enable_async is not None:
@@ -223,12 +228,12 @@ class AsyncSessionLogger:
223
228
  while not self._shutdown:
224
229
  try:
225
230
  # Get entry with timeout to allow shutdown checks
226
- entry = self._queue.get(timeout=0.1)
231
+ entry = self._queue.get(timeout=TimeoutConfig.QUEUE_GET_TIMEOUT)
227
232
 
228
233
  # Time the write operation
229
234
  start_time = time.perf_counter()
230
235
  self._write_entry(entry)
231
- write_time = (time.perf_counter() - start_time) * 1000
236
+ write_time = (time.perf_counter() - start_time) * PerformanceConfig.SECONDS_TO_MS
232
237
 
233
238
  # Update statistics
234
239
  write_times.append(write_time)
@@ -0,0 +1,21 @@
1
+ """
2
+ Communication Services Module
3
+ ============================
4
+
5
+ This module contains all communication-related services including
6
+ SocketIO server and WebSocket utilities.
7
+
8
+ Part of TSK-0046: Service Layer Architecture Reorganization
9
+
10
+ Services:
11
+ - SocketIOServer: Main SocketIO server for real-time communication
12
+ - WebSocketClientManager: WebSocket client management utilities
13
+ """
14
+
15
+ from .socketio import SocketIOServer
16
+ from .websocket import SocketIOClientManager
17
+
18
+ __all__ = [
19
+ 'SocketIOServer',
20
+ 'SocketIOClientManager',
21
+ ]