claude-mpm 5.0.2__py3-none-any.whl → 5.4.3__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.

Files changed (184) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
  3. claude_mpm/agents/PM_INSTRUCTIONS.md +1218 -905
  4. claude_mpm/agents/agent_loader.py +10 -17
  5. claude_mpm/agents/base_agent_loader.py +10 -35
  6. claude_mpm/agents/frontmatter_validator.py +68 -0
  7. claude_mpm/agents/templates/circuit-breakers.md +431 -45
  8. claude_mpm/cli/__init__.py +0 -1
  9. claude_mpm/cli/commands/__init__.py +2 -0
  10. claude_mpm/cli/commands/agent_state_manager.py +67 -23
  11. claude_mpm/cli/commands/agents.py +446 -25
  12. claude_mpm/cli/commands/auto_configure.py +535 -233
  13. claude_mpm/cli/commands/configure.py +1500 -147
  14. claude_mpm/cli/commands/configure_agent_display.py +13 -6
  15. claude_mpm/cli/commands/mpm_init/core.py +158 -1
  16. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  17. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  18. claude_mpm/cli/commands/postmortem.py +401 -0
  19. claude_mpm/cli/commands/run.py +1 -39
  20. claude_mpm/cli/commands/skills.py +322 -19
  21. claude_mpm/cli/commands/summarize.py +413 -0
  22. claude_mpm/cli/executor.py +8 -0
  23. claude_mpm/cli/interactive/agent_wizard.py +302 -195
  24. claude_mpm/cli/parsers/agents_parser.py +137 -0
  25. claude_mpm/cli/parsers/auto_configure_parser.py +13 -0
  26. claude_mpm/cli/parsers/base_parser.py +9 -0
  27. claude_mpm/cli/parsers/skills_parser.py +7 -0
  28. claude_mpm/cli/startup.py +133 -85
  29. claude_mpm/commands/mpm-agents-auto-configure.md +2 -2
  30. claude_mpm/commands/mpm-agents-list.md +2 -2
  31. claude_mpm/commands/mpm-config-view.md +2 -2
  32. claude_mpm/commands/mpm-help.md +3 -0
  33. claude_mpm/commands/{mpm-ticket-organize.md → mpm-organize.md} +4 -5
  34. claude_mpm/commands/mpm-postmortem.md +123 -0
  35. claude_mpm/commands/mpm-session-resume.md +2 -2
  36. claude_mpm/commands/mpm-ticket-view.md +2 -2
  37. claude_mpm/config/agent_presets.py +312 -82
  38. claude_mpm/config/agent_sources.py +27 -0
  39. claude_mpm/config/skill_presets.py +392 -0
  40. claude_mpm/constants.py +1 -0
  41. claude_mpm/core/claude_runner.py +2 -25
  42. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  43. claude_mpm/core/framework/loaders/file_loader.py +54 -101
  44. claude_mpm/core/interactive_session.py +19 -5
  45. claude_mpm/core/oneshot_session.py +16 -4
  46. claude_mpm/core/output_style_manager.py +173 -43
  47. claude_mpm/core/protocols/__init__.py +23 -0
  48. claude_mpm/core/protocols/runner_protocol.py +103 -0
  49. claude_mpm/core/protocols/session_protocol.py +131 -0
  50. claude_mpm/core/shared/singleton_manager.py +11 -4
  51. claude_mpm/core/socketio_pool.py +3 -3
  52. claude_mpm/core/system_context.py +38 -0
  53. claude_mpm/core/unified_agent_registry.py +134 -16
  54. claude_mpm/core/unified_config.py +22 -0
  55. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  56. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-313.pyc +0 -0
  57. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  58. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  59. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  60. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  61. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  62. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  63. claude_mpm/hooks/claude_hooks/event_handlers.py +35 -2
  64. claude_mpm/hooks/claude_hooks/hook_handler.py +4 -0
  65. claude_mpm/hooks/claude_hooks/memory_integration.py +12 -1
  66. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  67. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  68. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  69. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  70. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  71. claude_mpm/hooks/claude_hooks/services/connection_manager.py +4 -0
  72. claude_mpm/models/agent_definition.py +7 -0
  73. claude_mpm/scripts/launch_monitor.py +93 -13
  74. claude_mpm/services/agents/agent_recommendation_service.py +279 -0
  75. claude_mpm/services/agents/cache_git_manager.py +621 -0
  76. claude_mpm/services/agents/deployment/agent_template_builder.py +3 -2
  77. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +110 -3
  78. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +518 -55
  79. claude_mpm/services/agents/git_source_manager.py +20 -0
  80. claude_mpm/services/agents/sources/git_source_sync_service.py +45 -6
  81. claude_mpm/services/agents/toolchain_detector.py +6 -5
  82. claude_mpm/services/analysis/__init__.py +35 -0
  83. claude_mpm/services/analysis/clone_detector.py +1030 -0
  84. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  85. claude_mpm/services/analysis/postmortem_service.py +765 -0
  86. claude_mpm/services/command_deployment_service.py +106 -5
  87. claude_mpm/services/core/base.py +7 -2
  88. claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
  89. claude_mpm/services/event_bus/config.py +3 -1
  90. claude_mpm/services/git/git_operations_service.py +8 -8
  91. claude_mpm/services/mcp_config_manager.py +75 -145
  92. claude_mpm/services/mcp_service_verifier.py +6 -3
  93. claude_mpm/services/monitor/daemon.py +37 -10
  94. claude_mpm/services/monitor/daemon_manager.py +134 -21
  95. claude_mpm/services/monitor/server.py +225 -19
  96. claude_mpm/services/project/project_organizer.py +4 -0
  97. claude_mpm/services/runner_configuration_service.py +16 -3
  98. claude_mpm/services/session_management_service.py +16 -4
  99. claude_mpm/services/socketio/event_normalizer.py +15 -1
  100. claude_mpm/services/socketio/server/core.py +160 -21
  101. claude_mpm/services/version_control/git_operations.py +103 -0
  102. claude_mpm/utils/agent_filters.py +261 -0
  103. claude_mpm/utils/gitignore.py +3 -0
  104. claude_mpm/utils/migration.py +372 -0
  105. claude_mpm/utils/progress.py +5 -1
  106. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/METADATA +69 -84
  107. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/RECORD +112 -153
  108. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/entry_points.txt +0 -2
  109. claude_mpm/dashboard/analysis_runner.py +0 -455
  110. claude_mpm/dashboard/index.html +0 -13
  111. claude_mpm/dashboard/open_dashboard.py +0 -66
  112. claude_mpm/dashboard/static/css/activity.css +0 -1958
  113. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  114. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  115. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  116. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  117. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  118. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  119. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  120. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  121. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  122. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  123. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  124. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  125. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  126. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  127. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  128. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  129. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  130. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  131. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  132. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  133. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  134. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  135. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  136. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  137. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  138. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  139. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  140. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  141. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  142. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  143. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  144. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  145. claude_mpm/dashboard/templates/code_simple.html +0 -153
  146. claude_mpm/dashboard/templates/index.html +0 -606
  147. claude_mpm/dashboard/test_dashboard.html +0 -372
  148. claude_mpm/scripts/mcp_server.py +0 -75
  149. claude_mpm/scripts/mcp_wrapper.py +0 -39
  150. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  151. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  152. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  153. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  154. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  155. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  156. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  157. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  158. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  159. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  160. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -971
  161. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  162. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  163. claude_mpm/services/mcp_gateway/main.py +0 -589
  164. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  165. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  166. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  167. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  168. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  169. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  170. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  171. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  172. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  173. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  174. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  175. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  176. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  177. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  178. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  179. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  180. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  181. /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
  182. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/WHEEL +0 -0
  183. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/licenses/LICENSE +0 -0
  184. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.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
+ }
@@ -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{output}")
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.0.2
3
+ Version: 5.4.3
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
- Requires-Python: >=3.8
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"
@@ -77,81 +80,6 @@ Requires-Dist: aiohttp-cors<0.8.0,>=0.7.0; extra == "monitor"
77
80
  Requires-Dist: python-engineio>=4.8.0; extra == "monitor"
78
81
  Requires-Dist: aiofiles>=23.0.0; extra == "monitor"
79
82
  Requires-Dist: websockets>=12.0; extra == "monitor"
80
- Provides-Extra: agents
81
- Requires-Dist: alembic>=1.13.0; extra == "agents"
82
- Requires-Dist: astroid>=3.0.0; extra == "agents"
83
- Requires-Dist: axe-selenium-python>=2.1.0; extra == "agents"
84
- Requires-Dist: bandit>=1.7.5; extra == "agents"
85
- Requires-Dist: beautifulsoup4>=4.12.0; extra == "agents"
86
- Requires-Dist: black>=24.0.0; extra == "agents"
87
- Requires-Dist: click>=8.1.0; extra == "agents"
88
- Requires-Dist: commitizen>=3.13.0; extra == "agents"
89
- Requires-Dist: coverage>=7.0.0; extra == "agents"
90
- Requires-Dist: csvkit>=1.3.0; extra == "agents"
91
- Requires-Dist: dask>=2023.12.0; extra == "agents"
92
- Requires-Dist: detect-secrets>=1.4.0; extra == "agents"
93
- Requires-Dist: diagrams>=0.23.0; extra == "agents"
94
- Requires-Dist: docstring-parser>=0.15.0; extra == "agents"
95
- Requires-Dist: faker>=20.0.0; extra == "agents"
96
- Requires-Dist: flake8>=7.0.0; extra == "agents"
97
- Requires-Dist: gitlint>=0.19.0; extra == "agents"
98
- Requires-Dist: gitpython>=3.1.40; extra == "agents"
99
- Requires-Dist: google-auth>=2.0.0; extra == "agents"
100
- Requires-Dist: google-cloud-core>=2.0.0; extra == "agents"
101
- Requires-Dist: hypothesis>=6.98.0; extra == "agents"
102
- Requires-Dist: isort>=5.13.0; extra == "agents"
103
- Requires-Dist: jinja2>=3.1.0; extra == "agents"
104
- Requires-Dist: jsonschema>=4.19.0; extra == "agents"
105
- Requires-Dist: libcst>=1.1.0; extra == "agents"
106
- Requires-Dist: lizard>=1.17.0; extra == "agents"
107
- Requires-Dist: lxml>=4.9.0; extra == "agents"
108
- Requires-Dist: mermaid-py>=0.2.0; extra == "agents"
109
- Requires-Dist: mkdocs>=1.5.0; extra == "agents"
110
- Requires-Dist: mutmut>=2.4.0; extra == "agents"
111
- Requires-Dist: mypy>=1.8.0; extra == "agents"
112
- Requires-Dist: numpy>=1.24.0; extra == "agents"
113
- Requires-Dist: openpyxl>=3.1.0; extra == "agents"
114
- Requires-Dist: pandas>=2.1.0; extra == "agents"
115
- Requires-Dist: pathlib; extra == "agents"
116
- Requires-Dist: pillow>=9.0.0; extra == "agents"
117
- Requires-Dist: playwright>=1.40.0; extra == "agents"
118
- Requires-Dist: polars>=0.19.0; extra == "agents"
119
- Requires-Dist: pre-commit>=3.5.0; extra == "agents"
120
- Requires-Dist: prometheus-client>=0.19.0; extra == "agents"
121
- Requires-Dist: psycopg2-binary>=2.9.0; extra == "agents"
122
- Requires-Dist: pyarrow>=14.0.0; extra == "agents"
123
- Requires-Dist: pydantic>=2.6.0; extra == "agents"
124
- Requires-Dist: pydoc-markdown>=4.8.0; extra == "agents"
125
- Requires-Dist: pydriller>=2.5.0; extra == "agents"
126
- Requires-Dist: pygments>=2.17.0; extra == "agents"
127
- Requires-Dist: pyjwt>=2.8.0; extra == "agents"
128
- Requires-Dist: pylint>=3.0.0; extra == "agents"
129
- Requires-Dist: pymongo>=4.5.0; extra == "agents"
130
- Requires-Dist: pymysql>=1.1.0; extra == "agents"
131
- Requires-Dist: pytest>=8.0.0; extra == "agents"
132
- Requires-Dist: pytest-asyncio>=0.23.0; extra == "agents"
133
- Requires-Dist: pytest-benchmark>=4.0.0; extra == "agents"
134
- Requires-Dist: pytest-cov>=4.1.0; extra == "agents"
135
- Requires-Dist: python-dateutil>=2.8.0; extra == "agents"
136
- Requires-Dist: pyyaml>=6.0; extra == "agents"
137
- Requires-Dist: radon>=6.0.0; extra == "agents"
138
- Requires-Dist: redis>=5.0.0; extra == "agents"
139
- Requires-Dist: requests>=2.31.0; extra == "agents"
140
- Requires-Dist: rich>=13.0.0; extra == "agents"
141
- Requires-Dist: rope>=1.11.0; extra == "agents"
142
- Requires-Dist: safety>=3.0.0; extra == "agents"
143
- Requires-Dist: semantic-version>=2.10.0; extra == "agents"
144
- Requires-Dist: semgrep>=1.45.0; extra == "agents"
145
- Requires-Dist: sphinx>=7.2.0; extra == "agents"
146
- Requires-Dist: sqlalchemy>=2.0.0; extra == "agents"
147
- Requires-Dist: sqlparse>=0.4.4; extra == "agents"
148
- Requires-Dist: tabulate>=0.9.0; extra == "agents"
149
- Requires-Dist: tree-sitter>=0.21.0; extra == "agents"
150
- Requires-Dist: vaex>=4.17.0; extra == "agents"
151
- Requires-Dist: validators>=0.20.0; extra == "agents"
152
- Requires-Dist: xlrd>=2.0.0; extra == "agents"
153
- Requires-Dist: xlsxwriter>=3.1.0; extra == "agents"
154
- Requires-Dist: xlwt>=1.3.0; extra == "agents"
155
83
  Provides-Extra: data-processing
156
84
  Requires-Dist: pandas>=2.1.0; extra == "data-processing"
157
85
  Requires-Dist: openpyxl>=3.1.0; extra == "data-processing"
@@ -172,8 +100,6 @@ Requires-Dist: pymongo>=4.5.0; extra == "data-processing"
172
100
  Requires-Dist: redis>=5.0.0; extra == "data-processing"
173
101
  Requires-Dist: beautifulsoup4>=4.12.0; extra == "data-processing"
174
102
  Requires-Dist: jsonschema>=4.19.0; extra == "data-processing"
175
- Provides-Extra: agents-load-testing
176
- Requires-Dist: locust>=2.15.0; extra == "agents-load-testing"
177
103
  Dynamic: license-file
178
104
 
179
105
  # Claude MPM - Multi-Agent Project Manager
@@ -302,7 +228,7 @@ See [docs/features/hierarchical-base-agents.md](docs/features/hierarchical-base-
302
228
 
303
229
  **Before installing Claude MPM**, ensure you have:
304
230
 
305
- 1. **Python 3.8+** (3.11+ recommended)
231
+ 1. **Python 3.11+** (required for kuzu-memory dependency)
306
232
  2. **Claude Code CLI v1.0.92+** (required!)
307
233
 
308
234
  ```bash
@@ -439,6 +365,65 @@ claude-mpm verify
439
365
 
440
366
  **That's it!** See [docs/user/getting-started.md](docs/user/getting-started.md) for immediate usage.
441
367
 
368
+ ## Cache Management
369
+
370
+ Claude MPM maintains a local cache of agent templates at `~/.claude-mpm/cache/remote-agents/`.
371
+
372
+ ### Cache Structure
373
+
374
+ ```
375
+ ~/.claude-mpm/cache/remote-agents/
376
+ └── bobmatnyc/
377
+ └── claude-mpm-agents/
378
+ ├── .git/ # Git repository
379
+ ├── agents/ # 45+ agent templates
380
+ └── docs/
381
+ ```
382
+
383
+ ### Git Workflow (Optional)
384
+
385
+ If your cache is a git repository, you can manage agents with git operations:
386
+
387
+ ```bash
388
+ # Check cache status
389
+ claude-mpm agents cache-status
390
+
391
+ # Pull latest agents
392
+ claude-mpm agents cache-pull
393
+
394
+ # Commit local changes
395
+ claude-mpm agents cache-commit --message "feat: update agents"
396
+
397
+ # Push changes
398
+ claude-mpm agents cache-push
399
+
400
+ # Full sync workflow
401
+ claude-mpm agents cache-sync
402
+ ```
403
+
404
+ **Or use Makefile targets:**
405
+
406
+ ```bash
407
+ make agents-cache-status # Show git status
408
+ make agents-cache-pull # Pull latest
409
+ make agents-cache-sync # Full sync (pull + commit + push)
410
+ make deploy-agents # Deploy with auto-pull
411
+ ```
412
+
413
+ ### HTTP Sync Fallback
414
+
415
+ If cache is not a git repository, Claude MPM automatically falls back to HTTP sync with GitHub API.
416
+
417
+ ### Migration from Legacy Cache
418
+
419
+ If you have an old `cache/agents/` directory, run the migration script:
420
+
421
+ ```bash
422
+ python scripts/migrate_cache_to_remote_agents.py
423
+ ```
424
+
425
+ **See also:** [docs/CACHE_MANAGEMENT.md](docs/CACHE_MANAGEMENT.md) for comprehensive cache management guide.
426
+
442
427
  ## Quick Usage
443
428
 
444
429
  ```bash