claude-mpm 5.1.9__py3-none-any.whl → 5.4.48__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 (248) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +4 -0
  3. claude_mpm/agents/BASE_AGENT.md +164 -0
  4. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +1 -1
  5. claude_mpm/agents/MEMORY.md +1 -1
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +843 -900
  7. claude_mpm/agents/WORKFLOW.md +5 -254
  8. claude_mpm/agents/agent_loader.py +13 -44
  9. claude_mpm/agents/base_agent.json +1 -1
  10. claude_mpm/agents/frontmatter_validator.py +2 -2
  11. claude_mpm/agents/templates/circuit-breakers.md +138 -1
  12. claude_mpm/cli/__main__.py +4 -0
  13. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  14. claude_mpm/cli/commands/agent_state_manager.py +18 -27
  15. claude_mpm/cli/commands/agents.py +9 -40
  16. claude_mpm/cli/commands/auto_configure.py +210 -25
  17. claude_mpm/cli/commands/config.py +88 -2
  18. claude_mpm/cli/commands/configure.py +1098 -159
  19. claude_mpm/cli/commands/configure_agent_display.py +25 -6
  20. claude_mpm/cli/commands/mpm_init/core.py +225 -46
  21. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  22. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  23. claude_mpm/cli/commands/postmortem.py +1 -1
  24. claude_mpm/cli/commands/profile.py +277 -0
  25. claude_mpm/cli/commands/skills.py +218 -197
  26. claude_mpm/cli/commands/summarize.py +413 -0
  27. claude_mpm/cli/executor.py +21 -3
  28. claude_mpm/cli/interactive/agent_wizard.py +2 -2
  29. claude_mpm/cli/parsers/agents_parser.py +0 -9
  30. claude_mpm/cli/parsers/auto_configure_parser.py +0 -138
  31. claude_mpm/cli/parsers/base_parser.py +12 -0
  32. claude_mpm/cli/parsers/config_parser.py +153 -83
  33. claude_mpm/cli/parsers/profile_parser.py +148 -0
  34. claude_mpm/cli/parsers/skills_parser.py +0 -5
  35. claude_mpm/cli/startup.py +876 -149
  36. claude_mpm/commands/mpm-config.md +28 -0
  37. claude_mpm/commands/mpm-doctor.md +9 -22
  38. claude_mpm/commands/mpm-help.md +5 -287
  39. claude_mpm/commands/mpm-init.md +81 -507
  40. claude_mpm/commands/mpm-monitor.md +15 -402
  41. claude_mpm/commands/mpm-organize.md +120 -0
  42. claude_mpm/commands/mpm-postmortem.md +6 -108
  43. claude_mpm/commands/mpm-session-resume.md +12 -363
  44. claude_mpm/commands/mpm-status.md +5 -69
  45. claude_mpm/commands/mpm-ticket-view.md +52 -495
  46. claude_mpm/commands/mpm-version.md +5 -107
  47. claude_mpm/config/agent_sources.py +27 -0
  48. claude_mpm/core/config.py +2 -4
  49. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  50. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  51. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  52. claude_mpm/core/framework_loader.py +4 -2
  53. claude_mpm/core/logger.py +13 -0
  54. claude_mpm/core/optimized_startup.py +59 -0
  55. claude_mpm/core/shared/config_loader.py +1 -1
  56. claude_mpm/core/socketio_pool.py +3 -3
  57. claude_mpm/core/unified_agent_registry.py +5 -15
  58. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  59. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
  60. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
  61. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
  62. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
  63. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
  64. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
  65. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
  66. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
  67. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
  68. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
  69. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
  70. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
  71. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
  72. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -0
  73. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  74. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  75. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  76. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  77. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  78. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  79. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  80. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  81. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  82. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  83. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  84. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  85. claude_mpm/hooks/claude_hooks/event_handlers.py +211 -78
  86. claude_mpm/hooks/claude_hooks/hook_handler.py +155 -1
  87. claude_mpm/hooks/claude_hooks/installer.py +33 -10
  88. claude_mpm/hooks/claude_hooks/memory_integration.py +26 -9
  89. claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
  90. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  91. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  92. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  93. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  94. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  95. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  96. claude_mpm/hooks/claude_hooks/services/connection_manager.py +30 -6
  97. claude_mpm/hooks/kuzu_memory_hook.py +5 -5
  98. claude_mpm/hooks/memory_integration_hook.py +46 -1
  99. claude_mpm/init.py +63 -19
  100. claude_mpm/models/git_repository.py +3 -3
  101. claude_mpm/scripts/claude-hook-handler.sh +58 -18
  102. claude_mpm/scripts/launch_monitor.py +93 -13
  103. claude_mpm/services/agents/agent_builder.py +3 -3
  104. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  105. claude_mpm/services/agents/agent_review_service.py +280 -0
  106. claude_mpm/services/agents/cache_git_manager.py +6 -6
  107. claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
  108. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -5
  109. claude_mpm/services/agents/deployment/agent_format_converter.py +23 -13
  110. claude_mpm/services/agents/deployment/agent_template_builder.py +32 -20
  111. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  112. claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
  113. claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
  114. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +247 -35
  115. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +392 -87
  116. claude_mpm/services/agents/git_source_manager.py +53 -4
  117. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  118. claude_mpm/services/agents/recommender.py +5 -3
  119. claude_mpm/services/agents/single_tier_deployment_service.py +2 -2
  120. claude_mpm/services/agents/sources/git_source_sync_service.py +120 -7
  121. claude_mpm/services/agents/startup_sync.py +22 -2
  122. claude_mpm/services/agents/toolchain_detector.py +10 -6
  123. claude_mpm/services/analysis/__init__.py +11 -1
  124. claude_mpm/services/analysis/clone_detector.py +1030 -0
  125. claude_mpm/services/command_deployment_service.py +81 -10
  126. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  127. claude_mpm/services/diagnostics/checks/agent_sources_check.py +1 -1
  128. claude_mpm/services/event_bus/config.py +3 -1
  129. claude_mpm/services/git/git_operations_service.py +101 -16
  130. claude_mpm/services/monitor/daemon.py +9 -2
  131. claude_mpm/services/monitor/daemon_manager.py +39 -3
  132. claude_mpm/services/monitor/management/lifecycle.py +8 -1
  133. claude_mpm/services/monitor/server.py +698 -22
  134. claude_mpm/services/pm_skills_deployer.py +711 -0
  135. claude_mpm/services/profile_manager.py +331 -0
  136. claude_mpm/services/self_upgrade_service.py +120 -12
  137. claude_mpm/services/skills/__init__.py +3 -0
  138. claude_mpm/services/skills/git_skill_source_manager.py +130 -2
  139. claude_mpm/services/skills/selective_skill_deployer.py +704 -0
  140. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  141. claude_mpm/services/skills_deployer.py +127 -9
  142. claude_mpm/services/socketio/dashboard_server.py +1 -0
  143. claude_mpm/services/socketio/event_normalizer.py +51 -6
  144. claude_mpm/services/socketio/server/core.py +386 -108
  145. claude_mpm/services/version_control/git_operations.py +103 -0
  146. claude_mpm/skills/skill_manager.py +92 -3
  147. claude_mpm/utils/agent_dependency_loader.py +14 -2
  148. claude_mpm/utils/agent_filters.py +17 -44
  149. claude_mpm/utils/migration.py +4 -4
  150. claude_mpm/utils/robust_installer.py +47 -3
  151. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/METADATA +53 -87
  152. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/RECORD +157 -197
  153. claude_mpm-5.4.48.dist-info/entry_points.txt +5 -0
  154. claude_mpm-5.4.48.dist-info/licenses/LICENSE +94 -0
  155. claude_mpm-5.4.48.dist-info/licenses/LICENSE-FAQ.md +153 -0
  156. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  157. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  158. claude_mpm/agents/BASE_OPS.md +0 -219
  159. claude_mpm/agents/BASE_PM.md +0 -480
  160. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  161. claude_mpm/agents/BASE_QA.md +0 -167
  162. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  163. claude_mpm/agents/base_agent_loader.py +0 -601
  164. claude_mpm/cli/commands/agents_detect.py +0 -380
  165. claude_mpm/cli/commands/agents_recommend.py +0 -309
  166. claude_mpm/cli/ticket_cli.py +0 -35
  167. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  168. claude_mpm/commands/mpm-agents-detect.md +0 -177
  169. claude_mpm/commands/mpm-agents-list.md +0 -131
  170. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  171. claude_mpm/commands/mpm-config-view.md +0 -150
  172. claude_mpm/commands/mpm-ticket-organize.md +0 -304
  173. claude_mpm/dashboard/analysis_runner.py +0 -455
  174. claude_mpm/dashboard/index.html +0 -13
  175. claude_mpm/dashboard/open_dashboard.py +0 -66
  176. claude_mpm/dashboard/static/css/activity.css +0 -1958
  177. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  178. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  179. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  180. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  181. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  182. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  183. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  184. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  185. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  186. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  187. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  188. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  189. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  190. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  191. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  192. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  193. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  194. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  195. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  196. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  197. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  198. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  199. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  200. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  201. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  202. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  203. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  204. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  205. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  206. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  207. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  208. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  209. claude_mpm/dashboard/templates/code_simple.html +0 -153
  210. claude_mpm/dashboard/templates/index.html +0 -606
  211. claude_mpm/dashboard/test_dashboard.html +0 -372
  212. claude_mpm/scripts/mcp_server.py +0 -75
  213. claude_mpm/scripts/mcp_wrapper.py +0 -39
  214. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  215. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  216. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  217. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  218. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  219. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  220. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  221. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  222. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  223. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  224. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
  225. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  226. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  227. claude_mpm/services/mcp_gateway/main.py +0 -589
  228. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  229. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  230. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  231. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  232. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  233. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  234. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  235. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  236. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  237. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  238. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  239. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  240. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  241. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  242. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  243. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  244. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  245. claude_mpm-5.1.9.dist-info/entry_points.txt +0 -10
  246. claude_mpm-5.1.9.dist-info/licenses/LICENSE +0 -21
  247. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/WHEEL +0 -0
  248. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/top_level.txt +0 -0
@@ -50,10 +50,10 @@ class GitSourceManager:
50
50
 
51
51
  Args:
52
52
  cache_root: Root directory for repository caches.
53
- Defaults to ~/.claude-mpm/cache/remote-agents/
53
+ Defaults to ~/.claude-mpm/cache/agents/
54
54
  """
55
55
  if cache_root is None:
56
- cache_root = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
56
+ cache_root = Path.home() / ".claude-mpm" / "cache" / "agents"
57
57
 
58
58
  self.cache_root = cache_root
59
59
  self.cache_root.mkdir(parents=True, exist_ok=True)
@@ -339,14 +339,48 @@ class GitSourceManager:
339
339
 
340
340
  # Walk cache directory structure
341
341
  logger.debug(f"[DEBUG] Walking cache root: {self.cache_root}")
342
+
343
+ # Known legacy category directories to skip (flat cache structure)
344
+ LEGACY_CATEGORIES = {
345
+ "universal",
346
+ "engineer",
347
+ "ops",
348
+ "qa",
349
+ "security",
350
+ "documentation",
351
+ "claude-mpm",
352
+ }
353
+
354
+ # Repositories that are NOT agent repositories (should be excluded from agent discovery)
355
+ # These contain skills, documentation, or other non-agent content
356
+ EXCLUDED_REPOSITORIES = {
357
+ "claude-mpm-skills", # Skills repository, not agents
358
+ }
359
+
342
360
  for owner_dir in self.cache_root.iterdir():
343
361
  if not owner_dir.is_dir():
344
362
  continue
363
+
364
+ # Skip legacy category directories (they're not GitHub owners)
365
+ if owner_dir.name.lower() in LEGACY_CATEGORIES:
366
+ logger.debug(
367
+ f"[DEBUG] Skipping legacy category directory: {owner_dir.name}"
368
+ )
369
+ continue
370
+
345
371
  logger.debug(f"[DEBUG] Processing owner_dir: {owner_dir.name}")
346
372
 
347
373
  for repo_dir in owner_dir.iterdir():
348
374
  if not repo_dir.is_dir():
349
375
  continue
376
+
377
+ # Skip excluded repositories (e.g., skills repos are not agent repos)
378
+ if repo_dir.name in EXCLUDED_REPOSITORIES:
379
+ logger.debug(
380
+ f"[DEBUG] Skipping excluded repository: {repo_dir.name}"
381
+ )
382
+ continue
383
+
350
384
  logger.debug(f"[DEBUG] Processing repo_dir: {repo_dir.name}")
351
385
 
352
386
  # Bug #5 fix: Don't iterate subdirectories - RemoteAgentDiscoveryService
@@ -361,8 +395,23 @@ class GitSourceManager:
361
395
  )
362
396
  logger.debug(f"[DEBUG] Found {len(agents)} agents so far")
363
397
 
364
- logger.debug(f"[DEBUG] list_cached_agents COMPLETE: {len(agents)} total agents")
365
- return agents
398
+ logger.debug(f"[DEBUG] list_cached_agents COMPLETE: {len(agents)} total agents (before deduplication)")
399
+
400
+ # Deduplicate agents by agent_id (Bug #2 fix)
401
+ # When same agent exists in multiple locations, keep only first occurrence
402
+ seen_ids = set()
403
+ deduplicated_agents = []
404
+
405
+ for agent in agents:
406
+ agent_id = agent.get("agent_id") or agent.get("metadata", {}).get("name")
407
+ if agent_id and agent_id not in seen_ids:
408
+ seen_ids.add(agent_id)
409
+ deduplicated_agents.append(agent)
410
+ elif agent_id:
411
+ logger.debug(f"[DEBUG] Skipping duplicate agent: {agent_id}")
412
+
413
+ logger.debug(f"[DEBUG] After deduplication: {len(deduplicated_agents)} unique agents")
414
+ return deduplicated_agents
366
415
 
367
416
  def _discover_agents_in_directory(
368
417
  self,
@@ -13,9 +13,6 @@ from enum import Enum
13
13
  from pathlib import Path
14
14
  from typing import Any, Dict, List, Optional
15
15
 
16
- # Lazy import for base_agent_loader to reduce initialization overhead
17
- # base_agent_loader adds ~500ms to import time
18
- # from claude_mpm.agents.base_agent_loader import clear_base_agent_cache
19
16
  from claude_mpm.core.logging_utils import get_logger
20
17
  from claude_mpm.services.memory.cache.shared_prompt_cache import SharedPromptCache
21
18
  from claude_mpm.services.shared import ConfigServiceBase
@@ -23,13 +20,6 @@ from claude_mpm.services.shared import ConfigServiceBase
23
20
  logger = get_logger(__name__)
24
21
 
25
22
 
26
- def _get_clear_base_agent_cache():
27
- """Lazy loader for clear_base_agent_cache function."""
28
- from claude_mpm.agents.base_agent_loader import clear_base_agent_cache
29
-
30
- return clear_base_agent_cache
31
-
32
-
33
23
  class BaseAgentSection(str, Enum):
34
24
  """Base agent markdown sections."""
35
25
 
@@ -143,9 +133,7 @@ class BaseAgentManager(ConfigServiceBase):
143
133
  content = self._structure_to_markdown(current)
144
134
  self.base_agent_path.write_text(content, encoding="utf-8")
145
135
 
146
- # Clear caches (lazy load to avoid import overhead)
147
- clear_base_agent_cache = _get_clear_base_agent_cache()
148
- clear_base_agent_cache()
136
+ # Clear cache
149
137
  self.cache.invalidate("base_agent:instructions")
150
138
 
151
139
  logger.info("Base agent updated successfully")
@@ -226,9 +226,11 @@ class AgentRecommenderService(BaseService, IAgentRecommender):
226
226
  if max_agents is not None:
227
227
  recommendations = recommendations[:max_agents]
228
228
 
229
- # Check if toolchain is unknown and we have no recommendations
230
- if not recommendations and toolchain.primary_language.lower() == "unknown":
231
- self.logger.info("Toolchain unknown - applying default configuration")
229
+ # Check if we have no recommendations (any reason: unknown language, low scores, etc.)
230
+ if not recommendations:
231
+ self.logger.info(
232
+ f"No agents scored above threshold for {toolchain.primary_language}; using defaults"
233
+ )
232
234
 
233
235
  # Get default configuration
234
236
  default_config = self._capabilities_config.get("default_configuration", {})
@@ -78,14 +78,14 @@ class SingleTierDeploymentService:
78
78
  config: Agent source configuration with repositories
79
79
  deployment_dir: Target deployment directory (.claude/agents/)
80
80
  cache_root: Cache root for repositories
81
- (defaults to ~/.claude-mpm/cache/remote-agents/)
81
+ (defaults to ~/.claude-mpm/cache/agents/)
82
82
  """
83
83
  self.config = config
84
84
  self.deployment_dir = deployment_dir
85
85
  self.deployment_dir.mkdir(parents=True, exist_ok=True)
86
86
 
87
87
  if cache_root is None:
88
- cache_root = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
88
+ cache_root = Path.home() / ".claude-mpm" / "cache" / "agents"
89
89
 
90
90
  self.cache_root = cache_root
91
91
  self.git_source_manager = GitSourceManager(cache_root)
@@ -13,11 +13,16 @@ import logging
13
13
  import time
14
14
  from datetime import datetime, timezone
15
15
  from pathlib import Path
16
- from typing import Any, Dict, List, Optional, Tuple
16
+ from typing import Any, Dict, List, Optional, Set, Tuple
17
17
 
18
18
  import requests
19
19
 
20
20
  from claude_mpm.core.file_utils import get_file_hash
21
+
22
+ # Import normalize function for exclusion filtering
23
+ from claude_mpm.services.agents.deployment.multi_source_deployment_service import (
24
+ _normalize_agent_name,
25
+ )
21
26
  from claude_mpm.services.agents.sources.agent_sync_state import AgentSyncState
22
27
  from claude_mpm.utils.progress import create_progress_bar
23
28
 
@@ -188,10 +193,10 @@ class GitSourceSyncService:
188
193
 
189
194
  Args:
190
195
  source_url: Base URL for raw files (without trailing slash)
191
- cache_dir: Local cache directory (defaults to ~/.claude-mpm/cache/remote-agents/)
196
+ cache_dir: Local cache directory (defaults to ~/.claude-mpm/cache/agents/)
192
197
  source_id: Unique identifier for this source (for multi-source support)
193
198
 
194
- Design Decision: Cache to ~/.claude-mpm/cache/remote-agents/ (canonical location)
199
+ Design Decision: Cache to ~/.claude-mpm/cache/agents/ (canonical location)
195
200
 
196
201
  Rationale: Separates cached repository structure from deployed agents.
197
202
  This allows preserving nested directory structure in cache while
@@ -207,13 +212,13 @@ class GitSourceSyncService:
207
212
  self.source_url = source_url.rstrip("/")
208
213
  self.source_id = source_id
209
214
 
210
- # Setup cache directory (canonical: ~/.claude-mpm/cache/remote-agents/)
215
+ # Setup cache directory (canonical: ~/.claude-mpm/cache/agents/)
211
216
  if cache_dir:
212
217
  self.cache_dir = Path(cache_dir)
213
218
  else:
214
- # Default to ~/.claude-mpm/cache/remote-agents/ (canonical cache location)
219
+ # Default to ~/.claude-mpm/cache/agents/ (canonical cache location)
215
220
  home = Path.home()
216
- self.cache_dir = home / ".claude-mpm" / "cache" / "remote-agents"
221
+ self.cache_dir = home / ".claude-mpm" / "cache" / "agents"
217
222
 
218
223
  self.cache_dir.mkdir(parents=True, exist_ok=True)
219
224
 
@@ -851,6 +856,12 @@ class GitSourceSyncService:
851
856
  if base_path and not path.startswith(base_path + "/"):
852
857
  continue
853
858
 
859
+ # Exclude build/dist directories (prevents double-counting)
860
+ # e.g., both "agents/engineer.md" and "dist/agents/engineer.md"
861
+ path_parts = path.split("/")
862
+ if any(excluded in path_parts for excluded in ["dist", "build", ".cache"]):
863
+ continue
864
+
854
865
  # Remove base_path prefix for relative paths
855
866
  if base_path:
856
867
  relative_path = path[len(base_path) + 1 :]
@@ -917,6 +928,62 @@ class GitSourceSyncService:
917
928
  """
918
929
  return self.cache_dir
919
930
 
931
+ def _cleanup_excluded_agents(
932
+ self,
933
+ deployment_dir: Path,
934
+ excluded_set: Set[str],
935
+ ) -> Dict[str, List[str]]:
936
+ """Remove excluded agents from deployment directory.
937
+
938
+ Removes any agents in the deployment directory whose normalized
939
+ names match the exclusion list. This ensures that excluded agents
940
+ are cleaned up from previous deployments.
941
+
942
+ Args:
943
+ deployment_dir: Directory containing deployed agents
944
+ excluded_set: Set of normalized agent names to exclude
945
+
946
+ Returns:
947
+ Dictionary with cleanup results:
948
+ - removed: List of agent names that were removed
949
+ """
950
+ cleanup_results: Dict[str, List[str]] = {"removed": []}
951
+
952
+ if not deployment_dir.exists():
953
+ logger.debug("Deployment directory does not exist, no cleanup needed")
954
+ return cleanup_results
955
+
956
+ for item in deployment_dir.iterdir():
957
+ # Only process .md files
958
+ if not item.is_file() or item.suffix != ".md":
959
+ continue
960
+
961
+ # Skip hidden files
962
+ if item.name.startswith("."):
963
+ continue
964
+
965
+ # Normalize agent name for comparison
966
+ agent_name = _normalize_agent_name(item.stem)
967
+
968
+ # Check if this agent is excluded
969
+ if agent_name in excluded_set:
970
+ try:
971
+ item.unlink()
972
+ cleanup_results["removed"].append(item.stem)
973
+ logger.info(f"Removed excluded agent: {item.stem}")
974
+ except PermissionError as e:
975
+ logger.error(f"Permission denied removing {item.stem}: {e}")
976
+ except Exception as e:
977
+ logger.error(f"Failed to remove {item.stem}: {e}")
978
+
979
+ # Log summary
980
+ if cleanup_results["removed"]:
981
+ logger.info(
982
+ f"Cleanup complete: removed {len(cleanup_results['removed'])} excluded agents"
983
+ )
984
+
985
+ return cleanup_results
986
+
920
987
  def deploy_agents_to_project(
921
988
  self,
922
989
  project_dir: Path,
@@ -971,7 +1038,10 @@ class GitSourceSyncService:
971
1038
  """
972
1039
  import shutil
973
1040
 
974
- deployment_dir = project_dir / ".claude-mpm" / "agents"
1041
+ from claude_mpm.core.config import Config
1042
+
1043
+ # Deploy to .claude/agents/ where Claude Code expects them
1044
+ deployment_dir = project_dir / ".claude" / "agents"
975
1045
  deployment_dir.mkdir(parents=True, exist_ok=True)
976
1046
 
977
1047
  results = {
@@ -982,10 +1052,53 @@ class GitSourceSyncService:
982
1052
  "deployment_dir": str(deployment_dir),
983
1053
  }
984
1054
 
1055
+ # Load project config to get exclusion list
1056
+ config_file = project_dir / ".claude-mpm" / "configuration.yaml"
1057
+ if config_file.exists():
1058
+ config = Config(config_file=config_file)
1059
+ excluded_agents = config.get("excluded_agents", [])
1060
+ else:
1061
+ # No project config, no exclusions
1062
+ excluded_agents = []
1063
+
1064
+ # Create normalized exclusion set
1065
+ excluded_set: Set[str] = (
1066
+ {_normalize_agent_name(name) for name in excluded_agents}
1067
+ if excluded_agents
1068
+ else set()
1069
+ )
1070
+
1071
+ if excluded_set:
1072
+ logger.info(
1073
+ f"Applying exclusions: {', '.join(sorted(excluded_agents))} "
1074
+ f"(normalized: {', '.join(sorted(excluded_set))})"
1075
+ )
1076
+
985
1077
  # Get agents from cache or use provided list
986
1078
  if agent_list is None:
987
1079
  agent_list = self._discover_cached_agents()
988
1080
 
1081
+ # Filter out excluded agents
1082
+ if excluded_set:
1083
+ original_count = len(agent_list)
1084
+ agent_list = [
1085
+ agent_path
1086
+ for agent_path in agent_list
1087
+ if _normalize_agent_name(Path(agent_path).stem) not in excluded_set
1088
+ ]
1089
+ filtered_count = original_count - len(agent_list)
1090
+ if filtered_count > 0:
1091
+ logger.info(f"Filtered out {filtered_count} excluded agents")
1092
+
1093
+ # Clean up any previously deployed excluded agents
1094
+ if excluded_set:
1095
+ cleanup_results = self._cleanup_excluded_agents(deployment_dir, excluded_set)
1096
+ if cleanup_results["removed"]:
1097
+ logger.info(
1098
+ f"Cleaned up {len(cleanup_results['removed'])} excluded agents: "
1099
+ f"{', '.join(cleanup_results['removed'])}"
1100
+ )
1101
+
989
1102
  logger.info(
990
1103
  f"Deploying {len(agent_list)} agents from cache to {deployment_dir}"
991
1104
  )
@@ -110,6 +110,26 @@ def sync_agents_on_startup(config: Optional[Dict[str, Any]] = None) -> Dict[str,
110
110
  else:
111
111
  cache_dir = None # Will use default
112
112
 
113
+ # Check for old cache directory names and provide migration guidance
114
+ # This handles users upgrading from older versions
115
+ old_cache_paths = [
116
+ Path.home() / ".claude-mpm" / "cache" / "remote-agents",
117
+ ]
118
+ new_cache_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
119
+
120
+ for old_cache in old_cache_paths:
121
+ if old_cache.exists() and not new_cache_dir.exists():
122
+ logger.warning(f"Found old cache directory: {old_cache}")
123
+ logger.warning(
124
+ "The cache directory location has changed to: ~/.claude-mpm/cache/agents"
125
+ )
126
+ logger.warning("To migrate your existing cache, run:")
127
+ logger.warning(f" mv {old_cache} {new_cache_dir}")
128
+ logger.info(
129
+ "Agents will be re-synced to the new cache location automatically."
130
+ )
131
+ break # Only show warning once
132
+
113
133
  # Sync each enabled source
114
134
  for source_config in sources:
115
135
  try:
@@ -217,7 +237,7 @@ def get_sync_status() -> Dict[str, Any]:
217
237
  "enabled": agent_sync_config.get("enabled", True),
218
238
  "sources_configured": len(enabled_sources),
219
239
  "cache_dir": agent_sync_config.get(
220
- "cache_dir", "~/.claude-mpm/cache/remote-agents"
240
+ "cache_dir", "~/.claude-mpm/cache/agents"
221
241
  ),
222
242
  }
223
243
 
@@ -233,7 +253,7 @@ def get_sync_status() -> Dict[str, Any]:
233
253
  return {
234
254
  "enabled": False,
235
255
  "sources_configured": 0,
236
- "cache_dir": "~/.claude-mpm/cache/remote-agents",
256
+ "cache_dir": "~/.claude-mpm/cache/agents",
237
257
  "last_sync": None,
238
258
  "error": str(e),
239
259
  }
@@ -158,12 +158,15 @@ class ToolchainDetector:
158
158
  "make": ["ops"],
159
159
  }
160
160
 
161
- # Core agents always included
161
+ # Core agents always included (use exact agent IDs from repository)
162
162
  CORE_AGENTS = [
163
- "qa",
164
- "research",
165
- "documentation",
166
- "ticketing",
163
+ "engineer",
164
+ "qa-agent",
165
+ "memory-manager-agent",
166
+ "local-ops-agent",
167
+ "research-agent",
168
+ "documentation-agent",
169
+ "security-agent",
167
170
  ]
168
171
 
169
172
  # Directories to exclude from scanning
@@ -365,7 +368,8 @@ class ToolchainDetector:
365
368
  """Map detected toolchain to recommended agents.
366
369
 
367
370
  Combines language-specific, framework-specific, and ops agents with
368
- core agents (qa, research, documentation, ticketing).
371
+ core agents (engineer, qa-agent, memory-manager-agent, local-ops-agent, research-agent,
372
+ documentation-agent, security-agent).
369
373
 
370
374
  Args:
371
375
  toolchain: Detected toolchain dictionary with languages, frameworks, tools
@@ -1,9 +1,15 @@
1
1
  """
2
2
  Analysis services for Claude MPM.
3
3
 
4
- Provides postmortem analysis and error improvement suggestions.
4
+ Provides postmortem analysis, error improvement suggestions, and code clone detection.
5
5
  """
6
6
 
7
+ from .clone_detector import (
8
+ CloneDetector,
9
+ CloneReport,
10
+ RefactoringSuggestion,
11
+ SimilarityReport,
12
+ )
7
13
  from .postmortem_service import (
8
14
  ActionType,
9
15
  ErrorAnalysis,
@@ -16,10 +22,14 @@ from .postmortem_service import (
16
22
 
17
23
  __all__ = [
18
24
  "ActionType",
25
+ "CloneDetector",
26
+ "CloneReport",
19
27
  "ErrorAnalysis",
20
28
  "ErrorCategory",
21
29
  "ImprovementAction",
22
30
  "PostmortemReport",
23
31
  "PostmortemService",
32
+ "RefactoringSuggestion",
33
+ "SimilarityReport",
24
34
  "get_postmortem_service",
25
35
  ]