claude-mpm 4.1.4__py3-none-any.whl → 4.1.5__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 (41) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/cli/commands/tickets.py +365 -784
  3. claude_mpm/core/output_style_manager.py +24 -0
  4. claude_mpm/core/unified_agent_registry.py +46 -15
  5. claude_mpm/services/agents/deployment/agent_discovery_service.py +12 -3
  6. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +172 -233
  7. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +575 -0
  8. claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
  9. claude_mpm/services/agents/deployment/agent_record_service.py +419 -0
  10. claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
  11. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +4 -2
  12. claude_mpm/services/infrastructure/__init__.py +31 -5
  13. claude_mpm/services/infrastructure/monitoring/__init__.py +43 -0
  14. claude_mpm/services/infrastructure/monitoring/aggregator.py +437 -0
  15. claude_mpm/services/infrastructure/monitoring/base.py +130 -0
  16. claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
  17. claude_mpm/services/infrastructure/monitoring/network.py +218 -0
  18. claude_mpm/services/infrastructure/monitoring/process.py +342 -0
  19. claude_mpm/services/infrastructure/monitoring/resources.py +243 -0
  20. claude_mpm/services/infrastructure/monitoring/service.py +367 -0
  21. claude_mpm/services/infrastructure/monitoring.py +67 -1030
  22. claude_mpm/services/project/analyzer.py +13 -4
  23. claude_mpm/services/project/analyzer_refactored.py +450 -0
  24. claude_mpm/services/project/analyzer_v2.py +566 -0
  25. claude_mpm/services/project/architecture_analyzer.py +461 -0
  26. claude_mpm/services/project/dependency_analyzer.py +462 -0
  27. claude_mpm/services/project/language_analyzer.py +265 -0
  28. claude_mpm/services/project/metrics_collector.py +410 -0
  29. claude_mpm/services/ticket_manager.py +5 -1
  30. claude_mpm/services/ticket_services/__init__.py +26 -0
  31. claude_mpm/services/ticket_services/crud_service.py +328 -0
  32. claude_mpm/services/ticket_services/formatter_service.py +290 -0
  33. claude_mpm/services/ticket_services/search_service.py +324 -0
  34. claude_mpm/services/ticket_services/validation_service.py +303 -0
  35. claude_mpm/services/ticket_services/workflow_service.py +244 -0
  36. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.5.dist-info}/METADATA +1 -1
  37. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.5.dist-info}/RECORD +41 -17
  38. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.5.dist-info}/WHEEL +0 -0
  39. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.5.dist-info}/entry_points.txt +0 -0
  40. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.5.dist-info}/licenses/LICENSE +0 -0
  41. {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.5.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
@@ -13,14 +13,40 @@ Services:
13
13
  - MemoryGuardian: Memory monitoring and process restart management
14
14
  """
15
15
 
16
- from .health_monitor import HealthMonitor
17
16
  from .logging import LoggingService
18
- from .memory_guardian import MemoryGuardian
19
- from .monitoring import AdvancedHealthMonitor
17
+ from .monitoring import (
18
+ AdvancedHealthMonitor,
19
+ MonitoringAggregatorService,
20
+ NetworkHealthService,
21
+ ProcessHealthService,
22
+ ResourceMonitorService,
23
+ ServiceHealthService,
24
+ )
25
+
26
+ # Check if optional modules exist
27
+ try:
28
+ from .health_monitor import HealthMonitor
29
+ except ImportError:
30
+ HealthMonitor = None
31
+
32
+ try:
33
+ from .memory_guardian import MemoryGuardian
34
+ except ImportError:
35
+ MemoryGuardian = None
20
36
 
21
37
  __all__ = [
22
38
  "AdvancedHealthMonitor", # For SocketIO server monitoring
23
- "HealthMonitor", # For Memory Guardian system monitoring
24
39
  "LoggingService",
25
- "MemoryGuardian",
40
+ # New service-based monitoring API
41
+ "MonitoringAggregatorService",
42
+ "NetworkHealthService",
43
+ "ProcessHealthService",
44
+ "ResourceMonitorService",
45
+ "ServiceHealthService",
26
46
  ]
47
+
48
+ # Add optional modules if they exist
49
+ if HealthMonitor is not None:
50
+ __all__.append("HealthMonitor")
51
+ if MemoryGuardian is not None:
52
+ __all__.append("MemoryGuardian")
@@ -0,0 +1,43 @@
1
+ """Refactored monitoring services package.
2
+
3
+ Exports main monitoring components for backward compatibility.
4
+ """
5
+
6
+ from .aggregator import MonitoringAggregatorService
7
+ from .base import (
8
+ HealthChecker,
9
+ HealthCheckResult,
10
+ HealthMetric,
11
+ HealthStatus,
12
+ )
13
+
14
+ # Legacy exports for backward compatibility
15
+ from .legacy import (
16
+ AdvancedHealthMonitor,
17
+ NetworkConnectivityChecker,
18
+ ProcessResourceChecker,
19
+ ServiceHealthChecker,
20
+ )
21
+ from .network import NetworkHealthService
22
+ from .process import ProcessHealthService
23
+ from .resources import ResourceMonitorService
24
+ from .service import ServiceHealthService
25
+
26
+ __all__ = [
27
+ # New service-based API
28
+ "ResourceMonitorService",
29
+ "ProcessHealthService",
30
+ "ServiceHealthService",
31
+ "NetworkHealthService",
32
+ "MonitoringAggregatorService",
33
+ # Base components
34
+ "HealthStatus",
35
+ "HealthMetric",
36
+ "HealthCheckResult",
37
+ "HealthChecker",
38
+ # Legacy compatibility
39
+ "ProcessResourceChecker",
40
+ "NetworkConnectivityChecker",
41
+ "ServiceHealthChecker",
42
+ "AdvancedHealthMonitor",
43
+ ]