claude-mpm 5.4.22__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 (487) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT.md +164 -0
  3. claude_mpm/agents/BASE_ENGINEER.md +658 -0
  4. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
  5. claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
  6. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
  7. claude_mpm/agents/MEMORY.md +1 -1
  8. claude_mpm/agents/PM_INSTRUCTIONS.md +374 -1257
  9. claude_mpm/agents/WORKFLOW.md +6 -253
  10. claude_mpm/agents/agent_loader.py +1 -1
  11. claude_mpm/agents/base_agent.json +31 -0
  12. claude_mpm/agents/frontmatter_validator.py +2 -2
  13. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  14. claude_mpm/cli/__init__.py +5 -1
  15. claude_mpm/cli/commands/agent_state_manager.py +10 -10
  16. claude_mpm/cli/commands/agents.py +11 -13
  17. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  18. claude_mpm/cli/commands/auto_configure.py +4 -4
  19. claude_mpm/cli/commands/autotodos.py +566 -0
  20. claude_mpm/cli/commands/commander.py +216 -0
  21. claude_mpm/cli/commands/configure.py +621 -22
  22. claude_mpm/cli/commands/configure_agent_display.py +12 -0
  23. claude_mpm/cli/commands/hook_errors.py +60 -60
  24. claude_mpm/cli/commands/monitor.py +2 -2
  25. claude_mpm/cli/commands/mpm_init/core.py +72 -0
  26. claude_mpm/cli/commands/postmortem.py +1 -1
  27. claude_mpm/cli/commands/profile.py +276 -0
  28. claude_mpm/cli/commands/run.py +35 -3
  29. claude_mpm/cli/commands/skill_source.py +51 -2
  30. claude_mpm/cli/commands/skills.py +182 -32
  31. claude_mpm/cli/executor.py +130 -16
  32. claude_mpm/cli/interactive/__init__.py +10 -0
  33. claude_mpm/cli/interactive/agent_wizard.py +32 -52
  34. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  35. claude_mpm/cli/interactive/skill_selector.py +481 -0
  36. claude_mpm/cli/parsers/base_parser.py +83 -1
  37. claude_mpm/cli/parsers/commander_parser.py +116 -0
  38. claude_mpm/cli/parsers/profile_parser.py +147 -0
  39. claude_mpm/cli/parsers/run_parser.py +10 -0
  40. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  41. claude_mpm/cli/parsers/skills_parser.py +2 -3
  42. claude_mpm/cli/startup.py +690 -386
  43. claude_mpm/cli/startup_display.py +74 -6
  44. claude_mpm/cli/startup_logging.py +2 -2
  45. claude_mpm/cli/utils.py +7 -3
  46. claude_mpm/commander/__init__.py +78 -0
  47. claude_mpm/commander/adapters/__init__.py +60 -0
  48. claude_mpm/commander/adapters/auggie.py +260 -0
  49. claude_mpm/commander/adapters/base.py +288 -0
  50. claude_mpm/commander/adapters/claude_code.py +392 -0
  51. claude_mpm/commander/adapters/codex.py +237 -0
  52. claude_mpm/commander/adapters/communication.py +366 -0
  53. claude_mpm/commander/adapters/example_usage.py +310 -0
  54. claude_mpm/commander/adapters/mpm.py +389 -0
  55. claude_mpm/commander/adapters/registry.py +204 -0
  56. claude_mpm/commander/api/__init__.py +16 -0
  57. claude_mpm/commander/api/app.py +121 -0
  58. claude_mpm/commander/api/errors.py +133 -0
  59. claude_mpm/commander/api/routes/__init__.py +8 -0
  60. claude_mpm/commander/api/routes/events.py +184 -0
  61. claude_mpm/commander/api/routes/inbox.py +171 -0
  62. claude_mpm/commander/api/routes/messages.py +148 -0
  63. claude_mpm/commander/api/routes/projects.py +271 -0
  64. claude_mpm/commander/api/routes/sessions.py +226 -0
  65. claude_mpm/commander/api/routes/work.py +296 -0
  66. claude_mpm/commander/api/schemas.py +186 -0
  67. claude_mpm/commander/chat/__init__.py +7 -0
  68. claude_mpm/commander/chat/cli.py +146 -0
  69. claude_mpm/commander/chat/commands.py +96 -0
  70. claude_mpm/commander/chat/repl.py +310 -0
  71. claude_mpm/commander/config.py +51 -0
  72. claude_mpm/commander/config_loader.py +115 -0
  73. claude_mpm/commander/core/__init__.py +10 -0
  74. claude_mpm/commander/core/block_manager.py +325 -0
  75. claude_mpm/commander/core/response_manager.py +323 -0
  76. claude_mpm/commander/daemon.py +603 -0
  77. claude_mpm/commander/env_loader.py +59 -0
  78. claude_mpm/commander/events/__init__.py +26 -0
  79. claude_mpm/commander/events/manager.py +332 -0
  80. claude_mpm/commander/frameworks/__init__.py +12 -0
  81. claude_mpm/commander/frameworks/base.py +146 -0
  82. claude_mpm/commander/frameworks/claude_code.py +58 -0
  83. claude_mpm/commander/frameworks/mpm.py +62 -0
  84. claude_mpm/commander/inbox/__init__.py +16 -0
  85. claude_mpm/commander/inbox/dedup.py +128 -0
  86. claude_mpm/commander/inbox/inbox.py +224 -0
  87. claude_mpm/commander/inbox/models.py +70 -0
  88. claude_mpm/commander/instance_manager.py +450 -0
  89. claude_mpm/commander/llm/__init__.py +6 -0
  90. claude_mpm/commander/llm/openrouter_client.py +167 -0
  91. claude_mpm/commander/llm/summarizer.py +70 -0
  92. claude_mpm/commander/memory/__init__.py +45 -0
  93. claude_mpm/commander/memory/compression.py +347 -0
  94. claude_mpm/commander/memory/embeddings.py +230 -0
  95. claude_mpm/commander/memory/entities.py +310 -0
  96. claude_mpm/commander/memory/example_usage.py +290 -0
  97. claude_mpm/commander/memory/integration.py +325 -0
  98. claude_mpm/commander/memory/search.py +381 -0
  99. claude_mpm/commander/memory/store.py +657 -0
  100. claude_mpm/commander/models/__init__.py +18 -0
  101. claude_mpm/commander/models/events.py +121 -0
  102. claude_mpm/commander/models/project.py +162 -0
  103. claude_mpm/commander/models/work.py +214 -0
  104. claude_mpm/commander/parsing/__init__.py +20 -0
  105. claude_mpm/commander/parsing/extractor.py +132 -0
  106. claude_mpm/commander/parsing/output_parser.py +270 -0
  107. claude_mpm/commander/parsing/patterns.py +100 -0
  108. claude_mpm/commander/persistence/__init__.py +11 -0
  109. claude_mpm/commander/persistence/event_store.py +274 -0
  110. claude_mpm/commander/persistence/state_store.py +309 -0
  111. claude_mpm/commander/persistence/work_store.py +164 -0
  112. claude_mpm/commander/polling/__init__.py +13 -0
  113. claude_mpm/commander/polling/event_detector.py +104 -0
  114. claude_mpm/commander/polling/output_buffer.py +49 -0
  115. claude_mpm/commander/polling/output_poller.py +153 -0
  116. claude_mpm/commander/project_session.py +268 -0
  117. claude_mpm/commander/proxy/__init__.py +12 -0
  118. claude_mpm/commander/proxy/formatter.py +89 -0
  119. claude_mpm/commander/proxy/output_handler.py +191 -0
  120. claude_mpm/commander/proxy/relay.py +155 -0
  121. claude_mpm/commander/registry.py +410 -0
  122. claude_mpm/commander/runtime/__init__.py +10 -0
  123. claude_mpm/commander/runtime/executor.py +191 -0
  124. claude_mpm/commander/runtime/monitor.py +346 -0
  125. claude_mpm/commander/session/__init__.py +6 -0
  126. claude_mpm/commander/session/context.py +81 -0
  127. claude_mpm/commander/session/manager.py +59 -0
  128. claude_mpm/commander/tmux_orchestrator.py +361 -0
  129. claude_mpm/commander/web/__init__.py +1 -0
  130. claude_mpm/commander/work/__init__.py +30 -0
  131. claude_mpm/commander/work/executor.py +207 -0
  132. claude_mpm/commander/work/queue.py +405 -0
  133. claude_mpm/commander/workflow/__init__.py +27 -0
  134. claude_mpm/commander/workflow/event_handler.py +241 -0
  135. claude_mpm/commander/workflow/notifier.py +146 -0
  136. claude_mpm/commands/mpm-config.md +20 -249
  137. claude_mpm/commands/mpm-doctor.md +16 -21
  138. claude_mpm/commands/mpm-help.md +12 -205
  139. claude_mpm/commands/mpm-init.md +88 -506
  140. claude_mpm/commands/mpm-monitor.md +22 -401
  141. claude_mpm/commands/mpm-organize.md +70 -442
  142. claude_mpm/commands/mpm-postmortem.md +13 -107
  143. claude_mpm/commands/mpm-session-resume.md +20 -363
  144. claude_mpm/commands/mpm-status.md +13 -69
  145. claude_mpm/commands/mpm-ticket-view.md +60 -495
  146. claude_mpm/commands/mpm-version.md +13 -107
  147. claude_mpm/commands/mpm.md +8 -0
  148. claude_mpm/config/agent_presets.py +8 -7
  149. claude_mpm/config/skill_sources.py +16 -0
  150. claude_mpm/constants.py +1 -0
  151. claude_mpm/core/claude_runner.py +154 -2
  152. claude_mpm/core/config.py +37 -26
  153. claude_mpm/core/config_constants.py +74 -9
  154. claude_mpm/core/constants.py +56 -12
  155. claude_mpm/core/framework/loaders/agent_loader.py +1 -1
  156. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  157. claude_mpm/core/hook_manager.py +51 -3
  158. claude_mpm/core/interactive_session.py +12 -11
  159. claude_mpm/core/logger.py +26 -9
  160. claude_mpm/core/logging_utils.py +39 -13
  161. claude_mpm/core/network_config.py +148 -0
  162. claude_mpm/core/oneshot_session.py +7 -6
  163. claude_mpm/core/optimized_startup.py +61 -0
  164. claude_mpm/core/output_style_manager.py +66 -18
  165. claude_mpm/core/shared/config_loader.py +3 -1
  166. claude_mpm/core/socketio_pool.py +47 -15
  167. claude_mpm/core/unified_agent_registry.py +1 -1
  168. claude_mpm/core/unified_config.py +54 -8
  169. claude_mpm/core/unified_paths.py +95 -90
  170. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  171. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  172. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  173. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
  174. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DR8nis88.js +2 -0
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  220. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
  221. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  222. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
  223. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  224. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
  225. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
  226. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  227. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
  228. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
  229. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
  230. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
  231. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  232. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.RgBboRvH.js +1 -0
  233. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
  234. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  235. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  236. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  237. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  238. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  239. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  240. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  241. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  242. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  243. claude_mpm/experimental/cli_enhancements.py +2 -1
  244. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  245. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  246. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  247. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  248. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  249. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  250. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  251. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  252. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  253. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  254. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  255. claude_mpm/hooks/claude_hooks/event_handlers.py +527 -136
  256. claude_mpm/hooks/claude_hooks/hook_handler.py +313 -99
  257. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  258. claude_mpm/hooks/claude_hooks/installer.py +206 -36
  259. claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
  260. claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
  261. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  262. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  263. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  264. claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
  265. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  266. claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
  267. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  268. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  269. claude_mpm/hooks/claude_hooks/services/connection_manager.py +67 -32
  270. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
  271. claude_mpm/hooks/claude_hooks/services/container.py +310 -0
  272. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  273. claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
  274. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
  275. claude_mpm/hooks/kuzu_memory_hook.py +5 -5
  276. claude_mpm/hooks/session_resume_hook.py +89 -1
  277. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  278. claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
  279. claude_mpm/init.py +276 -0
  280. claude_mpm/models/git_repository.py +3 -3
  281. claude_mpm/scripts/claude-hook-handler.sh +46 -19
  282. claude_mpm/services/agents/agent_builder.py +3 -3
  283. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  284. claude_mpm/services/agents/agent_selection_service.py +2 -2
  285. claude_mpm/services/agents/cache_git_manager.py +7 -7
  286. claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
  287. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -2
  288. claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
  289. claude_mpm/services/agents/deployment/agent_template_builder.py +39 -19
  290. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  291. claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
  292. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  293. claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
  294. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +169 -26
  295. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +101 -75
  296. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  297. claude_mpm/services/agents/git_source_manager.py +23 -4
  298. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  299. claude_mpm/services/agents/recommender.py +5 -3
  300. claude_mpm/services/agents/single_tier_deployment_service.py +6 -6
  301. claude_mpm/services/agents/sources/git_source_sync_service.py +121 -10
  302. claude_mpm/services/agents/startup_sync.py +27 -4
  303. claude_mpm/services/cli/__init__.py +3 -0
  304. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  305. claude_mpm/services/cli/session_resume_helper.py +10 -2
  306. claude_mpm/services/command_deployment_service.py +44 -26
  307. claude_mpm/services/delegation_detector.py +175 -0
  308. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  309. claude_mpm/services/diagnostics/checks/agent_sources_check.py +31 -1
  310. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  311. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  312. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  313. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  314. claude_mpm/services/diagnostics/models.py +14 -1
  315. claude_mpm/services/event_log.py +325 -0
  316. claude_mpm/services/git/git_operations_service.py +8 -8
  317. claude_mpm/services/hook_installer_service.py +77 -8
  318. claude_mpm/services/infrastructure/__init__.py +4 -0
  319. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  320. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  321. claude_mpm/services/monitor/daemon_manager.py +15 -4
  322. claude_mpm/services/monitor/management/lifecycle.py +15 -3
  323. claude_mpm/services/monitor/server.py +571 -11
  324. claude_mpm/services/pm_skills_deployer.py +884 -0
  325. claude_mpm/services/profile_manager.py +337 -0
  326. claude_mpm/services/skills/git_skill_source_manager.py +281 -20
  327. claude_mpm/services/skills/selective_skill_deployer.py +211 -46
  328. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  329. claude_mpm/services/skills_deployer.py +192 -70
  330. claude_mpm/services/socketio/dashboard_server.py +1 -0
  331. claude_mpm/services/socketio/event_normalizer.py +37 -6
  332. claude_mpm/services/socketio/handlers/hook.py +14 -7
  333. claude_mpm/services/socketio/server/core.py +262 -123
  334. claude_mpm/services/socketio/server/main.py +12 -4
  335. claude_mpm/skills/__init__.py +2 -1
  336. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  337. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  338. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  339. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  340. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  341. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  342. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  343. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  344. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  345. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  346. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  347. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  348. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  349. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  350. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  351. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  352. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  353. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  354. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  355. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  356. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  357. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  358. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  359. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  360. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  361. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  362. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  363. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  364. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  365. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  366. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  367. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  368. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  369. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  370. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  371. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  372. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  373. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  374. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  375. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  376. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  377. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  378. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  379. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  380. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  381. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  382. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  383. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  384. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  385. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  386. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  387. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  388. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  389. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  390. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  391. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  392. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  393. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  394. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  395. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  396. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  397. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  398. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  399. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  400. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  401. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  402. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  403. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  404. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  405. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  406. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  407. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  408. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  409. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  410. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  411. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  412. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  413. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  414. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  415. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  416. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  417. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  418. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  419. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  420. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  421. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  422. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  423. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  424. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  425. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  426. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  427. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  428. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  429. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  430. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  431. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  432. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  433. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  434. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  435. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  436. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  437. claude_mpm/skills/bundled/security-scanning.md +112 -0
  438. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  439. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  440. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  441. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  442. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  443. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  444. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  445. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  446. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  447. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  448. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  449. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  450. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  451. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  452. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  453. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  454. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  455. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  456. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  457. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  458. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  459. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  460. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  461. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  462. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  463. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  464. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  465. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  466. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  467. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  468. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  469. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  470. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  471. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  472. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  473. claude_mpm/skills/registry.py +295 -90
  474. claude_mpm/skills/skill_manager.py +98 -3
  475. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  476. claude_mpm/utils/agent_dependency_loader.py +115 -4
  477. claude_mpm/utils/agent_filters.py +1 -1
  478. claude_mpm/utils/migration.py +4 -4
  479. claude_mpm/utils/robust_installer.py +86 -21
  480. claude_mpm-5.6.34.dist-info/METADATA +393 -0
  481. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/RECORD +486 -145
  482. claude_mpm-5.4.22.dist-info/METADATA +0 -996
  483. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/WHEEL +0 -0
  484. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/entry_points.txt +0 -0
  485. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE +0 -0
  486. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  487. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/top_level.txt +0 -0
@@ -29,7 +29,6 @@ from watchdog.observers import Observer
29
29
 
30
30
  from ...core.enums import ServiceState
31
31
  from ...core.logging_config import get_logger
32
- from ...dashboard.api.simple_directory import list_directory
33
32
  from .event_emitter import get_event_emitter
34
33
  from .handlers.code_analysis import CodeAnalysisHandler
35
34
  from .handlers.dashboard import DashboardHandler
@@ -369,6 +368,83 @@ class UnifiedMonitorServer:
369
368
  finally:
370
369
  await self._cleanup_async()
371
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
+
372
448
  def _setup_event_handlers(self):
373
449
  """Setup Socket.IO event handlers."""
374
450
  try:
@@ -475,7 +551,7 @@ class UnifiedMonitorServer:
475
551
  )
476
552
  if version_file.exists():
477
553
  version = version_file.read_text().strip()
478
- except Exception:
554
+ except Exception: # nosec B110
479
555
  pass
480
556
 
481
557
  return web.json_response(
@@ -500,10 +576,23 @@ class UnifiedMonitorServer:
500
576
  event = data.get("event", "claude_event")
501
577
  event_data = data.get("data", {})
502
578
 
503
- # 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
504
591
  if self.sio:
505
- await self.sio.emit(event, event_data)
506
- 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
+ )
507
596
 
508
597
  return web.Response(status=204) # No content response
509
598
 
@@ -588,6 +677,243 @@ class UnifiedMonitorServer:
588
677
  {"success": False, "error": str(e)}, status=500
589
678
  )
590
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
+
591
917
  # Version endpoint for dashboard build tracker
592
918
  async def version_handler(request):
593
919
  """Serve version information for dashboard build tracker."""
@@ -623,7 +949,7 @@ class UnifiedMonitorServer:
623
949
  # Configuration endpoint for dashboard initialization
624
950
  async def config_handler(request):
625
951
  """Return configuration for dashboard initialization."""
626
- import subprocess
952
+ import subprocess # nosec B404
627
953
 
628
954
  config = {
629
955
  "workingDirectory": Path.cwd(),
@@ -634,7 +960,7 @@ class UnifiedMonitorServer:
634
960
 
635
961
  # Try to get current git branch
636
962
  try:
637
- result = subprocess.run(
963
+ result = subprocess.run( # nosec B603 B607
638
964
  ["git", "branch", "--show-current"],
639
965
  capture_output=True,
640
966
  text=True,
@@ -644,7 +970,7 @@ class UnifiedMonitorServer:
644
970
  )
645
971
  if result.returncode == 0 and result.stdout.strip():
646
972
  config["gitBranch"] = result.stdout.strip()
647
- except Exception:
973
+ except Exception: # nosec B110
648
974
  pass # Keep default "Unknown" value
649
975
 
650
976
  return web.json_response(config)
@@ -653,7 +979,7 @@ class UnifiedMonitorServer:
653
979
  async def working_directory_handler(request):
654
980
  """Return the current working directory."""
655
981
  return web.json_response(
656
- {"working_directory": Path.cwd(), "success": True}
982
+ {"working_directory": str(Path.cwd()), "success": True}
657
983
  )
658
984
 
659
985
  # Monitor page routes
@@ -671,15 +997,249 @@ class UnifiedMonitorServer:
671
997
  return web.Response(text=content, content_type="text/html")
672
998
  return web.Response(text="Page not found", status=404)
673
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
+
674
1230
  # Register routes
675
1231
  self.app.router.add_get("/", dashboard_index)
1232
+ self.app.router.add_get("/favicon.svg", favicon_handler)
676
1233
  self.app.router.add_get("/health", health_check)
677
1234
  self.app.router.add_get("/version.json", version_handler)
678
1235
  self.app.router.add_get("/api/config", config_handler)
679
1236
  self.app.router.add_get("/api/working-directory", working_directory_handler)
680
- 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)
681
1240
  self.app.router.add_post("/api/events", api_events_handler)
682
1241
  self.app.router.add_post("/api/file", api_file_handler)
1242
+ self.app.router.add_post("/api/git-history", git_history_handler)
683
1243
 
684
1244
  # Monitor page routes
685
1245
  self.app.router.add_get("/monitor", lambda r: monitor_page_handler(r))
@@ -999,7 +1559,7 @@ class UnifiedMonitorServer:
999
1559
  gather = asyncio.gather(*tasks_to_cancel, return_exceptions=True)
1000
1560
  try:
1001
1561
  loop.run_until_complete(gather)
1002
- except Exception:
1562
+ except Exception: # nosec B110
1003
1563
  # Some tasks might fail to cancel, that's ok
1004
1564
  pass
1005
1565