claude-mpm 5.4.65__py3-none-any.whl → 5.6.10__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 (313) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
  3. claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
  4. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +107 -1928
  5. claude_mpm/agents/PM_INSTRUCTIONS.md +119 -689
  6. claude_mpm/agents/WORKFLOW.md +2 -0
  7. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  8. claude_mpm/cli/__init__.py +5 -1
  9. claude_mpm/cli/commands/agents.py +2 -4
  10. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  11. claude_mpm/cli/commands/autotodos.py +566 -0
  12. claude_mpm/cli/commands/commander.py +46 -0
  13. claude_mpm/cli/commands/configure.py +620 -21
  14. claude_mpm/cli/commands/hook_errors.py +60 -60
  15. claude_mpm/cli/commands/monitor.py +2 -2
  16. claude_mpm/cli/commands/mpm_init/core.py +2 -2
  17. claude_mpm/cli/commands/run.py +35 -3
  18. claude_mpm/cli/commands/skill_source.py +51 -2
  19. claude_mpm/cli/commands/skills.py +171 -17
  20. claude_mpm/cli/executor.py +120 -16
  21. claude_mpm/cli/interactive/__init__.py +10 -0
  22. claude_mpm/cli/interactive/agent_wizard.py +30 -50
  23. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  24. claude_mpm/cli/interactive/skill_selector.py +481 -0
  25. claude_mpm/cli/parsers/base_parser.py +76 -1
  26. claude_mpm/cli/parsers/commander_parser.py +83 -0
  27. claude_mpm/cli/parsers/run_parser.py +10 -0
  28. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  29. claude_mpm/cli/parsers/skills_parser.py +5 -0
  30. claude_mpm/cli/startup.py +203 -359
  31. claude_mpm/cli/startup_display.py +72 -5
  32. claude_mpm/cli/startup_logging.py +2 -2
  33. claude_mpm/cli/utils.py +7 -3
  34. claude_mpm/commander/__init__.py +72 -0
  35. claude_mpm/commander/adapters/__init__.py +31 -0
  36. claude_mpm/commander/adapters/base.py +191 -0
  37. claude_mpm/commander/adapters/claude_code.py +361 -0
  38. claude_mpm/commander/adapters/communication.py +366 -0
  39. claude_mpm/commander/api/__init__.py +16 -0
  40. claude_mpm/commander/api/app.py +105 -0
  41. claude_mpm/commander/api/errors.py +133 -0
  42. claude_mpm/commander/api/routes/__init__.py +8 -0
  43. claude_mpm/commander/api/routes/events.py +184 -0
  44. claude_mpm/commander/api/routes/inbox.py +171 -0
  45. claude_mpm/commander/api/routes/messages.py +148 -0
  46. claude_mpm/commander/api/routes/projects.py +271 -0
  47. claude_mpm/commander/api/routes/sessions.py +228 -0
  48. claude_mpm/commander/api/routes/work.py +260 -0
  49. claude_mpm/commander/api/schemas.py +182 -0
  50. claude_mpm/commander/chat/__init__.py +7 -0
  51. claude_mpm/commander/chat/cli.py +107 -0
  52. claude_mpm/commander/chat/commands.py +96 -0
  53. claude_mpm/commander/chat/repl.py +310 -0
  54. claude_mpm/commander/config.py +49 -0
  55. claude_mpm/commander/config_loader.py +115 -0
  56. claude_mpm/commander/daemon.py +398 -0
  57. claude_mpm/commander/events/__init__.py +26 -0
  58. claude_mpm/commander/events/manager.py +332 -0
  59. claude_mpm/commander/frameworks/__init__.py +12 -0
  60. claude_mpm/commander/frameworks/base.py +143 -0
  61. claude_mpm/commander/frameworks/claude_code.py +58 -0
  62. claude_mpm/commander/frameworks/mpm.py +62 -0
  63. claude_mpm/commander/inbox/__init__.py +16 -0
  64. claude_mpm/commander/inbox/dedup.py +128 -0
  65. claude_mpm/commander/inbox/inbox.py +224 -0
  66. claude_mpm/commander/inbox/models.py +70 -0
  67. claude_mpm/commander/instance_manager.py +337 -0
  68. claude_mpm/commander/llm/__init__.py +6 -0
  69. claude_mpm/commander/llm/openrouter_client.py +167 -0
  70. claude_mpm/commander/llm/summarizer.py +70 -0
  71. claude_mpm/commander/models/__init__.py +18 -0
  72. claude_mpm/commander/models/events.py +121 -0
  73. claude_mpm/commander/models/project.py +162 -0
  74. claude_mpm/commander/models/work.py +214 -0
  75. claude_mpm/commander/parsing/__init__.py +20 -0
  76. claude_mpm/commander/parsing/extractor.py +132 -0
  77. claude_mpm/commander/parsing/output_parser.py +270 -0
  78. claude_mpm/commander/parsing/patterns.py +100 -0
  79. claude_mpm/commander/persistence/__init__.py +11 -0
  80. claude_mpm/commander/persistence/event_store.py +274 -0
  81. claude_mpm/commander/persistence/state_store.py +309 -0
  82. claude_mpm/commander/persistence/work_store.py +164 -0
  83. claude_mpm/commander/polling/__init__.py +13 -0
  84. claude_mpm/commander/polling/event_detector.py +104 -0
  85. claude_mpm/commander/polling/output_buffer.py +49 -0
  86. claude_mpm/commander/polling/output_poller.py +153 -0
  87. claude_mpm/commander/project_session.py +268 -0
  88. claude_mpm/commander/proxy/__init__.py +12 -0
  89. claude_mpm/commander/proxy/formatter.py +89 -0
  90. claude_mpm/commander/proxy/output_handler.py +191 -0
  91. claude_mpm/commander/proxy/relay.py +155 -0
  92. claude_mpm/commander/registry.py +404 -0
  93. claude_mpm/commander/runtime/__init__.py +10 -0
  94. claude_mpm/commander/runtime/executor.py +191 -0
  95. claude_mpm/commander/runtime/monitor.py +316 -0
  96. claude_mpm/commander/session/__init__.py +6 -0
  97. claude_mpm/commander/session/context.py +81 -0
  98. claude_mpm/commander/session/manager.py +59 -0
  99. claude_mpm/commander/tmux_orchestrator.py +361 -0
  100. claude_mpm/commander/web/__init__.py +1 -0
  101. claude_mpm/commander/work/__init__.py +30 -0
  102. claude_mpm/commander/work/executor.py +189 -0
  103. claude_mpm/commander/work/queue.py +405 -0
  104. claude_mpm/commander/workflow/__init__.py +27 -0
  105. claude_mpm/commander/workflow/event_handler.py +219 -0
  106. claude_mpm/commander/workflow/notifier.py +146 -0
  107. claude_mpm/commands/mpm-config.md +8 -0
  108. claude_mpm/commands/mpm-doctor.md +8 -0
  109. claude_mpm/commands/mpm-help.md +8 -0
  110. claude_mpm/commands/mpm-init.md +8 -0
  111. claude_mpm/commands/mpm-monitor.md +8 -0
  112. claude_mpm/commands/mpm-organize.md +8 -0
  113. claude_mpm/commands/mpm-postmortem.md +8 -0
  114. claude_mpm/commands/mpm-session-resume.md +9 -1
  115. claude_mpm/commands/mpm-status.md +8 -0
  116. claude_mpm/commands/mpm-ticket-view.md +8 -0
  117. claude_mpm/commands/mpm-version.md +8 -0
  118. claude_mpm/commands/mpm.md +8 -0
  119. claude_mpm/config/agent_presets.py +8 -7
  120. claude_mpm/config/skill_sources.py +16 -0
  121. claude_mpm/constants.py +1 -0
  122. claude_mpm/core/claude_runner.py +2 -2
  123. claude_mpm/core/config.py +32 -19
  124. claude_mpm/core/hook_manager.py +51 -3
  125. claude_mpm/core/interactive_session.py +7 -7
  126. claude_mpm/core/logger.py +26 -9
  127. claude_mpm/core/logging_utils.py +35 -11
  128. claude_mpm/core/output_style_manager.py +31 -13
  129. claude_mpm/core/unified_config.py +54 -8
  130. claude_mpm/core/unified_paths.py +95 -90
  131. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  132. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  133. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cs_tUR18.js → 1WZnGYqX.js} +1 -1
  134. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CDuw-vjf.js → 67pF3qNn.js} +1 -1
  135. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bTOqqlTd.js → 6RxdMKe4.js} +1 -1
  136. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DwBR2MJi.js → 8cZrfX0h.js} +1 -1
  137. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{ZGh7QtNv.js → 9a6T2nm-.js} +1 -1
  138. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D9lljYKQ.js → B443AUzu.js} +1 -1
  139. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{RJiighC3.js → B8AwtY2H.js} +1 -1
  140. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uuIeMWc-.js → BF15LAsF.js} +1 -1
  141. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{D3k0OPJN.js → BRcwIQNr.js} +1 -1
  142. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CyWMqx4W.js → BV6nKitt.js} +1 -1
  143. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CiIAseT4.js → BViJ8lZt.js} +5 -5
  144. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CBBdVcY8.js → BcQ-Q0FE.js} +1 -1
  145. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BovzEFCE.js → Bpyvgze_.js} +1 -1
  146. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  147. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  148. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{eNVUfhuA.js → C3rbW_a-.js} +1 -1
  149. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{GYwsonyD.js → C8WYN38h.js} +1 -1
  150. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BIF9m_hv.js → C9I8FlXH.js} +1 -1
  151. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B0uc0UOD.js → CIQcWgO2.js} +3 -3
  152. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Be7GpZd6.js → CIctN7YN.js} +1 -1
  153. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Bh0LDWpI.js → CKrS_JZW.js} +2 -2
  154. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DUrLdbGD.js → CR6P9C4A.js} +1 -1
  155. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7xVLGWV.js → CRRR9MD_.js} +1 -1
  156. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  157. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dhb8PKl3.js → CSXtMOf0.js} +1 -1
  158. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BPYeabCQ.js → CT-sbxSk.js} +1 -1
  159. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{sQeU3Y1z.js → CWm6DJsp.js} +1 -1
  160. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CnA0NrzZ.js → CpqQ1Kzn.js} +1 -1
  161. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4B-KCzX.js → D2nGpDRe.js} +1 -1
  162. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DGkLK5U1.js → D9iCMida.js} +1 -1
  163. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{BofRWZRR.js → D9ykgMoY.js} +1 -1
  164. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DmxopI1J.js → DL2Ldur1.js} +1 -1
  165. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C30mlcqg.js → DPfltzjH.js} +1 -1
  166. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Vzk33B_K.js → DR8nis88.js} +2 -2
  167. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DI7hHRFL.js → DUliQN2b.js} +1 -1
  168. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C4JcI4KD.js → DXlhR01x.js} +1 -1
  169. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{bT1r9zLR.js → D_lyTybS.js} +1 -1
  170. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DZX00Y4g.js → DngoTTgh.js} +1 -1
  171. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzZX-COe.js → DqkmHtDC.js} +1 -1
  172. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{B7RN905-.js → DsDh8EYs.js} +1 -1
  173. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DLVjFsZ3.js → DypDmXgd.js} +1 -1
  174. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{iEWssX7S.js → IPYC-LnN.js} +1 -1
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DaimHw_p.js → JpevfAFt.js} +1 -1
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DY1XQ8fi.js → R8CEIRAd.js} +1 -1
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Dle-35c7.js → Zxy7qc-l.js} +2 -2
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{C_Usid8X.js → qtd3IeO4.js} +2 -2
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CzeYkLYB.js → ulBFON_C.js} +2 -2
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{Cfqx1Qun.js → wQVh1CoA.js} +1 -1
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/{app.D6-I5TpK.js → app.Dr7t0z2J.js} +2 -2
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.m1gL8KXf.js → 0.RgBboRvH.js} +1 -1
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{1.CgNOuw-d.js → 1.DG-KkbDf.js} +1 -1
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  188. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
  189. claude_mpm/dashboard/static/svelte-build/index.html +9 -9
  190. claude_mpm/experimental/cli_enhancements.py +2 -1
  191. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  192. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  193. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-314.pyc +0 -0
  194. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  195. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-312.pyc +0 -0
  196. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-314.pyc +0 -0
  197. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  198. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc +0 -0
  199. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-314.pyc +0 -0
  200. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  201. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc +0 -0
  202. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-314.pyc +0 -0
  203. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  204. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc +0 -0
  205. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  206. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc +0 -0
  207. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-314.pyc +0 -0
  208. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  209. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc +0 -0
  210. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-314.pyc +0 -0
  211. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-314.pyc +0 -0
  212. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  213. claude_mpm/hooks/claude_hooks/event_handlers.py +283 -87
  214. claude_mpm/hooks/claude_hooks/hook_handler.py +106 -89
  215. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  216. claude_mpm/hooks/claude_hooks/installer.py +116 -8
  217. claude_mpm/hooks/claude_hooks/memory_integration.py +51 -31
  218. claude_mpm/hooks/claude_hooks/response_tracking.py +42 -59
  219. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-314.pyc +0 -0
  220. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  221. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-312.pyc +0 -0
  222. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-314.pyc +0 -0
  223. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-314.pyc +0 -0
  224. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  225. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc +0 -0
  226. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc +0 -0
  227. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  228. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc +0 -0
  229. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-314.pyc +0 -0
  230. claude_mpm/hooks/claude_hooks/services/connection_manager.py +39 -24
  231. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +36 -103
  232. claude_mpm/hooks/claude_hooks/services/state_manager.py +23 -36
  233. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +73 -75
  234. claude_mpm/hooks/session_resume_hook.py +89 -1
  235. claude_mpm/hooks/templates/pre_tool_use_template.py +10 -2
  236. claude_mpm/init.py +1 -1
  237. claude_mpm/scripts/claude-hook-handler.sh +43 -16
  238. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  239. claude_mpm/services/agents/agent_selection_service.py +2 -2
  240. claude_mpm/services/agents/cache_git_manager.py +1 -1
  241. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  242. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +3 -0
  243. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  244. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  245. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  246. claude_mpm/services/agents/startup_sync.py +5 -2
  247. claude_mpm/services/cli/__init__.py +3 -0
  248. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  249. claude_mpm/services/cli/session_resume_helper.py +10 -2
  250. claude_mpm/services/delegation_detector.py +175 -0
  251. claude_mpm/services/diagnostics/checks/agent_sources_check.py +30 -0
  252. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  253. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  254. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  255. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  256. claude_mpm/services/diagnostics/models.py +14 -1
  257. claude_mpm/services/event_log.py +325 -0
  258. claude_mpm/services/infrastructure/__init__.py +4 -0
  259. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  260. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  261. claude_mpm/services/monitor/daemon_manager.py +15 -4
  262. claude_mpm/services/monitor/management/lifecycle.py +8 -2
  263. claude_mpm/services/monitor/server.py +106 -16
  264. claude_mpm/services/pm_skills_deployer.py +259 -87
  265. claude_mpm/services/skills/git_skill_source_manager.py +135 -11
  266. claude_mpm/services/skills/selective_skill_deployer.py +142 -26
  267. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  268. claude_mpm/services/skills_deployer.py +31 -5
  269. claude_mpm/services/socketio/handlers/hook.py +14 -7
  270. claude_mpm/services/socketio/server/main.py +12 -4
  271. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  272. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  273. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  274. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  275. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  276. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  277. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  278. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  279. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  280. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  281. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  282. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  283. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  284. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  285. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  286. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  287. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  288. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  289. claude_mpm/skills/skill_manager.py +4 -4
  290. claude_mpm/utils/agent_dependency_loader.py +4 -2
  291. claude_mpm/utils/robust_installer.py +10 -6
  292. claude_mpm-5.6.10.dist-info/METADATA +391 -0
  293. {claude_mpm-5.4.65.dist-info → claude_mpm-5.6.10.dist-info}/RECORD +303 -181
  294. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +0 -1
  295. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +0 -1
  296. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +0 -1
  297. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +0 -24
  298. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +0 -1
  299. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +0 -1
  300. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +0 -323
  301. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +0 -1
  302. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +0 -1
  303. claude_mpm-5.4.65.dist-info/METADATA +0 -999
  304. /claude_mpm/skills/bundled/pm/{pm-delegation-patterns → mpm-delegation-patterns}/SKILL.md +0 -0
  305. /claude_mpm/skills/bundled/pm/{pm-git-file-tracking → mpm-git-file-tracking}/SKILL.md +0 -0
  306. /claude_mpm/skills/bundled/pm/{pm-pr-workflow → mpm-pr-workflow}/SKILL.md +0 -0
  307. /claude_mpm/skills/bundled/pm/{pm-ticketing-integration → mpm-ticketing-integration}/SKILL.md +0 -0
  308. /claude_mpm/skills/bundled/pm/{pm-verification-protocols → mpm-verification-protocols}/SKILL.md +0 -0
  309. {claude_mpm-5.4.65.dist-info → claude_mpm-5.6.10.dist-info}/WHEEL +0 -0
  310. {claude_mpm-5.4.65.dist-info → claude_mpm-5.6.10.dist-info}/entry_points.txt +0 -0
  311. {claude_mpm-5.4.65.dist-info → claude_mpm-5.6.10.dist-info}/licenses/LICENSE +0 -0
  312. {claude_mpm-5.4.65.dist-info → claude_mpm-5.6.10.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  313. {claude_mpm-5.4.65.dist-info → claude_mpm-5.6.10.dist-info}/top_level.txt +0 -0
@@ -66,6 +66,7 @@ def ensure_run_attributes(args):
66
66
  args.monitor = getattr(args, "monitor", False)
67
67
  args.force = getattr(args, "force", False)
68
68
  args.reload_agents = getattr(args, "reload_agents", False)
69
+ args.force_sync = getattr(args, "force_sync", False)
69
70
  # Include dependency checking attributes
70
71
  args.check_dependencies = getattr(args, "check_dependencies", True)
71
72
  args.force_check_dependencies = getattr(args, "force_check_dependencies", False)
@@ -126,6 +127,14 @@ def execute_command(command: str, args) -> int:
126
127
  result = handle_verify(args)
127
128
  return result if result is not None else 0
128
129
 
130
+ # Handle commander command with lazy import
131
+ if command == "commander":
132
+ # Lazy import to avoid loading unless needed
133
+ from .commands.commander import handle_commander_command
134
+
135
+ result = handle_commander_command(args)
136
+ return result if result is not None else 0
137
+
129
138
  # Handle skill-source command with lazy import
130
139
  if command == "skill-source":
131
140
  # Lazy import to avoid loading unless needed
@@ -205,35 +214,127 @@ def execute_command(command: str, args) -> int:
205
214
  "status": show_status,
206
215
  }
207
216
 
208
- # Get handler and invoke
217
+ # Get handler and call it with argument list (same pattern as autotodos)
209
218
  handler = handlers.get(subcommand)
210
219
  if handler:
211
- # Build Click context programmatically
212
- import click
220
+ try:
221
+ # Build argument list for Click command based on subcommand
222
+ click_args = []
223
+
224
+ # list command: --format, --hook-type
225
+ if subcommand == "list":
226
+ if hasattr(args, "format") and args.format:
227
+ click_args.extend(["--format", args.format])
228
+ if hasattr(args, "hook_type") and args.hook_type:
229
+ click_args.extend(["--hook-type", args.hook_type])
230
+ # clear command: --hook-type, -y
231
+ elif subcommand == "clear":
232
+ if hasattr(args, "hook_type") and args.hook_type:
233
+ click_args.extend(["--hook-type", args.hook_type])
234
+ if hasattr(args, "yes") and args.yes:
235
+ click_args.append("-y")
236
+ # diagnose command: hook_type (positional argument)
237
+ elif subcommand == "diagnose":
238
+ if hasattr(args, "hook_type") and args.hook_type:
239
+ click_args.append(args.hook_type)
240
+ # status and summary commands: no options
241
+
242
+ # Call Click command with argument list and standalone_mode=False
243
+ handler(click_args, standalone_mode=False)
244
+ return 0
245
+ except SystemExit as e:
246
+ return e.code if e.code is not None else 0
247
+ except Exception as e:
248
+ print(f"Error: {e}")
249
+ return 1
250
+ else:
251
+ print(f"Unknown hook-errors subcommand: {subcommand}")
252
+ return 1
213
253
 
214
- ctx = click.Context(command=handler)
254
+ # Handle autotodos command with lazy import
255
+ if command == "autotodos":
256
+ # Lazy import to avoid loading unless needed
257
+ from .commands.autotodos import (
258
+ clear_autotodos,
259
+ inject_autotodos,
260
+ list_autotodos,
261
+ list_pm_violations,
262
+ scan_delegation_patterns,
263
+ show_autotodos_status,
264
+ )
215
265
 
216
- # Prepare keyword arguments from args
217
- kwargs = {}
218
- if hasattr(args, "format"):
219
- kwargs["format"] = args.format
220
- if hasattr(args, "hook_type"):
221
- kwargs["hook_type"] = args.hook_type
222
- if hasattr(args, "yes"):
223
- kwargs["yes"] = args.yes
266
+ # Get subcommand
267
+ subcommand = getattr(args, "autotodos_command", "status")
268
+ if not subcommand:
269
+ subcommand = "status"
224
270
 
271
+ # Map subcommands to functions
272
+ handlers = {
273
+ "list": list_autotodos,
274
+ "inject": inject_autotodos,
275
+ "clear": clear_autotodos,
276
+ "status": show_autotodos_status,
277
+ "scan": scan_delegation_patterns,
278
+ "violations": list_pm_violations,
279
+ }
280
+
281
+ # Get handler and call it with standalone_mode=False
282
+ handler = handlers.get(subcommand)
283
+ if handler:
225
284
  try:
226
- # Invoke handler with arguments
227
- with ctx:
228
- handler.invoke(ctx, **kwargs)
285
+ # Build argument list for Click command
286
+ click_args = []
287
+
288
+ if subcommand == "list":
289
+ fmt = getattr(args, "format", "table")
290
+ click_args = ["--format", fmt]
291
+ elif subcommand == "inject":
292
+ output = getattr(args, "output", None)
293
+ if output:
294
+ click_args = ["--output", output]
295
+ elif subcommand == "clear":
296
+ error_key = getattr(args, "error_key", None)
297
+ event_type = getattr(args, "event_type", "all")
298
+ if error_key:
299
+ click_args.append("--error-key")
300
+ click_args.append(error_key)
301
+ if event_type != "all":
302
+ click_args.append("--event-type")
303
+ click_args.append(event_type)
304
+ if getattr(args, "yes", False):
305
+ click_args.append("-y")
306
+ elif subcommand == "scan":
307
+ text = getattr(args, "text", None)
308
+ file = getattr(args, "file", None)
309
+ fmt = getattr(args, "format", "table")
310
+ save = getattr(args, "save", False)
311
+
312
+ if text:
313
+ click_args.append(text)
314
+ if file:
315
+ click_args.extend(["--file", file])
316
+ if fmt != "table":
317
+ click_args.extend(["--format", fmt])
318
+ if save:
319
+ click_args.append("--save")
320
+ elif subcommand == "violations":
321
+ fmt = getattr(args, "format", "table")
322
+ if fmt != "table":
323
+ click_args.extend(["--format", fmt])
324
+
325
+ # Call Click command with argument list and standalone_mode=False
326
+ handler(click_args, standalone_mode=False)
229
327
  return 0
230
328
  except SystemExit as e:
231
329
  return e.code if e.code is not None else 0
232
330
  except Exception as e:
233
331
  print(f"Error: {e}")
332
+ import traceback
333
+
334
+ traceback.print_exc()
234
335
  return 1
235
336
  else:
236
- print(f"Unknown hook-errors subcommand: {subcommand}")
337
+ print(f"Unknown autotodos subcommand: {subcommand}")
237
338
  return 1
238
339
 
239
340
  # Map stable commands to their implementations
@@ -259,6 +360,7 @@ def execute_command(command: str, args) -> int:
259
360
  CLICommands.SKILLS.value: manage_skills,
260
361
  "debug": manage_debug, # Add debug command
261
362
  "mpm-init": None, # Will be handled separately with lazy import
363
+ "commander": None, # Will be handled separately with lazy import
262
364
  }
263
365
 
264
366
  # Execute command if found
@@ -286,6 +388,8 @@ def execute_command(command: str, args) -> int:
286
388
  "local-deploy",
287
389
  "skill-source",
288
390
  "agent-source",
391
+ "hook-errors",
392
+ "autotodos",
289
393
  ]
290
394
 
291
395
  suggestion = suggest_similar_commands(command, all_commands)
@@ -10,12 +10,22 @@ from .agent_wizard import (
10
10
  run_interactive_agent_manager,
11
11
  run_interactive_agent_wizard,
12
12
  )
13
+ from .questionary_styles import (
14
+ BANNER_WIDTH,
15
+ MPM_STYLE,
16
+ print_banner,
17
+ print_section_header,
18
+ )
13
19
  from .skills_wizard import SkillsWizard, discover_and_link_runtime_skills
14
20
 
15
21
  __all__ = [
22
+ "BANNER_WIDTH",
23
+ "MPM_STYLE",
16
24
  "AgentWizard",
17
25
  "SkillsWizard",
18
26
  "discover_and_link_runtime_skills",
27
+ "print_banner",
28
+ "print_section_header",
19
29
  "run_interactive_agent_manager",
20
30
  "run_interactive_agent_wizard",
21
31
  ]
@@ -12,8 +12,12 @@ from pathlib import Path
12
12
  from typing import Any, Dict, List, Optional, Tuple
13
13
 
14
14
  import questionary
15
- from questionary import Style
16
15
 
16
+ from claude_mpm.cli.interactive.questionary_styles import (
17
+ BANNER_WIDTH,
18
+ MPM_STYLE,
19
+ print_section_header,
20
+ )
17
21
  from claude_mpm.core.logging_config import get_logger
18
22
  from claude_mpm.services.agents.local_template_manager import (
19
23
  LocalAgentTemplate,
@@ -23,16 +27,6 @@ from claude_mpm.utils.agent_filters import apply_all_filters
23
27
 
24
28
  logger = get_logger(__name__)
25
29
 
26
- # Questionary style matching Rich cyan theme (consistent with configure.py)
27
- QUESTIONARY_STYLE = Style(
28
- [
29
- ("selected", "fg:cyan bold"),
30
- ("pointer", "fg:cyan bold"),
31
- ("highlighted", "fg:cyan"),
32
- ("question", "fg:cyan bold"),
33
- ]
34
- )
35
-
36
30
 
37
31
  class AgentWizard:
38
32
  """
@@ -113,9 +107,7 @@ class AgentWizard:
113
107
  Tuple of (success, message)
114
108
  """
115
109
  try:
116
- print("\n" + "=" * 60)
117
- print("🧙‍♂️ Agent Creation Wizard")
118
- print("=" * 60)
110
+ print_section_header("🧙‍♂️", "Agent Creation Wizard", width=BANNER_WIDTH)
119
111
  print("\nI'll guide you through creating a custom local agent.")
120
112
  print("Press Ctrl+C anytime to cancel.\n")
121
113
 
@@ -281,9 +273,7 @@ class AgentWizard:
281
273
  # Get merged agents from all sources
282
274
  all_agents = self._merge_agent_sources()
283
275
 
284
- print("\n" + "=" * 60)
285
- print("🔧 Agent Management Menu")
286
- print("=" * 60)
276
+ print_section_header("🔧", "Agent Management Menu", width=BANNER_WIDTH)
287
277
 
288
278
  if not all_agents:
289
279
  print(
@@ -384,7 +374,7 @@ class AgentWizard:
384
374
  choice = questionary.select(
385
375
  "Agent Management Menu:",
386
376
  choices=menu_choices,
387
- style=QUESTIONARY_STYLE,
377
+ style=MPM_STYLE,
388
378
  ).ask()
389
379
 
390
380
  if not choice: # User pressed Esc
@@ -776,9 +766,7 @@ class AgentWizard:
776
766
 
777
767
  def _confirm_creation(self, config: Dict[str, Any]) -> bool:
778
768
  """Show preview and get confirmation from user."""
779
- print("\n" + "=" * 60)
780
- print("📋 Agent Configuration Preview")
781
- print("=" * 60)
769
+ print_section_header("📋", "Agent Configuration Preview", width=BANNER_WIDTH)
782
770
 
783
771
  print(f"Agent ID: {config['agent_id']}")
784
772
  print(f"Name: {config['name']}")
@@ -795,7 +783,8 @@ class AgentWizard:
795
783
  print("\nInstructions Preview:")
796
784
  print(f" {config['instructions_preview']}")
797
785
 
798
- print("\n" + "=" * 60)
786
+ print()
787
+ print("=" * BANNER_WIDTH)
799
788
 
800
789
  while True:
801
790
  confirm = input("\nCreate this agent? [Y/n]: ").strip().lower()
@@ -1046,8 +1035,7 @@ class AgentWizard:
1046
1035
 
1047
1036
  def _interactive_delete_menu(self, templates: list) -> Tuple[bool, str]:
1048
1037
  """Interactive deletion menu for multiple agents."""
1049
- print("\n🗑️ Delete Agents")
1050
- print("=" * 50)
1038
+ print_section_header("🗑️", "Delete Agents", width=BANNER_WIDTH)
1051
1039
 
1052
1040
  if not templates:
1053
1041
  return False, "No agents available to delete"
@@ -1154,9 +1142,9 @@ class AgentWizard:
1154
1142
  Args:
1155
1143
  agent: Agent metadata dictionary
1156
1144
  """
1157
- print("\n" + "=" * 60)
1158
- print(f"📄 Agent Details: {agent['agent_id']}")
1159
- print("=" * 60)
1145
+ print_section_header(
1146
+ "📄", f"Agent Details: {agent['agent_id']}", width=BANNER_WIDTH
1147
+ )
1160
1148
  print(f"Name: {agent['name']}")
1161
1149
  print(f"Category: {agent['category'] or 'N/A'}")
1162
1150
  print(f"Source: [{agent['source_type']}] {agent['source_identifier']}")
@@ -1188,9 +1176,7 @@ class AgentWizard:
1188
1176
  input("\nPress Enter to continue...")
1189
1177
  return
1190
1178
 
1191
- print("\n" + "=" * 60)
1192
- print("📦 Deploy Agent")
1193
- print("=" * 60)
1179
+ print_section_header("📦", "Deploy Agent", width=BANNER_WIDTH)
1194
1180
  print(f"\n{len(deployable)} agent(s) available to deploy:\n")
1195
1181
 
1196
1182
  # Build agent selection choices with arrow-key navigation
@@ -1200,7 +1186,7 @@ class AgentWizard:
1200
1186
  ]
1201
1187
 
1202
1188
  choice = questionary.select(
1203
- "Select agent to deploy:", choices=agent_choices, style=QUESTIONARY_STYLE
1189
+ "Select agent to deploy:", choices=agent_choices, style=MPM_STYLE
1204
1190
  ).ask()
1205
1191
 
1206
1192
  if not choice: # User pressed Esc
@@ -1296,9 +1282,7 @@ class AgentWizard:
1296
1282
  return
1297
1283
 
1298
1284
  while True:
1299
- print("\n" + "=" * 60)
1300
- print("🔍 Browse & Filter Agents")
1301
- print("=" * 60)
1285
+ print_section_header("🔍", "Browse & Filter Agents", width=BANNER_WIDTH)
1302
1286
 
1303
1287
  # Show filter menu with arrow-key navigation
1304
1288
  print("\n[bold]Filter by:[/bold]")
@@ -1314,7 +1298,7 @@ class AgentWizard:
1314
1298
  choice = questionary.select(
1315
1299
  "Browse & Filter Agents:",
1316
1300
  choices=filter_choices,
1317
- style=QUESTIONARY_STYLE,
1301
+ style=MPM_STYLE,
1318
1302
  ).ask()
1319
1303
 
1320
1304
  if not choice or "Back" in choice:
@@ -1343,7 +1327,7 @@ class AgentWizard:
1343
1327
  cat_choices = [f"{idx}. {cat}" for idx, cat in enumerate(categories, 1)]
1344
1328
 
1345
1329
  cat_choice = questionary.select(
1346
- "Select category:", choices=cat_choices, style=QUESTIONARY_STYLE
1330
+ "Select category:", choices=cat_choices, style=MPM_STYLE
1347
1331
  ).ask()
1348
1332
 
1349
1333
  if not cat_choice: # User pressed Esc
@@ -1457,9 +1441,11 @@ class AgentWizard:
1457
1441
  continue
1458
1442
 
1459
1443
  # Display filtered results
1460
- print("\n" + "=" * 60)
1461
- print(f"📋 {filter_description} ({len(filtered_agents)} agents)")
1462
- print("=" * 60)
1444
+ print_section_header(
1445
+ "📋",
1446
+ f"{filter_description} ({len(filtered_agents)} agents)",
1447
+ width=BANNER_WIDTH,
1448
+ )
1463
1449
 
1464
1450
  if not filtered_agents:
1465
1451
  print("\n[yellow]No agents found matching filter[/yellow]")
@@ -1523,7 +1509,7 @@ class AgentWizard:
1523
1509
  ]
1524
1510
 
1525
1511
  agent_choice = questionary.select(
1526
- "Select agent to deploy:", choices=agent_choices, style=QUESTIONARY_STYLE
1512
+ "Select agent to deploy:", choices=agent_choices, style=MPM_STYLE
1527
1513
  ).ask()
1528
1514
 
1529
1515
  if not agent_choice: # User pressed Esc
@@ -1629,7 +1615,7 @@ class AgentWizard:
1629
1615
  ]
1630
1616
 
1631
1617
  agent_choice = questionary.select(
1632
- "Select agent to view:", choices=agent_choices, style=QUESTIONARY_STYLE
1618
+ "Select agent to view:", choices=agent_choices, style=MPM_STYLE
1633
1619
  ).ask()
1634
1620
 
1635
1621
  if not agent_choice: # User pressed Esc
@@ -1652,9 +1638,7 @@ class AgentWizard:
1652
1638
  preset_service = AgentPresetService(self.source_manager)
1653
1639
 
1654
1640
  while True:
1655
- print("\n" + "=" * 60)
1656
- print("📦 Deploy Agent Preset")
1657
- print("=" * 60)
1641
+ print_section_header("📦", "Deploy Agent Preset", width=BANNER_WIDTH)
1658
1642
 
1659
1643
  # List available presets
1660
1644
  presets = preset_service.list_presets()
@@ -1690,9 +1674,7 @@ class AgentWizard:
1690
1674
  preset_name = presets[idx]["name"]
1691
1675
 
1692
1676
  # Show preset details
1693
- print("\n" + "=" * 60)
1694
- print(f"📦 Preset: {preset_name}")
1695
- print("=" * 60)
1677
+ print_section_header("📦", f"Preset: {preset_name}", width=BANNER_WIDTH)
1696
1678
  print(f"\n[bold]Description:[/bold] {presets[idx]['description']}\n")
1697
1679
 
1698
1680
  # Resolve preset
@@ -1872,9 +1854,7 @@ class AgentWizard:
1872
1854
  input("\nPress Enter to continue...")
1873
1855
  return
1874
1856
 
1875
- print("\n" + "=" * 60)
1876
- print("🔗 Manage Agent Sources")
1877
- print("=" * 60)
1857
+ print_section_header("🔗", "Manage Agent Sources", width=BANNER_WIDTH)
1878
1858
 
1879
1859
  try:
1880
1860
  from claude_mpm.config.agent_sources import AgentSourceConfiguration
@@ -0,0 +1,65 @@
1
+ """Shared questionary styles for consistent TUI across Claude MPM.
2
+
3
+ This module provides unified styling for all interactive questionary interfaces
4
+ to ensure visual consistency across agent wizard, skill selector, and other TUI components.
5
+ """
6
+
7
+ from questionary import Style
8
+
9
+ # Standard cyan-themed style for all selectors
10
+ # Matches the pattern used in agent_wizard.py and skill_selector.py
11
+ MPM_STYLE = Style(
12
+ [
13
+ ("qmark", "fg:cyan bold"),
14
+ ("question", "bold"),
15
+ ("answer", "fg:cyan"),
16
+ ("pointer", "fg:cyan bold"),
17
+ ("highlighted", "fg:cyan bold"),
18
+ ("selected", "fg:cyan"),
19
+ ]
20
+ )
21
+
22
+ # Banner constants for consistent formatting
23
+ BANNER_WIDTH = 60
24
+ BANNER_CHAR = "="
25
+
26
+
27
+ def print_banner(title: str, width: int = BANNER_WIDTH) -> None:
28
+ """Print a styled banner matching agent selector format.
29
+
30
+ Args:
31
+ title: Title text to display in the banner
32
+ width: Total width of the banner in characters (default: 60)
33
+
34
+ Example:
35
+ >>> print_banner("Agent Creation Wizard")
36
+ ============================================================
37
+ Agent Creation Wizard
38
+ ============================================================
39
+ """
40
+ print()
41
+ print(BANNER_CHAR * width)
42
+ print(f"{title:^{width}}")
43
+ print(BANNER_CHAR * width)
44
+ print()
45
+
46
+
47
+ def print_section_header(emoji: str, title: str, width: int = BANNER_WIDTH) -> None:
48
+ """Print a section header with emoji and title.
49
+
50
+ Args:
51
+ emoji: Emoji to display before the title
52
+ title: Section title text
53
+ width: Total width of the header line (default: 60)
54
+
55
+ Example:
56
+ >>> print_section_header("🔧", "Agent Management Menu")
57
+
58
+ ============================================================
59
+ 🔧 Agent Management Menu
60
+ ============================================================
61
+ """
62
+ print()
63
+ print(BANNER_CHAR * width)
64
+ print(f"{emoji} {title}")
65
+ print(BANNER_CHAR * width)