claude-mpm 5.4.55__py3-none-any.whl → 5.6.1__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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
- claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
- claude_mpm/agents/PM_INSTRUCTIONS.md +111 -686
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/cli/__init__.py +5 -1
- claude_mpm/cli/commands/agents.py +2 -4
- claude_mpm/cli/commands/agents_reconcile.py +197 -0
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +46 -0
- claude_mpm/cli/commands/configure.py +620 -21
- 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 +2 -2
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skills.py +166 -14
- claude_mpm/cli/executor.py +120 -16
- claude_mpm/cli/interactive/__init__.py +10 -0
- claude_mpm/cli/interactive/agent_wizard.py +30 -50
- claude_mpm/cli/interactive/questionary_styles.py +65 -0
- claude_mpm/cli/interactive/skill_selector.py +481 -0
- claude_mpm/cli/parsers/base_parser.py +76 -1
- claude_mpm/cli/parsers/commander_parser.py +83 -0
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/startup.py +276 -403
- claude_mpm/cli/startup_display.py +72 -5
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +72 -0
- claude_mpm/commander/adapters/__init__.py +31 -0
- claude_mpm/commander/adapters/base.py +191 -0
- claude_mpm/commander/adapters/claude_code.py +361 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +105 -0
- claude_mpm/commander/api/errors.py +112 -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 +215 -0
- claude_mpm/commander/api/routes/work.py +260 -0
- claude_mpm/commander/api/schemas.py +182 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +107 -0
- claude_mpm/commander/chat/commands.py +96 -0
- claude_mpm/commander/chat/repl.py +310 -0
- claude_mpm/commander/config.py +49 -0
- claude_mpm/commander/config_loader.py +115 -0
- claude_mpm/commander/daemon.py +398 -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 +143 -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 +337 -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/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 +404 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +316 -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 +189 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +219 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +8 -0
- claude_mpm/commands/mpm-doctor.md +8 -0
- claude_mpm/commands/mpm-help.md +8 -0
- claude_mpm/commands/mpm-init.md +8 -0
- claude_mpm/commands/mpm-monitor.md +8 -0
- claude_mpm/commands/mpm-organize.md +8 -0
- claude_mpm/commands/mpm-postmortem.md +8 -0
- claude_mpm/commands/mpm-session-resume.md +9 -1
- claude_mpm/commands/mpm-status.md +8 -0
- claude_mpm/commands/mpm-ticket-view.md +8 -0
- claude_mpm/commands/mpm-version.md +8 -0
- claude_mpm/commands/mpm.md +8 -0
- claude_mpm/config/agent_presets.py +8 -7
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +2 -2
- claude_mpm/core/config.py +5 -0
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/interactive_session.py +7 -7
- claude_mpm/core/logger.py +10 -7
- claude_mpm/core/logging_utils.py +4 -2
- claude_mpm/core/output_style_manager.py +31 -13
- claude_mpm/core/unified_config.py +54 -8
- claude_mpm/core/unified_paths.py +30 -13
- 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/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
- 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/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
- 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 -1
- claude_mpm/dashboard/static/svelte-build/index.html +9 -9
- 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/auto_pause_handler.py +486 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +250 -11
- claude_mpm/hooks/claude_hooks/hook_handler.py +106 -89
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +69 -5
- claude_mpm/hooks/claude_hooks/response_tracking.py +3 -1
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +20 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +14 -77
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +30 -6
- claude_mpm/hooks/session_resume_hook.py +85 -1
- claude_mpm/init.py +1 -1
- claude_mpm/scripts/claude-hook-handler.sh +36 -10
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/cache_git_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_template_builder.py +8 -0
- claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/sources/git_source_sync_service.py +7 -4
- claude_mpm/services/agents/startup_sync.py +5 -2
- 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/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
- 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_log.py +325 -0
- 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_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +8 -2
- claude_mpm/services/monitor/server.py +106 -16
- claude_mpm/services/pm_skills_deployer.py +261 -85
- claude_mpm/services/skills/git_skill_source_manager.py +75 -10
- claude_mpm/services/skills/selective_skill_deployer.py +177 -80
- claude_mpm/services/skills/skill_discovery_service.py +57 -3
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/main.py +12 -4
- 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-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/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/skill_manager.py +4 -4
- claude_mpm/utils/agent_dependency_loader.py +103 -4
- claude_mpm/utils/robust_installer.py +45 -24
- claude_mpm-5.6.1.dist-info/METADATA +391 -0
- {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/RECORD +377 -166
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
- 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/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-5.4.55.dist-info/METADATA +0 -999
- {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.55.dist-info → claude_mpm-5.6.1.dist-info}/top_level.txt +0 -0
claude_mpm/cli/startup.py
CHANGED
|
@@ -191,7 +191,8 @@ def should_skip_background_services(args, processed_argv):
|
|
|
191
191
|
skip_commands = ["--version", "-v", "--help", "-h"]
|
|
192
192
|
return any(cmd in (processed_argv or sys.argv[1:]) for cmd in skip_commands) or (
|
|
193
193
|
hasattr(args, "command")
|
|
194
|
-
and args.command
|
|
194
|
+
and args.command
|
|
195
|
+
in ["info", "doctor", "config", "mcp", "configure", "hook-errors", "autotodos"]
|
|
195
196
|
)
|
|
196
197
|
|
|
197
198
|
|
|
@@ -234,7 +235,7 @@ def deploy_bundled_skills():
|
|
|
234
235
|
if not skills_config.get("auto_deploy", True):
|
|
235
236
|
# Auto-deploy disabled, skip silently
|
|
236
237
|
return
|
|
237
|
-
except Exception:
|
|
238
|
+
except Exception: # nosec B110
|
|
238
239
|
# If config loading fails, assume auto-deploy is enabled (default)
|
|
239
240
|
pass
|
|
240
241
|
|
|
@@ -308,63 +309,60 @@ def deploy_output_style_on_startup():
|
|
|
308
309
|
communication without emojis and exclamation points. Styles are project-specific
|
|
309
310
|
to allow different projects to have different communication styles.
|
|
310
311
|
|
|
311
|
-
DESIGN DECISION: This is non-blocking and idempotent. Deploys to
|
|
312
|
-
directory (
|
|
313
|
-
|
|
312
|
+
DESIGN DECISION: This is non-blocking and idempotent. Deploys to user-level
|
|
313
|
+
directory (~/.claude/output-styles/) which is the official Claude Code location
|
|
314
|
+
for custom output styles.
|
|
314
315
|
|
|
315
|
-
Deploys
|
|
316
|
-
- claude-mpm
|
|
316
|
+
Deploys all styles:
|
|
317
|
+
- claude-mpm.md (professional mode)
|
|
317
318
|
- claude-mpm-teacher.md (teaching mode)
|
|
319
|
+
- claude-mpm-research.md (research mode - for codebase analysis)
|
|
318
320
|
"""
|
|
319
321
|
try:
|
|
320
|
-
import
|
|
321
|
-
from pathlib import Path
|
|
322
|
+
from ..core.output_style_manager import OutputStyleManager
|
|
322
323
|
|
|
323
|
-
#
|
|
324
|
-
|
|
325
|
-
professional_source = package_dir / "CLAUDE_MPM_OUTPUT_STYLE.md"
|
|
326
|
-
teacher_source = package_dir / "CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md"
|
|
324
|
+
# Initialize the output style manager
|
|
325
|
+
manager = OutputStyleManager()
|
|
327
326
|
|
|
328
|
-
#
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
# Create directory if it doesn't exist
|
|
335
|
-
output_styles_dir.mkdir(parents=True, exist_ok=True)
|
|
336
|
-
|
|
337
|
-
# Check if already deployed (both files exist and have content)
|
|
338
|
-
already_deployed = (
|
|
339
|
-
professional_target.exists()
|
|
340
|
-
and teacher_target.exists()
|
|
341
|
-
and professional_target.stat().st_size > 0
|
|
342
|
-
and teacher_target.stat().st_size > 0
|
|
343
|
-
)
|
|
327
|
+
# Check if Claude Code version supports output styles (>= 1.0.83)
|
|
328
|
+
if not manager.supports_output_styles():
|
|
329
|
+
# Skip deployment for older versions
|
|
330
|
+
# The manager will fall back to injecting content directly
|
|
331
|
+
return
|
|
344
332
|
|
|
345
|
-
if
|
|
333
|
+
# Check if all styles are already deployed and up-to-date
|
|
334
|
+
all_up_to_date = True
|
|
335
|
+
for style_config in manager.styles.values():
|
|
336
|
+
source_path = style_config["source"]
|
|
337
|
+
target_path = style_config["target"]
|
|
338
|
+
|
|
339
|
+
if not (
|
|
340
|
+
target_path.exists()
|
|
341
|
+
and source_path.exists()
|
|
342
|
+
and target_path.stat().st_size == source_path.stat().st_size
|
|
343
|
+
):
|
|
344
|
+
all_up_to_date = False
|
|
345
|
+
break
|
|
346
|
+
|
|
347
|
+
if all_up_to_date:
|
|
346
348
|
# Show feedback that output styles are ready
|
|
347
349
|
print("✓ Output styles ready", flush=True)
|
|
348
350
|
return
|
|
349
351
|
|
|
350
|
-
# Deploy
|
|
351
|
-
|
|
352
|
-
if professional_source.exists():
|
|
353
|
-
shutil.copy2(professional_source, professional_target)
|
|
354
|
-
deployed_count += 1
|
|
352
|
+
# Deploy all styles using the manager
|
|
353
|
+
results = manager.deploy_all_styles(activate_default=True)
|
|
355
354
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
deployed_count += 1
|
|
355
|
+
# Count successful deployments
|
|
356
|
+
deployed_count = sum(1 for success in results.values() if success)
|
|
359
357
|
|
|
360
358
|
if deployed_count > 0:
|
|
361
359
|
print(f"✓ Output styles deployed ({deployed_count} styles)", flush=True)
|
|
362
360
|
else:
|
|
363
|
-
#
|
|
361
|
+
# Deployment failed - log but don't fail startup
|
|
364
362
|
from ..core.logger import get_logger
|
|
365
363
|
|
|
366
364
|
logger = get_logger("cli")
|
|
367
|
-
logger.debug("
|
|
365
|
+
logger.debug("Failed to deploy any output styles")
|
|
368
366
|
|
|
369
367
|
except Exception as e:
|
|
370
368
|
# Non-critical - log but don't fail startup
|
|
@@ -453,7 +451,7 @@ def _cleanup_orphaned_agents(deploy_target: Path, deployed_agents: list[str]) ->
|
|
|
453
451
|
return removed_count
|
|
454
452
|
|
|
455
453
|
|
|
456
|
-
def sync_remote_agents_on_startup():
|
|
454
|
+
def sync_remote_agents_on_startup(force_sync: bool = False):
|
|
457
455
|
"""
|
|
458
456
|
Synchronize agent templates from remote sources on startup.
|
|
459
457
|
|
|
@@ -466,16 +464,16 @@ def sync_remote_agents_on_startup():
|
|
|
466
464
|
block startup to ensure claude-mpm remains functional.
|
|
467
465
|
|
|
468
466
|
Workflow:
|
|
469
|
-
1.
|
|
470
|
-
2.
|
|
471
|
-
3.
|
|
472
|
-
4. Cleanup
|
|
467
|
+
1. Sync all enabled Git sources (download/cache files) - Phase 1 progress bar
|
|
468
|
+
2. Deploy agents to ~/.claude/agents/ - Phase 2 progress bar
|
|
469
|
+
3. Cleanup orphaned agents (ours but no longer deployed) - Phase 3
|
|
470
|
+
4. Cleanup legacy agent cache directories (after sync/deployment) - Phase 4
|
|
473
471
|
5. Log deployment results
|
|
474
|
-
"""
|
|
475
|
-
# Cleanup legacy cache directories first (before syncing)
|
|
476
|
-
cleanup_legacy_agent_cache()
|
|
477
472
|
|
|
478
|
-
|
|
473
|
+
Args:
|
|
474
|
+
force_sync: Force download even if cache is fresh (bypasses ETag).
|
|
475
|
+
"""
|
|
476
|
+
# DEPRECATED: Legacy warning - no-op function, kept for compatibility
|
|
479
477
|
check_legacy_cache()
|
|
480
478
|
|
|
481
479
|
try:
|
|
@@ -484,7 +482,6 @@ def sync_remote_agents_on_startup():
|
|
|
484
482
|
from pathlib import Path
|
|
485
483
|
|
|
486
484
|
from ..core.shared.config_loader import ConfigLoader
|
|
487
|
-
from ..services.agents.deployment.agent_deployment import AgentDeploymentService
|
|
488
485
|
from ..services.agents.startup_sync import sync_agents_on_startup
|
|
489
486
|
from ..services.profile_manager import ProfileManager
|
|
490
487
|
from ..utils.progress import ProgressBar
|
|
@@ -509,7 +506,7 @@ def sync_remote_agents_on_startup():
|
|
|
509
506
|
)
|
|
510
507
|
|
|
511
508
|
# Phase 1: Sync files from Git sources
|
|
512
|
-
result = sync_agents_on_startup()
|
|
509
|
+
result = sync_agents_on_startup(force_refresh=force_sync)
|
|
513
510
|
|
|
514
511
|
# Only proceed with deployment if sync was enabled and ran
|
|
515
512
|
if result.get("enabled") and result.get("sources_synced", 0) > 0:
|
|
@@ -532,304 +529,89 @@ def sync_remote_agents_on_startup():
|
|
|
532
529
|
logger.warning(f"Agent sync completed with {len(errors)} errors")
|
|
533
530
|
|
|
534
531
|
# Phase 2: Deploy agents from cache to ~/.claude/agents/
|
|
535
|
-
#
|
|
532
|
+
# Use reconciliation service to respect configuration.yaml settings
|
|
536
533
|
try:
|
|
537
|
-
# Initialize deployment service with profile-filtered configuration
|
|
538
|
-
from ..core.config import Config
|
|
539
|
-
|
|
540
|
-
deploy_config = None
|
|
541
|
-
if active_profile and profile_manager.active_profile:
|
|
542
|
-
# Create config with excluded agents based on profile
|
|
543
|
-
# Get all agents that should be excluded (not in enabled list)
|
|
544
|
-
from pathlib import Path
|
|
545
|
-
|
|
546
|
-
cache_dir = Path.home() / ".claude-mpm" / "cache" / "agents"
|
|
547
|
-
if cache_dir.exists():
|
|
548
|
-
# Find all agent files
|
|
549
|
-
# Supports both flat cache and {owner}/{repo}/agents/ structure
|
|
550
|
-
all_agent_files = [
|
|
551
|
-
f
|
|
552
|
-
for f in cache_dir.rglob("*.md")
|
|
553
|
-
if "/agents/" in str(f)
|
|
554
|
-
and f.stem.lower() != "base-agent"
|
|
555
|
-
and f.name.lower()
|
|
556
|
-
not in {"readme.md", "changelog.md", "contributing.md"}
|
|
557
|
-
]
|
|
558
|
-
|
|
559
|
-
# Build exclusion list for agents not in profile
|
|
560
|
-
excluded_agents = []
|
|
561
|
-
for agent_file in all_agent_files:
|
|
562
|
-
agent_name = agent_file.stem
|
|
563
|
-
if not profile_manager.is_agent_enabled(agent_name):
|
|
564
|
-
excluded_agents.append(agent_name)
|
|
565
|
-
|
|
566
|
-
if excluded_agents:
|
|
567
|
-
# Get singleton config and update with profile settings
|
|
568
|
-
# BUGFIX: Config is a singleton that ignores dict parameter if already initialized.
|
|
569
|
-
# Creating Config({...}) doesn't store excluded_agents - use set() instead.
|
|
570
|
-
deploy_config = Config()
|
|
571
|
-
deploy_config.set(
|
|
572
|
-
"agent_deployment.excluded_agents", excluded_agents
|
|
573
|
-
)
|
|
574
|
-
deploy_config.set(
|
|
575
|
-
"agent_deployment.filter_non_mpm_agents", False
|
|
576
|
-
)
|
|
577
|
-
deploy_config.set("agent_deployment.case_sensitive", False)
|
|
578
|
-
deploy_config.set(
|
|
579
|
-
"agent_deployment.exclude_dependencies", False
|
|
580
|
-
)
|
|
581
|
-
logger.info(
|
|
582
|
-
f"Profile '{active_profile}': Excluding {len(excluded_agents)} agents from deployment"
|
|
583
|
-
)
|
|
584
|
-
|
|
585
|
-
deployment_service = AgentDeploymentService(config=deploy_config)
|
|
586
|
-
|
|
587
|
-
# Count agents in cache to show accurate progress
|
|
588
534
|
from pathlib import Path
|
|
589
535
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
# BUGFIX (cache-count-inflation): Clean up stale cache files
|
|
595
|
-
# from old repositories before counting to prevent inflated counts.
|
|
596
|
-
# Issue: Old caches like bobmatnyc/claude-mpm-agents/agents/
|
|
597
|
-
# were counted alongside current agents, inflating count
|
|
598
|
-
# from 44 to 85.
|
|
599
|
-
#
|
|
600
|
-
# Solution: Remove files with nested /agents/ paths
|
|
601
|
-
# (e.g., cache/agents/user/repo/agents/...)
|
|
602
|
-
# Keep only current agents (e.g., cache/agents/engineer/...)
|
|
603
|
-
removed_count = 0
|
|
604
|
-
stale_dirs = set()
|
|
605
|
-
|
|
606
|
-
for md_file in cache_dir.rglob("*.md"):
|
|
607
|
-
# Stale cache files have multiple /agents/ in their path RELATIVE to cache_dir
|
|
608
|
-
# Current: cache/agents/bobmatnyc/claude-mpm-agents/agents/engineer/...
|
|
609
|
-
# (1 occurrence in relative path: /agents/)
|
|
610
|
-
# Old flat: cache/agents/engineer/...
|
|
611
|
-
# (0 occurrences in relative path - no repo structure)
|
|
612
|
-
# The issue: str(md_file).count("/agents/") counts BOTH cache/agents/ AND repo/agents/
|
|
613
|
-
# Fix: Count /agents/ in path RELATIVE to cache_dir (after cache/agents/)
|
|
614
|
-
relative_path = str(md_file.relative_to(cache_dir))
|
|
615
|
-
if relative_path.count("/agents/") > 1:
|
|
616
|
-
# Track parent directory for cleanup
|
|
617
|
-
# Extract subdirectory under cache/agents/
|
|
618
|
-
# (e.g., "bobmatnyc")
|
|
619
|
-
parts = md_file.parts
|
|
620
|
-
cache_agents_idx = parts.index("agents")
|
|
621
|
-
if cache_agents_idx + 1 < len(parts):
|
|
622
|
-
stale_subdir = parts[cache_agents_idx + 1]
|
|
623
|
-
# Only remove if it's not a known category directory
|
|
624
|
-
if stale_subdir not in [
|
|
625
|
-
"engineer",
|
|
626
|
-
"ops",
|
|
627
|
-
"qa",
|
|
628
|
-
"universal",
|
|
629
|
-
"documentation",
|
|
630
|
-
"claude-mpm",
|
|
631
|
-
"security",
|
|
632
|
-
]:
|
|
633
|
-
stale_dirs.add(cache_dir / stale_subdir)
|
|
634
|
-
|
|
635
|
-
md_file.unlink()
|
|
636
|
-
removed_count += 1
|
|
637
|
-
|
|
638
|
-
# Remove empty stale directories
|
|
639
|
-
for stale_dir in stale_dirs:
|
|
640
|
-
if stale_dir.exists() and stale_dir.is_dir():
|
|
641
|
-
try:
|
|
642
|
-
# Remove directory and all contents
|
|
643
|
-
import shutil
|
|
644
|
-
|
|
645
|
-
shutil.rmtree(stale_dir)
|
|
646
|
-
except Exception:
|
|
647
|
-
pass # Ignore cleanup errors
|
|
648
|
-
|
|
649
|
-
if removed_count > 0:
|
|
650
|
-
from loguru import logger
|
|
651
|
-
|
|
652
|
-
logger.info(
|
|
653
|
-
f"Cleaned up {removed_count} stale cache files "
|
|
654
|
-
f"from old repositories"
|
|
655
|
-
)
|
|
536
|
+
from ..core.unified_config import UnifiedConfig
|
|
537
|
+
from ..services.agents.deployment.startup_reconciliation import (
|
|
538
|
+
perform_startup_reconciliation,
|
|
539
|
+
)
|
|
656
540
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
# (
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
"
|
|
670
|
-
"response_format.md",
|
|
671
|
-
"ticket_completeness_examples.md",
|
|
672
|
-
"validation_templates.md",
|
|
673
|
-
"git_file_tracking.md",
|
|
674
|
-
}
|
|
675
|
-
# Documentation files to exclude (by filename)
|
|
676
|
-
doc_files = {
|
|
677
|
-
"readme.md",
|
|
678
|
-
"changelog.md",
|
|
679
|
-
"contributing.md",
|
|
680
|
-
"implementation-summary.md",
|
|
681
|
-
"reorganization-plan.md",
|
|
682
|
-
"auto-deploy-index.md",
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
# Find all markdown files (after cleanup)
|
|
686
|
-
all_md_files = list(cache_dir.rglob("*.md"))
|
|
687
|
-
|
|
688
|
-
# Filter to only agent files:
|
|
689
|
-
# 1. Must have "/agents/" in path (current structure supports
|
|
690
|
-
# both flat and {owner}/{repo}/agents/ patterns)
|
|
691
|
-
# 2. Must not be in PM templates or doc files
|
|
692
|
-
# 3. Exclude BASE-AGENT.md which is not a deployable agent
|
|
693
|
-
# 4. Exclude build artifacts (dist/, build/, .cache/)
|
|
694
|
-
# to prevent double-counting
|
|
695
|
-
agent_files = [
|
|
696
|
-
f
|
|
697
|
-
for f in all_md_files
|
|
698
|
-
if (
|
|
699
|
-
# Must be in an agent directory
|
|
700
|
-
# Supports: cache/agents/{category}/... (flat)
|
|
701
|
-
# Supports: cache/agents/{owner}/{repo}/agents/{category}/... (GitHub sync)
|
|
702
|
-
"/agents/" in str(f)
|
|
703
|
-
# Exclude PM templates, doc files, and BASE-AGENT
|
|
704
|
-
and f.name.lower() not in pm_templates
|
|
705
|
-
and f.name.lower() not in doc_files
|
|
706
|
-
and f.name.lower() != "base-agent.md"
|
|
707
|
-
# Exclude build artifacts (prevents double-counting
|
|
708
|
-
# source + built files)
|
|
709
|
-
and not any(
|
|
710
|
-
part in str(f).split("/")
|
|
711
|
-
for part in ["dist", "build", ".cache"]
|
|
712
|
-
)
|
|
713
|
-
)
|
|
714
|
-
]
|
|
715
|
-
agent_count = len(agent_files)
|
|
716
|
-
|
|
717
|
-
if agent_count > 0:
|
|
718
|
-
# Deploy agents to project-level directory where Claude Code expects them
|
|
719
|
-
deploy_target = Path.cwd() / ".claude" / "agents"
|
|
720
|
-
deployment_result = deployment_service.deploy_agents(
|
|
721
|
-
target_dir=deploy_target,
|
|
722
|
-
force_rebuild=False, # Only deploy if versions differ
|
|
723
|
-
deployment_mode="update", # Version-aware updates
|
|
724
|
-
config=deploy_config, # Pass config to respect profile filtering
|
|
541
|
+
# Load configuration
|
|
542
|
+
unified_config = UnifiedConfig()
|
|
543
|
+
|
|
544
|
+
# Override with profile settings if active
|
|
545
|
+
if active_profile and profile_manager.active_profile:
|
|
546
|
+
# Get enabled agents from profile (returns Set[str])
|
|
547
|
+
profile_enabled_agents = (
|
|
548
|
+
profile_manager.active_profile.get_enabled_agents()
|
|
549
|
+
)
|
|
550
|
+
# Update config with profile's enabled list (convert Set to List)
|
|
551
|
+
unified_config.agents.enabled = list(profile_enabled_agents)
|
|
552
|
+
logger.info(
|
|
553
|
+
f"Profile '{active_profile}': Using {len(profile_enabled_agents)} enabled agents"
|
|
725
554
|
)
|
|
726
555
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
# FALLBACK: If deployment result doesn't track skipped agents (async path),
|
|
734
|
-
# count existing agents in target directory as "already deployed"
|
|
735
|
-
# This ensures accurate reporting when agents are already up-to-date
|
|
736
|
-
if total_configured == 0 and deploy_target.exists():
|
|
737
|
-
existing_agents = list(deploy_target.glob("*.md"))
|
|
738
|
-
# Filter out non-agent files (e.g., README.md, INSTRUCTIONS.md)
|
|
739
|
-
agent_count_in_target = len(
|
|
740
|
-
[
|
|
741
|
-
f
|
|
742
|
-
for f in existing_agents
|
|
743
|
-
if not f.name.startswith(("README", "INSTRUCTIONS"))
|
|
744
|
-
]
|
|
745
|
-
)
|
|
746
|
-
if agent_count_in_target > 0:
|
|
747
|
-
# All agents already deployed - count them as skipped
|
|
748
|
-
skipped = agent_count_in_target
|
|
749
|
-
total_configured = agent_count_in_target
|
|
556
|
+
# Perform reconciliation to deploy configured agents
|
|
557
|
+
project_path = Path.cwd()
|
|
558
|
+
agent_result, _skill_result = perform_startup_reconciliation(
|
|
559
|
+
project_path=project_path, config=unified_config, silent=False
|
|
560
|
+
)
|
|
750
561
|
|
|
751
|
-
|
|
562
|
+
# Display results with progress bar
|
|
563
|
+
total_operations = (
|
|
564
|
+
len(agent_result.deployed)
|
|
565
|
+
+ len(agent_result.removed)
|
|
566
|
+
+ len(agent_result.unchanged)
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
if total_operations > 0:
|
|
752
570
|
deploy_progress = ProgressBar(
|
|
753
|
-
total=
|
|
571
|
+
total=total_operations,
|
|
754
572
|
prefix="Deploying agents",
|
|
755
573
|
show_percentage=True,
|
|
756
574
|
show_counter=True,
|
|
757
575
|
)
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
)
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
576
|
+
deploy_progress.update(total_operations)
|
|
577
|
+
|
|
578
|
+
# Build summary message
|
|
579
|
+
deployed = len(agent_result.deployed)
|
|
580
|
+
removed = len(agent_result.removed)
|
|
581
|
+
unchanged = len(agent_result.unchanged)
|
|
582
|
+
|
|
583
|
+
summary_parts = []
|
|
584
|
+
if deployed > 0:
|
|
585
|
+
summary_parts.append(f"{deployed} new")
|
|
586
|
+
if removed > 0:
|
|
587
|
+
summary_parts.append(f"{removed} removed")
|
|
588
|
+
if unchanged > 0:
|
|
589
|
+
summary_parts.append(f"{unchanged} unchanged")
|
|
590
|
+
|
|
591
|
+
summary = f"Complete: {', '.join(summary_parts)}"
|
|
592
|
+
deploy_progress.finish(summary)
|
|
593
|
+
|
|
594
|
+
# Display errors if any
|
|
595
|
+
if agent_result.errors:
|
|
596
|
+
logger.warning(
|
|
597
|
+
f"Agent deployment completed with {len(agent_result.errors)} errors"
|
|
777
598
|
)
|
|
599
|
+
print("\n⚠️ Agent Deployment Errors:")
|
|
600
|
+
max_errors_to_show = 10
|
|
601
|
+
errors_to_display = agent_result.errors[:max_errors_to_show]
|
|
778
602
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
if deployed > 0 or updated > 0:
|
|
782
|
-
if removed > 0:
|
|
783
|
-
deploy_progress.finish(
|
|
784
|
-
f"Complete: {deployed} new, {updated} updated, {skipped} unchanged, "
|
|
785
|
-
f"{removed} removed ({total_configured} configured from {agent_count} files in cache)"
|
|
786
|
-
)
|
|
787
|
-
else:
|
|
788
|
-
deploy_progress.finish(
|
|
789
|
-
f"Complete: {deployed} new, {updated} updated, {skipped} unchanged "
|
|
790
|
-
f"({total_configured} configured from {agent_count} files in cache)"
|
|
791
|
-
)
|
|
792
|
-
elif removed > 0:
|
|
793
|
-
deploy_progress.finish(
|
|
794
|
-
f"Complete: {total_configured} agents deployed, "
|
|
795
|
-
f"{removed} removed ({agent_count} files in cache)"
|
|
796
|
-
)
|
|
797
|
-
else:
|
|
798
|
-
deploy_progress.finish(
|
|
799
|
-
f"Complete: {total_configured} agents deployed "
|
|
800
|
-
f"({agent_count} files in cache)"
|
|
801
|
-
)
|
|
802
|
-
|
|
803
|
-
# Display deployment errors to user (not just logs)
|
|
804
|
-
deploy_errors = deployment_result.get("errors", [])
|
|
805
|
-
if deploy_errors:
|
|
806
|
-
# Log for debugging
|
|
807
|
-
logger.warning(
|
|
808
|
-
f"Agent deployment completed with {len(deploy_errors)} errors: {deploy_errors}"
|
|
809
|
-
)
|
|
810
|
-
|
|
811
|
-
# Display errors to user with clear formatting
|
|
812
|
-
print("\n⚠️ Agent Deployment Errors:")
|
|
813
|
-
|
|
814
|
-
# Show first 10 errors to avoid overwhelming output
|
|
815
|
-
max_errors_to_show = 10
|
|
816
|
-
errors_to_display = deploy_errors[:max_errors_to_show]
|
|
817
|
-
|
|
818
|
-
for error in errors_to_display:
|
|
819
|
-
# Format error message for readability
|
|
820
|
-
# Errors typically come as strings like "agent.md: Error message"
|
|
821
|
-
print(f" - {error}")
|
|
603
|
+
for error in errors_to_display:
|
|
604
|
+
print(f" - {error}")
|
|
822
605
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
print(f" ... and {remaining} more error(s)")
|
|
606
|
+
if len(agent_result.errors) > max_errors_to_show:
|
|
607
|
+
remaining = len(agent_result.errors) - max_errors_to_show
|
|
608
|
+
print(f" ... and {remaining} more error(s)")
|
|
827
609
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
610
|
+
print(
|
|
611
|
+
f"\n❌ Failed to deploy {len(agent_result.errors)} agent(s). "
|
|
612
|
+
"Please check the error messages above."
|
|
613
|
+
)
|
|
614
|
+
print(" Run with --verbose for detailed error information.\n")
|
|
833
615
|
|
|
834
616
|
except Exception as e:
|
|
835
617
|
# Deployment failure shouldn't block startup
|
|
@@ -838,6 +620,11 @@ def sync_remote_agents_on_startup():
|
|
|
838
620
|
logger = get_logger("cli")
|
|
839
621
|
logger.warning(f"Failed to deploy agents from cache: {e}")
|
|
840
622
|
|
|
623
|
+
# Phase 4: Cleanup legacy agent cache directories (after sync/deployment)
|
|
624
|
+
# CRITICAL: This must run AFTER sync completes because sync may recreate
|
|
625
|
+
# legacy directories. Running cleanup here ensures they're removed.
|
|
626
|
+
cleanup_legacy_agent_cache()
|
|
627
|
+
|
|
841
628
|
except Exception as e:
|
|
842
629
|
# Non-critical - log but don't fail startup
|
|
843
630
|
from ..core.logger import get_logger
|
|
@@ -846,8 +633,14 @@ def sync_remote_agents_on_startup():
|
|
|
846
633
|
logger.debug(f"Failed to sync remote agents: {e}")
|
|
847
634
|
# Continue execution - agent sync failure shouldn't block startup
|
|
848
635
|
|
|
636
|
+
# Cleanup legacy cache even if sync failed
|
|
637
|
+
try:
|
|
638
|
+
cleanup_legacy_agent_cache()
|
|
639
|
+
except Exception: # nosec B110
|
|
640
|
+
pass # Ignore cleanup errors
|
|
641
|
+
|
|
849
642
|
|
|
850
|
-
def sync_remote_skills_on_startup():
|
|
643
|
+
def sync_remote_skills_on_startup(force_sync: bool = False):
|
|
851
644
|
"""
|
|
852
645
|
Synchronize skill templates from remote sources on startup.
|
|
853
646
|
|
|
@@ -865,6 +658,9 @@ def sync_remote_skills_on_startup():
|
|
|
865
658
|
4. Apply profile filtering if active
|
|
866
659
|
5. Deploy resolved skills to ~/.claude/skills/ - Phase 2 progress bar
|
|
867
660
|
6. Log deployment results with source indication
|
|
661
|
+
|
|
662
|
+
Args:
|
|
663
|
+
force_sync: Force download even if cache is fresh (bypasses ETag).
|
|
868
664
|
"""
|
|
869
665
|
try:
|
|
870
666
|
from pathlib import Path
|
|
@@ -970,7 +766,7 @@ def sync_remote_skills_on_startup():
|
|
|
970
766
|
|
|
971
767
|
# Sync all sources with progress callback
|
|
972
768
|
results = manager.sync_all_sources(
|
|
973
|
-
force=
|
|
769
|
+
force=force_sync, progress_callback=sync_progress.update
|
|
974
770
|
)
|
|
975
771
|
|
|
976
772
|
# Finish sync progress bar with clear breakdown
|
|
@@ -990,22 +786,37 @@ def sync_remote_skills_on_startup():
|
|
|
990
786
|
|
|
991
787
|
# Phase 2: Scan agents and save to configuration.yaml
|
|
992
788
|
# This step populates configuration.yaml with agent-referenced skills
|
|
993
|
-
#
|
|
994
|
-
#
|
|
995
|
-
# Previous behavior: If skills were cached, agent scan was skipped,
|
|
996
|
-
# leaving agent_referenced: [] empty, which prevented cleanup.
|
|
789
|
+
# CRITICAL: Always scan agents to populate agent_referenced, even when using cached skills.
|
|
790
|
+
# Without this, skill_filter=None causes ALL skills to deploy and NO cleanup to run.
|
|
997
791
|
agents_dir = Path.cwd() / ".claude" / "agents"
|
|
998
792
|
|
|
999
|
-
# Scan agents for skill requirements (
|
|
793
|
+
# Scan agents for skill requirements (ALWAYS run to ensure cleanup works)
|
|
1000
794
|
agent_skills = get_required_skills_from_agents(agents_dir)
|
|
795
|
+
logger.info(
|
|
796
|
+
f"Agent scan found {len(agent_skills)} unique skills across deployed agents"
|
|
797
|
+
)
|
|
1001
798
|
|
|
1002
799
|
# Save to project-level configuration.yaml
|
|
1003
800
|
project_config_path = Path.cwd() / ".claude-mpm" / "configuration.yaml"
|
|
1004
801
|
save_agent_skills_to_config(list(agent_skills), project_config_path)
|
|
802
|
+
logger.debug(
|
|
803
|
+
f"Saved {len(agent_skills)} agent-referenced skills to {project_config_path}"
|
|
804
|
+
)
|
|
1005
805
|
|
|
1006
806
|
# Phase 3: Resolve which skills to deploy (user_defined or agent_referenced)
|
|
1007
807
|
skills_to_deploy, skill_source = get_skills_to_deploy(project_config_path)
|
|
1008
808
|
|
|
809
|
+
# CRITICAL DEBUG: Log deployment resolution to diagnose cleanup issues
|
|
810
|
+
if skills_to_deploy:
|
|
811
|
+
logger.info(
|
|
812
|
+
f"Resolved {len(skills_to_deploy)} skills from {skill_source} (cleanup will run)"
|
|
813
|
+
)
|
|
814
|
+
else:
|
|
815
|
+
logger.warning(
|
|
816
|
+
f"No skills resolved from {skill_source} - will deploy ALL skills WITHOUT cleanup! "
|
|
817
|
+
f"This may indicate agent_referenced is empty in configuration.yaml."
|
|
818
|
+
)
|
|
819
|
+
|
|
1009
820
|
# Phase 4: Apply profile filtering if active
|
|
1010
821
|
if active_profile and profile_manager.active_profile:
|
|
1011
822
|
# Filter skills based on profile
|
|
@@ -1053,9 +864,7 @@ def sync_remote_skills_on_startup():
|
|
|
1053
864
|
total_skill_count = len(all_skills)
|
|
1054
865
|
|
|
1055
866
|
# Determine skill count based on resolution
|
|
1056
|
-
skill_count = (
|
|
1057
|
-
len(skills_to_deploy) if skills_to_deploy else total_skill_count
|
|
1058
|
-
)
|
|
867
|
+
skill_count = len(skills_to_deploy) if skills_to_deploy else total_skill_count
|
|
1059
868
|
|
|
1060
869
|
if skill_count > 0:
|
|
1061
870
|
# Deploy skills with resolved filter
|
|
@@ -1066,8 +875,13 @@ def sync_remote_skills_on_startup():
|
|
|
1066
875
|
# Deploy to project-local directory with cleanup
|
|
1067
876
|
deployment_result = manager.deploy_skills(
|
|
1068
877
|
target_dir=Path.cwd() / ".claude" / "skills",
|
|
1069
|
-
force=
|
|
1070
|
-
|
|
878
|
+
force=force_sync,
|
|
879
|
+
# CRITICAL FIX: Empty list should mean "deploy no skills", not "deploy all"
|
|
880
|
+
# When skills_to_deploy is [], we want skill_filter=set() NOT skill_filter=None
|
|
881
|
+
# None means "no filtering" (deploy all), empty set means "filter to nothing"
|
|
882
|
+
skill_filter=set(skills_to_deploy)
|
|
883
|
+
if skills_to_deploy is not None
|
|
884
|
+
else None,
|
|
1071
885
|
)
|
|
1072
886
|
|
|
1073
887
|
# REMOVED: User-level deployment (lines 1068-1074)
|
|
@@ -1078,6 +892,7 @@ def sync_remote_skills_on_startup():
|
|
|
1078
892
|
deployed = deployment_result.get("deployed_count", 0)
|
|
1079
893
|
skipped = deployment_result.get("skipped_count", 0)
|
|
1080
894
|
filtered = deployment_result.get("filtered_count", 0)
|
|
895
|
+
removed = deployment_result.get("removed_count", 0)
|
|
1081
896
|
total_available = deployed + skipped
|
|
1082
897
|
|
|
1083
898
|
# Only show progress bar if there are skills to deploy
|
|
@@ -1107,16 +922,25 @@ def sync_remote_skills_on_startup():
|
|
|
1107
922
|
"user override" if skill_source == "user_defined" else "from agents"
|
|
1108
923
|
)
|
|
1109
924
|
|
|
1110
|
-
|
|
925
|
+
# Build finish message with cleanup info
|
|
926
|
+
if deployed > 0 or removed > 0:
|
|
927
|
+
parts = []
|
|
928
|
+
if deployed > 0:
|
|
929
|
+
parts.append(f"{deployed} new")
|
|
930
|
+
if skipped > 0:
|
|
931
|
+
parts.append(f"{skipped} unchanged")
|
|
932
|
+
if removed > 0:
|
|
933
|
+
parts.append(f"{removed} removed")
|
|
934
|
+
|
|
935
|
+
status = ", ".join(parts)
|
|
936
|
+
|
|
1111
937
|
if filtered > 0:
|
|
1112
938
|
deploy_progress.finish(
|
|
1113
|
-
f"Complete: {
|
|
1114
|
-
f"({total_available} {source_label}, {filtered} files in cache)"
|
|
939
|
+
f"Complete: {status} ({total_available} {source_label}, {filtered} files in cache)"
|
|
1115
940
|
)
|
|
1116
941
|
else:
|
|
1117
942
|
deploy_progress.finish(
|
|
1118
|
-
f"Complete: {
|
|
1119
|
-
f"({total_available} skills {source_label} from {total_skill_count} files in cache)"
|
|
943
|
+
f"Complete: {status} ({total_available} skills {source_label} from {total_skill_count} files in cache)"
|
|
1120
944
|
)
|
|
1121
945
|
elif filtered > 0:
|
|
1122
946
|
# Skills filtered means agents require fewer skills than available
|
|
@@ -1124,10 +948,12 @@ def sync_remote_skills_on_startup():
|
|
|
1124
948
|
f"No skills needed ({source_label}, {total_skill_count} files in cache)"
|
|
1125
949
|
)
|
|
1126
950
|
else:
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
951
|
+
# No changes - all skills already deployed
|
|
952
|
+
msg = f"Complete: {total_available} skills {source_label}"
|
|
953
|
+
if removed > 0:
|
|
954
|
+
msg += f", {removed} removed"
|
|
955
|
+
msg += f" ({total_skill_count} files in cache)"
|
|
956
|
+
deploy_progress.finish(msg)
|
|
1131
957
|
|
|
1132
958
|
# Log deployment errors if any
|
|
1133
959
|
from ..core.logger import get_logger
|
|
@@ -1244,61 +1070,64 @@ def show_skill_summary():
|
|
|
1244
1070
|
Display skill availability summary on startup.
|
|
1245
1071
|
|
|
1246
1072
|
WHY: Users should see at a glance how many skills are deployed and available
|
|
1247
|
-
from
|
|
1073
|
+
from cache, similar to the agent summary showing "X deployed / Y cached".
|
|
1248
1074
|
|
|
1249
|
-
DESIGN DECISION: Fast, non-blocking check that counts skills from
|
|
1250
|
-
|
|
1075
|
+
DESIGN DECISION: Fast, non-blocking check that counts skills from:
|
|
1076
|
+
- Deployed skills: PROJECT-level .claude/skills/ directory
|
|
1077
|
+
- Cached skills: ~/.claude-mpm/cache/skills/ directory (from remote sources)
|
|
1078
|
+
|
|
1079
|
+
Shows format: "✓ Skills: X deployed / Y cached"
|
|
1251
1080
|
Failures are silent to avoid blocking startup.
|
|
1252
1081
|
"""
|
|
1253
1082
|
try:
|
|
1254
1083
|
from pathlib import Path
|
|
1255
1084
|
|
|
1256
|
-
# Count deployed skills (
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
if
|
|
1085
|
+
# Count deployed skills (PROJECT-level, not user-level)
|
|
1086
|
+
project_skills_dir = Path.cwd() / ".claude" / "skills"
|
|
1087
|
+
deployed_count = 0
|
|
1088
|
+
if project_skills_dir.exists():
|
|
1260
1089
|
# Count directories with SKILL.md (excludes collection repos)
|
|
1261
1090
|
# Exclude collection directories (obra-superpowers, etc.)
|
|
1262
1091
|
skill_dirs = [
|
|
1263
1092
|
d
|
|
1264
|
-
for d in
|
|
1093
|
+
for d in project_skills_dir.iterdir()
|
|
1265
1094
|
if d.is_dir()
|
|
1266
1095
|
and (d / "SKILL.md").exists()
|
|
1267
1096
|
and not (d / ".git").exists() # Exclude collection repos
|
|
1268
1097
|
]
|
|
1269
|
-
|
|
1098
|
+
deployed_count = len(skill_dirs)
|
|
1270
1099
|
|
|
1271
|
-
# Count
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
):
|
|
1100
|
+
# Count cached skills (from remote sources, not deployed yet)
|
|
1101
|
+
# This matches the agent summary pattern: deployed vs cached
|
|
1102
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "skills"
|
|
1103
|
+
cached_count = 0
|
|
1104
|
+
if cache_dir.exists():
|
|
1105
|
+
# Scan all repository directories in cache
|
|
1106
|
+
# Cache structure: ~/.claude-mpm/cache/skills/{owner}/{repo}/...
|
|
1107
|
+
for repo_dir in cache_dir.rglob("*"):
|
|
1108
|
+
if not repo_dir.is_dir():
|
|
1280
1109
|
continue
|
|
1281
1110
|
|
|
1282
|
-
# Count skill directories
|
|
1111
|
+
# Count skill directories (those with SKILL.md)
|
|
1283
1112
|
# Skills can be nested in: skills/category/skill-name/SKILL.md
|
|
1284
1113
|
# or in flat structure: skill-name/SKILL.md
|
|
1285
|
-
for root, dirs, files in os.walk(
|
|
1114
|
+
for root, dirs, files in os.walk(repo_dir):
|
|
1286
1115
|
if "SKILL.md" in files:
|
|
1287
|
-
# Exclude build artifacts and hidden directories
|
|
1288
|
-
# Get relative path from collection_dir to avoid excluding based on .claude parent
|
|
1116
|
+
# Exclude build artifacts and hidden directories
|
|
1289
1117
|
root_path = Path(root)
|
|
1290
|
-
relative_parts = root_path.relative_to(collection_dir).parts
|
|
1291
1118
|
if not any(
|
|
1292
1119
|
part.startswith(".")
|
|
1293
1120
|
or part in ["dist", "build", "__pycache__"]
|
|
1294
|
-
for part in
|
|
1121
|
+
for part in root_path.parts
|
|
1295
1122
|
):
|
|
1296
|
-
|
|
1123
|
+
cached_count += 1
|
|
1297
1124
|
|
|
1298
|
-
# Display summary
|
|
1299
|
-
|
|
1125
|
+
# Display summary using agent summary format: "X deployed / Y cached"
|
|
1126
|
+
# Only show non-deployed cached skills (subtract deployed from cached)
|
|
1127
|
+
non_deployed_cached = max(0, cached_count - deployed_count)
|
|
1128
|
+
if deployed_count > 0 or non_deployed_cached > 0:
|
|
1300
1129
|
print(
|
|
1301
|
-
f"✓ Skills: {
|
|
1130
|
+
f"✓ Skills: {deployed_count} deployed / {non_deployed_cached} cached",
|
|
1302
1131
|
flush=True,
|
|
1303
1132
|
)
|
|
1304
1133
|
|
|
@@ -1311,33 +1140,70 @@ def show_skill_summary():
|
|
|
1311
1140
|
|
|
1312
1141
|
|
|
1313
1142
|
def verify_and_show_pm_skills():
|
|
1314
|
-
"""Verify PM skills and display status.
|
|
1143
|
+
"""Verify PM skills and display status with enhanced validation.
|
|
1315
1144
|
|
|
1316
|
-
WHY: PM skills are
|
|
1317
|
-
|
|
1145
|
+
WHY: PM skills are CRITICAL for PM agent operation. PM must KNOW if
|
|
1146
|
+
framework knowledge is unavailable at startup. Enhanced validation
|
|
1147
|
+
checks all required skills exist, are not corrupted, and auto-repairs
|
|
1148
|
+
if needed.
|
|
1149
|
+
|
|
1150
|
+
Shows deployment status:
|
|
1151
|
+
- "✓ PM skills: 8/8 verified" if all required skills are valid
|
|
1152
|
+
- "⚠ PM skills: 2 missing, auto-repairing..." if issues detected
|
|
1153
|
+
- Non-blocking but visible warning if auto-repair fails
|
|
1318
1154
|
"""
|
|
1319
1155
|
try:
|
|
1320
1156
|
from pathlib import Path
|
|
1321
1157
|
|
|
1322
|
-
from ..services.pm_skills_deployer import
|
|
1158
|
+
from ..services.pm_skills_deployer import (
|
|
1159
|
+
REQUIRED_PM_SKILLS,
|
|
1160
|
+
PMSkillsDeployerService,
|
|
1161
|
+
)
|
|
1323
1162
|
|
|
1324
1163
|
deployer = PMSkillsDeployerService()
|
|
1325
1164
|
project_dir = Path.cwd()
|
|
1326
1165
|
|
|
1327
|
-
|
|
1166
|
+
# Verify with auto-repair enabled
|
|
1167
|
+
result = deployer.verify_pm_skills(project_dir, auto_repair=True)
|
|
1328
1168
|
|
|
1329
1169
|
if result.verified:
|
|
1330
|
-
# Show verified status
|
|
1331
|
-
|
|
1170
|
+
# Show verified status with count
|
|
1171
|
+
total_required = len(REQUIRED_PM_SKILLS)
|
|
1172
|
+
print(
|
|
1173
|
+
f"✓ PM skills: {total_required}/{total_required} verified", flush=True
|
|
1174
|
+
)
|
|
1332
1175
|
else:
|
|
1333
|
-
#
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1176
|
+
# Show warning with details
|
|
1177
|
+
missing_count = len(result.missing_skills)
|
|
1178
|
+
corrupted_count = len(result.corrupted_skills)
|
|
1179
|
+
|
|
1180
|
+
# Build status message
|
|
1181
|
+
issues = []
|
|
1182
|
+
if missing_count > 0:
|
|
1183
|
+
issues.append(f"{missing_count} missing")
|
|
1184
|
+
if corrupted_count > 0:
|
|
1185
|
+
issues.append(f"{corrupted_count} corrupted")
|
|
1186
|
+
|
|
1187
|
+
status = ", ".join(issues)
|
|
1188
|
+
|
|
1189
|
+
# Check if auto-repair was attempted
|
|
1190
|
+
if "Auto-repaired" in result.message:
|
|
1191
|
+
# Auto-repair succeeded
|
|
1192
|
+
total_required = len(REQUIRED_PM_SKILLS)
|
|
1193
|
+
print(
|
|
1194
|
+
f"✓ PM skills: {total_required}/{total_required} verified (auto-repaired)",
|
|
1195
|
+
flush=True,
|
|
1196
|
+
)
|
|
1339
1197
|
else:
|
|
1340
|
-
|
|
1198
|
+
# Auto-repair failed or not attempted
|
|
1199
|
+
print(f"⚠ PM skills: {status}", flush=True)
|
|
1200
|
+
|
|
1201
|
+
# Log warnings for debugging
|
|
1202
|
+
from ..core.logger import get_logger
|
|
1203
|
+
|
|
1204
|
+
logger = get_logger("cli")
|
|
1205
|
+
for warning in result.warnings:
|
|
1206
|
+
logger.warning(f"PM skills: {warning}")
|
|
1341
1207
|
|
|
1342
1208
|
except ImportError:
|
|
1343
1209
|
# PM skills deployer not available - skip silently
|
|
@@ -1372,7 +1238,7 @@ def auto_install_chrome_devtools_on_startup():
|
|
|
1372
1238
|
if not chrome_devtools_config.get("auto_install", True):
|
|
1373
1239
|
# Auto-install disabled, skip silently
|
|
1374
1240
|
return
|
|
1375
|
-
except Exception:
|
|
1241
|
+
except Exception: # nosec B110
|
|
1376
1242
|
# If config loading fails, assume auto-install is enabled (default)
|
|
1377
1243
|
pass
|
|
1378
1244
|
|
|
@@ -1390,7 +1256,7 @@ def auto_install_chrome_devtools_on_startup():
|
|
|
1390
1256
|
# Continue execution - chrome-devtools installation failure shouldn't block startup
|
|
1391
1257
|
|
|
1392
1258
|
|
|
1393
|
-
def run_background_services():
|
|
1259
|
+
def run_background_services(force_sync: bool = False):
|
|
1394
1260
|
"""
|
|
1395
1261
|
Initialize all background services on startup.
|
|
1396
1262
|
|
|
@@ -1401,6 +1267,9 @@ def run_background_services():
|
|
|
1401
1267
|
explicitly requests them via agent-manager commands. This prevents unwanted
|
|
1402
1268
|
file creation in project .claude/ directories.
|
|
1403
1269
|
See: SystemInstructionsDeployer and agent_deployment.py line 504-509
|
|
1270
|
+
|
|
1271
|
+
Args:
|
|
1272
|
+
force_sync: Force download even if cache is fresh (bypasses ETag).
|
|
1404
1273
|
"""
|
|
1405
1274
|
# Sync hooks early to ensure up-to-date configuration
|
|
1406
1275
|
# RATIONALE: Hooks should be synced before other services to fix stale configs
|
|
@@ -1411,7 +1280,9 @@ def run_background_services():
|
|
|
1411
1280
|
check_mcp_auto_configuration()
|
|
1412
1281
|
verify_mcp_gateway_startup()
|
|
1413
1282
|
check_for_updates_async()
|
|
1414
|
-
sync_remote_agents_on_startup(
|
|
1283
|
+
sync_remote_agents_on_startup(
|
|
1284
|
+
force_sync=force_sync
|
|
1285
|
+
) # Sync agents from remote sources
|
|
1415
1286
|
show_agent_summary() # Display agent counts after deployment
|
|
1416
1287
|
|
|
1417
1288
|
# Skills deployment order (precedence: remote > bundled)
|
|
@@ -1420,7 +1291,9 @@ def run_background_services():
|
|
|
1420
1291
|
# 3. Discover and link runtime skills (user-added skills)
|
|
1421
1292
|
# This ensures remote skills take precedence over bundled skills when names conflict
|
|
1422
1293
|
deploy_bundled_skills() # Base layer: package-bundled skills
|
|
1423
|
-
sync_remote_skills_on_startup(
|
|
1294
|
+
sync_remote_skills_on_startup(
|
|
1295
|
+
force_sync=force_sync
|
|
1296
|
+
) # Override layer: Git-based skills (takes precedence)
|
|
1424
1297
|
discover_and_link_runtime_skills() # Discovery: user-added skills
|
|
1425
1298
|
show_skill_summary() # Display skill counts after deployment
|
|
1426
1299
|
verify_and_show_pm_skills() # PM skills verification and status
|
|
@@ -1620,7 +1493,7 @@ def verify_mcp_gateway_startup():
|
|
|
1620
1493
|
loop.run_until_complete(
|
|
1621
1494
|
asyncio.gather(*pending, return_exceptions=True)
|
|
1622
1495
|
)
|
|
1623
|
-
except Exception:
|
|
1496
|
+
except Exception: # nosec B110
|
|
1624
1497
|
pass # Ignore cleanup errors
|
|
1625
1498
|
finally:
|
|
1626
1499
|
loop.close()
|
|
@@ -1714,7 +1587,7 @@ def check_for_updates_async():
|
|
|
1714
1587
|
|
|
1715
1588
|
logger = get_logger("upgrade_check")
|
|
1716
1589
|
logger.debug(f"Update check failed (non-critical): {e}")
|
|
1717
|
-
except Exception:
|
|
1590
|
+
except Exception: # nosec B110
|
|
1718
1591
|
pass # Avoid any errors in error handling
|
|
1719
1592
|
finally:
|
|
1720
1593
|
# Properly clean up event loop
|
|
@@ -1729,7 +1602,7 @@ def check_for_updates_async():
|
|
|
1729
1602
|
loop.run_until_complete(
|
|
1730
1603
|
asyncio.gather(*pending, return_exceptions=True)
|
|
1731
1604
|
)
|
|
1732
|
-
except Exception:
|
|
1605
|
+
except Exception: # nosec B110
|
|
1733
1606
|
pass # Ignore cleanup errors
|
|
1734
1607
|
finally:
|
|
1735
1608
|
loop.close()
|