claude-mpm 5.0.9__py3-none-any.whl → 5.6.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +4 -0
- claude_mpm/agents/BASE_AGENT.md +164 -0
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +115 -0
- claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +186 -0
- claude_mpm/agents/MEMORY.md +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +479 -616
- claude_mpm/agents/WORKFLOW.md +6 -253
- claude_mpm/agents/agent_loader.py +13 -44
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/frontmatter_validator.py +70 -2
- claude_mpm/agents/templates/circuit-breakers.md +457 -62
- claude_mpm/cli/__init__.py +5 -2
- claude_mpm/cli/__main__.py +4 -0
- claude_mpm/cli/chrome_devtools_installer.py +175 -0
- claude_mpm/cli/commands/agent_state_manager.py +18 -27
- claude_mpm/cli/commands/agents.py +177 -41
- claude_mpm/cli/commands/agents_reconcile.py +197 -0
- claude_mpm/cli/commands/auto_configure.py +723 -236
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/config.py +88 -2
- claude_mpm/cli/commands/configure.py +1874 -170
- claude_mpm/cli/commands/configure_agent_display.py +27 -6
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +232 -46
- claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
- claude_mpm/cli/commands/postmortem.py +1 -1
- claude_mpm/cli/commands/profile.py +276 -0
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +379 -204
- claude_mpm/cli/commands/summarize.py +413 -0
- claude_mpm/cli/executor.py +141 -19
- claude_mpm/cli/interactive/__init__.py +10 -0
- claude_mpm/cli/interactive/agent_wizard.py +115 -60
- claude_mpm/cli/interactive/questionary_styles.py +65 -0
- claude_mpm/cli/interactive/skill_selector.py +481 -0
- claude_mpm/cli/parsers/agents_parser.py +54 -9
- claude_mpm/cli/parsers/auto_configure_parser.py +13 -138
- claude_mpm/cli/parsers/base_parser.py +88 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/config_parser.py +153 -83
- claude_mpm/cli/parsers/profile_parser.py +147 -0
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +1 -1
- claude_mpm/cli/startup.py +1017 -266
- claude_mpm/cli/startup_display.py +74 -6
- claude_mpm/cli/startup_logging.py +2 -2
- claude_mpm/cli/utils.py +7 -3
- claude_mpm/commander/__init__.py +78 -0
- claude_mpm/commander/adapters/__init__.py +60 -0
- claude_mpm/commander/adapters/auggie.py +260 -0
- claude_mpm/commander/adapters/base.py +288 -0
- claude_mpm/commander/adapters/claude_code.py +392 -0
- claude_mpm/commander/adapters/codex.py +237 -0
- claude_mpm/commander/adapters/communication.py +366 -0
- claude_mpm/commander/adapters/example_usage.py +310 -0
- claude_mpm/commander/adapters/mpm.py +389 -0
- claude_mpm/commander/adapters/registry.py +204 -0
- claude_mpm/commander/api/__init__.py +16 -0
- claude_mpm/commander/api/app.py +121 -0
- claude_mpm/commander/api/errors.py +133 -0
- claude_mpm/commander/api/routes/__init__.py +8 -0
- claude_mpm/commander/api/routes/events.py +184 -0
- claude_mpm/commander/api/routes/inbox.py +171 -0
- claude_mpm/commander/api/routes/messages.py +148 -0
- claude_mpm/commander/api/routes/projects.py +271 -0
- claude_mpm/commander/api/routes/sessions.py +226 -0
- claude_mpm/commander/api/routes/work.py +296 -0
- claude_mpm/commander/api/schemas.py +186 -0
- claude_mpm/commander/chat/__init__.py +7 -0
- claude_mpm/commander/chat/cli.py +146 -0
- claude_mpm/commander/chat/commands.py +96 -0
- claude_mpm/commander/chat/repl.py +310 -0
- claude_mpm/commander/config.py +51 -0
- claude_mpm/commander/config_loader.py +115 -0
- claude_mpm/commander/core/__init__.py +10 -0
- claude_mpm/commander/core/block_manager.py +325 -0
- claude_mpm/commander/core/response_manager.py +323 -0
- claude_mpm/commander/daemon.py +603 -0
- claude_mpm/commander/env_loader.py +59 -0
- claude_mpm/commander/events/__init__.py +26 -0
- claude_mpm/commander/events/manager.py +332 -0
- claude_mpm/commander/frameworks/__init__.py +12 -0
- claude_mpm/commander/frameworks/base.py +146 -0
- claude_mpm/commander/frameworks/claude_code.py +58 -0
- claude_mpm/commander/frameworks/mpm.py +62 -0
- claude_mpm/commander/inbox/__init__.py +16 -0
- claude_mpm/commander/inbox/dedup.py +128 -0
- claude_mpm/commander/inbox/inbox.py +224 -0
- claude_mpm/commander/inbox/models.py +70 -0
- claude_mpm/commander/instance_manager.py +450 -0
- claude_mpm/commander/llm/__init__.py +6 -0
- claude_mpm/commander/llm/openrouter_client.py +167 -0
- claude_mpm/commander/llm/summarizer.py +70 -0
- claude_mpm/commander/memory/__init__.py +45 -0
- claude_mpm/commander/memory/compression.py +347 -0
- claude_mpm/commander/memory/embeddings.py +230 -0
- claude_mpm/commander/memory/entities.py +310 -0
- claude_mpm/commander/memory/example_usage.py +290 -0
- claude_mpm/commander/memory/integration.py +325 -0
- claude_mpm/commander/memory/search.py +381 -0
- claude_mpm/commander/memory/store.py +657 -0
- claude_mpm/commander/models/__init__.py +18 -0
- claude_mpm/commander/models/events.py +121 -0
- claude_mpm/commander/models/project.py +162 -0
- claude_mpm/commander/models/work.py +214 -0
- claude_mpm/commander/parsing/__init__.py +20 -0
- claude_mpm/commander/parsing/extractor.py +132 -0
- claude_mpm/commander/parsing/output_parser.py +270 -0
- claude_mpm/commander/parsing/patterns.py +100 -0
- claude_mpm/commander/persistence/__init__.py +11 -0
- claude_mpm/commander/persistence/event_store.py +274 -0
- claude_mpm/commander/persistence/state_store.py +309 -0
- claude_mpm/commander/persistence/work_store.py +164 -0
- claude_mpm/commander/polling/__init__.py +13 -0
- claude_mpm/commander/polling/event_detector.py +104 -0
- claude_mpm/commander/polling/output_buffer.py +49 -0
- claude_mpm/commander/polling/output_poller.py +153 -0
- claude_mpm/commander/project_session.py +268 -0
- claude_mpm/commander/proxy/__init__.py +12 -0
- claude_mpm/commander/proxy/formatter.py +89 -0
- claude_mpm/commander/proxy/output_handler.py +191 -0
- claude_mpm/commander/proxy/relay.py +155 -0
- claude_mpm/commander/registry.py +410 -0
- claude_mpm/commander/runtime/__init__.py +10 -0
- claude_mpm/commander/runtime/executor.py +191 -0
- claude_mpm/commander/runtime/monitor.py +346 -0
- claude_mpm/commander/session/__init__.py +6 -0
- claude_mpm/commander/session/context.py +81 -0
- claude_mpm/commander/session/manager.py +59 -0
- claude_mpm/commander/tmux_orchestrator.py +361 -0
- claude_mpm/commander/web/__init__.py +1 -0
- claude_mpm/commander/work/__init__.py +30 -0
- claude_mpm/commander/work/executor.py +207 -0
- claude_mpm/commander/work/queue.py +405 -0
- claude_mpm/commander/workflow/__init__.py +27 -0
- claude_mpm/commander/workflow/event_handler.py +241 -0
- claude_mpm/commander/workflow/notifier.py +146 -0
- claude_mpm/commands/mpm-config.md +36 -0
- claude_mpm/commands/mpm-doctor.md +16 -21
- claude_mpm/commands/mpm-help.md +12 -286
- claude_mpm/commands/mpm-init.md +88 -506
- claude_mpm/commands/mpm-monitor.md +22 -401
- claude_mpm/commands/mpm-organize.md +128 -0
- claude_mpm/commands/mpm-postmortem.md +13 -107
- claude_mpm/commands/mpm-session-resume.md +20 -363
- claude_mpm/commands/mpm-status.md +13 -69
- claude_mpm/commands/mpm-ticket-view.md +60 -495
- claude_mpm/commands/mpm-version.md +13 -107
- claude_mpm/commands/mpm.md +8 -0
- claude_mpm/config/agent_presets.py +8 -7
- claude_mpm/config/agent_sources.py +27 -0
- claude_mpm/config/skill_sources.py +16 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +154 -2
- claude_mpm/core/config.py +37 -26
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- claude_mpm/core/framework/formatters/content_formatter.py +3 -13
- claude_mpm/core/framework/loaders/agent_loader.py +8 -5
- claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
- claude_mpm/core/framework_loader.py +4 -2
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/interactive_session.py +12 -11
- claude_mpm/core/logger.py +39 -9
- claude_mpm/core/logging_utils.py +35 -11
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/optimized_startup.py +61 -0
- claude_mpm/core/output_style_manager.py +219 -44
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/core/socketio_pool.py +16 -8
- claude_mpm/core/unified_agent_registry.py +134 -16
- claude_mpm/core/unified_config.py +76 -8
- claude_mpm/core/unified_paths.py +95 -90
- claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DR8nis88.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.RgBboRvH.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
- claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
- claude_mpm/dashboard/static/svelte-build/index.html +36 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
- claude_mpm/experimental/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
- claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
- claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +479 -128
- claude_mpm/hooks/claude_hooks/hook_handler.py +254 -83
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +149 -18
- claude_mpm/hooks/claude_hooks/memory_integration.py +67 -19
- claude_mpm/hooks/claude_hooks/response_tracking.py +44 -62
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +69 -30
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +36 -103
- claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +73 -75
- claude_mpm/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/hooks/memory_integration_hook.py +46 -1
- claude_mpm/hooks/session_resume_hook.py +89 -1
- claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
- claude_mpm/init.py +276 -19
- claude_mpm/models/agent_definition.py +7 -0
- claude_mpm/models/git_repository.py +3 -3
- claude_mpm/scripts/claude-hook-handler.sh +87 -20
- claude_mpm/scripts/launch_monitor.py +93 -13
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/agent_recommendation_service.py +278 -0
- claude_mpm/services/agents/agent_review_service.py +280 -0
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/cache_git_manager.py +7 -7
- claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
- claude_mpm/services/agents/deployment/agent_discovery_service.py +6 -5
- claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +42 -20
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
- claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
- claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +348 -29
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +570 -68
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +57 -4
- claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/recommender.py +5 -3
- claude_mpm/services/agents/single_tier_deployment_service.py +6 -6
- claude_mpm/services/agents/sources/git_source_sync_service.py +129 -11
- claude_mpm/services/agents/startup_sync.py +27 -4
- claude_mpm/services/agents/toolchain_detector.py +10 -6
- claude_mpm/services/analysis/__init__.py +11 -1
- claude_mpm/services/analysis/clone_detector.py +1030 -0
- claude_mpm/services/cli/__init__.py +3 -0
- claude_mpm/services/cli/incremental_pause_manager.py +561 -0
- claude_mpm/services/cli/session_resume_helper.py +10 -2
- claude_mpm/services/command_deployment_service.py +81 -10
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +31 -1
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
- claude_mpm/services/diagnostics/models.py +14 -1
- claude_mpm/services/event_bus/config.py +3 -1
- claude_mpm/services/event_log.py +325 -0
- claude_mpm/services/git/git_operations_service.py +101 -16
- claude_mpm/services/infrastructure/__init__.py +4 -0
- claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
- claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
- claude_mpm/services/monitor/daemon.py +9 -2
- claude_mpm/services/monitor/daemon_manager.py +54 -7
- claude_mpm/services/monitor/management/lifecycle.py +15 -3
- claude_mpm/services/monitor/server.py +796 -30
- claude_mpm/services/pm_skills_deployer.py +884 -0
- claude_mpm/services/profile_manager.py +337 -0
- claude_mpm/services/project/project_organizer.py +4 -0
- claude_mpm/services/self_upgrade_service.py +120 -12
- claude_mpm/services/skills/__init__.py +3 -0
- claude_mpm/services/skills/git_skill_source_manager.py +303 -12
- claude_mpm/services/skills/selective_skill_deployer.py +869 -0
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
- claude_mpm/services/skills_deployer.py +294 -55
- claude_mpm/services/socketio/dashboard_server.py +1 -0
- claude_mpm/services/socketio/event_normalizer.py +51 -6
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/core.py +386 -108
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/services/version_control/git_operations.py +103 -0
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +112 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +98 -3
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- claude_mpm/utils/agent_dependency_loader.py +115 -4
- claude_mpm/utils/agent_filters.py +17 -44
- claude_mpm/utils/gitignore.py +3 -0
- claude_mpm/utils/migration.py +4 -4
- claude_mpm/utils/robust_installer.py +86 -21
- claude_mpm-5.6.23.dist-info/METADATA +393 -0
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/RECORD +508 -261
- claude_mpm-5.6.23.dist-info/entry_points.txt +5 -0
- claude_mpm-5.6.23.dist-info/licenses/LICENSE +94 -0
- claude_mpm-5.6.23.dist-info/licenses/LICENSE-FAQ.md +153 -0
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
- claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
- claude_mpm/agents/BASE_OPS.md +0 -219
- claude_mpm/agents/BASE_PM.md +0 -480
- claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
- claude_mpm/agents/BASE_QA.md +0 -167
- claude_mpm/agents/BASE_RESEARCH.md +0 -53
- claude_mpm/agents/OUTPUT_STYLE.md +0 -290
- claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +0 -1322
- claude_mpm/agents/base_agent_loader.py +0 -601
- claude_mpm/cli/commands/agents_detect.py +0 -380
- claude_mpm/cli/commands/agents_recommend.py +0 -309
- claude_mpm/cli/ticket_cli.py +0 -35
- claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
- claude_mpm/commands/mpm-agents-detect.md +0 -177
- claude_mpm/commands/mpm-agents-list.md +0 -131
- claude_mpm/commands/mpm-agents-recommend.md +0 -223
- claude_mpm/commands/mpm-config-view.md +0 -150
- claude_mpm/commands/mpm-ticket-organize.md +0 -304
- claude_mpm/dashboard/analysis_runner.py +0 -455
- claude_mpm/dashboard/index.html +0 -13
- claude_mpm/dashboard/open_dashboard.py +0 -66
- claude_mpm/dashboard/static/css/activity.css +0 -1958
- claude_mpm/dashboard/static/css/connection-status.css +0 -370
- claude_mpm/dashboard/static/css/dashboard.css +0 -4701
- claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
- claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
- claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
- claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
- claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
- claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
- claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
- claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
- claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
- claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
- claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
- claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
- claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
- claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
- claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
- claude_mpm/dashboard/static/js/connection-manager.js +0 -536
- claude_mpm/dashboard/static/js/dashboard.js +0 -1914
- claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
- claude_mpm/dashboard/static/js/socket-client.js +0 -1474
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
- claude_mpm/dashboard/static/socket.io.min.js +0 -7
- claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
- claude_mpm/dashboard/templates/code_simple.html +0 -153
- claude_mpm/dashboard/templates/index.html +0 -606
- claude_mpm/dashboard/test_dashboard.html +0 -372
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/scripts/mcp_server.py +0 -75
- claude_mpm/scripts/mcp_wrapper.py +0 -39
- claude_mpm/services/mcp_gateway/__init__.py +0 -159
- claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
- claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
- claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
- claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
- claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
- claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
- claude_mpm/services/mcp_gateway/core/base.py +0 -312
- claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
- claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
- claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
- claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
- claude_mpm/services/mcp_gateway/main.py +0 -589
- claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
- claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
- claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
- claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
- claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
- claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
- claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
- claude_mpm-5.0.9.dist-info/METADATA +0 -1028
- claude_mpm-5.0.9.dist-info/entry_points.txt +0 -10
- claude_mpm-5.0.9.dist-info/licenses/LICENSE +0 -21
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/WHEEL +0 -0
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"""Integration helpers for memory system with Commander.
|
|
2
|
+
|
|
3
|
+
Provides high-level functions to integrate conversation memory with
|
|
4
|
+
RuntimeMonitor, Chat CLI, and session resumption workflows.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
import uuid
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
|
+
from typing import List, Optional
|
|
11
|
+
|
|
12
|
+
from ..llm.openrouter_client import OpenRouterClient
|
|
13
|
+
from ..models.project import Project, ThreadMessage
|
|
14
|
+
from .compression import ContextCompressor
|
|
15
|
+
from .embeddings import EmbeddingService
|
|
16
|
+
from .entities import EntityExtractor
|
|
17
|
+
from .search import SemanticSearch
|
|
18
|
+
from .store import Conversation, ConversationMessage, ConversationStore
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MemoryIntegration:
|
|
24
|
+
"""High-level memory integration for Commander.
|
|
25
|
+
|
|
26
|
+
Provides simple API for common memory operations:
|
|
27
|
+
- Capture conversation from Project
|
|
28
|
+
- Search across all conversations
|
|
29
|
+
- Load context for session resume
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
store: ConversationStore for persistence
|
|
33
|
+
embeddings: EmbeddingService for vectors
|
|
34
|
+
search: SemanticSearch for queries
|
|
35
|
+
compressor: ContextCompressor for summaries
|
|
36
|
+
extractor: EntityExtractor for entity extraction
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
>>> memory = MemoryIntegration.create()
|
|
40
|
+
>>> await memory.capture_project_conversation(project)
|
|
41
|
+
>>> results = await memory.search("login bug fix", project_id="proj-xyz")
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
store: ConversationStore,
|
|
47
|
+
embeddings: EmbeddingService,
|
|
48
|
+
search: SemanticSearch,
|
|
49
|
+
compressor: ContextCompressor,
|
|
50
|
+
extractor: EntityExtractor,
|
|
51
|
+
):
|
|
52
|
+
"""Initialize memory integration.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
store: ConversationStore instance
|
|
56
|
+
embeddings: EmbeddingService instance
|
|
57
|
+
search: SemanticSearch instance
|
|
58
|
+
compressor: ContextCompressor instance
|
|
59
|
+
extractor: EntityExtractor instance
|
|
60
|
+
"""
|
|
61
|
+
self.store = store
|
|
62
|
+
self.embeddings = embeddings
|
|
63
|
+
self.search = search
|
|
64
|
+
self.compressor = compressor
|
|
65
|
+
self.extractor = extractor
|
|
66
|
+
|
|
67
|
+
logger.info("MemoryIntegration initialized")
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def create(
|
|
71
|
+
cls,
|
|
72
|
+
openrouter_client: Optional[OpenRouterClient] = None,
|
|
73
|
+
embedding_provider: str = "sentence-transformers",
|
|
74
|
+
) -> "MemoryIntegration":
|
|
75
|
+
"""Create MemoryIntegration with default configuration.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
openrouter_client: Optional OpenRouterClient for summarization
|
|
79
|
+
embedding_provider: Embedding provider ("sentence-transformers" or "openai")
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Configured MemoryIntegration instance
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
>>> from claude_mpm.commander.llm import OpenRouterClient
|
|
86
|
+
>>> client = OpenRouterClient()
|
|
87
|
+
>>> memory = MemoryIntegration.create(openrouter_client=client)
|
|
88
|
+
"""
|
|
89
|
+
store = ConversationStore()
|
|
90
|
+
embeddings = EmbeddingService(provider=embedding_provider)
|
|
91
|
+
search = SemanticSearch(store, embeddings)
|
|
92
|
+
|
|
93
|
+
# Create OpenRouter client if not provided
|
|
94
|
+
if openrouter_client is None:
|
|
95
|
+
openrouter_client = OpenRouterClient()
|
|
96
|
+
|
|
97
|
+
compressor = ContextCompressor(openrouter_client)
|
|
98
|
+
extractor = EntityExtractor()
|
|
99
|
+
|
|
100
|
+
return cls(store, embeddings, search, compressor, extractor)
|
|
101
|
+
|
|
102
|
+
async def capture_project_conversation(
|
|
103
|
+
self,
|
|
104
|
+
project: Project,
|
|
105
|
+
instance_name: str = "unknown",
|
|
106
|
+
session_id: Optional[str] = None,
|
|
107
|
+
) -> Conversation:
|
|
108
|
+
"""Capture conversation from Project thread.
|
|
109
|
+
|
|
110
|
+
Converts Project.thread (List[ThreadMessage]) into a Conversation
|
|
111
|
+
with entity extraction and optional summarization.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
project: Project with conversation thread
|
|
115
|
+
instance_name: Instance name (e.g., "claude-code-1")
|
|
116
|
+
session_id: Optional session ID
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Captured and saved Conversation
|
|
120
|
+
|
|
121
|
+
Example:
|
|
122
|
+
>>> conv = await memory.capture_project_conversation(project)
|
|
123
|
+
>>> print(f"Captured conversation {conv.id} with {len(conv.messages)} messages")
|
|
124
|
+
"""
|
|
125
|
+
if not project.thread:
|
|
126
|
+
logger.warning("Project %s has no conversation thread", project.id)
|
|
127
|
+
return None
|
|
128
|
+
|
|
129
|
+
# Convert ThreadMessages to ConversationMessages
|
|
130
|
+
messages = []
|
|
131
|
+
for thread_msg in project.thread:
|
|
132
|
+
conv_msg = ConversationMessage.from_thread_message(thread_msg)
|
|
133
|
+
|
|
134
|
+
# Extract entities
|
|
135
|
+
entities = self.extractor.extract(conv_msg.content)
|
|
136
|
+
conv_msg.entities = [e.to_dict() for e in entities]
|
|
137
|
+
|
|
138
|
+
messages.append(conv_msg)
|
|
139
|
+
|
|
140
|
+
# Create conversation
|
|
141
|
+
conversation = Conversation(
|
|
142
|
+
id=f"conv-{uuid.uuid4().hex[:12]}",
|
|
143
|
+
project_id=project.id,
|
|
144
|
+
instance_name=instance_name,
|
|
145
|
+
session_id=session_id or f"sess-{uuid.uuid4().hex[:8]}",
|
|
146
|
+
messages=messages,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# Auto-summarize if needed
|
|
150
|
+
if self.compressor.needs_summarization(messages):
|
|
151
|
+
conversation.summary = await self.compressor.summarize(messages)
|
|
152
|
+
logger.info("Auto-generated summary for conversation %s", conversation.id)
|
|
153
|
+
|
|
154
|
+
# Generate embedding for semantic search
|
|
155
|
+
text_for_embedding = conversation.summary or conversation.get_full_text()[:1000]
|
|
156
|
+
conversation.embedding = await self.embeddings.embed(text_for_embedding)
|
|
157
|
+
|
|
158
|
+
# Save to store
|
|
159
|
+
await self.store.save(conversation)
|
|
160
|
+
|
|
161
|
+
logger.info(
|
|
162
|
+
"Captured conversation %s (%d messages) from project %s",
|
|
163
|
+
conversation.id,
|
|
164
|
+
len(messages),
|
|
165
|
+
project.id,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return conversation
|
|
169
|
+
|
|
170
|
+
async def search_conversations(
|
|
171
|
+
self,
|
|
172
|
+
query: str,
|
|
173
|
+
project_id: Optional[str] = None,
|
|
174
|
+
limit: int = 10,
|
|
175
|
+
) -> List:
|
|
176
|
+
"""Search conversations by natural language query.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
query: Natural language search query
|
|
180
|
+
project_id: Optional project filter
|
|
181
|
+
limit: Maximum results
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
List of SearchResult with conversations
|
|
185
|
+
|
|
186
|
+
Example:
|
|
187
|
+
>>> results = await memory.search_conversations(
|
|
188
|
+
... "how did we fix the authentication bug?",
|
|
189
|
+
... project_id="proj-xyz",
|
|
190
|
+
... limit=5
|
|
191
|
+
... )
|
|
192
|
+
>>> for result in results:
|
|
193
|
+
... print(f"{result.score:.2f}: {result.snippet}")
|
|
194
|
+
"""
|
|
195
|
+
return await self.search.search(query, project_id=project_id, limit=limit)
|
|
196
|
+
|
|
197
|
+
async def load_context_for_session(
|
|
198
|
+
self,
|
|
199
|
+
project_id: str,
|
|
200
|
+
max_tokens: int = 4000,
|
|
201
|
+
limit_conversations: int = 10,
|
|
202
|
+
) -> str:
|
|
203
|
+
"""Load compressed context for session resumption.
|
|
204
|
+
|
|
205
|
+
Retrieves recent conversations from project and compresses them
|
|
206
|
+
into a context string suitable for LLM input.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
project_id: Project ID to load context for
|
|
210
|
+
max_tokens: Maximum tokens for context
|
|
211
|
+
limit_conversations: Maximum conversations to consider
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Compressed context string
|
|
215
|
+
|
|
216
|
+
Example:
|
|
217
|
+
>>> context = await memory.load_context_for_session("proj-xyz")
|
|
218
|
+
>>> print(f"Loaded context: {len(context)} chars")
|
|
219
|
+
"""
|
|
220
|
+
# Get recent conversations from project
|
|
221
|
+
conversations = await self.store.list_by_project(
|
|
222
|
+
project_id, limit=limit_conversations
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
if not conversations:
|
|
226
|
+
logger.info("No conversations found for project %s", project_id)
|
|
227
|
+
return ""
|
|
228
|
+
|
|
229
|
+
# Compress into context
|
|
230
|
+
context = await self.compressor.compress_for_context(
|
|
231
|
+
conversations, max_tokens=max_tokens
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
logger.info(
|
|
235
|
+
"Loaded context for project %s: %d conversations, %d chars",
|
|
236
|
+
project_id,
|
|
237
|
+
len(conversations),
|
|
238
|
+
len(context),
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
return context
|
|
242
|
+
|
|
243
|
+
async def update_conversation(
|
|
244
|
+
self,
|
|
245
|
+
conversation_id: str,
|
|
246
|
+
new_messages: List[ThreadMessage],
|
|
247
|
+
) -> Optional[Conversation]:
|
|
248
|
+
"""Update existing conversation with new messages.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
conversation_id: Conversation to update
|
|
252
|
+
new_messages: New messages to append
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
Updated conversation if found, None otherwise
|
|
256
|
+
|
|
257
|
+
Example:
|
|
258
|
+
>>> updated = await memory.update_conversation(
|
|
259
|
+
... "conv-abc123",
|
|
260
|
+
... [new_message1, new_message2]
|
|
261
|
+
... )
|
|
262
|
+
"""
|
|
263
|
+
# Load existing conversation
|
|
264
|
+
conversation = await self.store.load(conversation_id)
|
|
265
|
+
if not conversation:
|
|
266
|
+
logger.warning("Conversation %s not found", conversation_id)
|
|
267
|
+
return None
|
|
268
|
+
|
|
269
|
+
# Convert and append new messages
|
|
270
|
+
for thread_msg in new_messages:
|
|
271
|
+
conv_msg = ConversationMessage.from_thread_message(thread_msg)
|
|
272
|
+
|
|
273
|
+
# Extract entities
|
|
274
|
+
entities = self.extractor.extract(conv_msg.content)
|
|
275
|
+
conv_msg.entities = [e.to_dict() for e in entities]
|
|
276
|
+
|
|
277
|
+
conversation.messages.append(conv_msg)
|
|
278
|
+
|
|
279
|
+
# Update timestamp
|
|
280
|
+
conversation.updated_at = datetime.now(timezone.utc)
|
|
281
|
+
|
|
282
|
+
# Regenerate summary if needed
|
|
283
|
+
updated_summary = await self.compressor.update_summary_if_stale(
|
|
284
|
+
conversation, message_threshold=5
|
|
285
|
+
)
|
|
286
|
+
if updated_summary:
|
|
287
|
+
conversation.summary = updated_summary
|
|
288
|
+
|
|
289
|
+
# Regenerate embedding
|
|
290
|
+
text_for_embedding = conversation.summary or conversation.get_full_text()[:1000]
|
|
291
|
+
conversation.embedding = await self.embeddings.embed(text_for_embedding)
|
|
292
|
+
|
|
293
|
+
# Save
|
|
294
|
+
await self.store.save(conversation)
|
|
295
|
+
|
|
296
|
+
logger.info(
|
|
297
|
+
"Updated conversation %s (now %d messages)",
|
|
298
|
+
conversation_id,
|
|
299
|
+
len(conversation.messages),
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
return conversation
|
|
303
|
+
|
|
304
|
+
async def get_conversation_by_session(
|
|
305
|
+
self, session_id: str
|
|
306
|
+
) -> Optional[Conversation]:
|
|
307
|
+
"""Get conversation by session ID.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
session_id: Session ID from ToolSession
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
Conversation if found, None otherwise
|
|
314
|
+
|
|
315
|
+
Example:
|
|
316
|
+
>>> conv = await memory.get_conversation_by_session("sess-abc123")
|
|
317
|
+
"""
|
|
318
|
+
# For now, this requires loading and checking
|
|
319
|
+
# In production, you'd add an index on session_id
|
|
320
|
+
# This is a placeholder - implement proper query in store
|
|
321
|
+
logger.warning(
|
|
322
|
+
"get_conversation_by_session requires optimization - "
|
|
323
|
+
"add session_id index to store"
|
|
324
|
+
)
|
|
325
|
+
return None
|
|
@@ -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]
|