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,381 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Agent State Service - State Management for Agent Lifecycle
4
+ ===========================================================
5
+
6
+ Handles agent state tracking and transitions for the lifecycle manager.
7
+ Extracted from AgentLifecycleManager to follow Single Responsibility Principle.
8
+
9
+ Key Responsibilities:
10
+ - Track agent states (ACTIVE, MODIFIED, DELETED, etc.)
11
+ - Manage state transitions
12
+ - Validate state changes
13
+ - Maintain state history
14
+ """
15
+
16
+ import time
17
+ from dataclasses import dataclass, field
18
+ from enum import Enum
19
+ from typing import Dict, List, Optional
20
+
21
+ from claude_mpm.core.base_service import BaseService
22
+ from claude_mpm.services.agents.registry.modification_tracker import ModificationTier
23
+
24
+
25
+ class LifecycleState(Enum):
26
+ """Agent lifecycle states."""
27
+
28
+ ACTIVE = "active"
29
+ MODIFIED = "modified"
30
+ DELETED = "deleted"
31
+ CONFLICTED = "conflicted"
32
+ MIGRATING = "migrating"
33
+ VALIDATING = "validating"
34
+
35
+
36
+ @dataclass
37
+ class AgentLifecycleRecord:
38
+ """Complete lifecycle record for an agent."""
39
+
40
+ agent_name: str
41
+ current_state: LifecycleState
42
+ tier: ModificationTier
43
+ file_path: str
44
+ created_at: float
45
+ last_modified: float
46
+ version: str
47
+ modifications: List[str] = field(default_factory=list) # Modification IDs
48
+ persistence_operations: List[str] = field(default_factory=list) # Operation IDs
49
+ backup_paths: List[str] = field(default_factory=list)
50
+ validation_status: str = "valid"
51
+ validation_errors: List[str] = field(default_factory=list)
52
+ metadata: Dict[str, any] = field(default_factory=dict)
53
+
54
+ @property
55
+ def age_days(self) -> float:
56
+ """Get age in days."""
57
+ return (time.time() - self.created_at) / (24 * 3600)
58
+
59
+ @property
60
+ def last_modified_datetime(self):
61
+ """Get last modified as datetime."""
62
+ from datetime import datetime
63
+
64
+ return datetime.fromtimestamp(self.last_modified)
65
+
66
+
67
+ @dataclass
68
+ class StateTransition:
69
+ """Record of a state transition."""
70
+
71
+ agent_name: str
72
+ from_state: LifecycleState
73
+ to_state: LifecycleState
74
+ timestamp: float
75
+ reason: str
76
+ metadata: Dict[str, any] = field(default_factory=dict)
77
+
78
+
79
+ class AgentStateService(BaseService):
80
+ """
81
+ Service for managing agent lifecycle states.
82
+
83
+ Responsibilities:
84
+ - Track current state of all agents
85
+ - Validate and execute state transitions
86
+ - Maintain state history
87
+ - Query agents by state
88
+ """
89
+
90
+ def __init__(self):
91
+ """Initialize the agent state service."""
92
+ super().__init__("agent_state_service")
93
+
94
+ # Agent records storage
95
+ self.agent_records: Dict[str, AgentLifecycleRecord] = {}
96
+
97
+ # State transition history
98
+ self.transition_history: List[StateTransition] = []
99
+
100
+ # Valid state transitions
101
+ self.valid_transitions = {
102
+ LifecycleState.ACTIVE: [
103
+ LifecycleState.MODIFIED,
104
+ LifecycleState.DELETED,
105
+ LifecycleState.CONFLICTED,
106
+ LifecycleState.MIGRATING,
107
+ LifecycleState.VALIDATING,
108
+ ],
109
+ LifecycleState.MODIFIED: [
110
+ LifecycleState.ACTIVE,
111
+ LifecycleState.DELETED,
112
+ LifecycleState.CONFLICTED,
113
+ LifecycleState.VALIDATING,
114
+ ],
115
+ LifecycleState.DELETED: [
116
+ LifecycleState.ACTIVE, # For restoration
117
+ ],
118
+ LifecycleState.CONFLICTED: [
119
+ LifecycleState.ACTIVE,
120
+ LifecycleState.MODIFIED,
121
+ LifecycleState.DELETED,
122
+ ],
123
+ LifecycleState.MIGRATING: [
124
+ LifecycleState.ACTIVE,
125
+ LifecycleState.MODIFIED,
126
+ LifecycleState.CONFLICTED,
127
+ ],
128
+ LifecycleState.VALIDATING: [
129
+ LifecycleState.ACTIVE,
130
+ LifecycleState.MODIFIED,
131
+ LifecycleState.CONFLICTED,
132
+ ],
133
+ }
134
+
135
+ self.logger.info("AgentStateService initialized")
136
+
137
+ def create_record(
138
+ self,
139
+ agent_name: str,
140
+ tier: ModificationTier,
141
+ file_path: str,
142
+ initial_state: LifecycleState = LifecycleState.ACTIVE,
143
+ version: str = "1.0.0",
144
+ **metadata,
145
+ ) -> AgentLifecycleRecord:
146
+ """
147
+ Create a new agent lifecycle record.
148
+
149
+ Args:
150
+ agent_name: Name of the agent
151
+ tier: Agent tier (USER, PROJECT, SYSTEM)
152
+ file_path: Path to agent file
153
+ initial_state: Initial state (default: ACTIVE)
154
+ version: Initial version
155
+ **metadata: Additional metadata
156
+
157
+ Returns:
158
+ Created AgentLifecycleRecord
159
+ """
160
+ record = AgentLifecycleRecord(
161
+ agent_name=agent_name,
162
+ current_state=initial_state,
163
+ tier=tier,
164
+ file_path=file_path,
165
+ created_at=time.time(),
166
+ last_modified=time.time(),
167
+ version=version,
168
+ metadata=metadata,
169
+ )
170
+
171
+ self.agent_records[agent_name] = record
172
+ self.logger.debug(f"Created lifecycle record for agent '{agent_name}'")
173
+
174
+ return record
175
+
176
+ def get_record(self, agent_name: str) -> Optional[AgentLifecycleRecord]:
177
+ """Get lifecycle record for an agent."""
178
+ return self.agent_records.get(agent_name)
179
+
180
+ def update_state(
181
+ self, agent_name: str, new_state: LifecycleState, reason: str = "", **metadata
182
+ ) -> bool:
183
+ """
184
+ Update agent state with validation.
185
+
186
+ Args:
187
+ agent_name: Name of the agent
188
+ new_state: Target state
189
+ reason: Reason for transition
190
+ **metadata: Additional metadata
191
+
192
+ Returns:
193
+ True if transition successful, False otherwise
194
+ """
195
+ record = self.agent_records.get(agent_name)
196
+ if not record:
197
+ self.logger.warning(f"Agent '{agent_name}' not found for state update")
198
+ return False
199
+
200
+ # Check if transition is valid
201
+ if not self._is_valid_transition(record.current_state, new_state):
202
+ self.logger.warning(
203
+ f"Invalid state transition for '{agent_name}': "
204
+ f"{record.current_state.value} -> {new_state.value}"
205
+ )
206
+ return False
207
+
208
+ # Record transition
209
+ transition = StateTransition(
210
+ agent_name=agent_name,
211
+ from_state=record.current_state,
212
+ to_state=new_state,
213
+ timestamp=time.time(),
214
+ reason=reason,
215
+ metadata=metadata,
216
+ )
217
+ self.transition_history.append(transition)
218
+
219
+ # Update state
220
+ old_state = record.current_state
221
+ record.current_state = new_state
222
+ record.last_modified = time.time()
223
+
224
+ self.logger.info(
225
+ f"Agent '{agent_name}' state changed: "
226
+ f"{old_state.value} -> {new_state.value}"
227
+ )
228
+
229
+ return True
230
+
231
+ def _is_valid_transition(
232
+ self, from_state: LifecycleState, to_state: LifecycleState
233
+ ) -> bool:
234
+ """Check if a state transition is valid."""
235
+ if from_state == to_state:
236
+ return True # Allow same state (no-op)
237
+
238
+ valid_targets = self.valid_transitions.get(from_state, [])
239
+ return to_state in valid_targets
240
+
241
+ def list_agents_by_state(
242
+ self, state: Optional[LifecycleState] = None
243
+ ) -> List[AgentLifecycleRecord]:
244
+ """
245
+ List agents filtered by state.
246
+
247
+ Args:
248
+ state: State to filter by (None for all)
249
+
250
+ Returns:
251
+ List of matching agent records
252
+ """
253
+ agents = list(self.agent_records.values())
254
+
255
+ if state:
256
+ agents = [a for a in agents if a.current_state == state]
257
+
258
+ return sorted(agents, key=lambda x: x.last_modified, reverse=True)
259
+
260
+ def get_state_statistics(self) -> Dict[str, int]:
261
+ """Get count of agents in each state."""
262
+ stats = {}
263
+ for record in self.agent_records.values():
264
+ state_name = record.current_state.value
265
+ stats[state_name] = stats.get(state_name, 0) + 1
266
+ return stats
267
+
268
+ def get_transition_history(
269
+ self, agent_name: Optional[str] = None, limit: int = 100
270
+ ) -> List[StateTransition]:
271
+ """
272
+ Get state transition history.
273
+
274
+ Args:
275
+ agent_name: Filter by agent name (None for all)
276
+ limit: Maximum number of transitions to return
277
+
278
+ Returns:
279
+ List of state transitions
280
+ """
281
+ history = self.transition_history
282
+
283
+ if agent_name:
284
+ history = [t for t in history if t.agent_name == agent_name]
285
+
286
+ # Return most recent first
287
+ return sorted(history, key=lambda x: x.timestamp, reverse=True)[:limit]
288
+
289
+ def update_record_metadata(self, agent_name: str, **metadata) -> bool:
290
+ """
291
+ Update metadata for an agent record.
292
+
293
+ Args:
294
+ agent_name: Name of the agent
295
+ **metadata: Metadata to update
296
+
297
+ Returns:
298
+ True if successful, False if agent not found
299
+ """
300
+ record = self.agent_records.get(agent_name)
301
+ if not record:
302
+ return False
303
+
304
+ record.metadata.update(metadata)
305
+ record.last_modified = time.time()
306
+ return True
307
+
308
+ def increment_version(self, agent_name: str) -> Optional[str]:
309
+ """
310
+ Increment the patch version of an agent.
311
+
312
+ Args:
313
+ agent_name: Name of the agent
314
+
315
+ Returns:
316
+ New version string or None if agent not found
317
+ """
318
+ record = self.agent_records.get(agent_name)
319
+ if not record:
320
+ return None
321
+
322
+ # Parse and increment version
323
+ parts = record.version.split(".")
324
+ parts[-1] = str(int(parts[-1]) + 1)
325
+ record.version = ".".join(parts)
326
+ record.last_modified = time.time()
327
+
328
+ return record.version
329
+
330
+ def add_modification(self, agent_name: str, modification_id: str) -> bool:
331
+ """Add a modification ID to agent's history."""
332
+ record = self.agent_records.get(agent_name)
333
+ if not record:
334
+ return False
335
+
336
+ record.modifications.append(modification_id)
337
+ record.last_modified = time.time()
338
+ return True
339
+
340
+ def add_persistence_operation(self, agent_name: str, operation_id: str) -> bool:
341
+ """Add a persistence operation ID to agent's history."""
342
+ record = self.agent_records.get(agent_name)
343
+ if not record:
344
+ return False
345
+
346
+ record.persistence_operations.append(operation_id)
347
+ record.last_modified = time.time()
348
+ return True
349
+
350
+ def add_backup_path(self, agent_name: str, backup_path: str) -> bool:
351
+ """Add a backup path to agent's record."""
352
+ record = self.agent_records.get(agent_name)
353
+ if not record:
354
+ return False
355
+
356
+ record.backup_paths.append(backup_path)
357
+ record.last_modified = time.time()
358
+ return True
359
+
360
+ def get_tier_statistics(self) -> Dict[str, int]:
361
+ """Get count of agents in each tier."""
362
+ stats = {}
363
+ for record in self.agent_records.values():
364
+ tier_name = record.tier.value
365
+ stats[tier_name] = stats.get(tier_name, 0) + 1
366
+ return stats
367
+
368
+ async def _initialize(self) -> None:
369
+ """Initialize the state service."""
370
+ self.logger.info("AgentStateService initialized")
371
+
372
+ async def _cleanup(self) -> None:
373
+ """Cleanup the state service."""
374
+ self.logger.info("AgentStateService cleaned up")
375
+
376
+ async def _health_check(self) -> Dict[str, bool]:
377
+ """Perform health check."""
378
+ return {
379
+ "records_loaded": len(self.agent_records) > 0,
380
+ "transitions_valid": True,
381
+ }
@@ -93,7 +93,8 @@ class MultiSourceAgentDeploymentService:
93
93
  f"Discovering agents from {source_name} source: {source_dir}"
94
94
  )
95
95
  discovery_service = AgentDiscoveryService(source_dir)
96
- agents = discovery_service.list_available_agents()
96
+ # Pass log_discovery=False to avoid duplicate logging
97
+ agents = discovery_service.list_available_agents(log_discovery=False)
97
98
 
98
99
  for agent_info in agents:
99
100
  agent_name = agent_info.get("name")
@@ -110,8 +111,9 @@ class MultiSourceAgentDeploymentService:
110
111
 
111
112
  agents_by_name[agent_name].append(agent_info)
112
113
 
114
+ # Use more specific log message
113
115
  self.logger.info(
114
- f"Discovered {len(agents)} agents from {source_name} source"
116
+ f"Discovered {len(agents)} {source_name} agent templates from {source_dir.name}"
115
117
  )
116
118
 
117
119
  return agents_by_name
@@ -12,6 +12,7 @@ from .common_issues_check import CommonIssuesCheck
12
12
  from .configuration_check import ConfigurationCheck
13
13
  from .filesystem_check import FilesystemCheck
14
14
  from .installation_check import InstallationCheck
15
+ from .instructions_check import InstructionsCheck
15
16
  from .mcp_check import MCPCheck
16
17
  from .monitor_check import MonitorCheck
17
18
  from .startup_log_check import StartupLogCheck
@@ -24,6 +25,7 @@ __all__ = [
24
25
  "ConfigurationCheck",
25
26
  "FilesystemCheck",
26
27
  "InstallationCheck",
28
+ "InstructionsCheck",
27
29
  "MCPCheck",
28
30
  "MonitorCheck",
29
31
  "StartupLogCheck",