claude-mpm 5.0.2__py3-none-any.whl → 5.1.9__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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
- claude_mpm/agents/PM_INSTRUCTIONS.md +1176 -909
- claude_mpm/agents/base_agent_loader.py +10 -35
- claude_mpm/agents/frontmatter_validator.py +68 -0
- claude_mpm/agents/templates/circuit-breakers.md +293 -44
- claude_mpm/cli/__init__.py +0 -1
- claude_mpm/cli/commands/__init__.py +2 -0
- claude_mpm/cli/commands/agent_state_manager.py +64 -11
- claude_mpm/cli/commands/agents.py +446 -25
- claude_mpm/cli/commands/auto_configure.py +535 -233
- claude_mpm/cli/commands/configure.py +545 -89
- claude_mpm/cli/commands/postmortem.py +401 -0
- claude_mpm/cli/commands/run.py +1 -39
- claude_mpm/cli/commands/skills.py +322 -19
- claude_mpm/cli/interactive/agent_wizard.py +302 -195
- claude_mpm/cli/parsers/agents_parser.py +137 -0
- claude_mpm/cli/parsers/auto_configure_parser.py +13 -0
- claude_mpm/cli/parsers/base_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +7 -0
- claude_mpm/cli/startup.py +73 -32
- claude_mpm/commands/mpm-agents-auto-configure.md +2 -2
- claude_mpm/commands/mpm-agents-list.md +2 -2
- claude_mpm/commands/mpm-config-view.md +2 -2
- claude_mpm/commands/mpm-help.md +3 -0
- claude_mpm/commands/mpm-postmortem.md +123 -0
- claude_mpm/commands/mpm-session-resume.md +2 -2
- claude_mpm/commands/mpm-ticket-organize.md +2 -2
- claude_mpm/commands/mpm-ticket-view.md +2 -2
- claude_mpm/config/agent_presets.py +312 -82
- claude_mpm/config/skill_presets.py +392 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +2 -25
- claude_mpm/core/framework/loaders/file_loader.py +54 -101
- claude_mpm/core/interactive_session.py +19 -5
- claude_mpm/core/oneshot_session.py +16 -4
- claude_mpm/core/output_style_manager.py +173 -43
- claude_mpm/core/protocols/__init__.py +23 -0
- claude_mpm/core/protocols/runner_protocol.py +103 -0
- claude_mpm/core/protocols/session_protocol.py +131 -0
- claude_mpm/core/shared/singleton_manager.py +11 -4
- claude_mpm/core/system_context.py +38 -0
- claude_mpm/core/unified_agent_registry.py +129 -1
- claude_mpm/core/unified_config.py +22 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +12 -1
- claude_mpm/models/agent_definition.py +7 -0
- claude_mpm/services/agents/cache_git_manager.py +621 -0
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +110 -3
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +195 -1
- claude_mpm/services/agents/sources/git_source_sync_service.py +37 -5
- claude_mpm/services/analysis/__init__.py +25 -0
- claude_mpm/services/analysis/postmortem_reporter.py +474 -0
- claude_mpm/services/analysis/postmortem_service.py +765 -0
- claude_mpm/services/command_deployment_service.py +108 -5
- claude_mpm/services/core/base.py +7 -2
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
- claude_mpm/services/git/git_operations_service.py +8 -8
- claude_mpm/services/mcp_config_manager.py +75 -145
- claude_mpm/services/mcp_gateway/core/process_pool.py +22 -16
- claude_mpm/services/mcp_service_verifier.py +6 -3
- claude_mpm/services/monitor/daemon.py +28 -8
- claude_mpm/services/monitor/daemon_manager.py +96 -19
- claude_mpm/services/project/project_organizer.py +4 -0
- claude_mpm/services/runner_configuration_service.py +16 -3
- claude_mpm/services/session_management_service.py +16 -4
- claude_mpm/utils/agent_filters.py +288 -0
- claude_mpm/utils/gitignore.py +3 -0
- claude_mpm/utils/migration.py +372 -0
- claude_mpm/utils/progress.py +5 -1
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/METADATA +69 -8
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/RECORD +76 -62
- /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/WHEEL +0 -0
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.0.2.dist-info → claude_mpm-5.1.9.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
"""Migration utilities for transitioning to new directory structure.
|
|
2
|
+
|
|
3
|
+
WHY: Phase 3 of 1M-486 requires migrating from old single-tier deployment
|
|
4
|
+
(~/.claude/agents/, ~/.claude/skills/) to new two-phase architecture:
|
|
5
|
+
- Cache: ~/.claude-mpm/cache/remote-agents/, ~/.claude-mpm/cache/skills/
|
|
6
|
+
- Deployment: .claude-mpm/agents/, .claude-mpm/skills/
|
|
7
|
+
|
|
8
|
+
DESIGN DECISIONS:
|
|
9
|
+
- Optional migration: Users can continue using old paths (fallback support)
|
|
10
|
+
- User confirmation: Prevents accidental data movement
|
|
11
|
+
- Non-destructive: Creates copies, doesn't delete originals immediately
|
|
12
|
+
- Deprecation warnings: Guides users toward new structure
|
|
13
|
+
|
|
14
|
+
MIGRATION PATH:
|
|
15
|
+
1. Detect old locations (if they exist)
|
|
16
|
+
2. Prompt user for confirmation
|
|
17
|
+
3. Copy to new cache location (not deployment, as that's project-specific)
|
|
18
|
+
4. Show deprecation warning with cleanup instructions
|
|
19
|
+
5. Provide fallback support for unmigrated systems
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import logging
|
|
23
|
+
import shutil
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Dict, Optional
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MigrationUtility:
|
|
31
|
+
"""Handles migration from old to new directory structure.
|
|
32
|
+
|
|
33
|
+
Trade-offs:
|
|
34
|
+
- Safety: Non-destructive copies vs. automatic moves
|
|
35
|
+
- User experience: Manual confirmation vs. automatic migration
|
|
36
|
+
- Compatibility: Fallback support adds complexity but ensures smooth transition
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self):
|
|
40
|
+
"""Initialize migration utility with old and new paths."""
|
|
41
|
+
self.old_agent_dir = Path.home() / ".claude" / "agents"
|
|
42
|
+
self.old_skill_dir = Path.home() / ".claude" / "skills"
|
|
43
|
+
|
|
44
|
+
self.new_agent_cache = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
|
|
45
|
+
self.new_skill_cache = Path.home() / ".claude-mpm" / "cache" / "skills"
|
|
46
|
+
|
|
47
|
+
def detect_old_locations(self) -> Dict[str, bool]:
|
|
48
|
+
"""Detect if old directory locations exist and contain files.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Dictionary with 'agents' and 'skills' keys indicating presence
|
|
52
|
+
"""
|
|
53
|
+
results = {
|
|
54
|
+
"agents_exists": False,
|
|
55
|
+
"agents_count": 0,
|
|
56
|
+
"skills_exists": False,
|
|
57
|
+
"skills_count": 0,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Check agents
|
|
61
|
+
if self.old_agent_dir.exists():
|
|
62
|
+
agent_files = list(self.old_agent_dir.glob("*.md")) + list(
|
|
63
|
+
self.old_agent_dir.glob("*.json")
|
|
64
|
+
)
|
|
65
|
+
results["agents_exists"] = len(agent_files) > 0
|
|
66
|
+
results["agents_count"] = len(agent_files)
|
|
67
|
+
|
|
68
|
+
# Check skills
|
|
69
|
+
if self.old_skill_dir.exists():
|
|
70
|
+
skill_dirs = [
|
|
71
|
+
d
|
|
72
|
+
for d in self.old_skill_dir.iterdir()
|
|
73
|
+
if d.is_dir() and (d / "SKILL.md").exists()
|
|
74
|
+
]
|
|
75
|
+
results["skills_exists"] = len(skill_dirs) > 0
|
|
76
|
+
results["skills_count"] = len(skill_dirs)
|
|
77
|
+
|
|
78
|
+
return results
|
|
79
|
+
|
|
80
|
+
def migrate_agents(
|
|
81
|
+
self, dry_run: bool = False, auto_confirm: bool = False
|
|
82
|
+
) -> Dict[str, any]:
|
|
83
|
+
"""Migrate agents from ~/.claude/agents/ to ~/.claude-mpm/cache/remote-agents/.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
dry_run: Preview migration without making changes
|
|
87
|
+
auto_confirm: Skip confirmation prompt (use with caution)
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Dictionary with migration results:
|
|
91
|
+
{
|
|
92
|
+
"migrated_count": 5,
|
|
93
|
+
"migrated_files": ["engineer.md", ...],
|
|
94
|
+
"skipped_count": 2,
|
|
95
|
+
"errors": []
|
|
96
|
+
}
|
|
97
|
+
"""
|
|
98
|
+
if not self.old_agent_dir.exists():
|
|
99
|
+
return {
|
|
100
|
+
"migrated_count": 0,
|
|
101
|
+
"migrated_files": [],
|
|
102
|
+
"skipped_count": 0,
|
|
103
|
+
"errors": [],
|
|
104
|
+
"message": "No old agent directory found",
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# Find agent files
|
|
108
|
+
agent_files = list(self.old_agent_dir.glob("*.md")) + list(
|
|
109
|
+
self.old_agent_dir.glob("*.json")
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if not agent_files:
|
|
113
|
+
return {
|
|
114
|
+
"migrated_count": 0,
|
|
115
|
+
"migrated_files": [],
|
|
116
|
+
"skipped_count": 0,
|
|
117
|
+
"errors": [],
|
|
118
|
+
"message": "No agent files found in old directory",
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# Dry run mode
|
|
122
|
+
if dry_run:
|
|
123
|
+
return {
|
|
124
|
+
"migrated_count": len(agent_files),
|
|
125
|
+
"migrated_files": [f.name for f in agent_files],
|
|
126
|
+
"skipped_count": 0,
|
|
127
|
+
"errors": [],
|
|
128
|
+
"dry_run": True,
|
|
129
|
+
"message": f"Would migrate {len(agent_files)} agent files",
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
# Confirmation prompt (unless auto_confirm)
|
|
133
|
+
if not auto_confirm:
|
|
134
|
+
logger.info(
|
|
135
|
+
f"Migration will copy {len(agent_files)} agents from:\n"
|
|
136
|
+
f" {self.old_agent_dir}\n"
|
|
137
|
+
f" → {self.new_agent_cache}"
|
|
138
|
+
)
|
|
139
|
+
# In CLI context, this would show interactive prompt
|
|
140
|
+
# For now, we assume confirmation through function parameter
|
|
141
|
+
|
|
142
|
+
# Create cache directory
|
|
143
|
+
try:
|
|
144
|
+
self.new_agent_cache.mkdir(parents=True, exist_ok=True)
|
|
145
|
+
except PermissionError as e:
|
|
146
|
+
return {
|
|
147
|
+
"migrated_count": 0,
|
|
148
|
+
"migrated_files": [],
|
|
149
|
+
"skipped_count": 0,
|
|
150
|
+
"errors": [f"Permission denied creating cache directory: {e}"],
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# Copy files
|
|
154
|
+
results = {
|
|
155
|
+
"migrated_count": 0,
|
|
156
|
+
"migrated_files": [],
|
|
157
|
+
"skipped_count": 0,
|
|
158
|
+
"errors": [],
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
for agent_file in agent_files:
|
|
162
|
+
target_file = self.new_agent_cache / agent_file.name
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
# Skip if already exists and is identical
|
|
166
|
+
if target_file.exists():
|
|
167
|
+
if self._files_identical(agent_file, target_file):
|
|
168
|
+
results["skipped_count"] += 1
|
|
169
|
+
logger.debug(f"Skipped (identical): {agent_file.name}")
|
|
170
|
+
continue
|
|
171
|
+
|
|
172
|
+
# Copy to cache
|
|
173
|
+
shutil.copy2(agent_file, target_file)
|
|
174
|
+
results["migrated_count"] += 1
|
|
175
|
+
results["migrated_files"].append(agent_file.name)
|
|
176
|
+
logger.info(f"Migrated: {agent_file.name}")
|
|
177
|
+
|
|
178
|
+
except Exception as e:
|
|
179
|
+
error_msg = f"Failed to migrate {agent_file.name}: {e}"
|
|
180
|
+
results["errors"].append(error_msg)
|
|
181
|
+
logger.error(error_msg)
|
|
182
|
+
|
|
183
|
+
results["message"] = (
|
|
184
|
+
f"Migrated {results['migrated_count']} agents to cache. "
|
|
185
|
+
f"Old directory: {self.old_agent_dir}"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
return results
|
|
189
|
+
|
|
190
|
+
def migrate_skills(
|
|
191
|
+
self, dry_run: bool = False, auto_confirm: bool = False
|
|
192
|
+
) -> Dict[str, any]:
|
|
193
|
+
"""Migrate skills from ~/.claude/skills/ to ~/.claude-mpm/cache/skills/.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
dry_run: Preview migration without making changes
|
|
197
|
+
auto_confirm: Skip confirmation prompt
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Dictionary with migration results
|
|
201
|
+
"""
|
|
202
|
+
if not self.old_skill_dir.exists():
|
|
203
|
+
return {
|
|
204
|
+
"migrated_count": 0,
|
|
205
|
+
"migrated_skills": [],
|
|
206
|
+
"skipped_count": 0,
|
|
207
|
+
"errors": [],
|
|
208
|
+
"message": "No old skill directory found",
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
# Find skill directories
|
|
212
|
+
skill_dirs = [
|
|
213
|
+
d
|
|
214
|
+
for d in self.old_skill_dir.iterdir()
|
|
215
|
+
if d.is_dir() and (d / "SKILL.md").exists()
|
|
216
|
+
]
|
|
217
|
+
|
|
218
|
+
if not skill_dirs:
|
|
219
|
+
return {
|
|
220
|
+
"migrated_count": 0,
|
|
221
|
+
"migrated_skills": [],
|
|
222
|
+
"skipped_count": 0,
|
|
223
|
+
"errors": [],
|
|
224
|
+
"message": "No skill directories found",
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
# Dry run mode
|
|
228
|
+
if dry_run:
|
|
229
|
+
return {
|
|
230
|
+
"migrated_count": len(skill_dirs),
|
|
231
|
+
"migrated_skills": [d.name for d in skill_dirs],
|
|
232
|
+
"skipped_count": 0,
|
|
233
|
+
"errors": [],
|
|
234
|
+
"dry_run": True,
|
|
235
|
+
"message": f"Would migrate {len(skill_dirs)} skill directories",
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
# Create cache directory
|
|
239
|
+
try:
|
|
240
|
+
self.new_skill_cache.mkdir(parents=True, exist_ok=True)
|
|
241
|
+
except PermissionError as e:
|
|
242
|
+
return {
|
|
243
|
+
"migrated_count": 0,
|
|
244
|
+
"migrated_skills": [],
|
|
245
|
+
"skipped_count": 0,
|
|
246
|
+
"errors": [f"Permission denied creating cache directory: {e}"],
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
# Copy skill directories
|
|
250
|
+
results = {
|
|
251
|
+
"migrated_count": 0,
|
|
252
|
+
"migrated_skills": [],
|
|
253
|
+
"skipped_count": 0,
|
|
254
|
+
"errors": [],
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
for skill_dir in skill_dirs:
|
|
258
|
+
target_dir = self.new_skill_cache / skill_dir.name
|
|
259
|
+
|
|
260
|
+
try:
|
|
261
|
+
# Skip if already exists
|
|
262
|
+
if target_dir.exists():
|
|
263
|
+
results["skipped_count"] += 1
|
|
264
|
+
logger.debug(f"Skipped (exists): {skill_dir.name}")
|
|
265
|
+
continue
|
|
266
|
+
|
|
267
|
+
# Copy entire skill directory
|
|
268
|
+
shutil.copytree(skill_dir, target_dir)
|
|
269
|
+
results["migrated_count"] += 1
|
|
270
|
+
results["migrated_skills"].append(skill_dir.name)
|
|
271
|
+
logger.info(f"Migrated: {skill_dir.name}")
|
|
272
|
+
|
|
273
|
+
except Exception as e:
|
|
274
|
+
error_msg = f"Failed to migrate {skill_dir.name}: {e}"
|
|
275
|
+
results["errors"].append(error_msg)
|
|
276
|
+
logger.error(error_msg)
|
|
277
|
+
|
|
278
|
+
results["message"] = (
|
|
279
|
+
f"Migrated {results['migrated_count']} skills to cache. "
|
|
280
|
+
f"Old directory: {self.old_skill_dir}"
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
return results
|
|
284
|
+
|
|
285
|
+
def migrate_all(
|
|
286
|
+
self, dry_run: bool = False, auto_confirm: bool = False
|
|
287
|
+
) -> Dict[str, any]:
|
|
288
|
+
"""Migrate both agents and skills.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
dry_run: Preview migration without making changes
|
|
292
|
+
auto_confirm: Skip confirmation prompts
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
Combined migration results for agents and skills
|
|
296
|
+
"""
|
|
297
|
+
agent_results = self.migrate_agents(dry_run=dry_run, auto_confirm=auto_confirm)
|
|
298
|
+
skill_results = self.migrate_skills(dry_run=dry_run, auto_confirm=auto_confirm)
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
"agents": agent_results,
|
|
302
|
+
"skills": skill_results,
|
|
303
|
+
"total_migrated": agent_results["migrated_count"]
|
|
304
|
+
+ skill_results["migrated_count"],
|
|
305
|
+
"dry_run": dry_run,
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
def show_deprecation_warning(self) -> str:
|
|
309
|
+
"""Generate deprecation warning message for old paths.
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
Formatted warning message for display to user
|
|
313
|
+
"""
|
|
314
|
+
detection = self.detect_old_locations()
|
|
315
|
+
|
|
316
|
+
if not detection["agents_exists"] and not detection["skills_exists"]:
|
|
317
|
+
return ""
|
|
318
|
+
|
|
319
|
+
warning = "\n⚠️ DEPRECATION WARNING ⚠️\n\n"
|
|
320
|
+
warning += "Old directory structure detected:\n\n"
|
|
321
|
+
|
|
322
|
+
if detection["agents_exists"]:
|
|
323
|
+
warning += f" • {self.old_agent_dir}\n"
|
|
324
|
+
warning += f" ({detection['agents_count']} agent files)\n"
|
|
325
|
+
|
|
326
|
+
if detection["skills_exists"]:
|
|
327
|
+
warning += f" • {self.old_skill_dir}\n"
|
|
328
|
+
warning += f" ({detection['skills_count']} skill directories)\n"
|
|
329
|
+
|
|
330
|
+
warning += "\nThe deployment architecture has changed:\n"
|
|
331
|
+
warning += " OLD: ~/.claude/agents/ (single-tier, global)\n"
|
|
332
|
+
warning += " NEW: ~/.claude-mpm/cache/remote-agents/ → .claude-mpm/agents/ (two-phase, per-project)\n\n"
|
|
333
|
+
|
|
334
|
+
warning += "To migrate:\n"
|
|
335
|
+
warning += " claude-mpm migrate\n\n"
|
|
336
|
+
|
|
337
|
+
warning += "Or to continue using old paths (not recommended):\n"
|
|
338
|
+
warning += " # Fallback support is enabled automatically\n\n"
|
|
339
|
+
|
|
340
|
+
return warning
|
|
341
|
+
|
|
342
|
+
def _files_identical(self, file1: Path, file2: Path) -> bool:
|
|
343
|
+
"""Check if two files have identical content.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
file1: First file path
|
|
347
|
+
file2: Second file path
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
True if files are byte-for-byte identical
|
|
351
|
+
"""
|
|
352
|
+
try:
|
|
353
|
+
return file1.read_bytes() == file2.read_bytes()
|
|
354
|
+
except Exception:
|
|
355
|
+
return False
|
|
356
|
+
|
|
357
|
+
def get_fallback_paths(self) -> Dict[str, Optional[Path]]:
|
|
358
|
+
"""Get fallback paths for old directory structure.
|
|
359
|
+
|
|
360
|
+
Used when migration hasn't been performed and old paths still exist.
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
Dictionary with fallback paths:
|
|
364
|
+
{
|
|
365
|
+
"agent_dir": Path to old agents (or None),
|
|
366
|
+
"skill_dir": Path to old skills (or None)
|
|
367
|
+
}
|
|
368
|
+
"""
|
|
369
|
+
return {
|
|
370
|
+
"agent_dir": self.old_agent_dir if self.old_agent_dir.exists() else None,
|
|
371
|
+
"skill_dir": self.old_skill_dir if self.old_skill_dir.exists() else None,
|
|
372
|
+
}
|
claude_mpm/utils/progress.py
CHANGED
|
@@ -270,8 +270,12 @@ class ProgressBar:
|
|
|
270
270
|
truncate_at = max_width - 3 # Leave room for "..."
|
|
271
271
|
output = output[:truncate_at] + "..."
|
|
272
272
|
|
|
273
|
+
# Pad output to terminal width to clear previous longer text
|
|
274
|
+
# This prevents text artifacts when current message is shorter than previous
|
|
275
|
+
padded_output = output.ljust(max_width)
|
|
276
|
+
|
|
273
277
|
# Write to stdout with carriage return (overwrite current line)
|
|
274
|
-
sys.stdout.write(f"\r{
|
|
278
|
+
sys.stdout.write(f"\r{padded_output}")
|
|
275
279
|
sys.stdout.flush()
|
|
276
280
|
|
|
277
281
|
def finish(self, message: str = "Complete") -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-mpm
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.1.9
|
|
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
|
|
@@ -13,12 +13,10 @@ Keywords: claude,orchestration,multi-agent,ticket-management
|
|
|
13
13
|
Classifier: Development Status :: 3 - Alpha
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
19
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
-
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Requires-Python: >=3.11
|
|
22
20
|
Description-Content-Type: text/markdown
|
|
23
21
|
License-File: LICENSE
|
|
24
22
|
Requires-Dist: ai-trackdown-pytools>=1.4.0
|
|
@@ -48,7 +46,6 @@ Requires-Dist: pydantic-settings>=2.0.0
|
|
|
48
46
|
Requires-Dist: rich>=13.0.0
|
|
49
47
|
Requires-Dist: questionary>=2.0.0
|
|
50
48
|
Requires-Dist: pyee>=13.0.0
|
|
51
|
-
Requires-Dist: importlib-resources>=5.0; python_version < "3.9"
|
|
52
49
|
Requires-Dist: pathspec>=0.11.0
|
|
53
50
|
Requires-Dist: kuzu-memory>=1.1.5
|
|
54
51
|
Provides-Extra: mcp
|
|
@@ -66,6 +63,12 @@ Requires-Dist: pre-commit; extra == "dev"
|
|
|
66
63
|
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
67
64
|
Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
|
|
68
65
|
Requires-Dist: types-requests>=2.25.0; extra == "dev"
|
|
66
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
67
|
+
Provides-Extra: eval
|
|
68
|
+
Requires-Dist: deepeval>=1.0.0; extra == "eval"
|
|
69
|
+
Requires-Dist: pytest>=7.4.0; extra == "eval"
|
|
70
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "eval"
|
|
71
|
+
Requires-Dist: pytest-timeout>=2.1.0; extra == "eval"
|
|
69
72
|
Provides-Extra: docs
|
|
70
73
|
Requires-Dist: sphinx>=7.2.0; extra == "docs"
|
|
71
74
|
Requires-Dist: sphinx-rtd-theme>=1.3.0; extra == "docs"
|
|
@@ -121,7 +124,6 @@ Requires-Dist: prometheus-client>=0.19.0; extra == "agents"
|
|
|
121
124
|
Requires-Dist: psycopg2-binary>=2.9.0; extra == "agents"
|
|
122
125
|
Requires-Dist: pyarrow>=14.0.0; extra == "agents"
|
|
123
126
|
Requires-Dist: pydantic>=2.6.0; extra == "agents"
|
|
124
|
-
Requires-Dist: pydoc-markdown>=4.8.0; extra == "agents"
|
|
125
127
|
Requires-Dist: pydriller>=2.5.0; extra == "agents"
|
|
126
128
|
Requires-Dist: pygments>=2.17.0; extra == "agents"
|
|
127
129
|
Requires-Dist: pyjwt>=2.8.0; extra == "agents"
|
|
@@ -302,7 +304,7 @@ See [docs/features/hierarchical-base-agents.md](docs/features/hierarchical-base-
|
|
|
302
304
|
|
|
303
305
|
**Before installing Claude MPM**, ensure you have:
|
|
304
306
|
|
|
305
|
-
1. **Python 3.
|
|
307
|
+
1. **Python 3.11+** (required for kuzu-memory dependency)
|
|
306
308
|
2. **Claude Code CLI v1.0.92+** (required!)
|
|
307
309
|
|
|
308
310
|
```bash
|
|
@@ -439,6 +441,65 @@ claude-mpm verify
|
|
|
439
441
|
|
|
440
442
|
**That's it!** See [docs/user/getting-started.md](docs/user/getting-started.md) for immediate usage.
|
|
441
443
|
|
|
444
|
+
## Cache Management
|
|
445
|
+
|
|
446
|
+
Claude MPM maintains a local cache of agent templates at `~/.claude-mpm/cache/remote-agents/`.
|
|
447
|
+
|
|
448
|
+
### Cache Structure
|
|
449
|
+
|
|
450
|
+
```
|
|
451
|
+
~/.claude-mpm/cache/remote-agents/
|
|
452
|
+
└── bobmatnyc/
|
|
453
|
+
└── claude-mpm-agents/
|
|
454
|
+
├── .git/ # Git repository
|
|
455
|
+
├── agents/ # 45+ agent templates
|
|
456
|
+
└── docs/
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Git Workflow (Optional)
|
|
460
|
+
|
|
461
|
+
If your cache is a git repository, you can manage agents with git operations:
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
# Check cache status
|
|
465
|
+
claude-mpm agents cache-status
|
|
466
|
+
|
|
467
|
+
# Pull latest agents
|
|
468
|
+
claude-mpm agents cache-pull
|
|
469
|
+
|
|
470
|
+
# Commit local changes
|
|
471
|
+
claude-mpm agents cache-commit --message "feat: update agents"
|
|
472
|
+
|
|
473
|
+
# Push changes
|
|
474
|
+
claude-mpm agents cache-push
|
|
475
|
+
|
|
476
|
+
# Full sync workflow
|
|
477
|
+
claude-mpm agents cache-sync
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
**Or use Makefile targets:**
|
|
481
|
+
|
|
482
|
+
```bash
|
|
483
|
+
make agents-cache-status # Show git status
|
|
484
|
+
make agents-cache-pull # Pull latest
|
|
485
|
+
make agents-cache-sync # Full sync (pull + commit + push)
|
|
486
|
+
make deploy-agents # Deploy with auto-pull
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### HTTP Sync Fallback
|
|
490
|
+
|
|
491
|
+
If cache is not a git repository, Claude MPM automatically falls back to HTTP sync with GitHub API.
|
|
492
|
+
|
|
493
|
+
### Migration from Legacy Cache
|
|
494
|
+
|
|
495
|
+
If you have an old `cache/agents/` directory, run the migration script:
|
|
496
|
+
|
|
497
|
+
```bash
|
|
498
|
+
python scripts/migrate_cache_to_remote_agents.py
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
**See also:** [docs/CACHE_MANAGEMENT.md](docs/CACHE_MANAGEMENT.md) for comprehensive cache management guide.
|
|
502
|
+
|
|
442
503
|
## Quick Usage
|
|
443
504
|
|
|
444
505
|
```bash
|