claude-mpm 4.0.31__py3-none-any.whl → 4.0.34__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 (71) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +33 -25
  3. claude_mpm/agents/INSTRUCTIONS.md +14 -10
  4. claude_mpm/agents/templates/documentation.json +51 -34
  5. claude_mpm/agents/templates/research.json +0 -11
  6. claude_mpm/cli/__init__.py +63 -26
  7. claude_mpm/cli/commands/agent_manager.py +10 -8
  8. claude_mpm/core/framework_loader.py +272 -113
  9. claude_mpm/dashboard/static/css/dashboard.css +449 -0
  10. claude_mpm/dashboard/static/dist/components/agent-inference.js +1 -1
  11. claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
  12. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +1 -1
  13. claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
  14. claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
  15. claude_mpm/dashboard/static/dist/dashboard.js +1 -1
  16. claude_mpm/dashboard/static/dist/socket-client.js +1 -1
  17. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +774 -0
  18. claude_mpm/dashboard/static/js/components/agent-inference.js +257 -3
  19. claude_mpm/dashboard/static/js/components/build-tracker.js +289 -0
  20. claude_mpm/dashboard/static/js/components/event-viewer.js +168 -39
  21. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +17 -0
  22. claude_mpm/dashboard/static/js/components/session-manager.js +23 -3
  23. claude_mpm/dashboard/static/js/components/socket-manager.js +2 -0
  24. claude_mpm/dashboard/static/js/dashboard.js +207 -31
  25. claude_mpm/dashboard/static/js/socket-client.js +85 -6
  26. claude_mpm/dashboard/templates/index.html +1 -0
  27. claude_mpm/hooks/claude_hooks/connection_pool.py +12 -2
  28. claude_mpm/hooks/claude_hooks/event_handlers.py +81 -19
  29. claude_mpm/hooks/claude_hooks/hook_handler.py +72 -10
  30. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +398 -0
  31. claude_mpm/hooks/claude_hooks/response_tracking.py +10 -0
  32. claude_mpm/services/agents/deployment/agent_deployment.py +86 -37
  33. claude_mpm/services/agents/deployment/agent_template_builder.py +18 -10
  34. claude_mpm/services/agents/deployment/agents_directory_resolver.py +10 -25
  35. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +189 -3
  36. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +3 -2
  37. claude_mpm/services/agents/deployment/strategies/system_strategy.py +10 -3
  38. claude_mpm/services/agents/deployment/strategies/user_strategy.py +10 -14
  39. claude_mpm/services/agents/deployment/system_instructions_deployer.py +8 -13
  40. claude_mpm/services/agents/memory/agent_memory_manager.py +141 -184
  41. claude_mpm/services/agents/memory/content_manager.py +182 -232
  42. claude_mpm/services/agents/memory/template_generator.py +4 -40
  43. claude_mpm/services/event_bus/__init__.py +18 -0
  44. claude_mpm/services/event_bus/event_bus.py +334 -0
  45. claude_mpm/services/event_bus/relay.py +301 -0
  46. claude_mpm/services/events/__init__.py +44 -0
  47. claude_mpm/services/events/consumers/__init__.py +18 -0
  48. claude_mpm/services/events/consumers/dead_letter.py +296 -0
  49. claude_mpm/services/events/consumers/logging.py +183 -0
  50. claude_mpm/services/events/consumers/metrics.py +242 -0
  51. claude_mpm/services/events/consumers/socketio.py +376 -0
  52. claude_mpm/services/events/core.py +470 -0
  53. claude_mpm/services/events/interfaces.py +230 -0
  54. claude_mpm/services/events/producers/__init__.py +14 -0
  55. claude_mpm/services/events/producers/hook.py +269 -0
  56. claude_mpm/services/events/producers/system.py +327 -0
  57. claude_mpm/services/mcp_gateway/core/process_pool.py +411 -0
  58. claude_mpm/services/mcp_gateway/server/stdio_server.py +13 -0
  59. claude_mpm/services/monitor_build_service.py +345 -0
  60. claude_mpm/services/socketio/event_normalizer.py +667 -0
  61. claude_mpm/services/socketio/handlers/connection.py +78 -20
  62. claude_mpm/services/socketio/handlers/hook.py +14 -5
  63. claude_mpm/services/socketio/migration_utils.py +329 -0
  64. claude_mpm/services/socketio/server/broadcaster.py +26 -33
  65. claude_mpm/services/socketio/server/core.py +4 -3
  66. {claude_mpm-4.0.31.dist-info → claude_mpm-4.0.34.dist-info}/METADATA +4 -3
  67. {claude_mpm-4.0.31.dist-info → claude_mpm-4.0.34.dist-info}/RECORD +71 -50
  68. {claude_mpm-4.0.31.dist-info → claude_mpm-4.0.34.dist-info}/WHEEL +0 -0
  69. {claude_mpm-4.0.31.dist-info → claude_mpm-4.0.34.dist-info}/entry_points.txt +0 -0
  70. {claude_mpm-4.0.31.dist-info → claude_mpm-4.0.34.dist-info}/licenses/LICENSE +0 -0
  71. {claude_mpm-4.0.31.dist-info → claude_mpm-4.0.34.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,14 @@
1
+ """
2
+ Event Bus Producers
3
+ ==================
4
+
5
+ Various producer implementations for publishing events to the event bus.
6
+ """
7
+
8
+ from .hook import HookEventProducer
9
+ from .system import SystemEventProducer
10
+
11
+ __all__ = [
12
+ "HookEventProducer",
13
+ "SystemEventProducer",
14
+ ]
@@ -0,0 +1,269 @@
1
+ """
2
+ Hook Event Producer
3
+ ==================
4
+
5
+ Publishes hook system events to the event bus.
6
+ This replaces direct Socket.IO emission in the hook handler.
7
+ """
8
+
9
+ import uuid
10
+ from datetime import datetime
11
+ from typing import Any, Dict, List, Optional
12
+
13
+ from claude_mpm.core.logging_config import get_logger
14
+
15
+ from ..core import Event, EventPriority
16
+ from ..interfaces import IEventBus, IEventProducer
17
+
18
+
19
+ class HookEventProducer(IEventProducer):
20
+ """
21
+ Publishes hook events to the event bus.
22
+
23
+ This producer is used by the hook handler to publish events
24
+ without knowing about Socket.IO or other consumers.
25
+ """
26
+
27
+ def __init__(self, event_bus: IEventBus):
28
+ """
29
+ Initialize hook event producer.
30
+
31
+ Args:
32
+ event_bus: The event bus to publish to
33
+ """
34
+ self.logger = get_logger("HookEventProducer")
35
+ self.event_bus = event_bus
36
+ self._source_name = "hook_handler"
37
+
38
+ # Metrics
39
+ self._metrics = {
40
+ "events_published": 0,
41
+ "events_failed": 0,
42
+ "batch_published": 0,
43
+ }
44
+
45
+ async def publish(self, event: Event) -> bool:
46
+ """Publish a hook event to the bus."""
47
+ try:
48
+ success = await self.event_bus.publish(event)
49
+
50
+ if success:
51
+ self._metrics["events_published"] += 1
52
+ else:
53
+ self._metrics["events_failed"] += 1
54
+
55
+ return success
56
+
57
+ except Exception as e:
58
+ self.logger.error(f"Error publishing hook event: {e}")
59
+ self._metrics["events_failed"] += 1
60
+ return False
61
+
62
+ async def publish_batch(self, events: List[Event]) -> int:
63
+ """Publish multiple hook events."""
64
+ successful = 0
65
+
66
+ for event in events:
67
+ if await self.publish(event):
68
+ successful += 1
69
+
70
+ self._metrics["batch_published"] += 1
71
+ return successful
72
+
73
+ @property
74
+ def source_name(self) -> str:
75
+ """Get the name of this event source."""
76
+ return self._source_name
77
+
78
+ # Convenience methods for common hook events
79
+
80
+ async def publish_response(
81
+ self,
82
+ response_data: Dict[str, Any],
83
+ correlation_id: Optional[str] = None,
84
+ ) -> bool:
85
+ """
86
+ Publish an assistant response event.
87
+
88
+ Args:
89
+ response_data: The response data
90
+ correlation_id: Optional correlation ID
91
+
92
+ Returns:
93
+ True if published successfully
94
+ """
95
+ event = Event(
96
+ id=str(uuid.uuid4()),
97
+ topic="hook.response",
98
+ type="AssistantResponse",
99
+ timestamp=datetime.now(),
100
+ source=self.source_name,
101
+ data=response_data,
102
+ correlation_id=correlation_id,
103
+ priority=EventPriority.HIGH,
104
+ )
105
+
106
+ return await self.publish(event)
107
+
108
+ async def publish_tool_use(
109
+ self,
110
+ tool_name: str,
111
+ tool_params: Dict[str, Any],
112
+ tool_result: Optional[Any] = None,
113
+ correlation_id: Optional[str] = None,
114
+ ) -> bool:
115
+ """
116
+ Publish a tool usage event.
117
+
118
+ Args:
119
+ tool_name: Name of the tool used
120
+ tool_params: Parameters passed to the tool
121
+ tool_result: Optional tool result
122
+ correlation_id: Optional correlation ID
123
+
124
+ Returns:
125
+ True if published successfully
126
+ """
127
+ event = Event(
128
+ id=str(uuid.uuid4()),
129
+ topic="hook.tool",
130
+ type="ToolUse",
131
+ timestamp=datetime.now(),
132
+ source=self.source_name,
133
+ data={
134
+ "tool": tool_name,
135
+ "params": tool_params,
136
+ "result": tool_result,
137
+ },
138
+ correlation_id=correlation_id,
139
+ priority=EventPriority.NORMAL,
140
+ )
141
+
142
+ return await self.publish(event)
143
+
144
+ async def publish_error(
145
+ self,
146
+ error_type: str,
147
+ error_message: str,
148
+ error_details: Optional[Dict[str, Any]] = None,
149
+ correlation_id: Optional[str] = None,
150
+ ) -> bool:
151
+ """
152
+ Publish an error event.
153
+
154
+ Args:
155
+ error_type: Type of error
156
+ error_message: Error message
157
+ error_details: Optional additional details
158
+ correlation_id: Optional correlation ID
159
+
160
+ Returns:
161
+ True if published successfully
162
+ """
163
+ event = Event(
164
+ id=str(uuid.uuid4()),
165
+ topic="hook.error",
166
+ type="Error",
167
+ timestamp=datetime.now(),
168
+ source=self.source_name,
169
+ data={
170
+ "error_type": error_type,
171
+ "message": error_message,
172
+ "details": error_details or {},
173
+ },
174
+ correlation_id=correlation_id,
175
+ priority=EventPriority.CRITICAL,
176
+ )
177
+
178
+ return await self.publish(event)
179
+
180
+ async def publish_subagent_event(
181
+ self,
182
+ subagent_name: str,
183
+ event_type: str,
184
+ event_data: Dict[str, Any],
185
+ correlation_id: Optional[str] = None,
186
+ ) -> bool:
187
+ """
188
+ Publish a subagent-related event.
189
+
190
+ Args:
191
+ subagent_name: Name of the subagent
192
+ event_type: Type of subagent event
193
+ event_data: Event data
194
+ correlation_id: Optional correlation ID
195
+
196
+ Returns:
197
+ True if published successfully
198
+ """
199
+ event = Event(
200
+ id=str(uuid.uuid4()),
201
+ topic=f"hook.subagent.{event_type.lower()}",
202
+ type=f"Subagent{event_type}",
203
+ timestamp=datetime.now(),
204
+ source=self.source_name,
205
+ data={
206
+ "subagent": subagent_name,
207
+ **event_data,
208
+ },
209
+ correlation_id=correlation_id,
210
+ priority=EventPriority.NORMAL,
211
+ )
212
+
213
+ return await self.publish(event)
214
+
215
+ async def publish_raw_hook_event(
216
+ self,
217
+ hook_type: str,
218
+ hook_data: Dict[str, Any],
219
+ correlation_id: Optional[str] = None,
220
+ ) -> bool:
221
+ """
222
+ Publish a raw hook event.
223
+
224
+ This is for hook events that don't fit the standard patterns.
225
+
226
+ Args:
227
+ hook_type: Type of hook event
228
+ hook_data: Raw hook data
229
+ correlation_id: Optional correlation ID
230
+
231
+ Returns:
232
+ True if published successfully
233
+ """
234
+ # Determine topic based on hook type
235
+ if "response" in hook_type.lower():
236
+ topic = "hook.response"
237
+ elif "tool" in hook_type.lower():
238
+ topic = "hook.tool"
239
+ elif "error" in hook_type.lower():
240
+ topic = "hook.error"
241
+ elif "subagent" in hook_type.lower():
242
+ topic = "hook.subagent"
243
+ else:
244
+ topic = "hook.generic"
245
+
246
+ # Determine priority
247
+ if "error" in hook_type.lower() or "critical" in hook_type.lower():
248
+ priority = EventPriority.CRITICAL
249
+ elif "response" in hook_type.lower():
250
+ priority = EventPriority.HIGH
251
+ else:
252
+ priority = EventPriority.NORMAL
253
+
254
+ event = Event(
255
+ id=str(uuid.uuid4()),
256
+ topic=topic,
257
+ type=hook_type,
258
+ timestamp=datetime.now(),
259
+ source=self.source_name,
260
+ data=hook_data,
261
+ correlation_id=correlation_id,
262
+ priority=priority,
263
+ )
264
+
265
+ return await self.publish(event)
266
+
267
+ def get_metrics(self) -> Dict[str, Any]:
268
+ """Get producer metrics."""
269
+ return self._metrics
@@ -0,0 +1,327 @@
1
+ """
2
+ System Event Producer
3
+ ====================
4
+
5
+ Publishes system-level events to the event bus.
6
+ """
7
+
8
+ import uuid
9
+ from datetime import datetime
10
+ from typing import Any, Dict, List, Optional
11
+
12
+ from claude_mpm.core.logging_config import get_logger
13
+
14
+ from ..core import Event, EventPriority
15
+ from ..interfaces import IEventBus, IEventProducer
16
+
17
+
18
+ class SystemEventProducer(IEventProducer):
19
+ """
20
+ Publishes system events to the event bus.
21
+
22
+ Used for:
23
+ - Service lifecycle events
24
+ - Configuration changes
25
+ - Health status updates
26
+ - Performance metrics
27
+ - System errors
28
+ """
29
+
30
+ def __init__(self, event_bus: IEventBus, source_name: str = "system"):
31
+ """
32
+ Initialize system event producer.
33
+
34
+ Args:
35
+ event_bus: The event bus to publish to
36
+ source_name: Name of the system component
37
+ """
38
+ self.logger = get_logger("SystemEventProducer")
39
+ self.event_bus = event_bus
40
+ self._source_name = source_name
41
+
42
+ # Metrics
43
+ self._metrics = {
44
+ "events_published": 0,
45
+ "events_failed": 0,
46
+ }
47
+
48
+ async def publish(self, event: Event) -> bool:
49
+ """Publish a system event to the bus."""
50
+ try:
51
+ success = await self.event_bus.publish(event)
52
+
53
+ if success:
54
+ self._metrics["events_published"] += 1
55
+ else:
56
+ self._metrics["events_failed"] += 1
57
+
58
+ return success
59
+
60
+ except Exception as e:
61
+ self.logger.error(f"Error publishing system event: {e}")
62
+ self._metrics["events_failed"] += 1
63
+ return False
64
+
65
+ async def publish_batch(self, events: List[Event]) -> int:
66
+ """Publish multiple system events."""
67
+ successful = 0
68
+
69
+ for event in events:
70
+ if await self.publish(event):
71
+ successful += 1
72
+
73
+ return successful
74
+
75
+ @property
76
+ def source_name(self) -> str:
77
+ """Get the name of this event source."""
78
+ return self._source_name
79
+
80
+ # Convenience methods for common system events
81
+
82
+ async def publish_startup(
83
+ self,
84
+ service_name: str,
85
+ version: str,
86
+ config: Optional[Dict[str, Any]] = None,
87
+ ) -> bool:
88
+ """
89
+ Publish a service startup event.
90
+
91
+ Args:
92
+ service_name: Name of the service
93
+ version: Service version
94
+ config: Optional configuration data
95
+
96
+ Returns:
97
+ True if published successfully
98
+ """
99
+ event = Event(
100
+ id=str(uuid.uuid4()),
101
+ topic="system.lifecycle.startup",
102
+ type="ServiceStartup",
103
+ timestamp=datetime.now(),
104
+ source=self.source_name,
105
+ data={
106
+ "service": service_name,
107
+ "version": version,
108
+ "config": config or {},
109
+ },
110
+ priority=EventPriority.HIGH,
111
+ )
112
+
113
+ return await self.publish(event)
114
+
115
+ async def publish_shutdown(
116
+ self,
117
+ service_name: str,
118
+ reason: str = "normal",
119
+ details: Optional[Dict[str, Any]] = None,
120
+ ) -> bool:
121
+ """
122
+ Publish a service shutdown event.
123
+
124
+ Args:
125
+ service_name: Name of the service
126
+ reason: Shutdown reason
127
+ details: Optional additional details
128
+
129
+ Returns:
130
+ True if published successfully
131
+ """
132
+ event = Event(
133
+ id=str(uuid.uuid4()),
134
+ topic="system.lifecycle.shutdown",
135
+ type="ServiceShutdown",
136
+ timestamp=datetime.now(),
137
+ source=self.source_name,
138
+ data={
139
+ "service": service_name,
140
+ "reason": reason,
141
+ "details": details or {},
142
+ },
143
+ priority=EventPriority.HIGH,
144
+ )
145
+
146
+ return await self.publish(event)
147
+
148
+ async def publish_health_status(
149
+ self,
150
+ service_name: str,
151
+ status: str,
152
+ checks: Dict[str, bool],
153
+ details: Optional[Dict[str, Any]] = None,
154
+ ) -> bool:
155
+ """
156
+ Publish a health status event.
157
+
158
+ Args:
159
+ service_name: Name of the service
160
+ status: Health status (healthy, degraded, unhealthy)
161
+ checks: Individual health checks
162
+ details: Optional additional details
163
+
164
+ Returns:
165
+ True if published successfully
166
+ """
167
+ event = Event(
168
+ id=str(uuid.uuid4()),
169
+ topic="system.health",
170
+ type="HealthStatus",
171
+ timestamp=datetime.now(),
172
+ source=self.source_name,
173
+ data={
174
+ "service": service_name,
175
+ "status": status,
176
+ "checks": checks,
177
+ "details": details or {},
178
+ },
179
+ priority=EventPriority.NORMAL if status == "healthy" else EventPriority.HIGH,
180
+ )
181
+
182
+ return await self.publish(event)
183
+
184
+ async def publish_config_change(
185
+ self,
186
+ service_name: str,
187
+ config_key: str,
188
+ old_value: Any,
189
+ new_value: Any,
190
+ ) -> bool:
191
+ """
192
+ Publish a configuration change event.
193
+
194
+ Args:
195
+ service_name: Name of the service
196
+ config_key: Configuration key that changed
197
+ old_value: Previous value
198
+ new_value: New value
199
+
200
+ Returns:
201
+ True if published successfully
202
+ """
203
+ event = Event(
204
+ id=str(uuid.uuid4()),
205
+ topic="system.config",
206
+ type="ConfigChange",
207
+ timestamp=datetime.now(),
208
+ source=self.source_name,
209
+ data={
210
+ "service": service_name,
211
+ "key": config_key,
212
+ "old_value": old_value,
213
+ "new_value": new_value,
214
+ },
215
+ priority=EventPriority.NORMAL,
216
+ )
217
+
218
+ return await self.publish(event)
219
+
220
+ async def publish_performance_metrics(
221
+ self,
222
+ service_name: str,
223
+ metrics: Dict[str, Any],
224
+ ) -> bool:
225
+ """
226
+ Publish performance metrics.
227
+
228
+ Args:
229
+ service_name: Name of the service
230
+ metrics: Performance metrics data
231
+
232
+ Returns:
233
+ True if published successfully
234
+ """
235
+ event = Event(
236
+ id=str(uuid.uuid4()),
237
+ topic="system.performance",
238
+ type="PerformanceMetrics",
239
+ timestamp=datetime.now(),
240
+ source=self.source_name,
241
+ data={
242
+ "service": service_name,
243
+ "metrics": metrics,
244
+ },
245
+ priority=EventPriority.LOW,
246
+ )
247
+
248
+ return await self.publish(event)
249
+
250
+ async def publish_error(
251
+ self,
252
+ service_name: str,
253
+ error_type: str,
254
+ error_message: str,
255
+ stacktrace: Optional[str] = None,
256
+ context: Optional[Dict[str, Any]] = None,
257
+ ) -> bool:
258
+ """
259
+ Publish a system error event.
260
+
261
+ Args:
262
+ service_name: Name of the service
263
+ error_type: Type of error
264
+ error_message: Error message
265
+ stacktrace: Optional stack trace
266
+ context: Optional error context
267
+
268
+ Returns:
269
+ True if published successfully
270
+ """
271
+ event = Event(
272
+ id=str(uuid.uuid4()),
273
+ topic="system.error",
274
+ type="SystemError",
275
+ timestamp=datetime.now(),
276
+ source=self.source_name,
277
+ data={
278
+ "service": service_name,
279
+ "error_type": error_type,
280
+ "message": error_message,
281
+ "stacktrace": stacktrace,
282
+ "context": context or {},
283
+ },
284
+ priority=EventPriority.CRITICAL,
285
+ )
286
+
287
+ return await self.publish(event)
288
+
289
+ async def publish_warning(
290
+ self,
291
+ service_name: str,
292
+ warning_type: str,
293
+ message: str,
294
+ details: Optional[Dict[str, Any]] = None,
295
+ ) -> bool:
296
+ """
297
+ Publish a system warning event.
298
+
299
+ Args:
300
+ service_name: Name of the service
301
+ warning_type: Type of warning
302
+ message: Warning message
303
+ details: Optional additional details
304
+
305
+ Returns:
306
+ True if published successfully
307
+ """
308
+ event = Event(
309
+ id=str(uuid.uuid4()),
310
+ topic="system.warning",
311
+ type="SystemWarning",
312
+ timestamp=datetime.now(),
313
+ source=self.source_name,
314
+ data={
315
+ "service": service_name,
316
+ "warning_type": warning_type,
317
+ "message": message,
318
+ "details": details or {},
319
+ },
320
+ priority=EventPriority.HIGH,
321
+ )
322
+
323
+ return await self.publish(event)
324
+
325
+ def get_metrics(self) -> Dict[str, Any]:
326
+ """Get producer metrics."""
327
+ return self._metrics