claude-mpm 3.4.10__py3-none-any.whl → 5.4.55__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.
Files changed (950) hide show
  1. claude_mpm/BUILD_NUMBER +1 -0
  2. claude_mpm/VERSION +1 -0
  3. claude_mpm/__init__.py +50 -12
  4. claude_mpm/__main__.py +7 -2
  5. claude_mpm/agents/BASE_AGENT.md +164 -0
  6. claude_mpm/agents/BASE_ENGINEER.md +658 -0
  7. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +290 -0
  8. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
  9. claude_mpm/agents/MEMORY.md +72 -0
  10. claude_mpm/agents/PM_INSTRUCTIONS.md +1402 -0
  11. claude_mpm/agents/WORKFLOW.md +111 -0
  12. claude_mpm/agents/__init__.py +92 -80
  13. claude_mpm/agents/agent-template.yaml +83 -0
  14. claude_mpm/agents/agent_loader.py +560 -745
  15. claude_mpm/agents/agent_loader_integration.py +53 -55
  16. claude_mpm/agents/agents_metadata.py +186 -27
  17. claude_mpm/agents/async_agent_loader.py +436 -0
  18. claude_mpm/agents/base_agent.json +8 -4
  19. claude_mpm/agents/frontmatter_validator.py +754 -0
  20. claude_mpm/agents/system_agent_config.py +222 -155
  21. claude_mpm/agents/templates/README.md +465 -0
  22. claude_mpm/agents/templates/__init__.py +17 -13
  23. claude_mpm/agents/templates/circuit-breakers.md +1391 -0
  24. claude_mpm/agents/templates/context-management-examples.md +544 -0
  25. claude_mpm/agents/templates/git-file-tracking.md +584 -0
  26. claude_mpm/agents/templates/pm-examples.md +474 -0
  27. claude_mpm/agents/templates/pm-red-flags.md +310 -0
  28. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  29. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  30. claude_mpm/agents/templates/response-format.md +583 -0
  31. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  32. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  33. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  34. claude_mpm/agents/templates/validation-templates.md +312 -0
  35. claude_mpm/cli/__init__.py +90 -128
  36. claude_mpm/cli/__main__.py +33 -0
  37. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  38. claude_mpm/cli/commands/__init__.py +36 -12
  39. claude_mpm/cli/commands/agent_manager.py +1403 -0
  40. claude_mpm/cli/commands/agent_source.py +774 -0
  41. claude_mpm/cli/commands/agent_state_manager.py +335 -0
  42. claude_mpm/cli/commands/agents.py +2503 -168
  43. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  44. claude_mpm/cli/commands/agents_discover.py +338 -0
  45. claude_mpm/cli/commands/aggregate.py +540 -0
  46. claude_mpm/cli/commands/analyze.py +553 -0
  47. claude_mpm/cli/commands/analyze_code.py +528 -0
  48. claude_mpm/cli/commands/auto_configure.py +1053 -0
  49. claude_mpm/cli/commands/cleanup.py +588 -0
  50. claude_mpm/cli/commands/cleanup_orphaned_agents.py +150 -0
  51. claude_mpm/cli/commands/config.py +586 -0
  52. claude_mpm/cli/commands/configure.py +2654 -0
  53. claude_mpm/cli/commands/configure_agent_display.py +282 -0
  54. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  55. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  56. claude_mpm/cli/commands/configure_models.py +18 -0
  57. claude_mpm/cli/commands/configure_navigation.py +184 -0
  58. claude_mpm/cli/commands/configure_paths.py +104 -0
  59. claude_mpm/cli/commands/configure_persistence.py +254 -0
  60. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  61. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  62. claude_mpm/cli/commands/configure_validators.py +73 -0
  63. claude_mpm/cli/commands/dashboard.py +286 -0
  64. claude_mpm/cli/commands/debug.py +1386 -0
  65. claude_mpm/cli/commands/doctor.py +243 -0
  66. claude_mpm/cli/commands/hook_errors.py +277 -0
  67. claude_mpm/cli/commands/info.py +195 -74
  68. claude_mpm/cli/commands/local_deploy.py +534 -0
  69. claude_mpm/cli/commands/mcp.py +205 -0
  70. claude_mpm/cli/commands/mcp_command_router.py +161 -0
  71. claude_mpm/cli/commands/mcp_config.py +154 -0
  72. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  73. claude_mpm/cli/commands/mcp_external_commands.py +249 -0
  74. claude_mpm/cli/commands/mcp_install_commands.py +346 -0
  75. claude_mpm/cli/commands/mcp_pipx_config.py +208 -0
  76. claude_mpm/cli/commands/mcp_server_commands.py +155 -0
  77. claude_mpm/cli/commands/mcp_setup_external.py +868 -0
  78. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  79. claude_mpm/cli/commands/memory.py +585 -846
  80. claude_mpm/cli/commands/monitor.py +228 -310
  81. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  82. claude_mpm/cli/commands/mpm_init/core.py +759 -0
  83. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  84. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  85. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  86. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  87. claude_mpm/cli/commands/mpm_init/prompts.py +722 -0
  88. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  89. claude_mpm/cli/commands/mpm_init_handler.py +195 -0
  90. claude_mpm/cli/commands/postmortem.py +401 -0
  91. claude_mpm/cli/commands/profile.py +276 -0
  92. claude_mpm/cli/commands/run.py +910 -488
  93. claude_mpm/cli/commands/search.py +458 -0
  94. claude_mpm/cli/commands/skill_source.py +694 -0
  95. claude_mpm/cli/commands/skills.py +1246 -0
  96. claude_mpm/cli/commands/summarize.py +413 -0
  97. claude_mpm/cli/commands/tickets.py +536 -53
  98. claude_mpm/cli/commands/uninstall.py +176 -0
  99. claude_mpm/cli/commands/upgrade.py +152 -0
  100. claude_mpm/cli/commands/verify.py +119 -0
  101. claude_mpm/cli/executor.py +297 -0
  102. claude_mpm/cli/helpers.py +105 -0
  103. claude_mpm/cli/interactive/__init__.py +21 -0
  104. claude_mpm/cli/interactive/agent_wizard.py +1947 -0
  105. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  106. claude_mpm/cli/parser.py +87 -563
  107. claude_mpm/cli/parsers/__init__.py +35 -0
  108. claude_mpm/cli/parsers/agent_manager_parser.py +393 -0
  109. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  110. claude_mpm/cli/parsers/agents_parser.py +575 -0
  111. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  112. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  113. claude_mpm/cli/parsers/auto_configure_parser.py +120 -0
  114. claude_mpm/cli/parsers/base_parser.py +644 -0
  115. claude_mpm/cli/parsers/config_parser.py +208 -0
  116. claude_mpm/cli/parsers/configure_parser.py +138 -0
  117. claude_mpm/cli/parsers/dashboard_parser.py +113 -0
  118. claude_mpm/cli/parsers/debug_parser.py +319 -0
  119. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  120. claude_mpm/cli/parsers/mcp_parser.py +195 -0
  121. claude_mpm/cli/parsers/memory_parser.py +138 -0
  122. claude_mpm/cli/parsers/monitor_parser.py +142 -0
  123. claude_mpm/cli/parsers/mpm_init_parser.py +311 -0
  124. claude_mpm/cli/parsers/profile_parser.py +147 -0
  125. claude_mpm/cli/parsers/run_parser.py +157 -0
  126. claude_mpm/cli/parsers/search_parser.py +245 -0
  127. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  128. claude_mpm/cli/parsers/skills_parser.py +277 -0
  129. claude_mpm/cli/parsers/source_parser.py +138 -0
  130. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  131. claude_mpm/cli/shared/__init__.py +40 -0
  132. claude_mpm/cli/shared/argument_patterns.py +205 -0
  133. claude_mpm/cli/shared/base_command.py +242 -0
  134. claude_mpm/cli/shared/error_handling.py +242 -0
  135. claude_mpm/cli/shared/output_formatters.py +241 -0
  136. claude_mpm/cli/startup.py +1743 -0
  137. claude_mpm/cli/startup_display.py +480 -0
  138. claude_mpm/cli/startup_logging.py +839 -0
  139. claude_mpm/cli/utils.py +136 -47
  140. claude_mpm/cli_module/__init__.py +6 -6
  141. claude_mpm/cli_module/args.py +188 -140
  142. claude_mpm/cli_module/commands.py +79 -70
  143. claude_mpm/cli_module/migration_example.py +42 -64
  144. claude_mpm/commands/__init__.py +14 -0
  145. claude_mpm/commands/mpm-config.md +28 -0
  146. claude_mpm/commands/mpm-doctor.md +20 -0
  147. claude_mpm/commands/mpm-help.md +20 -0
  148. claude_mpm/commands/mpm-init.md +120 -0
  149. claude_mpm/commands/mpm-monitor.md +31 -0
  150. claude_mpm/commands/mpm-organize.md +120 -0
  151. claude_mpm/commands/mpm-postmortem.md +21 -0
  152. claude_mpm/commands/mpm-session-resume.md +30 -0
  153. claude_mpm/commands/mpm-status.md +20 -0
  154. claude_mpm/commands/mpm-ticket-view.md +109 -0
  155. claude_mpm/commands/mpm-version.md +20 -0
  156. claude_mpm/commands/mpm.md +31 -0
  157. claude_mpm/config/__init__.py +42 -2
  158. claude_mpm/config/agent_config.py +402 -0
  159. claude_mpm/config/agent_presets.py +488 -0
  160. claude_mpm/config/agent_sources.py +352 -0
  161. claude_mpm/config/experimental_features.py +217 -0
  162. claude_mpm/config/model_config.py +428 -0
  163. claude_mpm/config/paths.py +258 -0
  164. claude_mpm/config/skill_presets.py +392 -0
  165. claude_mpm/config/skill_sources.py +590 -0
  166. claude_mpm/config/socketio_config.py +125 -83
  167. claude_mpm/constants.py +132 -22
  168. claude_mpm/core/__init__.py +62 -36
  169. claude_mpm/core/agent_name_normalizer.py +71 -73
  170. claude_mpm/core/agent_registry.py +385 -492
  171. claude_mpm/core/agent_session_manager.py +81 -70
  172. claude_mpm/core/api_validator.py +330 -0
  173. claude_mpm/core/base_service.py +159 -122
  174. claude_mpm/core/cache.py +560 -0
  175. claude_mpm/core/claude_runner.py +696 -916
  176. claude_mpm/core/config.py +613 -122
  177. claude_mpm/core/config_aliases.py +74 -73
  178. claude_mpm/core/config_constants.py +314 -0
  179. claude_mpm/core/constants.py +361 -0
  180. claude_mpm/core/container.py +646 -104
  181. claude_mpm/core/enums.py +452 -0
  182. claude_mpm/core/error_handler.py +623 -0
  183. claude_mpm/core/exceptions.py +536 -0
  184. claude_mpm/core/factories.py +105 -109
  185. claude_mpm/core/file_utils.py +764 -0
  186. claude_mpm/core/framework/__init__.py +25 -0
  187. claude_mpm/core/framework/formatters/__init__.py +11 -0
  188. claude_mpm/core/framework/formatters/capability_generator.py +367 -0
  189. claude_mpm/core/framework/formatters/content_formatter.py +278 -0
  190. claude_mpm/core/framework/formatters/context_generator.py +185 -0
  191. claude_mpm/core/framework/loaders/__init__.py +13 -0
  192. claude_mpm/core/framework/loaders/agent_loader.py +213 -0
  193. claude_mpm/core/framework/loaders/file_loader.py +176 -0
  194. claude_mpm/core/framework/loaders/instruction_loader.py +222 -0
  195. claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
  196. claude_mpm/core/framework/processors/__init__.py +11 -0
  197. claude_mpm/core/framework/processors/memory_processor.py +230 -0
  198. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  199. claude_mpm/core/framework/processors/template_processor.py +244 -0
  200. claude_mpm/core/framework_loader.py +485 -414
  201. claude_mpm/core/hook_error_memory.py +381 -0
  202. claude_mpm/core/hook_manager.py +246 -86
  203. claude_mpm/core/hook_performance_config.py +147 -0
  204. claude_mpm/core/injectable_service.py +72 -63
  205. claude_mpm/core/instruction_reinforcement_hook.py +267 -0
  206. claude_mpm/core/interactive_session.py +670 -0
  207. claude_mpm/core/interfaces.py +570 -164
  208. claude_mpm/core/lazy.py +467 -0
  209. claude_mpm/core/log_manager.py +707 -0
  210. claude_mpm/core/logger.py +295 -134
  211. claude_mpm/core/logging_config.py +474 -0
  212. claude_mpm/core/logging_utils.py +520 -0
  213. claude_mpm/core/minimal_framework_loader.py +24 -22
  214. claude_mpm/core/mixins.py +30 -29
  215. claude_mpm/core/oneshot_session.py +594 -0
  216. claude_mpm/core/optimized_agent_loader.py +479 -0
  217. claude_mpm/core/optimized_startup.py +554 -0
  218. claude_mpm/core/output_style_manager.py +483 -0
  219. claude_mpm/core/pm_hook_interceptor.py +197 -82
  220. claude_mpm/core/protocols/__init__.py +23 -0
  221. claude_mpm/core/protocols/runner_protocol.py +103 -0
  222. claude_mpm/core/protocols/session_protocol.py +131 -0
  223. claude_mpm/core/service_registry.py +153 -116
  224. claude_mpm/core/session_manager.py +179 -64
  225. claude_mpm/core/shared/__init__.py +17 -0
  226. claude_mpm/core/shared/config_loader.py +326 -0
  227. claude_mpm/core/shared/path_resolver.py +281 -0
  228. claude_mpm/core/shared/singleton_manager.py +221 -0
  229. claude_mpm/core/socketio_pool.py +400 -137
  230. claude_mpm/core/system_context.py +38 -0
  231. claude_mpm/core/tool_access_control.py +64 -57
  232. claude_mpm/core/types.py +307 -0
  233. claude_mpm/core/typing_utils.py +553 -0
  234. claude_mpm/core/unified_agent_registry.py +969 -0
  235. claude_mpm/core/unified_config.py +570 -0
  236. claude_mpm/core/unified_paths.py +941 -0
  237. claude_mpm/dashboard/__init__.py +12 -0
  238. claude_mpm/dashboard/api/simple_directory.py +261 -0
  239. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  240. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +1 -0
  241. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +1 -0
  242. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/4TdZjIqw.js +1 -0
  243. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +24 -0
  244. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B0uc0UOD.js +36 -0
  245. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7RN905-.js +1 -0
  246. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7xVLGWV.js +2 -0
  247. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BIF9m_hv.js +61 -0
  248. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +1 -0
  249. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BPYeabCQ.js +1 -0
  250. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  251. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  252. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Be7GpZd6.js +7 -0
  253. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bh0LDWpI.js +145 -0
  254. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BofRWZRR.js +10 -0
  255. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BovzEFCE.js +30 -0
  256. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C30mlcqg.js +165 -0
  257. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4B-KCzX.js +1 -0
  258. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4JcI4KD.js +122 -0
  259. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CBBdVcY8.js +1 -0
  260. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CDuw-vjf.js +1 -0
  261. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C_Usid8X.js +15 -0
  262. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cfqx1Qun.js +10 -0
  263. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CiIAseT4.js +128 -0
  264. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  265. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CnA0NrzZ.js +1 -0
  266. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cs_tUR18.js +24 -0
  267. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  268. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CyWMqx4W.js +43 -0
  269. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzZX-COe.js +220 -0
  270. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzeYkLYB.js +65 -0
  271. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D3k0OPJN.js +4 -0
  272. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9lljYKQ.js +1 -0
  273. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DGkLK5U1.js +267 -0
  274. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DI7hHRFL.js +1 -0
  275. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DLVjFsZ3.js +139 -0
  276. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUrLdbGD.js +89 -0
  277. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  278. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DY1XQ8fi.js +2 -0
  279. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DZX00Y4g.js +1 -0
  280. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +1 -0
  281. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DaimHw_p.js +68 -0
  282. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +323 -0
  283. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dhb8PKl3.js +1 -0
  284. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dle-35c7.js +64 -0
  285. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DmxopI1J.js +1 -0
  286. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DwBR2MJi.js +60 -0
  287. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/GYwsonyD.js +1 -0
  288. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  289. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  290. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/RJiighC3.js +1 -0
  291. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Vzk33B_K.js +2 -0
  292. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ZGh7QtNv.js +7 -0
  293. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bT1r9zLR.js +1 -0
  294. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bTOqqlTd.js +1 -0
  295. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/eNVUfhuA.js +1 -0
  296. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/iEWssX7S.js +162 -0
  297. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/sQeU3Y1z.js +1 -0
  298. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uuIeMWc-.js +1 -0
  299. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.D6-I5TpK.js +2 -0
  300. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +1 -0
  301. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.m1gL8KXf.js +1 -0
  302. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.CgNOuw-d.js +1 -0
  303. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +1 -0
  304. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  305. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  306. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  307. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  308. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  309. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  310. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  311. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  312. claude_mpm/experimental/__init__.py +10 -0
  313. claude_mpm/experimental/cli_enhancements.py +104 -89
  314. claude_mpm/generators/__init__.py +1 -1
  315. claude_mpm/generators/agent_profile_generator.py +76 -66
  316. claude_mpm/hooks/__init__.py +37 -1
  317. claude_mpm/hooks/base_hook.py +37 -32
  318. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  319. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  320. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  321. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  322. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  323. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  324. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  325. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  326. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  327. claude_mpm/hooks/claude_hooks/connection_pool.py +250 -0
  328. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  329. claude_mpm/hooks/claude_hooks/event_handlers.py +888 -0
  330. claude_mpm/hooks/claude_hooks/hook_handler.py +652 -875
  331. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +10 -7
  332. claude_mpm/hooks/claude_hooks/installer.py +806 -0
  333. claude_mpm/hooks/claude_hooks/memory_integration.py +249 -0
  334. claude_mpm/hooks/claude_hooks/response_tracking.py +412 -0
  335. claude_mpm/hooks/claude_hooks/services/__init__.py +15 -0
  336. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  337. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  338. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  339. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  340. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  341. claude_mpm/hooks/claude_hooks/services/connection_manager.py +229 -0
  342. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +254 -0
  343. claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
  344. claude_mpm/hooks/claude_hooks/services/state_manager.py +284 -0
  345. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
  346. claude_mpm/hooks/claude_hooks/tool_analysis.py +224 -0
  347. claude_mpm/hooks/failure_learning/__init__.py +54 -0
  348. claude_mpm/hooks/failure_learning/failure_detection_hook.py +230 -0
  349. claude_mpm/hooks/failure_learning/fix_detection_hook.py +212 -0
  350. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +281 -0
  351. claude_mpm/hooks/instruction_reinforcement.py +301 -0
  352. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  353. claude_mpm/hooks/kuzu_memory_hook.py +386 -0
  354. claude_mpm/hooks/kuzu_response_hook.py +179 -0
  355. claude_mpm/hooks/memory_integration_hook.py +201 -107
  356. claude_mpm/hooks/session_resume_hook.py +121 -0
  357. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  358. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  359. claude_mpm/hooks/tool_call_interceptor.py +92 -76
  360. claude_mpm/hooks/validation_hooks.py +62 -54
  361. claude_mpm/init.py +518 -83
  362. claude_mpm/models/__init__.py +9 -9
  363. claude_mpm/models/agent_definition.py +40 -23
  364. claude_mpm/models/agent_session.py +538 -0
  365. claude_mpm/models/git_repository.py +198 -0
  366. claude_mpm/models/resume_log.py +340 -0
  367. claude_mpm/schemas/__init__.py +12 -0
  368. claude_mpm/scripts/__init__.py +15 -0
  369. claude_mpm/scripts/claude-hook-handler.sh +227 -0
  370. claude_mpm/scripts/launch_monitor.py +165 -0
  371. claude_mpm/scripts/mpm_doctor.py +322 -0
  372. claude_mpm/scripts/socketio_daemon.py +189 -200
  373. claude_mpm/scripts/start_activity_logging.py +91 -0
  374. claude_mpm/services/__init__.py +208 -39
  375. claude_mpm/services/agent_capabilities_service.py +266 -0
  376. claude_mpm/services/agents/__init__.py +89 -0
  377. claude_mpm/services/agents/agent_builder.py +514 -0
  378. claude_mpm/services/agents/agent_preset_service.py +238 -0
  379. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  380. claude_mpm/services/agents/agent_review_service.py +280 -0
  381. claude_mpm/services/agents/agent_selection_service.py +484 -0
  382. claude_mpm/services/agents/auto_config_manager.py +796 -0
  383. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  384. claude_mpm/services/agents/cache_git_manager.py +621 -0
  385. claude_mpm/services/agents/deployment/__init__.py +21 -0
  386. claude_mpm/services/agents/deployment/agent_config_provider.py +410 -0
  387. claude_mpm/services/agents/deployment/agent_configuration_manager.py +358 -0
  388. claude_mpm/services/agents/deployment/agent_definition_factory.py +80 -0
  389. claude_mpm/services/agents/deployment/agent_deployment.py +1037 -0
  390. claude_mpm/services/agents/deployment/agent_discovery_service.py +546 -0
  391. claude_mpm/services/agents/deployment/agent_environment_manager.py +288 -0
  392. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +383 -0
  393. claude_mpm/services/agents/deployment/agent_format_converter.py +505 -0
  394. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +160 -0
  395. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +957 -0
  396. claude_mpm/services/agents/deployment/agent_metrics_collector.py +273 -0
  397. claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
  398. claude_mpm/services/agents/deployment/agent_record_service.py +418 -0
  399. claude_mpm/services/agents/deployment/agent_restore_handler.py +84 -0
  400. claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
  401. claude_mpm/services/agents/deployment/agent_template_builder.py +1369 -0
  402. claude_mpm/services/agents/deployment/agent_validator.py +376 -0
  403. claude_mpm/services/agents/deployment/agent_version_manager.py +322 -0
  404. claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +10 -13
  405. claude_mpm/services/agents/deployment/agents_directory_resolver.py +149 -0
  406. claude_mpm/services/agents/deployment/async_agent_deployment.py +768 -0
  407. claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
  408. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  409. claude_mpm/services/agents/deployment/config/deployment_config.py +181 -0
  410. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  411. claude_mpm/services/agents/deployment/deployment_config_loader.py +178 -0
  412. claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
  413. claude_mpm/services/agents/deployment/deployment_type_detector.py +120 -0
  414. claude_mpm/services/agents/deployment/deployment_wrapper.py +129 -0
  415. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  416. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  417. claude_mpm/services/agents/deployment/facade/deployment_executor.py +70 -0
  418. claude_mpm/services/agents/deployment/facade/deployment_facade.py +269 -0
  419. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  420. claude_mpm/services/agents/deployment/interface_adapter.py +226 -0
  421. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  422. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  423. claude_mpm/services/agents/deployment/local_template_deployment.py +362 -0
  424. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +1478 -0
  425. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  426. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  427. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +162 -0
  428. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  429. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  430. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +240 -0
  431. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +110 -0
  432. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +80 -0
  433. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +92 -0
  434. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +101 -0
  435. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  436. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +102 -0
  437. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  438. claude_mpm/services/agents/deployment/processors/agent_processor.py +269 -0
  439. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +311 -0
  440. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +862 -0
  441. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  442. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  443. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  444. claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
  445. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  446. claude_mpm/services/agents/deployment/strategies/base_strategy.py +113 -0
  447. claude_mpm/services/agents/deployment/strategies/project_strategy.py +148 -0
  448. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  449. claude_mpm/services/agents/deployment/strategies/system_strategy.py +131 -0
  450. claude_mpm/services/agents/deployment/strategies/user_strategy.py +130 -0
  451. claude_mpm/services/agents/deployment/system_instructions_deployer.py +228 -0
  452. claude_mpm/services/agents/deployment/validation/__init__.py +21 -0
  453. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  454. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  455. claude_mpm/services/agents/deployment/validation/template_validator.py +319 -0
  456. claude_mpm/services/agents/deployment/validation/validation_result.py +214 -0
  457. claude_mpm/services/agents/git_source_manager.py +682 -0
  458. claude_mpm/services/agents/loading/__init__.py +11 -0
  459. claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +306 -228
  460. claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +106 -91
  461. claude_mpm/services/agents/loading/framework_agent_loader.py +433 -0
  462. claude_mpm/services/agents/local_template_manager.py +784 -0
  463. claude_mpm/services/agents/management/__init__.py +9 -0
  464. claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +92 -69
  465. claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +219 -168
  466. claude_mpm/services/agents/memory/__init__.py +22 -0
  467. claude_mpm/services/agents/memory/agent_memory_manager.py +784 -0
  468. claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +20 -18
  469. claude_mpm/services/agents/memory/content_manager.py +470 -0
  470. claude_mpm/services/agents/memory/memory_categorization_service.py +167 -0
  471. claude_mpm/services/agents/memory/memory_file_service.py +129 -0
  472. claude_mpm/services/agents/memory/memory_format_service.py +201 -0
  473. claude_mpm/services/agents/memory/memory_limits_service.py +101 -0
  474. claude_mpm/services/agents/memory/template_generator.py +83 -0
  475. claude_mpm/services/agents/observers.py +547 -0
  476. claude_mpm/services/agents/recommender.py +617 -0
  477. claude_mpm/services/agents/registry/__init__.py +30 -0
  478. claude_mpm/services/agents/registry/deployed_agent_discovery.py +273 -0
  479. claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +370 -295
  480. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  481. claude_mpm/services/agents/sources/__init__.py +13 -0
  482. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  483. claude_mpm/services/agents/sources/git_source_sync_service.py +1202 -0
  484. claude_mpm/services/agents/startup_sync.py +259 -0
  485. claude_mpm/services/agents/toolchain_detector.py +478 -0
  486. claude_mpm/services/analysis/__init__.py +35 -0
  487. claude_mpm/services/analysis/clone_detector.py +1030 -0
  488. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  489. claude_mpm/services/analysis/postmortem_service.py +765 -0
  490. claude_mpm/services/async_session_logger.py +665 -0
  491. claude_mpm/services/claude_session_logger.py +321 -0
  492. claude_mpm/services/cli/__init__.py +18 -0
  493. claude_mpm/services/cli/agent_cleanup_service.py +408 -0
  494. claude_mpm/services/cli/agent_dependency_service.py +395 -0
  495. claude_mpm/services/cli/agent_listing_service.py +463 -0
  496. claude_mpm/services/cli/agent_output_formatter.py +605 -0
  497. claude_mpm/services/cli/agent_validation_service.py +590 -0
  498. claude_mpm/services/cli/memory_crud_service.py +622 -0
  499. claude_mpm/services/cli/memory_output_formatter.py +604 -0
  500. claude_mpm/services/cli/resume_service.py +617 -0
  501. claude_mpm/services/cli/session_manager.py +604 -0
  502. claude_mpm/services/cli/session_pause_manager.py +504 -0
  503. claude_mpm/services/cli/session_resume_helper.py +372 -0
  504. claude_mpm/services/cli/startup_checker.py +362 -0
  505. claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
  506. claude_mpm/services/command_deployment_service.py +446 -0
  507. claude_mpm/services/command_handler_service.py +221 -0
  508. claude_mpm/services/communication/__init__.py +22 -0
  509. claude_mpm/services/core/__init__.py +108 -0
  510. claude_mpm/services/core/base.py +269 -0
  511. claude_mpm/services/core/cache_manager.py +309 -0
  512. claude_mpm/services/core/interfaces/__init__.py +273 -0
  513. claude_mpm/services/core/interfaces/agent.py +514 -0
  514. claude_mpm/services/core/interfaces/communication.py +316 -0
  515. claude_mpm/services/core/interfaces/health.py +169 -0
  516. claude_mpm/services/core/interfaces/infrastructure.py +357 -0
  517. claude_mpm/services/core/interfaces/model.py +281 -0
  518. claude_mpm/services/core/interfaces/process.py +372 -0
  519. claude_mpm/services/core/interfaces/project.py +121 -0
  520. claude_mpm/services/core/interfaces/restart.py +307 -0
  521. claude_mpm/services/core/interfaces/service.py +405 -0
  522. claude_mpm/services/core/interfaces/stability.py +260 -0
  523. claude_mpm/services/core/interfaces.py +81 -0
  524. claude_mpm/services/core/memory_manager.py +682 -0
  525. claude_mpm/services/core/models/__init__.py +70 -0
  526. claude_mpm/services/core/models/agent_config.py +384 -0
  527. claude_mpm/services/core/models/health.py +162 -0
  528. claude_mpm/services/core/models/process.py +239 -0
  529. claude_mpm/services/core/models/restart.py +302 -0
  530. claude_mpm/services/core/models/stability.py +264 -0
  531. claude_mpm/services/core/models/toolchain.py +306 -0
  532. claude_mpm/services/core/path_resolver.py +517 -0
  533. claude_mpm/services/core/service_container.py +520 -0
  534. claude_mpm/services/core/service_interfaces.py +436 -0
  535. claude_mpm/services/diagnostics/__init__.py +18 -0
  536. claude_mpm/services/diagnostics/checks/__init__.py +38 -0
  537. claude_mpm/services/diagnostics/checks/agent_check.py +370 -0
  538. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  539. claude_mpm/services/diagnostics/checks/base_check.py +60 -0
  540. claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
  541. claude_mpm/services/diagnostics/checks/common_issues_check.py +363 -0
  542. claude_mpm/services/diagnostics/checks/configuration_check.py +306 -0
  543. claude_mpm/services/diagnostics/checks/filesystem_check.py +233 -0
  544. claude_mpm/services/diagnostics/checks/installation_check.py +520 -0
  545. claude_mpm/services/diagnostics/checks/instructions_check.py +415 -0
  546. claude_mpm/services/diagnostics/checks/mcp_check.py +330 -0
  547. claude_mpm/services/diagnostics/checks/mcp_services_check.py +1058 -0
  548. claude_mpm/services/diagnostics/checks/monitor_check.py +281 -0
  549. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  550. claude_mpm/services/diagnostics/checks/startup_log_check.py +319 -0
  551. claude_mpm/services/diagnostics/diagnostic_runner.py +286 -0
  552. claude_mpm/services/diagnostics/doctor_reporter.py +578 -0
  553. claude_mpm/services/diagnostics/models.py +138 -0
  554. claude_mpm/services/event_aggregator.py +582 -0
  555. claude_mpm/services/event_bus/__init__.py +18 -0
  556. claude_mpm/services/event_bus/config.py +186 -0
  557. claude_mpm/services/event_bus/direct_relay.py +312 -0
  558. claude_mpm/services/event_bus/event_bus.py +396 -0
  559. claude_mpm/services/event_bus/relay.py +326 -0
  560. claude_mpm/services/events/__init__.py +44 -0
  561. claude_mpm/services/events/consumers/__init__.py +18 -0
  562. claude_mpm/services/events/consumers/dead_letter.py +306 -0
  563. claude_mpm/services/events/consumers/logging.py +184 -0
  564. claude_mpm/services/events/consumers/metrics.py +241 -0
  565. claude_mpm/services/events/consumers/socketio.py +377 -0
  566. claude_mpm/services/events/core.py +480 -0
  567. claude_mpm/services/events/interfaces.py +214 -0
  568. claude_mpm/services/events/producers/__init__.py +14 -0
  569. claude_mpm/services/events/producers/hook.py +269 -0
  570. claude_mpm/services/events/producers/system.py +329 -0
  571. claude_mpm/services/exceptions.py +433 -353
  572. claude_mpm/services/framework_claude_md_generator/__init__.py +81 -80
  573. claude_mpm/services/framework_claude_md_generator/content_assembler.py +74 -67
  574. claude_mpm/services/framework_claude_md_generator/content_validator.py +66 -62
  575. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +82 -60
  576. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +36 -37
  577. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +41 -40
  578. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +15 -15
  579. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +5 -4
  580. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  581. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  582. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  583. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  584. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +5 -4
  585. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  586. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  587. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +26 -30
  588. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +6 -5
  589. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  590. claude_mpm/services/framework_claude_md_generator/version_manager.py +31 -30
  591. claude_mpm/services/git/__init__.py +21 -0
  592. claude_mpm/services/git/git_operations_service.py +579 -0
  593. claude_mpm/services/github/__init__.py +21 -0
  594. claude_mpm/services/github/github_cli_service.py +397 -0
  595. claude_mpm/services/hook_installer_service.py +506 -0
  596. claude_mpm/services/hook_service.py +159 -111
  597. claude_mpm/services/infrastructure/__init__.py +52 -0
  598. claude_mpm/services/infrastructure/context_preservation.py +569 -0
  599. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  600. claude_mpm/services/infrastructure/logging.py +209 -0
  601. claude_mpm/services/infrastructure/monitoring/__init__.py +39 -0
  602. claude_mpm/services/infrastructure/monitoring/aggregator.py +432 -0
  603. claude_mpm/services/infrastructure/monitoring/base.py +122 -0
  604. claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
  605. claude_mpm/services/infrastructure/monitoring/network.py +219 -0
  606. claude_mpm/services/infrastructure/monitoring/process.py +343 -0
  607. claude_mpm/services/infrastructure/monitoring/resources.py +244 -0
  608. claude_mpm/services/infrastructure/monitoring/service.py +368 -0
  609. claude_mpm/services/infrastructure/monitoring.py +71 -0
  610. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  611. claude_mpm/services/instructions/__init__.py +9 -0
  612. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  613. claude_mpm/services/local_ops/__init__.py +155 -0
  614. claude_mpm/services/local_ops/crash_detector.py +257 -0
  615. claude_mpm/services/local_ops/health_checks/__init__.py +26 -0
  616. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  617. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  618. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  619. claude_mpm/services/local_ops/health_manager.py +427 -0
  620. claude_mpm/services/local_ops/log_monitor.py +396 -0
  621. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  622. claude_mpm/services/local_ops/process_manager.py +595 -0
  623. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  624. claude_mpm/services/local_ops/restart_manager.py +401 -0
  625. claude_mpm/services/local_ops/restart_policy.py +387 -0
  626. claude_mpm/services/local_ops/state_manager.py +372 -0
  627. claude_mpm/services/local_ops/unified_manager.py +600 -0
  628. claude_mpm/services/mcp_config_manager.py +1542 -0
  629. claude_mpm/services/mcp_service_verifier.py +732 -0
  630. claude_mpm/services/memory/__init__.py +19 -0
  631. claude_mpm/services/{memory_builder.py → memory/builder.py} +465 -373
  632. claude_mpm/services/memory/cache/__init__.py +14 -0
  633. claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +237 -200
  634. claude_mpm/services/memory/cache/simple_cache.py +331 -0
  635. claude_mpm/services/memory/failure_tracker.py +578 -0
  636. claude_mpm/services/memory/indexed_memory.py +648 -0
  637. claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +272 -243
  638. claude_mpm/services/memory/router.py +951 -0
  639. claude_mpm/services/memory_hook_service.py +470 -0
  640. claude_mpm/services/model/__init__.py +147 -0
  641. claude_mpm/services/model/base_provider.py +365 -0
  642. claude_mpm/services/model/claude_provider.py +412 -0
  643. claude_mpm/services/model/model_router.py +452 -0
  644. claude_mpm/services/model/ollama_provider.py +415 -0
  645. claude_mpm/services/monitor/__init__.py +20 -0
  646. claude_mpm/services/monitor/daemon.py +698 -0
  647. claude_mpm/services/monitor/daemon_manager.py +1076 -0
  648. claude_mpm/services/monitor/event_emitter.py +350 -0
  649. claude_mpm/services/monitor/handlers/__init__.py +21 -0
  650. claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
  651. claude_mpm/services/monitor/handlers/dashboard.py +299 -0
  652. claude_mpm/services/monitor/handlers/file.py +264 -0
  653. claude_mpm/services/monitor/handlers/hooks.py +512 -0
  654. claude_mpm/services/monitor/management/__init__.py +18 -0
  655. claude_mpm/services/monitor/management/health.py +124 -0
  656. claude_mpm/services/monitor/management/lifecycle.py +730 -0
  657. claude_mpm/services/monitor/server.py +1493 -0
  658. claude_mpm/services/monitor_build_service.py +349 -0
  659. claude_mpm/services/native_agent_converter.py +356 -0
  660. claude_mpm/services/orphan_detection.py +786 -0
  661. claude_mpm/services/pm_skills_deployer.py +707 -0
  662. claude_mpm/services/port_manager.py +597 -0
  663. claude_mpm/services/pr/__init__.py +14 -0
  664. claude_mpm/services/pr/pr_template_service.py +329 -0
  665. claude_mpm/services/profile_manager.py +337 -0
  666. claude_mpm/services/project/__init__.py +44 -0
  667. claude_mpm/services/{project_analyzer.py → project/analyzer.py} +541 -291
  668. claude_mpm/services/project/analyzer_v2.py +566 -0
  669. claude_mpm/services/project/architecture_analyzer.py +461 -0
  670. claude_mpm/services/project/archive_manager.py +1045 -0
  671. claude_mpm/services/project/dependency_analyzer.py +462 -0
  672. claude_mpm/services/project/detection_strategies.py +719 -0
  673. claude_mpm/services/project/documentation_manager.py +554 -0
  674. claude_mpm/services/project/enhanced_analyzer.py +572 -0
  675. claude_mpm/services/project/language_analyzer.py +265 -0
  676. claude_mpm/services/project/metrics_collector.py +407 -0
  677. claude_mpm/services/project/project_organizer.py +1009 -0
  678. claude_mpm/services/project/registry.py +636 -0
  679. claude_mpm/services/project/toolchain_analyzer.py +583 -0
  680. claude_mpm/services/project_port_allocator.py +596 -0
  681. claude_mpm/services/recovery_manager.py +293 -240
  682. claude_mpm/services/response_tracker.py +267 -0
  683. claude_mpm/services/runner_configuration_service.py +605 -0
  684. claude_mpm/services/self_upgrade_service.py +608 -0
  685. claude_mpm/services/session_management_service.py +314 -0
  686. claude_mpm/services/session_manager.py +380 -0
  687. claude_mpm/services/shared/__init__.py +21 -0
  688. claude_mpm/services/shared/async_service_base.py +216 -0
  689. claude_mpm/services/shared/config_service_base.py +301 -0
  690. claude_mpm/services/shared/lifecycle_service_base.py +308 -0
  691. claude_mpm/services/shared/manager_base.py +315 -0
  692. claude_mpm/services/shared/service_factory.py +309 -0
  693. claude_mpm/services/skills/__init__.py +21 -0
  694. claude_mpm/services/skills/git_skill_source_manager.py +1324 -0
  695. claude_mpm/services/skills/selective_skill_deployer.py +744 -0
  696. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  697. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  698. claude_mpm/services/skills_config.py +547 -0
  699. claude_mpm/services/skills_deployer.py +1168 -0
  700. claude_mpm/services/socketio/__init__.py +25 -0
  701. claude_mpm/services/socketio/client_proxy.py +229 -0
  702. claude_mpm/services/socketio/dashboard_server.py +362 -0
  703. claude_mpm/services/socketio/event_normalizer.py +798 -0
  704. claude_mpm/services/socketio/handlers/__init__.py +30 -0
  705. claude_mpm/services/socketio/handlers/base.py +136 -0
  706. claude_mpm/services/socketio/handlers/code_analysis.py +682 -0
  707. claude_mpm/services/socketio/handlers/connection.py +643 -0
  708. claude_mpm/services/socketio/handlers/connection_handler.py +333 -0
  709. claude_mpm/services/socketio/handlers/file.py +263 -0
  710. claude_mpm/services/socketio/handlers/git.py +962 -0
  711. claude_mpm/services/socketio/handlers/hook.py +211 -0
  712. claude_mpm/services/socketio/handlers/memory.py +26 -0
  713. claude_mpm/services/socketio/handlers/project.py +24 -0
  714. claude_mpm/services/socketio/handlers/registry.py +214 -0
  715. claude_mpm/services/socketio/migration_utils.py +343 -0
  716. claude_mpm/services/socketio/monitor_client.py +364 -0
  717. claude_mpm/services/socketio/server/__init__.py +18 -0
  718. claude_mpm/services/socketio/server/broadcaster.py +569 -0
  719. claude_mpm/services/socketio/server/connection_manager.py +579 -0
  720. claude_mpm/services/socketio/server/core.py +1079 -0
  721. claude_mpm/services/socketio/server/eventbus_integration.py +245 -0
  722. claude_mpm/services/socketio/server/main.py +501 -0
  723. claude_mpm/services/socketio_client_manager.py +173 -143
  724. claude_mpm/services/socketio_server.py +38 -1657
  725. claude_mpm/services/subprocess_launcher_service.py +322 -0
  726. claude_mpm/services/system_instructions_service.py +270 -0
  727. claude_mpm/services/ticket_manager.py +25 -209
  728. claude_mpm/services/ticket_services/__init__.py +26 -0
  729. claude_mpm/services/ticket_services/crud_service.py +328 -0
  730. claude_mpm/services/ticket_services/formatter_service.py +290 -0
  731. claude_mpm/services/ticket_services/search_service.py +324 -0
  732. claude_mpm/services/ticket_services/validation_service.py +303 -0
  733. claude_mpm/services/ticket_services/workflow_service.py +244 -0
  734. claude_mpm/services/unified/__init__.py +65 -0
  735. claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
  736. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
  737. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
  738. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +900 -0
  739. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +745 -0
  740. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
  741. claude_mpm/services/unified/config_strategies/__init__.py +175 -0
  742. claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
  743. claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
  744. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
  745. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
  746. claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
  747. claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
  748. claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
  749. claude_mpm/services/unified/deployment_strategies/base.py +553 -0
  750. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
  751. claude_mpm/services/unified/deployment_strategies/local.py +607 -0
  752. claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
  753. claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
  754. claude_mpm/services/unified/interfaces.py +475 -0
  755. claude_mpm/services/unified/migration.py +509 -0
  756. claude_mpm/services/unified/strategies.py +534 -0
  757. claude_mpm/services/unified/unified_analyzer.py +542 -0
  758. claude_mpm/services/unified/unified_config.py +691 -0
  759. claude_mpm/services/unified/unified_deployment.py +466 -0
  760. claude_mpm/services/utility_service.py +280 -0
  761. claude_mpm/services/version_control/__init__.py +34 -37
  762. claude_mpm/services/version_control/branch_strategy.py +26 -17
  763. claude_mpm/services/version_control/conflict_resolution.py +52 -36
  764. claude_mpm/services/version_control/git_operations.py +183 -49
  765. claude_mpm/services/version_control/semantic_versioning.py +172 -61
  766. claude_mpm/services/version_control/version_parser.py +546 -0
  767. claude_mpm/services/version_service.py +379 -0
  768. claude_mpm/services/visualization/__init__.py +15 -0
  769. claude_mpm/services/visualization/mermaid_generator.py +937 -0
  770. claude_mpm/skills/__init__.py +42 -0
  771. claude_mpm/skills/agent_skills_injector.py +324 -0
  772. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  773. claude_mpm/skills/bundled/__init__.py +6 -0
  774. claude_mpm/skills/bundled/api-documentation.md +393 -0
  775. claude_mpm/skills/bundled/async-testing.md +571 -0
  776. claude_mpm/skills/bundled/code-review.md +143 -0
  777. claude_mpm/skills/bundled/database-migration.md +199 -0
  778. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  779. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  780. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  781. claude_mpm/skills/bundled/git-workflow.md +414 -0
  782. claude_mpm/skills/bundled/imagemagick.md +204 -0
  783. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  784. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  785. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
  786. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
  787. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
  788. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
  789. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
  790. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  791. claude_mpm/skills/bundled/pdf.md +141 -0
  792. claude_mpm/skills/bundled/performance-profiling.md +573 -0
  793. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  794. claude_mpm/skills/bundled/security-scanning.md +439 -0
  795. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  796. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  797. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  798. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
  799. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  800. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
  801. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  802. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  803. claude_mpm/skills/bundled/xlsx.md +157 -0
  804. claude_mpm/skills/registry.py +286 -0
  805. claude_mpm/skills/skill_manager.py +405 -0
  806. claude_mpm/skills/skills_registry.py +347 -0
  807. claude_mpm/skills/skills_service.py +739 -0
  808. claude_mpm/storage/__init__.py +9 -0
  809. claude_mpm/storage/state_storage.py +546 -0
  810. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  811. claude_mpm/templates/questions/__init__.py +38 -0
  812. claude_mpm/templates/questions/base.py +193 -0
  813. claude_mpm/templates/questions/pr_strategy.py +311 -0
  814. claude_mpm/templates/questions/project_init.py +385 -0
  815. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  816. claude_mpm/ticket_wrapper.py +2 -2
  817. claude_mpm/tools/__init__.py +10 -0
  818. claude_mpm/tools/__main__.py +208 -0
  819. claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
  820. claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
  821. claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
  822. claude_mpm/tools/code_tree_analyzer/core.py +380 -0
  823. claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
  824. claude_mpm/tools/code_tree_analyzer/events.py +168 -0
  825. claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
  826. claude_mpm/tools/code_tree_analyzer/models.py +39 -0
  827. claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
  828. claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
  829. claude_mpm/tools/code_tree_builder.py +631 -0
  830. claude_mpm/tools/code_tree_events.py +420 -0
  831. claude_mpm/tools/socketio_debug.py +671 -0
  832. claude_mpm/utils/__init__.py +8 -8
  833. claude_mpm/utils/agent_dependency_loader.py +1090 -0
  834. claude_mpm/utils/agent_filters.py +261 -0
  835. claude_mpm/utils/common.py +544 -0
  836. claude_mpm/utils/config_manager.py +168 -126
  837. claude_mpm/utils/console.py +11 -0
  838. claude_mpm/utils/database_connector.py +298 -0
  839. claude_mpm/utils/dependency_cache.py +373 -0
  840. claude_mpm/utils/dependency_manager.py +60 -59
  841. claude_mpm/utils/dependency_strategies.py +381 -0
  842. claude_mpm/utils/display_helper.py +260 -0
  843. claude_mpm/utils/environment_context.py +313 -0
  844. claude_mpm/utils/error_handler.py +78 -66
  845. claude_mpm/utils/file_utils.py +305 -0
  846. claude_mpm/utils/framework_detection.py +12 -11
  847. claude_mpm/utils/git_analyzer.py +407 -0
  848. claude_mpm/utils/gitignore.py +244 -0
  849. claude_mpm/utils/import_migration_example.py +12 -60
  850. claude_mpm/utils/imports.py +48 -45
  851. claude_mpm/utils/log_cleanup.py +627 -0
  852. claude_mpm/utils/migration.py +372 -0
  853. claude_mpm/utils/path_operations.py +110 -104
  854. claude_mpm/utils/progress.py +387 -0
  855. claude_mpm/utils/robust_installer.py +823 -0
  856. claude_mpm/utils/session_logging.py +121 -0
  857. claude_mpm/utils/structured_questions.py +619 -0
  858. claude_mpm/utils/subprocess_utils.py +343 -0
  859. claude_mpm/validation/__init__.py +1 -1
  860. claude_mpm/validation/agent_validator.py +214 -108
  861. claude_mpm/validation/frontmatter_validator.py +252 -0
  862. claude_mpm-5.4.55.dist-info/METADATA +999 -0
  863. claude_mpm-5.4.55.dist-info/RECORD +868 -0
  864. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/entry_points.txt +1 -3
  865. claude_mpm-5.4.55.dist-info/licenses/LICENSE +94 -0
  866. claude_mpm-5.4.55.dist-info/licenses/LICENSE-FAQ.md +153 -0
  867. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -88
  868. claude_mpm/agents/INSTRUCTIONS.md +0 -352
  869. claude_mpm/agents/backups/INSTRUCTIONS.md +0 -352
  870. claude_mpm/agents/base_agent_loader.py +0 -529
  871. claude_mpm/agents/schema/agent_schema.json +0 -314
  872. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -36
  873. claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -46
  874. claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -45
  875. claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -49
  876. claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -46
  877. claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -45
  878. claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -49
  879. claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -46
  880. claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -46
  881. claude_mpm/agents/templates/data_engineer.json +0 -110
  882. claude_mpm/agents/templates/documentation.json +0 -109
  883. claude_mpm/agents/templates/engineer.json +0 -113
  884. claude_mpm/agents/templates/ops.json +0 -109
  885. claude_mpm/agents/templates/pm.json +0 -25
  886. claude_mpm/agents/templates/qa.json +0 -111
  887. claude_mpm/agents/templates/research.json +0 -65
  888. claude_mpm/agents/templates/security.json +0 -113
  889. claude_mpm/agents/templates/test_integration.json +0 -112
  890. claude_mpm/agents/templates/version_control.json +0 -107
  891. claude_mpm/cli/commands/ui.py +0 -57
  892. claude_mpm/core/simple_runner.py +0 -1046
  893. claude_mpm/dashboard/open_dashboard.py +0 -34
  894. claude_mpm/deployment_paths.py +0 -261
  895. claude_mpm/hooks/builtin/__init__.py +0 -1
  896. claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
  897. claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
  898. claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
  899. claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
  900. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
  901. claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
  902. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
  903. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
  904. claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
  905. claude_mpm/orchestration/__init__.py +0 -6
  906. claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
  907. claude_mpm/orchestration/archive/factory.py +0 -215
  908. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
  909. claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
  910. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
  911. claude_mpm/orchestration/archive/orchestrator.py +0 -501
  912. claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
  913. claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
  914. claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
  915. claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
  916. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
  917. claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
  918. claude_mpm/schemas/workflow_validator.py +0 -411
  919. claude_mpm/services/agent_deployment.py +0 -1534
  920. claude_mpm/services/agent_lifecycle_manager.py +0 -1169
  921. claude_mpm/services/agent_memory_manager.py +0 -1415
  922. claude_mpm/services/agent_registry.py +0 -676
  923. claude_mpm/services/deployed_agent_discovery.py +0 -226
  924. claude_mpm/services/framework_agent_loader.py +0 -337
  925. claude_mpm/services/framework_claude_md_generator.py +0 -621
  926. claude_mpm/services/health_monitor.py +0 -892
  927. claude_mpm/services/memory_router.py +0 -538
  928. claude_mpm/services/parent_directory_manager/__init__.py +0 -577
  929. claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
  930. claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
  931. claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
  932. claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
  933. claude_mpm/services/parent_directory_manager/operations.py +0 -186
  934. claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
  935. claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
  936. claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
  937. claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
  938. claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
  939. claude_mpm/services/standalone_socketio_server.py +0 -1300
  940. claude_mpm/services/ticket_manager_di.py +0 -318
  941. claude_mpm/services/ticketing_service_original.py +0 -508
  942. claude_mpm/ui/__init__.py +0 -1
  943. claude_mpm/ui/rich_terminal_ui.py +0 -295
  944. claude_mpm/ui/terminal_ui.py +0 -328
  945. claude_mpm/utils/paths.py +0 -289
  946. claude_mpm-3.4.10.dist-info/METADATA +0 -183
  947. claude_mpm-3.4.10.dist-info/RECORD +0 -201
  948. claude_mpm-3.4.10.dist-info/licenses/LICENSE +0 -21
  949. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/WHEEL +0 -0
  950. {claude_mpm-3.4.10.dist-info → claude_mpm-5.4.55.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,937 @@
1
+ """
2
+ Mermaid Diagram Generator Service for Claude MPM
3
+ ================================================
4
+
5
+ This service generates Mermaid diagrams for code visualization based on
6
+ analysis results from the Code Analyzer agent.
7
+
8
+ WHY: Visual representations of code structure help developers understand
9
+ complex codebases more quickly. Mermaid diagrams can be rendered in
10
+ documentation and provide interactive exploration capabilities.
11
+
12
+ DESIGN DECISION: We support multiple diagram types (entry points, module
13
+ dependencies, class hierarchies, and call graphs) to cover different
14
+ aspects of code structure analysis.
15
+ """
16
+
17
+ import re
18
+ from dataclasses import dataclass
19
+ from enum import Enum
20
+ from pathlib import Path
21
+ from typing import Any, Dict, List, Optional, Set, Tuple
22
+
23
+ from claude_mpm.services.core.base import SyncBaseService
24
+
25
+
26
+ class DiagramType(Enum):
27
+ """Supported Mermaid diagram types for code visualization."""
28
+
29
+ ENTRY_POINTS = "entry_points"
30
+ MODULE_DEPS = "module_deps"
31
+ CLASS_HIERARCHY = "class_hierarchy"
32
+ CALL_GRAPH = "call_graph"
33
+
34
+
35
+ @dataclass
36
+ class DiagramConfig:
37
+ """Configuration for diagram generation."""
38
+
39
+ title: Optional[str] = None
40
+ direction: str = "TB" # Top-Bottom by default
41
+ theme: str = "default"
42
+ max_depth: int = 5
43
+ include_external: bool = False
44
+ show_parameters: bool = True
45
+ show_return_types: bool = True
46
+
47
+
48
+ class MermaidGeneratorService(SyncBaseService):
49
+ """
50
+ Service for generating Mermaid diagrams from code analysis results.
51
+
52
+ This service provides methods to generate various types of diagrams
53
+ including entry points, module dependencies, class hierarchies, and
54
+ call graphs.
55
+ """
56
+
57
+ def __init__(self, config: Optional[Dict[str, Any]] = None):
58
+ """Initialize the Mermaid generator service."""
59
+ super().__init__(service_name="MermaidGeneratorService", config=config)
60
+ self._node_id_counter = 0
61
+ self._node_id_cache: Dict[str, str] = {}
62
+ self._reserved_keywords = {
63
+ "graph",
64
+ "subgraph",
65
+ "end",
66
+ "class",
67
+ "classDef",
68
+ "click",
69
+ "style",
70
+ "linkStyle",
71
+ "interpolate",
72
+ "flowchart",
73
+ "pie",
74
+ "sequenceDiagram",
75
+ "gantt",
76
+ "stateDiagram",
77
+ "erDiagram",
78
+ "journey",
79
+ "gitGraph",
80
+ "mindmap",
81
+ "timeline",
82
+ "quadrantChart",
83
+ "sankey",
84
+ "xychart",
85
+ "block",
86
+ "start",
87
+ "stop",
88
+ "operation",
89
+ "subroutine",
90
+ "condition",
91
+ "inputoutput",
92
+ "parallel",
93
+ "database",
94
+ }
95
+
96
+ def initialize(self) -> bool:
97
+ """Initialize the service."""
98
+ try:
99
+ self.log_info("Initializing MermaidGeneratorService")
100
+ self._initialized = True
101
+ return True
102
+ except Exception as e:
103
+ self.log_error(f"Failed to initialize: {e}")
104
+ return False
105
+
106
+ def shutdown(self) -> None:
107
+ """Shutdown the service."""
108
+ self.log_info("Shutting down MermaidGeneratorService")
109
+ self._node_id_cache.clear()
110
+ self._shutdown = True
111
+
112
+ def generate_diagram(
113
+ self,
114
+ diagram_type: DiagramType,
115
+ analysis_results: Dict[str, Any],
116
+ config: Optional[DiagramConfig] = None,
117
+ ) -> str:
118
+ """
119
+ Generate a Mermaid diagram based on analysis results.
120
+
121
+ Args:
122
+ diagram_type: Type of diagram to generate
123
+ analysis_results: Code analysis results from Code Analyzer agent
124
+ config: Optional configuration for diagram generation
125
+
126
+ Returns:
127
+ Mermaid diagram syntax as string
128
+
129
+ Raises:
130
+ ValueError: If diagram type is not supported or data is invalid
131
+ """
132
+ if not self._initialized:
133
+ raise RuntimeError("Service not initialized")
134
+
135
+ config = config or DiagramConfig()
136
+
137
+ # Reset node ID cache for each new diagram
138
+ self._node_id_cache.clear()
139
+ self._node_id_counter = 0
140
+
141
+ try:
142
+ if diagram_type == DiagramType.ENTRY_POINTS:
143
+ return self._generate_entry_points_diagram(analysis_results, config)
144
+ if diagram_type == DiagramType.MODULE_DEPS:
145
+ return self._generate_module_deps_diagram(analysis_results, config)
146
+ if diagram_type == DiagramType.CLASS_HIERARCHY:
147
+ return self._generate_class_hierarchy_diagram(analysis_results, config)
148
+ if diagram_type == DiagramType.CALL_GRAPH:
149
+ return self._generate_call_graph_diagram(analysis_results, config)
150
+ raise ValueError(f"Unsupported diagram type: {diagram_type}")
151
+ except Exception as e:
152
+ # Handle both DiagramType enums and plain strings
153
+ type_name = (
154
+ diagram_type.value
155
+ if hasattr(diagram_type, "value")
156
+ else str(diagram_type)
157
+ )
158
+ self.log_error(f"Failed to generate {type_name} diagram: {e}")
159
+ raise
160
+
161
+ def _generate_entry_points_diagram(
162
+ self, analysis_results: Dict[str, Any], config: DiagramConfig
163
+ ) -> str:
164
+ """Generate entry points flow diagram."""
165
+ lines = []
166
+ title = config.title or "Application Entry Points"
167
+
168
+ # Start diagram
169
+ lines.append(f"flowchart {config.direction}")
170
+ lines.append(f" %% {title}")
171
+ lines.append("")
172
+
173
+ # Get entry points from analysis results
174
+ entry_points = analysis_results.get("entry_points", {})
175
+
176
+ if not entry_points:
177
+ lines.append(" NoEntryPoints[No entry points found]")
178
+ return "\n".join(lines)
179
+
180
+ # Create start node
181
+ lines.append(" Start([Application Start])")
182
+ lines.append("")
183
+
184
+ # Process each entry point
185
+ for entry_type, entries in entry_points.items():
186
+ if not entries:
187
+ continue
188
+
189
+ # Create subgraph for each entry type
190
+ subgraph_id = self._sanitize_node_id(f"subgraph_{entry_type}")
191
+ lines.append(
192
+ f" subgraph {subgraph_id}[{entry_type.replace('_', ' ').title()}]"
193
+ )
194
+
195
+ for entry in entries:
196
+ if isinstance(entry, dict):
197
+ file_path = entry.get("file", "")
198
+ func_name = entry.get("function", "main")
199
+ line_num = entry.get("line", 0)
200
+
201
+ # Handle None or invalid file paths
202
+ if not file_path or not isinstance(file_path, (str, Path)):
203
+ file_path = "unknown"
204
+
205
+ # Create node for entry point
206
+ node_id = self._get_node_id(f"{file_path}:{func_name}")
207
+ try:
208
+ path_name = (
209
+ Path(file_path).name
210
+ if file_path != "unknown"
211
+ else "unknown"
212
+ )
213
+ except (TypeError, OSError):
214
+ path_name = "unknown"
215
+ node_label = self._escape_label(f"{path_name}::{func_name}")
216
+
217
+ if line_num:
218
+ node_label += f" (L{line_num})"
219
+
220
+ lines.append(f" {node_id}[{node_label}]")
221
+
222
+ lines.append(" end")
223
+ lines.append("")
224
+
225
+ # Connect start to entry points
226
+ for entry_type, entries in entry_points.items():
227
+ if entries:
228
+ for entry in entries[:3]: # Limit connections to avoid clutter
229
+ if isinstance(entry, dict):
230
+ file_path = entry.get("file", "")
231
+ func_name = entry.get("function", "main")
232
+
233
+ # Handle None or invalid file paths
234
+ if not file_path or not isinstance(file_path, (str, Path)):
235
+ file_path = "unknown"
236
+
237
+ node_id = self._get_node_id(f"{file_path}:{func_name}")
238
+ lines.append(f" Start --> {node_id}")
239
+
240
+ # Add styling
241
+ lines.append("")
242
+ lines.append(
243
+ " classDef entryPoint fill:#90EE90,stroke:#333,stroke-width:2px"
244
+ )
245
+ lines.append(" classDef startNode fill:#FFD700,stroke:#333,stroke-width:3px")
246
+ lines.append(" class Start startNode")
247
+
248
+ return "\n".join(lines)
249
+
250
+ def _generate_module_deps_diagram(
251
+ self, analysis_results: Dict[str, Any], config: DiagramConfig
252
+ ) -> str:
253
+ """Generate module dependency diagram."""
254
+ lines = []
255
+ title = config.title or "Module Dependencies"
256
+
257
+ # Start diagram
258
+ lines.append(f"flowchart {config.direction}")
259
+ lines.append(f" %% {title}")
260
+ lines.append("")
261
+
262
+ # Get dependencies from analysis results
263
+ dependencies = analysis_results.get("dependencies", {})
264
+ imports_data = analysis_results.get("imports", {})
265
+
266
+ # Handle None values
267
+ if dependencies is None:
268
+ dependencies = {}
269
+ if imports_data is None:
270
+ imports_data = {}
271
+
272
+ # Check if we have any meaningful data
273
+ has_deps = bool(dependencies and any(v for v in dependencies.values() if v))
274
+ has_imports = bool(imports_data and any(v for v in imports_data.values() if v))
275
+
276
+ if not has_deps and not has_imports:
277
+ lines.append(" NoDeps[No dependencies found]")
278
+ return "\n".join(lines)
279
+
280
+ # Track all modules and their relationships
281
+ modules: Set[str] = set()
282
+ edges: List[Tuple[str, str, str]] = [] # (from, to, label)
283
+
284
+ # Process dependencies
285
+ for module, deps in dependencies.items():
286
+ module_name = self._extract_module_name(module)
287
+ modules.add(module_name)
288
+
289
+ if isinstance(deps, list):
290
+ for dep in deps:
291
+ dep_name = self._extract_module_name(str(dep))
292
+ if not config.include_external and self._is_external_module(
293
+ dep_name
294
+ ):
295
+ continue
296
+ modules.add(dep_name)
297
+ edges.append((module_name, dep_name, "depends"))
298
+
299
+ # Process imports
300
+ for file_path, imports in imports_data.items():
301
+ module_name = self._extract_module_name(file_path)
302
+ modules.add(module_name)
303
+
304
+ if isinstance(imports, list):
305
+ for imp in imports:
306
+ if isinstance(imp, dict):
307
+ import_from = imp.get("from", imp.get("module", ""))
308
+ if import_from:
309
+ import_name = self._extract_module_name(import_from)
310
+ if not config.include_external and self._is_external_module(
311
+ import_name
312
+ ):
313
+ continue
314
+ modules.add(import_name)
315
+ edges.append((module_name, import_name, "imports"))
316
+
317
+ # Create nodes for all modules
318
+ external_modules = set()
319
+ internal_modules = set()
320
+
321
+ for module in modules:
322
+ node_id = self._get_node_id(module)
323
+ node_label = self._escape_label(module)
324
+
325
+ if self._is_external_module(module):
326
+ lines.append(f" {node_id}[({node_label})]")
327
+ external_modules.add(node_id)
328
+ else:
329
+ lines.append(f" {node_id}[{node_label}]")
330
+ internal_modules.add(node_id)
331
+
332
+ lines.append("")
333
+
334
+ # Create edges
335
+ for from_module, to_module, rel_type in edges:
336
+ from_id = self._get_node_id(from_module)
337
+ to_id = self._get_node_id(to_module)
338
+
339
+ if rel_type == "imports":
340
+ lines.append(f" {from_id} --> {to_id}")
341
+ else:
342
+ lines.append(f" {from_id} -.-> {to_id}")
343
+
344
+ # Add styling
345
+ lines.append("")
346
+ lines.append(" classDef internal fill:#87CEEB,stroke:#333,stroke-width:2px")
347
+ lines.append(" classDef external fill:#FFB6C1,stroke:#333,stroke-width:1px")
348
+
349
+ if internal_modules:
350
+ lines.append(f" class {','.join(internal_modules)} internal")
351
+ if external_modules:
352
+ lines.append(f" class {','.join(external_modules)} external")
353
+
354
+ return "\n".join(lines)
355
+
356
+ def _generate_class_hierarchy_diagram(
357
+ self, analysis_results: Dict[str, Any], config: DiagramConfig
358
+ ) -> str:
359
+ """Generate class hierarchy diagram."""
360
+ lines = []
361
+ title = config.title or "Class Hierarchy"
362
+
363
+ # Start diagram
364
+ lines.append("classDiagram")
365
+ lines.append(f" %% {title}")
366
+ lines.append("")
367
+
368
+ # Get classes from analysis results
369
+ classes = analysis_results.get("classes", {})
370
+
371
+ if not classes:
372
+ lines.append(" class NoClasses {")
373
+ lines.append(" <<placeholder>>")
374
+ lines.append(" No classes found")
375
+ lines.append(" }")
376
+ return "\n".join(lines)
377
+
378
+ # Process each class
379
+ for class_name, class_info in classes.items():
380
+ if not isinstance(class_info, dict):
381
+ continue
382
+
383
+ safe_name = self._sanitize_class_name(class_name)
384
+
385
+ # Define class
386
+ lines.append(f" class {safe_name} {{")
387
+
388
+ # Add class type annotation if it's special
389
+ if class_info.get("is_abstract"):
390
+ lines.append(" <<abstract>>")
391
+ elif class_info.get("is_interface"):
392
+ lines.append(" <<interface>>")
393
+ elif class_info.get("is_enum"):
394
+ lines.append(" <<enumeration>>")
395
+
396
+ # Add attributes
397
+ attributes = class_info.get("attributes", [])
398
+ if attributes:
399
+ for attr in attributes[:10]: # Limit to avoid clutter
400
+ if isinstance(attr, dict):
401
+ attr_name = attr.get("name", "")
402
+ attr_type = attr.get("type", "Any")
403
+ visibility = attr.get("visibility", "+")
404
+ if config.show_return_types:
405
+ lines.append(
406
+ f" {visibility}{attr_name}: {attr_type}"
407
+ )
408
+ else:
409
+ lines.append(f" {visibility}{attr_name}")
410
+ elif isinstance(attr, str):
411
+ lines.append(f" +{attr}")
412
+
413
+ # Add methods
414
+ methods = class_info.get("methods", [])
415
+ if methods:
416
+ for method in methods[:10]: # Limit to avoid clutter
417
+ if isinstance(method, dict):
418
+ method_name = method.get("name", "")
419
+ params = method.get("parameters", [])
420
+ return_type = method.get("return_type", "None")
421
+ visibility = method.get("visibility", "+")
422
+
423
+ if config.show_parameters and params:
424
+ param_str = (
425
+ ", ".join(params)
426
+ if isinstance(params, list)
427
+ else str(params)
428
+ )
429
+ method_sig = f"{method_name}({param_str})"
430
+ else:
431
+ method_sig = f"{method_name}()"
432
+
433
+ if config.show_return_types:
434
+ lines.append(
435
+ f" {visibility}{method_sig}: {return_type}"
436
+ )
437
+ else:
438
+ lines.append(f" {visibility}{method_sig}")
439
+ elif isinstance(method, str):
440
+ lines.append(f" +{method}()")
441
+
442
+ lines.append(" }")
443
+ lines.append("")
444
+
445
+ # Add relationships
446
+ for class_name, class_info in classes.items():
447
+ if not isinstance(class_info, dict):
448
+ continue
449
+
450
+ safe_name = self._sanitize_class_name(class_name)
451
+
452
+ # Inheritance relationships
453
+ bases = class_info.get("bases", [])
454
+ if bases:
455
+ for base in bases:
456
+ if isinstance(base, str):
457
+ safe_base = self._sanitize_class_name(base)
458
+ if safe_base in [self._sanitize_class_name(c) for c in classes]:
459
+ lines.append(f" {safe_base} <|-- {safe_name}")
460
+
461
+ # Composition relationships
462
+ compositions = class_info.get("compositions", [])
463
+ if compositions:
464
+ for comp in compositions:
465
+ if isinstance(comp, str):
466
+ safe_comp = self._sanitize_class_name(comp)
467
+ if safe_comp in [self._sanitize_class_name(c) for c in classes]:
468
+ lines.append(f" {safe_name} *-- {safe_comp}")
469
+
470
+ # Association relationships
471
+ associations = class_info.get("associations", [])
472
+ if associations:
473
+ for assoc in associations:
474
+ if isinstance(assoc, str):
475
+ safe_assoc = self._sanitize_class_name(assoc)
476
+ if safe_assoc in [
477
+ self._sanitize_class_name(c) for c in classes
478
+ ]:
479
+ lines.append(f" {safe_name} --> {safe_assoc}")
480
+
481
+ return "\n".join(lines)
482
+
483
+ def _generate_call_graph_diagram(
484
+ self, analysis_results: Dict[str, Any], config: DiagramConfig
485
+ ) -> str:
486
+ """Generate function call graph diagram."""
487
+ lines = []
488
+ title = config.title or "Function Call Graph"
489
+
490
+ # Start diagram
491
+ lines.append(f"flowchart {config.direction}")
492
+ lines.append(f" %% {title}")
493
+ lines.append("")
494
+
495
+ # Get functions and call relationships
496
+ functions = analysis_results.get("functions", {})
497
+ call_graph = analysis_results.get("call_graph", {})
498
+
499
+ if not functions and not call_graph:
500
+ lines.append(" NoFunctions[No functions found]")
501
+ return "\n".join(lines)
502
+
503
+ # Track all functions and their calls
504
+ all_functions: Set[str] = set()
505
+ calls: List[Tuple[str, str, Optional[str]]] = [] # (caller, callee, label)
506
+
507
+ # Process call graph
508
+ for caller, callees in call_graph.items():
509
+ all_functions.add(caller)
510
+
511
+ if isinstance(callees, list):
512
+ for callee in callees:
513
+ if isinstance(callee, dict):
514
+ func_name = callee.get("function", callee.get("name", ""))
515
+ if func_name:
516
+ all_functions.add(func_name)
517
+ call_count = callee.get("count", 0)
518
+ label = str(call_count) if call_count > 1 else None
519
+ calls.append((caller, func_name, label))
520
+ elif isinstance(callee, str):
521
+ all_functions.add(callee)
522
+ calls.append((caller, callee, None))
523
+
524
+ # Process functions to add those not in call graph
525
+ for func_name, func_info in functions.items():
526
+ all_functions.add(func_name)
527
+
528
+ # Check for calls within function
529
+ if isinstance(func_info, dict):
530
+ func_calls = func_info.get("calls", [])
531
+ for call in func_calls:
532
+ if isinstance(call, str):
533
+ all_functions.add(call)
534
+ calls.append((func_name, call, None))
535
+
536
+ # Create nodes for all functions
537
+ entry_functions = set()
538
+ regular_functions = set()
539
+
540
+ for func in all_functions:
541
+ node_id = self._get_node_id(func)
542
+ node_label = self._escape_label(func)
543
+
544
+ # Check if this is an entry point
545
+ is_entry = func in ["main", "__main__", "run", "start", "execute"]
546
+
547
+ if is_entry:
548
+ lines.append(f" {node_id}[/{node_label}/]")
549
+ entry_functions.add(node_id)
550
+ # Check if function has specific characteristics
551
+ elif func.startswith("_") and not func.startswith("__"):
552
+ lines.append(f" {node_id}[{node_label}]:::private")
553
+ elif func.startswith("__") and func.endswith("__"):
554
+ lines.append(f" {node_id}[{node_label}]:::magic")
555
+ else:
556
+ lines.append(f" {node_id}[{node_label}]")
557
+ regular_functions.add(node_id)
558
+
559
+ lines.append("")
560
+
561
+ # Create edges for calls
562
+ for caller, callee, label in calls:
563
+ caller_id = self._get_node_id(caller)
564
+ callee_id = self._get_node_id(callee)
565
+
566
+ if label:
567
+ lines.append(f" {caller_id} -->|{label}| {callee_id}")
568
+ else:
569
+ lines.append(f" {caller_id} --> {callee_id}")
570
+
571
+ # Add styling
572
+ lines.append("")
573
+ lines.append(" classDef entry fill:#90EE90,stroke:#333,stroke-width:3px")
574
+ lines.append(" classDef regular fill:#87CEEB,stroke:#333,stroke-width:2px")
575
+ lines.append(" classDef private fill:#FFE4B5,stroke:#333,stroke-width:1px")
576
+ lines.append(" classDef magic fill:#DDA0DD,stroke:#333,stroke-width:2px")
577
+
578
+ if entry_functions:
579
+ lines.append(f" class {','.join(entry_functions)} entry")
580
+ if regular_functions:
581
+ lines.append(f" class {','.join(regular_functions)} regular")
582
+
583
+ return "\n".join(lines)
584
+
585
+ def _sanitize_node_id(self, identifier: str) -> str:
586
+ """
587
+ Sanitize an identifier to be a valid Mermaid node ID.
588
+
589
+ Args:
590
+ identifier: Raw identifier string
591
+
592
+ Returns:
593
+ Sanitized identifier safe for use as node ID
594
+ """
595
+ # Replace common problematic characters
596
+ sanitized = identifier.replace(".", "_")
597
+ sanitized = sanitized.replace("/", "_")
598
+ sanitized = sanitized.replace("\\", "_")
599
+ sanitized = sanitized.replace("-", "_")
600
+ sanitized = sanitized.replace(" ", "_")
601
+ sanitized = sanitized.replace(":", "_")
602
+ sanitized = sanitized.replace("(", "_")
603
+ sanitized = sanitized.replace(")", "_")
604
+ sanitized = sanitized.replace("[", "_")
605
+ sanitized = sanitized.replace("]", "_")
606
+ sanitized = sanitized.replace("{", "_")
607
+ sanitized = sanitized.replace("}", "_")
608
+ sanitized = sanitized.replace("<", "_")
609
+ sanitized = sanitized.replace(">", "_")
610
+ sanitized = sanitized.replace(",", "_")
611
+ sanitized = sanitized.replace(";", "_")
612
+ sanitized = sanitized.replace("'", "_")
613
+ sanitized = sanitized.replace('"', "_")
614
+ sanitized = sanitized.replace("`", "_")
615
+ sanitized = sanitized.replace("@", "_")
616
+ sanitized = sanitized.replace("#", "_")
617
+ sanitized = sanitized.replace("$", "_")
618
+ sanitized = sanitized.replace("%", "_")
619
+ sanitized = sanitized.replace("^", "_")
620
+ sanitized = sanitized.replace("&", "_")
621
+ sanitized = sanitized.replace("*", "_")
622
+ sanitized = sanitized.replace("+", "_")
623
+ sanitized = sanitized.replace("=", "_")
624
+ sanitized = sanitized.replace("|", "_")
625
+ sanitized = sanitized.replace("~", "_")
626
+ sanitized = sanitized.replace("!", "_")
627
+ sanitized = sanitized.replace("?", "_")
628
+
629
+ # Remove consecutive underscores
630
+ sanitized = re.sub(r"_+", "_", sanitized)
631
+
632
+ # Remove leading/trailing underscores
633
+ sanitized = sanitized.strip("_")
634
+
635
+ # Ensure it doesn't start with a number
636
+ if sanitized and sanitized[0].isdigit():
637
+ sanitized = f"n_{sanitized}"
638
+
639
+ # Ensure it's not empty
640
+ if not sanitized:
641
+ sanitized = "node"
642
+
643
+ # Check against reserved keywords
644
+ if sanitized.lower() in self._reserved_keywords:
645
+ sanitized = f"{sanitized}_node"
646
+
647
+ return sanitized
648
+
649
+ def _sanitize_class_name(self, class_name: str) -> str:
650
+ """
651
+ Sanitize a class name for use in class diagrams.
652
+
653
+ Args:
654
+ class_name: Raw class name
655
+
656
+ Returns:
657
+ Sanitized class name
658
+ """
659
+ # For class diagrams, we need simpler names
660
+ sanitized = re.sub(r"[^a-zA-Z0-9_]", "", class_name)
661
+
662
+ # Ensure it doesn't start with a number
663
+ if sanitized and sanitized[0].isdigit():
664
+ sanitized = f"C_{sanitized}"
665
+
666
+ # Ensure it's not empty
667
+ if not sanitized:
668
+ sanitized = "Class"
669
+
670
+ return sanitized
671
+
672
+ def _escape_label(self, label: str) -> str:
673
+ """
674
+ Escape special characters in labels for Mermaid.
675
+
676
+ Args:
677
+ label: Raw label text
678
+
679
+ Returns:
680
+ Escaped label safe for Mermaid
681
+ """
682
+ # Escape ampersand first to avoid double-escaping
683
+ escaped = label.replace("&", "&amp;")
684
+ # Then escape other special characters
685
+ escaped = escaped.replace('"', '\\"')
686
+ escaped = escaped.replace("'", "\\'")
687
+ escaped = escaped.replace("`", "\\`")
688
+ escaped = escaped.replace("[", "&#91;")
689
+ escaped = escaped.replace("]", "&#93;")
690
+ escaped = escaped.replace("{", "&#123;")
691
+ escaped = escaped.replace("}", "&#125;")
692
+ escaped = escaped.replace("<", "&lt;")
693
+ escaped = escaped.replace(">", "&gt;")
694
+ escaped = escaped.replace("|", "&#124;")
695
+
696
+ # Limit length to avoid overly long labels
697
+ if len(escaped) > 50:
698
+ escaped = escaped[:47] + "..."
699
+
700
+ return escaped
701
+
702
+ def _get_node_id(self, identifier: str) -> str:
703
+ """
704
+ Get or create a unique node ID for an identifier.
705
+
706
+ Args:
707
+ identifier: Original identifier
708
+
709
+ Returns:
710
+ Unique node ID
711
+ """
712
+ # Always return the cached ID for the same identifier
713
+ if identifier in self._node_id_cache:
714
+ return self._node_id_cache[identifier]
715
+
716
+ # Generate a unique ID
717
+ sanitized = self._sanitize_node_id(identifier)
718
+
719
+ # Ensure uniqueness across all generated IDs
720
+ base_id = sanitized
721
+ counter = 1
722
+ used_ids = set(self._node_id_cache.values())
723
+ while sanitized in used_ids:
724
+ sanitized = f"{base_id}_{counter}"
725
+ counter += 1
726
+
727
+ self._node_id_cache[identifier] = sanitized
728
+ return sanitized
729
+
730
+ def _extract_module_name(self, path_or_module: str) -> str:
731
+ """
732
+ Extract a clean module name from a file path or module string.
733
+
734
+ Args:
735
+ path_or_module: File path or module name
736
+
737
+ Returns:
738
+ Clean module name
739
+ """
740
+ # Remove common file extensions
741
+ clean = re.sub(r"\.(py|js|ts|java|cpp|c|h|hpp)$", "", path_or_module)
742
+
743
+ # Convert path separators to dots
744
+ clean = clean.replace("/", ".")
745
+ clean = clean.replace("\\", ".")
746
+
747
+ # Remove leading dots
748
+ clean = clean.lstrip(".")
749
+
750
+ # Remove common prefixes
751
+ prefixes_to_remove = ["src.", "lib.", "pkg.", "app.", "modules."]
752
+ for prefix in prefixes_to_remove:
753
+ if clean.startswith(prefix):
754
+ clean = clean[len(prefix) :]
755
+
756
+ # Take last few components if too long
757
+ parts = clean.split(".")
758
+ if len(parts) > 3:
759
+ clean = ".".join(parts[-3:])
760
+
761
+ return clean or "module"
762
+
763
+ def _is_external_module(self, module_name: str) -> bool:
764
+ """
765
+ Check if a module is external (third-party).
766
+
767
+ Args:
768
+ module_name: Module name to check
769
+
770
+ Returns:
771
+ True if module appears to be external
772
+ """
773
+ # Common external/system module patterns
774
+ external_patterns = [
775
+ r"^(sys|os|re|json|typing|pathlib|datetime|collections|itertools)",
776
+ r"^(numpy|pandas|matplotlib|scipy|sklearn|tensorflow|torch|keras)",
777
+ r"^(requests|urllib|http|flask|django|fastapi|aiohttp)",
778
+ r"^(pytest|unittest|mock|coverage)",
779
+ r"^(logging|warnings|traceback|inspect)",
780
+ r"^(asyncio|threading|multiprocessing|concurrent)",
781
+ r"^(boto3|azure|google|aws)",
782
+ ]
783
+
784
+ for pattern in external_patterns:
785
+ if re.match(pattern, module_name):
786
+ return True
787
+
788
+ # Check for version numbers (common in external packages)
789
+ if re.search(r"\d+\.\d+", module_name):
790
+ return True
791
+
792
+ # Check for common external package naming patterns
793
+ # Single-level modules without dots are often external, but not always
794
+ if module_name.count(".") == 0:
795
+ # Check if it's a known stdlib module or starts with underscore (private)
796
+ if module_name.startswith("_") and not module_name.startswith("__"):
797
+ return True
798
+ # Don't assume all single-level modules are external
799
+ # Let specific pattern matching above handle known external modules
800
+
801
+ return False
802
+
803
+ def validate_mermaid_syntax(self, diagram: str) -> Tuple[bool, Optional[str]]:
804
+ """
805
+ Validate that the generated Mermaid syntax is correct.
806
+
807
+ Args:
808
+ diagram: Mermaid diagram syntax to validate
809
+
810
+ Returns:
811
+ Tuple of (is_valid, error_message)
812
+ """
813
+ try:
814
+ if not diagram or not diagram.strip():
815
+ return False, "Empty diagram"
816
+
817
+ lines = diagram.strip().split("\n")
818
+
819
+ if not lines:
820
+ return False, "Empty diagram"
821
+
822
+ # Find the first non-comment line for diagram type validation
823
+ first_content_line = None
824
+ for line in lines:
825
+ stripped = line.strip()
826
+ if stripped and not stripped.startswith("%%"):
827
+ first_content_line = stripped
828
+ break
829
+
830
+ if not first_content_line:
831
+ return False, "No content found after comments"
832
+
833
+ # Check for valid diagram type declaration
834
+ valid_starts = [
835
+ "graph",
836
+ "flowchart",
837
+ "sequenceDiagram",
838
+ "classDiagram",
839
+ "stateDiagram",
840
+ "erDiagram",
841
+ "gantt",
842
+ "pie",
843
+ "journey",
844
+ "gitGraph",
845
+ "mindmap",
846
+ "timeline",
847
+ "quadrantChart",
848
+ "sankey",
849
+ "xychart",
850
+ "block",
851
+ ]
852
+
853
+ if not any(first_content_line.startswith(start) for start in valid_starts):
854
+ return False, f"Invalid diagram type: {first_content_line}"
855
+
856
+ # Check for balanced brackets and quotes
857
+ open_brackets = diagram.count("[")
858
+ close_brackets = diagram.count("]")
859
+ if open_brackets != close_brackets:
860
+ return (
861
+ False,
862
+ f"Unbalanced brackets: {open_brackets} open, {close_brackets} close",
863
+ )
864
+
865
+ # Check for balanced parentheses
866
+ open_parens = diagram.count("(")
867
+ close_parens = diagram.count(")")
868
+ if open_parens != close_parens:
869
+ return (
870
+ False,
871
+ f"Unbalanced parentheses: {open_parens} open, {close_parens} close",
872
+ )
873
+
874
+ # Check for balanced braces in class diagrams
875
+ if "classDiagram" in first_content_line:
876
+ open_braces = diagram.count("{")
877
+ close_braces = diagram.count("}")
878
+ if open_braces != close_braces:
879
+ return (
880
+ False,
881
+ f"Unbalanced braces: {open_braces} open, {close_braces} close",
882
+ )
883
+
884
+ # Check for valid subgraph blocks
885
+ if "subgraph" in diagram:
886
+ # Only count subgraph declarations (with space after)
887
+ subgraph_pattern = r"\bsubgraph\s+"
888
+ subgraph_count = len(re.findall(subgraph_pattern, diagram))
889
+
890
+ # Count all 'end' statements that close blocks
891
+ end_pattern = r"^\s*end\s*$"
892
+ end_count = len(re.findall(end_pattern, diagram, re.MULTILINE))
893
+
894
+ if subgraph_count > end_count:
895
+ return (
896
+ False,
897
+ f"Unmatched subgraph blocks: {subgraph_count} subgraphs, {end_count} ends",
898
+ )
899
+
900
+ return True, None
901
+
902
+ except Exception as e:
903
+ return False, f"Validation error: {e!s}"
904
+
905
+ def format_diagram_with_metadata(
906
+ self, diagram: str, metadata: Optional[Dict[str, Any]] = None
907
+ ) -> str:
908
+ """
909
+ Format a diagram with metadata comments.
910
+
911
+ Args:
912
+ diagram: Mermaid diagram syntax
913
+ metadata: Optional metadata to include
914
+
915
+ Returns:
916
+ Formatted diagram with metadata
917
+ """
918
+ lines = []
919
+
920
+ # Add metadata as comments if provided
921
+ if metadata:
922
+ lines.append("%% Diagram Metadata")
923
+ lines.append(f"%% Generated: {metadata.get('timestamp', 'Unknown')}")
924
+ lines.append(f"%% Source: {metadata.get('source', 'Code Analysis')}")
925
+ lines.append(f"%% Type: {metadata.get('type', 'Unknown')}")
926
+
927
+ if "stats" in metadata:
928
+ lines.append("%% Statistics:")
929
+ for key, value in metadata["stats"].items():
930
+ lines.append(f"%% {key}: {value}")
931
+
932
+ lines.append("")
933
+
934
+ # Add the diagram
935
+ lines.append(diagram)
936
+
937
+ return "\n".join(lines)