claude-mpm 5.0.9__py3-none-any.whl → 5.6.23__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (614) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +4 -0
  3. claude_mpm/agents/BASE_AGENT.md +164 -0
  4. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +115 -0
  5. claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
  6. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +186 -0
  7. claude_mpm/agents/MEMORY.md +1 -1
  8. claude_mpm/agents/PM_INSTRUCTIONS.md +479 -616
  9. claude_mpm/agents/WORKFLOW.md +6 -253
  10. claude_mpm/agents/agent_loader.py +13 -44
  11. claude_mpm/agents/base_agent.json +1 -1
  12. claude_mpm/agents/frontmatter_validator.py +70 -2
  13. claude_mpm/agents/templates/circuit-breakers.md +457 -62
  14. claude_mpm/cli/__init__.py +5 -2
  15. claude_mpm/cli/__main__.py +4 -0
  16. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  17. claude_mpm/cli/commands/agent_state_manager.py +18 -27
  18. claude_mpm/cli/commands/agents.py +177 -41
  19. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  20. claude_mpm/cli/commands/auto_configure.py +723 -236
  21. claude_mpm/cli/commands/autotodos.py +566 -0
  22. claude_mpm/cli/commands/commander.py +216 -0
  23. claude_mpm/cli/commands/config.py +88 -2
  24. claude_mpm/cli/commands/configure.py +1874 -170
  25. claude_mpm/cli/commands/configure_agent_display.py +27 -6
  26. claude_mpm/cli/commands/hook_errors.py +60 -60
  27. claude_mpm/cli/commands/monitor.py +2 -2
  28. claude_mpm/cli/commands/mpm_init/core.py +232 -46
  29. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  30. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  31. claude_mpm/cli/commands/postmortem.py +1 -1
  32. claude_mpm/cli/commands/profile.py +276 -0
  33. claude_mpm/cli/commands/run.py +35 -3
  34. claude_mpm/cli/commands/skill_source.py +51 -2
  35. claude_mpm/cli/commands/skills.py +379 -204
  36. claude_mpm/cli/commands/summarize.py +413 -0
  37. claude_mpm/cli/executor.py +141 -19
  38. claude_mpm/cli/interactive/__init__.py +10 -0
  39. claude_mpm/cli/interactive/agent_wizard.py +115 -60
  40. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  41. claude_mpm/cli/interactive/skill_selector.py +481 -0
  42. claude_mpm/cli/parsers/agents_parser.py +54 -9
  43. claude_mpm/cli/parsers/auto_configure_parser.py +13 -138
  44. claude_mpm/cli/parsers/base_parser.py +88 -1
  45. claude_mpm/cli/parsers/commander_parser.py +116 -0
  46. claude_mpm/cli/parsers/config_parser.py +153 -83
  47. claude_mpm/cli/parsers/profile_parser.py +147 -0
  48. claude_mpm/cli/parsers/run_parser.py +10 -0
  49. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  50. claude_mpm/cli/parsers/skills_parser.py +1 -1
  51. claude_mpm/cli/startup.py +1017 -266
  52. claude_mpm/cli/startup_display.py +74 -6
  53. claude_mpm/cli/startup_logging.py +2 -2
  54. claude_mpm/cli/utils.py +7 -3
  55. claude_mpm/commander/__init__.py +78 -0
  56. claude_mpm/commander/adapters/__init__.py +60 -0
  57. claude_mpm/commander/adapters/auggie.py +260 -0
  58. claude_mpm/commander/adapters/base.py +288 -0
  59. claude_mpm/commander/adapters/claude_code.py +392 -0
  60. claude_mpm/commander/adapters/codex.py +237 -0
  61. claude_mpm/commander/adapters/communication.py +366 -0
  62. claude_mpm/commander/adapters/example_usage.py +310 -0
  63. claude_mpm/commander/adapters/mpm.py +389 -0
  64. claude_mpm/commander/adapters/registry.py +204 -0
  65. claude_mpm/commander/api/__init__.py +16 -0
  66. claude_mpm/commander/api/app.py +121 -0
  67. claude_mpm/commander/api/errors.py +133 -0
  68. claude_mpm/commander/api/routes/__init__.py +8 -0
  69. claude_mpm/commander/api/routes/events.py +184 -0
  70. claude_mpm/commander/api/routes/inbox.py +171 -0
  71. claude_mpm/commander/api/routes/messages.py +148 -0
  72. claude_mpm/commander/api/routes/projects.py +271 -0
  73. claude_mpm/commander/api/routes/sessions.py +226 -0
  74. claude_mpm/commander/api/routes/work.py +296 -0
  75. claude_mpm/commander/api/schemas.py +186 -0
  76. claude_mpm/commander/chat/__init__.py +7 -0
  77. claude_mpm/commander/chat/cli.py +146 -0
  78. claude_mpm/commander/chat/commands.py +96 -0
  79. claude_mpm/commander/chat/repl.py +310 -0
  80. claude_mpm/commander/config.py +51 -0
  81. claude_mpm/commander/config_loader.py +115 -0
  82. claude_mpm/commander/core/__init__.py +10 -0
  83. claude_mpm/commander/core/block_manager.py +325 -0
  84. claude_mpm/commander/core/response_manager.py +323 -0
  85. claude_mpm/commander/daemon.py +603 -0
  86. claude_mpm/commander/env_loader.py +59 -0
  87. claude_mpm/commander/events/__init__.py +26 -0
  88. claude_mpm/commander/events/manager.py +332 -0
  89. claude_mpm/commander/frameworks/__init__.py +12 -0
  90. claude_mpm/commander/frameworks/base.py +146 -0
  91. claude_mpm/commander/frameworks/claude_code.py +58 -0
  92. claude_mpm/commander/frameworks/mpm.py +62 -0
  93. claude_mpm/commander/inbox/__init__.py +16 -0
  94. claude_mpm/commander/inbox/dedup.py +128 -0
  95. claude_mpm/commander/inbox/inbox.py +224 -0
  96. claude_mpm/commander/inbox/models.py +70 -0
  97. claude_mpm/commander/instance_manager.py +450 -0
  98. claude_mpm/commander/llm/__init__.py +6 -0
  99. claude_mpm/commander/llm/openrouter_client.py +167 -0
  100. claude_mpm/commander/llm/summarizer.py +70 -0
  101. claude_mpm/commander/memory/__init__.py +45 -0
  102. claude_mpm/commander/memory/compression.py +347 -0
  103. claude_mpm/commander/memory/embeddings.py +230 -0
  104. claude_mpm/commander/memory/entities.py +310 -0
  105. claude_mpm/commander/memory/example_usage.py +290 -0
  106. claude_mpm/commander/memory/integration.py +325 -0
  107. claude_mpm/commander/memory/search.py +381 -0
  108. claude_mpm/commander/memory/store.py +657 -0
  109. claude_mpm/commander/models/__init__.py +18 -0
  110. claude_mpm/commander/models/events.py +121 -0
  111. claude_mpm/commander/models/project.py +162 -0
  112. claude_mpm/commander/models/work.py +214 -0
  113. claude_mpm/commander/parsing/__init__.py +20 -0
  114. claude_mpm/commander/parsing/extractor.py +132 -0
  115. claude_mpm/commander/parsing/output_parser.py +270 -0
  116. claude_mpm/commander/parsing/patterns.py +100 -0
  117. claude_mpm/commander/persistence/__init__.py +11 -0
  118. claude_mpm/commander/persistence/event_store.py +274 -0
  119. claude_mpm/commander/persistence/state_store.py +309 -0
  120. claude_mpm/commander/persistence/work_store.py +164 -0
  121. claude_mpm/commander/polling/__init__.py +13 -0
  122. claude_mpm/commander/polling/event_detector.py +104 -0
  123. claude_mpm/commander/polling/output_buffer.py +49 -0
  124. claude_mpm/commander/polling/output_poller.py +153 -0
  125. claude_mpm/commander/project_session.py +268 -0
  126. claude_mpm/commander/proxy/__init__.py +12 -0
  127. claude_mpm/commander/proxy/formatter.py +89 -0
  128. claude_mpm/commander/proxy/output_handler.py +191 -0
  129. claude_mpm/commander/proxy/relay.py +155 -0
  130. claude_mpm/commander/registry.py +410 -0
  131. claude_mpm/commander/runtime/__init__.py +10 -0
  132. claude_mpm/commander/runtime/executor.py +191 -0
  133. claude_mpm/commander/runtime/monitor.py +346 -0
  134. claude_mpm/commander/session/__init__.py +6 -0
  135. claude_mpm/commander/session/context.py +81 -0
  136. claude_mpm/commander/session/manager.py +59 -0
  137. claude_mpm/commander/tmux_orchestrator.py +361 -0
  138. claude_mpm/commander/web/__init__.py +1 -0
  139. claude_mpm/commander/work/__init__.py +30 -0
  140. claude_mpm/commander/work/executor.py +207 -0
  141. claude_mpm/commander/work/queue.py +405 -0
  142. claude_mpm/commander/workflow/__init__.py +27 -0
  143. claude_mpm/commander/workflow/event_handler.py +241 -0
  144. claude_mpm/commander/workflow/notifier.py +146 -0
  145. claude_mpm/commands/mpm-config.md +36 -0
  146. claude_mpm/commands/mpm-doctor.md +16 -21
  147. claude_mpm/commands/mpm-help.md +12 -286
  148. claude_mpm/commands/mpm-init.md +88 -506
  149. claude_mpm/commands/mpm-monitor.md +22 -401
  150. claude_mpm/commands/mpm-organize.md +128 -0
  151. claude_mpm/commands/mpm-postmortem.md +13 -107
  152. claude_mpm/commands/mpm-session-resume.md +20 -363
  153. claude_mpm/commands/mpm-status.md +13 -69
  154. claude_mpm/commands/mpm-ticket-view.md +60 -495
  155. claude_mpm/commands/mpm-version.md +13 -107
  156. claude_mpm/commands/mpm.md +8 -0
  157. claude_mpm/config/agent_presets.py +8 -7
  158. claude_mpm/config/agent_sources.py +27 -0
  159. claude_mpm/config/skill_sources.py +16 -0
  160. claude_mpm/constants.py +1 -0
  161. claude_mpm/core/claude_runner.py +154 -2
  162. claude_mpm/core/config.py +37 -26
  163. claude_mpm/core/config_constants.py +74 -9
  164. claude_mpm/core/constants.py +56 -12
  165. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  166. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  167. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  168. claude_mpm/core/framework_loader.py +4 -2
  169. claude_mpm/core/hook_manager.py +51 -3
  170. claude_mpm/core/interactive_session.py +12 -11
  171. claude_mpm/core/logger.py +39 -9
  172. claude_mpm/core/logging_utils.py +35 -11
  173. claude_mpm/core/network_config.py +148 -0
  174. claude_mpm/core/oneshot_session.py +7 -6
  175. claude_mpm/core/optimized_startup.py +61 -0
  176. claude_mpm/core/output_style_manager.py +219 -44
  177. claude_mpm/core/shared/config_loader.py +3 -1
  178. claude_mpm/core/socketio_pool.py +16 -8
  179. claude_mpm/core/unified_agent_registry.py +134 -16
  180. claude_mpm/core/unified_config.py +76 -8
  181. claude_mpm/core/unified_paths.py +95 -90
  182. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
  220. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
  221. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
  222. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DR8nis88.js +2 -0
  223. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
  224. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  225. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
  226. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
  227. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
  228. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
  229. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
  230. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
  231. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  232. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
  233. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  234. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
  235. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  236. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
  237. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
  238. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  239. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
  240. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
  241. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
  242. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
  243. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  244. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.RgBboRvH.js +1 -0
  245. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
  246. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  247. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  248. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  249. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  250. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  251. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  252. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  253. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  254. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  255. claude_mpm/experimental/cli_enhancements.py +2 -1
  256. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  257. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  258. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  259. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  260. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  261. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  262. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  263. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  264. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  265. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  266. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  267. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  268. claude_mpm/hooks/claude_hooks/event_handlers.py +479 -128
  269. claude_mpm/hooks/claude_hooks/hook_handler.py +254 -83
  270. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  271. claude_mpm/hooks/claude_hooks/installer.py +149 -18
  272. claude_mpm/hooks/claude_hooks/memory_integration.py +67 -19
  273. claude_mpm/hooks/claude_hooks/response_tracking.py +44 -62
  274. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  275. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  276. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  277. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  278. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  279. claude_mpm/hooks/claude_hooks/services/connection_manager.py +69 -30
  280. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +36 -103
  281. claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
  282. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +73 -75
  283. claude_mpm/hooks/kuzu_memory_hook.py +5 -5
  284. claude_mpm/hooks/memory_integration_hook.py +46 -1
  285. claude_mpm/hooks/session_resume_hook.py +89 -1
  286. claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
  287. claude_mpm/init.py +276 -19
  288. claude_mpm/models/agent_definition.py +7 -0
  289. claude_mpm/models/git_repository.py +3 -3
  290. claude_mpm/scripts/claude-hook-handler.sh +87 -20
  291. claude_mpm/scripts/launch_monitor.py +93 -13
  292. claude_mpm/scripts/start_activity_logging.py +0 -0
  293. claude_mpm/services/agents/agent_builder.py +3 -3
  294. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  295. claude_mpm/services/agents/agent_review_service.py +280 -0
  296. claude_mpm/services/agents/agent_selection_service.py +2 -2
  297. claude_mpm/services/agents/cache_git_manager.py +7 -7
  298. claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
  299. claude_mpm/services/agents/deployment/agent_discovery_service.py +6 -5
  300. claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
  301. claude_mpm/services/agents/deployment/agent_template_builder.py +42 -20
  302. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  303. claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
  304. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  305. claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
  306. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +348 -29
  307. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +570 -68
  308. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  309. claude_mpm/services/agents/git_source_manager.py +57 -4
  310. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  311. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  312. claude_mpm/services/agents/recommender.py +5 -3
  313. claude_mpm/services/agents/single_tier_deployment_service.py +6 -6
  314. claude_mpm/services/agents/sources/git_source_sync_service.py +129 -11
  315. claude_mpm/services/agents/startup_sync.py +27 -4
  316. claude_mpm/services/agents/toolchain_detector.py +10 -6
  317. claude_mpm/services/analysis/__init__.py +11 -1
  318. claude_mpm/services/analysis/clone_detector.py +1030 -0
  319. claude_mpm/services/cli/__init__.py +3 -0
  320. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  321. claude_mpm/services/cli/session_resume_helper.py +10 -2
  322. claude_mpm/services/command_deployment_service.py +81 -10
  323. claude_mpm/services/delegation_detector.py +175 -0
  324. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  325. claude_mpm/services/diagnostics/checks/agent_sources_check.py +31 -1
  326. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  327. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  328. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  329. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  330. claude_mpm/services/diagnostics/models.py +14 -1
  331. claude_mpm/services/event_bus/config.py +3 -1
  332. claude_mpm/services/event_log.py +325 -0
  333. claude_mpm/services/git/git_operations_service.py +101 -16
  334. claude_mpm/services/infrastructure/__init__.py +4 -0
  335. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  336. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  337. claude_mpm/services/monitor/daemon.py +9 -2
  338. claude_mpm/services/monitor/daemon_manager.py +54 -7
  339. claude_mpm/services/monitor/management/lifecycle.py +15 -3
  340. claude_mpm/services/monitor/server.py +796 -30
  341. claude_mpm/services/pm_skills_deployer.py +884 -0
  342. claude_mpm/services/profile_manager.py +337 -0
  343. claude_mpm/services/project/project_organizer.py +4 -0
  344. claude_mpm/services/self_upgrade_service.py +120 -12
  345. claude_mpm/services/skills/__init__.py +3 -0
  346. claude_mpm/services/skills/git_skill_source_manager.py +303 -12
  347. claude_mpm/services/skills/selective_skill_deployer.py +869 -0
  348. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  349. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  350. claude_mpm/services/skills_deployer.py +294 -55
  351. claude_mpm/services/socketio/dashboard_server.py +1 -0
  352. claude_mpm/services/socketio/event_normalizer.py +51 -6
  353. claude_mpm/services/socketio/handlers/hook.py +14 -7
  354. claude_mpm/services/socketio/server/core.py +386 -108
  355. claude_mpm/services/socketio/server/main.py +12 -4
  356. claude_mpm/services/version_control/git_operations.py +103 -0
  357. claude_mpm/skills/__init__.py +2 -1
  358. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  359. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  360. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  361. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  362. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  363. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  364. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  365. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  366. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  367. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  368. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  369. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  370. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  371. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  372. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  373. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  374. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  375. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  376. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  377. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  378. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  379. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  380. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  381. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  382. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  383. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  384. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  385. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  386. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  387. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  388. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  389. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  390. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  391. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  392. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  393. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  394. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  395. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  396. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  397. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  398. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  399. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  400. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  401. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  402. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  403. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  404. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  405. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  406. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  407. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  408. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  409. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  410. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  411. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  412. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  413. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  414. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  415. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  416. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  417. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  418. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  419. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  420. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  421. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  422. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  423. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  424. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  425. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  426. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  427. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  428. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  429. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  430. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  431. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  432. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  433. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  434. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  435. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  436. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  437. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  438. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  439. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  440. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  441. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  442. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  443. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  444. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  445. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  446. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  447. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  448. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  449. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  450. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  451. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  452. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  453. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  454. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  455. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  456. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  457. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  458. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  459. claude_mpm/skills/bundled/security-scanning.md +112 -0
  460. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  461. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  462. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  463. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  464. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  465. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  466. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  467. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  468. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  469. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  470. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  471. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  472. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  473. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  474. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  475. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  476. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  477. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  478. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  479. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  480. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  481. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  482. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  483. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  484. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  485. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  486. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  487. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  488. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  489. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  490. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  491. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  492. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  493. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  494. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  495. claude_mpm/skills/registry.py +295 -90
  496. claude_mpm/skills/skill_manager.py +98 -3
  497. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  498. claude_mpm/utils/agent_dependency_loader.py +115 -4
  499. claude_mpm/utils/agent_filters.py +17 -44
  500. claude_mpm/utils/gitignore.py +3 -0
  501. claude_mpm/utils/migration.py +4 -4
  502. claude_mpm/utils/robust_installer.py +86 -21
  503. claude_mpm-5.6.23.dist-info/METADATA +393 -0
  504. {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/RECORD +508 -261
  505. claude_mpm-5.6.23.dist-info/entry_points.txt +5 -0
  506. claude_mpm-5.6.23.dist-info/licenses/LICENSE +94 -0
  507. claude_mpm-5.6.23.dist-info/licenses/LICENSE-FAQ.md +153 -0
  508. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  509. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  510. claude_mpm/agents/BASE_OPS.md +0 -219
  511. claude_mpm/agents/BASE_PM.md +0 -480
  512. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  513. claude_mpm/agents/BASE_QA.md +0 -167
  514. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  515. claude_mpm/agents/OUTPUT_STYLE.md +0 -290
  516. claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +0 -1322
  517. claude_mpm/agents/base_agent_loader.py +0 -601
  518. claude_mpm/cli/commands/agents_detect.py +0 -380
  519. claude_mpm/cli/commands/agents_recommend.py +0 -309
  520. claude_mpm/cli/ticket_cli.py +0 -35
  521. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  522. claude_mpm/commands/mpm-agents-detect.md +0 -177
  523. claude_mpm/commands/mpm-agents-list.md +0 -131
  524. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  525. claude_mpm/commands/mpm-config-view.md +0 -150
  526. claude_mpm/commands/mpm-ticket-organize.md +0 -304
  527. claude_mpm/dashboard/analysis_runner.py +0 -455
  528. claude_mpm/dashboard/index.html +0 -13
  529. claude_mpm/dashboard/open_dashboard.py +0 -66
  530. claude_mpm/dashboard/static/css/activity.css +0 -1958
  531. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  532. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  533. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  534. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  535. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  536. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  537. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  538. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  539. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  540. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  541. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  542. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  543. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  544. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  545. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  546. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  547. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  548. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  549. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  550. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  551. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  552. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  553. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  554. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  555. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  556. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  557. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  558. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  559. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  560. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  561. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  562. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  563. claude_mpm/dashboard/templates/code_simple.html +0 -153
  564. claude_mpm/dashboard/templates/index.html +0 -606
  565. claude_mpm/dashboard/test_dashboard.html +0 -372
  566. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  567. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  568. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  569. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  570. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  571. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  572. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  573. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  574. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  575. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  576. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  577. claude_mpm/scripts/mcp_server.py +0 -75
  578. claude_mpm/scripts/mcp_wrapper.py +0 -39
  579. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  580. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  581. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  582. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  583. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  584. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  585. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  586. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  587. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  588. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  589. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
  590. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  591. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  592. claude_mpm/services/mcp_gateway/main.py +0 -589
  593. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  594. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  595. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  596. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  597. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  598. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  599. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  600. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  601. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  602. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  603. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  604. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  605. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  606. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  607. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  608. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  609. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  610. claude_mpm-5.0.9.dist-info/METADATA +0 -1028
  611. claude_mpm-5.0.9.dist-info/entry_points.txt +0 -10
  612. claude_mpm-5.0.9.dist-info/licenses/LICENSE +0 -21
  613. {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/WHEEL +0 -0
  614. {claude_mpm-5.0.9.dist-info → claude_mpm-5.6.23.dist-info}/top_level.txt +0 -0
@@ -15,7 +15,6 @@ DESIGN DECISIONS:
15
15
  """
16
16
 
17
17
  import asyncio
18
- import contextlib
19
18
  import os
20
19
  import threading
21
20
  import time
@@ -25,10 +24,11 @@ from typing import Dict, Optional
25
24
 
26
25
  import socketio
27
26
  from aiohttp import web
27
+ from watchdog.events import FileSystemEventHandler
28
+ from watchdog.observers import Observer
28
29
 
29
30
  from ...core.enums import ServiceState
30
31
  from ...core.logging_config import get_logger
31
- from ...dashboard.api.simple_directory import list_directory
32
32
  from .event_emitter import get_event_emitter
33
33
  from .handlers.code_analysis import CodeAnalysisHandler
34
34
  from .handlers.dashboard import DashboardHandler
@@ -45,6 +45,91 @@ except ImportError:
45
45
  EVENTBUS_AVAILABLE = False
46
46
 
47
47
 
48
+ class SvelteBuildWatcher(FileSystemEventHandler):
49
+ """File watcher for Svelte build directory changes.
50
+
51
+ Watches for file changes in svelte-build directory and triggers
52
+ hot reload via Socket.IO event emission.
53
+
54
+ STABILITY FIX: Added thread lock and stop() method to prevent timer leaks.
55
+ """
56
+
57
+ def __init__(
58
+ self, sio: socketio.AsyncServer, loop: asyncio.AbstractEventLoop, logger
59
+ ):
60
+ """Initialize the file watcher.
61
+
62
+ Args:
63
+ sio: Socket.IO server instance for emitting events
64
+ loop: Event loop for async operations
65
+ logger: Logger instance
66
+ """
67
+ super().__init__()
68
+ self.sio = sio
69
+ self.loop = loop
70
+ self.logger = logger
71
+ self.debounce_timer = None
72
+ self.debounce_delay = 0.5 # Wait 500ms after last change
73
+ self._timer_lock = threading.Lock() # STABILITY FIX: Prevent race condition
74
+
75
+ def stop(self):
76
+ """Stop the watcher and cancel any pending timers.
77
+
78
+ STABILITY FIX: Ensures timer is cancelled on shutdown.
79
+ """
80
+ with self._timer_lock:
81
+ if self.debounce_timer:
82
+ self.debounce_timer.cancel()
83
+ self.debounce_timer = None
84
+
85
+ def on_any_event(self, event):
86
+ """Handle any file system event.
87
+
88
+ Args:
89
+ event: File system event from watchdog
90
+ """
91
+ # Ignore directory events and temporary files
92
+ if event.is_directory or event.src_path.endswith((".tmp", ".swp", "~")):
93
+ return
94
+
95
+ self.logger.debug(
96
+ f"File change detected: {event.event_type} - {event.src_path}"
97
+ )
98
+
99
+ # STABILITY FIX: Use lock to prevent timer race condition
100
+ with self._timer_lock:
101
+ # Cancel existing timer
102
+ if self.debounce_timer:
103
+ self.debounce_timer.cancel()
104
+
105
+ # Schedule reload after debounce delay
106
+ self.debounce_timer = threading.Timer(
107
+ self.debounce_delay, self._trigger_reload
108
+ )
109
+ self.debounce_timer.start()
110
+
111
+ def _trigger_reload(self):
112
+ """Trigger hot reload by emitting Socket.IO event."""
113
+ try:
114
+ # Schedule the async emit in the event loop
115
+ asyncio.run_coroutine_threadsafe(self._emit_reload_event(), self.loop)
116
+ self.logger.info("Hot reload triggered - Svelte build changed")
117
+ except Exception as e:
118
+ self.logger.error(f"Error triggering reload: {e}")
119
+
120
+ async def _emit_reload_event(self):
121
+ """Emit the reload event to all connected clients."""
122
+ if self.sio:
123
+ await self.sio.emit(
124
+ "reload",
125
+ {
126
+ "type": "reload",
127
+ "timestamp": datetime.now(timezone.utc).isoformat() + "Z",
128
+ "reason": "svelte-build-updated",
129
+ },
130
+ )
131
+
132
+
48
133
  class UnifiedMonitorServer:
49
134
  """Unified server that combines HTTP dashboard and Socket.IO functionality.
50
135
 
@@ -52,15 +137,19 @@ class UnifiedMonitorServer:
52
137
  Replaces multiple competing server implementations with one stable solution.
53
138
  """
54
139
 
55
- def __init__(self, host: str = "localhost", port: int = 8765):
140
+ def __init__(
141
+ self, host: str = "localhost", port: int = 8765, enable_hot_reload: bool = False
142
+ ):
56
143
  """Initialize the unified monitor server.
57
144
 
58
145
  Args:
59
146
  host: Host to bind to
60
147
  port: Port to bind to
148
+ enable_hot_reload: Enable file watching and hot reload for development
61
149
  """
62
150
  self.host = host
63
151
  self.port = port
152
+ self.enable_hot_reload = enable_hot_reload
64
153
  self.logger = get_logger(__name__)
65
154
 
66
155
  # Core components
@@ -78,6 +167,10 @@ class UnifiedMonitorServer:
78
167
  # High-performance event emitter
79
168
  self.event_emitter = None
80
169
 
170
+ # File watching (optional for dev mode)
171
+ self.file_observer: Optional[Observer] = None
172
+ self.file_watcher: Optional[SvelteBuildWatcher] = None
173
+
81
174
  # State
82
175
  self.running = False
83
176
  self.loop = None
@@ -184,6 +277,9 @@ class UnifiedMonitorServer:
184
277
 
185
278
  time.sleep(0.1)
186
279
 
280
+ # STABILITY FIX: Give tasks more time to clean up before closing
281
+ time.sleep(0.5)
282
+
187
283
  # Clear the event loop from the thread BEFORE closing
188
284
  # This prevents other code from accidentally using it
189
285
  asyncio.set_event_loop(None)
@@ -229,6 +325,10 @@ class UnifiedMonitorServer:
229
325
  self.heartbeat_task = asyncio.create_task(self._heartbeat_loop())
230
326
  self.logger.info("Heartbeat task started (3-minute interval)")
231
327
 
328
+ # Setup file watching for hot reload (if enabled)
329
+ if self.enable_hot_reload:
330
+ self._setup_file_watcher()
331
+
232
332
  # Setup HTTP routes
233
333
  self._setup_http_routes()
234
334
 
@@ -268,6 +368,83 @@ class UnifiedMonitorServer:
268
368
  finally:
269
369
  await self._cleanup_async()
270
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
+
271
448
  def _setup_event_handlers(self):
272
449
  """Setup Socket.IO event handlers."""
273
450
  try:
@@ -304,20 +481,64 @@ class UnifiedMonitorServer:
304
481
  self.logger.error(f"Error setting up event emitter: {e}")
305
482
  raise
306
483
 
484
+ def _setup_file_watcher(self):
485
+ """Setup file watcher for Svelte build directory.
486
+
487
+ Watches for changes in svelte-build and triggers hot reload.
488
+ Only enabled when enable_hot_reload is True.
489
+ """
490
+ try:
491
+ dashboard_dir = Path(__file__).resolve().parent.parent.parent / "dashboard"
492
+ svelte_build_dir = dashboard_dir / "static" / "svelte-build"
493
+
494
+ if not svelte_build_dir.exists():
495
+ self.logger.warning(
496
+ f"Svelte build directory not found: {svelte_build_dir}. "
497
+ "Hot reload disabled."
498
+ )
499
+ return
500
+
501
+ # Create file watcher with Socket.IO reference
502
+ self.file_watcher = SvelteBuildWatcher(
503
+ sio=self.sio, loop=self.loop, logger=self.logger
504
+ )
505
+
506
+ # Create observer and schedule watching
507
+ self.file_observer = Observer()
508
+ self.file_observer.schedule(
509
+ self.file_watcher, str(svelte_build_dir), recursive=True
510
+ )
511
+ self.file_observer.start()
512
+
513
+ self.logger.info(f"🔥 Hot reload enabled - watching {svelte_build_dir}")
514
+
515
+ except Exception as e:
516
+ self.logger.error(f"Error setting up file watcher: {e}")
517
+ # Don't raise - hot reload is optional
518
+
307
519
  def _setup_http_routes(self):
308
520
  """Setup HTTP routes for the dashboard."""
309
521
  try:
310
- # Dashboard static files
311
- dashboard_dir = Path(__file__).parent.parent.parent / "dashboard"
522
+ # Dashboard static files - use .resolve() for absolute path
523
+ dashboard_dir = Path(__file__).resolve().parent.parent.parent / "dashboard"
524
+ static_dir = dashboard_dir / "static"
312
525
 
313
- # Main dashboard route
526
+ # Main dashboard route - serve Svelte dashboard
314
527
  async def dashboard_index(request):
315
- template_path = dashboard_dir / "templates" / "index.html"
316
- if template_path.exists():
317
- with template_path.open() as f:
528
+ svelte_index = static_dir / "svelte-build" / "index.html"
529
+ if svelte_index.exists():
530
+ with svelte_index.open(encoding="utf-8") as f:
318
531
  content = f.read()
319
532
  return web.Response(text=content, content_type="text/html")
320
- return web.Response(text="Dashboard not found", status=404)
533
+
534
+ # Log error with path details for debugging
535
+ self.logger.error(
536
+ f"Dashboard index.html not found at: {svelte_index.resolve()}"
537
+ )
538
+ return web.Response(
539
+ text=f"Dashboard not found. Expected location: {svelte_index.resolve()}",
540
+ status=404,
541
+ )
321
542
 
322
543
  # Health check
323
544
  async def health_check(request):
@@ -325,11 +546,12 @@ class UnifiedMonitorServer:
325
546
  version = "1.0.0"
326
547
  try:
327
548
  version_file = (
328
- Path(__file__).parent.parent.parent.parent.parent / "VERSION"
549
+ Path(__file__).resolve().parent.parent.parent.parent.parent
550
+ / "VERSION"
329
551
  )
330
552
  if version_file.exists():
331
553
  version = version_file.read_text().strip()
332
- except Exception:
554
+ except Exception: # nosec B110
333
555
  pass
334
556
 
335
557
  return web.json_response(
@@ -354,10 +576,23 @@ class UnifiedMonitorServer:
354
576
  event = data.get("event", "claude_event")
355
577
  event_data = data.get("data", {})
356
578
 
357
- # 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
358
591
  if self.sio:
359
- await self.sio.emit(event, event_data)
360
- 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
+ )
361
596
 
362
597
  return web.Response(status=204) # No content response
363
598
 
@@ -442,6 +677,243 @@ class UnifiedMonitorServer:
442
677
  {"success": False, "error": str(e)}, status=500
443
678
  )
444
679
 
680
+ # File listing endpoint for file browser
681
+ async def api_files_handler(request):
682
+ """List files in a directory for the file browser."""
683
+ try:
684
+ # Get path from query param, default to working directory
685
+ path = request.query.get("path", str(Path.cwd()))
686
+ dir_path = Path(path)
687
+
688
+ if not dir_path.exists():
689
+ return web.json_response(
690
+ {"success": False, "error": "Directory not found"},
691
+ status=404,
692
+ )
693
+
694
+ if not dir_path.is_dir():
695
+ return web.json_response(
696
+ {"success": False, "error": "Path is not a directory"},
697
+ status=400,
698
+ )
699
+
700
+ # Patterns to exclude
701
+ exclude_patterns = {
702
+ ".git",
703
+ "node_modules",
704
+ "__pycache__",
705
+ ".svelte-kit",
706
+ "venv",
707
+ ".venv",
708
+ "dist",
709
+ "build",
710
+ ".next",
711
+ ".cache",
712
+ ".pytest_cache",
713
+ ".mypy_cache",
714
+ ".ruff_cache",
715
+ "eggs",
716
+ "*.egg-info",
717
+ ".tox",
718
+ ".nox",
719
+ "htmlcov",
720
+ ".coverage",
721
+ }
722
+
723
+ entries = []
724
+ try:
725
+ for entry in sorted(
726
+ dir_path.iterdir(),
727
+ key=lambda x: (not x.is_dir(), x.name.lower()),
728
+ ):
729
+ # Skip hidden files and excluded patterns
730
+ if entry.name.startswith(".") and entry.name not in {
731
+ ".env",
732
+ ".gitignore",
733
+ }:
734
+ if entry.name in {".git", ".svelte-kit", ".cache"}:
735
+ continue
736
+ if entry.name in exclude_patterns:
737
+ continue
738
+ if any(
739
+ entry.name.endswith(p.replace("*", ""))
740
+ for p in exclude_patterns
741
+ if "*" in p
742
+ ):
743
+ continue
744
+
745
+ try:
746
+ stat = entry.stat()
747
+ entries.append(
748
+ {
749
+ "name": entry.name,
750
+ "path": str(entry),
751
+ "type": "directory"
752
+ if entry.is_dir()
753
+ else "file",
754
+ "size": stat.st_size if entry.is_file() else 0,
755
+ "modified": stat.st_mtime,
756
+ "extension": entry.suffix.lstrip(".")
757
+ if entry.is_file()
758
+ else None,
759
+ }
760
+ )
761
+ except (PermissionError, OSError):
762
+ continue
763
+
764
+ except PermissionError:
765
+ return web.json_response(
766
+ {"success": False, "error": "Permission denied"},
767
+ status=403,
768
+ )
769
+
770
+ # Separate directories and files
771
+ directories = [e for e in entries if e["type"] == "directory"]
772
+ files = [e for e in entries if e["type"] == "file"]
773
+
774
+ return web.json_response(
775
+ {
776
+ "success": True,
777
+ "path": str(dir_path),
778
+ "directories": directories,
779
+ "files": files,
780
+ "total_directories": len(directories),
781
+ "total_files": len(files),
782
+ }
783
+ )
784
+
785
+ except Exception as e:
786
+ self.logger.error(f"Error listing directory: {e}")
787
+ return web.json_response(
788
+ {"success": False, "error": str(e)}, status=500
789
+ )
790
+
791
+ # File read endpoint (GET) for file browser
792
+ async def api_file_read_handler(request):
793
+ """Read file content via GET request."""
794
+ import base64
795
+
796
+ try:
797
+ file_path = request.query.get("path", "")
798
+
799
+ if not file_path:
800
+ return web.json_response(
801
+ {"success": False, "error": "Path parameter required"},
802
+ status=400,
803
+ )
804
+
805
+ path = Path(file_path)
806
+
807
+ if not path.exists():
808
+ return web.json_response(
809
+ {"success": False, "error": "File not found"},
810
+ status=404,
811
+ )
812
+
813
+ if not path.is_file():
814
+ return web.json_response(
815
+ {"success": False, "error": "Path is not a file"},
816
+ status=400,
817
+ )
818
+
819
+ # Get file info
820
+ file_size = path.stat().st_size
821
+ file_ext = path.suffix.lstrip(".").lower()
822
+
823
+ # Define image extensions
824
+ image_extensions = {
825
+ "png",
826
+ "jpg",
827
+ "jpeg",
828
+ "gif",
829
+ "svg",
830
+ "webp",
831
+ "ico",
832
+ "bmp",
833
+ }
834
+
835
+ # Check if file is an image
836
+ if file_ext in image_extensions:
837
+ # Read as binary and encode to base64
838
+ try:
839
+ binary_content = path.read_bytes()
840
+ base64_content = base64.b64encode(binary_content).decode(
841
+ "utf-8"
842
+ )
843
+
844
+ # Map extension to MIME type
845
+ mime_types = {
846
+ "png": "image/png",
847
+ "jpg": "image/jpeg",
848
+ "jpeg": "image/jpeg",
849
+ "gif": "image/gif",
850
+ "svg": "image/svg+xml",
851
+ "webp": "image/webp",
852
+ "ico": "image/x-icon",
853
+ "bmp": "image/bmp",
854
+ }
855
+ mime_type = mime_types.get(file_ext, "image/png")
856
+
857
+ return web.json_response(
858
+ {
859
+ "success": True,
860
+ "path": str(path),
861
+ "content": base64_content,
862
+ "size": file_size,
863
+ "type": "image",
864
+ "mime": mime_type,
865
+ "extension": file_ext,
866
+ }
867
+ )
868
+ except Exception as e:
869
+ self.logger.error(f"Error reading image file: {e}")
870
+ return web.json_response(
871
+ {
872
+ "success": False,
873
+ "error": f"Failed to read image: {e!s}",
874
+ },
875
+ status=500,
876
+ )
877
+
878
+ # Read text file content
879
+ try:
880
+ content = path.read_text(encoding="utf-8")
881
+ lines = content.count("\n") + 1
882
+ except UnicodeDecodeError:
883
+ return web.json_response(
884
+ {"success": False, "error": "File is not a text file"},
885
+ status=415,
886
+ )
887
+
888
+ return web.json_response(
889
+ {
890
+ "success": True,
891
+ "path": str(path),
892
+ "content": content,
893
+ "lines": lines,
894
+ "size": file_size,
895
+ "type": file_ext or "text",
896
+ }
897
+ )
898
+
899
+ except Exception as e:
900
+ self.logger.error(f"Error reading file: {e}")
901
+ return web.json_response(
902
+ {"success": False, "error": str(e)}, status=500
903
+ )
904
+
905
+ # Favicon handler
906
+ async def favicon_handler(request):
907
+ """Serve favicon.svg from static directory."""
908
+ from aiohttp.web_fileresponse import FileResponse
909
+
910
+ favicon_path = static_dir / "svelte-build" / "favicon.svg"
911
+ if favicon_path.exists():
912
+ return FileResponse(
913
+ favicon_path, headers={"Content-Type": "image/svg+xml"}
914
+ )
915
+ raise web.HTTPNotFound()
916
+
445
917
  # Version endpoint for dashboard build tracker
446
918
  async def version_handler(request):
447
919
  """Serve version information for dashboard build tracker."""
@@ -477,7 +949,7 @@ class UnifiedMonitorServer:
477
949
  # Configuration endpoint for dashboard initialization
478
950
  async def config_handler(request):
479
951
  """Return configuration for dashboard initialization."""
480
- import subprocess
952
+ import subprocess # nosec B404
481
953
 
482
954
  config = {
483
955
  "workingDirectory": Path.cwd(),
@@ -488,7 +960,7 @@ class UnifiedMonitorServer:
488
960
 
489
961
  # Try to get current git branch
490
962
  try:
491
- result = subprocess.run(
963
+ result = subprocess.run( # nosec B603 B607
492
964
  ["git", "branch", "--show-current"],
493
965
  capture_output=True,
494
966
  text=True,
@@ -498,7 +970,7 @@ class UnifiedMonitorServer:
498
970
  )
499
971
  if result.returncode == 0 and result.stdout.strip():
500
972
  config["gitBranch"] = result.stdout.strip()
501
- except Exception:
973
+ except Exception: # nosec B110
502
974
  pass # Keep default "Unknown" value
503
975
 
504
976
  return web.json_response(config)
@@ -507,7 +979,7 @@ class UnifiedMonitorServer:
507
979
  async def working_directory_handler(request):
508
980
  """Return the current working directory."""
509
981
  return web.json_response(
510
- {"working_directory": Path.cwd(), "success": True}
982
+ {"working_directory": str(Path.cwd()), "success": True}
511
983
  )
512
984
 
513
985
  # Monitor page routes
@@ -525,15 +997,249 @@ class UnifiedMonitorServer:
525
997
  return web.Response(text=content, content_type="text/html")
526
998
  return web.Response(text="Page not found", status=404)
527
999
 
1000
+ # Git history handler
1001
+ async def git_history_handler(request: web.Request) -> web.Response:
1002
+ """Get git history for a file."""
1003
+ import subprocess # nosec B404
1004
+
1005
+ try:
1006
+ data = await request.json()
1007
+ file_path = data.get("path", "")
1008
+ limit = data.get("limit", 10)
1009
+
1010
+ if not file_path:
1011
+ return web.json_response(
1012
+ {
1013
+ "success": False,
1014
+ "error": "No path provided",
1015
+ "commits": [],
1016
+ },
1017
+ status=400,
1018
+ )
1019
+
1020
+ path = Path(file_path)
1021
+ if not path.exists():
1022
+ return web.json_response(
1023
+ {
1024
+ "success": False,
1025
+ "error": "File not found",
1026
+ "commits": [],
1027
+ },
1028
+ status=404,
1029
+ )
1030
+
1031
+ # Get git log for file
1032
+ result = subprocess.run( # nosec B603 B607
1033
+ [
1034
+ "git",
1035
+ "log",
1036
+ f"-{limit}",
1037
+ "--pretty=format:%H|%an|%ar|%s",
1038
+ "--",
1039
+ str(path),
1040
+ ],
1041
+ check=False,
1042
+ capture_output=True,
1043
+ text=True,
1044
+ cwd=str(path.parent),
1045
+ )
1046
+
1047
+ commits = []
1048
+ if result.returncode == 0 and result.stdout:
1049
+ for line in result.stdout.strip().split("\n"):
1050
+ if line:
1051
+ parts = line.split("|", 3)
1052
+ if len(parts) == 4:
1053
+ commits.append(
1054
+ {
1055
+ "hash": parts[0][:7],
1056
+ "author": parts[1],
1057
+ "date": parts[2],
1058
+ "message": parts[3],
1059
+ }
1060
+ )
1061
+
1062
+ return web.json_response({"success": True, "commits": commits})
1063
+ except Exception as e:
1064
+ return web.json_response(
1065
+ {"success": False, "error": str(e), "commits": []}, status=500
1066
+ )
1067
+
1068
+ # Git diff handler
1069
+ async def git_diff_handler(request: web.Request) -> web.Response:
1070
+ """Get git diff for a file with optional commit selection."""
1071
+ import subprocess # nosec B404
1072
+
1073
+ try:
1074
+ file_path = request.query.get("path", "")
1075
+ commit_hash = request.query.get(
1076
+ "commit", ""
1077
+ ) # Optional commit hash
1078
+
1079
+ if not file_path:
1080
+ return web.json_response(
1081
+ {
1082
+ "success": False,
1083
+ "error": "No path provided",
1084
+ "diff": "",
1085
+ "has_changes": False,
1086
+ },
1087
+ status=400,
1088
+ )
1089
+
1090
+ path = Path(file_path)
1091
+ if not path.exists():
1092
+ return web.json_response(
1093
+ {
1094
+ "success": False,
1095
+ "error": "File not found",
1096
+ "diff": "",
1097
+ "has_changes": False,
1098
+ },
1099
+ status=404,
1100
+ )
1101
+
1102
+ # Find git repository root
1103
+ git_root_result = subprocess.run( # nosec B603 B607
1104
+ ["git", "rev-parse", "--show-toplevel"],
1105
+ check=False,
1106
+ capture_output=True,
1107
+ text=True,
1108
+ cwd=str(path.parent),
1109
+ )
1110
+
1111
+ if git_root_result.returncode != 0:
1112
+ # Not in a git repository
1113
+ return web.json_response(
1114
+ {
1115
+ "success": True,
1116
+ "diff": "",
1117
+ "has_changes": False,
1118
+ "tracked": False,
1119
+ "history": [],
1120
+ "has_uncommitted": False,
1121
+ }
1122
+ )
1123
+
1124
+ git_root = Path(git_root_result.stdout.strip())
1125
+
1126
+ # Check if file is tracked by git
1127
+ ls_files_result = subprocess.run( # nosec B603 B607
1128
+ ["git", "ls-files", "--error-unmatch", str(path)],
1129
+ check=False,
1130
+ capture_output=True,
1131
+ text=True,
1132
+ cwd=str(git_root),
1133
+ )
1134
+
1135
+ if ls_files_result.returncode != 0:
1136
+ # File is not tracked by git
1137
+ return web.json_response(
1138
+ {
1139
+ "success": True,
1140
+ "diff": "",
1141
+ "has_changes": False,
1142
+ "tracked": False,
1143
+ "history": [],
1144
+ "has_uncommitted": False,
1145
+ }
1146
+ )
1147
+
1148
+ # Get commit history for this file (last 5 commits)
1149
+ history_result = subprocess.run( # nosec B603 B607
1150
+ [
1151
+ "git",
1152
+ "log",
1153
+ "-5",
1154
+ "--pretty=format:%H|%s|%ar",
1155
+ "--",
1156
+ str(path),
1157
+ ],
1158
+ check=False,
1159
+ capture_output=True,
1160
+ text=True,
1161
+ cwd=str(git_root),
1162
+ )
1163
+
1164
+ history = []
1165
+ if history_result.returncode == 0 and history_result.stdout:
1166
+ for line in history_result.stdout.strip().split("\n"):
1167
+ if line:
1168
+ parts = line.split("|", 2)
1169
+ if len(parts) == 3:
1170
+ history.append(
1171
+ {
1172
+ "hash": parts[0][:7], # Short hash
1173
+ "full_hash": parts[0], # Full hash for API
1174
+ "message": parts[1],
1175
+ "time_ago": parts[2],
1176
+ }
1177
+ )
1178
+
1179
+ # Check for uncommitted changes
1180
+ uncommitted_result = subprocess.run( # nosec B603 B607
1181
+ ["git", "diff", "HEAD", str(path)],
1182
+ check=False,
1183
+ capture_output=True,
1184
+ text=True,
1185
+ cwd=str(git_root),
1186
+ )
1187
+
1188
+ has_uncommitted = bool(uncommitted_result.stdout.strip())
1189
+
1190
+ # Get diff based on commit parameter
1191
+ if commit_hash:
1192
+ # Get diff for specific commit
1193
+ result = subprocess.run( # nosec B603 B607
1194
+ ["git", "show", commit_hash, "--", str(path)],
1195
+ check=False,
1196
+ capture_output=True,
1197
+ text=True,
1198
+ cwd=str(git_root),
1199
+ )
1200
+ diff_output = result.stdout if result.returncode == 0 else ""
1201
+ has_changes = bool(diff_output.strip())
1202
+ else:
1203
+ # Get uncommitted diff (default behavior)
1204
+ diff_output = uncommitted_result.stdout
1205
+ has_changes = has_uncommitted
1206
+
1207
+ return web.json_response(
1208
+ {
1209
+ "success": True,
1210
+ "diff": diff_output,
1211
+ "has_changes": has_changes,
1212
+ "tracked": True,
1213
+ "history": history,
1214
+ "has_uncommitted": has_uncommitted,
1215
+ }
1216
+ )
1217
+ except Exception as e:
1218
+ return web.json_response(
1219
+ {
1220
+ "success": False,
1221
+ "error": str(e),
1222
+ "diff": "",
1223
+ "has_changes": False,
1224
+ "history": [],
1225
+ "has_uncommitted": False,
1226
+ },
1227
+ status=500,
1228
+ )
1229
+
528
1230
  # Register routes
529
1231
  self.app.router.add_get("/", dashboard_index)
1232
+ self.app.router.add_get("/favicon.svg", favicon_handler)
530
1233
  self.app.router.add_get("/health", health_check)
531
1234
  self.app.router.add_get("/version.json", version_handler)
532
1235
  self.app.router.add_get("/api/config", config_handler)
533
1236
  self.app.router.add_get("/api/working-directory", working_directory_handler)
534
- self.app.router.add_get("/api/directory", list_directory)
1237
+ self.app.router.add_get("/api/files", api_files_handler)
1238
+ self.app.router.add_get("/api/file/read", api_file_read_handler)
1239
+ self.app.router.add_get("/api/file/diff", git_diff_handler)
535
1240
  self.app.router.add_post("/api/events", api_events_handler)
536
1241
  self.app.router.add_post("/api/file", api_file_handler)
1242
+ self.app.router.add_post("/api/git-history", git_history_handler)
537
1243
 
538
1244
  # Monitor page routes
539
1245
  self.app.router.add_get("/monitor", lambda r: monitor_page_handler(r))
@@ -546,12 +1252,43 @@ class UnifiedMonitorServer:
546
1252
  "/monitor/events", lambda r: monitor_page_handler(r)
547
1253
  )
548
1254
 
549
- # Static files with cache busting headers for development
550
- static_dir = dashboard_dir / "static"
1255
+ # Serve Svelte _app assets (compiled JS/CSS)
1256
+ svelte_build_dir = static_dir / "svelte-build"
1257
+ if svelte_build_dir.exists():
1258
+ svelte_app_dir = svelte_build_dir / "_app"
1259
+ if svelte_app_dir.exists():
1260
+ # Serve _app assets with proper caching
1261
+ async def app_assets_handler(request):
1262
+ """Serve Svelte _app assets."""
1263
+ from aiohttp.web_fileresponse import FileResponse
1264
+
1265
+ rel_path = request.match_info["filepath"]
1266
+ file_path = svelte_app_dir / rel_path
1267
+
1268
+ if not file_path.exists() or not file_path.is_file():
1269
+ raise web.HTTPNotFound()
1270
+
1271
+ response = FileResponse(file_path)
1272
+
1273
+ # Add cache headers for immutable assets
1274
+ if "/immutable/" in str(rel_path):
1275
+ response.headers["Cache-Control"] = (
1276
+ "public, max-age=31536000, immutable"
1277
+ )
1278
+ else:
1279
+ response.headers["Cache-Control"] = (
1280
+ "no-cache, no-store, must-revalidate"
1281
+ )
1282
+
1283
+ return response
1284
+
1285
+ self.app.router.add_get("/_app/{filepath:.*}", app_assets_handler)
1286
+
1287
+ # Legacy static files (for backward compatibility)
551
1288
  if static_dir.exists():
552
1289
 
553
1290
  async def static_handler(request):
554
- """Serve static files with cache-control headers for development."""
1291
+ """Serve legacy static files with cache-control headers for development."""
555
1292
 
556
1293
  from aiohttp.web_fileresponse import FileResponse
557
1294
 
@@ -576,10 +1313,13 @@ class UnifiedMonitorServer:
576
1313
 
577
1314
  self.app.router.add_get("/static/{filepath:.*}", static_handler)
578
1315
 
579
- # Templates
580
- templates_dir = dashboard_dir / "templates"
581
- if templates_dir.exists():
582
- self.app.router.add_static("/templates/", templates_dir)
1316
+ # Log dashboard availability
1317
+ if svelte_build_dir.exists():
1318
+ self.logger.info(
1319
+ f"✅ Svelte dashboard available at / (root) (build: {svelte_build_dir})"
1320
+ )
1321
+ else:
1322
+ self.logger.warning(f"Svelte build not found at: {svelte_build_dir}")
583
1323
 
584
1324
  self.logger.info("HTTP routes registered successfully")
585
1325
 
@@ -691,11 +1431,37 @@ class UnifiedMonitorServer:
691
1431
  async def _cleanup_async(self):
692
1432
  """Cleanup async resources."""
693
1433
  try:
1434
+ # Stop file observer if running
1435
+ # STABILITY FIX: Ensure watcher is stopped and verify observer termination
1436
+ if self.file_observer:
1437
+ try:
1438
+ # Stop the watcher first to cancel pending timers
1439
+ if self.file_watcher:
1440
+ self.file_watcher.stop()
1441
+
1442
+ # Stop the observer
1443
+ self.file_observer.stop()
1444
+ self.file_observer.join(timeout=2)
1445
+
1446
+ # Verify observer actually stopped
1447
+ if self.file_observer.is_alive():
1448
+ self.logger.warning("File observer did not stop cleanly")
1449
+
1450
+ self.logger.debug("File observer stopped")
1451
+ except Exception as e:
1452
+ self.logger.debug(f"Error stopping file observer: {e}")
1453
+ finally:
1454
+ self.file_observer = None
1455
+ self.file_watcher = None
1456
+
694
1457
  # Cancel heartbeat task if running
1458
+ # STABILITY FIX: Add timeout to prevent infinite wait on cancellation
695
1459
  if self.heartbeat_task and not self.heartbeat_task.done():
696
1460
  self.heartbeat_task.cancel()
697
- with contextlib.suppress(asyncio.CancelledError):
698
- await self.heartbeat_task
1461
+ try:
1462
+ await asyncio.wait_for(self.heartbeat_task, timeout=2.0)
1463
+ except (asyncio.CancelledError, asyncio.TimeoutError):
1464
+ pass
699
1465
  self.logger.debug("Heartbeat task cancelled")
700
1466
 
701
1467
  # Close the Socket.IO server first to stop accepting new connections
@@ -793,7 +1559,7 @@ class UnifiedMonitorServer:
793
1559
  gather = asyncio.gather(*tasks_to_cancel, return_exceptions=True)
794
1560
  try:
795
1561
  loop.run_until_complete(gather)
796
- except Exception:
1562
+ except Exception: # nosec B110
797
1563
  # Some tasks might fail to cancel, that's ok
798
1564
  pass
799
1565