claude-mpm 5.0.9__py3-none-any.whl → 5.4.41__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 (263) 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/{PM_INSTRUCTIONS_TEACH.md → CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md} +721 -41
  5. claude_mpm/agents/MEMORY.md +1 -1
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +468 -468
  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 +70 -2
  11. claude_mpm/agents/templates/circuit-breakers.md +431 -45
  12. claude_mpm/cli/__init__.py +0 -1
  13. claude_mpm/cli/__main__.py +4 -0
  14. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  15. claude_mpm/cli/commands/agent_state_manager.py +18 -27
  16. claude_mpm/cli/commands/agents.py +175 -37
  17. claude_mpm/cli/commands/auto_configure.py +723 -236
  18. claude_mpm/cli/commands/config.py +88 -2
  19. claude_mpm/cli/commands/configure.py +1262 -157
  20. claude_mpm/cli/commands/configure_agent_display.py +25 -6
  21. claude_mpm/cli/commands/mpm_init/core.py +225 -46
  22. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  23. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  24. claude_mpm/cli/commands/postmortem.py +1 -1
  25. claude_mpm/cli/commands/profile.py +277 -0
  26. claude_mpm/cli/commands/skills.py +214 -189
  27. claude_mpm/cli/commands/summarize.py +413 -0
  28. claude_mpm/cli/executor.py +21 -3
  29. claude_mpm/cli/interactive/agent_wizard.py +85 -10
  30. claude_mpm/cli/parsers/agents_parser.py +54 -9
  31. claude_mpm/cli/parsers/auto_configure_parser.py +13 -138
  32. claude_mpm/cli/parsers/base_parser.py +12 -0
  33. claude_mpm/cli/parsers/config_parser.py +153 -83
  34. claude_mpm/cli/parsers/profile_parser.py +148 -0
  35. claude_mpm/cli/parsers/skills_parser.py +3 -2
  36. claude_mpm/cli/startup.py +879 -149
  37. claude_mpm/commands/mpm-config.md +28 -0
  38. claude_mpm/commands/mpm-doctor.md +9 -22
  39. claude_mpm/commands/mpm-help.md +5 -287
  40. claude_mpm/commands/mpm-init.md +81 -507
  41. claude_mpm/commands/mpm-monitor.md +15 -402
  42. claude_mpm/commands/mpm-organize.md +120 -0
  43. claude_mpm/commands/mpm-postmortem.md +6 -108
  44. claude_mpm/commands/mpm-session-resume.md +12 -363
  45. claude_mpm/commands/mpm-status.md +5 -69
  46. claude_mpm/commands/mpm-ticket-view.md +52 -495
  47. claude_mpm/commands/mpm-version.md +5 -107
  48. claude_mpm/config/agent_sources.py +27 -0
  49. claude_mpm/core/config.py +2 -4
  50. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  51. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  52. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  53. claude_mpm/core/framework_loader.py +4 -2
  54. claude_mpm/core/logger.py +13 -0
  55. claude_mpm/core/optimized_startup.py +59 -0
  56. claude_mpm/core/output_style_manager.py +173 -43
  57. claude_mpm/core/shared/config_loader.py +1 -1
  58. claude_mpm/core/socketio_pool.py +3 -3
  59. claude_mpm/core/unified_agent_registry.py +134 -16
  60. claude_mpm/core/unified_config.py +22 -0
  61. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  62. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
  63. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
  64. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
  65. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
  66. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
  67. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
  68. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
  69. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
  70. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
  71. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
  72. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
  73. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
  74. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
  75. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -0
  76. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  77. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  78. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  79. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  80. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  81. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  82. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  83. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  84. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  85. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  86. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  87. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  88. claude_mpm/hooks/claude_hooks/event_handlers.py +211 -78
  89. claude_mpm/hooks/claude_hooks/hook_handler.py +155 -1
  90. claude_mpm/hooks/claude_hooks/installer.py +33 -10
  91. claude_mpm/hooks/claude_hooks/memory_integration.py +28 -0
  92. claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
  93. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  94. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  95. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  96. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  97. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  98. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  99. claude_mpm/hooks/claude_hooks/services/connection_manager.py +30 -6
  100. claude_mpm/hooks/memory_integration_hook.py +46 -1
  101. claude_mpm/init.py +63 -19
  102. claude_mpm/models/agent_definition.py +7 -0
  103. claude_mpm/models/git_repository.py +3 -3
  104. claude_mpm/scripts/claude-hook-handler.sh +58 -18
  105. claude_mpm/scripts/launch_monitor.py +93 -13
  106. claude_mpm/scripts/start_activity_logging.py +0 -0
  107. claude_mpm/services/agents/agent_builder.py +3 -3
  108. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  109. claude_mpm/services/agents/agent_review_service.py +280 -0
  110. claude_mpm/services/agents/cache_git_manager.py +6 -6
  111. claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
  112. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -5
  113. claude_mpm/services/agents/deployment/agent_template_builder.py +5 -3
  114. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  115. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +320 -29
  116. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +546 -68
  117. claude_mpm/services/agents/git_source_manager.py +36 -2
  118. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  119. claude_mpm/services/agents/recommender.py +5 -3
  120. claude_mpm/services/agents/single_tier_deployment_service.py +2 -2
  121. claude_mpm/services/agents/sources/git_source_sync_service.py +13 -6
  122. claude_mpm/services/agents/startup_sync.py +22 -2
  123. claude_mpm/services/agents/toolchain_detector.py +10 -6
  124. claude_mpm/services/analysis/__init__.py +11 -1
  125. claude_mpm/services/analysis/clone_detector.py +1030 -0
  126. claude_mpm/services/command_deployment_service.py +81 -10
  127. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  128. claude_mpm/services/diagnostics/checks/agent_sources_check.py +1 -1
  129. claude_mpm/services/event_bus/config.py +3 -1
  130. claude_mpm/services/git/git_operations_service.py +101 -16
  131. claude_mpm/services/monitor/daemon.py +9 -2
  132. claude_mpm/services/monitor/daemon_manager.py +39 -3
  133. claude_mpm/services/monitor/management/lifecycle.py +8 -1
  134. claude_mpm/services/monitor/server.py +698 -22
  135. claude_mpm/services/pm_skills_deployer.py +676 -0
  136. claude_mpm/services/profile_manager.py +331 -0
  137. claude_mpm/services/project/project_organizer.py +4 -0
  138. claude_mpm/services/self_upgrade_service.py +120 -12
  139. claude_mpm/services/skills/__init__.py +3 -0
  140. claude_mpm/services/skills/git_skill_source_manager.py +130 -2
  141. claude_mpm/services/skills/selective_skill_deployer.py +704 -0
  142. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  143. claude_mpm/services/skills_deployer.py +126 -9
  144. claude_mpm/services/socketio/dashboard_server.py +1 -0
  145. claude_mpm/services/socketio/event_normalizer.py +51 -6
  146. claude_mpm/services/socketio/server/core.py +386 -108
  147. claude_mpm/services/version_control/git_operations.py +103 -0
  148. claude_mpm/skills/skill_manager.py +92 -3
  149. claude_mpm/utils/agent_dependency_loader.py +14 -2
  150. claude_mpm/utils/agent_filters.py +17 -44
  151. claude_mpm/utils/gitignore.py +3 -0
  152. claude_mpm/utils/migration.py +4 -4
  153. claude_mpm/utils/robust_installer.py +47 -3
  154. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/METADATA +57 -87
  155. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/RECORD +160 -211
  156. claude_mpm-5.4.41.dist-info/entry_points.txt +5 -0
  157. claude_mpm-5.4.41.dist-info/licenses/LICENSE +94 -0
  158. claude_mpm-5.4.41.dist-info/licenses/LICENSE-FAQ.md +153 -0
  159. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  160. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  161. claude_mpm/agents/BASE_OPS.md +0 -219
  162. claude_mpm/agents/BASE_PM.md +0 -480
  163. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  164. claude_mpm/agents/BASE_QA.md +0 -167
  165. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  166. claude_mpm/agents/base_agent_loader.py +0 -601
  167. claude_mpm/cli/commands/agents_detect.py +0 -380
  168. claude_mpm/cli/commands/agents_recommend.py +0 -309
  169. claude_mpm/cli/ticket_cli.py +0 -35
  170. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  171. claude_mpm/commands/mpm-agents-detect.md +0 -177
  172. claude_mpm/commands/mpm-agents-list.md +0 -131
  173. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  174. claude_mpm/commands/mpm-config-view.md +0 -150
  175. claude_mpm/commands/mpm-ticket-organize.md +0 -304
  176. claude_mpm/dashboard/analysis_runner.py +0 -455
  177. claude_mpm/dashboard/index.html +0 -13
  178. claude_mpm/dashboard/open_dashboard.py +0 -66
  179. claude_mpm/dashboard/static/css/activity.css +0 -1958
  180. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  181. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  182. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  183. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  184. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  185. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  186. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  187. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  188. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  189. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  190. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  191. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  192. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  193. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  194. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  195. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  196. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  197. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  198. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  199. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  200. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  201. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  202. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  203. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  204. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  205. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  206. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  207. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  208. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  209. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  210. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  211. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  212. claude_mpm/dashboard/templates/code_simple.html +0 -153
  213. claude_mpm/dashboard/templates/index.html +0 -606
  214. claude_mpm/dashboard/test_dashboard.html +0 -372
  215. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  216. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  217. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  218. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  219. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  220. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  221. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  222. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  223. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  224. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  225. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  226. claude_mpm/scripts/mcp_server.py +0 -75
  227. claude_mpm/scripts/mcp_wrapper.py +0 -39
  228. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  229. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  230. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  231. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  232. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  233. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  234. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  235. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  236. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  237. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  238. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
  239. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  240. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  241. claude_mpm/services/mcp_gateway/main.py +0 -589
  242. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  243. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  244. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  245. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  246. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  247. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  248. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  249. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  250. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  251. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  252. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  253. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  254. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  255. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  256. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  257. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  258. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  259. claude_mpm-5.0.9.dist-info/entry_points.txt +0 -10
  260. claude_mpm-5.0.9.dist-info/licenses/LICENSE +0 -21
  261. /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
  262. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/WHEEL +0 -0
  263. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,331 @@
1
+ """
2
+ Profile Manager Service
3
+ ======================
4
+
5
+ Manages agent and skill filtering based on deployment profiles.
6
+
7
+ A profile defines which agents and skills should be deployed, reducing
8
+ context usage by limiting available agents to only what's needed for
9
+ a specific project or workflow.
10
+
11
+ Profile Structure:
12
+ profile:
13
+ name: framework-development
14
+ description: Python backend + TypeScript/Svelte dashboard
15
+
16
+ agents:
17
+ enabled:
18
+ - python-engineer
19
+ - typescript-engineer
20
+ disabled:
21
+ - java-engineer
22
+ - dart-engineer
23
+
24
+ skills:
25
+ enabled:
26
+ - flask
27
+ - pytest
28
+ disabled_categories:
29
+ - wordpress-*
30
+ - react-*
31
+
32
+ Usage:
33
+ # Auto-detect project directory (searches for .claude-mpm in cwd and parents)
34
+ profile_manager = ProfileManager()
35
+
36
+ # Or explicitly specify project directory
37
+ profile_manager = ProfileManager(project_dir=Path("/path/to/project"))
38
+
39
+ profile_manager.load_profile("framework-development")
40
+
41
+ if profile_manager.is_agent_enabled("python-engineer"):
42
+ # Deploy agent
43
+ pass
44
+
45
+ if profile_manager.is_skill_enabled("flask"):
46
+ # Deploy skill
47
+ pass
48
+ """
49
+
50
+ import fnmatch
51
+ from pathlib import Path
52
+ from typing import Optional, Set, Dict, Any
53
+
54
+ import yaml
55
+
56
+ from ..core.logger import get_logger
57
+
58
+ logger = get_logger(__name__)
59
+
60
+
61
+ class ProfileManager:
62
+ """
63
+ Manages deployment profiles for agent and skill filtering.
64
+
65
+ Provides methods to:
66
+ - Load profiles from YAML files
67
+ - Check if agents are enabled/disabled
68
+ - Check if skills are enabled/disabled (with glob pattern support)
69
+ - Get lists of enabled/disabled entities
70
+ """
71
+
72
+ def __init__(self, project_dir: Optional[Path] = None, profiles_dir: Optional[Path] = None):
73
+ """
74
+ Initialize ProfileManager.
75
+
76
+ Args:
77
+ project_dir: Project root directory. If not provided, tries to find
78
+ .claude-mpm directory in current or parent directories.
79
+ profiles_dir: Directory containing profile YAML files. If provided,
80
+ takes precedence over project_dir.
81
+ """
82
+ if profiles_dir:
83
+ self.profiles_dir = profiles_dir
84
+ elif project_dir:
85
+ self.profiles_dir = Path(project_dir) / ".claude-mpm" / "profiles"
86
+ else:
87
+ # Try to find .claude-mpm directory automatically
88
+ self.profiles_dir = self._find_profiles_dir()
89
+
90
+ self.active_profile: Optional[str] = None
91
+ self._profile_data: Dict[str, Any] = {}
92
+
93
+ # Cached sets for performance
94
+ self._enabled_agents: Set[str] = set()
95
+ self._disabled_agents: Set[str] = set()
96
+ self._enabled_skills: Set[str] = set()
97
+ self._disabled_skill_patterns: list[str] = []
98
+
99
+ def _find_profiles_dir(self) -> Path:
100
+ """Find profiles directory by searching for .claude-mpm in cwd and parents.
101
+
102
+ Returns:
103
+ Path to profiles directory (may not exist yet)
104
+ """
105
+ current = Path.cwd()
106
+
107
+ # Search current directory and up to 5 parent directories
108
+ for _ in range(6):
109
+ profiles_dir = current / ".claude-mpm" / "profiles"
110
+ if profiles_dir.exists():
111
+ logger.debug(f"Found profiles directory at: {profiles_dir}")
112
+ return profiles_dir
113
+ if current.parent == current: # Reached filesystem root
114
+ break
115
+ current = current.parent
116
+
117
+ # Fallback to cwd (directory may not exist yet, which is fine)
118
+ fallback = Path.cwd() / ".claude-mpm" / "profiles"
119
+ logger.debug(f"Profiles directory not found, using fallback: {fallback}")
120
+ return fallback
121
+
122
+ def load_profile(self, profile_name: str) -> bool:
123
+ """
124
+ Load profile from YAML file.
125
+
126
+ Args:
127
+ profile_name: Name of profile (without .yaml extension)
128
+
129
+ Returns:
130
+ bool: True if profile loaded successfully, False otherwise
131
+ """
132
+ profile_path = self.profiles_dir / f"{profile_name}.yaml"
133
+
134
+ logger.debug(f"Looking for profile at: {profile_path}")
135
+
136
+ if not profile_path.exists():
137
+ logger.warning(f"Profile not found: {profile_path}")
138
+ return False
139
+
140
+ try:
141
+ with profile_path.open("r") as f:
142
+ self._profile_data = yaml.safe_load(f) or {}
143
+
144
+ # Extract profile metadata
145
+ profile_info = self._profile_data.get("profile", {})
146
+ self.active_profile = profile_info.get("name", profile_name)
147
+
148
+ # Parse agents
149
+ agents_config = self._profile_data.get("agents", {})
150
+ self._enabled_agents = set(agents_config.get("enabled", []))
151
+ self._disabled_agents = set(agents_config.get("disabled", []))
152
+
153
+ # Parse skills
154
+ skills_config = self._profile_data.get("skills", {})
155
+ self._enabled_skills = set(skills_config.get("enabled", []))
156
+ self._disabled_skill_patterns = skills_config.get("disabled_categories", [])
157
+
158
+ logger.info(
159
+ f"Loaded profile '{self.active_profile}': "
160
+ f"{len(self._enabled_agents)} agents, "
161
+ f"{len(self._enabled_skills)} skills enabled"
162
+ )
163
+
164
+ return True
165
+
166
+ except Exception as e:
167
+ logger.error(f"Failed to load profile {profile_name}: {e}")
168
+ return False
169
+
170
+ def is_agent_enabled(self, agent_name: str) -> bool:
171
+ """
172
+ Check if agent is enabled in active profile.
173
+
174
+ If no profile is loaded, all agents are enabled by default.
175
+
176
+ Args:
177
+ agent_name: Name of agent to check
178
+
179
+ Returns:
180
+ bool: True if agent should be deployed
181
+ """
182
+ if not self.active_profile:
183
+ # No profile active - all agents enabled
184
+ return True
185
+
186
+ # If enabled list exists, agent must be in it
187
+ if self._enabled_agents:
188
+ return agent_name in self._enabled_agents
189
+
190
+ # Otherwise, agent must NOT be in disabled list
191
+ return agent_name not in self._disabled_agents
192
+
193
+ def is_skill_enabled(self, skill_name: str) -> bool:
194
+ """
195
+ Check if skill is enabled in active profile.
196
+
197
+ Supports both short names (flask) and full names (toolchains-python-frameworks-flask).
198
+ Supports glob pattern matching for disabled_categories.
199
+
200
+ If no profile is loaded, all skills are enabled by default.
201
+
202
+ Args:
203
+ skill_name: Name of skill to check (e.g., "flask", "toolchains-python-frameworks-flask")
204
+
205
+ Returns:
206
+ bool: True if skill should be deployed
207
+ """
208
+ if not self.active_profile:
209
+ # No profile active - all skills enabled
210
+ return True
211
+
212
+ # Check if skill is explicitly disabled by pattern
213
+ for pattern in self._disabled_skill_patterns:
214
+ if fnmatch.fnmatch(skill_name, pattern):
215
+ logger.debug(f"Skill '{skill_name}' matched disabled pattern '{pattern}'")
216
+ return False
217
+
218
+ # If enabled list exists, check for match
219
+ if self._enabled_skills:
220
+ # Exact match
221
+ if skill_name in self._enabled_skills:
222
+ return True
223
+
224
+ # Check if full skill name ends with short name from enabled list
225
+ # Example: "toolchains-python-frameworks-flask" matches "flask"
226
+ for short_name in self._enabled_skills:
227
+ if skill_name.endswith(f"-{short_name}"):
228
+ return True
229
+ # Also check if short name is contained as a segment
230
+ if f"-{short_name}-" in skill_name or skill_name.startswith(f"{short_name}-"):
231
+ return True
232
+
233
+ return False
234
+
235
+ # No enabled list and didn't match disabled pattern - allow it
236
+ return True
237
+
238
+ def get_enabled_agents(self) -> Set[str]:
239
+ """
240
+ Get set of enabled agent names.
241
+
242
+ Returns:
243
+ Set[str]: Agent names that should be deployed
244
+ """
245
+ return self._enabled_agents.copy()
246
+
247
+ def get_disabled_agents(self) -> Set[str]:
248
+ """
249
+ Get set of disabled agent names.
250
+
251
+ Returns:
252
+ Set[str]: Agent names that should NOT be deployed
253
+ """
254
+ return self._disabled_agents.copy()
255
+
256
+ def get_enabled_skills(self) -> Set[str]:
257
+ """
258
+ Get set of explicitly enabled skill names.
259
+
260
+ Returns:
261
+ Set[str]: Skill names that should be deployed
262
+ """
263
+ return self._enabled_skills.copy()
264
+
265
+ def get_disabled_skill_patterns(self) -> list[str]:
266
+ """
267
+ Get list of disabled skill glob patterns.
268
+
269
+ Returns:
270
+ list[str]: Glob patterns for skills that should NOT be deployed
271
+ """
272
+ return self._disabled_skill_patterns.copy()
273
+
274
+ def get_filtering_summary(self) -> Dict[str, Any]:
275
+ """
276
+ Get summary of current profile filtering.
277
+
278
+ Returns:
279
+ Dict containing:
280
+ - active_profile: Name of active profile (or None)
281
+ - enabled_agents_count: Number of explicitly enabled agents
282
+ - disabled_agents_count: Number of explicitly disabled agents
283
+ - enabled_skills_count: Number of explicitly enabled skills
284
+ - disabled_patterns_count: Number of disabled skill patterns
285
+ """
286
+ return {
287
+ "active_profile": self.active_profile,
288
+ "enabled_agents_count": len(self._enabled_agents),
289
+ "disabled_agents_count": len(self._disabled_agents),
290
+ "enabled_skills_count": len(self._enabled_skills),
291
+ "disabled_patterns_count": len(self._disabled_skill_patterns),
292
+ }
293
+
294
+ def list_available_profiles(self) -> list[str]:
295
+ """
296
+ List all available profile names in profiles directory.
297
+
298
+ Returns:
299
+ list[str]: Profile names (without .yaml extension)
300
+ """
301
+ if not self.profiles_dir.exists():
302
+ return []
303
+
304
+ profiles = []
305
+ for profile_path in self.profiles_dir.glob("*.yaml"):
306
+ profiles.append(profile_path.stem)
307
+
308
+ return sorted(profiles)
309
+
310
+ def get_profile_description(self, profile_name: str) -> Optional[str]:
311
+ """
312
+ Get description of a profile without loading it fully.
313
+
314
+ Args:
315
+ profile_name: Name of profile
316
+
317
+ Returns:
318
+ Optional[str]: Profile description or None if not found
319
+ """
320
+ profile_path = self.profiles_dir / f"{profile_name}.yaml"
321
+
322
+ if not profile_path.exists():
323
+ return None
324
+
325
+ try:
326
+ with profile_path.open("r") as f:
327
+ data = yaml.safe_load(f) or {}
328
+ profile_info = data.get("profile", {})
329
+ return profile_info.get("description")
330
+ except Exception:
331
+ return None
@@ -58,6 +58,10 @@ class ProjectOrganizer:
58
58
  ".mcp-vector-search/",
59
59
  ".kuzu-memory/",
60
60
  "kuzu-memories/", # kuzu-memory database directory
61
+ # User-specific config files (should NOT be committed)
62
+ ".mcp.json",
63
+ ".claude.json",
64
+ ".claude/",
61
65
  # Python artifacts
62
66
  "__pycache__/",
63
67
  "*.py[cod]",
@@ -3,7 +3,7 @@ Self-Upgrade Service
3
3
  ====================
4
4
 
5
5
  Handles version checking and self-upgrade functionality for claude-mpm.
6
- Supports pip, pipx, and npm installations with automatic detection.
6
+ Supports pip, pipx, npm, uv tool, and Homebrew installations with automatic detection.
7
7
  Also checks Claude Code version compatibility.
8
8
 
9
9
  WHY: Users should be notified of updates and have an easy way to upgrade
@@ -11,7 +11,7 @@ without manually running installation commands. Claude Code version checking
11
11
  ensures compatibility with required features.
12
12
 
13
13
  DESIGN DECISIONS:
14
- - Detects installation method (pip/pipx/npm/editable)
14
+ - Detects installation method (pip/pipx/npm/uv_tool/homebrew/editable)
15
15
  - Non-blocking version checks with caching
16
16
  - Interactive upgrade prompts with confirmation
17
17
  - Automatic restart after upgrade
@@ -40,6 +40,8 @@ class InstallationMethod:
40
40
  PIP = "pip"
41
41
  PIPX = "pipx"
42
42
  NPM = "npm"
43
+ UV_TOOL = "uv_tool"
44
+ HOMEBREW = "homebrew"
43
45
  EDITABLE = "editable"
44
46
  UNKNOWN = "unknown"
45
47
 
@@ -95,6 +97,14 @@ class SelfUpgradeService:
95
97
  """
96
98
  Detect how claude-mpm was installed.
97
99
 
100
+ Detection priority:
101
+ 1. Editable (skip auto-upgrade)
102
+ 2. UV Tool
103
+ 3. Homebrew
104
+ 4. Pipx
105
+ 5. NPM
106
+ 6. Pip (default)
107
+
98
108
  Returns:
99
109
  Installation method constant
100
110
  """
@@ -105,6 +115,14 @@ class SelfUpgradeService:
105
115
  ]:
106
116
  return InstallationMethod.EDITABLE
107
117
 
118
+ # Check for UV tool installation
119
+ if self._check_uv_tool_installation():
120
+ return InstallationMethod.UV_TOOL
121
+
122
+ # Check for Homebrew installation
123
+ if self._check_homebrew_installation():
124
+ return InstallationMethod.HOMEBREW
125
+
108
126
  # Check for pipx by looking at executable path
109
127
  executable = sys.executable
110
128
  if "pipx" in executable:
@@ -127,6 +145,85 @@ class SelfUpgradeService:
127
145
  # Default to pip
128
146
  return InstallationMethod.PIP
129
147
 
148
+ def _check_uv_tool_installation(self) -> bool:
149
+ """
150
+ Check if claude-mpm is installed via uv tool.
151
+
152
+ Detection methods:
153
+ 1. Check UV_TOOL_DIR environment variable
154
+ 2. Check if executable path contains .local/share/uv/tools/
155
+ 3. Fallback: Run `uv tool list` and check for claude-mpm
156
+
157
+ Returns:
158
+ True if UV tool installation detected
159
+ """
160
+ # Method 1: Check UV_TOOL_DIR environment variable
161
+ uv_tool_dir = os.environ.get("UV_TOOL_DIR")
162
+ if uv_tool_dir and "claude-mpm" in uv_tool_dir:
163
+ return True
164
+
165
+ # Method 2: Check executable path
166
+ executable = sys.executable
167
+ if ".local/share/uv/tools/" in executable or "uv/tools/" in executable:
168
+ return True
169
+
170
+ # Method 3: Fallback to `uv tool list` command
171
+ try:
172
+ result = subprocess.run(
173
+ ["uv", "tool", "list"],
174
+ check=False,
175
+ capture_output=True,
176
+ text=True,
177
+ timeout=5,
178
+ )
179
+ if result.returncode == 0 and "claude-mpm" in result.stdout:
180
+ return True
181
+ except (FileNotFoundError, subprocess.TimeoutExpired):
182
+ # uv not installed or command failed
183
+ pass
184
+ except Exception as e:
185
+ self.logger.debug(f"UV tool check failed: {e}")
186
+
187
+ return False
188
+
189
+ def _check_homebrew_installation(self) -> bool:
190
+ """
191
+ Check if claude-mpm is installed via Homebrew.
192
+
193
+ Detection methods:
194
+ 1. Check if executable path starts with /opt/homebrew/ or /usr/local/Cellar/
195
+ 2. Fallback: Run `brew list claude-mpm` to verify
196
+
197
+ Returns:
198
+ True if Homebrew installation detected
199
+ """
200
+ # Method 1: Check executable path
201
+ executable = sys.executable
202
+ if executable.startswith("/opt/homebrew/") or executable.startswith(
203
+ "/usr/local/Cellar/"
204
+ ):
205
+ return True
206
+
207
+ # Method 2: Fallback to `brew list` command
208
+ try:
209
+ result = subprocess.run(
210
+ ["brew", "list", "claude-mpm"],
211
+ check=False,
212
+ capture_output=True,
213
+ text=True,
214
+ timeout=5,
215
+ )
216
+ # brew list returns 0 if package is installed
217
+ if result.returncode == 0:
218
+ return True
219
+ except (FileNotFoundError, subprocess.TimeoutExpired):
220
+ # brew not installed or command failed
221
+ pass
222
+ except Exception as e:
223
+ self.logger.debug(f"Homebrew check failed: {e}")
224
+
225
+ return False
226
+
130
227
  def _get_claude_code_version(self) -> Optional[str]:
131
228
  """
132
229
  Get the installed Claude Code version.
@@ -257,6 +354,8 @@ class SelfUpgradeService:
257
354
  if self.installation_method in [
258
355
  InstallationMethod.PIP,
259
356
  InstallationMethod.PIPX,
357
+ InstallationMethod.UV_TOOL,
358
+ InstallationMethod.HOMEBREW,
260
359
  ]:
261
360
  result = await self.version_checker.check_for_update(
262
361
  "claude-mpm", self.current_version, cache_ttl
@@ -313,15 +412,18 @@ class SelfUpgradeService:
313
412
  Returns:
314
413
  Shell command string to upgrade claude-mpm
315
414
  """
316
- if self.installation_method == InstallationMethod.PIPX:
317
- return "pipx upgrade claude-mpm"
318
- if self.installation_method == InstallationMethod.NPM:
319
- return "npm update -g claude-mpm"
320
- if self.installation_method == InstallationMethod.PIP:
321
- return f"{sys.executable} -m pip install --upgrade claude-mpm"
322
- if self.installation_method == InstallationMethod.EDITABLE:
323
- return "git pull && pip install -e ."
324
- return "pip install --upgrade claude-mpm"
415
+ upgrade_commands = {
416
+ InstallationMethod.UV_TOOL: "uv tool upgrade claude-mpm",
417
+ InstallationMethod.HOMEBREW: "brew upgrade claude-mpm",
418
+ InstallationMethod.PIPX: "pipx upgrade claude-mpm",
419
+ InstallationMethod.NPM: "npm update -g claude-mpm",
420
+ InstallationMethod.PIP: f"{sys.executable} -m pip install --upgrade claude-mpm",
421
+ InstallationMethod.EDITABLE: "git pull && pip install -e .",
422
+ }
423
+
424
+ return upgrade_commands.get(
425
+ self.installation_method, "pip install --upgrade claude-mpm"
426
+ )
325
427
 
326
428
  def prompt_for_upgrade(self, update_info: Dict[str, any]) -> bool:
327
429
  """
@@ -432,7 +534,13 @@ class SelfUpgradeService:
432
534
  args = sys.argv[:]
433
535
 
434
536
  # Replace current process with new one
435
- if self.installation_method == InstallationMethod.PIPX:
537
+ if self.installation_method == InstallationMethod.UV_TOOL:
538
+ # Use uv run
539
+ os.execvp("uv", ["uv", "tool", "run", "claude-mpm", *args[1:]])
540
+ elif self.installation_method == InstallationMethod.HOMEBREW:
541
+ # Use direct executable (installed to PATH by Homebrew)
542
+ os.execvp("claude-mpm", args)
543
+ elif self.installation_method == InstallationMethod.PIPX:
436
544
  # Use pipx run
437
545
  os.execvp("pipx", ["pipx", "run", "claude-mpm", *args[1:]])
438
546
  elif self.installation_method == InstallationMethod.NPM:
@@ -3,6 +3,7 @@
3
3
  This package provides services for Git-based skills management:
4
4
  - GitSkillSourceManager: Multi-repository orchestration with priority resolution
5
5
  - SkillDiscoveryService: Parse skills from Git repositories (Markdown with YAML frontmatter)
6
+ - SkillToAgentMapper: Map skills to agents using YAML configuration
6
7
  """
7
8
 
8
9
  from claude_mpm.services.skills.git_skill_source_manager import GitSkillSourceManager
@@ -10,9 +11,11 @@ from claude_mpm.services.skills.skill_discovery_service import (
10
11
  SkillDiscoveryService,
11
12
  SkillMetadata,
12
13
  )
14
+ from claude_mpm.services.skills.skill_to_agent_mapper import SkillToAgentMapper
13
15
 
14
16
  __all__ = [
15
17
  "GitSkillSourceManager",
16
18
  "SkillDiscoveryService",
17
19
  "SkillMetadata",
20
+ "SkillToAgentMapper",
18
21
  ]