claude-mpm 5.4.36__py3-none-any.whl → 5.4.62__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/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +5 -0
- claude_mpm/agents/PM_INSTRUCTIONS.md +489 -177
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/frontmatter_validator.py +2 -2
- claude_mpm/cli/commands/configure_agent_display.py +12 -0
- claude_mpm/cli/commands/mpm_init/core.py +72 -0
- claude_mpm/cli/commands/profile.py +276 -0
- claude_mpm/cli/commands/skills.py +14 -18
- claude_mpm/cli/executor.py +10 -0
- claude_mpm/cli/parsers/base_parser.py +7 -0
- claude_mpm/cli/parsers/profile_parser.py +147 -0
- claude_mpm/cli/parsers/skills_parser.py +0 -6
- claude_mpm/cli/startup.py +433 -147
- claude_mpm/commands/mpm-config.md +13 -250
- claude_mpm/commands/mpm-doctor.md +9 -22
- claude_mpm/commands/mpm-help.md +5 -206
- claude_mpm/commands/mpm-init.md +81 -507
- claude_mpm/commands/mpm-monitor.md +15 -402
- claude_mpm/commands/mpm-organize.md +61 -441
- claude_mpm/commands/mpm-postmortem.md +6 -108
- claude_mpm/commands/mpm-session-resume.md +12 -363
- claude_mpm/commands/mpm-status.md +5 -69
- claude_mpm/commands/mpm-ticket-view.md +52 -495
- claude_mpm/commands/mpm-version.md +5 -107
- claude_mpm/core/optimized_startup.py +61 -0
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CWc5urbQ.js → 4TdZjIqw.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B0uc0UOD.js +36 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7RN905-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7xVLGWV.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BIF9m_hv.js +61 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BPYeabCQ.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/{uj46x2Wr.js → BSNlmTZj.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Be7GpZd6.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bh0LDWpI.js +145 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BofRWZRR.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BovzEFCE.js +30 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C30mlcqg.js +165 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4B-KCzX.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4JcI4KD.js +122 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CBBdVcY8.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CDuw-vjf.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C_Usid8X.js +15 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cfqx1Qun.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CiIAseT4.js +128 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CnA0NrzZ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cs_tUR18.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CyWMqx4W.js +43 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzZX-COe.js +220 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzeYkLYB.js +65 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D3k0OPJN.js +4 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9lljYKQ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DGkLK5U1.js +267 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DI7hHRFL.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DLVjFsZ3.js +139 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUrLdbGD.js +89 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DY1XQ8fi.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DZX00Y4g.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DaimHw_p.js +68 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +323 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dhb8PKl3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dle-35c7.js +64 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DmxopI1J.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DwBR2MJi.js +60 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/GYwsonyD.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DjhvlsAc.js → NqQ1dWOy.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/RJiighC3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{N4qtv3Hx.js → Vzk33B_K.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ZGh7QtNv.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bT1r9zLR.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bTOqqlTd.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/eNVUfhuA.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/iEWssX7S.js +162 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/sQeU3Y1z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uuIeMWc-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.D6-I5TpK.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.CAGBuiOw.js → 0.m1gL8KXf.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.CgNOuw-d.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
- claude_mpm/dashboard/static/svelte-build/index.html +10 -10
- 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/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/init.py +276 -0
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/deployment/agent_deployment.py +22 -0
- claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -1
- claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +37 -17
- claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
- claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +149 -4
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +47 -26
- claude_mpm/services/agents/git_source_manager.py +21 -2
- claude_mpm/services/agents/sources/git_source_sync_service.py +116 -5
- claude_mpm/services/monitor/management/lifecycle.py +7 -1
- claude_mpm/services/pm_skills_deployer.py +711 -0
- claude_mpm/services/profile_manager.py +337 -0
- claude_mpm/services/skills/git_skill_source_manager.py +148 -11
- claude_mpm/services/skills/selective_skill_deployer.py +97 -48
- claude_mpm/services/skills_deployer.py +161 -65
- 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/pm-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/pm-git-file-tracking/SKILL.md +113 -0
- claude_mpm/skills/bundled/pm/pm-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/pm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/pm-verification-protocols/SKILL.md +198 -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/skill_manager.py +98 -3
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/METADATA +3 -2
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/RECORD +244 -68
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/top_level.txt +0 -0
|
@@ -206,8 +206,8 @@ class AgentBuilderService:
|
|
|
206
206
|
"""
|
|
207
207
|
errors = []
|
|
208
208
|
|
|
209
|
-
# Required fields
|
|
210
|
-
required_fields = ["id", "name", "prompt"
|
|
209
|
+
# Required fields (model is optional - defaults to sonnet if not specified)
|
|
210
|
+
required_fields = ["id", "name", "prompt"]
|
|
211
211
|
for field in required_fields:
|
|
212
212
|
if field not in config:
|
|
213
213
|
errors.append(f"Missing required field: {field}")
|
|
@@ -219,7 +219,7 @@ class AgentBuilderService:
|
|
|
219
219
|
except AgentDeploymentError as e:
|
|
220
220
|
errors.append(str(e))
|
|
221
221
|
|
|
222
|
-
# Validate model
|
|
222
|
+
# Validate model (only if present)
|
|
223
223
|
if "model" in config:
|
|
224
224
|
try:
|
|
225
225
|
self._validate_model(config["model"])
|
|
@@ -898,6 +898,9 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
898
898
|
)
|
|
899
899
|
)
|
|
900
900
|
|
|
901
|
+
# Keep track of all enabled agents before filtering (for cleanup)
|
|
902
|
+
all_enabled_agents = agents_to_deploy.copy()
|
|
903
|
+
|
|
901
904
|
# Compare with deployed versions if agents directory exists
|
|
902
905
|
if agents_dir.exists():
|
|
903
906
|
comparison_results = self.multi_source_service.compare_deployed_versions(
|
|
@@ -954,6 +957,25 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
954
957
|
f"All {len(comparison_results.get('up_to_date', []))} agents are up to date"
|
|
955
958
|
)
|
|
956
959
|
|
|
960
|
+
# Cleanup excluded agents (remove agents not in deployment list)
|
|
961
|
+
# CRITICAL: Use all_enabled_agents (before filtering for updates) to preserve up-to-date agents
|
|
962
|
+
# Bug fix (1M-XXX): Previously used filtered agents_to_deploy which could be empty,
|
|
963
|
+
# causing all agents to be removed when everything was up-to-date
|
|
964
|
+
exclusion_cleanup_results = self.multi_source_service.cleanup_excluded_agents(
|
|
965
|
+
deployed_agents_dir=agents_dir,
|
|
966
|
+
agents_to_deploy=all_enabled_agents,
|
|
967
|
+
)
|
|
968
|
+
|
|
969
|
+
# Add exclusion cleanup results to main cleanup results
|
|
970
|
+
if exclusion_cleanup_results.get("removed"):
|
|
971
|
+
cleanup_results.setdefault("excluded_removed", []).extend(
|
|
972
|
+
exclusion_cleanup_results["removed"]
|
|
973
|
+
)
|
|
974
|
+
self.logger.info(
|
|
975
|
+
f"Removed {len(exclusion_cleanup_results['removed'])} excluded agents: "
|
|
976
|
+
f"{', '.join(exclusion_cleanup_results['removed'])}"
|
|
977
|
+
)
|
|
978
|
+
|
|
957
979
|
# Convert to list of Path objects
|
|
958
980
|
template_files = list(agents_to_deploy.values())
|
|
959
981
|
|
|
@@ -248,7 +248,9 @@ class AgentDiscoveryService:
|
|
|
248
248
|
return agent_info
|
|
249
249
|
|
|
250
250
|
except yaml.YAMLError as e:
|
|
251
|
-
self.logger.warning(
|
|
251
|
+
self.logger.warning(
|
|
252
|
+
f"Invalid YAML frontmatter in {template_file.name}: {e}"
|
|
253
|
+
)
|
|
252
254
|
return None
|
|
253
255
|
except Exception as e:
|
|
254
256
|
self.logger.error(
|
|
@@ -137,8 +137,8 @@ class AgentFormatConverter:
|
|
|
137
137
|
else:
|
|
138
138
|
pass
|
|
139
139
|
|
|
140
|
-
# Extract additional fields
|
|
141
|
-
model = self.extract_yaml_field(yaml_content, "model")
|
|
140
|
+
# Extract additional fields - model is optional (Claude Code uses conversation model if not set)
|
|
141
|
+
model = self.extract_yaml_field(yaml_content, "model") # None if not specified
|
|
142
142
|
author = (
|
|
143
143
|
self.extract_yaml_field(yaml_content, "author")
|
|
144
144
|
or "claude-mpm@anthropic.com"
|
|
@@ -147,7 +147,7 @@ class AgentFormatConverter:
|
|
|
147
147
|
# Extract instructions from YAML content
|
|
148
148
|
instructions = self._extract_instructions_from_yaml(yaml_content, agent_name)
|
|
149
149
|
|
|
150
|
-
# Map model names to Claude Code format
|
|
150
|
+
# Map model names to Claude Code format (only if model is specified)
|
|
151
151
|
model_map = {
|
|
152
152
|
"claude-3-5-sonnet-20241022": "sonnet",
|
|
153
153
|
"claude-3-5-sonnet": "sonnet",
|
|
@@ -159,7 +159,8 @@ class AgentFormatConverter:
|
|
|
159
159
|
"opus": "opus",
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
|
|
162
|
+
# Only map model if it's not None (preserve None for agents without model field)
|
|
163
|
+
mapped_model = model_map.get(model, model) if model is not None else None
|
|
163
164
|
|
|
164
165
|
# Create multiline description with example (Claude Code format)
|
|
165
166
|
multiline_description = f"""{description}
|
|
@@ -172,16 +173,27 @@ assistant: "I'll use the {name} agent to provide specialized assistance."
|
|
|
172
173
|
|
|
173
174
|
# Build new YAML frontmatter - Claude Code compatible format
|
|
174
175
|
# NOTE: Removed tags field and other non-essential fields for Claude Code compatibility
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
author: "{author}"
|
|
182
|
-
---
|
|
176
|
+
frontmatter_lines = [
|
|
177
|
+
"---",
|
|
178
|
+
f"name: {name}",
|
|
179
|
+
"description: |",
|
|
180
|
+
f" {self._indent_text(multiline_description, 2)}",
|
|
181
|
+
]
|
|
183
182
|
|
|
184
|
-
|
|
183
|
+
# Only include model field if explicitly set in source
|
|
184
|
+
if mapped_model is not None:
|
|
185
|
+
frontmatter_lines.append(f"model: {mapped_model}")
|
|
186
|
+
|
|
187
|
+
frontmatter_lines.extend(
|
|
188
|
+
[
|
|
189
|
+
f'version: "{version}"',
|
|
190
|
+
f'author: "{author}"',
|
|
191
|
+
"---",
|
|
192
|
+
"",
|
|
193
|
+
]
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
new_frontmatter = "\n".join(frontmatter_lines)
|
|
185
197
|
|
|
186
198
|
return new_frontmatter + instructions
|
|
187
199
|
|
|
@@ -419,7 +419,7 @@ class AgentTemplateBuilder:
|
|
|
419
419
|
if non_standard:
|
|
420
420
|
self.logger.info(f"Using non-standard tools: {non_standard}")
|
|
421
421
|
|
|
422
|
-
# Extract model from template
|
|
422
|
+
# Extract model from template (no fallback - preserve None if not specified)
|
|
423
423
|
capabilities_model = (
|
|
424
424
|
capabilities.get("model") if isinstance(capabilities, dict) else None
|
|
425
425
|
)
|
|
@@ -428,7 +428,7 @@ class AgentTemplateBuilder:
|
|
|
428
428
|
template_data.get("model")
|
|
429
429
|
or capabilities_model
|
|
430
430
|
or template_data.get("configuration_fields", {}).get("model")
|
|
431
|
-
|
|
431
|
+
# No default fallback - preserve None if not set
|
|
432
432
|
)
|
|
433
433
|
|
|
434
434
|
# Convert tools list to comma-separated string (without spaces for compatibility)
|
|
@@ -448,11 +448,11 @@ class AgentTemplateBuilder:
|
|
|
448
448
|
"opus": "opus",
|
|
449
449
|
}
|
|
450
450
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
model
|
|
451
|
+
# Only map model if it's not None
|
|
452
|
+
if model is not None:
|
|
453
|
+
if model in model_map:
|
|
454
|
+
model = model_map[model]
|
|
455
|
+
# If model is specified but not in map, keep as-is (no default)
|
|
456
456
|
|
|
457
457
|
# Get response format from template or use base agent default
|
|
458
458
|
template_data.get("response", {}).get("format", "structured")
|
|
@@ -559,8 +559,9 @@ class AgentTemplateBuilder:
|
|
|
559
559
|
f"description: {self._format_description_for_yaml(description)}"
|
|
560
560
|
)
|
|
561
561
|
|
|
562
|
-
# Add model field (required for Claude Code)
|
|
563
|
-
|
|
562
|
+
# Add model field only if explicitly set (not required for Claude Code)
|
|
563
|
+
if model is not None:
|
|
564
|
+
frontmatter_lines.append(f"model: {model}")
|
|
564
565
|
|
|
565
566
|
# Add type field (important for agent categorization)
|
|
566
567
|
if agent_type and agent_type != "general":
|
|
@@ -585,6 +586,14 @@ class AgentTemplateBuilder:
|
|
|
585
586
|
tags_str = ",".join(metadata["tags"])
|
|
586
587
|
frontmatter_lines.append(f"tags: {tags_str}")
|
|
587
588
|
|
|
589
|
+
# CRITICAL: Preserve skills field from template for selective skill deployment
|
|
590
|
+
# Skills are used by startup.py to determine which skills to deploy
|
|
591
|
+
skills = template_data.get("skills", [])
|
|
592
|
+
if skills and isinstance(skills, list):
|
|
593
|
+
frontmatter_lines.append("skills:")
|
|
594
|
+
for skill in skills:
|
|
595
|
+
frontmatter_lines.append(f"- {skill}")
|
|
596
|
+
|
|
588
597
|
frontmatter_lines.extend(
|
|
589
598
|
[
|
|
590
599
|
"---",
|
|
@@ -718,21 +727,32 @@ Only include memories that are:
|
|
|
718
727
|
"description", f"{name} agent for specialized tasks"
|
|
719
728
|
)
|
|
720
729
|
|
|
721
|
-
# Get tools and model
|
|
730
|
+
# Get tools and model (no fallback for model)
|
|
722
731
|
raw_tools = merged_config.get("tools")
|
|
723
732
|
tools = self.normalize_tools_input(raw_tools)
|
|
724
|
-
model = merged_config.get("model"
|
|
733
|
+
model = merged_config.get("model") # No default - preserve None
|
|
725
734
|
|
|
726
735
|
# Format tools as YAML list
|
|
727
736
|
tools_yaml = self.format_yaml_list(tools, 2)
|
|
728
737
|
|
|
729
738
|
# Build YAML content with only essential fields
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
739
|
+
yaml_lines = [
|
|
740
|
+
f"name: {name}",
|
|
741
|
+
f"description: {description}",
|
|
742
|
+
]
|
|
743
|
+
|
|
744
|
+
# Only include model if explicitly set
|
|
745
|
+
if model is not None:
|
|
746
|
+
yaml_lines.append(f"model: {model}")
|
|
747
|
+
|
|
748
|
+
yaml_lines.extend(
|
|
749
|
+
[
|
|
750
|
+
"tools:",
|
|
751
|
+
tools_yaml,
|
|
752
|
+
]
|
|
753
|
+
)
|
|
754
|
+
|
|
755
|
+
return "\n".join(yaml_lines) + "\n"
|
|
736
756
|
|
|
737
757
|
def merge_narrative_fields(self, base_data: dict, template_data: dict) -> dict:
|
|
738
758
|
"""
|
|
@@ -551,38 +551,39 @@ class AsyncAgentDeploymentService:
|
|
|
551
551
|
or ["Read", "Write", "Edit", "Grep", "Glob", "LS"] # Default fallback
|
|
552
552
|
)
|
|
553
553
|
|
|
554
|
-
# Get model from capabilities.model in new format
|
|
554
|
+
# Get model from capabilities.model in new format (no default fallback)
|
|
555
555
|
model = (
|
|
556
556
|
agent_data.get("capabilities", {}).get("model")
|
|
557
557
|
or agent_data.get("configuration_fields", {}).get("model")
|
|
558
|
-
|
|
558
|
+
# No default fallback - preserve None if not set
|
|
559
559
|
)
|
|
560
560
|
|
|
561
|
-
# Simplify model name for Claude Code
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
if
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
561
|
+
# Simplify model name for Claude Code (only if model is specified)
|
|
562
|
+
if model is not None:
|
|
563
|
+
model_map = {
|
|
564
|
+
"claude-4-sonnet-20250514": "sonnet",
|
|
565
|
+
"claude-sonnet-4-20250514": "sonnet",
|
|
566
|
+
"claude-opus-4-20250514": "opus",
|
|
567
|
+
"claude-3-opus-20240229": "opus",
|
|
568
|
+
"claude-3-haiku-20240307": "haiku",
|
|
569
|
+
"claude-3.5-sonnet": "sonnet",
|
|
570
|
+
"claude-3-sonnet": "sonnet",
|
|
571
|
+
}
|
|
572
|
+
# Better fallback: extract the model type (opus/sonnet/haiku) from the string
|
|
573
|
+
if model not in model_map:
|
|
574
|
+
if "opus" in model.lower():
|
|
575
|
+
model = "opus"
|
|
576
|
+
elif "sonnet" in model.lower():
|
|
577
|
+
model = "sonnet"
|
|
578
|
+
elif "haiku" in model.lower():
|
|
579
|
+
model = "haiku"
|
|
580
|
+
else:
|
|
581
|
+
# Last resort: try to extract from hyphenated format
|
|
582
|
+
model = model_map.get(
|
|
583
|
+
model, model.split("-")[-1] if "-" in model else model
|
|
584
|
+
)
|
|
579
585
|
else:
|
|
580
|
-
|
|
581
|
-
model = model_map.get(
|
|
582
|
-
model, model.split("-")[-1] if "-" in model else model
|
|
583
|
-
)
|
|
584
|
-
else:
|
|
585
|
-
model = model_map[model]
|
|
586
|
+
model = model_map[model]
|
|
586
587
|
|
|
587
588
|
# Convert tools list to comma-separated string for Claude Code compatibility
|
|
588
589
|
# IMPORTANT: No spaces after commas - Claude Code requires exact format
|
|
@@ -601,9 +602,12 @@ class AsyncAgentDeploymentService:
|
|
|
601
602
|
f"base_version: {self._format_version_display(base_version)}",
|
|
602
603
|
"author: claude-mpm", # Identify as system agent for deployment
|
|
603
604
|
f"tools: {tools_str}",
|
|
604
|
-
f"model: {model}",
|
|
605
605
|
]
|
|
606
606
|
|
|
607
|
+
# Only include model field if explicitly set
|
|
608
|
+
if model is not None:
|
|
609
|
+
frontmatter_lines.append(f"model: {model}")
|
|
610
|
+
|
|
607
611
|
# Add optional fields if present
|
|
608
612
|
# Check for color in metadata section (new format) or root (old format)
|
|
609
613
|
color = agent_data.get("metadata", {}).get("color") or agent_data.get("color")
|
|
@@ -157,7 +157,9 @@ class LocalTemplateDeploymentService:
|
|
|
157
157
|
|
|
158
158
|
# Add capabilities
|
|
159
159
|
if template.capabilities:
|
|
160
|
-
|
|
160
|
+
# Only include model if explicitly set (no default)
|
|
161
|
+
if "model" in template.capabilities:
|
|
162
|
+
frontmatter["model"] = template.capabilities["model"]
|
|
161
163
|
tools = template.capabilities.get("tools", "*")
|
|
162
164
|
if tools == "*":
|
|
163
165
|
frontmatter["tools"] = "all"
|
|
@@ -26,6 +26,18 @@ from .agent_version_manager import AgentVersionManager
|
|
|
26
26
|
from .remote_agent_discovery_service import RemoteAgentDiscoveryService
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
def _normalize_agent_name(name: str) -> str:
|
|
30
|
+
"""Normalize agent name for consistent comparison.
|
|
31
|
+
|
|
32
|
+
Converts spaces, underscores to hyphens and lowercases.
|
|
33
|
+
Examples:
|
|
34
|
+
"Dart Engineer" -> "dart-engineer"
|
|
35
|
+
"dart_engineer" -> "dart-engineer"
|
|
36
|
+
"DART-ENGINEER" -> "dart-engineer"
|
|
37
|
+
"""
|
|
38
|
+
return name.lower().replace(" ", "-").replace("_", "-")
|
|
39
|
+
|
|
40
|
+
|
|
29
41
|
class MultiSourceAgentDeploymentService:
|
|
30
42
|
"""Service for deploying agents from multiple sources with version comparison.
|
|
31
43
|
|
|
@@ -531,10 +543,42 @@ class MultiSourceAgentDeploymentService:
|
|
|
531
543
|
|
|
532
544
|
# Apply exclusion filters
|
|
533
545
|
if excluded_agents:
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
546
|
+
# Find agents to remove by matching normalized names
|
|
547
|
+
# Normalization handles: "Dart Engineer", "dart_engineer", "dart-engineer"
|
|
548
|
+
agents_to_remove = []
|
|
549
|
+
excluded_set = {_normalize_agent_name(name) for name in excluded_agents}
|
|
550
|
+
|
|
551
|
+
for canonical_id, agent_info in list(selected_agents.items()):
|
|
552
|
+
# Check agent name field (normalized)
|
|
553
|
+
agent_name = _normalize_agent_name(agent_info.get("name", ""))
|
|
554
|
+
|
|
555
|
+
# Also check the agent_id portion of canonical_id (after the colon)
|
|
556
|
+
# Example: "bobmatnyc/claude-mpm-agents:pm" -> "pm"
|
|
557
|
+
raw_agent_id = (
|
|
558
|
+
canonical_id.split(":")[-1] if ":" in canonical_id else canonical_id
|
|
559
|
+
)
|
|
560
|
+
agent_id = _normalize_agent_name(raw_agent_id)
|
|
561
|
+
|
|
562
|
+
# Check file stem from path (most reliable match)
|
|
563
|
+
file_stem = ""
|
|
564
|
+
path_str = agent_info.get("path") or agent_info.get("file_path")
|
|
565
|
+
if path_str:
|
|
566
|
+
file_stem = _normalize_agent_name(Path(path_str).stem)
|
|
567
|
+
|
|
568
|
+
if (
|
|
569
|
+
agent_name in excluded_set
|
|
570
|
+
or agent_id in excluded_set
|
|
571
|
+
or file_stem in excluded_set
|
|
572
|
+
):
|
|
573
|
+
agents_to_remove.append(canonical_id)
|
|
574
|
+
self.logger.info(
|
|
575
|
+
f"Excluding agent '{agent_info.get('name', raw_agent_id)}' "
|
|
576
|
+
f"(canonical_id: {canonical_id}) from deployment"
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
# Remove matched agents
|
|
580
|
+
for canonical_id in agents_to_remove:
|
|
581
|
+
del selected_agents[canonical_id]
|
|
538
582
|
|
|
539
583
|
# Apply config-based filtering if provided
|
|
540
584
|
if config:
|
|
@@ -583,6 +627,107 @@ class MultiSourceAgentDeploymentService:
|
|
|
583
627
|
|
|
584
628
|
return agents_to_deploy, agent_sources, cleanup_results
|
|
585
629
|
|
|
630
|
+
def cleanup_excluded_agents(
|
|
631
|
+
self,
|
|
632
|
+
deployed_agents_dir: Path,
|
|
633
|
+
agents_to_deploy: Dict[str, Path],
|
|
634
|
+
) -> Dict[str, Any]:
|
|
635
|
+
"""Remove agents from deployed directory that aren't in the deployment list.
|
|
636
|
+
|
|
637
|
+
Similar to skill cleanup logic, this removes agents that were previously
|
|
638
|
+
deployed but are no longer in the enabled agents list (e.g., filtered out
|
|
639
|
+
by profile configuration).
|
|
640
|
+
|
|
641
|
+
Args:
|
|
642
|
+
deployed_agents_dir: Directory containing deployed agents (~/.claude/agents)
|
|
643
|
+
agents_to_deploy: Dictionary mapping agent file stems to template paths
|
|
644
|
+
|
|
645
|
+
Returns:
|
|
646
|
+
Dictionary with cleanup results:
|
|
647
|
+
- removed: List of removed agent names
|
|
648
|
+
- errors: List of errors during cleanup
|
|
649
|
+
"""
|
|
650
|
+
cleanup_results = {"removed": [], "errors": []}
|
|
651
|
+
|
|
652
|
+
# Safety check - only operate on deployed agents directory
|
|
653
|
+
if not deployed_agents_dir.exists():
|
|
654
|
+
self.logger.debug(
|
|
655
|
+
"Deployed agents directory does not exist, no cleanup needed"
|
|
656
|
+
)
|
|
657
|
+
return cleanup_results
|
|
658
|
+
|
|
659
|
+
# Build set of agent names that should exist (file stems without .md extension)
|
|
660
|
+
expected_agents = set(agents_to_deploy.keys())
|
|
661
|
+
|
|
662
|
+
try:
|
|
663
|
+
# Check each file in deployed_agents_dir
|
|
664
|
+
for item in deployed_agents_dir.iterdir():
|
|
665
|
+
# Only process .md files
|
|
666
|
+
if not item.is_file() or item.suffix != ".md":
|
|
667
|
+
continue
|
|
668
|
+
|
|
669
|
+
# Skip hidden files
|
|
670
|
+
if item.name.startswith("."):
|
|
671
|
+
continue
|
|
672
|
+
|
|
673
|
+
# Get agent name (file stem)
|
|
674
|
+
agent_name = item.stem
|
|
675
|
+
|
|
676
|
+
# Check if this agent should be kept
|
|
677
|
+
if agent_name not in expected_agents:
|
|
678
|
+
try:
|
|
679
|
+
# Security: Validate path is within deployed_agents_dir
|
|
680
|
+
resolved_item = item.resolve()
|
|
681
|
+
resolved_target = deployed_agents_dir.resolve()
|
|
682
|
+
|
|
683
|
+
if not str(resolved_item).startswith(str(resolved_target)):
|
|
684
|
+
self.logger.error(
|
|
685
|
+
f"Refusing to remove path outside target directory: {item}"
|
|
686
|
+
)
|
|
687
|
+
cleanup_results["errors"].append(
|
|
688
|
+
{
|
|
689
|
+
"agent": agent_name,
|
|
690
|
+
"error": "Path outside target directory",
|
|
691
|
+
}
|
|
692
|
+
)
|
|
693
|
+
continue
|
|
694
|
+
|
|
695
|
+
# Remove the agent file
|
|
696
|
+
item.unlink()
|
|
697
|
+
cleanup_results["removed"].append(agent_name)
|
|
698
|
+
self.logger.info(f"Removed excluded agent: {agent_name}")
|
|
699
|
+
|
|
700
|
+
except PermissionError as e:
|
|
701
|
+
error_msg = f"Permission denied removing {agent_name}: {e}"
|
|
702
|
+
self.logger.error(error_msg)
|
|
703
|
+
cleanup_results["errors"].append(
|
|
704
|
+
{"agent": agent_name, "error": error_msg}
|
|
705
|
+
)
|
|
706
|
+
except Exception as e:
|
|
707
|
+
error_msg = f"Error removing {agent_name}: {e}"
|
|
708
|
+
self.logger.error(error_msg)
|
|
709
|
+
cleanup_results["errors"].append(
|
|
710
|
+
{"agent": agent_name, "error": error_msg}
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
except Exception as e:
|
|
714
|
+
self.logger.error(f"Error during agent cleanup: {e}")
|
|
715
|
+
cleanup_results["errors"].append(
|
|
716
|
+
{"agent": "cleanup_process", "error": str(e)}
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
# Log cleanup summary
|
|
720
|
+
if cleanup_results["removed"]:
|
|
721
|
+
self.logger.info(
|
|
722
|
+
f"Cleanup complete: removed {len(cleanup_results['removed'])} excluded agents"
|
|
723
|
+
)
|
|
724
|
+
if cleanup_results["errors"]:
|
|
725
|
+
self.logger.warning(
|
|
726
|
+
f"Encountered {len(cleanup_results['errors'])} errors during cleanup"
|
|
727
|
+
)
|
|
728
|
+
|
|
729
|
+
return cleanup_results
|
|
730
|
+
|
|
586
731
|
def cleanup_outdated_user_agents(
|
|
587
732
|
self,
|
|
588
733
|
agents_by_name: Dict[str, List[Dict[str, Any]]],
|
|
@@ -402,10 +402,11 @@ class RemoteAgentDiscoveryService:
|
|
|
402
402
|
)
|
|
403
403
|
return agents
|
|
404
404
|
|
|
405
|
-
# Support
|
|
405
|
+
# Support four cache structures (PRIORITY ORDER):
|
|
406
406
|
# 1. Built output: {path}/dist/agents/ - PREFERRED (built with BASE-AGENT composition)
|
|
407
407
|
# 2. Git repo path: {path}/agents/ - source files (fallback)
|
|
408
|
-
# 3.
|
|
408
|
+
# 3. Owner/repo structure: {path}/{owner}/{repo}/agents/ - GitHub sync structure
|
|
409
|
+
# 4. Flattened cache: {path}/ - directly contains category directories (legacy)
|
|
409
410
|
|
|
410
411
|
# Priority 1: Check for dist/agents/ (built output with BASE-AGENT composition)
|
|
411
412
|
dist_agents_dir = self.agents_cache_dir / "dist" / "agents"
|
|
@@ -422,32 +423,52 @@ class RemoteAgentDiscoveryService:
|
|
|
422
423
|
self.logger.debug(f"Using source agents (no dist/ found): {agents_dir}")
|
|
423
424
|
scan_dir = agents_dir
|
|
424
425
|
else:
|
|
425
|
-
#
|
|
426
|
-
#
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
"
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
scan_dir =
|
|
426
|
+
# Priority 3: Check for {owner}/{repo}/agents/ structure (GitHub sync)
|
|
427
|
+
# e.g., ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/agents/
|
|
428
|
+
owner_repo_agents_dir = None
|
|
429
|
+
for owner_dir in self.agents_cache_dir.iterdir():
|
|
430
|
+
if owner_dir.is_dir() and not owner_dir.name.startswith("."):
|
|
431
|
+
for repo_dir in owner_dir.iterdir():
|
|
432
|
+
if repo_dir.is_dir():
|
|
433
|
+
potential_agents = repo_dir / "agents"
|
|
434
|
+
if potential_agents.exists():
|
|
435
|
+
owner_repo_agents_dir = potential_agents
|
|
436
|
+
self.logger.debug(
|
|
437
|
+
f"Using GitHub sync structure: {owner_repo_agents_dir}"
|
|
438
|
+
)
|
|
439
|
+
break
|
|
440
|
+
if owner_repo_agents_dir:
|
|
441
|
+
break
|
|
442
|
+
|
|
443
|
+
if owner_repo_agents_dir:
|
|
444
|
+
scan_dir = owner_repo_agents_dir
|
|
444
445
|
else:
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
446
|
+
# LEGACY: Flattened cache structure - scan root directly
|
|
447
|
+
# Check if this looks like the flattened cache (has category subdirectories)
|
|
448
|
+
category_dirs = [
|
|
449
|
+
"universal",
|
|
450
|
+
"engineer",
|
|
451
|
+
"ops",
|
|
452
|
+
"qa",
|
|
453
|
+
"security",
|
|
454
|
+
"documentation",
|
|
455
|
+
]
|
|
456
|
+
has_categories = any(
|
|
457
|
+
(self.agents_cache_dir / cat).exists() for cat in category_dirs
|
|
449
458
|
)
|
|
450
|
-
|
|
459
|
+
|
|
460
|
+
if has_categories:
|
|
461
|
+
self.logger.debug(
|
|
462
|
+
f"Using flattened cache structure: {self.agents_cache_dir}"
|
|
463
|
+
)
|
|
464
|
+
scan_dir = self.agents_cache_dir
|
|
465
|
+
else:
|
|
466
|
+
self.logger.warning(
|
|
467
|
+
f"No agent directories found. Checked: {dist_agents_dir}, {agents_dir}, "
|
|
468
|
+
f"owner/repo/agents/ structure, and category directories in {self.agents_cache_dir}. "
|
|
469
|
+
"Expected agents in /dist/agents/, /agents/, owner/repo/agents/, or category directories."
|
|
470
|
+
)
|
|
471
|
+
return agents
|
|
451
472
|
|
|
452
473
|
# Find all Markdown files recursively
|
|
453
474
|
md_files = list(scan_dir.rglob("*.md"))
|
|
@@ -395,8 +395,27 @@ class GitSourceManager:
|
|
|
395
395
|
)
|
|
396
396
|
logger.debug(f"[DEBUG] Found {len(agents)} agents so far")
|
|
397
397
|
|
|
398
|
-
logger.debug(
|
|
399
|
-
|
|
398
|
+
logger.debug(
|
|
399
|
+
f"[DEBUG] list_cached_agents COMPLETE: {len(agents)} total agents (before deduplication)"
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
# Deduplicate agents by agent_id (Bug #2 fix)
|
|
403
|
+
# When same agent exists in multiple locations, keep only first occurrence
|
|
404
|
+
seen_ids = set()
|
|
405
|
+
deduplicated_agents = []
|
|
406
|
+
|
|
407
|
+
for agent in agents:
|
|
408
|
+
agent_id = agent.get("agent_id") or agent.get("metadata", {}).get("name")
|
|
409
|
+
if agent_id and agent_id not in seen_ids:
|
|
410
|
+
seen_ids.add(agent_id)
|
|
411
|
+
deduplicated_agents.append(agent)
|
|
412
|
+
elif agent_id:
|
|
413
|
+
logger.debug(f"[DEBUG] Skipping duplicate agent: {agent_id}")
|
|
414
|
+
|
|
415
|
+
logger.debug(
|
|
416
|
+
f"[DEBUG] After deduplication: {len(deduplicated_agents)} unique agents"
|
|
417
|
+
)
|
|
418
|
+
return deduplicated_agents
|
|
400
419
|
|
|
401
420
|
def _discover_agents_in_directory(
|
|
402
421
|
self,
|