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.
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +4 -0
- claude_mpm/agents/BASE_AGENT.md +164 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +1 -1
- claude_mpm/agents/MEMORY.md +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +843 -900
- claude_mpm/agents/WORKFLOW.md +5 -254
- claude_mpm/agents/agent_loader.py +13 -44
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/frontmatter_validator.py +2 -2
- claude_mpm/agents/templates/circuit-breakers.md +138 -1
- claude_mpm/cli/__main__.py +4 -0
- claude_mpm/cli/chrome_devtools_installer.py +175 -0
- claude_mpm/cli/commands/agent_state_manager.py +18 -27
- claude_mpm/cli/commands/agents.py +9 -40
- claude_mpm/cli/commands/auto_configure.py +210 -25
- claude_mpm/cli/commands/config.py +88 -2
- claude_mpm/cli/commands/configure.py +1098 -159
- claude_mpm/cli/commands/configure_agent_display.py +25 -6
- claude_mpm/cli/commands/mpm_init/core.py +225 -46
- claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
- claude_mpm/cli/commands/postmortem.py +1 -1
- claude_mpm/cli/commands/profile.py +277 -0
- claude_mpm/cli/commands/skills.py +218 -197
- claude_mpm/cli/commands/summarize.py +413 -0
- claude_mpm/cli/executor.py +21 -3
- claude_mpm/cli/interactive/agent_wizard.py +2 -2
- claude_mpm/cli/parsers/agents_parser.py +0 -9
- claude_mpm/cli/parsers/auto_configure_parser.py +0 -138
- claude_mpm/cli/parsers/base_parser.py +12 -0
- claude_mpm/cli/parsers/config_parser.py +153 -83
- claude_mpm/cli/parsers/profile_parser.py +148 -0
- claude_mpm/cli/parsers/skills_parser.py +0 -5
- claude_mpm/cli/startup.py +876 -149
- claude_mpm/commands/mpm-config.md +28 -0
- claude_mpm/commands/mpm-doctor.md +9 -22
- claude_mpm/commands/mpm-help.md +5 -287
- claude_mpm/commands/mpm-init.md +81 -507
- claude_mpm/commands/mpm-monitor.md +15 -402
- claude_mpm/commands/mpm-organize.md +120 -0
- claude_mpm/commands/mpm-postmortem.md +6 -108
- claude_mpm/commands/mpm-session-resume.md +12 -363
- claude_mpm/commands/mpm-status.md +5 -69
- claude_mpm/commands/mpm-ticket-view.md +52 -495
- claude_mpm/commands/mpm-version.md +5 -107
- claude_mpm/config/agent_sources.py +27 -0
- claude_mpm/core/config.py +2 -4
- claude_mpm/core/framework/formatters/content_formatter.py +3 -13
- claude_mpm/core/framework/loaders/agent_loader.py +8 -5
- claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
- claude_mpm/core/framework_loader.py +4 -2
- claude_mpm/core/logger.py +13 -0
- claude_mpm/core/optimized_startup.py +59 -0
- claude_mpm/core/shared/config_loader.py +1 -1
- claude_mpm/core/socketio_pool.py +3 -3
- claude_mpm/core/unified_agent_registry.py +5 -15
- claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
- claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
- claude_mpm/dashboard/static/svelte-build/index.html +36 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +211 -78
- claude_mpm/hooks/claude_hooks/hook_handler.py +155 -1
- claude_mpm/hooks/claude_hooks/installer.py +33 -10
- claude_mpm/hooks/claude_hooks/memory_integration.py +26 -9
- claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +30 -6
- claude_mpm/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/hooks/memory_integration_hook.py +46 -1
- claude_mpm/init.py +63 -19
- claude_mpm/models/git_repository.py +3 -3
- claude_mpm/scripts/claude-hook-handler.sh +58 -18
- claude_mpm/scripts/launch_monitor.py +93 -13
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/agent_recommendation_service.py +278 -0
- claude_mpm/services/agents/agent_review_service.py +280 -0
- claude_mpm/services/agents/cache_git_manager.py +6 -6
- claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -5
- claude_mpm/services/agents/deployment/agent_format_converter.py +23 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +32 -20
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
- claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
- claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +247 -35
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +392 -87
- claude_mpm/services/agents/git_source_manager.py +53 -4
- claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
- claude_mpm/services/agents/recommender.py +5 -3
- claude_mpm/services/agents/single_tier_deployment_service.py +2 -2
- claude_mpm/services/agents/sources/git_source_sync_service.py +120 -7
- claude_mpm/services/agents/startup_sync.py +22 -2
- claude_mpm/services/agents/toolchain_detector.py +10 -6
- claude_mpm/services/analysis/__init__.py +11 -1
- claude_mpm/services/analysis/clone_detector.py +1030 -0
- claude_mpm/services/command_deployment_service.py +81 -10
- claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +1 -1
- claude_mpm/services/event_bus/config.py +3 -1
- claude_mpm/services/git/git_operations_service.py +101 -16
- claude_mpm/services/monitor/daemon.py +9 -2
- claude_mpm/services/monitor/daemon_manager.py +39 -3
- claude_mpm/services/monitor/management/lifecycle.py +8 -1
- claude_mpm/services/monitor/server.py +698 -22
- claude_mpm/services/pm_skills_deployer.py +711 -0
- claude_mpm/services/profile_manager.py +331 -0
- claude_mpm/services/self_upgrade_service.py +120 -12
- claude_mpm/services/skills/__init__.py +3 -0
- claude_mpm/services/skills/git_skill_source_manager.py +130 -2
- claude_mpm/services/skills/selective_skill_deployer.py +704 -0
- claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
- claude_mpm/services/skills_deployer.py +127 -9
- claude_mpm/services/socketio/dashboard_server.py +1 -0
- claude_mpm/services/socketio/event_normalizer.py +51 -6
- claude_mpm/services/socketio/server/core.py +386 -108
- claude_mpm/services/version_control/git_operations.py +103 -0
- claude_mpm/skills/skill_manager.py +92 -3
- claude_mpm/utils/agent_dependency_loader.py +14 -2
- claude_mpm/utils/agent_filters.py +17 -44
- claude_mpm/utils/migration.py +4 -4
- claude_mpm/utils/robust_installer.py +47 -3
- {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/METADATA +53 -87
- {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/RECORD +157 -197
- claude_mpm-5.4.48.dist-info/entry_points.txt +5 -0
- claude_mpm-5.4.48.dist-info/licenses/LICENSE +94 -0
- claude_mpm-5.4.48.dist-info/licenses/LICENSE-FAQ.md +153 -0
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
- claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
- claude_mpm/agents/BASE_OPS.md +0 -219
- claude_mpm/agents/BASE_PM.md +0 -480
- claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
- claude_mpm/agents/BASE_QA.md +0 -167
- claude_mpm/agents/BASE_RESEARCH.md +0 -53
- claude_mpm/agents/base_agent_loader.py +0 -601
- claude_mpm/cli/commands/agents_detect.py +0 -380
- claude_mpm/cli/commands/agents_recommend.py +0 -309
- claude_mpm/cli/ticket_cli.py +0 -35
- claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
- claude_mpm/commands/mpm-agents-detect.md +0 -177
- claude_mpm/commands/mpm-agents-list.md +0 -131
- claude_mpm/commands/mpm-agents-recommend.md +0 -223
- claude_mpm/commands/mpm-config-view.md +0 -150
- claude_mpm/commands/mpm-ticket-organize.md +0 -304
- claude_mpm/dashboard/analysis_runner.py +0 -455
- claude_mpm/dashboard/index.html +0 -13
- claude_mpm/dashboard/open_dashboard.py +0 -66
- claude_mpm/dashboard/static/css/activity.css +0 -1958
- claude_mpm/dashboard/static/css/connection-status.css +0 -370
- claude_mpm/dashboard/static/css/dashboard.css +0 -4701
- claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
- claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
- claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
- claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
- claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
- claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
- claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
- claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
- claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
- claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
- claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
- claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
- claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
- claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
- claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
- claude_mpm/dashboard/static/js/connection-manager.js +0 -536
- claude_mpm/dashboard/static/js/dashboard.js +0 -1914
- claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
- claude_mpm/dashboard/static/js/socket-client.js +0 -1474
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
- claude_mpm/dashboard/static/socket.io.min.js +0 -7
- claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
- claude_mpm/dashboard/templates/code_simple.html +0 -153
- claude_mpm/dashboard/templates/index.html +0 -606
- claude_mpm/dashboard/test_dashboard.html +0 -372
- claude_mpm/scripts/mcp_server.py +0 -75
- claude_mpm/scripts/mcp_wrapper.py +0 -39
- claude_mpm/services/mcp_gateway/__init__.py +0 -159
- claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
- claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
- claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
- claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
- claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
- claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
- claude_mpm/services/mcp_gateway/core/base.py +0 -312
- claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
- claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
- claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
- claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
- claude_mpm/services/mcp_gateway/main.py +0 -589
- claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
- claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
- claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
- claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
- claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
- claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
- claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
- claude_mpm-5.1.9.dist-info/entry_points.txt +0 -10
- claude_mpm-5.1.9.dist-info/licenses/LICENSE +0 -21
- {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/WHEEL +0 -0
- {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.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
|
|
@@ -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
|
|
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
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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.
|
|
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
|
]
|