claude-mpm 4.1.4__py3-none-any.whl → 4.1.6__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 (81) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/templates/research.json +39 -13
  3. claude_mpm/cli/__init__.py +2 -0
  4. claude_mpm/cli/commands/__init__.py +2 -0
  5. claude_mpm/cli/commands/configure.py +1221 -0
  6. claude_mpm/cli/commands/configure_tui.py +1921 -0
  7. claude_mpm/cli/commands/tickets.py +365 -784
  8. claude_mpm/cli/parsers/base_parser.py +7 -0
  9. claude_mpm/cli/parsers/configure_parser.py +119 -0
  10. claude_mpm/cli/startup_logging.py +39 -12
  11. claude_mpm/constants.py +1 -0
  12. claude_mpm/core/output_style_manager.py +24 -0
  13. claude_mpm/core/socketio_pool.py +35 -3
  14. claude_mpm/core/unified_agent_registry.py +46 -15
  15. claude_mpm/dashboard/static/css/connection-status.css +370 -0
  16. claude_mpm/dashboard/static/js/components/connection-debug.js +654 -0
  17. claude_mpm/dashboard/static/js/connection-manager.js +536 -0
  18. claude_mpm/dashboard/templates/index.html +11 -0
  19. claude_mpm/hooks/claude_hooks/services/__init__.py +3 -1
  20. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +190 -0
  21. claude_mpm/services/agents/deployment/agent_discovery_service.py +12 -3
  22. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +172 -233
  23. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +575 -0
  24. claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
  25. claude_mpm/services/agents/deployment/agent_record_service.py +419 -0
  26. claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
  27. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +4 -2
  28. claude_mpm/services/diagnostics/checks/__init__.py +2 -0
  29. claude_mpm/services/diagnostics/checks/instructions_check.py +418 -0
  30. claude_mpm/services/diagnostics/diagnostic_runner.py +15 -2
  31. claude_mpm/services/event_bus/direct_relay.py +173 -0
  32. claude_mpm/services/infrastructure/__init__.py +31 -5
  33. claude_mpm/services/infrastructure/monitoring/__init__.py +43 -0
  34. claude_mpm/services/infrastructure/monitoring/aggregator.py +437 -0
  35. claude_mpm/services/infrastructure/monitoring/base.py +130 -0
  36. claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
  37. claude_mpm/services/infrastructure/monitoring/network.py +218 -0
  38. claude_mpm/services/infrastructure/monitoring/process.py +342 -0
  39. claude_mpm/services/infrastructure/monitoring/resources.py +243 -0
  40. claude_mpm/services/infrastructure/monitoring/service.py +367 -0
  41. claude_mpm/services/infrastructure/monitoring.py +67 -1030
  42. claude_mpm/services/project/analyzer.py +13 -4
  43. claude_mpm/services/project/analyzer_refactored.py +450 -0
  44. claude_mpm/services/project/analyzer_v2.py +566 -0
  45. claude_mpm/services/project/architecture_analyzer.py +461 -0
  46. claude_mpm/services/project/dependency_analyzer.py +462 -0
  47. claude_mpm/services/project/language_analyzer.py +265 -0
  48. claude_mpm/services/project/metrics_collector.py +410 -0
  49. claude_mpm/services/socketio/handlers/connection_handler.py +345 -0
  50. claude_mpm/services/socketio/server/broadcaster.py +32 -1
  51. claude_mpm/services/socketio/server/connection_manager.py +516 -0
  52. claude_mpm/services/socketio/server/core.py +63 -0
  53. claude_mpm/services/socketio/server/eventbus_integration.py +20 -9
  54. claude_mpm/services/socketio/server/main.py +27 -1
  55. claude_mpm/services/ticket_manager.py +5 -1
  56. claude_mpm/services/ticket_services/__init__.py +26 -0
  57. claude_mpm/services/ticket_services/crud_service.py +328 -0
  58. claude_mpm/services/ticket_services/formatter_service.py +290 -0
  59. claude_mpm/services/ticket_services/search_service.py +324 -0
  60. claude_mpm/services/ticket_services/validation_service.py +303 -0
  61. claude_mpm/services/ticket_services/workflow_service.py +244 -0
  62. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/METADATA +3 -1
  63. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/RECORD +67 -46
  64. claude_mpm/agents/OUTPUT_STYLE.md +0 -73
  65. claude_mpm/agents/backups/INSTRUCTIONS.md +0 -352
  66. claude_mpm/agents/templates/OPTIMIZATION_REPORT.md +0 -156
  67. claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -79
  68. claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -68
  69. claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -77
  70. claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -78
  71. claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -67
  72. claude_mpm/agents/templates/backup/research_agent_2025011_234551.json +0 -88
  73. claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -72
  74. claude_mpm/agents/templates/backup/research_memory_efficient.json +0 -88
  75. claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -78
  76. claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -62
  77. claude_mpm/agents/templates/vercel_ops_instructions.md +0 -582
  78. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/WHEEL +0 -0
  79. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/entry_points.txt +0 -0
  80. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/licenses/LICENSE +0 -0
  81. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,190 @@
1
+ """HTTP-based connection management service for Claude hook handler.
2
+
3
+ This service manages:
4
+ - HTTP POST event emission for ephemeral hook processes
5
+ - EventBus initialization (optional)
6
+ - Event emission through both channels
7
+
8
+ DESIGN DECISION: Use stateless HTTP POST instead of persistent SocketIO
9
+ connections because hook handlers are ephemeral processes (< 1 second lifetime).
10
+ This eliminates disconnection issues and matches the process lifecycle.
11
+ """
12
+
13
+ import os
14
+ import sys
15
+ from datetime import datetime
16
+
17
+ # Debug mode is enabled by default for better visibility into hook processing
18
+ DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
19
+
20
+ # Import requests for HTTP POST communication
21
+ try:
22
+ import requests
23
+
24
+ REQUESTS_AVAILABLE = True
25
+ except ImportError:
26
+ REQUESTS_AVAILABLE = False
27
+ requests = None
28
+
29
+ # Import EventNormalizer for consistent event formatting
30
+ try:
31
+ from claude_mpm.services.socketio.event_normalizer import EventNormalizer
32
+ except ImportError:
33
+ # Create a simple fallback EventNormalizer if import fails
34
+ class EventNormalizer:
35
+ def normalize(self, event_data, source="hook"):
36
+ """Simple fallback normalizer that returns event as-is."""
37
+ return type(
38
+ "NormalizedEvent",
39
+ (),
40
+ {
41
+ "to_dict": lambda: {
42
+ "event": "claude_event",
43
+ "type": event_data.get("type", "unknown"),
44
+ "subtype": event_data.get("subtype", "generic"),
45
+ "timestamp": event_data.get(
46
+ "timestamp", datetime.now().isoformat()
47
+ ),
48
+ "data": event_data.get("data", event_data),
49
+ }
50
+ },
51
+ )
52
+
53
+
54
+ # Import EventBus for decoupled event distribution
55
+ try:
56
+ from claude_mpm.services.event_bus import EventBus
57
+
58
+ EVENTBUS_AVAILABLE = True
59
+ except ImportError:
60
+ EVENTBUS_AVAILABLE = False
61
+ EventBus = None
62
+
63
+
64
+ class ConnectionManagerService:
65
+ """Manages connections for the Claude hook handler using HTTP POST."""
66
+
67
+ def __init__(self):
68
+ """Initialize connection management service."""
69
+ # Event normalizer for consistent event schema
70
+ self.event_normalizer = EventNormalizer()
71
+
72
+ # Server configuration for HTTP POST
73
+ self.server_host = os.environ.get("CLAUDE_MPM_SERVER_HOST", "localhost")
74
+ self.server_port = int(os.environ.get("CLAUDE_MPM_SERVER_PORT", "8765"))
75
+ self.http_endpoint = f"http://{self.server_host}:{self.server_port}/api/events"
76
+
77
+ # Initialize EventBus for in-process event distribution (optional)
78
+ self.event_bus = None
79
+ self._initialize_eventbus()
80
+
81
+ # For backward compatibility with tests
82
+ self.connection_pool = None # No longer used
83
+
84
+ if DEBUG:
85
+ print(
86
+ f"✅ HTTP connection manager initialized - endpoint: {self.http_endpoint}",
87
+ file=sys.stderr,
88
+ )
89
+
90
+ def _initialize_eventbus(self):
91
+ """Initialize the EventBus for in-process distribution."""
92
+ if EVENTBUS_AVAILABLE:
93
+ try:
94
+ self.event_bus = EventBus.get_instance()
95
+ if DEBUG:
96
+ print("✅ EventBus initialized for hook handler", file=sys.stderr)
97
+ except Exception as e:
98
+ if DEBUG:
99
+ print(f"⚠️ Failed to initialize EventBus: {e}", file=sys.stderr)
100
+ self.event_bus = None
101
+
102
+ def emit_event(self, namespace: str, event: str, data: dict):
103
+ """Emit event using HTTP POST and optionally EventBus.
104
+
105
+ WHY HTTP POST approach:
106
+ - Stateless: Perfect for ephemeral hook processes
107
+ - Fire-and-forget: No connection management needed
108
+ - Fast: Minimal overhead, no handshake
109
+ - Reliable: Server handles buffering and retries
110
+ """
111
+ # Create event data for normalization
112
+ raw_event = {
113
+ "type": "hook",
114
+ "subtype": event, # e.g., "user_prompt", "pre_tool", "subagent_stop"
115
+ "timestamp": datetime.now().isoformat(),
116
+ "data": data,
117
+ "source": "claude_hooks", # Identify the source
118
+ "session_id": data.get("sessionId"), # Include session if available
119
+ }
120
+
121
+ # Normalize the event using EventNormalizer for consistent schema
122
+ normalized_event = self.event_normalizer.normalize(raw_event, source="hook")
123
+ claude_event_data = normalized_event.to_dict()
124
+
125
+ # Log important events for debugging
126
+ if DEBUG and event in ["subagent_stop", "pre_tool"]:
127
+ if event == "subagent_stop":
128
+ agent_type = data.get("agent_type", "unknown")
129
+ print(
130
+ f"Hook handler: Publishing SubagentStop for agent '{agent_type}'",
131
+ file=sys.stderr,
132
+ )
133
+ elif event == "pre_tool" and data.get("tool_name") == "Task":
134
+ delegation = data.get("delegation_details", {})
135
+ agent_type = delegation.get("agent_type", "unknown")
136
+ print(
137
+ f"Hook handler: Publishing Task delegation to agent '{agent_type}'",
138
+ file=sys.stderr,
139
+ )
140
+
141
+ # Primary method: HTTP POST to server
142
+ # This is fire-and-forget with a short timeout
143
+ if REQUESTS_AVAILABLE:
144
+ try:
145
+ # Send HTTP POST with short timeout (fire-and-forget pattern)
146
+ response = requests.post(
147
+ self.http_endpoint,
148
+ json=claude_event_data,
149
+ timeout=0.5, # 500ms timeout - don't wait long
150
+ headers={"Content-Type": "application/json"},
151
+ )
152
+ if DEBUG and response.status_code == 204:
153
+ print(f"✅ Emitted via HTTP POST: {event}", file=sys.stderr)
154
+ elif DEBUG and response.status_code != 204:
155
+ print(
156
+ f"⚠️ HTTP POST returned status {response.status_code} for: {event}",
157
+ file=sys.stderr,
158
+ )
159
+ except requests.exceptions.Timeout:
160
+ # Timeout is expected for fire-and-forget pattern
161
+ if DEBUG:
162
+ print(f"✅ HTTP POST sent (timeout OK): {event}", file=sys.stderr)
163
+ except requests.exceptions.ConnectionError:
164
+ # Server might not be running - this is OK
165
+ if DEBUG:
166
+ print(f"⚠️ Server not available for: {event}", file=sys.stderr)
167
+ except Exception as e:
168
+ if DEBUG:
169
+ print(f"⚠️ Failed to emit via HTTP POST: {e}", file=sys.stderr)
170
+ elif DEBUG:
171
+ print(
172
+ "⚠️ requests module not available - cannot emit via HTTP",
173
+ file=sys.stderr,
174
+ )
175
+
176
+ # Also publish to EventBus for any in-process subscribers
177
+ if self.event_bus and EVENTBUS_AVAILABLE:
178
+ try:
179
+ # Publish to EventBus with topic format: hook.{event}
180
+ topic = f"hook.{event}"
181
+ self.event_bus.publish(topic, claude_event_data)
182
+ if DEBUG:
183
+ print(f"✅ Published to EventBus: {topic}", file=sys.stderr)
184
+ except Exception as e:
185
+ if DEBUG:
186
+ print(f"⚠️ Failed to publish to EventBus: {e}", file=sys.stderr)
187
+
188
+ def cleanup(self):
189
+ """Cleanup connections on service destruction."""
190
+ # Nothing to cleanup for HTTP POST approach
@@ -34,10 +34,14 @@ class AgentDiscoveryService:
34
34
  self.logger = get_logger(__name__)
35
35
  self.templates_dir = templates_dir
36
36
 
37
- def list_available_agents(self) -> List[Dict[str, Any]]:
37
+ def list_available_agents(self, log_discovery: bool = True) -> List[Dict[str, Any]]:
38
38
  """
39
39
  List all available agent templates with their metadata.
40
40
 
41
+ Args:
42
+ log_discovery: Whether to log discovery results (default: True).
43
+ Set to False when called from multi-source discovery to avoid duplicate logs.
44
+
41
45
  Returns:
42
46
  List of agent information dictionaries containing:
43
47
  - name: Agent name
@@ -73,7 +77,11 @@ class AgentDiscoveryService:
73
77
  # Sort by agent name for consistent ordering
74
78
  agents.sort(key=lambda x: x.get("name", ""))
75
79
 
76
- self.logger.info(f"Discovered {len(agents)} available agent templates")
80
+ # Only log if requested (to avoid duplicate logging from multi-source discovery)
81
+ if log_discovery:
82
+ self.logger.info(
83
+ f"Discovered {len(agents)} available agent templates from {self.templates_dir.name}"
84
+ )
77
85
  return agents
78
86
 
79
87
  def get_filtered_templates(
@@ -153,7 +161,8 @@ class AgentDiscoveryService:
153
161
  Dictionary mapping categories to lists of agent names
154
162
  """
155
163
  categories = {}
156
- agents = self.list_available_agents()
164
+ # Don't log discovery when called internally
165
+ agents = self.list_available_agents(log_discovery=False)
157
166
 
158
167
  for agent in agents:
159
168
  agent_name = agent.get("name", "unknown")