claude-mpm 5.0.9__py3-none-any.whl → 5.6.23__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_OUTPUT_STYLE.md +115 -0
- claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +186 -0
- claude_mpm/agents/MEMORY.md +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +479 -616
- claude_mpm/agents/WORKFLOW.md +6 -253
- claude_mpm/agents/agent_loader.py +13 -44
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/frontmatter_validator.py +70 -2
- claude_mpm/agents/templates/circuit-breakers.md +457 -62
- claude_mpm/cli/__init__.py +5 -2
- 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 +177 -41
- claude_mpm/cli/commands/agents_reconcile.py +197 -0
- claude_mpm/cli/commands/auto_configure.py +723 -236
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/config.py +88 -2
- claude_mpm/cli/commands/configure.py +1874 -170
- claude_mpm/cli/commands/configure_agent_display.py +27 -6
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +232 -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 +276 -0
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +379 -204
- claude_mpm/cli/commands/summarize.py +413 -0
- claude_mpm/cli/executor.py +141 -19
- claude_mpm/cli/interactive/__init__.py +10 -0
- claude_mpm/cli/interactive/agent_wizard.py +115 -60
- claude_mpm/cli/interactive/questionary_styles.py +65 -0
- claude_mpm/cli/interactive/skill_selector.py +481 -0
- claude_mpm/cli/parsers/agents_parser.py +54 -9
- claude_mpm/cli/parsers/auto_configure_parser.py +13 -138
- claude_mpm/cli/parsers/base_parser.py +88 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/config_parser.py +153 -83
- claude_mpm/cli/parsers/profile_parser.py +147 -0
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +1 -1
- claude_mpm/cli/startup.py +1017 -266
- claude_mpm/cli/startup_display.py +74 -6
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +78 -0
- claude_mpm/commander/adapters/__init__.py +60 -0
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +288 -0
- claude_mpm/commander/adapters/claude_code.py +392 -0
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/adapters/example_usage.py +310 -0
- claude_mpm/commander/adapters/mpm.py +389 -0
- claude_mpm/commander/adapters/registry.py +204 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +121 -0
- claude_mpm/commander/api/errors.py +133 -0
- claude_mpm/commander/api/routes/__init__.py +8 -0
- claude_mpm/commander/api/routes/events.py +184 -0
- claude_mpm/commander/api/routes/inbox.py +171 -0
- claude_mpm/commander/api/routes/messages.py +148 -0
- claude_mpm/commander/api/routes/projects.py +271 -0
- claude_mpm/commander/api/routes/sessions.py +226 -0
- claude_mpm/commander/api/routes/work.py +296 -0
- claude_mpm/commander/api/schemas.py +186 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +146 -0
- claude_mpm/commander/chat/commands.py +96 -0
- claude_mpm/commander/chat/repl.py +310 -0
- claude_mpm/commander/config.py +51 -0
- claude_mpm/commander/config_loader.py +115 -0
- claude_mpm/commander/core/__init__.py +10 -0
- claude_mpm/commander/core/block_manager.py +325 -0
- claude_mpm/commander/core/response_manager.py +323 -0
- claude_mpm/commander/daemon.py +603 -0
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/__init__.py +26 -0
- claude_mpm/commander/events/manager.py +332 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +146 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +62 -0
- claude_mpm/commander/inbox/__init__.py +16 -0
- claude_mpm/commander/inbox/dedup.py +128 -0
- claude_mpm/commander/inbox/inbox.py +224 -0
- claude_mpm/commander/inbox/models.py +70 -0
- claude_mpm/commander/instance_manager.py +450 -0
- claude_mpm/commander/llm/__init__.py +6 -0
- claude_mpm/commander/llm/openrouter_client.py +167 -0
- claude_mpm/commander/llm/summarizer.py +70 -0
- claude_mpm/commander/memory/__init__.py +45 -0
- claude_mpm/commander/memory/compression.py +347 -0
- claude_mpm/commander/memory/embeddings.py +230 -0
- claude_mpm/commander/memory/entities.py +310 -0
- claude_mpm/commander/memory/example_usage.py +290 -0
- claude_mpm/commander/memory/integration.py +325 -0
- claude_mpm/commander/memory/search.py +381 -0
- claude_mpm/commander/memory/store.py +657 -0
- claude_mpm/commander/models/__init__.py +18 -0
- claude_mpm/commander/models/events.py +121 -0
- claude_mpm/commander/models/project.py +162 -0
- claude_mpm/commander/models/work.py +214 -0
- claude_mpm/commander/parsing/__init__.py +20 -0
- claude_mpm/commander/parsing/extractor.py +132 -0
- claude_mpm/commander/parsing/output_parser.py +270 -0
- claude_mpm/commander/parsing/patterns.py +100 -0
- claude_mpm/commander/persistence/__init__.py +11 -0
- claude_mpm/commander/persistence/event_store.py +274 -0
- claude_mpm/commander/persistence/state_store.py +309 -0
- claude_mpm/commander/persistence/work_store.py +164 -0
- claude_mpm/commander/polling/__init__.py +13 -0
- claude_mpm/commander/polling/event_detector.py +104 -0
- claude_mpm/commander/polling/output_buffer.py +49 -0
- claude_mpm/commander/polling/output_poller.py +153 -0
- claude_mpm/commander/project_session.py +268 -0
- claude_mpm/commander/proxy/__init__.py +12 -0
- claude_mpm/commander/proxy/formatter.py +89 -0
- claude_mpm/commander/proxy/output_handler.py +191 -0
- claude_mpm/commander/proxy/relay.py +155 -0
- claude_mpm/commander/registry.py +410 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +346 -0
- claude_mpm/commander/session/__init__.py +6 -0
- claude_mpm/commander/session/context.py +81 -0
- claude_mpm/commander/session/manager.py +59 -0
- claude_mpm/commander/tmux_orchestrator.py +361 -0
- claude_mpm/commander/web/__init__.py +1 -0
- claude_mpm/commander/work/__init__.py +30 -0
- claude_mpm/commander/work/executor.py +207 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +241 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +36 -0
- claude_mpm/commands/mpm-doctor.md +16 -21
- claude_mpm/commands/mpm-help.md +12 -286
- claude_mpm/commands/mpm-init.md +88 -506
- claude_mpm/commands/mpm-monitor.md +22 -401
- claude_mpm/commands/mpm-organize.md +128 -0
- claude_mpm/commands/mpm-postmortem.md +13 -107
- claude_mpm/commands/mpm-session-resume.md +20 -363
- claude_mpm/commands/mpm-status.md +13 -69
- claude_mpm/commands/mpm-ticket-view.md +60 -495
- claude_mpm/commands/mpm-version.md +13 -107
- claude_mpm/commands/mpm.md +8 -0
- claude_mpm/config/agent_presets.py +8 -7
- claude_mpm/config/agent_sources.py +27 -0
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +154 -2
- claude_mpm/core/config.py +37 -26
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- 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/hook_manager.py +51 -3
- claude_mpm/core/interactive_session.py +12 -11
- claude_mpm/core/logger.py +39 -9
- claude_mpm/core/logging_utils.py +35 -11
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/optimized_startup.py +61 -0
- claude_mpm/core/output_style_manager.py +219 -44
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/core/socketio_pool.py +16 -8
- claude_mpm/core/unified_agent_registry.py +134 -16
- claude_mpm/core/unified_config.py +76 -8
- claude_mpm/core/unified_paths.py +95 -90
- claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DR8nis88.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.RgBboRvH.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -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/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
- claude_mpm/experimental/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
- claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.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__/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/auto_pause_handler.py +485 -0
- claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +479 -128
- claude_mpm/hooks/claude_hooks/hook_handler.py +254 -83
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +149 -18
- claude_mpm/hooks/claude_hooks/memory_integration.py +67 -19
- claude_mpm/hooks/claude_hooks/response_tracking.py +44 -62
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.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 +69 -30
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +36 -103
- claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +73 -75
- claude_mpm/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/hooks/memory_integration_hook.py +46 -1
- claude_mpm/hooks/session_resume_hook.py +89 -1
- claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
- claude_mpm/init.py +276 -19
- claude_mpm/models/agent_definition.py +7 -0
- claude_mpm/models/git_repository.py +3 -3
- claude_mpm/scripts/claude-hook-handler.sh +87 -20
- claude_mpm/scripts/launch_monitor.py +93 -13
- claude_mpm/scripts/start_activity_logging.py +0 -0
- 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/agent_selection_service.py +2 -2
- claude_mpm/services/agents/cache_git_manager.py +7 -7
- claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
- claude_mpm/services/agents/deployment/agent_discovery_service.py +6 -5
- claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +42 -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/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +348 -29
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +570 -68
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +57 -4
- claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/recommender.py +5 -3
- claude_mpm/services/agents/single_tier_deployment_service.py +6 -6
- claude_mpm/services/agents/sources/git_source_sync_service.py +129 -11
- claude_mpm/services/agents/startup_sync.py +27 -4
- 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/cli/__init__.py +3 -0
- claude_mpm/services/cli/incremental_pause_manager.py +561 -0
- claude_mpm/services/cli/session_resume_helper.py +10 -2
- claude_mpm/services/command_deployment_service.py +81 -10
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +31 -1
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
- claude_mpm/services/diagnostics/models.py +14 -1
- claude_mpm/services/event_bus/config.py +3 -1
- claude_mpm/services/event_log.py +325 -0
- claude_mpm/services/git/git_operations_service.py +101 -16
- claude_mpm/services/infrastructure/__init__.py +4 -0
- claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
- claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
- claude_mpm/services/monitor/daemon.py +9 -2
- claude_mpm/services/monitor/daemon_manager.py +54 -7
- claude_mpm/services/monitor/management/lifecycle.py +15 -3
- claude_mpm/services/monitor/server.py +796 -30
- claude_mpm/services/pm_skills_deployer.py +884 -0
- claude_mpm/services/profile_manager.py +337 -0
- claude_mpm/services/project/project_organizer.py +4 -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 +303 -12
- claude_mpm/services/skills/selective_skill_deployer.py +869 -0
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
- claude_mpm/services/skills_deployer.py +294 -55
- claude_mpm/services/socketio/dashboard_server.py +1 -0
- claude_mpm/services/socketio/event_normalizer.py +51 -6
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/core.py +386 -108
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/services/version_control/git_operations.py +103 -0
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +112 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +98 -3
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- claude_mpm/utils/agent_dependency_loader.py +115 -4
- claude_mpm/utils/agent_filters.py +17 -44
- claude_mpm/utils/gitignore.py +3 -0
- claude_mpm/utils/migration.py +4 -4
- claude_mpm/utils/robust_installer.py +86 -21
- claude_mpm-5.6.23.dist-info/METADATA +393 -0
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/RECORD +508 -261
- claude_mpm-5.6.23.dist-info/entry_points.txt +5 -0
- claude_mpm-5.6.23.dist-info/licenses/LICENSE +94 -0
- claude_mpm-5.6.23.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/OUTPUT_STYLE.md +0 -290
- claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +0 -1322
- 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/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- 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.0.9.dist-info/METADATA +0 -1028
- claude_mpm-5.0.9.dist-info/entry_points.txt +0 -10
- claude_mpm-5.0.9.dist-info/licenses/LICENSE +0 -21
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/WHEEL +0 -0
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,869 @@
|
|
|
1
|
+
"""Selective skill deployment based on agent requirements.
|
|
2
|
+
|
|
3
|
+
WHY: Agents now have a skills field in their frontmatter. We should only deploy
|
|
4
|
+
skills that agents actually reference, reducing deployed skills from ~78 to ~20
|
|
5
|
+
for a typical project.
|
|
6
|
+
|
|
7
|
+
DESIGN DECISIONS:
|
|
8
|
+
- Dual-source skill discovery:
|
|
9
|
+
1. Explicit frontmatter declarations (skills: field)
|
|
10
|
+
2. SkillToAgentMapper inference (pattern-based)
|
|
11
|
+
- Support both legacy flat list and new required/optional dict formats
|
|
12
|
+
- Parse YAML frontmatter from agent markdown files
|
|
13
|
+
- Combine explicit + inferred skills for comprehensive coverage
|
|
14
|
+
- Return set of unique skill names for filtering
|
|
15
|
+
- Track deployed skills in .mpm-deployed-skills.json index
|
|
16
|
+
- Remove orphaned skills (deployed by mpm but no longer referenced)
|
|
17
|
+
|
|
18
|
+
FORMATS SUPPORTED:
|
|
19
|
+
1. Legacy: skills: [skill-a, skill-b, ...]
|
|
20
|
+
2. New: skills: {required: [...], optional: [...]}
|
|
21
|
+
|
|
22
|
+
SKILL DISCOVERY FLOW:
|
|
23
|
+
1. Scan deployed agents (.claude/agents/*.md)
|
|
24
|
+
2. Extract frontmatter skills (explicit declarations)
|
|
25
|
+
3. Query SkillToAgentMapper for pattern-based skills
|
|
26
|
+
4. Combine both sources into unified set
|
|
27
|
+
|
|
28
|
+
DEPLOYMENT TRACKING:
|
|
29
|
+
1. Track which skills were deployed by claude-mpm in index file
|
|
30
|
+
2. Update index after each deployment operation
|
|
31
|
+
3. Clean up orphaned skills no longer referenced by agents
|
|
32
|
+
|
|
33
|
+
References:
|
|
34
|
+
- Feature: Progressive skills discovery (#117)
|
|
35
|
+
- Service: SkillToAgentMapper (skill_to_agent_mapper.py)
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
import json
|
|
39
|
+
import re
|
|
40
|
+
from datetime import datetime, timezone
|
|
41
|
+
from pathlib import Path
|
|
42
|
+
from typing import Any, Dict, List, Set, Tuple
|
|
43
|
+
|
|
44
|
+
import yaml
|
|
45
|
+
|
|
46
|
+
from claude_mpm.core.logging_config import get_logger
|
|
47
|
+
|
|
48
|
+
logger = get_logger(__name__)
|
|
49
|
+
|
|
50
|
+
# Deployment tracking index file
|
|
51
|
+
DEPLOYED_INDEX_FILE = ".mpm-deployed-skills.json"
|
|
52
|
+
|
|
53
|
+
# Core PM skills that should always be deployed
|
|
54
|
+
# These are referenced in PM_INSTRUCTIONS.md with [SKILL: name] markers
|
|
55
|
+
# Without these skills, PM only sees placeholders, not actual content
|
|
56
|
+
PM_CORE_SKILLS = {
|
|
57
|
+
"mpm-delegation-patterns",
|
|
58
|
+
"mpm-verification-protocols",
|
|
59
|
+
"mpm-tool-usage-guide",
|
|
60
|
+
"mpm-git-file-tracking",
|
|
61
|
+
"mpm-pr-workflow",
|
|
62
|
+
"mpm-ticketing-integration",
|
|
63
|
+
"mpm-teaching-mode",
|
|
64
|
+
"mpm-bug-reporting",
|
|
65
|
+
"mpm-circuit-breaker-enforcement",
|
|
66
|
+
"mpm-session-management",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# Core skills that are universally useful across all projects
|
|
70
|
+
# These are deployed when skill mapping returns too many skills (>60)
|
|
71
|
+
# Target: ~25-30 core skills for balanced functionality
|
|
72
|
+
CORE_SKILLS = {
|
|
73
|
+
# Universal debugging and verification (4 skills)
|
|
74
|
+
"universal-debugging-systematic-debugging",
|
|
75
|
+
"universal-debugging-verification-before-completion",
|
|
76
|
+
"universal-verification-pre-merge",
|
|
77
|
+
"universal-verification-screenshot",
|
|
78
|
+
# Universal testing patterns (2 skills)
|
|
79
|
+
"universal-testing-test-driven-development",
|
|
80
|
+
"universal-testing-testing-anti-patterns",
|
|
81
|
+
# Universal architecture and design (1 skill)
|
|
82
|
+
"universal-architecture-software-patterns",
|
|
83
|
+
# Universal infrastructure (3 skills)
|
|
84
|
+
"universal-infrastructure-env-manager",
|
|
85
|
+
"universal-infrastructure-docker",
|
|
86
|
+
"universal-infrastructure-github-actions",
|
|
87
|
+
# Universal collaboration (1 skill)
|
|
88
|
+
"universal-collaboration-stacked-prs",
|
|
89
|
+
# Universal emergency/operations (1 skill)
|
|
90
|
+
"toolchains-universal-emergency-release",
|
|
91
|
+
"toolchains-universal-dependency-audit",
|
|
92
|
+
# Common language toolchains (6 skills)
|
|
93
|
+
"toolchains-typescript-core",
|
|
94
|
+
"toolchains-python-core",
|
|
95
|
+
"toolchains-javascript-tooling-biome",
|
|
96
|
+
"toolchains-python-tooling-mypy",
|
|
97
|
+
"toolchains-typescript-testing-vitest",
|
|
98
|
+
"toolchains-python-frameworks-flask",
|
|
99
|
+
# Common web frameworks (4 skills)
|
|
100
|
+
"toolchains-javascript-frameworks-nextjs",
|
|
101
|
+
"toolchains-nextjs-core",
|
|
102
|
+
"toolchains-typescript-frameworks-nodejs-backend",
|
|
103
|
+
"toolchains-javascript-frameworks-react-state-machine",
|
|
104
|
+
# Common testing tools (2 skills)
|
|
105
|
+
"toolchains-javascript-testing-playwright",
|
|
106
|
+
"toolchains-typescript-testing-jest",
|
|
107
|
+
# Common data/UI tools (3 skills)
|
|
108
|
+
"universal-data-xlsx",
|
|
109
|
+
"toolchains-ui-styling-tailwind",
|
|
110
|
+
"toolchains-ui-components-headlessui",
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def parse_agent_frontmatter(agent_file: Path) -> Dict[str, Any]:
|
|
115
|
+
"""Parse YAML frontmatter from agent markdown file.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
agent_file: Path to agent markdown file
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Parsed frontmatter as dictionary, or empty dict if parsing fails
|
|
122
|
+
|
|
123
|
+
Example:
|
|
124
|
+
>>> frontmatter = parse_agent_frontmatter(Path("agent.md"))
|
|
125
|
+
>>> skills = frontmatter.get('skills', [])
|
|
126
|
+
"""
|
|
127
|
+
try:
|
|
128
|
+
content = agent_file.read_text(encoding="utf-8")
|
|
129
|
+
except Exception as e:
|
|
130
|
+
logger.warning(f"Failed to read {agent_file}: {e}")
|
|
131
|
+
return {}
|
|
132
|
+
|
|
133
|
+
# Match YAML frontmatter between --- delimiters
|
|
134
|
+
match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
|
|
135
|
+
if not match:
|
|
136
|
+
logger.debug(f"No frontmatter found in {agent_file}")
|
|
137
|
+
return {}
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
frontmatter = yaml.safe_load(match.group(1))
|
|
141
|
+
return frontmatter or {}
|
|
142
|
+
except yaml.YAMLError as e:
|
|
143
|
+
logger.warning(f"Failed to parse frontmatter in {agent_file}: {e}")
|
|
144
|
+
return {}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def get_skills_from_agent(frontmatter: Dict[str, Any]) -> Set[str]:
|
|
148
|
+
"""Extract skill names from agent frontmatter (handles both formats).
|
|
149
|
+
|
|
150
|
+
Supports both legacy and new formats:
|
|
151
|
+
- Legacy: skills: [skill-a, skill-b, ...]
|
|
152
|
+
- New: skills: {required: [...], optional: [...]}
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
frontmatter: Parsed agent frontmatter
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
Set of unique skill names
|
|
159
|
+
|
|
160
|
+
Example:
|
|
161
|
+
>>> # Legacy format
|
|
162
|
+
>>> frontmatter = {'skills': ['skill-a', 'skill-b']}
|
|
163
|
+
>>> get_skills_from_agent(frontmatter)
|
|
164
|
+
{'skill-a', 'skill-b'}
|
|
165
|
+
|
|
166
|
+
>>> # New format
|
|
167
|
+
>>> frontmatter = {'skills': {'required': ['skill-a'], 'optional': ['skill-b']}}
|
|
168
|
+
>>> get_skills_from_agent(frontmatter)
|
|
169
|
+
{'skill-a', 'skill-b'}
|
|
170
|
+
"""
|
|
171
|
+
skills_field = frontmatter.get("skills")
|
|
172
|
+
|
|
173
|
+
# Handle None or missing skills field
|
|
174
|
+
if skills_field is None:
|
|
175
|
+
return set()
|
|
176
|
+
|
|
177
|
+
# New format: {required: [...], optional: [...]}
|
|
178
|
+
if isinstance(skills_field, dict):
|
|
179
|
+
required = skills_field.get("required") or []
|
|
180
|
+
optional = skills_field.get("optional") or []
|
|
181
|
+
|
|
182
|
+
# Ensure both are lists
|
|
183
|
+
if not isinstance(required, list):
|
|
184
|
+
required = []
|
|
185
|
+
if not isinstance(optional, list):
|
|
186
|
+
optional = []
|
|
187
|
+
|
|
188
|
+
return set(required + optional)
|
|
189
|
+
|
|
190
|
+
# Legacy format: [skill1, skill2, ...]
|
|
191
|
+
if isinstance(skills_field, list):
|
|
192
|
+
return set(skills_field)
|
|
193
|
+
|
|
194
|
+
# Unsupported format
|
|
195
|
+
logger.warning(f"Unexpected skills field type: {type(skills_field)}")
|
|
196
|
+
return set()
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def get_skills_from_mapping(agent_ids: List[str]) -> Set[str]:
|
|
200
|
+
"""Get skills for agents using SkillToAgentMapper inference.
|
|
201
|
+
|
|
202
|
+
DEPRECATED: This function is deprecated as of Phase 3 refactor.
|
|
203
|
+
Skills are now declared exclusively in agent frontmatter.
|
|
204
|
+
|
|
205
|
+
The static skill_to_agent_mapping.yaml is no longer used for skill deployment.
|
|
206
|
+
Each agent must declare its skills in frontmatter or it gets zero skills.
|
|
207
|
+
|
|
208
|
+
This function remains for backward compatibility but is NO LONGER CALLED
|
|
209
|
+
by get_required_skills_from_agents().
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
agent_ids: List of DEPLOYED agent identifiers (e.g., ["python-engineer", "typescript-engineer"])
|
|
213
|
+
These should be extracted from ~/.claude/agents/*.md files only.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
Set of unique skill names inferred from mapping configuration for DEPLOYED agents only
|
|
217
|
+
NOTE: This is now an empty set as the function is deprecated.
|
|
218
|
+
|
|
219
|
+
Example:
|
|
220
|
+
>>> # DEPRECATED - use frontmatter instead
|
|
221
|
+
>>> deployed_agent_ids = ["python-engineer", "typescript-engineer", "qa"]
|
|
222
|
+
>>> skills = get_skills_from_mapping(deployed_agent_ids) # Returns empty set
|
|
223
|
+
"""
|
|
224
|
+
# DEPRECATED: Return empty set
|
|
225
|
+
logger.warning(
|
|
226
|
+
"get_skills_from_mapping() is DEPRECATED and returns empty set. "
|
|
227
|
+
"Skills are now declared in agent frontmatter only. "
|
|
228
|
+
"Update your agents with 'skills:' field in frontmatter."
|
|
229
|
+
)
|
|
230
|
+
return set()
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def extract_skills_from_content(agent_file: Path) -> Set[str]:
|
|
234
|
+
"""Extract skill names from [SKILL: skill-name] markers in agent file content.
|
|
235
|
+
|
|
236
|
+
This function complements frontmatter skill extraction by finding inline
|
|
237
|
+
skill references in the agent's markdown content body.
|
|
238
|
+
|
|
239
|
+
Supports multiple formats:
|
|
240
|
+
- Bold marker: **[SKILL: skill-name]**
|
|
241
|
+
- Plain marker: [SKILL: skill-name]
|
|
242
|
+
- Backtick list: - `skill-name` - Description
|
|
243
|
+
- With spaces: [SKILL: skill-name ]
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
agent_file: Path to agent markdown file
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Set of skill names found in content body
|
|
250
|
+
|
|
251
|
+
Example:
|
|
252
|
+
>>> skills = extract_skills_from_content(Path("pm.md"))
|
|
253
|
+
>>> # Finds skills from markers like **[SKILL: mpm-delegation-patterns]**
|
|
254
|
+
>>> # Also finds from lists like - `mpm-teaching-mode` - Description
|
|
255
|
+
>>> print(f"Found {len(skills)} skills in content")
|
|
256
|
+
"""
|
|
257
|
+
try:
|
|
258
|
+
content = agent_file.read_text(encoding="utf-8")
|
|
259
|
+
except Exception as e:
|
|
260
|
+
logger.warning(f"Failed to read {agent_file}: {e}")
|
|
261
|
+
return set()
|
|
262
|
+
|
|
263
|
+
skills = set()
|
|
264
|
+
|
|
265
|
+
# Pattern 1: [SKILL: skill-name] markers (with optional markdown bold)
|
|
266
|
+
# Handles: **[SKILL: skill-name]** or [SKILL: skill-name]
|
|
267
|
+
# Pattern breakdown:
|
|
268
|
+
# - \*{0,2}: Optional bold markdown (0-2 asterisks)
|
|
269
|
+
# - \[SKILL:\s*: Opening bracket with optional whitespace
|
|
270
|
+
# - ([a-zA-Z0-9_-]+): Skill name (capture group)
|
|
271
|
+
# - \s*\]: Closing bracket with optional whitespace
|
|
272
|
+
# - \*{0,2}: Optional closing bold markdown
|
|
273
|
+
pattern1 = r"\*{0,2}\[SKILL:\s*([a-zA-Z0-9_-]+)\s*\]\*{0,2}"
|
|
274
|
+
matches1 = re.findall(pattern1, content, re.IGNORECASE)
|
|
275
|
+
skills.update(matches1)
|
|
276
|
+
|
|
277
|
+
# Pattern 2: Backtick list items with mpm-* or toolchains-* skills
|
|
278
|
+
# Handles: - `mpm-skill-name` - Description
|
|
279
|
+
# Pattern breakdown:
|
|
280
|
+
# - ^-\s+: Start with dash and whitespace (list item)
|
|
281
|
+
# - `: Opening backtick
|
|
282
|
+
# - ((?:mpm-|toolchains-|universal-)[a-zA-Z0-9_-]+): Skill name starting with prefix
|
|
283
|
+
# - `: Closing backtick
|
|
284
|
+
# - \s+-: Followed by whitespace and dash (description separator)
|
|
285
|
+
pattern2 = r"^-\s+`((?:mpm-|toolchains-|universal-)[a-zA-Z0-9_-]+)`\s+-"
|
|
286
|
+
matches2 = re.findall(pattern2, content, re.MULTILINE | re.IGNORECASE)
|
|
287
|
+
skills.update(matches2)
|
|
288
|
+
|
|
289
|
+
if skills:
|
|
290
|
+
logger.debug(
|
|
291
|
+
f"Found {len(skills)} skills from content markers in {agent_file.name}"
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
return skills
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def get_required_skills_from_agents(agents_dir: Path) -> Set[str]:
|
|
298
|
+
"""Extract all skills referenced by deployed agents.
|
|
299
|
+
|
|
300
|
+
MAJOR CHANGE (Phase 3): Now uses TWO sources for skill discovery:
|
|
301
|
+
1. Frontmatter-declared skills (skills: field)
|
|
302
|
+
2. Content body markers ([SKILL: skill-name])
|
|
303
|
+
|
|
304
|
+
The static skill_to_agent_mapping.yaml is DEPRECATED. Each agent must
|
|
305
|
+
declare its skills via frontmatter OR inline markers.
|
|
306
|
+
|
|
307
|
+
This change:
|
|
308
|
+
- Eliminates dual-source complexity (frontmatter + mapping)
|
|
309
|
+
- Makes skill requirements explicit per agent
|
|
310
|
+
- Enables per-agent customization via frontmatter or inline markers
|
|
311
|
+
- Removes dependency on static YAML mapping
|
|
312
|
+
- Fixes PM skills being removed as orphaned (they use inline markers)
|
|
313
|
+
|
|
314
|
+
Special handling for PM_INSTRUCTIONS.md:
|
|
315
|
+
- Also scans .claude-mpm/PM_INSTRUCTIONS.md for skill markers
|
|
316
|
+
- PM instructions are not in agents_dir but contain [SKILL: ...] references
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
agents_dir: Path to deployed agents directory (e.g., .claude/agents/)
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
Set of unique skill names referenced across all agents
|
|
323
|
+
|
|
324
|
+
Example:
|
|
325
|
+
>>> agents_dir = Path(".claude/agents")
|
|
326
|
+
>>> required_skills = get_required_skills_from_agents(agents_dir)
|
|
327
|
+
>>> print(f"Found {len(required_skills)} unique skills")
|
|
328
|
+
"""
|
|
329
|
+
if not agents_dir.exists():
|
|
330
|
+
logger.warning(f"Agents directory not found: {agents_dir}")
|
|
331
|
+
return set()
|
|
332
|
+
|
|
333
|
+
# Scan all agent markdown files
|
|
334
|
+
agent_files = list(agents_dir.glob("*.md"))
|
|
335
|
+
|
|
336
|
+
# Special case: Add PM_INSTRUCTIONS.md if it exists
|
|
337
|
+
# PM instructions live in .claude-mpm/ not .claude/agents/
|
|
338
|
+
pm_instructions = agents_dir.parent.parent / ".claude-mpm" / "PM_INSTRUCTIONS.md"
|
|
339
|
+
if pm_instructions.exists():
|
|
340
|
+
agent_files.append(pm_instructions)
|
|
341
|
+
logger.debug("Added PM_INSTRUCTIONS.md for skill scanning")
|
|
342
|
+
|
|
343
|
+
logger.debug(f"Scanning {len(agent_files)} agent files (including PM instructions)")
|
|
344
|
+
|
|
345
|
+
# Use TWO sources: frontmatter AND content markers
|
|
346
|
+
frontmatter_skills = set()
|
|
347
|
+
content_skills = set()
|
|
348
|
+
|
|
349
|
+
for agent_file in agent_files:
|
|
350
|
+
agent_id = agent_file.stem
|
|
351
|
+
|
|
352
|
+
# Source 1: Extract from frontmatter
|
|
353
|
+
frontmatter = parse_agent_frontmatter(agent_file)
|
|
354
|
+
agent_fm_skills = get_skills_from_agent(frontmatter)
|
|
355
|
+
|
|
356
|
+
if agent_fm_skills:
|
|
357
|
+
frontmatter_skills.update(agent_fm_skills)
|
|
358
|
+
logger.debug(
|
|
359
|
+
f"Agent {agent_id}: {len(agent_fm_skills)} skills from frontmatter"
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
# Source 2: Extract from content body [SKILL: ...] markers
|
|
363
|
+
agent_content_skills = extract_skills_from_content(agent_file)
|
|
364
|
+
|
|
365
|
+
if agent_content_skills:
|
|
366
|
+
content_skills.update(agent_content_skills)
|
|
367
|
+
logger.debug(
|
|
368
|
+
f"Agent {agent_id}: {len(agent_content_skills)} skills from content markers"
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
if not agent_fm_skills and not agent_content_skills:
|
|
372
|
+
logger.debug(
|
|
373
|
+
f"Agent {agent_id}: No skills declared (checked frontmatter + content)"
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
# Combine both sources
|
|
377
|
+
all_skills = frontmatter_skills | content_skills
|
|
378
|
+
|
|
379
|
+
logger.info(
|
|
380
|
+
f"Found {len(all_skills)} unique skills "
|
|
381
|
+
f"({len(frontmatter_skills)} from frontmatter, "
|
|
382
|
+
f"{len(content_skills)} from content markers)"
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
# Normalize skill paths: convert slashes to dashes for compatibility with deployment
|
|
386
|
+
# Some skills may use slash format, normalize to dashes
|
|
387
|
+
normalized_skills = {skill.replace("/", "-") for skill in all_skills}
|
|
388
|
+
|
|
389
|
+
if normalized_skills != all_skills:
|
|
390
|
+
logger.debug(
|
|
391
|
+
f"Normalized {len(all_skills)} skills to {len(normalized_skills)} "
|
|
392
|
+
"(converted slashes to dashes)"
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
# Always include PM core skills to ensure PM_INSTRUCTIONS.md markers are resolved
|
|
396
|
+
# These skills are referenced in PM_INSTRUCTIONS.md and must be deployed
|
|
397
|
+
# for PM to see actual content instead of [SKILL: name] placeholders
|
|
398
|
+
before_pm_skills = len(normalized_skills)
|
|
399
|
+
normalized_skills = normalized_skills | PM_CORE_SKILLS
|
|
400
|
+
pm_skills_added = len(normalized_skills) - before_pm_skills
|
|
401
|
+
|
|
402
|
+
if pm_skills_added > 0:
|
|
403
|
+
logger.info(
|
|
404
|
+
f"Added {pm_skills_added} PM core skills to ensure PM_INSTRUCTIONS.md markers resolve"
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
return normalized_skills
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
# === Deployment Tracking Functions ===
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def load_deployment_index(claude_skills_dir: Path) -> Dict[str, Any]:
|
|
414
|
+
"""Load deployment tracking index from ~/.claude/skills/.
|
|
415
|
+
|
|
416
|
+
Args:
|
|
417
|
+
claude_skills_dir: Path to Claude skills directory (~/.claude/skills/)
|
|
418
|
+
|
|
419
|
+
Returns:
|
|
420
|
+
Dict containing:
|
|
421
|
+
- deployed_skills: Dict mapping skill name to deployment metadata
|
|
422
|
+
- user_requested_skills: List of skill names manually requested by user
|
|
423
|
+
- last_sync: ISO timestamp of last sync operation
|
|
424
|
+
|
|
425
|
+
Example:
|
|
426
|
+
>>> index = load_deployment_index(Path.home() / ".claude" / "skills")
|
|
427
|
+
>>> print(f"Tracked skills: {len(index['deployed_skills'])}")
|
|
428
|
+
"""
|
|
429
|
+
index_path = claude_skills_dir / DEPLOYED_INDEX_FILE
|
|
430
|
+
|
|
431
|
+
if not index_path.exists():
|
|
432
|
+
logger.debug(f"No deployment index found at {index_path}, creating new")
|
|
433
|
+
return {"deployed_skills": {}, "user_requested_skills": [], "last_sync": None}
|
|
434
|
+
|
|
435
|
+
try:
|
|
436
|
+
with open(index_path, encoding="utf-8") as f:
|
|
437
|
+
index = json.load(f)
|
|
438
|
+
|
|
439
|
+
# Ensure required keys exist
|
|
440
|
+
if "deployed_skills" not in index:
|
|
441
|
+
index["deployed_skills"] = {}
|
|
442
|
+
if "user_requested_skills" not in index:
|
|
443
|
+
index["user_requested_skills"] = []
|
|
444
|
+
if "last_sync" not in index:
|
|
445
|
+
index["last_sync"] = None
|
|
446
|
+
|
|
447
|
+
logger.debug(
|
|
448
|
+
f"Loaded deployment index: {len(index['deployed_skills'])} tracked skills, "
|
|
449
|
+
f"{len(index['user_requested_skills'])} user-requested"
|
|
450
|
+
)
|
|
451
|
+
return index
|
|
452
|
+
|
|
453
|
+
except (json.JSONDecodeError, OSError) as e:
|
|
454
|
+
logger.warning(f"Failed to load deployment index: {e}, creating new")
|
|
455
|
+
return {"deployed_skills": {}, "user_requested_skills": [], "last_sync": None}
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def save_deployment_index(claude_skills_dir: Path, index: Dict[str, Any]) -> None:
|
|
459
|
+
"""Save deployment tracking index to ~/.claude/skills/.
|
|
460
|
+
|
|
461
|
+
Args:
|
|
462
|
+
claude_skills_dir: Path to Claude skills directory (~/.claude/skills/)
|
|
463
|
+
index: Index data to save
|
|
464
|
+
|
|
465
|
+
Example:
|
|
466
|
+
>>> index = {"deployed_skills": {...}, "last_sync": "2025-12-22T10:30:00Z"}
|
|
467
|
+
>>> save_deployment_index(Path.home() / ".claude" / "skills", index)
|
|
468
|
+
"""
|
|
469
|
+
index_path = claude_skills_dir / DEPLOYED_INDEX_FILE
|
|
470
|
+
|
|
471
|
+
try:
|
|
472
|
+
# Ensure directory exists
|
|
473
|
+
claude_skills_dir.mkdir(parents=True, exist_ok=True)
|
|
474
|
+
|
|
475
|
+
with open(index_path, "w", encoding="utf-8") as f:
|
|
476
|
+
json.dump(index, f, indent=2, ensure_ascii=False)
|
|
477
|
+
|
|
478
|
+
logger.debug(f"Saved deployment index: {len(index['deployed_skills'])} skills")
|
|
479
|
+
|
|
480
|
+
except OSError as e:
|
|
481
|
+
logger.error(f"Failed to save deployment index: {e}")
|
|
482
|
+
raise
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def track_deployed_skill(
|
|
486
|
+
claude_skills_dir: Path, skill_name: str, collection: str
|
|
487
|
+
) -> None:
|
|
488
|
+
"""Track a newly deployed skill in the deployment index.
|
|
489
|
+
|
|
490
|
+
Args:
|
|
491
|
+
claude_skills_dir: Path to Claude skills directory (~/.claude/skills/)
|
|
492
|
+
skill_name: Name of deployed skill
|
|
493
|
+
collection: Collection name skill was deployed from
|
|
494
|
+
|
|
495
|
+
Example:
|
|
496
|
+
>>> track_deployed_skill(
|
|
497
|
+
... Path.home() / ".claude" / "skills",
|
|
498
|
+
... "systematic-debugging",
|
|
499
|
+
... "claude-mpm-skills"
|
|
500
|
+
... )
|
|
501
|
+
"""
|
|
502
|
+
index = load_deployment_index(claude_skills_dir)
|
|
503
|
+
|
|
504
|
+
# Add skill to deployed_skills
|
|
505
|
+
index["deployed_skills"][skill_name] = {
|
|
506
|
+
"collection": collection,
|
|
507
|
+
"deployed_at": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
# Update last_sync timestamp
|
|
511
|
+
index["last_sync"] = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
512
|
+
|
|
513
|
+
save_deployment_index(claude_skills_dir, index)
|
|
514
|
+
logger.debug(f"Tracked deployment: {skill_name} from {collection}")
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
def untrack_skill(claude_skills_dir: Path, skill_name: str) -> None:
|
|
518
|
+
"""Remove skill from deployment tracking index.
|
|
519
|
+
|
|
520
|
+
Args:
|
|
521
|
+
claude_skills_dir: Path to Claude skills directory (~/.claude/skills/)
|
|
522
|
+
skill_name: Name of skill to untrack
|
|
523
|
+
|
|
524
|
+
Example:
|
|
525
|
+
>>> untrack_skill(
|
|
526
|
+
... Path.home() / ".claude" / "skills",
|
|
527
|
+
... "old-skill"
|
|
528
|
+
... )
|
|
529
|
+
"""
|
|
530
|
+
index = load_deployment_index(claude_skills_dir)
|
|
531
|
+
|
|
532
|
+
if skill_name in index["deployed_skills"]:
|
|
533
|
+
del index["deployed_skills"][skill_name]
|
|
534
|
+
index["last_sync"] = (
|
|
535
|
+
datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
536
|
+
)
|
|
537
|
+
save_deployment_index(claude_skills_dir, index)
|
|
538
|
+
logger.debug(f"Untracked skill: {skill_name}")
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
def cleanup_orphan_skills(
|
|
542
|
+
claude_skills_dir: Path, required_skills: Set[str]
|
|
543
|
+
) -> Dict[str, Any]:
|
|
544
|
+
"""Remove skills deployed by claude-mpm but no longer referenced by agents.
|
|
545
|
+
|
|
546
|
+
This function:
|
|
547
|
+
1. Loads deployment tracking index
|
|
548
|
+
2. Identifies orphaned skills (tracked but not in required_skills AND not user-requested)
|
|
549
|
+
3. Removes orphaned skill directories from ~/.claude/skills/
|
|
550
|
+
4. Updates deployment index
|
|
551
|
+
|
|
552
|
+
User-requested skills are NEVER cleaned up as orphans - they are treated as required.
|
|
553
|
+
|
|
554
|
+
Args:
|
|
555
|
+
claude_skills_dir: Path to Claude skills directory (~/.claude/skills/)
|
|
556
|
+
required_skills: Set of skill names currently required by agents
|
|
557
|
+
|
|
558
|
+
Returns:
|
|
559
|
+
Dict containing:
|
|
560
|
+
- removed_count: Number of skills removed
|
|
561
|
+
- removed_skills: List of removed skill names
|
|
562
|
+
- kept_count: Number of skills kept
|
|
563
|
+
- errors: List of error messages
|
|
564
|
+
|
|
565
|
+
Example:
|
|
566
|
+
>>> required = {"skill-a", "skill-b"}
|
|
567
|
+
>>> result = cleanup_orphan_skills(
|
|
568
|
+
... Path.home() / ".claude" / "skills",
|
|
569
|
+
... required
|
|
570
|
+
... )
|
|
571
|
+
>>> print(f"Removed {result['removed_count']} orphaned skills")
|
|
572
|
+
"""
|
|
573
|
+
import shutil
|
|
574
|
+
|
|
575
|
+
index = load_deployment_index(claude_skills_dir)
|
|
576
|
+
tracked_skills = set(index["deployed_skills"].keys())
|
|
577
|
+
user_requested = set(index.get("user_requested_skills", []))
|
|
578
|
+
|
|
579
|
+
# Find orphaned skills: tracked by mpm but not in required_skills AND not user-requested
|
|
580
|
+
# User-requested skills are treated as required and NEVER cleaned up
|
|
581
|
+
all_required = required_skills | user_requested
|
|
582
|
+
orphaned = tracked_skills - all_required
|
|
583
|
+
|
|
584
|
+
if not orphaned:
|
|
585
|
+
logger.info("No orphaned skills to remove")
|
|
586
|
+
return {
|
|
587
|
+
"removed_count": 0,
|
|
588
|
+
"removed_skills": [],
|
|
589
|
+
"kept_count": len(tracked_skills),
|
|
590
|
+
"errors": [],
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
logger.info(
|
|
594
|
+
f"Found {len(orphaned)} orphaned skills (tracked but not required by agents)"
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
removed = []
|
|
598
|
+
errors = []
|
|
599
|
+
|
|
600
|
+
for skill_name in orphaned:
|
|
601
|
+
skill_dir = claude_skills_dir / skill_name
|
|
602
|
+
|
|
603
|
+
# Remove skill directory if it exists
|
|
604
|
+
if skill_dir.exists():
|
|
605
|
+
try:
|
|
606
|
+
# Validate path is within claude_skills_dir (security)
|
|
607
|
+
skill_dir.resolve().relative_to(claude_skills_dir.resolve())
|
|
608
|
+
|
|
609
|
+
# Remove directory
|
|
610
|
+
if skill_dir.is_symlink():
|
|
611
|
+
logger.debug(f"Removing symlink: {skill_dir}")
|
|
612
|
+
skill_dir.unlink()
|
|
613
|
+
else:
|
|
614
|
+
shutil.rmtree(skill_dir)
|
|
615
|
+
|
|
616
|
+
removed.append(skill_name)
|
|
617
|
+
logger.info(f"Removed orphaned skill: {skill_name}")
|
|
618
|
+
|
|
619
|
+
except ValueError:
|
|
620
|
+
error_msg = f"Path traversal attempt detected: {skill_dir}"
|
|
621
|
+
logger.error(error_msg)
|
|
622
|
+
errors.append(error_msg)
|
|
623
|
+
continue
|
|
624
|
+
except Exception as e:
|
|
625
|
+
error_msg = f"Failed to remove {skill_name}: {e}"
|
|
626
|
+
logger.error(error_msg)
|
|
627
|
+
errors.append(error_msg)
|
|
628
|
+
continue
|
|
629
|
+
|
|
630
|
+
# Remove from tracking index
|
|
631
|
+
untrack_skill(claude_skills_dir, skill_name)
|
|
632
|
+
|
|
633
|
+
kept_count = len(tracked_skills) - len(removed)
|
|
634
|
+
|
|
635
|
+
logger.info(
|
|
636
|
+
f"Cleanup complete: removed {len(removed)} skills, kept {kept_count} skills"
|
|
637
|
+
)
|
|
638
|
+
|
|
639
|
+
return {
|
|
640
|
+
"removed_count": len(removed),
|
|
641
|
+
"removed_skills": removed,
|
|
642
|
+
"kept_count": kept_count,
|
|
643
|
+
"errors": errors,
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
# === Configuration Management Functions ===
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
def save_agent_skills_to_config(skills: List[str], config_path: Path) -> None:
|
|
651
|
+
"""Save agent-scanned skills to configuration.yaml under skills.agent_referenced.
|
|
652
|
+
|
|
653
|
+
Args:
|
|
654
|
+
skills: List of skill names scanned from deployed agents
|
|
655
|
+
config_path: Path to configuration.yaml file
|
|
656
|
+
|
|
657
|
+
Example:
|
|
658
|
+
>>> skills = ["systematic-debugging", "typescript-core"]
|
|
659
|
+
>>> save_agent_skills_to_config(skills, Path(".claude-mpm/configuration.yaml"))
|
|
660
|
+
"""
|
|
661
|
+
import yaml
|
|
662
|
+
|
|
663
|
+
try:
|
|
664
|
+
# Load existing configuration (or create empty dict)
|
|
665
|
+
if config_path.exists():
|
|
666
|
+
with open(config_path, encoding="utf-8") as f:
|
|
667
|
+
config = yaml.safe_load(f) or {}
|
|
668
|
+
else:
|
|
669
|
+
config = {}
|
|
670
|
+
|
|
671
|
+
# Ensure skills section exists
|
|
672
|
+
if "skills" not in config:
|
|
673
|
+
config["skills"] = {}
|
|
674
|
+
|
|
675
|
+
# Update agent_referenced skills (sorted for consistency)
|
|
676
|
+
config["skills"]["agent_referenced"] = sorted(skills)
|
|
677
|
+
|
|
678
|
+
# Ensure user_defined exists (but don't overwrite if set)
|
|
679
|
+
if "user_defined" not in config["skills"]:
|
|
680
|
+
config["skills"]["user_defined"] = []
|
|
681
|
+
|
|
682
|
+
# Save configuration
|
|
683
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
684
|
+
with open(config_path, "w", encoding="utf-8") as f:
|
|
685
|
+
yaml.dump(config, f, default_flow_style=False, sort_keys=False)
|
|
686
|
+
|
|
687
|
+
logger.info(
|
|
688
|
+
f"Saved {len(skills)} agent-referenced skills to configuration.yaml"
|
|
689
|
+
)
|
|
690
|
+
|
|
691
|
+
except Exception as e:
|
|
692
|
+
logger.error(f"Failed to save agent skills to config: {e}")
|
|
693
|
+
raise
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
def get_skills_to_deploy(config_path: Path) -> Tuple[List[str], str]:
|
|
697
|
+
"""Resolve which skills to deploy based on configuration priority.
|
|
698
|
+
|
|
699
|
+
Returns (skills_list, source) where source is 'user_defined' or 'agent_referenced'.
|
|
700
|
+
|
|
701
|
+
Logic:
|
|
702
|
+
- If config.skills.user_defined is non-empty → return (user_defined, 'user_defined')
|
|
703
|
+
- Otherwise → return (agent_referenced, 'agent_referenced')
|
|
704
|
+
|
|
705
|
+
Args:
|
|
706
|
+
config_path: Path to configuration.yaml file
|
|
707
|
+
|
|
708
|
+
Returns:
|
|
709
|
+
Tuple of (skills list, source string)
|
|
710
|
+
|
|
711
|
+
Example:
|
|
712
|
+
>>> skills, source = get_skills_to_deploy(Path(".claude-mpm/configuration.yaml"))
|
|
713
|
+
>>> print(f"Deploy {len(skills)} skills from {source}")
|
|
714
|
+
"""
|
|
715
|
+
import yaml
|
|
716
|
+
|
|
717
|
+
try:
|
|
718
|
+
# Load configuration
|
|
719
|
+
if not config_path.exists():
|
|
720
|
+
logger.warning(f"Configuration file not found: {config_path}")
|
|
721
|
+
return ([], "agent_referenced")
|
|
722
|
+
|
|
723
|
+
with open(config_path, encoding="utf-8") as f:
|
|
724
|
+
config = yaml.safe_load(f) or {}
|
|
725
|
+
|
|
726
|
+
skills_config = config.get("skills", {})
|
|
727
|
+
user_defined = skills_config.get("user_defined", [])
|
|
728
|
+
agent_referenced = skills_config.get("agent_referenced", [])
|
|
729
|
+
|
|
730
|
+
# Priority: user_defined if non-empty, otherwise agent_referenced
|
|
731
|
+
if user_defined:
|
|
732
|
+
logger.info(
|
|
733
|
+
f"Using {len(user_defined)} user-defined skills from configuration"
|
|
734
|
+
)
|
|
735
|
+
return (user_defined, "user_defined")
|
|
736
|
+
logger.info(
|
|
737
|
+
f"Using {len(agent_referenced)} agent-referenced skills from configuration"
|
|
738
|
+
)
|
|
739
|
+
return (agent_referenced, "agent_referenced")
|
|
740
|
+
|
|
741
|
+
except Exception as e:
|
|
742
|
+
logger.error(f"Failed to load skills from config: {e}")
|
|
743
|
+
return ([], "agent_referenced")
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
# === User-Requested Skills Management ===
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
def get_user_requested_skills(claude_skills_dir: Path) -> List[str]:
|
|
750
|
+
"""Get list of user-requested skills.
|
|
751
|
+
|
|
752
|
+
Args:
|
|
753
|
+
claude_skills_dir: Path to Claude skills directory (~/.claude/skills/)
|
|
754
|
+
|
|
755
|
+
Returns:
|
|
756
|
+
List of skill names manually requested by user
|
|
757
|
+
|
|
758
|
+
Example:
|
|
759
|
+
>>> skills = get_user_requested_skills(Path.home() / ".claude" / "skills")
|
|
760
|
+
>>> print(f"User requested {len(skills)} skills")
|
|
761
|
+
"""
|
|
762
|
+
index = load_deployment_index(claude_skills_dir)
|
|
763
|
+
return index.get("user_requested_skills", [])
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
def add_user_requested_skill(skill_name: str, claude_skills_dir: Path) -> bool:
|
|
767
|
+
"""Add a skill to user_requested_skills list.
|
|
768
|
+
|
|
769
|
+
This function:
|
|
770
|
+
1. Loads deployment index
|
|
771
|
+
2. Adds skill name to user_requested_skills (if not already present)
|
|
772
|
+
3. Saves updated index
|
|
773
|
+
4. Returns success status
|
|
774
|
+
|
|
775
|
+
Note: This function does NOT deploy the skill, it only marks it as user-requested.
|
|
776
|
+
Use this in conjunction with skill deployment functions.
|
|
777
|
+
|
|
778
|
+
Args:
|
|
779
|
+
skill_name: Name of skill to mark as user-requested
|
|
780
|
+
claude_skills_dir: Path to Claude skills directory (~/.claude/skills/)
|
|
781
|
+
|
|
782
|
+
Returns:
|
|
783
|
+
True if skill was added, False if already present
|
|
784
|
+
|
|
785
|
+
Example:
|
|
786
|
+
>>> added = add_user_requested_skill(
|
|
787
|
+
... "django-framework",
|
|
788
|
+
... Path.home() / ".claude" / "skills"
|
|
789
|
+
... )
|
|
790
|
+
>>> print(f"Skill added: {added}")
|
|
791
|
+
"""
|
|
792
|
+
index = load_deployment_index(claude_skills_dir)
|
|
793
|
+
user_requested = index.get("user_requested_skills", [])
|
|
794
|
+
|
|
795
|
+
if skill_name in user_requested:
|
|
796
|
+
logger.debug(f"Skill {skill_name} already in user_requested_skills")
|
|
797
|
+
return False
|
|
798
|
+
|
|
799
|
+
user_requested.append(skill_name)
|
|
800
|
+
index["user_requested_skills"] = user_requested
|
|
801
|
+
index["last_sync"] = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
802
|
+
|
|
803
|
+
save_deployment_index(claude_skills_dir, index)
|
|
804
|
+
logger.info(f"Added {skill_name} to user_requested_skills")
|
|
805
|
+
return True
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
def remove_user_requested_skill(skill_name: str, claude_skills_dir: Path) -> bool:
|
|
809
|
+
"""Remove a skill from user_requested_skills list.
|
|
810
|
+
|
|
811
|
+
This function:
|
|
812
|
+
1. Loads deployment index
|
|
813
|
+
2. Removes skill name from user_requested_skills
|
|
814
|
+
3. Saves updated index
|
|
815
|
+
4. Returns success status
|
|
816
|
+
|
|
817
|
+
Note: This function does NOT remove the deployed skill directory.
|
|
818
|
+
It only removes the skill from user_requested_skills, making it eligible
|
|
819
|
+
for cleanup during orphan removal.
|
|
820
|
+
|
|
821
|
+
Args:
|
|
822
|
+
skill_name: Name of skill to remove from user_requested_skills
|
|
823
|
+
claude_skills_dir: Path to Claude skills directory (~/.claude/skills/)
|
|
824
|
+
|
|
825
|
+
Returns:
|
|
826
|
+
True if skill was removed, False if not present
|
|
827
|
+
|
|
828
|
+
Example:
|
|
829
|
+
>>> removed = remove_user_requested_skill(
|
|
830
|
+
... "django-framework",
|
|
831
|
+
... Path.home() / ".claude" / "skills"
|
|
832
|
+
... )
|
|
833
|
+
>>> print(f"Skill removed: {removed}")
|
|
834
|
+
"""
|
|
835
|
+
index = load_deployment_index(claude_skills_dir)
|
|
836
|
+
user_requested = index.get("user_requested_skills", [])
|
|
837
|
+
|
|
838
|
+
if skill_name not in user_requested:
|
|
839
|
+
logger.debug(f"Skill {skill_name} not in user_requested_skills")
|
|
840
|
+
return False
|
|
841
|
+
|
|
842
|
+
user_requested.remove(skill_name)
|
|
843
|
+
index["user_requested_skills"] = user_requested
|
|
844
|
+
index["last_sync"] = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
845
|
+
|
|
846
|
+
save_deployment_index(claude_skills_dir, index)
|
|
847
|
+
logger.info(f"Removed {skill_name} from user_requested_skills")
|
|
848
|
+
return True
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
def is_user_requested_skill(skill_name: str, claude_skills_dir: Path) -> bool:
|
|
852
|
+
"""Check if a skill is in the user_requested_skills list.
|
|
853
|
+
|
|
854
|
+
Args:
|
|
855
|
+
skill_name: Name of skill to check
|
|
856
|
+
claude_skills_dir: Path to Claude skills directory (~/.claude/skills/)
|
|
857
|
+
|
|
858
|
+
Returns:
|
|
859
|
+
True if skill is user-requested, False otherwise
|
|
860
|
+
|
|
861
|
+
Example:
|
|
862
|
+
>>> is_requested = is_user_requested_skill(
|
|
863
|
+
... "django-framework",
|
|
864
|
+
... Path.home() / ".claude" / "skills"
|
|
865
|
+
... )
|
|
866
|
+
>>> print(f"User requested: {is_requested}")
|
|
867
|
+
"""
|
|
868
|
+
user_requested = get_user_requested_skills(claude_skills_dir)
|
|
869
|
+
return skill_name in user_requested
|