claude-mpm 5.4.85__py3-none-any.whl → 5.6.76__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +8 -5
- claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
- claude_mpm/agents/PM_INSTRUCTIONS.md +109 -706
- 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/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- 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 +2 -2
- claude_mpm/cli/commands/oauth.py +481 -0
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +5 -3
- claude_mpm/cli/executor.py +128 -16
- claude_mpm/cli/helpers.py +1 -1
- claude_mpm/cli/parsers/base_parser.py +84 -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/run_parser.py +10 -0
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +5 -0
- claude_mpm/cli/startup.py +345 -40
- claude_mpm/cli/startup_display.py +76 -7
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/startup_migrations.py +236 -0
- 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 +124 -0
- claude_mpm/commander/chat/repl.py +1957 -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 +868 -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 +5 -0
- claude_mpm/core/claude_runner.py +152 -0
- 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 +5 -4
- 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/output_style_manager.py +52 -12
- claude_mpm/core/socketio_pool.py +47 -15
- claude_mpm/core/unified_config.py +10 -6
- claude_mpm/core/unified_paths.py +68 -80
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
- claude_mpm/dashboard/static/svelte-build/index.html +9 -9
- claude_mpm/experimental/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
- claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +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/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/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 +22 -15
- 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/remote_agent_discovery_service.py +3 -0
- 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/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 -2
- claude_mpm/services/monitor/server.py +111 -16
- claude_mpm/services/pm_skills_deployer.py +261 -87
- claude_mpm/services/skills/git_skill_source_manager.py +130 -10
- claude_mpm/services/skills/selective_skill_deployer.py +142 -16
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +31 -5
- 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/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-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -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-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/{pm-teaching-mode → mpm-teaching-mode}/SKILL.md +2 -2
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +4 -4
- claude_mpm-5.6.76.dist-info/METADATA +416 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/RECORD +312 -175
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/WHEEL +1 -1
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/entry_points.txt +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
- claude_mpm-5.4.85.dist-info/METADATA +0 -1023
- /claude_mpm/skills/bundled/pm/{pm-bug-reporting/pm-bug-reporting.md → mpm-bug-reporting/SKILL.md} +0 -0
- /claude_mpm/skills/bundled/pm/{pm-delegation-patterns → mpm-delegation-patterns}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-git-file-tracking → mpm-git-file-tracking}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-pr-workflow → mpm-pr-workflow}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-ticketing-integration → mpm-ticketing-integration}/SKILL.md +0 -0
- /claude_mpm/skills/bundled/pm/{pm-verification-protocols → mpm-verification-protocols}/SKILL.md +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.85.dist-info → claude_mpm-5.6.76.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
"""Semantic search for conversations.
|
|
2
|
+
|
|
3
|
+
Provides vector-based and text-based search across all stored conversations
|
|
4
|
+
with filtering by project, date range, and entity types.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from typing import List, Optional, Tuple
|
|
11
|
+
|
|
12
|
+
from .embeddings import EmbeddingService
|
|
13
|
+
from .entities import EntityType
|
|
14
|
+
from .store import Conversation, ConversationStore
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class SearchResult:
|
|
21
|
+
"""Search result with relevance score.
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
conversation: Matched conversation
|
|
25
|
+
score: Relevance score (0-1, higher is more relevant)
|
|
26
|
+
matched_entities: Entities that matched the query
|
|
27
|
+
snippet: Relevant text snippet
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
>>> result = search_results[0]
|
|
31
|
+
>>> print(f"Score: {result.score:.3f}")
|
|
32
|
+
>>> print(f"Conversation: {result.conversation.id}")
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
conversation: Conversation
|
|
36
|
+
score: float
|
|
37
|
+
matched_entities: List[str] = None
|
|
38
|
+
snippet: str = ""
|
|
39
|
+
|
|
40
|
+
def __post_init__(self) -> None:
|
|
41
|
+
"""Initialize matched_entities if not provided."""
|
|
42
|
+
if self.matched_entities is None:
|
|
43
|
+
self.matched_entities = []
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class SemanticSearch:
|
|
47
|
+
"""Semantic search across conversations.
|
|
48
|
+
|
|
49
|
+
Combines vector similarity search with text search and entity filtering
|
|
50
|
+
for comprehensive conversation retrieval.
|
|
51
|
+
|
|
52
|
+
Attributes:
|
|
53
|
+
store: ConversationStore for persistence
|
|
54
|
+
embeddings: EmbeddingService for vector generation
|
|
55
|
+
|
|
56
|
+
Example:
|
|
57
|
+
>>> search = SemanticSearch(store, embeddings)
|
|
58
|
+
>>> results = await search.search(
|
|
59
|
+
... "how did we fix the login bug?",
|
|
60
|
+
... project_id="proj-xyz",
|
|
61
|
+
... limit=5
|
|
62
|
+
... )
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def __init__(self, store: ConversationStore, embeddings: EmbeddingService):
|
|
66
|
+
"""Initialize semantic search.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
store: ConversationStore for conversation persistence
|
|
70
|
+
embeddings: EmbeddingService for vector generation
|
|
71
|
+
"""
|
|
72
|
+
self.store = store
|
|
73
|
+
self.embeddings = embeddings
|
|
74
|
+
|
|
75
|
+
logger.info("SemanticSearch initialized (vector: %s)", store.enable_vector)
|
|
76
|
+
|
|
77
|
+
async def search(
|
|
78
|
+
self,
|
|
79
|
+
query: str,
|
|
80
|
+
project_id: Optional[str] = None,
|
|
81
|
+
limit: int = 10,
|
|
82
|
+
date_range: Optional[Tuple[datetime, datetime]] = None,
|
|
83
|
+
entity_types: Optional[List[EntityType]] = None,
|
|
84
|
+
) -> List[SearchResult]:
|
|
85
|
+
"""Search conversations semantically.
|
|
86
|
+
|
|
87
|
+
Uses vector similarity if available, falls back to text search.
|
|
88
|
+
Results are ranked by relevance score.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
query: Natural language search query
|
|
92
|
+
project_id: Optional project ID filter
|
|
93
|
+
limit: Maximum number of results
|
|
94
|
+
date_range: Optional (start, end) datetime filter
|
|
95
|
+
entity_types: Optional list of entity types to filter by
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
List of SearchResult ordered by relevance (highest first)
|
|
99
|
+
|
|
100
|
+
Example:
|
|
101
|
+
>>> results = await search.search(
|
|
102
|
+
... "login bug fix",
|
|
103
|
+
... project_id="proj-xyz",
|
|
104
|
+
... limit=5
|
|
105
|
+
... )
|
|
106
|
+
>>> print(f"Found {len(results)} results")
|
|
107
|
+
>>> print(f"Top result: {results[0].conversation.summary}")
|
|
108
|
+
"""
|
|
109
|
+
logger.debug(
|
|
110
|
+
"Searching conversations (query: %s, project: %s, limit: %d)",
|
|
111
|
+
query[:50],
|
|
112
|
+
project_id or "all",
|
|
113
|
+
limit,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if self.store.enable_vector:
|
|
117
|
+
# Use vector search
|
|
118
|
+
results = await self._vector_search(query, project_id, limit)
|
|
119
|
+
else:
|
|
120
|
+
# Fall back to text search
|
|
121
|
+
conversations = await self.store.search_by_text(query, project_id, limit)
|
|
122
|
+
results = [
|
|
123
|
+
SearchResult(conversation=conv, score=0.5) for conv in conversations
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
# Apply date range filter
|
|
127
|
+
if date_range:
|
|
128
|
+
start, end = date_range
|
|
129
|
+
results = [r for r in results if start <= r.conversation.updated_at <= end]
|
|
130
|
+
|
|
131
|
+
# Apply entity type filter
|
|
132
|
+
if entity_types:
|
|
133
|
+
results = self._filter_by_entities(results, entity_types)
|
|
134
|
+
|
|
135
|
+
# Generate snippets for top results
|
|
136
|
+
for result in results[:limit]:
|
|
137
|
+
result.snippet = self._generate_snippet(result.conversation, query)
|
|
138
|
+
|
|
139
|
+
logger.info("Search returned %d results", len(results))
|
|
140
|
+
return results[:limit]
|
|
141
|
+
|
|
142
|
+
async def _vector_search(
|
|
143
|
+
self,
|
|
144
|
+
query: str,
|
|
145
|
+
project_id: Optional[str] = None,
|
|
146
|
+
limit: int = 10,
|
|
147
|
+
) -> List[SearchResult]:
|
|
148
|
+
"""Perform vector similarity search.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
query: Search query
|
|
152
|
+
project_id: Optional project filter
|
|
153
|
+
limit: Maximum results
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
List of SearchResult with similarity scores
|
|
157
|
+
"""
|
|
158
|
+
# Generate query embedding
|
|
159
|
+
query_embedding = await self.embeddings.embed(query)
|
|
160
|
+
|
|
161
|
+
# Get all conversations (TODO: optimize with vector DB query)
|
|
162
|
+
if project_id:
|
|
163
|
+
conversations = await self.store.list_by_project(project_id, limit=100)
|
|
164
|
+
else:
|
|
165
|
+
# For now, we'll search recent conversations across all projects
|
|
166
|
+
# In production, you'd want to implement proper vector search in SQL
|
|
167
|
+
conversations = []
|
|
168
|
+
logger.warning(
|
|
169
|
+
"Vector search without project_id not fully optimized. "
|
|
170
|
+
"Consider implementing KNN query in SQL."
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Calculate similarities
|
|
174
|
+
results = []
|
|
175
|
+
for conv in conversations:
|
|
176
|
+
if not conv.embedding:
|
|
177
|
+
# Generate embedding if missing
|
|
178
|
+
text = conv.summary or conv.get_full_text()[:1000]
|
|
179
|
+
conv.embedding = await self.embeddings.embed(text)
|
|
180
|
+
await self.store.save(conv)
|
|
181
|
+
|
|
182
|
+
# Calculate cosine similarity
|
|
183
|
+
score = self.embeddings.cosine_similarity(query_embedding, conv.embedding)
|
|
184
|
+
results.append(SearchResult(conversation=conv, score=score))
|
|
185
|
+
|
|
186
|
+
# Sort by score descending
|
|
187
|
+
results.sort(key=lambda r: r.score, reverse=True)
|
|
188
|
+
|
|
189
|
+
return results[:limit]
|
|
190
|
+
|
|
191
|
+
def _filter_by_entities(
|
|
192
|
+
self, results: List[SearchResult], entity_types: List[EntityType]
|
|
193
|
+
) -> List[SearchResult]:
|
|
194
|
+
"""Filter results by entity types.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
results: Search results to filter
|
|
198
|
+
entity_types: Entity types to require
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Filtered results
|
|
202
|
+
"""
|
|
203
|
+
filtered = []
|
|
204
|
+
for result in results:
|
|
205
|
+
# Check if conversation has any messages with matching entities
|
|
206
|
+
has_entity = False
|
|
207
|
+
for msg in result.conversation.messages:
|
|
208
|
+
for entity in msg.entities:
|
|
209
|
+
if EntityType(entity["type"]) in entity_types:
|
|
210
|
+
has_entity = True
|
|
211
|
+
if "matched_entities" not in result.matched_entities:
|
|
212
|
+
result.matched_entities.append(entity["value"])
|
|
213
|
+
|
|
214
|
+
if has_entity:
|
|
215
|
+
filtered.append(result)
|
|
216
|
+
|
|
217
|
+
return filtered
|
|
218
|
+
|
|
219
|
+
def _generate_snippet(self, conversation: Conversation, query: str) -> str:
|
|
220
|
+
"""Generate relevant text snippet from conversation.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
conversation: Conversation to extract snippet from
|
|
224
|
+
query: Search query for context
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
Relevant snippet (max 200 chars)
|
|
228
|
+
"""
|
|
229
|
+
# Try to find message containing query terms
|
|
230
|
+
query_terms = query.lower().split()
|
|
231
|
+
|
|
232
|
+
for msg in conversation.messages:
|
|
233
|
+
content_lower = msg.content.lower()
|
|
234
|
+
if any(term in content_lower for term in query_terms):
|
|
235
|
+
# Found relevant message, extract snippet
|
|
236
|
+
start_idx = 0
|
|
237
|
+
for term in query_terms:
|
|
238
|
+
if term in content_lower:
|
|
239
|
+
start_idx = content_lower.index(term)
|
|
240
|
+
break
|
|
241
|
+
|
|
242
|
+
# Extract context around match
|
|
243
|
+
snippet_start = max(0, start_idx - 50)
|
|
244
|
+
snippet_end = min(len(msg.content), start_idx + 150)
|
|
245
|
+
snippet = msg.content[snippet_start:snippet_end]
|
|
246
|
+
|
|
247
|
+
# Add ellipsis if truncated
|
|
248
|
+
if snippet_start > 0:
|
|
249
|
+
snippet = "..." + snippet
|
|
250
|
+
if snippet_end < len(msg.content):
|
|
251
|
+
snippet = snippet + "..."
|
|
252
|
+
|
|
253
|
+
return snippet.strip()
|
|
254
|
+
|
|
255
|
+
# No match found, use summary or first message
|
|
256
|
+
if conversation.summary:
|
|
257
|
+
return conversation.summary[:200]
|
|
258
|
+
if conversation.messages:
|
|
259
|
+
return conversation.messages[0].content[:200] + "..."
|
|
260
|
+
|
|
261
|
+
return ""
|
|
262
|
+
|
|
263
|
+
async def find_similar(
|
|
264
|
+
self,
|
|
265
|
+
conversation_id: str,
|
|
266
|
+
limit: int = 5,
|
|
267
|
+
) -> List[SearchResult]:
|
|
268
|
+
"""Find conversations similar to a given conversation.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
conversation_id: Reference conversation ID
|
|
272
|
+
limit: Maximum number of similar conversations
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
List of similar conversations ordered by similarity
|
|
276
|
+
|
|
277
|
+
Example:
|
|
278
|
+
>>> similar = await search.find_similar("conv-abc123", limit=5)
|
|
279
|
+
"""
|
|
280
|
+
# Load reference conversation
|
|
281
|
+
ref_conv = await self.store.load(conversation_id)
|
|
282
|
+
if not ref_conv:
|
|
283
|
+
logger.warning("Conversation %s not found", conversation_id)
|
|
284
|
+
return []
|
|
285
|
+
|
|
286
|
+
# Ensure embedding exists
|
|
287
|
+
if not ref_conv.embedding:
|
|
288
|
+
text = ref_conv.summary or ref_conv.get_full_text()[:1000]
|
|
289
|
+
ref_conv.embedding = await self.embeddings.embed(text)
|
|
290
|
+
await self.store.save(ref_conv)
|
|
291
|
+
|
|
292
|
+
# Get all conversations from same project
|
|
293
|
+
all_convs = await self.store.list_by_project(ref_conv.project_id, limit=100)
|
|
294
|
+
|
|
295
|
+
# Calculate similarities
|
|
296
|
+
results = []
|
|
297
|
+
for conv in all_convs:
|
|
298
|
+
# Skip the reference conversation itself
|
|
299
|
+
if conv.id == conversation_id:
|
|
300
|
+
continue
|
|
301
|
+
|
|
302
|
+
if not conv.embedding:
|
|
303
|
+
text = conv.summary or conv.get_full_text()[:1000]
|
|
304
|
+
conv.embedding = await self.embeddings.embed(text)
|
|
305
|
+
await self.store.save(conv)
|
|
306
|
+
|
|
307
|
+
score = self.embeddings.cosine_similarity(
|
|
308
|
+
ref_conv.embedding, conv.embedding
|
|
309
|
+
)
|
|
310
|
+
results.append(SearchResult(conversation=conv, score=score))
|
|
311
|
+
|
|
312
|
+
# Sort by similarity
|
|
313
|
+
results.sort(key=lambda r: r.score, reverse=True)
|
|
314
|
+
|
|
315
|
+
logger.info(
|
|
316
|
+
"Found %d similar conversations to %s",
|
|
317
|
+
len(results[:limit]),
|
|
318
|
+
conversation_id,
|
|
319
|
+
)
|
|
320
|
+
return results[:limit]
|
|
321
|
+
|
|
322
|
+
async def search_by_entities(
|
|
323
|
+
self,
|
|
324
|
+
entity_type: EntityType,
|
|
325
|
+
entity_value: str,
|
|
326
|
+
project_id: Optional[str] = None,
|
|
327
|
+
limit: int = 10,
|
|
328
|
+
) -> List[SearchResult]:
|
|
329
|
+
"""Search conversations by specific entity.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
entity_type: Type of entity to search for
|
|
333
|
+
entity_value: Entity value (e.g., "src/auth.py")
|
|
334
|
+
project_id: Optional project filter
|
|
335
|
+
limit: Maximum results
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
List of conversations containing the entity
|
|
339
|
+
|
|
340
|
+
Example:
|
|
341
|
+
>>> results = await search.search_by_entities(
|
|
342
|
+
... EntityType.FILE,
|
|
343
|
+
... "src/auth.py",
|
|
344
|
+
... project_id="proj-xyz"
|
|
345
|
+
... )
|
|
346
|
+
"""
|
|
347
|
+
# Get conversations from project
|
|
348
|
+
if project_id:
|
|
349
|
+
conversations = await self.store.list_by_project(project_id, limit=100)
|
|
350
|
+
else:
|
|
351
|
+
conversations = []
|
|
352
|
+
logger.warning("Entity search without project_id requires full scan")
|
|
353
|
+
|
|
354
|
+
# Filter by entity
|
|
355
|
+
results = []
|
|
356
|
+
for conv in conversations:
|
|
357
|
+
for msg in conv.messages:
|
|
358
|
+
for entity in msg.entities:
|
|
359
|
+
if (
|
|
360
|
+
entity.get("type") == entity_type.value
|
|
361
|
+
and entity.get("value") == entity_value
|
|
362
|
+
):
|
|
363
|
+
results.append(
|
|
364
|
+
SearchResult(
|
|
365
|
+
conversation=conv,
|
|
366
|
+
score=1.0, # Exact match
|
|
367
|
+
matched_entities=[entity_value],
|
|
368
|
+
)
|
|
369
|
+
)
|
|
370
|
+
break
|
|
371
|
+
|
|
372
|
+
if len(results) >= limit:
|
|
373
|
+
break
|
|
374
|
+
|
|
375
|
+
logger.info(
|
|
376
|
+
"Found %d conversations with entity %s:%s",
|
|
377
|
+
len(results),
|
|
378
|
+
entity_type.value,
|
|
379
|
+
entity_value,
|
|
380
|
+
)
|
|
381
|
+
return results[:limit]
|