agentic-mermaid 0.1.0 → 0.1.2

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 (333) hide show
  1. package/CHANGELOG.md +149 -4
  2. package/LICENSES/Apache-2.0.txt +202 -0
  3. package/README.md +25 -32
  4. package/THIRD_PARTY_NOTICES.md +29 -0
  5. package/assets/fonts/FONT-LICENSES.md +9 -5
  6. package/assets/fonts/Inter-Bold.ttf +0 -0
  7. package/assets/fonts/Inter-Medium.ttf +0 -0
  8. package/assets/fonts/Inter-Regular.ttf +0 -0
  9. package/assets/fonts/Inter-SemiBold.ttf +0 -0
  10. package/dist/agent-core.d.ts +463 -0
  11. package/dist/agent-core.js +397 -0
  12. package/dist/agent.d.ts +81 -1822
  13. package/dist/agent.js +336 -36839
  14. package/dist/agentic-mermaid-mcp.js +7 -37908
  15. package/dist/am.js +33638 -36261
  16. package/dist/chunk-4QECACIA.js +4702 -0
  17. package/dist/chunk-CDPKJ2BQ.js +37 -0
  18. package/dist/chunk-QKDLMOJJ.js +3487 -0
  19. package/dist/chunk-WI35L7IR.js +615 -0
  20. package/dist/chunk-WN3YDOBG.js +149 -0
  21. package/dist/chunk-ZYMMKQ3I.js +62637 -0
  22. package/dist/index-D54dqSdC.d.ts +6777 -0
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +310 -32836
  25. package/dist/mcp-cli-SBQSTJFC.js +17 -0
  26. package/docs/README.md +14 -6
  27. package/docs/schemas/style-spec.schema.json +1221 -30
  28. package/examples/styles/catalog.json +54 -0
  29. package/examples/styles/cloudflare-workers-inspired-prototype.mmd +9 -0
  30. package/examples/styles/cloudflare-workers-inspired-prototype.style.json +110 -0
  31. package/examples/styles/cupertino-prototype.mmd +10 -0
  32. package/examples/styles/cupertino-prototype.style.json +63 -0
  33. package/examples/styles/mid-century-report.style.json +2 -2
  34. package/examples/styles/star-chart-atlas.style.json +2 -1
  35. package/examples/styles/transit-route-map.style.json +2 -2
  36. package/examples/styles/vercel-inspired-prototype.mmd +6 -0
  37. package/examples/styles/vercel-inspired-prototype.style.json +87 -0
  38. package/package.json +70 -43
  39. package/server.json +41 -0
  40. package/skills/agentic-mermaid-diagram-workflow/SKILL.md +17 -36
  41. package/skills/agentic-mermaid-diagram-workflow/references/cli.md +4 -5
  42. package/skills/agentic-mermaid-diagram-workflow/references/code-mode.md +15 -31
  43. package/skills/agentic-mermaid-diagram-workflow/references/sequence.md +10 -14
  44. package/skills/agentic-mermaid-live-editor/SKILL.md +100 -206
  45. package/AGENT_NATIVE.md +0 -602
  46. package/Instructions_for_agents.md +0 -83
  47. package/TODO.md +0 -662
  48. package/assets/hero.png +0 -0
  49. package/dist/index-x2Cj1dVv.d.ts +0 -1089
  50. package/docs/agent-api-cookbook.md +0 -308
  51. package/docs/agent-mutation-policy.md +0 -104
  52. package/docs/agent-workflow-examples.md +0 -46
  53. package/docs/api.md +0 -203
  54. package/docs/ascii.md +0 -103
  55. package/docs/assets/improvements/box-start-connector.png +0 -0
  56. package/docs/assets/improvements/comment-dropped-lint.png +0 -0
  57. package/docs/assets/improvements/er-content-loss.png +0 -0
  58. package/docs/assets/improvements/fan-in-trunks.png +0 -0
  59. package/docs/assets/improvements/gantt-family.png +0 -0
  60. package/docs/assets/improvements/gantt-milestone-clamp.png +0 -0
  61. package/docs/assets/improvements/gantt-verify-seam.png +0 -0
  62. package/docs/assets/improvements/subgraph-container-edges.png +0 -0
  63. package/docs/assets/improvements/wrapper-frontmatter.png +0 -0
  64. package/docs/assets/improvements/wrapper-init-directive.png +0 -0
  65. package/docs/assets/improvements/wrapper-leading-comment.png +0 -0
  66. package/docs/assets/style-cookbook/mid-century-report.png +0 -0
  67. package/docs/assets/style-cookbook/star-chart-atlas.png +0 -0
  68. package/docs/assets/style-cookbook/transit-route-map.png +0 -0
  69. package/docs/comparison.md +0 -94
  70. package/docs/config.md +0 -105
  71. package/docs/contributing/adding-diagram-types.md +0 -144
  72. package/docs/contributing/diagram-family-citizenship.matrix.json +0 -2127
  73. package/docs/contributing/diagram-family-citizenship.md +0 -82
  74. package/docs/contributing/harvesting-upstream-tests.md +0 -126
  75. package/docs/contributing/lessons-learned.md +0 -276
  76. package/docs/contributing/releasing.md +0 -71
  77. package/docs/contributing/visual-review-evidence.md +0 -53
  78. package/docs/custom-style-cookbook.md +0 -154
  79. package/docs/design/families/README.md +0 -26
  80. package/docs/design/families/architecture-beta.md +0 -48
  81. package/docs/design/families/flowchart-parser-conformance.md +0 -22
  82. package/docs/design/families/gantt-research.md +0 -137
  83. package/docs/design/families/gantt.md +0 -329
  84. package/docs/design/families/journey-agentic-cards-before.png +0 -0
  85. package/docs/design/families/journey-mermaid-classic-implementation.png +0 -0
  86. package/docs/design/families/journey-mermaid-classic-prototype.png +0 -0
  87. package/docs/design/families/journey-mermaid-classic-prototype.svg +0 -163
  88. package/docs/design/families/journey-mermaid-classic-prototype.svg.png +0 -0
  89. package/docs/design/families/journey-migration-parity.md +0 -433
  90. package/docs/design/families/journey-usage-research.md +0 -423
  91. package/docs/design/families/journey.md +0 -125
  92. package/docs/design/families/xychart.md +0 -85
  93. package/docs/design/system/README.md +0 -45
  94. package/docs/design/system/abstraction-audit.md +0 -224
  95. package/docs/design/system/abstraction-recommendations.md +0 -655
  96. package/docs/design/system/architecture.mmd +0 -29
  97. package/docs/design/system/architecture.svg +0 -137
  98. package/docs/design/system/layout-guarantees-and-robustness.md +0 -351
  99. package/docs/design/system/layout-rubric.md +0 -138
  100. package/docs/design/system/route-contracts.md +0 -848
  101. package/docs/design/system/source-preservation-ladder.md +0 -52
  102. package/docs/design/system/styles-rollout.md +0 -216
  103. package/docs/design/system/ugly-layouts.md +0 -119
  104. package/docs/diagram-families.md +0 -193
  105. package/docs/features.md +0 -147
  106. package/docs/fork-differences.md +0 -130
  107. package/docs/getting-started.md +0 -175
  108. package/docs/issue-derived-test-cases.md +0 -156
  109. package/docs/layout-characterization/README.md +0 -245
  110. package/docs/layout-characterization/contact-sheet-families.md +0 -496
  111. package/docs/layout-characterization/contact-sheet.md +0 -638
  112. package/docs/layout-characterization/properties.md +0 -281
  113. package/docs/layout-characterization/visual-quality.md +0 -160
  114. package/docs/layout-characterization/visual-snapshots/architecture.svg +0 -79
  115. package/docs/layout-characterization/visual-snapshots/class.svg +0 -60
  116. package/docs/layout-characterization/visual-snapshots/er.svg +0 -61
  117. package/docs/layout-characterization/visual-snapshots/flowchart.svg +0 -58
  118. package/docs/layout-characterization/visual-snapshots/gantt.svg +0 -52
  119. package/docs/layout-characterization/visual-snapshots/journey.svg +0 -118
  120. package/docs/layout-characterization/visual-snapshots/pie.svg +0 -36
  121. package/docs/layout-characterization/visual-snapshots/quadrant.svg +0 -47
  122. package/docs/layout-characterization/visual-snapshots/sequence.svg +0 -59
  123. package/docs/layout-characterization/visual-snapshots/state.svg +0 -52
  124. package/docs/layout-characterization/visual-snapshots/timeline.svg +0 -64
  125. package/docs/layout-characterization/visual-snapshots/xychart.svg +0 -97
  126. package/docs/mcp-code-mode-rationale.md +0 -101
  127. package/docs/mcp-http-transport.md +0 -223
  128. package/docs/mermaid-layout-complaints.md +0 -837
  129. package/docs/mutation-testing.md +0 -206
  130. package/docs/project/divergences.md +0 -98
  131. package/docs/project/dogfooding-docs-strategy.md +0 -66
  132. package/docs/project/hosted-mcp-cloudflare-plan.md +0 -338
  133. package/docs/project/lessons-learned.md +0 -1019
  134. package/docs/project/remove-role-styling-plan.md +0 -176
  135. package/docs/quality.md +0 -212
  136. package/docs/react.md +0 -97
  137. package/docs/style-authoring.md +0 -133
  138. package/docs/testing-strategy.md +0 -335
  139. package/docs/theming.md +0 -162
  140. package/examples/agent-improve-auth-flow.ts +0 -206
  141. package/examples/agent-loop.ts +0 -53
  142. package/examples/mcp-vs-cli-complex-diagrams.ts +0 -133
  143. package/llms.txt +0 -104
  144. package/skill-evals/README.md +0 -77
  145. package/skill-evals/fixtures/architecture-cache/input.mmd +0 -5
  146. package/skill-evals/fixtures/class-payment/input.mmd +0 -4
  147. package/skill-evals/fixtures/er-orders/input.mmd +0 -10
  148. package/skill-evals/fixtures/flowchart-cache/input.mmd +0 -3
  149. package/skill-evals/fixtures/gantt-release/input.mmd +0 -7
  150. package/skill-evals/fixtures/journey-checkout/input.mmd +0 -6
  151. package/skill-evals/fixtures/pie-exports/input.mmd +0 -5
  152. package/skill-evals/fixtures/quadrant-priorities/input.mmd +0 -11
  153. package/skill-evals/fixtures/sequence-retry/input.mmd +0 -8
  154. package/skill-evals/fixtures/state-lifecycle/input.mmd +0 -5
  155. package/skill-evals/fixtures/timeline-release/input.mmd +0 -6
  156. package/skill-evals/fixtures/xychart-growth/input.mmd +0 -5
  157. package/skill-evals/shared-benchmark.json +0 -510
  158. package/src/agent/analyze.ts +0 -157
  159. package/src/agent/apply.ts +0 -146
  160. package/src/agent/architecture-body.ts +0 -458
  161. package/src/agent/certificates.ts +0 -110
  162. package/src/agent/class-body.ts +0 -319
  163. package/src/agent/core.ts +0 -207
  164. package/src/agent/create.ts +0 -106
  165. package/src/agent/describe.ts +0 -364
  166. package/src/agent/er-body.ts +0 -224
  167. package/src/agent/facts.ts +0 -337
  168. package/src/agent/families-builtin.ts +0 -934
  169. package/src/agent/families.ts +0 -232
  170. package/src/agent/family-layouts.ts +0 -826
  171. package/src/agent/flowchart-body.ts +0 -372
  172. package/src/agent/flowchart-unsupported.ts +0 -243
  173. package/src/agent/gantt-body.ts +0 -495
  174. package/src/agent/index.ts +0 -10
  175. package/src/agent/journey-body.ts +0 -414
  176. package/src/agent/label-metrics.ts +0 -28
  177. package/src/agent/layout-to-rendered.ts +0 -63
  178. package/src/agent/mutate.ts +0 -97
  179. package/src/agent/mutation-ops.ts +0 -51
  180. package/src/agent/op-schema.ts +0 -439
  181. package/src/agent/parse.ts +0 -223
  182. package/src/agent/pie-body.ts +0 -270
  183. package/src/agent/png.ts +0 -117
  184. package/src/agent/quadrant-body.ts +0 -336
  185. package/src/agent/quality.ts +0 -363
  186. package/src/agent/readability-audit.ts +0 -92
  187. package/src/agent/rendered-route-audit.ts +0 -61
  188. package/src/agent/sequence-body.ts +0 -345
  189. package/src/agent/serialize.ts +0 -214
  190. package/src/agent/state-body.ts +0 -589
  191. package/src/agent/structural-count.ts +0 -150
  192. package/src/agent/timeline-body.ts +0 -280
  193. package/src/agent/trace-log.ts +0 -43
  194. package/src/agent/types.ts +0 -979
  195. package/src/agent/verify.ts +0 -571
  196. package/src/agent/xychart-body.ts +0 -472
  197. package/src/architecture/config.ts +0 -282
  198. package/src/architecture/layout.ts +0 -496
  199. package/src/architecture/parser.ts +0 -375
  200. package/src/architecture/renderer.ts +0 -611
  201. package/src/architecture/types.ts +0 -113
  202. package/src/ascii/ansi.ts +0 -423
  203. package/src/ascii/architecture.ts +0 -210
  204. package/src/ascii/canvas.ts +0 -443
  205. package/src/ascii/class-diagram.ts +0 -697
  206. package/src/ascii/converter.ts +0 -475
  207. package/src/ascii/draw.ts +0 -1693
  208. package/src/ascii/edge-bundling.ts +0 -328
  209. package/src/ascii/edge-routing.ts +0 -330
  210. package/src/ascii/er-diagram.ts +0 -439
  211. package/src/ascii/gantt.ts +0 -276
  212. package/src/ascii/grid.ts +0 -747
  213. package/src/ascii/index.ts +0 -196
  214. package/src/ascii/journey.ts +0 -189
  215. package/src/ascii/meta.ts +0 -244
  216. package/src/ascii/multiline-utils.ts +0 -80
  217. package/src/ascii/pathfinder.ts +0 -301
  218. package/src/ascii/pie.ts +0 -67
  219. package/src/ascii/quadrant.ts +0 -158
  220. package/src/ascii/reverse.ts +0 -216
  221. package/src/ascii/sequence.ts +0 -499
  222. package/src/ascii/shapes/circle.ts +0 -27
  223. package/src/ascii/shapes/corners.ts +0 -143
  224. package/src/ascii/shapes/diamond.ts +0 -27
  225. package/src/ascii/shapes/hexagon.ts +0 -27
  226. package/src/ascii/shapes/index.ts +0 -106
  227. package/src/ascii/shapes/rectangle.ts +0 -168
  228. package/src/ascii/shapes/rounded.ts +0 -27
  229. package/src/ascii/shapes/special.ts +0 -332
  230. package/src/ascii/shapes/stadium.ts +0 -110
  231. package/src/ascii/shapes/state.ts +0 -192
  232. package/src/ascii/shapes/types.ts +0 -73
  233. package/src/ascii/timeline.ts +0 -128
  234. package/src/ascii/types.ts +0 -312
  235. package/src/ascii/validate.ts +0 -120
  236. package/src/ascii/width.ts +0 -81
  237. package/src/ascii/xychart.ts +0 -919
  238. package/src/browser.ts +0 -29
  239. package/src/class/layout.ts +0 -240
  240. package/src/class/parser.ts +0 -332
  241. package/src/class/renderer.ts +0 -638
  242. package/src/class/types.ts +0 -129
  243. package/src/cli/agent-instructions.ts +0 -1
  244. package/src/cli/am-bin.ts +0 -6
  245. package/src/cli/exit-codes.ts +0 -18
  246. package/src/cli/index.ts +0 -1117
  247. package/src/cli/init-agent.ts +0 -147
  248. package/src/color-resolver.ts +0 -152
  249. package/src/elk-instance.ts +0 -114
  250. package/src/er/layout.ts +0 -187
  251. package/src/er/parser.ts +0 -226
  252. package/src/er/renderer.ts +0 -792
  253. package/src/er/types.ts +0 -99
  254. package/src/font-manifest.ts +0 -27
  255. package/src/gantt/layout.ts +0 -365
  256. package/src/gantt/parser.ts +0 -282
  257. package/src/gantt/pipeline.ts +0 -27
  258. package/src/gantt/renderer.ts +0 -414
  259. package/src/gantt/schedule.ts +0 -513
  260. package/src/gantt/types.ts +0 -255
  261. package/src/index.ts +0 -368
  262. package/src/journey/layout.ts +0 -520
  263. package/src/journey/parser.ts +0 -218
  264. package/src/journey/renderer.ts +0 -811
  265. package/src/journey/types.ts +0 -144
  266. package/src/layout/geometry.ts +0 -182
  267. package/src/layout/pass.ts +0 -142
  268. package/src/layout/passes/index.ts +0 -3916
  269. package/src/layout-engine.ts +0 -1565
  270. package/src/layout-rubric.ts +0 -659
  271. package/src/mcp/artifacts.ts +0 -137
  272. package/src/mcp/dynamic-harness.ts +0 -31
  273. package/src/mcp/dynamic-modules.d.ts +0 -7
  274. package/src/mcp/facade.ts +0 -608
  275. package/src/mcp/harness-runtime.ts +0 -203
  276. package/src/mcp/hosted-server.ts +0 -468
  277. package/src/mcp/mcp-bin.ts +0 -3
  278. package/src/mcp/mcp-cli.ts +0 -82
  279. package/src/mcp/protocol.ts +0 -13
  280. package/src/mcp/sandbox.ts +0 -195
  281. package/src/mcp/sdk-decl.ts +0 -387
  282. package/src/mcp/server.ts +0 -362
  283. package/src/mcp/tool-surface.ts +0 -146
  284. package/src/mermaid-source.ts +0 -655
  285. package/src/multiline-utils.ts +0 -228
  286. package/src/parser.ts +0 -1031
  287. package/src/pie/layout.ts +0 -168
  288. package/src/pie/parser.ts +0 -136
  289. package/src/pie/renderer.ts +0 -234
  290. package/src/pie/types.ts +0 -82
  291. package/src/quadrant/layout.ts +0 -191
  292. package/src/quadrant/parser.ts +0 -183
  293. package/src/quadrant/renderer.ts +0 -322
  294. package/src/quadrant/types.ts +0 -113
  295. package/src/render-family-hooks.ts +0 -244
  296. package/src/renderer.ts +0 -1099
  297. package/src/route-contracts.ts +0 -2723
  298. package/src/scene/backend.ts +0 -76
  299. package/src/scene/fidelity.ts +0 -183
  300. package/src/scene/hybrid-backend.ts +0 -174
  301. package/src/scene/ir.ts +0 -181
  302. package/src/scene/marks.ts +0 -127
  303. package/src/scene/rough-backend.ts +0 -378
  304. package/src/scene/seed.ts +0 -46
  305. package/src/scene/style-registry.ts +0 -556
  306. package/src/sequence/layout.ts +0 -456
  307. package/src/sequence/parser.ts +0 -255
  308. package/src/sequence/renderer.ts +0 -604
  309. package/src/sequence/types.ts +0 -154
  310. package/src/shape-clipping.ts +0 -351
  311. package/src/shared/accessibility-directives.ts +0 -22
  312. package/src/shared/batched.ts +0 -61
  313. package/src/shared/color-math.ts +0 -72
  314. package/src/shared/svg-a11y.ts +0 -29
  315. package/src/shared/syntax-error.ts +0 -17
  316. package/src/shared/unicode-ranges.ts +0 -135
  317. package/src/styles.ts +0 -318
  318. package/src/svg-paths.ts +0 -28
  319. package/src/text-metrics.ts +0 -248
  320. package/src/theme.ts +0 -639
  321. package/src/timeline/layout.ts +0 -381
  322. package/src/timeline/parser.ts +0 -215
  323. package/src/timeline/renderer.ts +0 -538
  324. package/src/timeline/types.ts +0 -105
  325. package/src/types.ts +0 -454
  326. package/src/website-worker-modules.d.ts +0 -18
  327. package/src/xychart/axis-utils.ts +0 -109
  328. package/src/xychart/colors.ts +0 -124
  329. package/src/xychart/config.ts +0 -88
  330. package/src/xychart/layout.ts +0 -656
  331. package/src/xychart/parser.ts +0 -504
  332. package/src/xychart/renderer.ts +0 -640
  333. package/src/xychart/types.ts +0 -282
@@ -1,147 +0,0 @@
1
- // `am init-agent` — write a repo-local, agent-agnostic onboarding drop-in.
2
- //
3
- // The generated files are meant for consumer repositories, not this repository:
4
- // - AGENTS.md: a marked section with the Agentic Mermaid contract.
5
- // - skills/agentic-mermaid-diagram-workflow/SKILL.md: generic SKILL.md bundle.
6
- // - .mcp.json: sample MCP config for Code Mode.
7
- //
8
- // The command is idempotent and non-clobbering by default. It deliberately uses
9
- // root `skills/` instead of `.claude/` or `.agents/` so the output mirrors this
10
- // repo's agent-agnostic skill layout.
11
-
12
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
13
- import { dirname, join } from 'node:path'
14
- import { BUILTIN_FAMILY_METADATA } from '../agent/families.ts'
15
-
16
- const HOSTED_BASE = 'https://agentic-mermaid.dev'
17
- const HOSTED_LLMS_TXT = `${HOSTED_BASE}/llms.txt`
18
- const HOSTED_AGENT_GUIDE = `${HOSTED_BASE}/agent-instructions.md`
19
-
20
- export const AGENTS_MARKER = '<!-- agentic-mermaid:start -->'
21
- const AGENTS_MARKER_END = '<!-- agentic-mermaid:end -->'
22
- const STRUCTURED_NARROWERS = BUILTIN_FAMILY_METADATA.map(f => `\`${f.narrower}\``).join(' / ')
23
-
24
- export const AGENTS_SNIPPET = `${AGENTS_MARKER}
25
- ## Editing Mermaid diagrams
26
-
27
- Use **Agentic Mermaid** whenever you create or edit Mermaid diagrams. Do not
28
- regenerate an existing diagram from scratch when a typed edit path exists.
29
-
30
- New diagrams: author Mermaid source directly, then parse, verify, and render.
31
- Existing structured diagrams: parse → narrow (${STRUCTURED_NARROWERS}) → mutate
32
- → verify → serialize. Run verify at every commit point and never serialize a
33
- diagram whose verify result you have not inspected. For styled output pass
34
- \`style\` (a name like \`hand-drawn\`, a JSON record, or a stack) and \`seed\`
35
- to any render call — \`npx agentic-mermaid styles\` lists what is available.
36
-
37
- Useful entrypoints:
38
-
39
- - Hosted discovery digest: ${HOSTED_LLMS_TXT}
40
- - Hosted agent guide: ${HOSTED_AGENT_GUIDE}
41
- - Local/package guide: \`npx agentic-mermaid --agent-instructions\`
42
- - Capabilities: \`npx agentic-mermaid capabilities --json\`
43
- - Repo skill: \`skills/agentic-mermaid-diagram-workflow/SKILL.md\`
44
- ${AGENTS_MARKER_END}
45
- `
46
-
47
- export const INIT_SKILL_MD = `---
48
- name: agentic-mermaid-diagram-workflow
49
- description: Agent-agnostic workflow for authoring and editing Mermaid diagrams with Agentic Mermaid's parse, narrow, mutate, verify, serialize, and render APIs. Use when creating or modifying Mermaid diagrams.
50
- ---
51
-
52
- # Agentic Mermaid — diagram workflow
53
-
54
- Use Agentic Mermaid for Mermaid diagram work. Prefer the narrowest safe channel:
55
-
56
- - MCP connected: use \`agentic-mermaid-mcp\` Code Mode and the global \`mermaid.*\` SDK.
57
- - JS/TS available: import from \`agentic-mermaid/agent\`.
58
- - Shell only: use \`npx agentic-mermaid --agent-instructions\` and \`npx agentic-mermaid capabilities --json\`.
59
-
60
- ## Safe edit loop
61
-
62
- New diagrams: author Mermaid source directly, then parse, verify, and render.
63
- Existing structured diagrams:
64
-
65
- 1. \`parseMermaid(source)\`.
66
- 2. Narrow with ${STRUCTURED_NARROWERS}.
67
- 3. Edit with \`mutate(d, op)\`; mutation ops use \`kind\`, not \`type\`.
68
- 4. Run \`verifyMermaid(d)\` and inspect \`ok\`, \`warnings\`, and layout evidence.
69
- 5. Serialize only after inspected verification passes.
70
-
71
- Do not concatenate strings or regenerate a whole existing structured diagram when a typed op exists. Every built-in renderable family ships a typed path when the body narrows; only opaque fallback bodies are source-level-only. If you deliberately edit source for an opaque fallback, re-parse and verify before returning it.
72
-
73
- ## Output artifacts
74
-
75
- Agentic Mermaid outputs SVG, PNG, and ASCII:
76
-
77
- \`\`\`bash
78
- npx agentic-mermaid render diagram.mmd --format svg > diagram.svg
79
- npx agentic-mermaid render diagram.mmd --format png --output diagram.png
80
- npx agentic-mermaid render diagram.mmd --format ascii > diagram.txt
81
- \`\`\`
82
-
83
- Docs:
84
-
85
- - ${HOSTED_LLMS_TXT}
86
- - ${HOSTED_AGENT_GUIDE}
87
- `
88
-
89
- export const MCP_CONFIG_SAMPLE = JSON.stringify(
90
- {
91
- mcpServers: {
92
- 'agentic-mermaid': {
93
- command: 'npx',
94
- args: ['-y', '--package', 'agentic-mermaid', 'agentic-mermaid-mcp'],
95
- },
96
- },
97
- },
98
- null,
99
- 2,
100
- ) + '\n'
101
-
102
- export interface InitAgentResult {
103
- written: string[]
104
- appended: string[]
105
- skipped: string[]
106
- }
107
-
108
- function ensureDir(file: string): void {
109
- const dir = dirname(file)
110
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
111
- }
112
-
113
- function writeIfMissing(path: string, content: string, result: InitAgentResult, force: boolean): void {
114
- if (existsSync(path) && !force) {
115
- result.skipped.push(path)
116
- return
117
- }
118
- ensureDir(path)
119
- writeFileSync(path, content)
120
- result.written.push(path)
121
- }
122
-
123
- export function initAgentFiles(opts: { dir: string; force?: boolean }): InitAgentResult {
124
- const { dir, force = false } = opts
125
- const result: InitAgentResult = { written: [], appended: [], skipped: [] }
126
-
127
- const agentsPath = join(dir, 'AGENTS.md')
128
- if (!existsSync(agentsPath)) {
129
- ensureDir(agentsPath)
130
- writeFileSync(agentsPath, AGENTS_SNIPPET)
131
- result.written.push(agentsPath)
132
- } else {
133
- const existing = readFileSync(agentsPath, 'utf8')
134
- if (existing.includes(AGENTS_MARKER)) {
135
- result.skipped.push(agentsPath)
136
- } else {
137
- const sep = existing.endsWith('\n') ? '\n' : '\n\n'
138
- writeFileSync(agentsPath, existing + sep + AGENTS_SNIPPET)
139
- result.appended.push(agentsPath)
140
- }
141
- }
142
-
143
- writeIfMissing(join(dir, 'skills', 'agentic-mermaid-diagram-workflow', 'SKILL.md'), INIT_SKILL_MD, result, force)
144
- writeIfMissing(join(dir, '.mcp.json'), MCP_CONFIG_SAMPLE, result, force)
145
-
146
- return result
147
- }
@@ -1,152 +0,0 @@
1
- import type { MermaidGraph, RenderOptions } from './types.ts'
2
- import { tryParseHex, luma255 } from './shared/color-math.ts'
3
- import type { DiagramColors } from './theme.ts'
4
- import { DEFAULTS, THEMES } from './theme.ts'
5
- import type { MermaidRuntimeConfig, MermaidThemeVariables } from './mermaid-source.ts'
6
-
7
- const ZINC_DARK = THEMES['zinc-dark'] ?? { bg: '#18181B', fg: '#FAFAFA' }
8
-
9
- const MERMAID_THEME_COLORS: Record<string, DiagramColors> = {
10
- default: { bg: DEFAULTS.bg, fg: DEFAULTS.fg },
11
- base: { bg: DEFAULTS.bg, fg: DEFAULTS.fg },
12
- neutral: { bg: '#ffffff', fg: '#1f2937', line: '#9ca3af', accent: '#6b7280', muted: '#6b7280' },
13
- dark: {
14
- bg: ZINC_DARK.bg,
15
- fg: ZINC_DARK.fg,
16
- line: ZINC_DARK.line,
17
- accent: ZINC_DARK.accent,
18
- muted: ZINC_DARK.muted,
19
- surface: ZINC_DARK.surface,
20
- border: ZINC_DARK.border,
21
- },
22
- forest: { bg: '#f0fdf4', fg: '#14532d', line: '#4d7c0f', accent: '#15803d', muted: '#65a30d', border: '#86efac' },
23
- }
24
-
25
- /** Mermaid themeVariables keys read per DiagramColors channel — the single
26
- * source of truth shared by resolveDiagramColors and the aesthetic-defaults
27
- * composition in index.ts (user theming must beat style palettes). */
28
- export const CHANNEL_THEME_KEYS = {
29
- bg: ['background', 'mainBkg'],
30
- fg: ['primaryTextColor', 'textColor', 'nodeTextColor'],
31
- line: ['lineColor', 'defaultLinkColor'],
32
- accent: ['arrowheadColor', 'primaryColor'],
33
- muted: ['secondaryTextColor', 'tertiaryTextColor'],
34
- surface: ['primaryColor', 'nodeBkg', 'mainBkg'],
35
- border: ['primaryBorderColor', 'secondaryBorderColor'],
36
- } as const
37
-
38
- /**
39
- * The internal color waist: every public color dialect is normalized to
40
- * DiagramColors before layout/render code sees it.
41
- */
42
- export function resolveDiagramColors(
43
- options: RenderOptions,
44
- config: MermaidRuntimeConfig,
45
- font?: string,
46
- ): DiagramColors {
47
- const theme = resolveThemeColors(config.theme)
48
- const vars = config.themeVariables
49
-
50
- return {
51
- bg: options.bg ?? readThemeValue(vars, ...CHANNEL_THEME_KEYS.bg) ?? theme?.bg ?? DEFAULTS.bg,
52
- fg: options.fg ?? readThemeValue(vars, ...CHANNEL_THEME_KEYS.fg) ?? theme?.fg ?? DEFAULTS.fg,
53
- line: options.line ?? readThemeValue(vars, ...CHANNEL_THEME_KEYS.line) ?? theme?.line,
54
- accent: options.accent ?? readThemeValue(vars, ...CHANNEL_THEME_KEYS.accent) ?? theme?.accent,
55
- muted: options.muted ?? readThemeValue(vars, ...CHANNEL_THEME_KEYS.muted) ?? theme?.muted,
56
- surface: options.surface ?? readThemeValue(vars, ...CHANNEL_THEME_KEYS.surface) ?? theme?.surface,
57
- border: options.border ?? readThemeValue(vars, ...CHANNEL_THEME_KEYS.border) ?? theme?.border,
58
- shadow: options.shadow ?? theme?.shadow,
59
- font,
60
- embedFontImport: options.embedFontImport,
61
- }
62
- }
63
-
64
- export function resolveThemeColors(themeName: string | undefined): DiagramColors | undefined {
65
- if (!themeName) return undefined
66
- if (themeName in THEMES) return THEMES[themeName as keyof typeof THEMES]
67
- return MERMAID_THEME_COLORS[themeName.toLowerCase()]
68
- }
69
-
70
- export function readThemeValue(vars: MermaidThemeVariables | undefined, ...keys: string[]): string | undefined {
71
- if (!vars) return undefined
72
-
73
- for (const key of keys) {
74
- const value = vars[key]
75
- if (typeof value === 'string' && value.length > 0) return value
76
- }
77
-
78
- return undefined
79
- }
80
-
81
- /**
82
- * Resolve inline node styles from Mermaid classDef/class/style directives.
83
- * Class styles are applied first; explicit style directives override them.
84
- */
85
- export function resolveNodeInlineStyle(
86
- nodeId: string,
87
- graph: MermaidGraph,
88
- ): Record<string, string> | undefined {
89
- let result: Record<string, string> | undefined
90
-
91
- const className = graph.classAssignments.get(nodeId)
92
- if (className) {
93
- const classDef = graph.classDefs.get(className)
94
- if (classDef) result = { ...classDef }
95
- }
96
-
97
- const nodeStyle = graph.nodeStyles.get(nodeId)
98
- if (nodeStyle) result = result ? { ...result, ...nodeStyle } : { ...nodeStyle }
99
-
100
- return result
101
- }
102
-
103
- /**
104
- * Resolve inline edge styles from Mermaid linkStyle directives. Default link
105
- * style is applied first; edge-index-specific style overrides it.
106
- */
107
- export function resolveEdgeInlineStyle(
108
- edgeIndex: number,
109
- graph: MermaidGraph,
110
- ): Record<string, string> | undefined {
111
- let result: Record<string, string> | undefined
112
-
113
- const defaultStyle = graph.linkStyles.get('default')
114
- if (defaultStyle) result = { ...defaultStyle }
115
-
116
- const indexStyle = graph.linkStyles.get(edgeIndex)
117
- if (indexStyle) result = result ? { ...result, ...indexStyle } : { ...indexStyle }
118
-
119
- return result
120
- }
121
-
122
- function parseHexToRgb(hex: string): { r: number; g: number; b: number } | null {
123
- const rgb = tryParseHex(hex)
124
- return rgb ? { r: rgb[0], g: rgb[1], b: rgb[2] } : null
125
- }
126
-
127
- function parseRgbFunction(color: string): { r: number; g: number; b: number } | null {
128
- const match = color.match(/^rgba?\(\s*(\d{1,3})(?:\s*,\s*|\s+)(\d{1,3})(?:\s*,\s*|\s+)(\d{1,3})/i)
129
- if (!match) return null
130
- const rgb = {
131
- r: Number.parseInt(match[1]!, 10),
132
- g: Number.parseInt(match[2]!, 10),
133
- b: Number.parseInt(match[3]!, 10),
134
- }
135
- return Object.values(rgb).every(v => v >= 0 && v <= 255) ? rgb : null
136
- }
137
-
138
- export function contrastTextColor(fill: string): string | undefined {
139
- const rgb = parseHexToRgb(fill) ?? parseRgbFunction(fill)
140
- if (!rgb) return undefined
141
- const brightness = luma255(rgb.r, rgb.g, rgb.b)
142
- return brightness > 140 ? '#000000' : '#FFFFFF'
143
- }
144
-
145
- export function resolveInlineNodeTextColor(
146
- inlineStyle: Record<string, string> | undefined,
147
- fallback: string = 'var(--_text)',
148
- ): string {
149
- if (inlineStyle?.color) return inlineStyle.color
150
- if (inlineStyle?.fill) return contrastTextColor(inlineStyle.fill) ?? fallback
151
- return fallback
152
- }
@@ -1,114 +0,0 @@
1
- /**
2
- * Shared ELK instance singleton.
3
- *
4
- * Uses elk.bundled.js (pure synchronous JS, ~1.6 MB) for all environments.
5
- * The singleton is created lazily on first use and cached forever.
6
- *
7
- * ELK's FakeWorker wraps both postMessage and onmessage in setTimeout(0),
8
- * making the normal API fully async. To bypass this:
9
- * 1. During construction, we capture setTimeout(0) callbacks and flush them
10
- * synchronously — this registers the layout algorithms immediately.
11
- * 2. For layout calls, we call dispatcher.saveDispatch() directly (skipping
12
- * the FakeWorker's postMessage setTimeout) and intercept the result via
13
- * rawWorker.onmessage (which the dispatcher calls synchronously).
14
- */
15
-
16
- import type { ElkNode } from 'elkjs'
17
- // @ts-ignore — static import of bundled ELK
18
- import ELKBundled from 'elkjs/lib/elk.bundled.js'
19
-
20
- interface RawFakeWorker {
21
- postMessage(msg: unknown): void
22
- onmessage: ((e: { data: Record<string, unknown> }) => void) | null
23
- dispatcher: {
24
- saveDispatch(msg: { data: Record<string, unknown> }): void
25
- }
26
- }
27
-
28
- let elk: unknown = null
29
- let rawWorker: RawFakeWorker | null = null
30
-
31
- /**
32
- * Ensure the ELK singleton exists.
33
- *
34
- * Patches setTimeout during construction to capture and synchronously flush
35
- * the algorithm registration callback that ELK queues via setTimeout(0).
36
- * Without this, layout calls fail with "algorithm not found" until the
37
- * next macrotask.
38
- */
39
- function ensureElk(): void {
40
- if (elk) return
41
-
42
- // Capture setTimeout(0) callbacks queued during ELK construction
43
- const pending: (() => void)[] = []
44
- const origSetTimeout = globalThis.setTimeout
45
- // @ts-ignore — simplified signature for our interception
46
- globalThis.setTimeout = (fn: () => void, delay?: number) => {
47
- if (delay === 0) { pending.push(fn); return 0 }
48
- return origSetTimeout(fn, delay)
49
- }
50
-
51
- // Bun and Cloudflare workerd define `self` (= globalThis) but not
52
- // `document`, which tricks elk-worker.min.js into taking the Web Worker
53
- // branch (registering self.onmessage, exporting no Worker) instead of the
54
- // CJS branch that exports {Worker: FakeWorker}. Deleting `self` worked on
55
- // Bun but not on workerd, where the global is undeletable. Temporarily
56
- // defining `document` flips the same branch condition on both runtimes:
57
- // elk-worker checks `typeof document === 'undefined' && typeof self !==
58
- // 'undefined'` before falling through to module.exports.
59
- const g = globalThis as Record<string, unknown>
60
- const hadDocument = typeof g.document !== 'undefined'
61
- if (!hadDocument) g.document = {}
62
-
63
- elk = new ELKBundled()
64
-
65
- if (!hadDocument) delete g.document
66
-
67
- // Restore setTimeout immediately
68
- globalThis.setTimeout = origSetTimeout
69
-
70
- // Flush captured callbacks synchronously — registers layout algorithms
71
- pending.forEach(fn => fn())
72
-
73
- // Cache the raw FakeWorker for elkLayoutSync()
74
- rawWorker = (elk as unknown as { worker: { worker: RawFakeWorker } }).worker.worker
75
- }
76
-
77
- /**
78
- * Run ELK layout synchronously.
79
- *
80
- * Bypasses BOTH of ELK's setTimeout(0) wrappers:
81
- * - FakeWorker.postMessage wraps dispatch in setTimeout(0) — bypassed by
82
- * calling dispatcher.saveDispatch() directly
83
- * - PromisedWorker.onmessage wraps receive in setTimeout(0) — bypassed by
84
- * replacing rawWorker.onmessage with a direct interceptor
85
- */
86
- export function elkLayoutSync(graph: ElkNode): ElkNode {
87
- ensureElk()
88
-
89
- let result: ElkNode | undefined
90
- let error: unknown
91
-
92
- // Replace onmessage to intercept the result synchronously
93
- // (the dispatcher calls this directly, without setTimeout)
94
- const origOnmessage = rawWorker!.onmessage
95
- rawWorker!.onmessage = (answer: { data: Record<string, unknown> }) => {
96
- if (answer.data.error) {
97
- error = answer.data.error
98
- } else {
99
- result = answer.data.data as ElkNode
100
- }
101
- }
102
-
103
- // Call dispatcher.saveDispatch directly — bypasses FakeWorker.postMessage's
104
- // setTimeout(0) wrapper. The dispatcher processes the layout synchronously
105
- // and calls rawWorker.onmessage with the result.
106
- rawWorker!.dispatcher.saveDispatch({ data: { id: 0, cmd: 'layout', graph } as unknown as Record<string, unknown> })
107
-
108
- // Restore original handler
109
- rawWorker!.onmessage = origOnmessage
110
-
111
- if (error) throw error
112
- if (!result) throw new Error('ELK layout did not return synchronously')
113
- return result
114
- }
package/src/er/layout.ts DELETED
@@ -1,187 +0,0 @@
1
- /**
2
- * ER diagram layout engine (ELK.js).
3
- *
4
- * Each entity box has:
5
- * 1. Header (entity name)
6
- * 2. Attribute rows (type, name, keys)
7
- */
8
-
9
- import type { ElkNode, ElkExtendedEdge } from 'elkjs'
10
- import type { ErDiagram, ErEntity, PositionedErDiagram, PositionedErEntity, PositionedErRelationship } from './types.ts'
11
- import type { RenderOptions, Point } from '../types.ts'
12
- import { applyTextTransform, estimateTextWidth, estimateMonoTextWidth, FONT_SIZES, FONT_WEIGHTS, STROKE_WIDTHS, resolveRenderStyle } from '../styles.ts'
13
- import type { RenderStyleDefaults } from '../styles.ts'
14
- import { measureMultilineText } from '../text-metrics.ts'
15
- import { elkLayoutSync } from '../elk-instance.ts'
16
-
17
- /** Layout constants for ER diagrams */
18
- const ER = {
19
- padding: 40,
20
- boxPadX: 14,
21
- headerHeight: 34,
22
- rowHeight: 22,
23
- minWidth: 140,
24
- attrFontSize: 11,
25
- attrFontWeight: 400,
26
- nodeSpacing: 70,
27
- layerSpacing: 90,
28
- } as const
29
-
30
- /** Shared by layout (sizing) and renderer (drawing) — keep it single-sourced. */
31
- export const ER_STYLE_DEFAULTS: RenderStyleDefaults = {
32
- nodeLabelFontSize: FONT_SIZES.nodeLabel,
33
- edgeLabelFontSize: FONT_SIZES.edgeLabel,
34
- groupHeaderFontSize: FONT_SIZES.groupHeader,
35
- nodeLabelFontWeight: 700, // entity headers are drawn bold; measure them bold too
36
- edgeLabelFontWeight: FONT_WEIGHTS.edgeLabel,
37
- groupHeaderFontWeight: FONT_WEIGHTS.groupHeader,
38
- nodePaddingX: ER.boxPadX,
39
- nodePaddingY: 8,
40
- nodeCornerRadius: 0,
41
- nodeLineWidth: STROKE_WIDTHS.outerBox,
42
- edgeLineWidth: STROKE_WIDTHS.connector,
43
- groupCornerRadius: 0,
44
- groupPaddingX: ER.boxPadX,
45
- groupPaddingY: 8,
46
- groupLineWidth: STROKE_WIDTHS.outerBox,
47
- }
48
-
49
- type EntitySizeMap = Map<string, { width: number; height: number; headerHeight: number }>
50
-
51
- /** Build ELK graph and size map from an ER diagram. */
52
- function buildErElkGraph(
53
- diagram: ErDiagram,
54
- options: RenderOptions
55
- ): { elkGraph: ElkNode; entitySizes: EntitySizeMap } {
56
- const style = resolveRenderStyle(options, ER_STYLE_DEFAULTS)
57
- const entitySizes: EntitySizeMap = new Map()
58
-
59
- for (const entity of diagram.entities) {
60
- const label = applyTextTransform(entity.label, style.nodeTextTransform)
61
- const headerTextW = estimateTextWidth(label, style.nodeLabelFontSize, style.nodeLabelFontWeight)
62
- let maxAttrW = 0
63
- for (const attr of entity.attributes) {
64
- const attrText = `${attr.type} ${attr.name}${attr.keys.length > 0 ? ' ' + attr.keys.join(',') : ''}`
65
- const w = estimateMonoTextWidth(attrText, ER.attrFontSize)
66
- if (w > maxAttrW) maxAttrW = w
67
- }
68
- const width = Math.max(ER.minWidth, headerTextW + style.nodePaddingX * 2, maxAttrW + style.nodePaddingX * 2)
69
- const headerHeight = Math.max(ER.headerHeight, measureMultilineText(label, style.nodeLabelFontSize, style.nodeLabelFontWeight).height + style.nodePaddingY * 2)
70
- const height = headerHeight + Math.max(entity.attributes.length, 1) * ER.rowHeight
71
- entitySizes.set(entity.id, { width, height, headerHeight })
72
- }
73
-
74
- const elkGraph: ElkNode = {
75
- id: 'root',
76
- layoutOptions: {
77
- 'elk.algorithm': 'layered',
78
- 'elk.direction': 'RIGHT',
79
- 'elk.spacing.nodeNode': String(ER.nodeSpacing),
80
- 'elk.layered.spacing.nodeNodeBetweenLayers': String(ER.layerSpacing),
81
- 'elk.padding': `[top=${ER.padding},left=${ER.padding},bottom=${ER.padding},right=${ER.padding}]`,
82
- 'elk.edgeRouting': 'ORTHOGONAL',
83
- 'elk.edgeLabels.placement': 'CENTER',
84
- },
85
- children: [],
86
- edges: [],
87
- }
88
-
89
- for (const entity of diagram.entities) {
90
- const size = entitySizes.get(entity.id)!
91
- elkGraph.children!.push({ id: entity.id, width: size.width, height: size.height })
92
- }
93
-
94
- for (let i = 0; i < diagram.relationships.length; i++) {
95
- const rel = diagram.relationships[i]!
96
- const edge: ElkExtendedEdge = { id: `e${i}`, sources: [rel.entity1], targets: [rel.entity2] }
97
- if (rel.label) {
98
- const label = applyTextTransform(rel.label, style.edgeTextTransform)
99
- const metrics = measureMultilineText(label, style.edgeLabelFontSize, style.edgeLabelFontWeight)
100
- edge.labels = [{ text: label, width: metrics.width + 8, height: metrics.height + 6 }]
101
- }
102
- elkGraph.edges!.push(edge)
103
- }
104
-
105
- return { elkGraph, entitySizes }
106
- }
107
-
108
- /** Extract positioned entities and relationships from ELK result. */
109
- function extractErLayout(
110
- result: ElkNode,
111
- diagram: ErDiagram,
112
- entitySizes: EntitySizeMap
113
- ): PositionedErDiagram {
114
- const entityLookup = new Map<string, ErEntity>()
115
- for (const entity of diagram.entities) entityLookup.set(entity.id, entity)
116
-
117
- const positionedEntities: PositionedErEntity[] = []
118
- for (const child of result.children ?? []) {
119
- const entity = entityLookup.get(child.id)
120
- if (entity) {
121
- positionedEntities.push({
122
- id: entity.id,
123
- label: entity.label,
124
- attributes: entity.attributes,
125
- x: child.x ?? 0,
126
- y: child.y ?? 0,
127
- width: child.width ?? entitySizes.get(entity.id)!.width,
128
- height: child.height ?? entitySizes.get(entity.id)!.height,
129
- headerHeight: entitySizes.get(entity.id)!.headerHeight,
130
- rowHeight: ER.rowHeight,
131
- })
132
- }
133
- }
134
-
135
- const relationships: PositionedErRelationship[] = []
136
- for (let i = 0; i < (result.edges?.length ?? 0); i++) {
137
- const elkEdge = result.edges![i]!
138
- const rel = diagram.relationships[i]!
139
-
140
- const points: Point[] = []
141
- if (elkEdge.sections && elkEdge.sections.length > 0) {
142
- const section = elkEdge.sections[0]!
143
- points.push({ x: section.startPoint.x, y: section.startPoint.y })
144
- if (section.bendPoints) {
145
- for (const bp of section.bendPoints) {
146
- points.push({ x: bp.x, y: bp.y })
147
- }
148
- }
149
- points.push({ x: section.endPoint.x, y: section.endPoint.y })
150
- }
151
-
152
- relationships.push({
153
- entity1: rel.entity1,
154
- entity2: rel.entity2,
155
- cardinality1: rel.cardinality1,
156
- cardinality2: rel.cardinality2,
157
- label: rel.label,
158
- identifying: rel.identifying,
159
- points,
160
- })
161
- }
162
-
163
- return {
164
- width: result.width ?? 600,
165
- height: result.height ?? 400,
166
- accessibilityTitle: diagram.accessibilityTitle,
167
- accessibilityDescription: diagram.accessibilityDescription,
168
- entities: positionedEntities,
169
- relationships,
170
- }
171
- }
172
-
173
- /**
174
- * Lay out a parsed ER diagram using ELK.js.
175
- */
176
- export function layoutErDiagram(
177
- diagram: ErDiagram,
178
- options: RenderOptions = {}
179
- ): PositionedErDiagram {
180
- if (diagram.entities.length === 0) {
181
- return { width: 0, height: 0, accessibilityTitle: diagram.accessibilityTitle, accessibilityDescription: diagram.accessibilityDescription, entities: [], relationships: [] }
182
- }
183
-
184
- const { elkGraph, entitySizes } = buildErElkGraph(diagram, options)
185
- const result = elkLayoutSync(elkGraph)
186
- return extractErLayout(result, diagram, entitySizes)
187
- }