claude-mpm 5.4.41__py3-none-any.whl → 5.6.72__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_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 +161 -298
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/auth/__init__.py +35 -0
- claude_mpm/auth/callback_server.py +328 -0
- claude_mpm/auth/models.py +104 -0
- claude_mpm/auth/oauth_manager.py +266 -0
- claude_mpm/auth/providers/__init__.py +12 -0
- claude_mpm/auth/providers/base.py +165 -0
- claude_mpm/auth/providers/google.py +261 -0
- claude_mpm/auth/token_storage.py +252 -0
- 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 +216 -0
- claude_mpm/cli/commands/configure.py +620 -21
- claude_mpm/cli/commands/configure_agent_display.py +3 -1
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/mcp.py +29 -17
- claude_mpm/cli/commands/mcp_command_router.py +39 -0
- claude_mpm/cli/commands/mcp_service_commands.py +304 -0
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +15 -8
- claude_mpm/cli/commands/oauth.py +481 -0
- claude_mpm/cli/commands/profile.py +9 -10
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +182 -32
- claude_mpm/cli/executor.py +129 -16
- claude_mpm/cli/helpers.py +1 -1
- 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 +89 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/mcp_parser.py +79 -0
- claude_mpm/cli/parsers/oauth_parser.py +165 -0
- claude_mpm/cli/parsers/profile_parser.py +0 -1
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +2 -3
- claude_mpm/cli/startup.py +662 -524
- claude_mpm/cli/startup_display.py +76 -7
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +78 -0
- claude_mpm/commander/adapters/__init__.py +60 -0
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +288 -0
- claude_mpm/commander/adapters/claude_code.py +392 -0
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/adapters/example_usage.py +310 -0
- claude_mpm/commander/adapters/mpm.py +389 -0
- claude_mpm/commander/adapters/registry.py +204 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +121 -0
- claude_mpm/commander/api/errors.py +133 -0
- claude_mpm/commander/api/routes/__init__.py +8 -0
- claude_mpm/commander/api/routes/events.py +184 -0
- claude_mpm/commander/api/routes/inbox.py +171 -0
- claude_mpm/commander/api/routes/messages.py +148 -0
- claude_mpm/commander/api/routes/projects.py +271 -0
- claude_mpm/commander/api/routes/sessions.py +226 -0
- claude_mpm/commander/api/routes/work.py +296 -0
- claude_mpm/commander/api/schemas.py +186 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +149 -0
- claude_mpm/commander/chat/commands.py +122 -0
- claude_mpm/commander/chat/repl.py +1821 -0
- claude_mpm/commander/config.py +51 -0
- claude_mpm/commander/config_loader.py +115 -0
- claude_mpm/commander/core/__init__.py +10 -0
- claude_mpm/commander/core/block_manager.py +325 -0
- claude_mpm/commander/core/response_manager.py +323 -0
- claude_mpm/commander/daemon.py +603 -0
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/__init__.py +26 -0
- claude_mpm/commander/events/manager.py +392 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +233 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +57 -0
- claude_mpm/commander/git/__init__.py +5 -0
- claude_mpm/commander/git/worktree_manager.py +212 -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 +865 -0
- claude_mpm/commander/llm/__init__.py +6 -0
- claude_mpm/commander/llm/openrouter_client.py +167 -0
- claude_mpm/commander/llm/summarizer.py +70 -0
- claude_mpm/commander/memory/__init__.py +45 -0
- claude_mpm/commander/memory/compression.py +347 -0
- claude_mpm/commander/memory/embeddings.py +230 -0
- claude_mpm/commander/memory/entities.py +310 -0
- claude_mpm/commander/memory/example_usage.py +290 -0
- claude_mpm/commander/memory/integration.py +325 -0
- claude_mpm/commander/memory/search.py +381 -0
- claude_mpm/commander/memory/store.py +657 -0
- claude_mpm/commander/models/__init__.py +18 -0
- claude_mpm/commander/models/events.py +127 -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 +403 -0
- claude_mpm/commander/persistence/work_store.py +164 -0
- claude_mpm/commander/polling/__init__.py +13 -0
- claude_mpm/commander/polling/event_detector.py +104 -0
- claude_mpm/commander/polling/output_buffer.py +49 -0
- claude_mpm/commander/polling/output_poller.py +153 -0
- claude_mpm/commander/project_session.py +268 -0
- claude_mpm/commander/proxy/__init__.py +12 -0
- claude_mpm/commander/proxy/formatter.py +89 -0
- claude_mpm/commander/proxy/output_handler.py +191 -0
- claude_mpm/commander/proxy/relay.py +155 -0
- claude_mpm/commander/registry.py +410 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +346 -0
- claude_mpm/commander/session/__init__.py +6 -0
- claude_mpm/commander/session/context.py +81 -0
- claude_mpm/commander/session/manager.py +59 -0
- claude_mpm/commander/tmux_orchestrator.py +362 -0
- claude_mpm/commander/web/__init__.py +1 -0
- claude_mpm/commander/work/__init__.py +30 -0
- claude_mpm/commander/work/executor.py +207 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +241 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +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/config/skill_sources.py +16 -0
- claude_mpm/constants.py +6 -0
- claude_mpm/core/claude_runner.py +154 -2
- claude_mpm/core/config.py +35 -22
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- claude_mpm/core/hook_manager.py +53 -4
- claude_mpm/core/interactive_session.py +12 -11
- claude_mpm/core/logger.py +26 -9
- claude_mpm/core/logging_utils.py +39 -13
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/optimized_startup.py +3 -1
- claude_mpm/core/output_style_manager.py +66 -18
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/core/socketio_pool.py +47 -15
- claude_mpm/core/unified_config.py +54 -8
- claude_mpm/core/unified_paths.py +95 -90
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uj46x2Wr.js → BSNlmTZj.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{N4qtv3Hx.js → DR8nis88.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DjhvlsAc.js → NqQ1dWOy.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.CAGBuiOw.js → 0.RgBboRvH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
- claude_mpm/dashboard/static/svelte-build/index.html +11 -11
- claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
- claude_mpm/experimental/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
- claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +466 -136
- claude_mpm/hooks/claude_hooks/hook_handler.py +204 -104
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +291 -59
- claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
- claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
- claude_mpm/hooks/claude_hooks/services/__init__.py +21 -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__/container.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +41 -26
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
- claude_mpm/hooks/claude_hooks/services/container.py +326 -0
- claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
- claude_mpm/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/hooks/session_resume_hook.py +89 -1
- claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
- claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
- claude_mpm/init.py +224 -4
- claude_mpm/mcp/__init__.py +9 -0
- claude_mpm/mcp/google_workspace_server.py +610 -0
- claude_mpm/scripts/claude-hook-handler.sh +46 -19
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/cache_git_manager.py +1 -1
- 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/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +36 -8
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +50 -26
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +21 -2
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
- claude_mpm/services/agents/sources/git_source_sync_service.py +116 -5
- 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/command_deployment_service.py +44 -26
- 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/hook_installer_service.py +77 -8
- 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/mcp_config_manager.py +99 -19
- claude_mpm/services/mcp_service_registry.py +294 -0
- claude_mpm/services/monitor/daemon_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +8 -3
- claude_mpm/services/monitor/server.py +111 -16
- claude_mpm/services/pm_skills_deployer.py +302 -94
- claude_mpm/services/profile_manager.py +10 -4
- claude_mpm/services/skills/git_skill_source_manager.py +192 -29
- claude_mpm/services/skills/selective_skill_deployer.py +211 -46
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +192 -70
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +112 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +29 -23
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- claude_mpm/utils/agent_dependency_loader.py +103 -4
- claude_mpm/utils/robust_installer.py +45 -24
- claude_mpm-5.6.72.dist-info/METADATA +416 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/RECORD +477 -159
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/WHEEL +1 -1
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/entry_points.txt +2 -0
- 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/CWc5urbQ.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/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm-5.4.41.dist-info/METADATA +0 -998
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.41.dist-info → claude_mpm-5.6.72.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""Secure OAuth token storage with Fernet encryption and keyring.
|
|
2
|
+
|
|
3
|
+
This module provides encrypted persistence for OAuth tokens, using
|
|
4
|
+
the system keyring for encryption key storage and Fernet symmetric
|
|
5
|
+
encryption for the actual token data.
|
|
6
|
+
|
|
7
|
+
Security Features:
|
|
8
|
+
- Encryption keys stored in system keyring (not on disk)
|
|
9
|
+
- Fernet symmetric encryption for token data
|
|
10
|
+
- File permissions restricted to owner only (600)
|
|
11
|
+
- Credentials stored in user-specific directory
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import stat
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
import keyring
|
|
20
|
+
from cryptography.fernet import Fernet, InvalidToken
|
|
21
|
+
|
|
22
|
+
from claude_mpm.auth.models import OAuthToken, StoredToken, TokenMetadata, TokenStatus
|
|
23
|
+
|
|
24
|
+
# Keyring service identifier for encryption keys
|
|
25
|
+
KEYRING_SERVICE = "claude-mpm-oauth"
|
|
26
|
+
|
|
27
|
+
# Default credentials directory
|
|
28
|
+
CREDENTIALS_DIR = Path.home() / ".claude-mpm" / "credentials"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TokenStorage:
|
|
32
|
+
"""Secure storage for OAuth tokens using Fernet encryption.
|
|
33
|
+
|
|
34
|
+
Tokens are encrypted using Fernet symmetric encryption with keys
|
|
35
|
+
stored securely in the system keyring. Token files are stored
|
|
36
|
+
with restricted permissions (600) in the credentials directory.
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
credentials_dir: Directory where encrypted tokens are stored.
|
|
40
|
+
|
|
41
|
+
Example:
|
|
42
|
+
```python
|
|
43
|
+
storage = TokenStorage()
|
|
44
|
+
|
|
45
|
+
# Store a token
|
|
46
|
+
token = OAuthToken(
|
|
47
|
+
access_token="abc123",
|
|
48
|
+
expires_at=datetime.now(timezone.utc) + timedelta(hours=1),
|
|
49
|
+
scopes=["read", "write"]
|
|
50
|
+
)
|
|
51
|
+
metadata = TokenMetadata(service_name="github-mcp", provider="github")
|
|
52
|
+
storage.store("github-mcp", token, metadata)
|
|
53
|
+
|
|
54
|
+
# Retrieve the token
|
|
55
|
+
stored = storage.retrieve("github-mcp")
|
|
56
|
+
if stored:
|
|
57
|
+
print(f"Token expires at: {stored.token.expires_at}")
|
|
58
|
+
```
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def __init__(self, credentials_dir: Optional[Path] = None) -> None:
|
|
62
|
+
"""Initialize token storage.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
credentials_dir: Custom directory for storing encrypted tokens.
|
|
66
|
+
Defaults to ~/.claude-mpm/credentials/
|
|
67
|
+
"""
|
|
68
|
+
self.credentials_dir = credentials_dir or CREDENTIALS_DIR
|
|
69
|
+
self._ensure_credentials_dir()
|
|
70
|
+
|
|
71
|
+
def _ensure_credentials_dir(self) -> None:
|
|
72
|
+
"""Create credentials directory with secure permissions if needed."""
|
|
73
|
+
if not self.credentials_dir.exists():
|
|
74
|
+
self.credentials_dir.mkdir(parents=True, mode=0o700)
|
|
75
|
+
else:
|
|
76
|
+
# Ensure directory has correct permissions
|
|
77
|
+
self.credentials_dir.chmod(0o700)
|
|
78
|
+
|
|
79
|
+
def _get_encryption_key(self, service_name: str) -> bytes:
|
|
80
|
+
"""Get or create the Fernet encryption key for a service.
|
|
81
|
+
|
|
82
|
+
Keys are stored in the system keyring, not on disk.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
service_name: Name of the service to get/create key for.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Fernet encryption key as bytes.
|
|
89
|
+
"""
|
|
90
|
+
key_name = f"{service_name}-key"
|
|
91
|
+
existing_key = keyring.get_password(KEYRING_SERVICE, key_name)
|
|
92
|
+
|
|
93
|
+
if existing_key:
|
|
94
|
+
return existing_key.encode()
|
|
95
|
+
|
|
96
|
+
# Generate new key and store in keyring
|
|
97
|
+
new_key = Fernet.generate_key()
|
|
98
|
+
keyring.set_password(KEYRING_SERVICE, key_name, new_key.decode())
|
|
99
|
+
return new_key
|
|
100
|
+
|
|
101
|
+
def _delete_encryption_key(self, service_name: str) -> None:
|
|
102
|
+
"""Delete the encryption key for a service from keyring.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
service_name: Name of the service to delete key for.
|
|
106
|
+
"""
|
|
107
|
+
key_name = f"{service_name}-key"
|
|
108
|
+
try:
|
|
109
|
+
keyring.delete_password(KEYRING_SERVICE, key_name)
|
|
110
|
+
except keyring.errors.PasswordDeleteError:
|
|
111
|
+
pass # Key doesn't exist, nothing to delete
|
|
112
|
+
|
|
113
|
+
def _get_token_path(self, service_name: str) -> Path:
|
|
114
|
+
"""Get the file path for a service's encrypted token.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
service_name: Name of the service.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Path to the encrypted token file.
|
|
121
|
+
"""
|
|
122
|
+
# Sanitize service name for filesystem
|
|
123
|
+
safe_name = "".join(
|
|
124
|
+
c if c.isalnum() or c in "-_" else "_" for c in service_name
|
|
125
|
+
)
|
|
126
|
+
return self.credentials_dir / f"{safe_name}.enc"
|
|
127
|
+
|
|
128
|
+
def store(
|
|
129
|
+
self,
|
|
130
|
+
service_name: str,
|
|
131
|
+
token: OAuthToken,
|
|
132
|
+
metadata: TokenMetadata,
|
|
133
|
+
) -> None:
|
|
134
|
+
"""Store an OAuth token securely.
|
|
135
|
+
|
|
136
|
+
The token is encrypted using Fernet symmetric encryption with
|
|
137
|
+
a key stored in the system keyring. The encrypted data is
|
|
138
|
+
written to a file with 600 permissions.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
service_name: Unique identifier for the service.
|
|
142
|
+
token: OAuth token data to store.
|
|
143
|
+
metadata: Token metadata including provider info.
|
|
144
|
+
"""
|
|
145
|
+
stored_token = StoredToken(
|
|
146
|
+
version=1,
|
|
147
|
+
metadata=metadata,
|
|
148
|
+
token=token,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Serialize to JSON
|
|
152
|
+
token_json = stored_token.model_dump_json()
|
|
153
|
+
|
|
154
|
+
# Encrypt the token data
|
|
155
|
+
key = self._get_encryption_key(service_name)
|
|
156
|
+
fernet = Fernet(key)
|
|
157
|
+
encrypted_data = fernet.encrypt(token_json.encode())
|
|
158
|
+
|
|
159
|
+
# Write encrypted data with secure permissions
|
|
160
|
+
token_path = self._get_token_path(service_name)
|
|
161
|
+
token_path.write_bytes(encrypted_data)
|
|
162
|
+
|
|
163
|
+
# Set file permissions to owner read/write only (600)
|
|
164
|
+
token_path.chmod(stat.S_IRUSR | stat.S_IWUSR)
|
|
165
|
+
|
|
166
|
+
def retrieve(self, service_name: str) -> Optional[StoredToken]:
|
|
167
|
+
"""Retrieve a stored OAuth token.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
service_name: Unique identifier for the service.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
StoredToken if found and valid, None otherwise.
|
|
174
|
+
"""
|
|
175
|
+
token_path = self._get_token_path(service_name)
|
|
176
|
+
|
|
177
|
+
if not token_path.exists():
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
# Read encrypted data
|
|
182
|
+
encrypted_data = token_path.read_bytes()
|
|
183
|
+
|
|
184
|
+
# Decrypt
|
|
185
|
+
key = self._get_encryption_key(service_name)
|
|
186
|
+
fernet = Fernet(key)
|
|
187
|
+
decrypted_data = fernet.decrypt(encrypted_data)
|
|
188
|
+
|
|
189
|
+
# Deserialize
|
|
190
|
+
return StoredToken.model_validate_json(decrypted_data)
|
|
191
|
+
|
|
192
|
+
except (InvalidToken, json.JSONDecodeError, ValueError):
|
|
193
|
+
# Token is corrupted or invalid
|
|
194
|
+
return None
|
|
195
|
+
|
|
196
|
+
def delete(self, service_name: str) -> bool:
|
|
197
|
+
"""Delete a stored token and its encryption key.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
service_name: Unique identifier for the service.
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
True if token was deleted, False if it didn't exist.
|
|
204
|
+
"""
|
|
205
|
+
token_path = self._get_token_path(service_name)
|
|
206
|
+
|
|
207
|
+
if not token_path.exists():
|
|
208
|
+
return False
|
|
209
|
+
|
|
210
|
+
# Delete the token file
|
|
211
|
+
token_path.unlink()
|
|
212
|
+
|
|
213
|
+
# Delete the encryption key from keyring
|
|
214
|
+
self._delete_encryption_key(service_name)
|
|
215
|
+
|
|
216
|
+
return True
|
|
217
|
+
|
|
218
|
+
def list_services(self) -> list[str]:
|
|
219
|
+
"""List all services with stored tokens.
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
List of service names that have stored tokens.
|
|
223
|
+
"""
|
|
224
|
+
services = []
|
|
225
|
+
for path in self.credentials_dir.glob("*.enc"):
|
|
226
|
+
# Extract service name from filename
|
|
227
|
+
service_name = path.stem
|
|
228
|
+
services.append(service_name)
|
|
229
|
+
return sorted(services)
|
|
230
|
+
|
|
231
|
+
def get_status(self, service_name: str) -> TokenStatus:
|
|
232
|
+
"""Get the status of a stored token.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
service_name: Unique identifier for the service.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
TokenStatus indicating the token's current state.
|
|
239
|
+
"""
|
|
240
|
+
stored = self.retrieve(service_name)
|
|
241
|
+
|
|
242
|
+
if stored is None:
|
|
243
|
+
token_path = self._get_token_path(service_name)
|
|
244
|
+
if token_path.exists():
|
|
245
|
+
# File exists but couldn't be decrypted
|
|
246
|
+
return TokenStatus.INVALID
|
|
247
|
+
return TokenStatus.MISSING
|
|
248
|
+
|
|
249
|
+
if stored.token.is_expired():
|
|
250
|
+
return TokenStatus.EXPIRED
|
|
251
|
+
|
|
252
|
+
return TokenStatus.VALID
|
claude_mpm/cli/__init__.py
CHANGED
|
@@ -91,7 +91,11 @@ def main(argv: Optional[list] = None):
|
|
|
91
91
|
)
|
|
92
92
|
|
|
93
93
|
try:
|
|
94
|
-
|
|
94
|
+
# Check for --force-sync flag or environment variable
|
|
95
|
+
force_sync = getattr(args, "force_sync", False) or os.environ.get(
|
|
96
|
+
"CLAUDE_MPM_FORCE_SYNC", "0"
|
|
97
|
+
) in ("1", "true", "True", "yes")
|
|
98
|
+
run_background_services(force_sync=force_sync)
|
|
95
99
|
launch_progress.finish(message="Ready")
|
|
96
100
|
|
|
97
101
|
# Inform user about Claude Code initialization delay (3-5 seconds)
|
|
@@ -1379,7 +1379,7 @@ class AgentsCommand(AgentCommand):
|
|
|
1379
1379
|
return CommandResult.error_result("agent_id is required")
|
|
1380
1380
|
|
|
1381
1381
|
import os
|
|
1382
|
-
import subprocess
|
|
1382
|
+
import subprocess # nosec B404
|
|
1383
1383
|
|
|
1384
1384
|
from ...services.agents.local_template_manager import (
|
|
1385
1385
|
LocalAgentTemplateManager,
|
|
@@ -1415,7 +1415,7 @@ class AgentsCommand(AgentCommand):
|
|
|
1415
1415
|
|
|
1416
1416
|
# Use system editor
|
|
1417
1417
|
editor = getattr(args, "editor", None) or os.environ.get("EDITOR", "nano")
|
|
1418
|
-
subprocess.run([editor, str(template_file)], check=True)
|
|
1418
|
+
subprocess.run([editor, str(template_file)], check=True) # nosec B603
|
|
1419
1419
|
return CommandResult.success_result(
|
|
1420
1420
|
f"Agent '{agent_id}' edited successfully"
|
|
1421
1421
|
)
|
|
@@ -1519,8 +1519,6 @@ class AgentsCommand(AgentCommand):
|
|
|
1519
1519
|
console.print("For a better experience with integrated configuration:")
|
|
1520
1520
|
console.print(" • Agent management")
|
|
1521
1521
|
console.print(" • Skills management")
|
|
1522
|
-
console.print(" • Template editing")
|
|
1523
|
-
console.print(" • Behavior configuration")
|
|
1524
1522
|
console.print(" • Startup settings\n")
|
|
1525
1523
|
|
|
1526
1524
|
console.print("Please use: [bold green]claude-mpm config[/bold green]\n")
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent/Skill Reconciliation CLI Command
|
|
3
|
+
|
|
4
|
+
Shows the reconciliation view between configured and deployed agents/skills,
|
|
5
|
+
and performs reconciliation (deploy missing, remove unneeded).
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
claude-mpm agents reconcile [--dry-run] [--show-only]
|
|
9
|
+
claude-mpm skills reconcile [--dry-run] [--show-only]
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from rich.console import Console
|
|
15
|
+
from rich.table import Table
|
|
16
|
+
|
|
17
|
+
from ...core.unified_config import UnifiedConfig
|
|
18
|
+
from ...services.agents.deployment.deployment_reconciler import (
|
|
19
|
+
DeploymentReconciler,
|
|
20
|
+
ReconciliationState,
|
|
21
|
+
)
|
|
22
|
+
from ..shared import BaseCommand, CommandResult
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AgentsReconcileCommand(BaseCommand):
|
|
26
|
+
"""CLI command for agent reconciliation."""
|
|
27
|
+
|
|
28
|
+
def __init__(self):
|
|
29
|
+
super().__init__("agents-reconcile")
|
|
30
|
+
self.console = Console()
|
|
31
|
+
|
|
32
|
+
def run(self, args) -> CommandResult:
|
|
33
|
+
"""Execute reconciliation."""
|
|
34
|
+
# Load config
|
|
35
|
+
config = UnifiedConfig()
|
|
36
|
+
reconciler = DeploymentReconciler(config)
|
|
37
|
+
|
|
38
|
+
# Get project path
|
|
39
|
+
project_path = Path(getattr(args, "project_path", "."))
|
|
40
|
+
|
|
41
|
+
# Show current state
|
|
42
|
+
if getattr(args, "show_only", False) or getattr(args, "dry_run", False):
|
|
43
|
+
return self._show_reconciliation_view(reconciler, project_path)
|
|
44
|
+
|
|
45
|
+
# Perform reconciliation
|
|
46
|
+
return self._reconcile_agents(reconciler, project_path)
|
|
47
|
+
|
|
48
|
+
def _show_reconciliation_view(
|
|
49
|
+
self, reconciler: DeploymentReconciler, project_path: Path
|
|
50
|
+
) -> CommandResult:
|
|
51
|
+
"""Show reconciliation view without making changes."""
|
|
52
|
+
view = reconciler.get_reconciliation_view(project_path)
|
|
53
|
+
agent_state = view["agents"]
|
|
54
|
+
skill_state = view["skills"]
|
|
55
|
+
|
|
56
|
+
# Display agents table
|
|
57
|
+
self.console.print(
|
|
58
|
+
"\n[bold blue]═══ Agent Reconciliation View ═══[/bold blue]\n"
|
|
59
|
+
)
|
|
60
|
+
agent_table = self._build_reconciliation_table(agent_state, "Agent")
|
|
61
|
+
self.console.print(agent_table)
|
|
62
|
+
|
|
63
|
+
# Display skills table
|
|
64
|
+
self.console.print(
|
|
65
|
+
"\n[bold blue]═══ Skill Reconciliation View ═══[/bold blue]\n"
|
|
66
|
+
)
|
|
67
|
+
skill_table = self._build_reconciliation_table(skill_state, "Skill")
|
|
68
|
+
self.console.print(skill_table)
|
|
69
|
+
|
|
70
|
+
# Show summary
|
|
71
|
+
self._show_summary(agent_state, skill_state)
|
|
72
|
+
|
|
73
|
+
return CommandResult.success_result("Reconciliation view displayed")
|
|
74
|
+
|
|
75
|
+
def _build_reconciliation_table(
|
|
76
|
+
self, state: ReconciliationState, item_type: str
|
|
77
|
+
) -> Table:
|
|
78
|
+
"""Build Rich table for reconciliation state."""
|
|
79
|
+
table = Table(title=f"{item_type} Deployment Status")
|
|
80
|
+
|
|
81
|
+
table.add_column(f"{item_type}", style="cyan", no_wrap=True)
|
|
82
|
+
table.add_column("Configured", style="green")
|
|
83
|
+
table.add_column("Deployed", style="yellow")
|
|
84
|
+
table.add_column("Action", style="magenta")
|
|
85
|
+
|
|
86
|
+
# All items to consider
|
|
87
|
+
all_items = state.configured | state.deployed | state.cached
|
|
88
|
+
|
|
89
|
+
for item_id in sorted(all_items):
|
|
90
|
+
configured = "✓" if item_id in state.configured else "✗"
|
|
91
|
+
deployed = "✓" if item_id in state.deployed else "✗"
|
|
92
|
+
|
|
93
|
+
# Determine action
|
|
94
|
+
if item_id in state.to_deploy:
|
|
95
|
+
if item_id in state.cached:
|
|
96
|
+
action = "Will deploy"
|
|
97
|
+
else:
|
|
98
|
+
action = "[red]Missing in cache![/red]"
|
|
99
|
+
elif item_id in state.to_remove:
|
|
100
|
+
action = "Will remove"
|
|
101
|
+
elif item_id in state.unchanged:
|
|
102
|
+
action = "-"
|
|
103
|
+
elif item_id in state.cached and item_id not in state.configured:
|
|
104
|
+
action = "[dim]Available (not configured)[/dim]"
|
|
105
|
+
else:
|
|
106
|
+
action = "-"
|
|
107
|
+
|
|
108
|
+
table.add_row(item_id, configured, deployed, action)
|
|
109
|
+
|
|
110
|
+
return table
|
|
111
|
+
|
|
112
|
+
def _show_summary(
|
|
113
|
+
self, agent_state: ReconciliationState, skill_state: ReconciliationState
|
|
114
|
+
) -> None:
|
|
115
|
+
"""Show reconciliation summary."""
|
|
116
|
+
self.console.print("\n[bold]Summary:[/bold]")
|
|
117
|
+
|
|
118
|
+
# Agents
|
|
119
|
+
self.console.print("\nAgents:")
|
|
120
|
+
self.console.print(f" Configured: {len(agent_state.configured)}")
|
|
121
|
+
self.console.print(f" Deployed: {len(agent_state.deployed)}")
|
|
122
|
+
self.console.print(f" To deploy: {len(agent_state.to_deploy)}")
|
|
123
|
+
self.console.print(f" To remove: {len(agent_state.to_remove)}")
|
|
124
|
+
self.console.print(f" Unchanged: {len(agent_state.unchanged)}")
|
|
125
|
+
|
|
126
|
+
# Skills
|
|
127
|
+
self.console.print("\nSkills:")
|
|
128
|
+
self.console.print(f" Configured: {len(skill_state.configured)}")
|
|
129
|
+
self.console.print(f" Deployed: {len(skill_state.deployed)}")
|
|
130
|
+
self.console.print(f" To deploy: {len(skill_state.to_deploy)}")
|
|
131
|
+
self.console.print(f" To remove: {len(skill_state.to_remove)}")
|
|
132
|
+
self.console.print(f" Unchanged: {len(skill_state.unchanged)}")
|
|
133
|
+
|
|
134
|
+
# Show next steps
|
|
135
|
+
if agent_state.to_deploy or skill_state.to_deploy:
|
|
136
|
+
self.console.print(
|
|
137
|
+
"\n[yellow]Run without --show-only to perform deployment[/yellow]"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
def _reconcile_agents(
|
|
141
|
+
self, reconciler: DeploymentReconciler, project_path: Path
|
|
142
|
+
) -> CommandResult:
|
|
143
|
+
"""Perform agent and skill reconciliation."""
|
|
144
|
+
# Show current state first
|
|
145
|
+
self._show_reconciliation_view(reconciler, project_path)
|
|
146
|
+
|
|
147
|
+
self.console.print("\n[bold blue]Performing reconciliation...[/bold blue]\n")
|
|
148
|
+
|
|
149
|
+
# Reconcile agents
|
|
150
|
+
self.console.print("[cyan]Reconciling agents...[/cyan]")
|
|
151
|
+
agent_result = reconciler.reconcile_agents(project_path)
|
|
152
|
+
|
|
153
|
+
if agent_result.deployed:
|
|
154
|
+
self.console.print(
|
|
155
|
+
f" [green]✓ Deployed: {', '.join(agent_result.deployed)}[/green]"
|
|
156
|
+
)
|
|
157
|
+
if agent_result.removed:
|
|
158
|
+
self.console.print(
|
|
159
|
+
f" [yellow]✓ Removed: {', '.join(agent_result.removed)}[/yellow]"
|
|
160
|
+
)
|
|
161
|
+
if agent_result.errors:
|
|
162
|
+
for error in agent_result.errors:
|
|
163
|
+
self.console.print(f" [red]✗ {error}[/red]")
|
|
164
|
+
|
|
165
|
+
# Reconcile skills
|
|
166
|
+
self.console.print("\n[cyan]Reconciling skills...[/cyan]")
|
|
167
|
+
skill_result = reconciler.reconcile_skills(project_path)
|
|
168
|
+
|
|
169
|
+
if skill_result.deployed:
|
|
170
|
+
self.console.print(
|
|
171
|
+
f" [green]✓ Deployed: {', '.join(skill_result.deployed)}[/green]"
|
|
172
|
+
)
|
|
173
|
+
if skill_result.removed:
|
|
174
|
+
self.console.print(
|
|
175
|
+
f" [yellow]✓ Removed: {', '.join(skill_result.removed)}[/yellow]"
|
|
176
|
+
)
|
|
177
|
+
if skill_result.errors:
|
|
178
|
+
for error in skill_result.errors:
|
|
179
|
+
self.console.print(f" [red]✗ {error}[/red]")
|
|
180
|
+
|
|
181
|
+
# Final summary
|
|
182
|
+
total_errors = len(agent_result.errors) + len(skill_result.errors)
|
|
183
|
+
if total_errors == 0:
|
|
184
|
+
self.console.print("\n[bold green]✓ Reconciliation complete![/bold green]")
|
|
185
|
+
return CommandResult.success_result("Reconciliation successful")
|
|
186
|
+
self.console.print(
|
|
187
|
+
f"\n[bold yellow]⚠ Reconciliation complete with {total_errors} errors[/bold yellow]"
|
|
188
|
+
)
|
|
189
|
+
return CommandResult.error_result(f"Reconciliation had {total_errors} errors")
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class SkillsReconcileCommand(AgentsReconcileCommand):
|
|
193
|
+
"""CLI command for skill reconciliation (alias to agents reconcile)."""
|
|
194
|
+
|
|
195
|
+
def __init__(self):
|
|
196
|
+
BaseCommand.__init__(self, "skills-reconcile")
|
|
197
|
+
self.console = Console()
|