claude-mpm 5.4.95__py3-none-any.whl → 5.4.97__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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
- claude_mpm/agents/PM_INSTRUCTIONS.md +7 -4
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/cli/commands/autotodos.py +526 -0
- claude_mpm/cli/executor.py +88 -0
- claude_mpm/cli/parsers/base_parser.py +54 -1
- claude_mpm/cli/startup.py +3 -2
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/output_style_manager.py +15 -5
- claude_mpm/hooks/claude_hooks/event_handlers.py +79 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +4 -3
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +14 -77
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/event_log.py +317 -0
- {claude_mpm-5.4.95.dist-info → claude_mpm-5.4.97.dist-info}/METADATA +4 -2
- {claude_mpm-5.4.95.dist-info → claude_mpm-5.4.97.dist-info}/RECORD +22 -34
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- {claude_mpm-5.4.95.dist-info → claude_mpm-5.4.97.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.95.dist-info → claude_mpm-5.4.97.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.95.dist-info → claude_mpm-5.4.97.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.95.dist-info → claude_mpm-5.4.97.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.95.dist-info → claude_mpm-5.4.97.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""Delegation Pattern Detector for PM outputs.
|
|
2
|
+
|
|
3
|
+
WHY this is needed:
|
|
4
|
+
- Detect when PM asks user to do something manually instead of delegating
|
|
5
|
+
- Convert manual instructions into actionable autotodos
|
|
6
|
+
- Enforce delegation principle in PM workflow
|
|
7
|
+
- Help PM recognize delegation opportunities
|
|
8
|
+
|
|
9
|
+
DESIGN DECISION: Pattern-based detection
|
|
10
|
+
- Simple regex patterns to catch common delegation anti-patterns
|
|
11
|
+
- Extract action items from PM's output
|
|
12
|
+
- Format as autotodos for PM to see and delegate properly
|
|
13
|
+
- Non-invasive - just surfaces patterns for review
|
|
14
|
+
|
|
15
|
+
Examples of patterns to detect:
|
|
16
|
+
- "Make sure .env.local is in your .gitignore"
|
|
17
|
+
- "You'll need to run npm install"
|
|
18
|
+
- "Please run the tests manually"
|
|
19
|
+
- "Remember to update the README"
|
|
20
|
+
- "Don't forget to commit your changes"
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import re
|
|
24
|
+
from typing import Any, Dict, List, Tuple
|
|
25
|
+
|
|
26
|
+
from ..core.logger import get_logger
|
|
27
|
+
|
|
28
|
+
# Delegation anti-patterns with capture groups for action extraction
|
|
29
|
+
# Each pattern is (regex_pattern, todo_template)
|
|
30
|
+
# {match} in template will be replaced with captured text
|
|
31
|
+
USER_DELEGATION_PATTERNS: List[Tuple[str, str]] = [
|
|
32
|
+
# "Make sure (to) X" → "Verify: X"
|
|
33
|
+
(r"(?i)make sure (?:to |that |you )?(.+)", "Verify: {match}"),
|
|
34
|
+
# "You'll/will need to X" → "Task: X"
|
|
35
|
+
(r"(?i)you(?:'ll| will)? need to (.+)", "Task: {match}"),
|
|
36
|
+
# "Please run/execute/do X" → "Execute: X"
|
|
37
|
+
(r"(?i)please (?:run|execute|do) (.+)", "Execute: {match}"),
|
|
38
|
+
# "Remember to X" → "Task: X"
|
|
39
|
+
(r"(?i)remember to (.+)", "Task: {match}"),
|
|
40
|
+
# "Don't forget to X" → "Task: X"
|
|
41
|
+
(r"(?i)don'?t forget to (.+)", "Task: {match}"),
|
|
42
|
+
# "You should/can/could X" → "Suggested: X"
|
|
43
|
+
(r"(?i)you (?:should|can|could) (.+)", "Suggested: {match}"),
|
|
44
|
+
# "Be sure to X" → "Task: X"
|
|
45
|
+
(r"(?i)be sure to (.+)", "Task: {match}"),
|
|
46
|
+
# "Don't forget X" (without 'to') → "Task: X"
|
|
47
|
+
(r"(?i)don'?t forget (.+)", "Task: {match}"),
|
|
48
|
+
# "You may want to X" → "Suggested: X"
|
|
49
|
+
(r"(?i)you may want to (.+)", "Suggested: {match}"),
|
|
50
|
+
# "It's important to X" → "Task: X"
|
|
51
|
+
(r"(?i)it'?s important to (.+)", "Task: {match}"),
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class DelegationDetector:
|
|
56
|
+
"""Detects delegation anti-patterns in PM outputs.
|
|
57
|
+
|
|
58
|
+
WHY this design:
|
|
59
|
+
- Pattern-based detection for common manual instruction phrases
|
|
60
|
+
- Extract actionable tasks from PM's text
|
|
61
|
+
- Format as autotodos for PM visibility
|
|
62
|
+
- Simple and extensible (add new patterns easily)
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def __init__(self):
|
|
66
|
+
self.logger = get_logger("delegation_detector")
|
|
67
|
+
|
|
68
|
+
def detect_user_delegation(self, text: str) -> List[Dict[str, Any]]:
|
|
69
|
+
"""Detect delegation anti-patterns in text.
|
|
70
|
+
|
|
71
|
+
Scans text for patterns where PM is asking user to do something
|
|
72
|
+
manually instead of delegating to an agent.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
text: PM output text to scan
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
List of detected patterns with:
|
|
79
|
+
- pattern_type: Type of pattern matched
|
|
80
|
+
- original_text: Original sentence matched
|
|
81
|
+
- suggested_todo: Formatted todo text
|
|
82
|
+
- action: Extracted action text
|
|
83
|
+
"""
|
|
84
|
+
detections = []
|
|
85
|
+
|
|
86
|
+
# Split into sentences for better pattern matching
|
|
87
|
+
# Split on period followed by space/newline, or just newline
|
|
88
|
+
# This avoids splitting on periods in filenames like .env.local
|
|
89
|
+
sentences = re.split(r"(?:\.\s+|\n+)", text)
|
|
90
|
+
|
|
91
|
+
for sentence in sentences:
|
|
92
|
+
sentence = sentence.strip()
|
|
93
|
+
if not sentence:
|
|
94
|
+
continue
|
|
95
|
+
|
|
96
|
+
# Try each pattern
|
|
97
|
+
for pattern, todo_template in USER_DELEGATION_PATTERNS:
|
|
98
|
+
match = re.search(pattern, sentence, re.IGNORECASE)
|
|
99
|
+
if match:
|
|
100
|
+
# Extract the captured action
|
|
101
|
+
action = match.group(1).strip()
|
|
102
|
+
|
|
103
|
+
# Skip if action is too short (likely false positive)
|
|
104
|
+
if len(action) < 5:
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
# Format todo using template
|
|
108
|
+
suggested_todo = todo_template.format(match=action)
|
|
109
|
+
|
|
110
|
+
# Determine pattern type from template prefix
|
|
111
|
+
pattern_type = todo_template.split(":")[0]
|
|
112
|
+
|
|
113
|
+
detection = {
|
|
114
|
+
"pattern_type": pattern_type,
|
|
115
|
+
"original_text": sentence.strip(),
|
|
116
|
+
"suggested_todo": suggested_todo,
|
|
117
|
+
"action": action,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
detections.append(detection)
|
|
121
|
+
self.logger.debug(
|
|
122
|
+
f"Detected delegation pattern: {pattern_type} - {action}"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Only match first pattern per sentence
|
|
126
|
+
break
|
|
127
|
+
|
|
128
|
+
return detections
|
|
129
|
+
|
|
130
|
+
def format_as_autotodo(self, detection: Dict[str, Any]) -> Dict[str, str]:
|
|
131
|
+
"""Format a detection as an autotodo.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
detection: Detection dict from detect_user_delegation
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
Dictionary with todo fields (content, activeForm, status)
|
|
138
|
+
"""
|
|
139
|
+
pattern_type = detection["pattern_type"]
|
|
140
|
+
suggested_todo = detection["suggested_todo"]
|
|
141
|
+
action = detection["action"]
|
|
142
|
+
|
|
143
|
+
# Create todo content
|
|
144
|
+
content = f"[Delegation] {suggested_todo}"
|
|
145
|
+
|
|
146
|
+
# Active form for in-progress display
|
|
147
|
+
active_form = f"Delegating: {action[:30]}..."
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
"content": content,
|
|
151
|
+
"activeForm": active_form,
|
|
152
|
+
"status": "pending",
|
|
153
|
+
"metadata": {
|
|
154
|
+
"pattern_type": pattern_type,
|
|
155
|
+
"original_text": detection["original_text"],
|
|
156
|
+
"action": action,
|
|
157
|
+
"source": "delegation_detector",
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
# Global instance
|
|
163
|
+
_delegation_detector: DelegationDetector | None = None
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def get_delegation_detector() -> DelegationDetector:
|
|
167
|
+
"""Get the global delegation detector instance.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
DelegationDetector instance
|
|
171
|
+
"""
|
|
172
|
+
global _delegation_detector
|
|
173
|
+
if _delegation_detector is None:
|
|
174
|
+
_delegation_detector = DelegationDetector()
|
|
175
|
+
return _delegation_detector
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"""Event Log Service for persistent event storage.
|
|
2
|
+
|
|
3
|
+
WHY this is needed:
|
|
4
|
+
- Decouple event producers from consumers
|
|
5
|
+
- Persist events for later processing (e.g., autotodos CLI)
|
|
6
|
+
- Enable event-driven architecture patterns
|
|
7
|
+
- Provide audit trail of system events
|
|
8
|
+
|
|
9
|
+
DESIGN DECISION: Simple JSON file storage because:
|
|
10
|
+
- Human-readable and inspectable
|
|
11
|
+
- No additional database dependencies
|
|
12
|
+
- Fast for small event volumes
|
|
13
|
+
- Easy to clear and manage
|
|
14
|
+
- Follows existing pattern (hook_error_memory)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
from datetime import datetime, timezone
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any, Dict, List, Literal, Optional
|
|
21
|
+
|
|
22
|
+
from ..core.logger import get_logger
|
|
23
|
+
|
|
24
|
+
# Event status types
|
|
25
|
+
EventStatus = Literal["pending", "resolved", "archived"]
|
|
26
|
+
|
|
27
|
+
# Max message length to prevent file bloat
|
|
28
|
+
MAX_MESSAGE_LENGTH = 2000
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class EventLog:
|
|
32
|
+
"""Persistent event log with simple JSON storage.
|
|
33
|
+
|
|
34
|
+
WHY this design:
|
|
35
|
+
- Store events with timestamp, type, payload, status
|
|
36
|
+
- Support filtering by status and event type
|
|
37
|
+
- Prevent file bloat with message truncation
|
|
38
|
+
- Enable mark-as-resolved workflow
|
|
39
|
+
- Keep it simple - no complex queries needed
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(self, log_file: Optional[Path] = None):
|
|
43
|
+
"""Initialize event log.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
log_file: Path to event log file (default: .claude-mpm/event_log.json)
|
|
47
|
+
"""
|
|
48
|
+
self.logger = get_logger("event_log")
|
|
49
|
+
|
|
50
|
+
# Use default location if not specified
|
|
51
|
+
if log_file is None:
|
|
52
|
+
log_file = Path.cwd() / ".claude-mpm" / "event_log.json"
|
|
53
|
+
|
|
54
|
+
self.log_file = log_file
|
|
55
|
+
self.events: List[Dict[str, Any]] = self._load_events()
|
|
56
|
+
|
|
57
|
+
def _load_events(self) -> List[Dict[str, Any]]:
|
|
58
|
+
"""Load events from disk.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
List of event records
|
|
62
|
+
"""
|
|
63
|
+
if not self.log_file.exists():
|
|
64
|
+
return []
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
content = self.log_file.read_text()
|
|
68
|
+
if not content.strip():
|
|
69
|
+
return []
|
|
70
|
+
data = json.loads(content)
|
|
71
|
+
|
|
72
|
+
# Validate structure
|
|
73
|
+
if not isinstance(data, list):
|
|
74
|
+
self.logger.warning("Event log is not a list, resetting")
|
|
75
|
+
return []
|
|
76
|
+
|
|
77
|
+
return data
|
|
78
|
+
except json.JSONDecodeError as e:
|
|
79
|
+
self.logger.warning(f"Failed to parse event log: {e}, resetting")
|
|
80
|
+
return []
|
|
81
|
+
except Exception as e:
|
|
82
|
+
self.logger.error(f"Error loading event log: {e}")
|
|
83
|
+
return []
|
|
84
|
+
|
|
85
|
+
def _save_events(self):
|
|
86
|
+
"""Persist events to disk."""
|
|
87
|
+
try:
|
|
88
|
+
# Ensure directory exists
|
|
89
|
+
self.log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
90
|
+
|
|
91
|
+
# Write with pretty formatting for human readability
|
|
92
|
+
self.log_file.write_text(json.dumps(self.events, indent=2))
|
|
93
|
+
except Exception as e:
|
|
94
|
+
self.logger.error(f"Failed to save event log: {e}")
|
|
95
|
+
|
|
96
|
+
def _truncate_message(self, message: str) -> str:
|
|
97
|
+
"""Truncate message to prevent file bloat.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
message: Message to truncate
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Truncated message with ellipsis if needed
|
|
104
|
+
"""
|
|
105
|
+
if len(message) <= MAX_MESSAGE_LENGTH:
|
|
106
|
+
return message
|
|
107
|
+
|
|
108
|
+
return message[:MAX_MESSAGE_LENGTH] + "... (truncated)"
|
|
109
|
+
|
|
110
|
+
def append_event(
|
|
111
|
+
self,
|
|
112
|
+
event_type: str,
|
|
113
|
+
payload: Dict[str, Any],
|
|
114
|
+
status: EventStatus = "pending",
|
|
115
|
+
) -> str:
|
|
116
|
+
"""Append a new event to the log.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
event_type: Type of event (e.g., "autotodo.error", "hook.error")
|
|
120
|
+
payload: Event data (will be truncated if too large)
|
|
121
|
+
status: Event status (default: "pending")
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Event ID (timestamp-based for simplicity)
|
|
125
|
+
"""
|
|
126
|
+
# Truncate any message fields in payload
|
|
127
|
+
truncated_payload = payload.copy()
|
|
128
|
+
if "message" in truncated_payload:
|
|
129
|
+
truncated_payload["message"] = self._truncate_message(
|
|
130
|
+
str(truncated_payload["message"])
|
|
131
|
+
)
|
|
132
|
+
if "full_message" in truncated_payload:
|
|
133
|
+
truncated_payload["full_message"] = self._truncate_message(
|
|
134
|
+
str(truncated_payload["full_message"])
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Create event record
|
|
138
|
+
timestamp = datetime.now(timezone.utc).isoformat()
|
|
139
|
+
event = {
|
|
140
|
+
"id": timestamp, # Use timestamp as ID for simplicity
|
|
141
|
+
"timestamp": timestamp,
|
|
142
|
+
"event_type": event_type,
|
|
143
|
+
"payload": truncated_payload,
|
|
144
|
+
"status": status,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
# Append and save
|
|
148
|
+
self.events.append(event)
|
|
149
|
+
self._save_events()
|
|
150
|
+
|
|
151
|
+
self.logger.debug(f"Appended event: {event_type} (status: {status})")
|
|
152
|
+
return timestamp
|
|
153
|
+
|
|
154
|
+
def list_events(
|
|
155
|
+
self,
|
|
156
|
+
event_type: Optional[str] = None,
|
|
157
|
+
status: Optional[EventStatus] = None,
|
|
158
|
+
limit: Optional[int] = None,
|
|
159
|
+
) -> List[Dict[str, Any]]:
|
|
160
|
+
"""List events with optional filtering.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
event_type: Filter by event type (e.g., "autotodo.error")
|
|
164
|
+
status: Filter by status (e.g., "pending")
|
|
165
|
+
limit: Maximum number of events to return (most recent first)
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
List of matching events
|
|
169
|
+
"""
|
|
170
|
+
# Filter events
|
|
171
|
+
filtered = self.events
|
|
172
|
+
|
|
173
|
+
if event_type:
|
|
174
|
+
filtered = [e for e in filtered if e["event_type"] == event_type]
|
|
175
|
+
|
|
176
|
+
if status:
|
|
177
|
+
filtered = [e for e in filtered if e["status"] == status]
|
|
178
|
+
|
|
179
|
+
# Sort by timestamp (most recent first)
|
|
180
|
+
filtered = sorted(filtered, key=lambda e: e["timestamp"], reverse=True)
|
|
181
|
+
|
|
182
|
+
# Apply limit
|
|
183
|
+
if limit:
|
|
184
|
+
filtered = filtered[:limit]
|
|
185
|
+
|
|
186
|
+
return filtered
|
|
187
|
+
|
|
188
|
+
def mark_resolved(self, event_id: str) -> bool:
|
|
189
|
+
"""Mark an event as resolved.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
event_id: Event ID (timestamp)
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
True if event was found and updated
|
|
196
|
+
"""
|
|
197
|
+
for event in self.events:
|
|
198
|
+
if event["id"] == event_id:
|
|
199
|
+
event["status"] = "resolved"
|
|
200
|
+
event["resolved_at"] = datetime.now(timezone.utc).isoformat()
|
|
201
|
+
self._save_events()
|
|
202
|
+
self.logger.debug(f"Marked event resolved: {event_id}")
|
|
203
|
+
return True
|
|
204
|
+
|
|
205
|
+
return False
|
|
206
|
+
|
|
207
|
+
def mark_all_resolved(
|
|
208
|
+
self, event_type: Optional[str] = None, status: EventStatus = "pending"
|
|
209
|
+
) -> int:
|
|
210
|
+
"""Mark multiple events as resolved.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
event_type: Optional filter by event type
|
|
214
|
+
status: Filter by current status (default: "pending")
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
Number of events marked as resolved
|
|
218
|
+
"""
|
|
219
|
+
count = 0
|
|
220
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
221
|
+
|
|
222
|
+
for event in self.events:
|
|
223
|
+
# Check filters
|
|
224
|
+
if event["status"] != status:
|
|
225
|
+
continue
|
|
226
|
+
if event_type and event["event_type"] != event_type:
|
|
227
|
+
continue
|
|
228
|
+
|
|
229
|
+
# Mark resolved
|
|
230
|
+
event["status"] = "resolved"
|
|
231
|
+
event["resolved_at"] = now
|
|
232
|
+
count += 1
|
|
233
|
+
|
|
234
|
+
if count > 0:
|
|
235
|
+
self._save_events()
|
|
236
|
+
self.logger.debug(f"Marked {count} events as resolved")
|
|
237
|
+
|
|
238
|
+
return count
|
|
239
|
+
|
|
240
|
+
def clear_resolved(self, older_than_days: Optional[int] = None) -> int:
|
|
241
|
+
"""Remove resolved events from the log.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
older_than_days: Only clear events older than N days
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
Number of events removed
|
|
248
|
+
"""
|
|
249
|
+
if older_than_days:
|
|
250
|
+
# Calculate cutoff timestamp
|
|
251
|
+
from datetime import timedelta
|
|
252
|
+
|
|
253
|
+
cutoff = datetime.now(timezone.utc) - timedelta(days=older_than_days)
|
|
254
|
+
cutoff_iso = cutoff.isoformat()
|
|
255
|
+
|
|
256
|
+
# Keep events that are NOT resolved OR are newer than cutoff
|
|
257
|
+
before_count = len(self.events)
|
|
258
|
+
self.events = [
|
|
259
|
+
e
|
|
260
|
+
for e in self.events
|
|
261
|
+
if e["status"] != "resolved" or e.get("resolved_at", "") > cutoff_iso
|
|
262
|
+
]
|
|
263
|
+
removed = before_count - len(self.events)
|
|
264
|
+
else:
|
|
265
|
+
# Remove all resolved events
|
|
266
|
+
before_count = len(self.events)
|
|
267
|
+
self.events = [e for e in self.events if e["status"] != "resolved"]
|
|
268
|
+
removed = before_count - len(self.events)
|
|
269
|
+
|
|
270
|
+
if removed > 0:
|
|
271
|
+
self._save_events()
|
|
272
|
+
self.logger.debug(f"Cleared {removed} resolved events")
|
|
273
|
+
|
|
274
|
+
return removed
|
|
275
|
+
|
|
276
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
277
|
+
"""Get event log statistics.
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
Dictionary with event counts by status and type
|
|
281
|
+
"""
|
|
282
|
+
stats = {
|
|
283
|
+
"total_events": len(self.events),
|
|
284
|
+
"by_status": {"pending": 0, "resolved": 0, "archived": 0},
|
|
285
|
+
"by_type": {},
|
|
286
|
+
"log_file": str(self.log_file),
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
for event in self.events:
|
|
290
|
+
# Count by status
|
|
291
|
+
status = event["status"]
|
|
292
|
+
stats["by_status"][status] = stats["by_status"].get(status, 0) + 1
|
|
293
|
+
|
|
294
|
+
# Count by type
|
|
295
|
+
event_type = event["event_type"]
|
|
296
|
+
stats["by_type"][event_type] = stats["by_type"].get(event_type, 0) + 1
|
|
297
|
+
|
|
298
|
+
return stats
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
# Global instance
|
|
302
|
+
_event_log: Optional[EventLog] = None
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def get_event_log(log_file: Optional[Path] = None) -> EventLog:
|
|
306
|
+
"""Get the global event log instance.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
log_file: Optional custom log file path
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
EventLog instance
|
|
313
|
+
"""
|
|
314
|
+
global _event_log
|
|
315
|
+
if _event_log is None:
|
|
316
|
+
_event_log = EventLog(log_file)
|
|
317
|
+
return _event_log
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-mpm
|
|
3
|
-
Version: 5.4.
|
|
3
|
+
Version: 5.4.97
|
|
4
4
|
Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
|
|
5
5
|
Author-email: Bob Matsuoka <bob@matsuoka.com>
|
|
6
6
|
Maintainer: Claude MPM Team
|
|
@@ -118,7 +118,7 @@ A powerful orchestration framework for **Claude Code (CLI)** that enables multi-
|
|
|
118
118
|
|
|
119
119
|
## Who Should Use Claude MPM?
|
|
120
120
|
|
|
121
|
-
- 👥 **[Non-Technical Users (Founders/PMs)](docs/usecases/non-technical-users.md)** -
|
|
121
|
+
- 👥 **[Non-Technical Users (Founders/PMs)](docs/usecases/non-technical-users.md)** - Research and understand codebases using Research Mode - no coding experience required
|
|
122
122
|
- 💻 **[Developers](docs/usecases/developers.md)** - Multi-agent development workflows with semantic code search and advanced features
|
|
123
123
|
- 🏢 **[Teams](docs/usecases/teams.md)** - Collaboration patterns, session management, and coordinated workflows
|
|
124
124
|
|
|
@@ -195,6 +195,8 @@ ls ~/.claude/agents/ # Should show 47+ agents
|
|
|
195
195
|
|
|
196
196
|
**💡 Recommended Partners**: Install [kuzu-memory](https://github.com/bobmatnyc/kuzu-memory) (persistent context) and [mcp-vector-search](https://github.com/bobmatnyc/mcp-vector-search) (semantic search) for enhanced capabilities.
|
|
197
197
|
|
|
198
|
+
**💡 Tool Version Management**: Use [ASDF version manager](docs/guides/asdf-tool-versions.md) to avoid Python/uv version conflicts across projects.
|
|
199
|
+
|
|
198
200
|
---
|
|
199
201
|
|
|
200
202
|
## Key Features
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
claude_mpm/BUILD_NUMBER,sha256=9JfxhnDtr-8l3kCP2U5TVXSErptHoga8m7XA8zqgGOc,4
|
|
2
|
-
claude_mpm/VERSION,sha256=
|
|
2
|
+
claude_mpm/VERSION,sha256=BdiMNKt3O_zm2CNWcenla-qyFB2MItaHAgpbSdn2wrk,7
|
|
3
3
|
claude_mpm/__init__.py,sha256=AGfh00BHKvLYD-UVFw7qbKtl7NMRIzRXOWw7vEuZ-h4,2214
|
|
4
4
|
claude_mpm/__main__.py,sha256=Ro5UBWBoQaSAIoSqWAr7zkbLyvi4sSy28WShqAhKJG0,723
|
|
5
5
|
claude_mpm/constants.py,sha256=pz3lTrZZR5HhV3eZzYtIbtBwWo7iM6pkBHP_ixxmI6Y,6827
|
|
@@ -7,11 +7,11 @@ claude_mpm/init.py,sha256=YSA2f0evX8FvqyI2Zx_4tvhaw18FPSMlf5yqTR_ilPE,26394
|
|
|
7
7
|
claude_mpm/ticket_wrapper.py,sha256=qe5xY579t7_7fK5nyeAfHN_fr7CXdeOD3jfXEc8-7yo,828
|
|
8
8
|
claude_mpm/agents/BASE_AGENT.md,sha256=UWvKX5S5L2l68F_sn54otC_HDX5kTt8G4ionUcTVpGo,5645
|
|
9
9
|
claude_mpm/agents/BASE_ENGINEER.md,sha256=I7BusSGQfuV0uSkRBro51qzCzagUEPrXnndIElypPJk,24434
|
|
10
|
-
claude_mpm/agents/CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md,sha256=d4hZRc2wG2XzLaIxl2eQgdeuW6115C_pm6MtqNHVtOc,12997
|
|
11
10
|
claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md,sha256=C61nb8szGeeGaXQd9-VPpL1t79G2pDoYlDsGv_JLOLk,4349
|
|
11
|
+
claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md,sha256=OIVDU0Ypw5qrXix9rmMDG4u0V4ePnYDlsu5AoTmfZzs,13294
|
|
12
12
|
claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md,sha256=vneNW5vHjfKsRIukkuGbAnvnyp_-EC3qpFzHDdsMOwc,4796
|
|
13
13
|
claude_mpm/agents/MEMORY.md,sha256=V1mGx5oEaLdN9AYLX3Xetslmr2Ja6vnLPATeEoR6bvw,3303
|
|
14
|
-
claude_mpm/agents/PM_INSTRUCTIONS.md,sha256=
|
|
14
|
+
claude_mpm/agents/PM_INSTRUCTIONS.md,sha256=A0TBjt4sxwahevpnubh2wgVzKOisX2AluBiqyuolQ0E,33500
|
|
15
15
|
claude_mpm/agents/WORKFLOW.md,sha256=BD5V5wNgz4C2gHPn4ekRmj4i7nn56s1ZF8YnhWBPkFw,3331
|
|
16
16
|
claude_mpm/agents/__init__.py,sha256=3cCQh2Hf_-2F9XDT5In533Bw7oKuGIqZvOdBW7af6dY,3403
|
|
17
17
|
claude_mpm/agents/agent-template.yaml,sha256=mRlz5Yd0SmknTeoJWgFkZXzEF5T7OmGBJGs2-KPT93k,1969
|
|
@@ -24,7 +24,7 @@ claude_mpm/agents/frontmatter_validator.py,sha256=H0R7rCrNdaok5q7yCxEX2uiIcELU28
|
|
|
24
24
|
claude_mpm/agents/system_agent_config.py,sha256=19axX46jzvY6svETjfMaFyAYtgbQO2PRXKJ-VYnCPDk,24137
|
|
25
25
|
claude_mpm/agents/templates/README.md,sha256=qqhKh10y2CGuoytQmqlQtXCa_RD1ZmeT0m24S5VPQnI,18511
|
|
26
26
|
claude_mpm/agents/templates/__init__.py,sha256=kghxAWs3KvcAA9Esk3NI7caumYgW6fiW8vRO1-MEndU,2735
|
|
27
|
-
claude_mpm/agents/templates/circuit-breakers.md,sha256=
|
|
27
|
+
claude_mpm/agents/templates/circuit-breakers.md,sha256=K7_nvXWG6PEUDLdj1pqOU3Lj8_snoVN9TPCUavIZ4TA,49497
|
|
28
28
|
claude_mpm/agents/templates/context-management-examples.md,sha256=ySVsHKB9rh--yP3oNo6Q0cprYb7eKuKOkVl7uIGvzUs,15025
|
|
29
29
|
claude_mpm/agents/templates/git-file-tracking.md,sha256=r8qckL8pS2nIvZAImFgbjAzpaEhzV44B1lzz6V8Jg8M,18842
|
|
30
30
|
claude_mpm/agents/templates/pm-examples.md,sha256=Y_A5cqQHWLX7gbLQ9Z5uCLyrkoMS-ewR5POG42pW7ZQ,16804
|
|
@@ -39,10 +39,10 @@ claude_mpm/agents/templates/validation-templates.md,sha256=Y4_D7dphQaKigZWqKWvJ4
|
|
|
39
39
|
claude_mpm/cli/__init__.py,sha256=j5x0uyJ4bRrKY1V4626cQI66OZsBzRz6JN26gQBxYSQ,4568
|
|
40
40
|
claude_mpm/cli/__main__.py,sha256=KSy-J-vbTM2yXHOjsBJNZ60I2CJ2i5QP5zxsZV7-cjo,997
|
|
41
41
|
claude_mpm/cli/chrome_devtools_installer.py,sha256=efA_ZX1iR3oaJi3222079BQw6DEG8KYr2HVGtgVj2Gs,5637
|
|
42
|
-
claude_mpm/cli/executor.py,sha256=
|
|
42
|
+
claude_mpm/cli/executor.py,sha256=BswSkXHYbkBFuy0Wg7h1YpPExwK9KZZiev_630EB4Nc,14004
|
|
43
43
|
claude_mpm/cli/helpers.py,sha256=CypEhw0tbNH6_GzVTaQdi4w7ThCWO43Ep92YbJzPR4I,3638
|
|
44
44
|
claude_mpm/cli/parser.py,sha256=Vqx9n-6Xo1uNhXR4rThmgWpZXTr0nOtkgDf3oMS9b0g,5855
|
|
45
|
-
claude_mpm/cli/startup.py,sha256=
|
|
45
|
+
claude_mpm/cli/startup.py,sha256=JyNv5YZa_xC6B8fmw-mNxv0XK-XhIWFibJUz72Tg2H8,63021
|
|
46
46
|
claude_mpm/cli/startup_display.py,sha256=2b7cIow39gUFdJyarh9lv4uvnicnCWml-onUbKnGGWY,17132
|
|
47
47
|
claude_mpm/cli/startup_logging.py,sha256=wHokzcCA0AJPxAqFrpY5PMOBh1iOhdhgP1gY1OvD0gY,29392
|
|
48
48
|
claude_mpm/cli/utils.py,sha256=FSMPftBZM8MeUyTtiB63Lz7oFOgkzwTetQs58RbRb_Q,8785
|
|
@@ -58,6 +58,7 @@ claude_mpm/cli/commands/aggregate.py,sha256=v5JzzoWf6Omc4DaWfx_3gm5EWiUmUp6ps3Bd
|
|
|
58
58
|
claude_mpm/cli/commands/analyze.py,sha256=NuSreG9PINgf_1_41adMT_sOXz-z695Zqjwef4OEc9w,19162
|
|
59
59
|
claude_mpm/cli/commands/analyze_code.py,sha256=5FAoubjZbEO_GlErj3xNgNbJXBjhtqSOWE2FkhAzTaM,17256
|
|
60
60
|
claude_mpm/cli/commands/auto_configure.py,sha256=0Suzil6O0SBNeHUCwHOkt2q7gfuXRTyUu2UC99cCG4Y,40567
|
|
61
|
+
claude_mpm/cli/commands/autotodos.py,sha256=xJbSp1JXe-uK9OIFxKeQmFkbHyLTfyW_c34jCuPsIRQ,18126
|
|
61
62
|
claude_mpm/cli/commands/cleanup.py,sha256=RQikOGLuLFWXzjeoHArdr5FA4Pf7tSK9w2NXL4vCrok,19769
|
|
62
63
|
claude_mpm/cli/commands/cleanup_orphaned_agents.py,sha256=JR8crvgrz7Sa6d-SI-gKywok5S9rwc_DzDVk_h85sVs,4467
|
|
63
64
|
claude_mpm/cli/commands/config.py,sha256=2M9VUPYcQkBUCIyyB-v1qTL3xYvao9YI2l_JGBUDauA,23374
|
|
@@ -122,7 +123,7 @@ claude_mpm/cli/parsers/agents_parser.py,sha256=lJ_9M1IRHoNU9-WLXLqinxEmDk1rRL6Eh
|
|
|
122
123
|
claude_mpm/cli/parsers/analyze_code_parser.py,sha256=cpJSMFbc3mqB4qrMBIEZiikzPekC2IQX-cjt9U2fHW4,5356
|
|
123
124
|
claude_mpm/cli/parsers/analyze_parser.py,sha256=E00Ao0zwzbJPchs_AJt-aoQ7LQEtJPXRCNQ6Piivb4o,3908
|
|
124
125
|
claude_mpm/cli/parsers/auto_configure_parser.py,sha256=CZOk_nJZrNtRo8WnYWQKdfXywq6l6ZLMHU7U9hA7A_4,3699
|
|
125
|
-
claude_mpm/cli/parsers/base_parser.py,sha256=
|
|
126
|
+
claude_mpm/cli/parsers/base_parser.py,sha256=5Y-4nbn5KUC0KR6MliNH2Nf-o_s9xR76tBPFUE6D_lc,21865
|
|
126
127
|
claude_mpm/cli/parsers/config_parser.py,sha256=i8kv6XWhftzZlEBruAl58Fl6IcyeOb7QVkfPeEayjCk,6255
|
|
127
128
|
claude_mpm/cli/parsers/configure_parser.py,sha256=t3cwAQX3BfljDDRJH3i0LplpRprw5jdKcI9Uy3M8xtE,4382
|
|
128
129
|
claude_mpm/cli/parsers/dashboard_parser.py,sha256=JBCM6v_iZhADr_Fwtk_d3up9AOod1avMab-vkNE61gE,3460
|
|
@@ -191,7 +192,7 @@ claude_mpm/core/factories.py,sha256=oVyUzNqKKM6vEOIn5YV0r08TjLnLkUWLcCZPpj8W8b8,
|
|
|
191
192
|
claude_mpm/core/file_utils.py,sha256=ycbmSl4JflNGG3qcEnCLDeRYV1nceHn2SJVfGO8x1Qg,19937
|
|
192
193
|
claude_mpm/core/framework_loader.py,sha256=72z8e35ha1TI-5IVwB58VaVnogkozr51DgVHSJKLxR0,21028
|
|
193
194
|
claude_mpm/core/hook_error_memory.py,sha256=PHiSQWU4ek9IoqeiY8UixQrcshfVDEfegVVe-nM22EM,12842
|
|
194
|
-
claude_mpm/core/hook_manager.py,sha256=
|
|
195
|
+
claude_mpm/core/hook_manager.py,sha256=y_e4a0gKsHbOtfaobwdhnBSr2raHHAhKszRYbKo4i_4,14947
|
|
195
196
|
claude_mpm/core/hook_performance_config.py,sha256=e7a7oFctkRhA3aPXMO5Wavr-E6ku7ikLxMzPU7P1-yg,5779
|
|
196
197
|
claude_mpm/core/injectable_service.py,sha256=9N4mHt6a_PwoP0pQo-QhVTnXLJlgDCCOg358d0jPEs4,7384
|
|
197
198
|
claude_mpm/core/instruction_reinforcement_hook.py,sha256=hSYvUp_ducWnhcKTkUbUoCLUb_yCzbIgsqEp7VpF9h0,9542
|
|
@@ -207,7 +208,7 @@ claude_mpm/core/mixins.py,sha256=vmZ7Nu2ZOnKjbhN07Ixk4noIej9nsJiknrp-Sclfu0A,534
|
|
|
207
208
|
claude_mpm/core/oneshot_session.py,sha256=nA86Zk7W3Rh_yIhPuegFL7Xgc9S63vQ_MqfLk52doV0,21994
|
|
208
209
|
claude_mpm/core/optimized_agent_loader.py,sha256=yevEwTZWzVeZYEJhV3czD45OU7ukJIaJos4MGnFP7YQ,15857
|
|
209
210
|
claude_mpm/core/optimized_startup.py,sha256=U5I4f7PNYXCBOLbCkbWT2V2sv01T8iWP2Bw-f928Q9M,17927
|
|
210
|
-
claude_mpm/core/output_style_manager.py,sha256=
|
|
211
|
+
claude_mpm/core/output_style_manager.py,sha256=K3EY4w5wvvdjfzNSEZQxSYhzBCxAEexXQHHYAYR9Jcw,17931
|
|
211
212
|
claude_mpm/core/pm_hook_interceptor.py,sha256=92C8TrpK-XVQD8BiXbqs8lSCX72PU0KZG5oAjhf8GOQ,11197
|
|
212
213
|
claude_mpm/core/service_registry.py,sha256=QpmAMWCov8XXaxQwE7WiNbgv6u_CRjpKPB64kLYvZKk,11722
|
|
213
214
|
claude_mpm/core/session_manager.py,sha256=iEDZWKBYHSu001nFX8vFvH33RvQOW0eIgomWhFM53sw,12078
|
|
@@ -335,34 +336,19 @@ claude_mpm/hooks/claude_hooks/__init__.py,sha256=b4mud_g3S-3itHY_Dzpbb_SmdMEcJwt
|
|
|
335
336
|
claude_mpm/hooks/claude_hooks/auto_pause_handler.py,sha256=xDAQZ33I5OhGvtWvA9mxwVSoir9tM-aCvrWkSRdnVmU,17465
|
|
336
337
|
claude_mpm/hooks/claude_hooks/connection_pool.py,sha256=vpi-XbVf61GWhh85tHBzubbOgbJly_I-5-QmsleND2M,8658
|
|
337
338
|
claude_mpm/hooks/claude_hooks/correlation_manager.py,sha256=3n-RxzqE8egG4max_NcpJgL9gzrBY6Ti529LrjleI1g,2033
|
|
338
|
-
claude_mpm/hooks/claude_hooks/event_handlers.py,sha256=
|
|
339
|
-
claude_mpm/hooks/claude_hooks/hook_handler.py,sha256=
|
|
339
|
+
claude_mpm/hooks/claude_hooks/event_handlers.py,sha256=ryhpNe9c8wzGb2p3s0kBjFxY8BsVlHjwCo9Xc5RQnhc,45520
|
|
340
|
+
claude_mpm/hooks/claude_hooks/hook_handler.py,sha256=R2RhUoRvI0q_EGu-d5L9bH7cGg5_OLDskQoNrl3JsU0,28504
|
|
340
341
|
claude_mpm/hooks/claude_hooks/hook_wrapper.sh,sha256=4lG3TlLVoVfTJipPj1X_ICUlS-KpnkbUp1U3oSq80Bw,2476
|
|
341
342
|
claude_mpm/hooks/claude_hooks/installer.py,sha256=VbvVGMcrmCXQB3Pf9zOdjeGET2AFqbUDMHDy5KXuvz0,30463
|
|
342
343
|
claude_mpm/hooks/claude_hooks/memory_integration.py,sha256=73w7A5-3s5i1oYdkbEgw7qhgalQvSuJjfx6OFqfaw64,9963
|
|
343
344
|
claude_mpm/hooks/claude_hooks/response_tracking.py,sha256=bgX4iVQqmX0L3_GHyKs1q4CSIjnavdxYnJZT0GaT4gs,17148
|
|
344
345
|
claude_mpm/hooks/claude_hooks/tool_analysis.py,sha256=3_o2PP9D7wEMwLriCtIBOw0cj2fSZfepN7lI4P1meSQ,7862
|
|
345
|
-
claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc,sha256=EGpgXqhPM0iRRZtCqHaLVQ6wDH42OH_M7Gt5GiFLyro,346
|
|
346
|
-
claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc,sha256=X7A8O4KPXkuDaLDFbF7Izi1qVDyS0tQjHVo1xy_HzNQ,21172
|
|
347
|
-
claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc,sha256=SQX5iiP9bQZkLL-cj_2tlGH7lpAzarO0mYal7btj3tc,3521
|
|
348
|
-
claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc,sha256=HOJFN4bPVYKDDLzcnLMMn5MBy6rQS3cqveDS6Zh2ifg,40994
|
|
349
|
-
claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc,sha256=oanjwor2IoiY_AKIqZcuz3ex-Mp2OndP7VlvAn_4hMQ,30603
|
|
350
|
-
claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc,sha256=9mpAKY4gNcbU5VvZ5tGbf2UM0uIEWdreKSUvVr_BKcM,33917
|
|
351
|
-
claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc,sha256=YbwauQDKSGvXkT1972faalJLuxwyvq328DYQhkCnel0,10513
|
|
352
|
-
claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc,sha256=-L-n4xvi1eHY48MdZ-7v249UaNfkuiIwfwxdPgxwd80,16730
|
|
353
|
-
claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc,sha256=ZjcNfNY5Ht6FhalPeh7M7OzMffcey5iF4AVjDDg9kak,10694
|
|
354
346
|
claude_mpm/hooks/claude_hooks/services/__init__.py,sha256=OIYOKsUNw1BHYawOCp-KFK5kmQKuj92cCqCEPO0nwo0,585
|
|
355
347
|
claude_mpm/hooks/claude_hooks/services/connection_manager.py,sha256=6MhoPiSQSkG5Xsb9KjPk_eu60h6-v5uNXjn6ry255aA,10452
|
|
356
|
-
claude_mpm/hooks/claude_hooks/services/connection_manager_http.py,sha256=
|
|
348
|
+
claude_mpm/hooks/claude_hooks/services/connection_manager_http.py,sha256=7YKEsD45us5SNnj-jpSyFBYbU0KrZ8FWoIdZDUeU2gI,7795
|
|
357
349
|
claude_mpm/hooks/claude_hooks/services/duplicate_detector.py,sha256=Fh9LmEMsVmQM9t0U1v2l_fuBwvNpVkl_0EF8Wu5KLHQ,3882
|
|
358
350
|
claude_mpm/hooks/claude_hooks/services/state_manager.py,sha256=QB0JPJQThTVg0TGRO3Dc_3y3bac-hkulgMqqzo_71ng,11189
|
|
359
351
|
claude_mpm/hooks/claude_hooks/services/subagent_processor.py,sha256=nJw1ERCMxq23ioZ5DKwprmwO0fuvuqpdFHJ03XaMiDo,16052
|
|
360
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc,sha256=xBfLBSqnpcKfcQBWfh7xUm454g1lq1LvbO7SxGvcOPc,644
|
|
361
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc,sha256=Q40QpUbg9q_QHgv8kuYdQmRVjqcjewzYUC5BoaHinFo,10152
|
|
362
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc,sha256=bvZ_QcuI0j125Ebv8RzeWUh1BkuRTUfufGi0NV7HjuY,12359
|
|
363
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc,sha256=Yy_REAUhJCiFjOhxeDb4v0qyEvEbUtCmXD9PAz40dhw,5321
|
|
364
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc,sha256=TPkEc-Zi3oNS5dCXBpGbSZwg_8RQvzNzd4pVx9B3WeM,12364
|
|
365
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc,sha256=WffRFbZrgwiOypPUMgcm_LT18AtyGckgDny5IXhkogg,15554
|
|
366
352
|
claude_mpm/hooks/failure_learning/__init__.py,sha256=iJ80AKFHiT8DjIH2a72DQVJvL6nAFrizNA2yTKwZ4rw,1805
|
|
367
353
|
claude_mpm/hooks/failure_learning/failure_detection_hook.py,sha256=KENoB5N-dBm5hb0SxeIZtCvNKbmG2BKHOJSrSO-3Z_I,7500
|
|
368
354
|
claude_mpm/hooks/failure_learning/fix_detection_hook.py,sha256=XUk1bnBVLdfhQ9AMQSvGsTSeFQsKsVud2wbWX-Jjor8,7164
|
|
@@ -387,7 +373,9 @@ claude_mpm/services/async_session_logger.py,sha256=u8yw3EAhOEvuZfky3Snb9JOaZ9TWQ
|
|
|
387
373
|
claude_mpm/services/claude_session_logger.py,sha256=c2SPLhAq0JaUIyCmg6RsylZ2upaaqlb88ETneuYo8O0,11162
|
|
388
374
|
claude_mpm/services/command_deployment_service.py,sha256=GgSxRehQY-PR-yeztz9WP8w6cT5_8NO9bXfn0aTN1Lc,16685
|
|
389
375
|
claude_mpm/services/command_handler_service.py,sha256=8iru6eRdQloXrGiE75E1zoUbD_Ajldu3sw17Yx772Lw,7280
|
|
376
|
+
claude_mpm/services/delegation_detector.py,sha256=ZpElqjhTbuEeeTjTMUsl-G1lHMJ9m1g-6orM3t7wNfM,6168
|
|
390
377
|
claude_mpm/services/event_aggregator.py,sha256=V_5Wln1RzozLMDZawIPl5gSjIN5KHniNPaaSP11Lihc,20251
|
|
378
|
+
claude_mpm/services/event_log.py,sha256=B5nSpAUOYEOTuP1V-rCdX3rONKwUejtR19aJKIzwTKQ,9661
|
|
391
379
|
claude_mpm/services/exceptions.py,sha256=5lVZETr_6-xk0ItH7BTfYUiX5RlckS1e8ah_UalYG9c,26475
|
|
392
380
|
claude_mpm/services/hook_installer_service.py,sha256=x3H3bFVlmhK4Ue1K279f44lwMEw3W1p3zoETGfjIH_w,19708
|
|
393
381
|
claude_mpm/services/hook_service.py,sha256=I6JILbackBsdvrDNQ9TeGSB7XNqozNRP26T4E9_ROtU,15693
|
|
@@ -995,10 +983,10 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
|
|
|
995
983
|
claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
|
|
996
984
|
claude_mpm/validation/agent_validator.py,sha256=GprtAvu80VyMXcKGsK_VhYiXWA6BjKHv7O6HKx0AB9w,20917
|
|
997
985
|
claude_mpm/validation/frontmatter_validator.py,sha256=YpJlYNNYcV8u6hIOi3_jaRsDnzhbcQpjCBE6eyBKaFY,7076
|
|
998
|
-
claude_mpm-5.4.
|
|
999
|
-
claude_mpm-5.4.
|
|
1000
|
-
claude_mpm-5.4.
|
|
1001
|
-
claude_mpm-5.4.
|
|
1002
|
-
claude_mpm-5.4.
|
|
1003
|
-
claude_mpm-5.4.
|
|
1004
|
-
claude_mpm-5.4.
|
|
986
|
+
claude_mpm-5.4.97.dist-info/licenses/LICENSE,sha256=ca3y_Rk4aPrbF6f62z8Ht5MJM9OAvbGlHvEDcj9vUQ4,3867
|
|
987
|
+
claude_mpm-5.4.97.dist-info/licenses/LICENSE-FAQ.md,sha256=TxfEkXVCK98RzDOer09puc7JVCP_q_bN4dHtZKHCMcM,5104
|
|
988
|
+
claude_mpm-5.4.97.dist-info/METADATA,sha256=hlWS-oaVXxxH2ac2RGflbYhcb3ohULWQYotGwtsqTSc,14349
|
|
989
|
+
claude_mpm-5.4.97.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
990
|
+
claude_mpm-5.4.97.dist-info/entry_points.txt,sha256=n-Uk4vwHPpuvu-g_I7-GHORzTnN_m6iyOsoLveKKD0E,228
|
|
991
|
+
claude_mpm-5.4.97.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
|
|
992
|
+
claude_mpm-5.4.97.dist-info/RECORD,,
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|