claude-mpm 5.4.48__py3-none-any.whl → 5.6.34__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
- claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
- claude_mpm/agents/PM_INSTRUCTIONS.md +119 -689
- claude_mpm/agents/WORKFLOW.md +2 -0
- claude_mpm/agents/templates/circuit-breakers.md +26 -17
- claude_mpm/cli/__init__.py +5 -1
- claude_mpm/cli/commands/agents.py +2 -4
- claude_mpm/cli/commands/agents_reconcile.py +197 -0
- claude_mpm/cli/commands/autotodos.py +566 -0
- claude_mpm/cli/commands/commander.py +216 -0
- claude_mpm/cli/commands/configure.py +620 -21
- claude_mpm/cli/commands/configure_agent_display.py +3 -1
- claude_mpm/cli/commands/hook_errors.py +60 -60
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init/core.py +15 -8
- claude_mpm/cli/commands/profile.py +9 -10
- claude_mpm/cli/commands/run.py +35 -3
- claude_mpm/cli/commands/skill_source.py +51 -2
- claude_mpm/cli/commands/skills.py +171 -17
- claude_mpm/cli/executor.py +120 -16
- claude_mpm/cli/interactive/__init__.py +10 -0
- claude_mpm/cli/interactive/agent_wizard.py +30 -50
- claude_mpm/cli/interactive/questionary_styles.py +65 -0
- claude_mpm/cli/interactive/skill_selector.py +481 -0
- claude_mpm/cli/parsers/base_parser.py +76 -1
- claude_mpm/cli/parsers/commander_parser.py +116 -0
- claude_mpm/cli/parsers/profile_parser.py +0 -1
- claude_mpm/cli/parsers/run_parser.py +10 -0
- claude_mpm/cli/parsers/skill_source_parser.py +4 -0
- claude_mpm/cli/parsers/skills_parser.py +5 -0
- claude_mpm/cli/startup.py +544 -511
- 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 +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 +1 -0
- claude_mpm/core/claude_runner.py +154 -2
- claude_mpm/core/config.py +35 -22
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- claude_mpm/core/hook_manager.py +51 -3
- claude_mpm/core/interactive_session.py +12 -11
- claude_mpm/core/logger.py +26 -9
- claude_mpm/core/logging_utils.py +39 -13
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/optimized_startup.py +3 -1
- claude_mpm/core/output_style_manager.py +66 -18
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/core/socketio_pool.py +47 -15
- claude_mpm/core/unified_config.py +54 -8
- claude_mpm/core/unified_paths.py +95 -90
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uj46x2Wr.js → BSNlmTZj.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{N4qtv3Hx.js → DR8nis88.js} +2 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DjhvlsAc.js → NqQ1dWOy.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.CAGBuiOw.js → 0.RgBboRvH.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
- claude_mpm/dashboard/static/svelte-build/index.html +11 -11
- claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
- claude_mpm/experimental/cli_enhancements.py +2 -1
- claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
- claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +527 -136
- claude_mpm/hooks/claude_hooks/hook_handler.py +170 -104
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
- claude_mpm/hooks/claude_hooks/installer.py +206 -36
- claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
- claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
- claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +41 -26
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
- claude_mpm/hooks/claude_hooks/services/container.py +310 -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 +215 -2
- claude_mpm/scripts/claude-hook-handler.sh +46 -19
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/agent_recommendation_service.py +8 -8
- claude_mpm/services/agents/agent_selection_service.py +2 -2
- claude_mpm/services/agents/cache_git_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -1
- claude_mpm/services/agents/deployment/agent_format_converter.py +8 -6
- claude_mpm/services/agents/deployment/agent_template_builder.py +14 -4
- claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +4 -4
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +4 -1
- claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
- claude_mpm/services/agents/git_source_manager.py +6 -2
- claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
- claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
- claude_mpm/services/agents/sources/git_source_sync_service.py +10 -5
- claude_mpm/services/agents/startup_sync.py +5 -2
- claude_mpm/services/cli/__init__.py +3 -0
- claude_mpm/services/cli/incremental_pause_manager.py +561 -0
- claude_mpm/services/cli/session_resume_helper.py +10 -2
- claude_mpm/services/command_deployment_service.py +44 -26
- claude_mpm/services/delegation_detector.py +175 -0
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
- claude_mpm/services/diagnostics/models.py +14 -1
- claude_mpm/services/event_log.py +325 -0
- claude_mpm/services/hook_installer_service.py +77 -8
- claude_mpm/services/infrastructure/__init__.py +4 -0
- claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
- claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
- claude_mpm/services/monitor/daemon_manager.py +15 -4
- claude_mpm/services/monitor/management/lifecycle.py +8 -3
- claude_mpm/services/monitor/server.py +106 -16
- claude_mpm/services/pm_skills_deployer.py +267 -94
- claude_mpm/services/profile_manager.py +10 -4
- claude_mpm/services/skills/git_skill_source_manager.py +192 -29
- claude_mpm/services/skills/selective_skill_deployer.py +211 -46
- claude_mpm/services/skills/skill_discovery_service.py +74 -4
- claude_mpm/services/skills_deployer.py +188 -67
- claude_mpm/services/socketio/handlers/hook.py +14 -7
- claude_mpm/services/socketio/server/main.py +12 -4
- claude_mpm/skills/__init__.py +2 -1
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
- claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
- claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
- claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
- claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
- claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
- claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
- claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
- claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
- claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
- claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
- claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
- claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
- claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
- claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
- claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
- claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
- claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
- claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
- claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
- claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +112 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/registry.py +295 -90
- claude_mpm/skills/skill_manager.py +29 -23
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- claude_mpm/utils/agent_dependency_loader.py +103 -4
- claude_mpm/utils/robust_installer.py +45 -24
- claude_mpm-5.6.34.dist-info/METADATA +393 -0
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/RECORD +453 -151
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm-5.4.48.dist-info/METADATA +0 -999
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"""Context Usage Tracker Service.
|
|
2
|
+
|
|
3
|
+
WHY: Track cumulative token usage across Claude Code hook invocations to prevent
|
|
4
|
+
context window exhaustion and enable intelligent auto-pause behavior.
|
|
5
|
+
|
|
6
|
+
DESIGN DECISIONS:
|
|
7
|
+
- File-based persistence (hooks run in separate processes)
|
|
8
|
+
- Atomic file operations using StateStorage
|
|
9
|
+
- Threshold detection at 70% (caution), 85% (warning), 90% (auto_pause), 95% (critical)
|
|
10
|
+
- Session-scoped tracking with reset capability
|
|
11
|
+
- Compatible with 200k context budget for Claude Sonnet 4.5
|
|
12
|
+
|
|
13
|
+
USAGE:
|
|
14
|
+
tracker = ContextUsageTracker()
|
|
15
|
+
state = tracker.update_usage(input_tokens=15000, output_tokens=2000)
|
|
16
|
+
if tracker.should_auto_pause():
|
|
17
|
+
# Trigger auto-pause workflow
|
|
18
|
+
pass
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from dataclasses import asdict, dataclass, field
|
|
22
|
+
from datetime import datetime, timezone
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Optional
|
|
25
|
+
|
|
26
|
+
from claude_mpm.core.logger import get_logger
|
|
27
|
+
from claude_mpm.storage.state_storage import StateStorage
|
|
28
|
+
|
|
29
|
+
logger = get_logger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class ContextUsageState:
|
|
34
|
+
"""State tracking for cumulative context/token usage.
|
|
35
|
+
|
|
36
|
+
Attributes:
|
|
37
|
+
session_id: Unique session identifier
|
|
38
|
+
cumulative_input_tokens: Total input tokens across all hook invocations
|
|
39
|
+
cumulative_output_tokens: Total output tokens across all hook invocations
|
|
40
|
+
cache_creation_tokens: Total tokens spent creating prompt cache
|
|
41
|
+
cache_read_tokens: Total tokens read from prompt cache
|
|
42
|
+
percentage_used: Percentage of 200k context budget used (0.0-100.0)
|
|
43
|
+
threshold_reached: Highest threshold crossed ('caution', 'warning', 'auto_pause', 'critical')
|
|
44
|
+
auto_pause_active: Whether auto-pause has been triggered
|
|
45
|
+
last_updated: ISO timestamp of last update
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
session_id: str
|
|
49
|
+
cumulative_input_tokens: int = 0
|
|
50
|
+
cumulative_output_tokens: int = 0
|
|
51
|
+
cache_creation_tokens: int = 0
|
|
52
|
+
cache_read_tokens: int = 0
|
|
53
|
+
percentage_used: float = 0.0
|
|
54
|
+
threshold_reached: Optional[str] = None
|
|
55
|
+
auto_pause_active: bool = False
|
|
56
|
+
last_updated: str = field(
|
|
57
|
+
default_factory=lambda: datetime.now(timezone.utc).isoformat()
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ContextUsageTracker:
|
|
62
|
+
"""Track cumulative context/token usage across hook invocations.
|
|
63
|
+
|
|
64
|
+
Features:
|
|
65
|
+
- Cumulative tracking across multiple API calls
|
|
66
|
+
- File-based persistence for cross-process state sharing
|
|
67
|
+
- Atomic file operations for concurrent safety
|
|
68
|
+
- Threshold detection (70%, 85%, 90%, 95%)
|
|
69
|
+
- Auto-pause triggering at 90%+ usage
|
|
70
|
+
- Session management with reset capability
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
# Claude Sonnet 4.5 context window
|
|
74
|
+
CONTEXT_BUDGET = 200000
|
|
75
|
+
|
|
76
|
+
# Threshold levels for warnings and auto-pause
|
|
77
|
+
THRESHOLDS = {
|
|
78
|
+
"caution": 0.70, # Yellow warning
|
|
79
|
+
"warning": 0.85, # Orange warning
|
|
80
|
+
"auto_pause": 0.90, # Trigger auto-pause
|
|
81
|
+
"critical": 0.95, # Red critical alert
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
def __init__(self, project_path: Optional[Path] = None):
|
|
85
|
+
"""Initialize context usage tracker.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
project_path: Project root path (default: current directory)
|
|
89
|
+
"""
|
|
90
|
+
self.project_path = (project_path or Path.cwd()).resolve()
|
|
91
|
+
self.state_dir = self.project_path / ".claude-mpm" / "state"
|
|
92
|
+
self.state_dir.mkdir(parents=True, exist_ok=True)
|
|
93
|
+
self.state_file = self.state_dir / "context-usage.json"
|
|
94
|
+
|
|
95
|
+
# Use StateStorage for atomic operations
|
|
96
|
+
self.storage = StateStorage(self.state_dir)
|
|
97
|
+
|
|
98
|
+
logger.debug(f"ContextUsageTracker initialized: {self.state_file}")
|
|
99
|
+
|
|
100
|
+
def update_usage(
|
|
101
|
+
self,
|
|
102
|
+
input_tokens: int,
|
|
103
|
+
output_tokens: int,
|
|
104
|
+
cache_creation: int = 0,
|
|
105
|
+
cache_read: int = 0,
|
|
106
|
+
) -> ContextUsageState:
|
|
107
|
+
"""Update cumulative usage from API response.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
input_tokens: Input tokens from this API call
|
|
111
|
+
output_tokens: Output tokens from this API call
|
|
112
|
+
cache_creation: Cache creation tokens (optional)
|
|
113
|
+
cache_read: Cache read tokens (optional)
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Updated context usage state
|
|
117
|
+
|
|
118
|
+
Raises:
|
|
119
|
+
ValueError: If token counts are negative
|
|
120
|
+
"""
|
|
121
|
+
if any(
|
|
122
|
+
t < 0 for t in [input_tokens, output_tokens, cache_creation, cache_read]
|
|
123
|
+
):
|
|
124
|
+
raise ValueError("Token counts cannot be negative")
|
|
125
|
+
|
|
126
|
+
# Load current state
|
|
127
|
+
state = self._load_state()
|
|
128
|
+
|
|
129
|
+
# Update cumulative counters
|
|
130
|
+
state.cumulative_input_tokens += input_tokens
|
|
131
|
+
state.cumulative_output_tokens += output_tokens
|
|
132
|
+
state.cache_creation_tokens += cache_creation
|
|
133
|
+
state.cache_read_tokens += cache_read
|
|
134
|
+
|
|
135
|
+
# Calculate total effective tokens (input + output, cache read is "free")
|
|
136
|
+
total_tokens = state.cumulative_input_tokens + state.cumulative_output_tokens
|
|
137
|
+
state.percentage_used = (total_tokens / self.CONTEXT_BUDGET) * 100
|
|
138
|
+
|
|
139
|
+
# Check thresholds
|
|
140
|
+
state.threshold_reached = self.check_thresholds(state)
|
|
141
|
+
|
|
142
|
+
# Activate auto-pause if threshold reached
|
|
143
|
+
if state.threshold_reached in {"auto_pause", "critical"}:
|
|
144
|
+
state.auto_pause_active = True
|
|
145
|
+
|
|
146
|
+
# Update timestamp
|
|
147
|
+
state.last_updated = datetime.now(timezone.utc).isoformat()
|
|
148
|
+
|
|
149
|
+
# Persist state atomically
|
|
150
|
+
self._save_state(state)
|
|
151
|
+
|
|
152
|
+
logger.debug(
|
|
153
|
+
f"Usage updated: {total_tokens}/{self.CONTEXT_BUDGET} tokens "
|
|
154
|
+
f"({state.percentage_used:.1f}%), threshold: {state.threshold_reached}"
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
return state
|
|
158
|
+
|
|
159
|
+
def check_thresholds(
|
|
160
|
+
self, state: Optional[ContextUsageState] = None
|
|
161
|
+
) -> Optional[str]:
|
|
162
|
+
"""Check which threshold (if any) has been exceeded.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
state: Optional state to check (uses current state if None)
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Highest threshold exceeded ('caution', 'warning', 'auto_pause', 'critical')
|
|
169
|
+
or None if no thresholds exceeded
|
|
170
|
+
"""
|
|
171
|
+
if state is None:
|
|
172
|
+
state = self.get_current_state()
|
|
173
|
+
|
|
174
|
+
percentage = state.percentage_used / 100 # Convert to 0.0-1.0
|
|
175
|
+
|
|
176
|
+
# Check thresholds in descending order (highest first)
|
|
177
|
+
for threshold_name in ["critical", "auto_pause", "warning", "caution"]:
|
|
178
|
+
if percentage >= self.THRESHOLDS[threshold_name]:
|
|
179
|
+
return threshold_name
|
|
180
|
+
|
|
181
|
+
return None
|
|
182
|
+
|
|
183
|
+
def should_auto_pause(self) -> bool:
|
|
184
|
+
"""Check if auto-pause should be triggered.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
True if 90%+ context budget used
|
|
188
|
+
"""
|
|
189
|
+
state = self.get_current_state()
|
|
190
|
+
return state.percentage_used >= (self.THRESHOLDS["auto_pause"] * 100)
|
|
191
|
+
|
|
192
|
+
def get_current_state(self) -> ContextUsageState:
|
|
193
|
+
"""Get current usage state without modifying.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
Current context usage state
|
|
197
|
+
"""
|
|
198
|
+
return self._load_state()
|
|
199
|
+
|
|
200
|
+
def reset_session(self, new_session_id: str) -> None:
|
|
201
|
+
"""Reset tracking for a new session.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
new_session_id: New session identifier
|
|
205
|
+
"""
|
|
206
|
+
state = ContextUsageState(session_id=new_session_id)
|
|
207
|
+
self._save_state(state)
|
|
208
|
+
logger.info(f"Context usage reset for new session: {new_session_id}")
|
|
209
|
+
|
|
210
|
+
def _load_state(self) -> ContextUsageState:
|
|
211
|
+
"""Load state from persistence file.
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Loaded state or default state if file doesn't exist/is corrupted
|
|
215
|
+
"""
|
|
216
|
+
try:
|
|
217
|
+
if not self.state_file.exists():
|
|
218
|
+
# Generate initial session ID
|
|
219
|
+
session_id = (
|
|
220
|
+
f"session-{datetime.now(timezone.utc).strftime('%Y%m%d-%H%M%S')}"
|
|
221
|
+
)
|
|
222
|
+
logger.debug("No state file found, creating default state")
|
|
223
|
+
return ContextUsageState(session_id=session_id)
|
|
224
|
+
|
|
225
|
+
# Load JSON state
|
|
226
|
+
data = self.storage.read_json(self.state_file)
|
|
227
|
+
|
|
228
|
+
if data is None:
|
|
229
|
+
logger.warning("Failed to read state file, using default state")
|
|
230
|
+
session_id = (
|
|
231
|
+
f"session-{datetime.now(timezone.utc).strftime('%Y%m%d-%H%M%S')}"
|
|
232
|
+
)
|
|
233
|
+
return ContextUsageState(session_id=session_id)
|
|
234
|
+
|
|
235
|
+
# Reconstruct ContextUsageState from dict
|
|
236
|
+
return ContextUsageState(**data)
|
|
237
|
+
|
|
238
|
+
except Exception as e:
|
|
239
|
+
logger.error(f"Error loading state, using default: {e}")
|
|
240
|
+
session_id = (
|
|
241
|
+
f"session-{datetime.now(timezone.utc).strftime('%Y%m%d-%H%M%S')}"
|
|
242
|
+
)
|
|
243
|
+
return ContextUsageState(session_id=session_id)
|
|
244
|
+
|
|
245
|
+
def _save_state(self, state: ContextUsageState) -> None:
|
|
246
|
+
"""Save state to persistence file atomically.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
state: Context usage state to persist
|
|
250
|
+
|
|
251
|
+
Raises:
|
|
252
|
+
RuntimeError: If atomic write fails
|
|
253
|
+
"""
|
|
254
|
+
try:
|
|
255
|
+
# Convert dataclass to dict
|
|
256
|
+
state_dict = asdict(state)
|
|
257
|
+
|
|
258
|
+
# Atomic write using StateStorage
|
|
259
|
+
if not self.storage.write_json(state_dict, self.state_file, atomic=True):
|
|
260
|
+
raise RuntimeError(f"Failed to write state to {self.state_file}")
|
|
261
|
+
|
|
262
|
+
logger.debug(f"State saved: {self.state_file}")
|
|
263
|
+
|
|
264
|
+
except Exception as e:
|
|
265
|
+
logger.error(f"Error saving state: {e}")
|
|
266
|
+
raise RuntimeError(f"Failed to persist context usage state: {e}") from e
|
|
267
|
+
|
|
268
|
+
def get_usage_summary(self) -> dict:
|
|
269
|
+
"""Get human-readable usage summary.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
Dictionary with usage statistics
|
|
273
|
+
"""
|
|
274
|
+
state = self.get_current_state()
|
|
275
|
+
total_tokens = state.cumulative_input_tokens + state.cumulative_output_tokens
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
"session_id": state.session_id,
|
|
279
|
+
"total_tokens": total_tokens,
|
|
280
|
+
"budget": self.CONTEXT_BUDGET,
|
|
281
|
+
"percentage_used": round(state.percentage_used, 2),
|
|
282
|
+
"threshold_reached": state.threshold_reached,
|
|
283
|
+
"auto_pause_active": state.auto_pause_active,
|
|
284
|
+
"breakdown": {
|
|
285
|
+
"input_tokens": state.cumulative_input_tokens,
|
|
286
|
+
"output_tokens": state.cumulative_output_tokens,
|
|
287
|
+
"cache_creation_tokens": state.cache_creation_tokens,
|
|
288
|
+
"cache_read_tokens": state.cache_read_tokens,
|
|
289
|
+
},
|
|
290
|
+
"last_updated": state.last_updated,
|
|
291
|
+
}
|
|
@@ -6,7 +6,8 @@ Integrates with session management and response tracking infrastructure.
|
|
|
6
6
|
Triggers:
|
|
7
7
|
- model_context_window_exceeded (stop_reason)
|
|
8
8
|
- Manual pause command
|
|
9
|
-
- 95% token threshold reached
|
|
9
|
+
- 95% token threshold reached (critical)
|
|
10
|
+
- 90% token threshold reached (auto-pause)
|
|
10
11
|
- Session end with high token usage (>85%)
|
|
11
12
|
|
|
12
13
|
Design Principles:
|
|
@@ -71,6 +72,7 @@ class ResumeLogGenerator:
|
|
|
71
72
|
thresholds = self.config.get("context_management", {}).get("thresholds", {})
|
|
72
73
|
self.threshold_caution = thresholds.get("caution", 0.70)
|
|
73
74
|
self.threshold_warning = thresholds.get("warning", 0.85)
|
|
75
|
+
self.threshold_auto_pause = thresholds.get("auto_pause", 0.90)
|
|
74
76
|
self.threshold_critical = thresholds.get("critical", 0.95)
|
|
75
77
|
|
|
76
78
|
logger.info(
|
|
@@ -96,14 +98,14 @@ class ResumeLogGenerator:
|
|
|
96
98
|
if not self.enabled or not self.auto_generate:
|
|
97
99
|
return manual_trigger # Only generate on manual trigger if auto is disabled
|
|
98
100
|
|
|
99
|
-
# Trigger conditions
|
|
101
|
+
# Trigger conditions (ordered by severity)
|
|
100
102
|
triggers = [
|
|
101
103
|
stop_reason == "max_tokens",
|
|
102
104
|
stop_reason == "model_context_window_exceeded",
|
|
103
105
|
manual_trigger,
|
|
104
|
-
token_usage_pct and token_usage_pct >= self.threshold_critical,
|
|
105
|
-
token_usage_pct
|
|
106
|
-
and token_usage_pct >= self.threshold_warning, #
|
|
106
|
+
token_usage_pct and token_usage_pct >= self.threshold_critical, # 95%
|
|
107
|
+
token_usage_pct and token_usage_pct >= self.threshold_auto_pause, # 90%
|
|
108
|
+
token_usage_pct and token_usage_pct >= self.threshold_warning, # 85%
|
|
107
109
|
]
|
|
108
110
|
|
|
109
111
|
should_gen = any(triggers)
|
|
@@ -121,6 +123,22 @@ class ResumeLogGenerator:
|
|
|
121
123
|
|
|
122
124
|
return should_gen
|
|
123
125
|
|
|
126
|
+
def should_auto_pause(self, token_usage_pct: Optional[float]) -> bool:
|
|
127
|
+
"""Check if auto-pause threshold (90%) has been reached.
|
|
128
|
+
|
|
129
|
+
This is a convenience method to check specifically for the 90% threshold
|
|
130
|
+
which triggers automatic session pausing.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
token_usage_pct: Current token usage percentage (0.0-1.0)
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
True if auto-pause threshold has been reached
|
|
137
|
+
"""
|
|
138
|
+
if token_usage_pct is None:
|
|
139
|
+
return False
|
|
140
|
+
return token_usage_pct >= self.threshold_auto_pause
|
|
141
|
+
|
|
124
142
|
def generate_from_session_state(
|
|
125
143
|
self,
|
|
126
144
|
session_id: str,
|
|
@@ -427,6 +445,7 @@ class ResumeLogGenerator:
|
|
|
427
445
|
"thresholds": {
|
|
428
446
|
"caution": f"{self.threshold_caution:.0%}",
|
|
429
447
|
"warning": f"{self.threshold_warning:.0%}",
|
|
448
|
+
"auto_pause": f"{self.threshold_auto_pause:.0%}",
|
|
430
449
|
"critical": f"{self.threshold_critical:.0%}",
|
|
431
450
|
},
|
|
432
451
|
}
|
|
@@ -95,10 +95,10 @@ class DaemonManager:
|
|
|
95
95
|
def _get_default_log_file(self) -> Path:
|
|
96
96
|
"""Get default log file path with port number to support multiple daemons."""
|
|
97
97
|
project_root = Path.cwd()
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
logs_dir = project_root / ".claude-mpm" / "logs"
|
|
99
|
+
logs_dir.mkdir(parents=True, exist_ok=True)
|
|
100
100
|
# Include port in filename to support multiple daemon instances
|
|
101
|
-
return
|
|
101
|
+
return logs_dir / f"monitor-daemon-{self.port}.log"
|
|
102
102
|
|
|
103
103
|
def cleanup_port_conflicts(self, max_retries: int = 3) -> bool:
|
|
104
104
|
"""Clean up any processes using the daemon port.
|
|
@@ -649,14 +649,24 @@ class DaemonManager:
|
|
|
649
649
|
|
|
650
650
|
# Wait for the subprocess to write its PID file and bind to port
|
|
651
651
|
# The subprocess will write the PID file after it starts successfully
|
|
652
|
-
|
|
652
|
+
# Allow configuration via environment variable (default 30s to account for agent/skill sync)
|
|
653
|
+
max_wait = int(os.environ.get("CLAUDE_MPM_MONITOR_TIMEOUT", "30"))
|
|
653
654
|
start_time = time.time()
|
|
654
655
|
pid_file_found = False
|
|
655
656
|
port_bound = False
|
|
657
|
+
last_progress_log = 0.0
|
|
656
658
|
|
|
657
659
|
self.logger.debug(f"Waiting up to {max_wait}s for daemon to start...")
|
|
658
660
|
|
|
659
661
|
while time.time() - start_time < max_wait:
|
|
662
|
+
# Log progress every 5 seconds to show we're waiting
|
|
663
|
+
elapsed = time.time() - start_time
|
|
664
|
+
if elapsed - last_progress_log >= 5.0:
|
|
665
|
+
self.logger.info(
|
|
666
|
+
f"Waiting for monitor daemon... ({int(elapsed)}s elapsed, syncing agents/skills)"
|
|
667
|
+
)
|
|
668
|
+
last_progress_log = elapsed
|
|
669
|
+
|
|
660
670
|
# Check if process is still running
|
|
661
671
|
returncode = process.poll()
|
|
662
672
|
if returncode is not None:
|
|
@@ -976,6 +986,7 @@ class DaemonManager:
|
|
|
976
986
|
os.dup2(null_in.fileno(), sys.stdin.fileno())
|
|
977
987
|
|
|
978
988
|
# Redirect stdout and stderr to log file
|
|
989
|
+
# Ensure logs directory exists
|
|
979
990
|
self.log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
980
991
|
with self.log_file.open("a") as log_out:
|
|
981
992
|
os.dup2(log_out.fileno(), sys.stdout.fileno())
|
|
@@ -14,7 +14,6 @@ DESIGN DECISIONS:
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
import json
|
|
17
|
-
import logging.handlers
|
|
18
17
|
import os
|
|
19
18
|
import signal
|
|
20
19
|
import socket
|
|
@@ -129,12 +128,16 @@ class DaemonLifecycle:
|
|
|
129
128
|
# Redirect stdout and stderr
|
|
130
129
|
if self.log_file:
|
|
131
130
|
# Redirect to log file
|
|
131
|
+
# Ensure logs directory exists
|
|
132
|
+
self.log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
132
133
|
with self.log_file.open("a") as log_out:
|
|
133
134
|
os.dup2(log_out.fileno(), sys.stdout.fileno())
|
|
134
135
|
os.dup2(log_out.fileno(), sys.stderr.fileno())
|
|
135
136
|
else:
|
|
136
137
|
# Default to a daemon log file instead of /dev/null for errors
|
|
137
|
-
default_log =
|
|
138
|
+
default_log = (
|
|
139
|
+
Path.home() / ".claude-mpm" / "logs" / "monitor-daemon.log"
|
|
140
|
+
)
|
|
138
141
|
default_log.parent.mkdir(parents=True, exist_ok=True)
|
|
139
142
|
with default_log.open("a") as log_out:
|
|
140
143
|
os.dup2(log_out.fileno(), sys.stdout.fileno())
|
|
@@ -476,7 +479,9 @@ class DaemonLifecycle:
|
|
|
476
479
|
try:
|
|
477
480
|
# If no log file specified, create a default one
|
|
478
481
|
if not self.log_file:
|
|
479
|
-
default_log =
|
|
482
|
+
default_log = (
|
|
483
|
+
Path.home() / ".claude-mpm" / "logs" / "monitor-daemon.log"
|
|
484
|
+
)
|
|
480
485
|
default_log.parent.mkdir(parents=True, exist_ok=True)
|
|
481
486
|
self.log_file = default_log
|
|
482
487
|
|
|
@@ -368,6 +368,83 @@ class UnifiedMonitorServer:
|
|
|
368
368
|
finally:
|
|
369
369
|
await self._cleanup_async()
|
|
370
370
|
|
|
371
|
+
def _categorize_event(self, event_name: str) -> str:
|
|
372
|
+
"""Categorize event by name to determine Socket.IO event type.
|
|
373
|
+
|
|
374
|
+
Maps specific event names to their category for frontend filtering.
|
|
375
|
+
|
|
376
|
+
Args:
|
|
377
|
+
event_name: The raw event name (e.g., "subagent_start", "todo_updated")
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
Category name (e.g., "hook_event", "system_event")
|
|
381
|
+
"""
|
|
382
|
+
# Hook events - agent lifecycle and todo updates
|
|
383
|
+
if event_name in ("subagent_start", "subagent_stop", "todo_updated"):
|
|
384
|
+
return "hook_event"
|
|
385
|
+
|
|
386
|
+
# Tool events - both hook-style and direct tool events
|
|
387
|
+
if event_name in (
|
|
388
|
+
"pre_tool",
|
|
389
|
+
"post_tool",
|
|
390
|
+
"tool.start",
|
|
391
|
+
"tool.end",
|
|
392
|
+
"tool_use",
|
|
393
|
+
"tool_result",
|
|
394
|
+
):
|
|
395
|
+
return "tool_event"
|
|
396
|
+
|
|
397
|
+
# Session events - session lifecycle
|
|
398
|
+
if event_name in (
|
|
399
|
+
"session.started",
|
|
400
|
+
"session.ended",
|
|
401
|
+
"session_start",
|
|
402
|
+
"session_end",
|
|
403
|
+
):
|
|
404
|
+
return "session_event"
|
|
405
|
+
|
|
406
|
+
# Response events - API response lifecycle
|
|
407
|
+
if event_name in (
|
|
408
|
+
"response.start",
|
|
409
|
+
"response.end",
|
|
410
|
+
"response_started",
|
|
411
|
+
"response_ended",
|
|
412
|
+
):
|
|
413
|
+
return "response_event"
|
|
414
|
+
|
|
415
|
+
# Agent events - agent delegation and returns
|
|
416
|
+
if event_name in (
|
|
417
|
+
"agent.delegated",
|
|
418
|
+
"agent.returned",
|
|
419
|
+
"agent_start",
|
|
420
|
+
"agent_end",
|
|
421
|
+
):
|
|
422
|
+
return "agent_event"
|
|
423
|
+
|
|
424
|
+
# File events - file operations
|
|
425
|
+
if event_name in (
|
|
426
|
+
"file.read",
|
|
427
|
+
"file.write",
|
|
428
|
+
"file.edit",
|
|
429
|
+
"file_read",
|
|
430
|
+
"file_write",
|
|
431
|
+
):
|
|
432
|
+
return "file_event"
|
|
433
|
+
|
|
434
|
+
# Claude API events
|
|
435
|
+
if event_name in ("user_prompt", "assistant_message"):
|
|
436
|
+
return "claude_event"
|
|
437
|
+
|
|
438
|
+
# System events
|
|
439
|
+
if event_name in ("system_ready", "system_shutdown"):
|
|
440
|
+
return "system_event"
|
|
441
|
+
|
|
442
|
+
# Log uncategorized events for debugging
|
|
443
|
+
self.logger.debug(f"Uncategorized event: {event_name}")
|
|
444
|
+
|
|
445
|
+
# Default to claude_event for unknown events
|
|
446
|
+
return "claude_event"
|
|
447
|
+
|
|
371
448
|
def _setup_event_handlers(self):
|
|
372
449
|
"""Setup Socket.IO event handlers."""
|
|
373
450
|
try:
|
|
@@ -474,7 +551,7 @@ class UnifiedMonitorServer:
|
|
|
474
551
|
)
|
|
475
552
|
if version_file.exists():
|
|
476
553
|
version = version_file.read_text().strip()
|
|
477
|
-
except Exception:
|
|
554
|
+
except Exception: # nosec B110
|
|
478
555
|
pass
|
|
479
556
|
|
|
480
557
|
return web.json_response(
|
|
@@ -499,10 +576,23 @@ class UnifiedMonitorServer:
|
|
|
499
576
|
event = data.get("event", "claude_event")
|
|
500
577
|
event_data = data.get("data", {})
|
|
501
578
|
|
|
502
|
-
#
|
|
579
|
+
# Categorize event and wrap in expected format
|
|
580
|
+
event_type = self._categorize_event(event)
|
|
581
|
+
wrapped_event = {
|
|
582
|
+
"type": event_type,
|
|
583
|
+
"subtype": event,
|
|
584
|
+
"data": event_data,
|
|
585
|
+
"timestamp": event_data.get("timestamp")
|
|
586
|
+
or datetime.now(timezone.utc).isoformat() + "Z",
|
|
587
|
+
"session_id": event_data.get("session_id"),
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
# Emit to Socket.IO clients via the categorized event type
|
|
503
591
|
if self.sio:
|
|
504
|
-
await self.sio.emit(
|
|
505
|
-
self.logger.debug(
|
|
592
|
+
await self.sio.emit(event_type, wrapped_event)
|
|
593
|
+
self.logger.debug(
|
|
594
|
+
f"HTTP event forwarded to Socket.IO: {event} -> {event_type}"
|
|
595
|
+
)
|
|
506
596
|
|
|
507
597
|
return web.Response(status=204) # No content response
|
|
508
598
|
|
|
@@ -859,7 +949,7 @@ class UnifiedMonitorServer:
|
|
|
859
949
|
# Configuration endpoint for dashboard initialization
|
|
860
950
|
async def config_handler(request):
|
|
861
951
|
"""Return configuration for dashboard initialization."""
|
|
862
|
-
import subprocess
|
|
952
|
+
import subprocess # nosec B404
|
|
863
953
|
|
|
864
954
|
config = {
|
|
865
955
|
"workingDirectory": Path.cwd(),
|
|
@@ -870,7 +960,7 @@ class UnifiedMonitorServer:
|
|
|
870
960
|
|
|
871
961
|
# Try to get current git branch
|
|
872
962
|
try:
|
|
873
|
-
result = subprocess.run(
|
|
963
|
+
result = subprocess.run( # nosec B603 B607
|
|
874
964
|
["git", "branch", "--show-current"],
|
|
875
965
|
capture_output=True,
|
|
876
966
|
text=True,
|
|
@@ -880,7 +970,7 @@ class UnifiedMonitorServer:
|
|
|
880
970
|
)
|
|
881
971
|
if result.returncode == 0 and result.stdout.strip():
|
|
882
972
|
config["gitBranch"] = result.stdout.strip()
|
|
883
|
-
except Exception:
|
|
973
|
+
except Exception: # nosec B110
|
|
884
974
|
pass # Keep default "Unknown" value
|
|
885
975
|
|
|
886
976
|
return web.json_response(config)
|
|
@@ -910,7 +1000,7 @@ class UnifiedMonitorServer:
|
|
|
910
1000
|
# Git history handler
|
|
911
1001
|
async def git_history_handler(request: web.Request) -> web.Response:
|
|
912
1002
|
"""Get git history for a file."""
|
|
913
|
-
import subprocess
|
|
1003
|
+
import subprocess # nosec B404
|
|
914
1004
|
|
|
915
1005
|
try:
|
|
916
1006
|
data = await request.json()
|
|
@@ -939,7 +1029,7 @@ class UnifiedMonitorServer:
|
|
|
939
1029
|
)
|
|
940
1030
|
|
|
941
1031
|
# Get git log for file
|
|
942
|
-
result = subprocess.run(
|
|
1032
|
+
result = subprocess.run( # nosec B603 B607
|
|
943
1033
|
[
|
|
944
1034
|
"git",
|
|
945
1035
|
"log",
|
|
@@ -978,7 +1068,7 @@ class UnifiedMonitorServer:
|
|
|
978
1068
|
# Git diff handler
|
|
979
1069
|
async def git_diff_handler(request: web.Request) -> web.Response:
|
|
980
1070
|
"""Get git diff for a file with optional commit selection."""
|
|
981
|
-
import subprocess
|
|
1071
|
+
import subprocess # nosec B404
|
|
982
1072
|
|
|
983
1073
|
try:
|
|
984
1074
|
file_path = request.query.get("path", "")
|
|
@@ -1010,7 +1100,7 @@ class UnifiedMonitorServer:
|
|
|
1010
1100
|
)
|
|
1011
1101
|
|
|
1012
1102
|
# Find git repository root
|
|
1013
|
-
git_root_result = subprocess.run(
|
|
1103
|
+
git_root_result = subprocess.run( # nosec B603 B607
|
|
1014
1104
|
["git", "rev-parse", "--show-toplevel"],
|
|
1015
1105
|
check=False,
|
|
1016
1106
|
capture_output=True,
|
|
@@ -1034,7 +1124,7 @@ class UnifiedMonitorServer:
|
|
|
1034
1124
|
git_root = Path(git_root_result.stdout.strip())
|
|
1035
1125
|
|
|
1036
1126
|
# Check if file is tracked by git
|
|
1037
|
-
ls_files_result = subprocess.run(
|
|
1127
|
+
ls_files_result = subprocess.run( # nosec B603 B607
|
|
1038
1128
|
["git", "ls-files", "--error-unmatch", str(path)],
|
|
1039
1129
|
check=False,
|
|
1040
1130
|
capture_output=True,
|
|
@@ -1056,7 +1146,7 @@ class UnifiedMonitorServer:
|
|
|
1056
1146
|
)
|
|
1057
1147
|
|
|
1058
1148
|
# Get commit history for this file (last 5 commits)
|
|
1059
|
-
history_result = subprocess.run(
|
|
1149
|
+
history_result = subprocess.run( # nosec B603 B607
|
|
1060
1150
|
[
|
|
1061
1151
|
"git",
|
|
1062
1152
|
"log",
|
|
@@ -1087,7 +1177,7 @@ class UnifiedMonitorServer:
|
|
|
1087
1177
|
)
|
|
1088
1178
|
|
|
1089
1179
|
# Check for uncommitted changes
|
|
1090
|
-
uncommitted_result = subprocess.run(
|
|
1180
|
+
uncommitted_result = subprocess.run( # nosec B603 B607
|
|
1091
1181
|
["git", "diff", "HEAD", str(path)],
|
|
1092
1182
|
check=False,
|
|
1093
1183
|
capture_output=True,
|
|
@@ -1100,7 +1190,7 @@ class UnifiedMonitorServer:
|
|
|
1100
1190
|
# Get diff based on commit parameter
|
|
1101
1191
|
if commit_hash:
|
|
1102
1192
|
# Get diff for specific commit
|
|
1103
|
-
result = subprocess.run(
|
|
1193
|
+
result = subprocess.run( # nosec B603 B607
|
|
1104
1194
|
["git", "show", commit_hash, "--", str(path)],
|
|
1105
1195
|
check=False,
|
|
1106
1196
|
capture_output=True,
|
|
@@ -1469,7 +1559,7 @@ class UnifiedMonitorServer:
|
|
|
1469
1559
|
gather = asyncio.gather(*tasks_to_cancel, return_exceptions=True)
|
|
1470
1560
|
try:
|
|
1471
1561
|
loop.run_until_complete(gather)
|
|
1472
|
-
except Exception:
|
|
1562
|
+
except Exception: # nosec B110
|
|
1473
1563
|
# Some tasks might fail to cancel, that's ok
|
|
1474
1564
|
pass
|
|
1475
1565
|
|