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.

Files changed (467) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
  3. claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
  4. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
  5. claude_mpm/agents/PM_INSTRUCTIONS.md +119 -689
  6. claude_mpm/agents/WORKFLOW.md +2 -0
  7. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  8. claude_mpm/cli/__init__.py +5 -1
  9. claude_mpm/cli/commands/agents.py +2 -4
  10. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  11. claude_mpm/cli/commands/autotodos.py +566 -0
  12. claude_mpm/cli/commands/commander.py +216 -0
  13. claude_mpm/cli/commands/configure.py +620 -21
  14. claude_mpm/cli/commands/configure_agent_display.py +3 -1
  15. claude_mpm/cli/commands/hook_errors.py +60 -60
  16. claude_mpm/cli/commands/monitor.py +2 -2
  17. claude_mpm/cli/commands/mpm_init/core.py +15 -8
  18. claude_mpm/cli/commands/profile.py +9 -10
  19. claude_mpm/cli/commands/run.py +35 -3
  20. claude_mpm/cli/commands/skill_source.py +51 -2
  21. claude_mpm/cli/commands/skills.py +171 -17
  22. claude_mpm/cli/executor.py +120 -16
  23. claude_mpm/cli/interactive/__init__.py +10 -0
  24. claude_mpm/cli/interactive/agent_wizard.py +30 -50
  25. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  26. claude_mpm/cli/interactive/skill_selector.py +481 -0
  27. claude_mpm/cli/parsers/base_parser.py +76 -1
  28. claude_mpm/cli/parsers/commander_parser.py +116 -0
  29. claude_mpm/cli/parsers/profile_parser.py +0 -1
  30. claude_mpm/cli/parsers/run_parser.py +10 -0
  31. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  32. claude_mpm/cli/parsers/skills_parser.py +5 -0
  33. claude_mpm/cli/startup.py +544 -511
  34. claude_mpm/cli/startup_display.py +74 -6
  35. claude_mpm/cli/startup_logging.py +2 -2
  36. claude_mpm/cli/utils.py +7 -3
  37. claude_mpm/commander/__init__.py +78 -0
  38. claude_mpm/commander/adapters/__init__.py +60 -0
  39. claude_mpm/commander/adapters/auggie.py +260 -0
  40. claude_mpm/commander/adapters/base.py +288 -0
  41. claude_mpm/commander/adapters/claude_code.py +392 -0
  42. claude_mpm/commander/adapters/codex.py +237 -0
  43. claude_mpm/commander/adapters/communication.py +366 -0
  44. claude_mpm/commander/adapters/example_usage.py +310 -0
  45. claude_mpm/commander/adapters/mpm.py +389 -0
  46. claude_mpm/commander/adapters/registry.py +204 -0
  47. claude_mpm/commander/api/__init__.py +16 -0
  48. claude_mpm/commander/api/app.py +121 -0
  49. claude_mpm/commander/api/errors.py +133 -0
  50. claude_mpm/commander/api/routes/__init__.py +8 -0
  51. claude_mpm/commander/api/routes/events.py +184 -0
  52. claude_mpm/commander/api/routes/inbox.py +171 -0
  53. claude_mpm/commander/api/routes/messages.py +148 -0
  54. claude_mpm/commander/api/routes/projects.py +271 -0
  55. claude_mpm/commander/api/routes/sessions.py +226 -0
  56. claude_mpm/commander/api/routes/work.py +296 -0
  57. claude_mpm/commander/api/schemas.py +186 -0
  58. claude_mpm/commander/chat/__init__.py +7 -0
  59. claude_mpm/commander/chat/cli.py +146 -0
  60. claude_mpm/commander/chat/commands.py +96 -0
  61. claude_mpm/commander/chat/repl.py +310 -0
  62. claude_mpm/commander/config.py +51 -0
  63. claude_mpm/commander/config_loader.py +115 -0
  64. claude_mpm/commander/core/__init__.py +10 -0
  65. claude_mpm/commander/core/block_manager.py +325 -0
  66. claude_mpm/commander/core/response_manager.py +323 -0
  67. claude_mpm/commander/daemon.py +603 -0
  68. claude_mpm/commander/env_loader.py +59 -0
  69. claude_mpm/commander/events/__init__.py +26 -0
  70. claude_mpm/commander/events/manager.py +332 -0
  71. claude_mpm/commander/frameworks/__init__.py +12 -0
  72. claude_mpm/commander/frameworks/base.py +146 -0
  73. claude_mpm/commander/frameworks/claude_code.py +58 -0
  74. claude_mpm/commander/frameworks/mpm.py +62 -0
  75. claude_mpm/commander/inbox/__init__.py +16 -0
  76. claude_mpm/commander/inbox/dedup.py +128 -0
  77. claude_mpm/commander/inbox/inbox.py +224 -0
  78. claude_mpm/commander/inbox/models.py +70 -0
  79. claude_mpm/commander/instance_manager.py +450 -0
  80. claude_mpm/commander/llm/__init__.py +6 -0
  81. claude_mpm/commander/llm/openrouter_client.py +167 -0
  82. claude_mpm/commander/llm/summarizer.py +70 -0
  83. claude_mpm/commander/memory/__init__.py +45 -0
  84. claude_mpm/commander/memory/compression.py +347 -0
  85. claude_mpm/commander/memory/embeddings.py +230 -0
  86. claude_mpm/commander/memory/entities.py +310 -0
  87. claude_mpm/commander/memory/example_usage.py +290 -0
  88. claude_mpm/commander/memory/integration.py +325 -0
  89. claude_mpm/commander/memory/search.py +381 -0
  90. claude_mpm/commander/memory/store.py +657 -0
  91. claude_mpm/commander/models/__init__.py +18 -0
  92. claude_mpm/commander/models/events.py +121 -0
  93. claude_mpm/commander/models/project.py +162 -0
  94. claude_mpm/commander/models/work.py +214 -0
  95. claude_mpm/commander/parsing/__init__.py +20 -0
  96. claude_mpm/commander/parsing/extractor.py +132 -0
  97. claude_mpm/commander/parsing/output_parser.py +270 -0
  98. claude_mpm/commander/parsing/patterns.py +100 -0
  99. claude_mpm/commander/persistence/__init__.py +11 -0
  100. claude_mpm/commander/persistence/event_store.py +274 -0
  101. claude_mpm/commander/persistence/state_store.py +309 -0
  102. claude_mpm/commander/persistence/work_store.py +164 -0
  103. claude_mpm/commander/polling/__init__.py +13 -0
  104. claude_mpm/commander/polling/event_detector.py +104 -0
  105. claude_mpm/commander/polling/output_buffer.py +49 -0
  106. claude_mpm/commander/polling/output_poller.py +153 -0
  107. claude_mpm/commander/project_session.py +268 -0
  108. claude_mpm/commander/proxy/__init__.py +12 -0
  109. claude_mpm/commander/proxy/formatter.py +89 -0
  110. claude_mpm/commander/proxy/output_handler.py +191 -0
  111. claude_mpm/commander/proxy/relay.py +155 -0
  112. claude_mpm/commander/registry.py +410 -0
  113. claude_mpm/commander/runtime/__init__.py +10 -0
  114. claude_mpm/commander/runtime/executor.py +191 -0
  115. claude_mpm/commander/runtime/monitor.py +346 -0
  116. claude_mpm/commander/session/__init__.py +6 -0
  117. claude_mpm/commander/session/context.py +81 -0
  118. claude_mpm/commander/session/manager.py +59 -0
  119. claude_mpm/commander/tmux_orchestrator.py +361 -0
  120. claude_mpm/commander/web/__init__.py +1 -0
  121. claude_mpm/commander/work/__init__.py +30 -0
  122. claude_mpm/commander/work/executor.py +207 -0
  123. claude_mpm/commander/work/queue.py +405 -0
  124. claude_mpm/commander/workflow/__init__.py +27 -0
  125. claude_mpm/commander/workflow/event_handler.py +241 -0
  126. claude_mpm/commander/workflow/notifier.py +146 -0
  127. claude_mpm/commands/mpm-config.md +8 -0
  128. claude_mpm/commands/mpm-doctor.md +8 -0
  129. claude_mpm/commands/mpm-help.md +8 -0
  130. claude_mpm/commands/mpm-init.md +8 -0
  131. claude_mpm/commands/mpm-monitor.md +8 -0
  132. claude_mpm/commands/mpm-organize.md +8 -0
  133. claude_mpm/commands/mpm-postmortem.md +8 -0
  134. claude_mpm/commands/mpm-session-resume.md +9 -1
  135. claude_mpm/commands/mpm-status.md +8 -0
  136. claude_mpm/commands/mpm-ticket-view.md +8 -0
  137. claude_mpm/commands/mpm-version.md +8 -0
  138. claude_mpm/commands/mpm.md +8 -0
  139. claude_mpm/config/agent_presets.py +8 -7
  140. claude_mpm/config/skill_sources.py +16 -0
  141. claude_mpm/constants.py +1 -0
  142. claude_mpm/core/claude_runner.py +154 -2
  143. claude_mpm/core/config.py +35 -22
  144. claude_mpm/core/config_constants.py +74 -9
  145. claude_mpm/core/constants.py +56 -12
  146. claude_mpm/core/hook_manager.py +51 -3
  147. claude_mpm/core/interactive_session.py +12 -11
  148. claude_mpm/core/logger.py +26 -9
  149. claude_mpm/core/logging_utils.py +39 -13
  150. claude_mpm/core/network_config.py +148 -0
  151. claude_mpm/core/oneshot_session.py +7 -6
  152. claude_mpm/core/optimized_startup.py +3 -1
  153. claude_mpm/core/output_style_manager.py +66 -18
  154. claude_mpm/core/shared/config_loader.py +3 -1
  155. claude_mpm/core/socketio_pool.py +47 -15
  156. claude_mpm/core/unified_config.py +54 -8
  157. claude_mpm/core/unified_paths.py +95 -90
  158. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  159. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  160. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
  161. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
  162. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
  163. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
  164. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
  165. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
  166. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
  167. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
  168. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  169. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
  170. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uj46x2Wr.js → BSNlmTZj.js} +1 -1
  171. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
  172. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
  173. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
  174. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{N4qtv3Hx.js → DR8nis88.js} +2 -2
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DjhvlsAc.js → NqQ1dWOy.js} +1 -1
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.CAGBuiOw.js → 0.RgBboRvH.js} +1 -1
  220. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
  221. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  222. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
  223. claude_mpm/dashboard/static/svelte-build/index.html +11 -11
  224. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  225. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  226. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  227. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  228. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  229. claude_mpm/experimental/cli_enhancements.py +2 -1
  230. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  231. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  232. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  233. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  234. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  235. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  236. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  237. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  238. claude_mpm/hooks/claude_hooks/event_handlers.py +527 -136
  239. claude_mpm/hooks/claude_hooks/hook_handler.py +170 -104
  240. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  241. claude_mpm/hooks/claude_hooks/installer.py +206 -36
  242. claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
  243. claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
  244. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  245. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  246. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  247. claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
  248. claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
  249. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  250. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  251. claude_mpm/hooks/claude_hooks/services/connection_manager.py +41 -26
  252. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
  253. claude_mpm/hooks/claude_hooks/services/container.py +310 -0
  254. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  255. claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
  256. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
  257. claude_mpm/hooks/session_resume_hook.py +89 -1
  258. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  259. claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
  260. claude_mpm/init.py +215 -2
  261. claude_mpm/scripts/claude-hook-handler.sh +46 -19
  262. claude_mpm/scripts/start_activity_logging.py +0 -0
  263. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  264. claude_mpm/services/agents/agent_selection_service.py +2 -2
  265. claude_mpm/services/agents/cache_git_manager.py +1 -1
  266. claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -1
  267. claude_mpm/services/agents/deployment/agent_format_converter.py +8 -6
  268. claude_mpm/services/agents/deployment/agent_template_builder.py +14 -4
  269. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  270. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +4 -4
  271. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +4 -1
  272. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  273. claude_mpm/services/agents/git_source_manager.py +6 -2
  274. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  275. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  276. claude_mpm/services/agents/sources/git_source_sync_service.py +10 -5
  277. claude_mpm/services/agents/startup_sync.py +5 -2
  278. claude_mpm/services/cli/__init__.py +3 -0
  279. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  280. claude_mpm/services/cli/session_resume_helper.py +10 -2
  281. claude_mpm/services/command_deployment_service.py +44 -26
  282. claude_mpm/services/delegation_detector.py +175 -0
  283. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  284. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  285. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  286. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  287. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  288. claude_mpm/services/diagnostics/models.py +14 -1
  289. claude_mpm/services/event_log.py +325 -0
  290. claude_mpm/services/hook_installer_service.py +77 -8
  291. claude_mpm/services/infrastructure/__init__.py +4 -0
  292. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  293. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  294. claude_mpm/services/monitor/daemon_manager.py +15 -4
  295. claude_mpm/services/monitor/management/lifecycle.py +8 -3
  296. claude_mpm/services/monitor/server.py +106 -16
  297. claude_mpm/services/pm_skills_deployer.py +267 -94
  298. claude_mpm/services/profile_manager.py +10 -4
  299. claude_mpm/services/skills/git_skill_source_manager.py +192 -29
  300. claude_mpm/services/skills/selective_skill_deployer.py +211 -46
  301. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  302. claude_mpm/services/skills_deployer.py +188 -67
  303. claude_mpm/services/socketio/handlers/hook.py +14 -7
  304. claude_mpm/services/socketio/server/main.py +12 -4
  305. claude_mpm/skills/__init__.py +2 -1
  306. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  307. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  308. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  309. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  310. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  311. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  312. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  313. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  314. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  315. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  316. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  317. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  318. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  319. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  320. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  321. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  322. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  323. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  324. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  325. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  326. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  327. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  328. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  329. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  330. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  331. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  332. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  333. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  334. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  335. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  336. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  337. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  338. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  339. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  340. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  341. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  342. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  343. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  344. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  345. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  346. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  347. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  348. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  349. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  350. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  351. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  352. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  353. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  354. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  355. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  356. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  357. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  358. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  359. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  360. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  361. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  362. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  363. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  364. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  365. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  366. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  367. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  368. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  369. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  370. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  371. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  372. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  373. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  374. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  375. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  376. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  377. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  378. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  379. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  380. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  381. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  382. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  383. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  384. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  385. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  386. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  387. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  388. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  389. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  390. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  391. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  392. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  393. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  394. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  395. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  396. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  397. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  398. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  399. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  400. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  401. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  402. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  403. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  404. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  405. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  406. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  407. claude_mpm/skills/bundled/security-scanning.md +112 -0
  408. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  409. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  410. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  411. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  412. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  413. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  414. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  415. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  416. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  417. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  418. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  419. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  420. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  421. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  422. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  423. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  424. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  425. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  426. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  427. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  428. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  429. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  430. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  431. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  432. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  433. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  434. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  435. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  436. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  437. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  438. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  439. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  440. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  441. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  442. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  443. claude_mpm/skills/registry.py +295 -90
  444. claude_mpm/skills/skill_manager.py +29 -23
  445. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  446. claude_mpm/utils/agent_dependency_loader.py +103 -4
  447. claude_mpm/utils/robust_installer.py +45 -24
  448. claude_mpm-5.6.34.dist-info/METADATA +393 -0
  449. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/RECORD +453 -151
  450. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
  451. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
  452. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
  453. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
  454. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +0 -1
  455. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
  456. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
  457. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
  458. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
  459. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
  460. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  461. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  462. claude_mpm-5.4.48.dist-info/METADATA +0 -999
  463. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/WHEEL +0 -0
  464. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/entry_points.txt +0 -0
  465. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE +0 -0
  466. {claude_mpm-5.4.48.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  467. {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, # Generate at 85% too
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
- claude_mpm_dir = project_root / ".claude-mpm"
99
- claude_mpm_dir.mkdir(exist_ok=True)
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 claude_mpm_dir / f"monitor-daemon-{self.port}.log"
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
- max_wait = 10 # seconds
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 = Path.home() / ".claude-mpm" / "monitor-daemon.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 = Path.home() / ".claude-mpm" / "monitor-daemon.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
- # Emit to Socket.IO clients via the appropriate event
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(event, event_data)
505
- self.logger.debug(f"HTTP event forwarded to Socket.IO: {event}")
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