agentic-mermaid 0.1.1 → 0.2.0

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 (340) hide show
  1. package/AGENT_NATIVE.md +155 -91
  2. package/CHANGELOG.md +163 -4
  3. package/Instructions_for_agents.md +10 -10
  4. package/LICENSES/Apache-2.0.txt +202 -0
  5. package/README.md +31 -38
  6. package/THIRD_PARTY_NOTICES.md +29 -0
  7. package/assets/hero.png +0 -0
  8. package/dist/agent-core.d.ts +463 -0
  9. package/dist/agent-core.js +397 -0
  10. package/dist/agent.d.ts +73 -1868
  11. package/dist/agent.js +336 -37325
  12. package/dist/agentic-mermaid-mcp.js +7 -38399
  13. package/dist/am.js +33626 -40446
  14. package/dist/chunk-2P5FKUQC.js +3485 -0
  15. package/dist/chunk-2S3VSS6I.js +149 -0
  16. package/dist/chunk-2SILJDW2.js +37 -0
  17. package/dist/chunk-BJYMBT4I.js +61963 -0
  18. package/dist/chunk-FDM43XU7.js +615 -0
  19. package/dist/chunk-MYPDVZCO.js +4702 -0
  20. package/dist/index-DWPa2MJs.d.ts +6780 -0
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +310 -33014
  23. package/dist/mcp-cli-5J47WEY3.js +17 -0
  24. package/docs/README.md +39 -31
  25. package/docs/agent-api-cookbook.md +44 -35
  26. package/docs/agent-mutation-policy.md +1 -1
  27. package/docs/agent-workflow-examples.md +2 -2
  28. package/docs/api.md +284 -77
  29. package/docs/ascii.md +26 -16
  30. package/docs/code-mode-impact.md +214 -0
  31. package/docs/comparison.md +23 -11
  32. package/docs/computational-aesthetics-prototype-plan.md +252 -0
  33. package/docs/config.md +26 -10
  34. package/docs/custom-fonts.md +265 -0
  35. package/docs/custom-style-cookbook.md +130 -9
  36. package/docs/diagram-families.md +48 -23
  37. package/docs/features.md +59 -52
  38. package/docs/fork-differences.md +6 -3
  39. package/docs/getting-started.md +23 -16
  40. package/docs/issue-derived-test-cases.md +29 -22
  41. package/docs/mcp-code-mode-rationale.md +13 -6
  42. package/docs/mcp-http-transport.md +20 -13
  43. package/docs/mermaid-layout-complaints.md +66 -52
  44. package/docs/mutation-testing.md +145 -66
  45. package/docs/quality.md +23 -14
  46. package/docs/react.md +2 -2
  47. package/docs/schemas/style-spec.schema.json +1221 -30
  48. package/docs/style-authoring.md +241 -38
  49. package/docs/svg-semantic-contract.md +49 -0
  50. package/docs/testing-strategy.md +166 -58
  51. package/docs/theming.md +19 -32
  52. package/examples/styles/catalog.json +54 -0
  53. package/examples/styles/cloudflare-workers-inspired-prototype.mmd +9 -0
  54. package/examples/styles/cloudflare-workers-inspired-prototype.style.json +110 -0
  55. package/examples/styles/cupertino-prototype.mmd +10 -0
  56. package/examples/styles/cupertino-prototype.style.json +63 -0
  57. package/examples/styles/mid-century-report.style.json +2 -2
  58. package/examples/styles/star-chart-atlas.style.json +2 -1
  59. package/examples/styles/transit-route-map.style.json +2 -2
  60. package/examples/styles/vercel-inspired-prototype.mmd +6 -0
  61. package/examples/styles/vercel-inspired-prototype.style.json +87 -0
  62. package/package.json +85 -45
  63. package/server.json +2 -2
  64. package/skills/agentic-mermaid-diagram-workflow/SKILL.md +17 -36
  65. package/skills/agentic-mermaid-diagram-workflow/references/cli.md +4 -5
  66. package/skills/agentic-mermaid-diagram-workflow/references/code-mode.md +15 -31
  67. package/skills/agentic-mermaid-diagram-workflow/references/sequence.md +10 -14
  68. package/skills/agentic-mermaid-live-editor/SKILL.md +100 -206
  69. package/TODO.md +0 -684
  70. package/dist/index-wjRjbsP-.d.ts +0 -1102
  71. package/docs/assets/improvements/box-start-connector.png +0 -0
  72. package/docs/assets/improvements/comment-dropped-lint.png +0 -0
  73. package/docs/assets/improvements/er-content-loss.png +0 -0
  74. package/docs/assets/improvements/fan-in-trunks.png +0 -0
  75. package/docs/assets/improvements/gantt-family.png +0 -0
  76. package/docs/assets/improvements/gantt-milestone-clamp.png +0 -0
  77. package/docs/assets/improvements/gantt-verify-seam.png +0 -0
  78. package/docs/assets/improvements/subgraph-container-edges.png +0 -0
  79. package/docs/assets/improvements/wrapper-frontmatter.png +0 -0
  80. package/docs/assets/improvements/wrapper-init-directive.png +0 -0
  81. package/docs/assets/improvements/wrapper-leading-comment.png +0 -0
  82. package/docs/assets/style-cookbook/mid-century-report.png +0 -0
  83. package/docs/assets/style-cookbook/star-chart-atlas.png +0 -0
  84. package/docs/assets/style-cookbook/transit-route-map.png +0 -0
  85. package/docs/contributing/adding-diagram-types.md +0 -144
  86. package/docs/contributing/diagram-family-citizenship.matrix.json +0 -2127
  87. package/docs/contributing/diagram-family-citizenship.md +0 -82
  88. package/docs/contributing/harvesting-upstream-tests.md +0 -126
  89. package/docs/contributing/lessons-learned.md +0 -276
  90. package/docs/contributing/releasing.md +0 -82
  91. package/docs/contributing/visual-review-evidence.md +0 -53
  92. package/docs/design/families/README.md +0 -26
  93. package/docs/design/families/architecture-beta.md +0 -48
  94. package/docs/design/families/flowchart-parser-conformance.md +0 -22
  95. package/docs/design/families/gantt-research.md +0 -137
  96. package/docs/design/families/gantt.md +0 -329
  97. package/docs/design/families/journey-agentic-cards-before.png +0 -0
  98. package/docs/design/families/journey-experience-curve-implementation.png +0 -0
  99. package/docs/design/families/journey-mermaid-classic-implementation.png +0 -0
  100. package/docs/design/families/journey-mermaid-classic-prototype.png +0 -0
  101. package/docs/design/families/journey-mermaid-classic-prototype.svg +0 -163
  102. package/docs/design/families/journey-mermaid-classic-prototype.svg.png +0 -0
  103. package/docs/design/families/journey-migration-parity.md +0 -439
  104. package/docs/design/families/journey-section-overlap-after.png +0 -0
  105. package/docs/design/families/journey-section-overlap-before.png +0 -0
  106. package/docs/design/families/journey-usage-research.md +0 -423
  107. package/docs/design/families/journey.md +0 -153
  108. package/docs/design/families/xychart.md +0 -85
  109. package/docs/design/system/README.md +0 -45
  110. package/docs/design/system/abstraction-audit.md +0 -224
  111. package/docs/design/system/abstraction-recommendations.md +0 -655
  112. package/docs/design/system/architecture.mmd +0 -29
  113. package/docs/design/system/architecture.svg +0 -137
  114. package/docs/design/system/layout-guarantees-and-robustness.md +0 -351
  115. package/docs/design/system/layout-rubric.md +0 -138
  116. package/docs/design/system/route-contracts.md +0 -848
  117. package/docs/design/system/source-preservation-ladder.md +0 -52
  118. package/docs/design/system/styles-rollout.md +0 -216
  119. package/docs/design/system/ugly-layouts.md +0 -119
  120. package/docs/layout-characterization/README.md +0 -245
  121. package/docs/layout-characterization/contact-sheet-families.md +0 -498
  122. package/docs/layout-characterization/contact-sheet.md +0 -638
  123. package/docs/layout-characterization/properties.md +0 -281
  124. package/docs/layout-characterization/visual-quality.md +0 -160
  125. package/docs/layout-characterization/visual-snapshots/architecture.svg +0 -79
  126. package/docs/layout-characterization/visual-snapshots/class.svg +0 -60
  127. package/docs/layout-characterization/visual-snapshots/er.svg +0 -61
  128. package/docs/layout-characterization/visual-snapshots/flowchart.svg +0 -58
  129. package/docs/layout-characterization/visual-snapshots/gantt.svg +0 -52
  130. package/docs/layout-characterization/visual-snapshots/journey.svg +0 -98
  131. package/docs/layout-characterization/visual-snapshots/pie.svg +0 -36
  132. package/docs/layout-characterization/visual-snapshots/quadrant.svg +0 -47
  133. package/docs/layout-characterization/visual-snapshots/sequence.svg +0 -59
  134. package/docs/layout-characterization/visual-snapshots/state.svg +0 -52
  135. package/docs/layout-characterization/visual-snapshots/timeline.svg +0 -64
  136. package/docs/layout-characterization/visual-snapshots/xychart.svg +0 -97
  137. package/docs/project/divergences.md +0 -98
  138. package/docs/project/dogfooding-docs-strategy.md +0 -66
  139. package/docs/project/hosted-mcp-cloudflare-plan.md +0 -338
  140. package/docs/project/lessons-learned.md +0 -1019
  141. package/docs/project/remove-role-styling-plan.md +0 -176
  142. package/examples/agent-improve-auth-flow.ts +0 -206
  143. package/examples/agent-loop.ts +0 -53
  144. package/examples/mcp-vs-cli-complex-diagrams.ts +0 -133
  145. package/llms.txt +0 -104
  146. package/skill-evals/README.md +0 -77
  147. package/skill-evals/fixtures/architecture-cache/input.mmd +0 -5
  148. package/skill-evals/fixtures/class-payment/input.mmd +0 -4
  149. package/skill-evals/fixtures/er-orders/input.mmd +0 -10
  150. package/skill-evals/fixtures/flowchart-cache/input.mmd +0 -3
  151. package/skill-evals/fixtures/gantt-release/input.mmd +0 -7
  152. package/skill-evals/fixtures/journey-checkout/input.mmd +0 -6
  153. package/skill-evals/fixtures/pie-exports/input.mmd +0 -5
  154. package/skill-evals/fixtures/quadrant-priorities/input.mmd +0 -11
  155. package/skill-evals/fixtures/sequence-retry/input.mmd +0 -8
  156. package/skill-evals/fixtures/state-lifecycle/input.mmd +0 -5
  157. package/skill-evals/fixtures/timeline-release/input.mmd +0 -6
  158. package/skill-evals/fixtures/xychart-growth/input.mmd +0 -5
  159. package/skill-evals/shared-benchmark.json +0 -510
  160. package/src/agent/analyze.ts +0 -157
  161. package/src/agent/apply.ts +0 -146
  162. package/src/agent/architecture-body.ts +0 -458
  163. package/src/agent/certificates.ts +0 -110
  164. package/src/agent/class-body.ts +0 -319
  165. package/src/agent/core.ts +0 -207
  166. package/src/agent/create.ts +0 -106
  167. package/src/agent/describe.ts +0 -368
  168. package/src/agent/er-body.ts +0 -224
  169. package/src/agent/facts.ts +0 -360
  170. package/src/agent/families-builtin.ts +0 -920
  171. package/src/agent/families.ts +0 -232
  172. package/src/agent/family-layouts.ts +0 -832
  173. package/src/agent/flowchart-body.ts +0 -372
  174. package/src/agent/flowchart-unsupported.ts +0 -243
  175. package/src/agent/font-coverage.ts +0 -288
  176. package/src/agent/gantt-body.ts +0 -495
  177. package/src/agent/index.ts +0 -10
  178. package/src/agent/journey-body.ts +0 -374
  179. package/src/agent/label-metrics.ts +0 -28
  180. package/src/agent/layout-to-rendered.ts +0 -63
  181. package/src/agent/mutate.ts +0 -97
  182. package/src/agent/mutation-ops.ts +0 -51
  183. package/src/agent/op-schema.ts +0 -443
  184. package/src/agent/parse.ts +0 -223
  185. package/src/agent/pie-body.ts +0 -270
  186. package/src/agent/png.ts +0 -171
  187. package/src/agent/quadrant-body.ts +0 -336
  188. package/src/agent/quality.ts +0 -363
  189. package/src/agent/readability-audit.ts +0 -92
  190. package/src/agent/rendered-route-audit.ts +0 -61
  191. package/src/agent/sequence-body.ts +0 -345
  192. package/src/agent/serialize.ts +0 -214
  193. package/src/agent/state-body.ts +0 -589
  194. package/src/agent/structural-count.ts +0 -150
  195. package/src/agent/timeline-body.ts +0 -280
  196. package/src/agent/trace-log.ts +0 -43
  197. package/src/agent/types.ts +0 -995
  198. package/src/agent/verify.ts +0 -603
  199. package/src/agent/xychart-body.ts +0 -472
  200. package/src/architecture/config.ts +0 -282
  201. package/src/architecture/layout.ts +0 -496
  202. package/src/architecture/parser.ts +0 -375
  203. package/src/architecture/renderer.ts +0 -611
  204. package/src/architecture/types.ts +0 -113
  205. package/src/ascii/ansi.ts +0 -423
  206. package/src/ascii/architecture.ts +0 -210
  207. package/src/ascii/canvas.ts +0 -443
  208. package/src/ascii/class-diagram.ts +0 -697
  209. package/src/ascii/converter.ts +0 -475
  210. package/src/ascii/draw.ts +0 -1693
  211. package/src/ascii/edge-bundling.ts +0 -328
  212. package/src/ascii/edge-routing.ts +0 -330
  213. package/src/ascii/er-diagram.ts +0 -439
  214. package/src/ascii/gantt.ts +0 -276
  215. package/src/ascii/grid.ts +0 -747
  216. package/src/ascii/index.ts +0 -196
  217. package/src/ascii/journey.ts +0 -169
  218. package/src/ascii/meta.ts +0 -244
  219. package/src/ascii/multiline-utils.ts +0 -80
  220. package/src/ascii/pathfinder.ts +0 -301
  221. package/src/ascii/pie.ts +0 -67
  222. package/src/ascii/quadrant.ts +0 -158
  223. package/src/ascii/reverse.ts +0 -216
  224. package/src/ascii/sequence.ts +0 -499
  225. package/src/ascii/shapes/circle.ts +0 -27
  226. package/src/ascii/shapes/corners.ts +0 -143
  227. package/src/ascii/shapes/diamond.ts +0 -27
  228. package/src/ascii/shapes/hexagon.ts +0 -27
  229. package/src/ascii/shapes/index.ts +0 -106
  230. package/src/ascii/shapes/rectangle.ts +0 -168
  231. package/src/ascii/shapes/rounded.ts +0 -27
  232. package/src/ascii/shapes/special.ts +0 -332
  233. package/src/ascii/shapes/stadium.ts +0 -110
  234. package/src/ascii/shapes/state.ts +0 -192
  235. package/src/ascii/shapes/types.ts +0 -73
  236. package/src/ascii/timeline.ts +0 -141
  237. package/src/ascii/types.ts +0 -312
  238. package/src/ascii/validate.ts +0 -120
  239. package/src/ascii/width.ts +0 -81
  240. package/src/ascii/wrap.ts +0 -131
  241. package/src/ascii/xychart.ts +0 -919
  242. package/src/browser.ts +0 -29
  243. package/src/class/layout.ts +0 -240
  244. package/src/class/parser.ts +0 -332
  245. package/src/class/renderer.ts +0 -638
  246. package/src/class/types.ts +0 -129
  247. package/src/cli/agent-instructions.ts +0 -1
  248. package/src/cli/am-bin.ts +0 -6
  249. package/src/cli/exit-codes.ts +0 -18
  250. package/src/cli/index.ts +0 -1132
  251. package/src/cli/init-agent.ts +0 -147
  252. package/src/cli/run-entrypoint.ts +0 -10
  253. package/src/color-resolver.ts +0 -152
  254. package/src/elk-instance.ts +0 -114
  255. package/src/er/layout.ts +0 -187
  256. package/src/er/parser.ts +0 -226
  257. package/src/er/renderer.ts +0 -792
  258. package/src/er/types.ts +0 -99
  259. package/src/family-rubric.ts +0 -425
  260. package/src/font-manifest.ts +0 -31
  261. package/src/gantt/layout.ts +0 -365
  262. package/src/gantt/parser.ts +0 -282
  263. package/src/gantt/pipeline.ts +0 -27
  264. package/src/gantt/renderer.ts +0 -414
  265. package/src/gantt/schedule.ts +0 -513
  266. package/src/gantt/types.ts +0 -255
  267. package/src/index.ts +0 -368
  268. package/src/journey/layout.ts +0 -554
  269. package/src/journey/parse-core.ts +0 -251
  270. package/src/journey/parser.ts +0 -101
  271. package/src/journey/renderer.ts +0 -917
  272. package/src/journey/types.ts +0 -144
  273. package/src/layout/geometry.ts +0 -182
  274. package/src/layout/pass.ts +0 -142
  275. package/src/layout/passes/index.ts +0 -3916
  276. package/src/layout-engine.ts +0 -1565
  277. package/src/layout-rubric.ts +0 -659
  278. package/src/mcp/artifacts.ts +0 -137
  279. package/src/mcp/dynamic-harness.ts +0 -31
  280. package/src/mcp/dynamic-modules.d.ts +0 -7
  281. package/src/mcp/facade.ts +0 -608
  282. package/src/mcp/harness-runtime.ts +0 -203
  283. package/src/mcp/hosted-server.ts +0 -468
  284. package/src/mcp/mcp-bin.ts +0 -3
  285. package/src/mcp/mcp-cli.ts +0 -82
  286. package/src/mcp/protocol.ts +0 -13
  287. package/src/mcp/sandbox.ts +0 -195
  288. package/src/mcp/sdk-decl.ts +0 -391
  289. package/src/mcp/server.ts +0 -362
  290. package/src/mcp/tool-surface.ts +0 -146
  291. package/src/mermaid-source.ts +0 -655
  292. package/src/multiline-utils.ts +0 -228
  293. package/src/parser.ts +0 -1031
  294. package/src/pie/layout.ts +0 -168
  295. package/src/pie/parser.ts +0 -136
  296. package/src/pie/renderer.ts +0 -234
  297. package/src/pie/types.ts +0 -82
  298. package/src/quadrant/layout.ts +0 -191
  299. package/src/quadrant/parser.ts +0 -183
  300. package/src/quadrant/renderer.ts +0 -322
  301. package/src/quadrant/types.ts +0 -113
  302. package/src/render-family-hooks.ts +0 -244
  303. package/src/renderer.ts +0 -1099
  304. package/src/route-contracts.ts +0 -2723
  305. package/src/scene/backend.ts +0 -76
  306. package/src/scene/fidelity.ts +0 -183
  307. package/src/scene/hybrid-backend.ts +0 -174
  308. package/src/scene/ir.ts +0 -181
  309. package/src/scene/marks.ts +0 -127
  310. package/src/scene/rough-backend.ts +0 -378
  311. package/src/scene/seed.ts +0 -46
  312. package/src/scene/style-registry.ts +0 -556
  313. package/src/sequence/layout.ts +0 -456
  314. package/src/sequence/parser.ts +0 -255
  315. package/src/sequence/renderer.ts +0 -604
  316. package/src/sequence/types.ts +0 -154
  317. package/src/shape-clipping.ts +0 -351
  318. package/src/shared/accessibility-directives.ts +0 -22
  319. package/src/shared/batched.ts +0 -61
  320. package/src/shared/color-math.ts +0 -93
  321. package/src/shared/svg-a11y.ts +0 -29
  322. package/src/shared/syntax-error.ts +0 -17
  323. package/src/shared/unicode-ranges.ts +0 -135
  324. package/src/styles.ts +0 -318
  325. package/src/svg-paths.ts +0 -28
  326. package/src/text-metrics.ts +0 -248
  327. package/src/theme.ts +0 -710
  328. package/src/timeline/layout.ts +0 -381
  329. package/src/timeline/parser.ts +0 -215
  330. package/src/timeline/renderer.ts +0 -538
  331. package/src/timeline/types.ts +0 -105
  332. package/src/types.ts +0 -462
  333. package/src/website-worker-modules.d.ts +0 -18
  334. package/src/xychart/axis-utils.ts +0 -109
  335. package/src/xychart/colors.ts +0 -124
  336. package/src/xychart/config.ts +0 -88
  337. package/src/xychart/layout.ts +0 -656
  338. package/src/xychart/parser.ts +0 -504
  339. package/src/xychart/renderer.ts +0 -640
  340. package/src/xychart/types.ts +0 -282
@@ -0,0 +1,3485 @@
1
+ import {
2
+ projectKnownRenderErrorDiagnostic,
3
+ projectRenderErrorDiagnostic
4
+ } from "./chunk-2SILJDW2.js";
5
+ import {
6
+ renderMermaidPNG,
7
+ renderMermaidPNGWithReceipt
8
+ } from "./chunk-FDM43XU7.js";
9
+ import {
10
+ analyzeMermaid,
11
+ analyzeMermaidSource,
12
+ buildChecked,
13
+ buildMermaid,
14
+ checkMermaid,
15
+ checkMermaidSource,
16
+ configWarningsForMermaid,
17
+ createMermaid,
18
+ describeMermaid,
19
+ describeMermaidFacts,
20
+ describeMermaidFactsSource,
21
+ describeMermaidSource,
22
+ describeOps,
23
+ hasOpSchema,
24
+ layoutMermaidWithReceipt,
25
+ mutate,
26
+ mutateChecked,
27
+ opSignatures,
28
+ renderMermaidASCII,
29
+ renderMermaidASCIIWithReceipt,
30
+ renderMermaidSVG,
31
+ renderMermaidSVGWithReceipt,
32
+ verifyMermaid,
33
+ verifySummary
34
+ } from "./chunk-MYPDVZCO.js";
35
+ import {
36
+ BUILTIN_FAMILY_METADATA,
37
+ PACKAGE_VERSION,
38
+ ParsedDiagramFamilyMismatchError,
39
+ RENDER_CONTRACT_VERSION,
40
+ RENDER_OUTPUT_DESCRIPTORS,
41
+ RenderCapabilityError,
42
+ architectureVisualOverridesTypeScriptDeclaration,
43
+ asArchitecture,
44
+ asClass,
45
+ asEr,
46
+ asFlowchart,
47
+ asGantt,
48
+ asGitGraph,
49
+ asJourney,
50
+ asMindmap,
51
+ asPie,
52
+ asQuadrant,
53
+ asRadar,
54
+ asSequence,
55
+ asState,
56
+ asTimeline,
57
+ asXyChart,
58
+ knownBuiltinFamilies,
59
+ limitJsonConfigDiagnostics,
60
+ normalizePortablePngBackground,
61
+ parseRegisteredMermaid,
62
+ pngOutputOptionsJsonSchema,
63
+ projectNativePngOutputPolicyInput,
64
+ resolveStyleStack,
65
+ safeCssColor,
66
+ safeCssFontFamily,
67
+ safeCssPaint,
68
+ serializeMermaid,
69
+ sharedRenderOptionsJsonSchema,
70
+ sharedRenderOptionsTypeScriptDeclaration,
71
+ styleSpecTypeScriptDeclaration,
72
+ validateJsonConfigAdmission,
73
+ validateSerializableRenderOptions
74
+ } from "./chunk-BJYMBT4I.js";
75
+
76
+ // src/mcp/server.ts
77
+ import { randomUUID as randomUUID2 } from "crypto";
78
+ import { createServer } from "http";
79
+ import { tmpdir as tmpdir2 } from "os";
80
+ import { join as join2 } from "path";
81
+ import { URL } from "url";
82
+
83
+ // src/mcp/sandbox.ts
84
+ import vm from "vm";
85
+
86
+ // src/mcp/facade.ts
87
+ import { parse as parseJavaScript } from "acorn";
88
+ function createTracingMermaid(trace, makeSandboxError, isClosed, hostPolicy, beforeSdkCall) {
89
+ const diagramIds = /* @__PURE__ */ new WeakMap();
90
+ const trusted = /* @__PURE__ */ new WeakSet();
91
+ const hardened = /* @__PURE__ */ new WeakMap();
92
+ const raw = /* @__PURE__ */ new WeakMap();
93
+ let nextId = 1;
94
+ const forbidden = (prop) => prop === "constructor" || prop === "__proto__" || prop === "prototype";
95
+ const protoFor = (target) => Object.isExtensible(target) ? null : Reflect.getPrototypeOf(target);
96
+ const sandboxError = (message) => makeSandboxError ? makeSandboxError(message) : new Error(message);
97
+ const assertOpen = () => {
98
+ if (isClosed?.()) throw sandboxError("Code Mode SDK calls are not allowed while returning results");
99
+ const blocked = beforeSdkCall?.();
100
+ if (blocked) throw sandboxError(blocked);
101
+ };
102
+ const readonly = () => {
103
+ throw sandboxError("Code Mode SDK results are read-only; use mermaid.mutate(...) for structured edits");
104
+ };
105
+ const arrayMutators = /* @__PURE__ */ new Set(["copyWithin", "fill", "pop", "push", "reverse", "shift", "sort", "splice", "unshift"]);
106
+ const arrayCallbackMethods = /* @__PURE__ */ new Set(["forEach", "map", "filter", "find", "findIndex", "findLast", "findLastIndex", "some", "every", "flatMap"]);
107
+ const rawOf = (value) => value && (typeof value === "object" || typeof value === "function") && raw.has(value) ? raw.get(value) : value;
108
+ const isMap = (value) => value instanceof Map || Object.prototype.toString.call(value) === "[object Map]";
109
+ const isSet = (value) => value instanceof Set || Object.prototype.toString.call(value) === "[object Set]";
110
+ const structuredErrorMetadata = /* @__PURE__ */ new WeakMap();
111
+ const structuredErrorFields = (error) => {
112
+ if (typeof error !== "object" || error === null) return void 0;
113
+ const carried = structuredErrorMetadata.get(error);
114
+ if (carried) return carried;
115
+ let fields;
116
+ if (error instanceof RenderCapabilityError) {
117
+ fields = {
118
+ name: error.name,
119
+ code: error.code,
120
+ output: error.output,
121
+ family: error.family,
122
+ decision: error.decision
123
+ };
124
+ } else if (error instanceof ParsedDiagramFamilyMismatchError) {
125
+ fields = {
126
+ name: error.name,
127
+ code: error.code,
128
+ expectedFamilyId: error.expectedFamilyId,
129
+ detectedFamilyId: error.detectedFamilyId
130
+ };
131
+ } else {
132
+ const renderDiagnostic = projectKnownRenderErrorDiagnostic(error);
133
+ if (!renderDiagnostic) return void 0;
134
+ fields = {
135
+ name: renderDiagnostic.code === "ASCII_TARGET_WIDTH_IMPOSSIBLE" ? "AsciiWidthError" : "MermaidFamilyDetectionError",
136
+ ...renderDiagnostic
137
+ };
138
+ }
139
+ if (!fields) return void 0;
140
+ const encoded = JSON.stringify(fields);
141
+ return encoded === void 0 ? void 0 : JSON.parse(encoded);
142
+ };
143
+ const extensibleDataEnvelope = (value) => {
144
+ if (Object.isExtensible(value)) return value;
145
+ if (Array.isArray(value)) return value.slice();
146
+ const prototype = Reflect.getPrototypeOf(value);
147
+ return prototype === Object.prototype || prototype === null ? Object.assign(Object.create(prototype), value) : value;
148
+ };
149
+ const hostCall = (fn, genericRenderFailure = false) => {
150
+ try {
151
+ return fn();
152
+ } catch (e) {
153
+ const fields = structuredErrorFields(e) ?? (genericRenderFailure ? { name: "RenderError", ...projectRenderErrorDiagnostic(e) } : void 0);
154
+ const wrapped = sandboxError(fields?.message ?? e.message);
155
+ if (fields) {
156
+ structuredErrorMetadata.set(wrapped, fields);
157
+ for (const [field, value] of Object.entries(fields)) {
158
+ Object.defineProperty(wrapped, field, {
159
+ value: harden(value),
160
+ enumerable: true,
161
+ writable: false,
162
+ configurable: false
163
+ });
164
+ }
165
+ }
166
+ throw wrapped;
167
+ }
168
+ };
169
+ const jsonClone = (value) => hostCall(() => {
170
+ if (!value || typeof value !== "object" && typeof value !== "function") return value;
171
+ const encoded = JSON.stringify(value);
172
+ return encoded === void 0 ? void 0 : JSON.parse(encoded);
173
+ });
174
+ const iteratorOf = (items) => {
175
+ let index = 0;
176
+ const iterator = {
177
+ [Symbol.iterator]() {
178
+ return this;
179
+ },
180
+ next() {
181
+ return index < items.length ? { value: items[index++], done: false } : { value: void 0, done: true };
182
+ }
183
+ };
184
+ return harden(iterator);
185
+ };
186
+ function descriptorFor(target, prop) {
187
+ if (forbidden(prop)) return void 0;
188
+ const desc = Reflect.getOwnPropertyDescriptor(target, prop);
189
+ if (!desc) return void 0;
190
+ if ("value" in desc) return { ...desc, value: harden(desc.value) };
191
+ return { ...desc, get: desc.get ? harden(desc.get) : void 0, set: desc.set ? harden(readonly) : void 0 };
192
+ }
193
+ const isDiagramLike = (value) => Boolean(value && typeof value === "object" && "body" in value && "canonicalSource" in value);
194
+ const idOf = (value) => {
195
+ value = rawOf(value);
196
+ if (!isDiagramLike(value)) return void 0;
197
+ const obj = value;
198
+ let id = diagramIds.get(obj);
199
+ if (!id) {
200
+ id = nextId++;
201
+ diagramIds.set(obj, id);
202
+ }
203
+ return id;
204
+ };
205
+ const trustDiagram = (value) => {
206
+ value = rawOf(value);
207
+ if (isDiagramLike(value)) trusted.add(value);
208
+ };
209
+ const requireTrustedDiagram = (value, verb) => {
210
+ value = rawOf(value);
211
+ if (value && (typeof value === "object" || typeof value === "function") && !trusted.has(value)) {
212
+ throw sandboxError(`Code Mode ${verb} input must come from mermaid.parseRegisteredMermaid(...) or mermaid.mutate(...)`);
213
+ }
214
+ };
215
+ const rememberRaw = (proxy2, target) => {
216
+ raw.set(proxy2, target);
217
+ if (isDiagramLike(target)) diagramIds.set(proxy2, idOf(target));
218
+ return proxy2;
219
+ };
220
+ const harden = (value) => {
221
+ if (!value || typeof value !== "object" && typeof value !== "function") return value;
222
+ const unwrapped = rawOf(value);
223
+ if (unwrapped !== value) return harden(unwrapped);
224
+ const obj = value;
225
+ const cached = hardened.get(obj);
226
+ if (cached) return cached;
227
+ if (isMap(value)) {
228
+ let proxy3;
229
+ proxy3 = new Proxy(value, {
230
+ get(target, prop) {
231
+ if (forbidden(prop)) return void 0;
232
+ if (prop === "size") return target.size;
233
+ if (prop === "get") return harden((key) => harden(target.get(rawOf(key))));
234
+ if (prop === "set" || prop === "delete" || prop === "clear" || prop === "getOrInsert" || prop === "getOrInsertComputed") return harden(readonly);
235
+ if (prop === "has") return harden((key) => target.has(rawOf(key)));
236
+ if (prop === Symbol.iterator || prop === "entries") return harden(() => iteratorOf(Array.from(target.entries(), ([k, v]) => harden([harden(k), harden(v)]))));
237
+ if (prop === "values") return harden(() => iteratorOf(Array.from(target.values(), (v) => harden(v))));
238
+ if (prop === "keys") return harden(() => iteratorOf(Array.from(target.keys(), (k) => harden(k))));
239
+ if (prop === "forEach") return harden((cb, thisArg) => {
240
+ for (const [k, v] of target.entries()) cb.call(thisArg, harden(v), harden(k), proxy3);
241
+ });
242
+ const got = hostCall(() => Reflect.get(target, prop, target));
243
+ return typeof got === "function" ? void 0 : harden(got);
244
+ },
245
+ set() {
246
+ return readonly();
247
+ },
248
+ deleteProperty() {
249
+ return readonly();
250
+ },
251
+ defineProperty() {
252
+ return readonly();
253
+ },
254
+ setPrototypeOf() {
255
+ return readonly();
256
+ },
257
+ getOwnPropertyDescriptor(target, prop) {
258
+ return descriptorFor(target, prop);
259
+ },
260
+ preventExtensions() {
261
+ return readonly();
262
+ },
263
+ getPrototypeOf(target) {
264
+ return protoFor(target);
265
+ }
266
+ });
267
+ hardened.set(obj, proxy3);
268
+ return rememberRaw(proxy3, value);
269
+ }
270
+ if (isSet(value)) {
271
+ let proxy3;
272
+ proxy3 = new Proxy(value, {
273
+ get(target, prop) {
274
+ if (forbidden(prop)) return void 0;
275
+ if (prop === "size") return target.size;
276
+ if (prop === "add" || prop === "delete" || prop === "clear") return harden(readonly);
277
+ if (prop === "has") return harden((val) => target.has(rawOf(val)));
278
+ if (prop === Symbol.iterator || prop === "values" || prop === "keys") return harden(() => iteratorOf(Array.from(target.values(), (v) => harden(v))));
279
+ if (prop === "entries") return harden(() => iteratorOf(Array.from(target.values(), (v) => harden([harden(v), harden(v)]))));
280
+ if (prop === "forEach") return harden((cb, thisArg) => {
281
+ for (const v of target.values()) cb.call(thisArg, harden(v), harden(v), proxy3);
282
+ });
283
+ const got = hostCall(() => Reflect.get(target, prop, target));
284
+ return typeof got === "function" ? void 0 : harden(got);
285
+ },
286
+ set() {
287
+ return readonly();
288
+ },
289
+ deleteProperty() {
290
+ return readonly();
291
+ },
292
+ defineProperty() {
293
+ return readonly();
294
+ },
295
+ setPrototypeOf() {
296
+ return readonly();
297
+ },
298
+ getOwnPropertyDescriptor(target, prop) {
299
+ return descriptorFor(target, prop);
300
+ },
301
+ preventExtensions() {
302
+ return readonly();
303
+ },
304
+ getPrototypeOf(target) {
305
+ return protoFor(target);
306
+ }
307
+ });
308
+ hardened.set(obj, proxy3);
309
+ return rememberRaw(proxy3, value);
310
+ }
311
+ if (typeof value === "function") {
312
+ const original = value;
313
+ const callable = (...args) => harden(hostCall(() => Reflect.apply(original, void 0, args)));
314
+ const proxy3 = new Proxy(callable, {
315
+ apply(_target, thisArg, args) {
316
+ return harden(hostCall(() => Reflect.apply(original, thisArg, args)));
317
+ },
318
+ get(_target, prop, receiver) {
319
+ if (forbidden(prop)) return void 0;
320
+ if (!Reflect.getOwnPropertyDescriptor(original, prop)) return void 0;
321
+ return harden(hostCall(() => Reflect.get(original, prop, receiver)));
322
+ },
323
+ set() {
324
+ return readonly();
325
+ },
326
+ deleteProperty() {
327
+ return readonly();
328
+ },
329
+ defineProperty() {
330
+ return readonly();
331
+ },
332
+ setPrototypeOf() {
333
+ return readonly();
334
+ },
335
+ getOwnPropertyDescriptor(_target, prop) {
336
+ return descriptorFor(original, prop);
337
+ },
338
+ preventExtensions() {
339
+ return readonly();
340
+ },
341
+ getPrototypeOf() {
342
+ return protoFor(original);
343
+ }
344
+ });
345
+ hardened.set(obj, proxy3);
346
+ return rememberRaw(proxy3, value);
347
+ }
348
+ const proxyTarget = extensibleDataEnvelope(value);
349
+ let proxy2;
350
+ proxy2 = new Proxy(proxyTarget, {
351
+ get(target, prop, receiver) {
352
+ if (forbidden(prop)) return void 0;
353
+ if (Array.isArray(target)) {
354
+ if (typeof prop === "string" && arrayMutators.has(prop)) return harden(readonly);
355
+ if (prop === Symbol.iterator || prop === "values") return harden(() => iteratorOf(Array.prototype.map.call(target, (v) => harden(v))));
356
+ if (prop === "entries") return harden(() => iteratorOf(Array.prototype.map.call(target, (v, i) => harden([i, harden(v)]))));
357
+ if (prop === "keys") return harden(() => iteratorOf(Array.from({ length: target.length }, (_, i) => i)));
358
+ if (typeof prop === "string" && arrayCallbackMethods.has(prop)) {
359
+ return harden((cb, thisArg) => {
360
+ const values = Array.prototype.map.call(target, (v) => harden(v));
361
+ const call = (v, i) => cb.call(thisArg, v, i, proxy2);
362
+ if (prop === "forEach") {
363
+ values.forEach(call);
364
+ return void 0;
365
+ }
366
+ if (prop === "map") return values.map(call);
367
+ if (prop === "filter") return values.filter((v, i) => call(v, i));
368
+ if (prop === "find") return values.find((v, i) => Boolean(call(v, i)));
369
+ if (prop === "findIndex") return values.findIndex((v, i) => Boolean(call(v, i)));
370
+ if (prop === "findLast") {
371
+ for (let i = values.length - 1; i >= 0; i--) if (call(values[i], i)) return values[i];
372
+ return void 0;
373
+ }
374
+ if (prop === "findLastIndex") {
375
+ for (let i = values.length - 1; i >= 0; i--) if (call(values[i], i)) return i;
376
+ return -1;
377
+ }
378
+ if (prop === "some") return values.some((v, i) => Boolean(call(v, i)));
379
+ if (prop === "every") return values.every((v, i) => Boolean(call(v, i)));
380
+ if (prop === "flatMap") return values.flatMap(call);
381
+ });
382
+ }
383
+ if (prop === "toSorted") {
384
+ return harden((compare) => {
385
+ const values = Array.prototype.map.call(target, (v) => harden(v));
386
+ return compare ? values.slice().sort((a, b) => compare(a, b)) : values.slice().sort();
387
+ });
388
+ }
389
+ if (prop === "toReversed") return harden(() => Array.prototype.map.call(target, (v) => harden(v)).reverse());
390
+ if (prop === "toSpliced") return harden(function(start, deleteCount, ...items) {
391
+ const values = Array.prototype.map.call(target, (v) => harden(v));
392
+ const copy = values.slice();
393
+ if (arguments.length === 1) copy.splice(start);
394
+ else copy.splice(start, deleteCount ?? 0, ...items.map((item) => harden(rawOf(item))));
395
+ return copy;
396
+ });
397
+ if (prop === "with") return harden((index, item) => {
398
+ const values = Array.prototype.map.call(target, (v) => harden(v));
399
+ const normalized = index < 0 ? values.length + index : index;
400
+ if (normalized < 0 || normalized >= values.length) throw sandboxError("Invalid array index");
401
+ const copy = values.slice();
402
+ copy[normalized] = harden(rawOf(item));
403
+ return copy;
404
+ });
405
+ if (prop === "reduce" || prop === "reduceRight") {
406
+ return harden(function(cb, initial) {
407
+ const values = Array.prototype.map.call(target, (v) => harden(v));
408
+ const reducer = (previous, current, index) => cb(previous, current, index, proxy2);
409
+ return arguments.length >= 2 ? prop === "reduce" ? values.reduce(reducer, initial) : values.reduceRight(reducer, initial) : prop === "reduce" ? values.reduce(reducer) : values.reduceRight(reducer);
410
+ });
411
+ }
412
+ }
413
+ if (!Reflect.getOwnPropertyDescriptor(target, prop)) return void 0;
414
+ const got = hostCall(() => Reflect.get(target, prop, receiver));
415
+ return typeof got === "function" ? void 0 : harden(got);
416
+ },
417
+ set() {
418
+ return readonly();
419
+ },
420
+ deleteProperty() {
421
+ return readonly();
422
+ },
423
+ defineProperty() {
424
+ return readonly();
425
+ },
426
+ setPrototypeOf() {
427
+ return readonly();
428
+ },
429
+ has(target, prop) {
430
+ return forbidden(prop) ? false : Reflect.has(target, prop);
431
+ },
432
+ getOwnPropertyDescriptor(target, prop) {
433
+ return descriptorFor(target, prop);
434
+ },
435
+ preventExtensions() {
436
+ return readonly();
437
+ },
438
+ getPrototypeOf(target) {
439
+ return protoFor(target);
440
+ }
441
+ });
442
+ hardened.set(obj, proxy2);
443
+ if (proxyTarget !== obj) hardened.set(proxyTarget, proxy2);
444
+ return rememberRaw(proxy2, value);
445
+ };
446
+ const fingerprint = (value) => fingerprintDiagram(rawOf(value));
447
+ const bodyKind = (value) => {
448
+ const kind = value?.body?.kind;
449
+ return kind != null && FAMILY_KINDS.has(kind) ? kind : "opaque";
450
+ };
451
+ const push = (call) => {
452
+ trace?.push(call);
453
+ };
454
+ const sdkTarget = {
455
+ parseRegisteredMermaid,
456
+ createMermaid,
457
+ buildMermaid,
458
+ asFlowchart,
459
+ asState,
460
+ asSequence,
461
+ asTimeline,
462
+ asClass,
463
+ asEr,
464
+ asJourney,
465
+ asArchitecture,
466
+ asXyChart,
467
+ asPie,
468
+ asQuadrant,
469
+ asGantt,
470
+ asMindmap,
471
+ asGitGraph,
472
+ asRadar,
473
+ mutate,
474
+ verifyMermaid,
475
+ analyzeMermaid,
476
+ analyzeMermaidSource,
477
+ describeMermaidFacts,
478
+ describeMermaidFactsSource,
479
+ checkMermaid,
480
+ checkMermaidSource,
481
+ serializeMermaid,
482
+ renderMermaidSVG,
483
+ renderMermaidSVGWithReceipt,
484
+ renderMermaidASCII,
485
+ renderMermaidASCIIWithReceipt,
486
+ layoutMermaidWithReceipt,
487
+ // Read-only op discovery: field shapes / enum values / constraint notes and
488
+ // compact signatures for a family's ops, so a Code Mode script can look up
489
+ // exact op shapes at runtime instead of guessing (or triggering INVALID_OP).
490
+ describeOps,
491
+ opSignatures
492
+ };
493
+ const sdkProps = new Set(Reflect.ownKeys(sdkTarget));
494
+ const sdkValues = /* @__PURE__ */ new Map();
495
+ const sdkValue = (target, prop) => {
496
+ if (forbidden(prop) || !sdkProps.has(prop)) return void 0;
497
+ if (sdkValues.has(prop)) return sdkValues.get(prop);
498
+ let value;
499
+ if (prop === "parseRegisteredMermaid") value = harden((source) => {
500
+ assertOpen();
501
+ if (typeof source !== "string") throw sandboxError(`Code Mode ${prop} source must be a string`);
502
+ const r = hostCall(() => target.parseRegisteredMermaid(source));
503
+ if (r.ok) trustDiagram(r.value);
504
+ const diagram = r.ok ? idOf(r.value) : void 0;
505
+ push({ verb: "parse", diagram, source: r.ok ? r.value.body.kind === "opaque" ? r.value.body.source : r.value.canonicalSource : void 0 });
506
+ return harden(r);
507
+ });
508
+ else if (prop === "createMermaid") value = harden((kind, opts) => {
509
+ assertOpen();
510
+ const r = hostCall(() => target.createMermaid(kind, jsonClone(opts)));
511
+ trustDiagram(r);
512
+ push({ verb: "create", family: FAMILY_KINDS.has(kind) ? kind : void 0, diagram: idOf(r), ok: true });
513
+ return harden(r);
514
+ });
515
+ else if (prop === "buildMermaid") value = harden((kind, ops, opts) => {
516
+ assertOpen();
517
+ const opsForHost = jsonClone(ops);
518
+ const r = hostCall(() => buildChecked(kind, opsForHost, jsonClone(opts)));
519
+ if (r.ok) trustDiagram(r.value);
520
+ push({
521
+ verb: "create",
522
+ family: FAMILY_KINDS.has(kind) ? kind : void 0,
523
+ diagram: r.ok ? idOf(r.value) : void 0,
524
+ ops: Array.isArray(ops) ? ops.length : void 0,
525
+ ok: r.ok
526
+ });
527
+ return harden(r);
528
+ });
529
+ else if (typeof prop === "string" && prop.startsWith("as") && prop in target) {
530
+ value = harden((d) => {
531
+ assertOpen();
532
+ requireTrustedDiagram(d, String(prop));
533
+ const input = idOf(d);
534
+ const r = hostCall(() => target[prop](rawOf(d)));
535
+ if (r) trustDiagram(r);
536
+ push({ verb: "narrow", family: narrowerFamily(prop), input, ok: r !== null });
537
+ return harden(r);
538
+ });
539
+ } else if (prop === "mutate") value = harden((d, op) => {
540
+ assertOpen();
541
+ requireTrustedDiagram(d, "mutate");
542
+ const opForHost = jsonClone(op);
543
+ const call = {
544
+ verb: "mutate",
545
+ body: bodyKind(rawOf(d)),
546
+ input: idOf(d),
547
+ opKind: typeof opForHost === "object" && opForHost && "kind" in opForHost ? String(opForHost.kind) : void 0
548
+ };
549
+ push(call);
550
+ const r = hostCall(() => mutateChecked(rawOf(d), opForHost));
551
+ if (r.ok) {
552
+ trustDiagram(r.value);
553
+ call.output = idOf(r.value);
554
+ call.fingerprint = fingerprint(r.value);
555
+ }
556
+ return harden(r);
557
+ });
558
+ else if (prop === "verifyMermaid") value = harden((input, opts) => {
559
+ assertOpen();
560
+ requireTrustedDiagram(input, "verifyMermaid");
561
+ const r = hostCall(() => target.verifyMermaid(rawOf(input), opts));
562
+ const diagram = idOf(input);
563
+ push({ verb: "verify", diagram, ok: r.ok, inspected: false, fingerprint: fingerprint(input) });
564
+ return harden(new Proxy(r, {
565
+ get(verifyTarget, verifyProp, verifyReceiver) {
566
+ if (isClosed?.()) throw sandboxError("Code Mode SDK calls are not allowed while returning results");
567
+ if (verifyProp === "ok" || verifyProp === "warnings" || verifyProp === "layout") {
568
+ push({ verb: "verify_inspect", diagram, property: verifyProp });
569
+ }
570
+ if (forbidden(verifyProp)) return void 0;
571
+ return harden(hostCall(() => Reflect.get(verifyTarget, verifyProp, verifyReceiver)));
572
+ },
573
+ set() {
574
+ return readonly();
575
+ },
576
+ deleteProperty() {
577
+ return readonly();
578
+ },
579
+ defineProperty() {
580
+ return readonly();
581
+ },
582
+ setPrototypeOf() {
583
+ return readonly();
584
+ },
585
+ getOwnPropertyDescriptor(target2, prop2) {
586
+ return descriptorFor(target2, prop2);
587
+ },
588
+ preventExtensions() {
589
+ return readonly();
590
+ },
591
+ getPrototypeOf(target2) {
592
+ return protoFor(target2);
593
+ }
594
+ }));
595
+ });
596
+ else if (prop === "analyzeMermaid") value = harden((d) => {
597
+ assertOpen();
598
+ requireTrustedDiagram(d, "analyzeMermaid");
599
+ const r = hostCall(() => target.analyzeMermaid(rawOf(d)));
600
+ push({ verb: "analyze", diagram: idOf(d), ok: true, fingerprint: fingerprint(d) });
601
+ return harden(r);
602
+ });
603
+ else if (prop === "analyzeMermaidSource") value = harden((source) => {
604
+ assertOpen();
605
+ if (typeof source !== "string") throw sandboxError("Code Mode analyzeMermaidSource source must be a string");
606
+ const r = hostCall(() => target.analyzeMermaidSource(source));
607
+ push({ verb: "analyze", source, ok: r.ok });
608
+ return harden(r);
609
+ });
610
+ else if (prop === "describeMermaidFacts") value = harden((d) => {
611
+ assertOpen();
612
+ requireTrustedDiagram(d, "describeMermaidFacts");
613
+ const r = hostCall(() => target.describeMermaidFacts(rawOf(d)));
614
+ push({ verb: "facts", diagram: idOf(d), ok: true, fingerprint: fingerprint(d) });
615
+ return harden(r);
616
+ });
617
+ else if (prop === "describeMermaidFactsSource") value = harden((source) => {
618
+ assertOpen();
619
+ if (typeof source !== "string") throw sandboxError("Code Mode describeMermaidFactsSource source must be a string");
620
+ const r = hostCall(() => target.describeMermaidFactsSource(source));
621
+ push({ verb: "facts", source, ok: r.ok });
622
+ return harden(r);
623
+ });
624
+ else if (prop === "checkMermaid") value = harden((d, spec) => {
625
+ assertOpen();
626
+ requireTrustedDiagram(d, "checkMermaid");
627
+ const r = hostCall(() => target.checkMermaid(rawOf(d), jsonClone(spec)));
628
+ push({ verb: "check", diagram: idOf(d), ok: r.ok, fingerprint: fingerprint(d) });
629
+ return harden(r);
630
+ });
631
+ else if (prop === "checkMermaidSource") value = harden((source, spec) => {
632
+ assertOpen();
633
+ if (typeof source !== "string") throw sandboxError("Code Mode checkMermaidSource source must be a string");
634
+ const r = hostCall(() => target.checkMermaidSource(source, jsonClone(spec)));
635
+ push({ verb: "check", source, ok: r.ok ? r.value.ok : false });
636
+ return harden(r);
637
+ });
638
+ else if (prop === "serializeMermaid") value = harden((d) => {
639
+ assertOpen();
640
+ requireTrustedDiagram(d, "serializeMermaid");
641
+ const source = hostCall(() => target.serializeMermaid(rawOf(d)));
642
+ push({ verb: "serialize", diagram: idOf(d), source, fingerprint: fingerprint(d) });
643
+ return source;
644
+ });
645
+ else if (prop === "renderMermaidSVG" || prop === "renderMermaidSVGWithReceipt" || prop === "renderMermaidASCII" || prop === "renderMermaidASCIIWithReceipt" || prop === "layoutMermaidWithReceipt") value = harden((input, opts) => {
646
+ assertOpen();
647
+ if (input && typeof input === "object") requireTrustedDiagram(input, String(prop));
648
+ const isAscii = prop === "renderMermaidASCII" || prop === "renderMermaidASCIIWithReceipt";
649
+ const configCallback = opts?.onConfigDiagnostic;
650
+ const projectionCallback = isAscii ? opts?.onProjectionDiagnostic : void 0;
651
+ if (configCallback !== void 0 && typeof configCallback !== "function") {
652
+ throw sandboxError(`Code Mode ${String(prop)} onConfigDiagnostic must be a function`);
653
+ }
654
+ if (projectionCallback !== void 0 && typeof projectionCallback !== "function") {
655
+ throw sandboxError(`Code Mode ${String(prop)} onProjectionDiagnostic must be a function`);
656
+ }
657
+ let cloned = jsonClone(opts);
658
+ if (hostPolicy) cloned = { ...cloned ?? {}, ...hostPolicy.render };
659
+ const configDiagnostics = [];
660
+ const projectionDiagnostics = [];
661
+ if (configCallback || projectionCallback) cloned ??= {};
662
+ if (configCallback) {
663
+ cloned.onConfigDiagnostic = (diagnostic) => configDiagnostics.push(diagnostic);
664
+ }
665
+ if (projectionCallback) {
666
+ cloned.onProjectionDiagnostic = (diagnostic) => projectionDiagnostics.push(diagnostic);
667
+ }
668
+ const rendered = hostCall(
669
+ () => target[prop](rawOf(input), cloned),
670
+ true
671
+ );
672
+ for (const diagnostic of configDiagnostics) configCallback(harden(jsonClone(diagnostic)));
673
+ for (const diagnostic of projectionDiagnostics) projectionCallback(harden(jsonClone(diagnostic)));
674
+ return jsonClone(rendered);
675
+ });
676
+ else if (prop === "describeOps" || prop === "opSignatures") value = harden((family) => {
677
+ assertOpen();
678
+ if (typeof family !== "string") throw sandboxError(`Code Mode ${String(prop)} family must be a string`);
679
+ if (!hasOpSchema(family)) {
680
+ const families = knownBuiltinFamilies().filter(hasOpSchema);
681
+ throw sandboxError(`Code Mode ${String(prop)} family must be one of: ${families.join(", ")}`);
682
+ }
683
+ return harden(hostCall(() => target[prop](family)));
684
+ });
685
+ sdkValues.set(prop, value);
686
+ return value;
687
+ };
688
+ const marshalResult = (value) => {
689
+ try {
690
+ const rawObj = rawOf(value);
691
+ const candidate = rawObj && typeof rawObj === "object" && !Array.isArray(rawObj) && rawObj.ok === true && "value" in rawObj ? rawOf(rawObj.value) : rawObj;
692
+ if (isDiagramLike(candidate) && trusted.has(candidate)) {
693
+ const d = candidate;
694
+ const verification = verifyMermaid(d);
695
+ const summary = verifySummary(verification);
696
+ if (!verification.ok) {
697
+ return {
698
+ ok: false,
699
+ family: d.kind,
700
+ error: {
701
+ code: "VERIFY_FAILED",
702
+ message: "returned diagram failed verify; source was not emitted",
703
+ details: summary.warnings
704
+ }
705
+ };
706
+ }
707
+ return { ok: true, family: d.kind, source: serializeMermaid(d), verify: summary };
708
+ }
709
+ } catch {
710
+ }
711
+ return value;
712
+ };
713
+ const proxy = new Proxy(sdkTarget, {
714
+ get(target, prop) {
715
+ return sdkValue(target, prop);
716
+ },
717
+ set() {
718
+ return readonly();
719
+ },
720
+ deleteProperty() {
721
+ return readonly();
722
+ },
723
+ defineProperty() {
724
+ return readonly();
725
+ },
726
+ setPrototypeOf() {
727
+ return readonly();
728
+ },
729
+ getOwnPropertyDescriptor(target, prop) {
730
+ if (!sdkProps.has(prop) || forbidden(prop)) return void 0;
731
+ const desc = Reflect.getOwnPropertyDescriptor(target, prop);
732
+ return desc && "value" in desc ? { ...desc, value: sdkValue(target, prop) } : void 0;
733
+ },
734
+ preventExtensions() {
735
+ return readonly();
736
+ },
737
+ getPrototypeOf(target) {
738
+ return protoFor(target);
739
+ },
740
+ has(_target, prop) {
741
+ return sdkProps.has(prop) && !forbidden(prop);
742
+ },
743
+ ownKeys() {
744
+ return Array.from(sdkProps);
745
+ }
746
+ });
747
+ resultMarshallers.set(proxy, marshalResult);
748
+ return proxy;
749
+ }
750
+ var resultMarshallers = /* @__PURE__ */ new WeakMap();
751
+ function marshalCodeModeResult(sdk, value) {
752
+ const fn = sdk && typeof sdk === "object" ? resultMarshallers.get(sdk) : void 0;
753
+ return fn ? fn(value) : value;
754
+ }
755
+ var CODE_MODE_RETURN_HINT = "return plain data instead \u2014 e.g. serializeMermaid(d) for a diagram, or read the fields you need (verifyMermaid(d).ok, .warnings); the declarative mutate/build tools return a ready { ok, family, source, verify } envelope";
756
+ function fingerprintDiagram(value) {
757
+ if (!value || typeof value !== "object") return void 0;
758
+ if (!("body" in value) || !("canonicalSource" in value)) return void 0;
759
+ try {
760
+ return JSON.stringify(value, jsonReplacer);
761
+ } catch {
762
+ return void 0;
763
+ }
764
+ }
765
+ var FAMILY_KINDS = new Set(BUILTIN_FAMILY_METADATA.map((m) => m.id));
766
+ var NARROWER_TO_FAMILY = new Map(
767
+ BUILTIN_FAMILY_METADATA.map((m) => [m.narrower, m.id])
768
+ );
769
+ function narrowerFamily(prop) {
770
+ const family = NARROWER_TO_FAMILY.get(String(prop));
771
+ if (!family) throw new Error(`Unknown Code Mode narrower: ${String(prop)}`);
772
+ return family;
773
+ }
774
+ function expressionFirstWraps(code) {
775
+ const t = code.trim();
776
+ const stripped = t.replace(/;\s*$/, "");
777
+ const expressionWrapped = `(() => { return (
778
+ ${stripped}
779
+ ) })()`;
780
+ const statementWrapped = `(() => { ${code} })()`;
781
+ try {
782
+ new Function(`return (
783
+ ${stripped}
784
+ )`);
785
+ return [expressionWrapped];
786
+ } catch {
787
+ return [statementWrapped];
788
+ }
789
+ }
790
+ function unsupportedCodeReason(code) {
791
+ const ast = parseCodeModeAst(code);
792
+ if (!ast) return void 0;
793
+ let usesAsync = false;
794
+ let usesRealm = false;
795
+ walkJavaScriptAst(ast, (node, parent, parentKey) => {
796
+ if (node.type === "ImportExpression" || node.type === "AwaitExpression") usesAsync = true;
797
+ if ("async" in node && node.async === true) usesAsync = true;
798
+ if (node.type !== "Identifier" || !("name" in node) || typeof node.name !== "string") return;
799
+ const propertyNameOnly = parentKey === "key" && parent?.computed !== true || parent?.type === "MemberExpression" && parentKey === "property" && parent.computed === false;
800
+ if (propertyNameOnly && !(node.name === "fromAsync" && parent?.type === "MemberExpression" && parent.object?.type === "Identifier" && parent.object.name === "Array")) return;
801
+ if (SYNC_UNSUPPORTED_IDENTIFIERS.has(node.name)) usesAsync = true;
802
+ if (REALM_UNSUPPORTED_IDENTIFIERS.has(node.name)) usesRealm = true;
803
+ });
804
+ if (usesAsync) {
805
+ return "Code Mode is synchronous; async/await, Promise jobs, finalizers, queueMicrotask, Array.fromAsync, and dynamic import are not supported";
806
+ }
807
+ if (usesRealm) {
808
+ return "Code Mode does not expose blocking or realm-creating globals";
809
+ }
810
+ return void 0;
811
+ }
812
+ var SYNC_UNSUPPORTED_IDENTIFIERS = /* @__PURE__ */ new Set([
813
+ "async",
814
+ "await",
815
+ "Promise",
816
+ "AsyncDisposableStack",
817
+ "FinalizationRegistry",
818
+ "WeakRef",
819
+ "fromAsync",
820
+ "queueMicrotask"
821
+ ]);
822
+ var REALM_UNSUPPORTED_IDENTIFIERS = /* @__PURE__ */ new Set(["Atomics", "SharedArrayBuffer", "ShadowRealm", "WebAssembly"]);
823
+ function parseCodeModeAst(code) {
824
+ const stripped = code.trim().replace(/;\s*$/, "");
825
+ const candidates = [
826
+ `(${stripped})`,
827
+ `function __agent_code__(){
828
+ ${code}
829
+ }`,
830
+ // Parse otherwise-invalid top-level await so it is rejected before an
831
+ // isolate/CPU budget is allocated and telemetry remains truthful.
832
+ `async function __agent_code__(){
833
+ ${code}
834
+ }`
835
+ ];
836
+ for (const candidate of candidates) {
837
+ try {
838
+ return parseJavaScript(candidate, { ecmaVersion: "latest", sourceType: "script" });
839
+ } catch {
840
+ }
841
+ }
842
+ return void 0;
843
+ }
844
+ function walkJavaScriptAst(node, visit, parent, parentKey) {
845
+ const record = node;
846
+ visit(record, parent, parentKey);
847
+ for (const [key, value] of Object.entries(record)) {
848
+ if (key === "start" || key === "end" || key === "type") continue;
849
+ if (Array.isArray(value)) {
850
+ for (const child of value) if (isAcornNode(child)) walkJavaScriptAst(child, visit, record, key);
851
+ } else if (isAcornNode(value)) {
852
+ walkJavaScriptAst(value, visit, record, key);
853
+ }
854
+ }
855
+ }
856
+ function isAcornNode(value) {
857
+ return Boolean(value && typeof value === "object" && "type" in value && typeof value.type === "string");
858
+ }
859
+ function jsonReplacer(_k, v) {
860
+ if (v instanceof Map) return Object.fromEntries(v);
861
+ if (v instanceof Set) return Array.from(v);
862
+ return v;
863
+ }
864
+
865
+ // src/mcp/execute-limits.ts
866
+ var DEFAULT_EXECUTE_TIMEOUT_MS = 5e3;
867
+ var DEFAULT_EXECUTE_OUTPUT_LIMITS = Object.freeze({
868
+ maxResultBytes: 2 * 1024 * 1024,
869
+ maxLogEntries: 1e3,
870
+ maxLogBytes: 256 * 1024
871
+ });
872
+ var LOGS_TRUNCATED_MARKER = "\u2026[logs truncated: hosted execute caps console output]";
873
+ function normalizeExecuteOutputLimits(value) {
874
+ if (value === void 0) return DEFAULT_EXECUTE_OUTPUT_LIMITS;
875
+ for (const field of ["maxResultBytes", "maxLogEntries", "maxLogBytes"]) {
876
+ if (!Number.isSafeInteger(value[field]) || value[field] <= 0) {
877
+ throw new TypeError(`Code Mode ${field} must be a positive safe integer`);
878
+ }
879
+ }
880
+ return Object.freeze({ ...value });
881
+ }
882
+ function utf8ByteLength(value) {
883
+ let bytes = 0;
884
+ for (const char of value) {
885
+ const code = char.codePointAt(0);
886
+ bytes += code <= 127 ? 1 : code <= 2047 ? 2 : code <= 65535 ? 3 : 4;
887
+ }
888
+ return bytes;
889
+ }
890
+
891
+ // src/mcp/sandbox.ts
892
+ var MIN_BUN_SDK_TIMEOUT_MS = 1e3;
893
+ var SAFE_GLOBALS = {};
894
+ async function executeInSandbox(code, opts = {}) {
895
+ try {
896
+ return runInSandbox(code, opts);
897
+ } finally {
898
+ await new Promise((resolve2) => setTimeout(resolve2, 0));
899
+ }
900
+ }
901
+ function runInSandbox(code, opts = {}) {
902
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_EXECUTE_TIMEOUT_MS;
903
+ const outputLimits = normalizeExecuteOutputLimits(opts.outputLimits);
904
+ const startedAt = performance.now();
905
+ const remainingBudgetMs = () => Math.floor(timeoutMs - (performance.now() - startedAt));
906
+ const trace = [];
907
+ const early = (error) => opts.trace ? { ok: false, error, logs: [], trace } : { ok: false, error, logs: [] };
908
+ const unsupported = unsupportedCodeReason(code);
909
+ if (unsupported) return early(unsupported);
910
+ const sandbox = {
911
+ ...SAFE_GLOBALS,
912
+ eval: void 0,
913
+ Function: void 0
914
+ };
915
+ const context = vm.createContext(sandbox, {
916
+ name: "agentic-mermaid-codemode",
917
+ microtaskMode: "afterEvaluate",
918
+ codeGeneration: { strings: false, wasm: false }
919
+ });
920
+ vm.runInContext(`
921
+ (() => {
922
+ const logs = []
923
+ let logBytes = 0
924
+ let logsTruncated = false
925
+ const maxLogEntries = ${outputLimits.maxLogEntries}
926
+ const maxLogBytes = ${outputLimits.maxLogBytes}
927
+ const truncationMarker = ${JSON.stringify(LOGS_TRUNCATED_MARKER)}
928
+ const safeString = String
929
+ const safeStringify = JSON.stringify.bind(JSON)
930
+ const objectToString = Object.prototype.toString
931
+ const safeToStringTag = (v) => objectToString.call(v)
932
+ const safeFromEntries = Object.fromEntries.bind(Object)
933
+ const safeArrayFrom = Array.from.bind(Array)
934
+ const utf8Bytes = (value) => {
935
+ let bytes = 0
936
+ for (const char of value) {
937
+ const code = char.codePointAt(0)
938
+ bytes += code <= 0x7f ? 1 : code <= 0x7ff ? 2 : code <= 0xffff ? 3 : 4
939
+ }
940
+ return bytes
941
+ }
942
+ const truncateUtf8 = (value, maximum) => {
943
+ let bytes = 0
944
+ let output = ''
945
+ for (const char of value) {
946
+ const code = char.codePointAt(0)
947
+ const width = code <= 0x7f ? 1 : code <= 0x7ff ? 2 : code <= 0xffff ? 3 : 4
948
+ if (bytes + width > maximum) break
949
+ output += char
950
+ bytes += width
951
+ }
952
+ return output
953
+ }
954
+ const str = (v) => {
955
+ if (typeof v === 'string') return v
956
+ try {
957
+ const json = safeStringify(v)
958
+ return typeof json === 'string' ? json : safeString(v)
959
+ } catch {
960
+ try { return safeString(v) } catch { return '[unprintable]' }
961
+ }
962
+ }
963
+ const appendLog = (args) => {
964
+ if (logsTruncated) return
965
+ if (logs.length >= maxLogEntries || logBytes >= maxLogBytes) {
966
+ logsTruncated = true
967
+ logs.push(truncationMarker)
968
+ return
969
+ }
970
+ let line = args.map(str).join(' ')
971
+ const remaining = maxLogBytes - logBytes
972
+ if (utf8Bytes(line) > remaining) {
973
+ line = truncateUtf8(line, remaining)
974
+ logsTruncated = true
975
+ }
976
+ logBytes += utf8Bytes(line)
977
+ logs.push(line)
978
+ if (logsTruncated) logs.push(truncationMarker)
979
+ }
980
+ Object.defineProperty(globalThis, '__pi_read_logs', {
981
+ value: () => safeStringify(logs),
982
+ writable: false,
983
+ configurable: false,
984
+ })
985
+ Object.defineProperty(globalThis, '__pi_result', { value: undefined, writable: true, configurable: false })
986
+ Object.defineProperty(globalThis, '__pi_error', { value: undefined, writable: true, configurable: false })
987
+ Object.defineProperty(globalThis, '__pi_format_error', {
988
+ value: (err) => {
989
+ try {
990
+ if (typeof err === 'string') return err
991
+ if (err && (typeof err === 'object' || typeof err === 'function')) {
992
+ const message = err.message
993
+ if (typeof message === 'string') return message
994
+ }
995
+ return safeString(err)
996
+ } catch { return 'sandbox error' }
997
+ },
998
+ writable: false,
999
+ configurable: false,
1000
+ })
1001
+ Object.defineProperty(globalThis, '__pi_stringify_result', {
1002
+ value: (value) => safeStringify(value, (_k, v) => {
1003
+ const tag = safeToStringTag(v)
1004
+ if (tag === '[object Map]') return safeFromEntries(v)
1005
+ if (tag === '[object Set]') return safeArrayFrom(v)
1006
+ return v
1007
+ }),
1008
+ writable: false,
1009
+ configurable: false,
1010
+ })
1011
+ Object.defineProperty(globalThis, 'console', {
1012
+ value: Object.freeze({
1013
+ log: (...a) => appendLog(a),
1014
+ error: (...a) => appendLog(a),
1015
+ warn: (...a) => appendLog(a),
1016
+ }),
1017
+ writable: false,
1018
+ configurable: false,
1019
+ })
1020
+ try {
1021
+ Object.defineProperty(Error, 'prepareStackTrace', { value: undefined, writable: false, configurable: false })
1022
+ Object.freeze(Error)
1023
+ Object.freeze(Error.prototype)
1024
+ } catch {}
1025
+ try { Object.defineProperty(Array, 'fromAsync', { value: undefined, writable: false, configurable: false }) } catch {}
1026
+ try { Object.freeze(Promise.prototype); Object.freeze(Promise) } catch {}
1027
+ for (const name of [
1028
+ 'constructor', '__proto__', 'eval', 'Function', 'Promise',
1029
+ 'Atomics', 'SharedArrayBuffer', 'ShadowRealm', 'WebAssembly',
1030
+ 'queueMicrotask', 'setTimeout', 'setInterval', 'setImmediate',
1031
+ 'fetch', 'process', 'require', 'Bun', 'Worker', 'MessageChannel', 'MessagePort',
1032
+ 'AsyncDisposableStack', 'DisposableStack', 'SuppressedError', 'FinalizationRegistry', 'WeakRef',
1033
+ ]) {
1034
+ try { Object.defineProperty(globalThis, name, { value: undefined, writable: false, configurable: false }) } catch {}
1035
+ }
1036
+ try { Object.setPrototypeOf(globalThis, null) } catch {}
1037
+ })()
1038
+ `, context);
1039
+ const makeSandboxError = vm.runInContext(`(message) => new Error(String(message))`, context);
1040
+ let sdkClosed = false;
1041
+ let sdkCallOccurred = false;
1042
+ sandbox.mermaid = createTracingMermaid(
1043
+ opts.trace ? trace : void 0,
1044
+ makeSandboxError,
1045
+ () => sdkClosed,
1046
+ void 0,
1047
+ () => {
1048
+ sdkCallOccurred = true;
1049
+ if (typeof Bun === "undefined") return void 0;
1050
+ const remaining = remainingBudgetMs();
1051
+ return remaining < MIN_BUN_SDK_TIMEOUT_MS ? `Code Mode SDK calls under Bun require at least ${MIN_BUN_SDK_TIMEOUT_MS}ms of remaining timeout budget (timeoutMs >= ${MIN_BUN_SDK_TIMEOUT_MS})` : void 0;
1052
+ }
1053
+ );
1054
+ const readLogs = () => {
1055
+ try {
1056
+ const encoded = vm.runInContext(`__pi_read_logs()`, context, { timeout: 50 });
1057
+ if (typeof encoded !== "string") return [];
1058
+ const value = JSON.parse(encoded);
1059
+ return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
1060
+ } catch {
1061
+ return [];
1062
+ }
1063
+ };
1064
+ const errorMessage = (err) => {
1065
+ try {
1066
+ sandbox.__pi_error = err;
1067
+ const message = vm.runInContext(`__pi_format_error(__pi_error)`, context, { timeout: 50 });
1068
+ return typeof message === "string" ? message : "sandbox error";
1069
+ } catch (e) {
1070
+ return e instanceof Error ? e.message : "sandbox error";
1071
+ } finally {
1072
+ try {
1073
+ sandbox.__pi_error = void 0;
1074
+ } catch {
1075
+ }
1076
+ }
1077
+ };
1078
+ const wraps = expressionFirstWraps(code);
1079
+ let result;
1080
+ let runErr = null;
1081
+ for (const wrapped of wraps) {
1082
+ let script;
1083
+ try {
1084
+ script = new vm.Script(wrapped, { filename: "codemode.ts" });
1085
+ } catch (e) {
1086
+ runErr = e;
1087
+ break;
1088
+ }
1089
+ try {
1090
+ const remainingMs = remainingBudgetMs();
1091
+ if (remainingMs <= 0) throw new Error(`Code Mode execution timed out after ${timeoutMs}ms`);
1092
+ result = script.runInContext(context, { timeout: remainingMs });
1093
+ runErr = null;
1094
+ break;
1095
+ } catch (e) {
1096
+ runErr = e;
1097
+ break;
1098
+ }
1099
+ }
1100
+ const withTrace = (r) => opts.trace ? { ...r, trace } : r;
1101
+ if (runErr) {
1102
+ sdkClosed = true;
1103
+ return withTrace({ ok: false, error: errorMessage(runErr), logs: readLogs() });
1104
+ }
1105
+ if (result === void 0) {
1106
+ sdkClosed = true;
1107
+ return withTrace({ ok: true, value: null, logs: readLogs() });
1108
+ }
1109
+ sdkClosed = true;
1110
+ let marshalled = result;
1111
+ const resultMayContainSdkValue = sdkCallOccurred && result !== null && (typeof result === "object" || typeof result === "function");
1112
+ if (resultMayContainSdkValue) {
1113
+ const remainingMs = remainingBudgetMs();
1114
+ if (remainingMs <= 0 || typeof Bun !== "undefined" && remainingMs < MIN_BUN_SDK_TIMEOUT_MS) {
1115
+ return withTrace({ ok: false, error: `Code Mode execution timed out after ${timeoutMs}ms while committing the result`, logs: readLogs() });
1116
+ }
1117
+ const marshalKey = `__pi_marshal_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`;
1118
+ const marshalTarget = () => marshalCodeModeResult(sandbox.mermaid, result);
1119
+ const safeMarshal = new Proxy(marshalTarget, {
1120
+ apply: (target) => Reflect.apply(target, void 0, []),
1121
+ get(target, prop, receiver) {
1122
+ if (prop === "constructor" || prop === "__proto__" || prop === "prototype") return void 0;
1123
+ return Object.prototype.hasOwnProperty.call(target, prop) ? Reflect.get(target, prop, receiver) : void 0;
1124
+ },
1125
+ getPrototypeOf: () => null,
1126
+ has: (target, prop) => Object.prototype.hasOwnProperty.call(target, prop) && prop !== "constructor" && prop !== "__proto__" && prop !== "prototype",
1127
+ set: () => false,
1128
+ defineProperty: () => false,
1129
+ deleteProperty: () => false,
1130
+ setPrototypeOf: () => false
1131
+ });
1132
+ try {
1133
+ if (!Reflect.defineProperty(sandbox, marshalKey, {
1134
+ value: safeMarshal,
1135
+ enumerable: false,
1136
+ writable: false,
1137
+ configurable: true
1138
+ })) throw new Error("could not install the result commit guard");
1139
+ marshalled = vm.runInContext(`globalThis[${JSON.stringify(marshalKey)}]()`, context, { timeout: remainingMs });
1140
+ } catch (e) {
1141
+ const message = errorMessage(e);
1142
+ return withTrace({
1143
+ ok: false,
1144
+ error: /timed out/i.test(message) ? `Code Mode execution timed out after ${timeoutMs}ms while committing the result` : `could not commit Code Mode result: ${message}`,
1145
+ logs: readLogs()
1146
+ });
1147
+ } finally {
1148
+ try {
1149
+ Reflect.deleteProperty(sandbox, marshalKey);
1150
+ } catch {
1151
+ }
1152
+ }
1153
+ }
1154
+ let stringified;
1155
+ try {
1156
+ const stringifyTimeoutMs = remainingBudgetMs();
1157
+ if (stringifyTimeoutMs <= 0) {
1158
+ return withTrace({ ok: false, error: `Code Mode execution timed out after ${timeoutMs}ms while serializing the result`, logs: readLogs() });
1159
+ }
1160
+ sandbox.__pi_result = marshalled;
1161
+ stringified = vm.runInContext("__pi_stringify_result(__pi_result)", context, { timeout: stringifyTimeoutMs });
1162
+ } catch (e) {
1163
+ return withTrace({ ok: false, error: `non-serializable: ${errorMessage(e)} \u2014 ${CODE_MODE_RETURN_HINT}`, logs: readLogs() });
1164
+ } finally {
1165
+ try {
1166
+ sandbox.__pi_result = void 0;
1167
+ } catch {
1168
+ }
1169
+ }
1170
+ if (stringified === void 0) return withTrace({ ok: true, value: null, logs: readLogs() });
1171
+ if (typeof stringified !== "string") return withTrace({ ok: false, error: "non-serializable: result did not stringify to JSON text", logs: readLogs() });
1172
+ if (utf8ByteLength(stringified) > outputLimits.maxResultBytes) {
1173
+ return withTrace({ ok: false, error: `sandbox result exceeded ${outputLimits.maxResultBytes} bytes; reduce console output or returned data`, logs: readLogs() });
1174
+ }
1175
+ try {
1176
+ return withTrace({ ok: true, value: JSON.parse(stringified), logs: readLogs() });
1177
+ } catch (e) {
1178
+ return withTrace({ ok: false, error: `non-serializable: ${e instanceof Error ? e.message : "invalid JSON"}`, logs: readLogs() });
1179
+ }
1180
+ }
1181
+
1182
+ // src/mcp/protocol.ts
1183
+ function preserveExactJsonRpcIds(body) {
1184
+ const replacements = [];
1185
+ const stack = [];
1186
+ let i = 0;
1187
+ const stringEnd = (start) => {
1188
+ let j = start + 1;
1189
+ while (j < body.length) {
1190
+ if (body[j] === "\\") {
1191
+ j += 2;
1192
+ continue;
1193
+ }
1194
+ if (body[j] === '"') return j + 1;
1195
+ j++;
1196
+ }
1197
+ return j;
1198
+ };
1199
+ while (i < body.length) {
1200
+ const ch = body[i];
1201
+ if (ch === '"') {
1202
+ const end = stringEnd(i);
1203
+ let key;
1204
+ try {
1205
+ key = JSON.parse(body.slice(i, end));
1206
+ } catch {
1207
+ i = end;
1208
+ continue;
1209
+ }
1210
+ const rpcObject = stack.length === 1 && stack[0] === "{" || stack.length === 2 && stack[0] === "[" && stack[1] === "{";
1211
+ let cursor = end;
1212
+ while (/\s/.test(body[cursor] ?? "")) cursor++;
1213
+ if (rpcObject && key === "id" && body[cursor] === ":") {
1214
+ cursor++;
1215
+ while (/\s/.test(body[cursor] ?? "")) cursor++;
1216
+ const number = body.slice(cursor).match(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/)?.[0];
1217
+ if (number && !isSafelyRoundTrippableInteger(number)) {
1218
+ let sentinel = `__agentic_mermaid_exact_id_${replacements.length}__`;
1219
+ while (body.includes(sentinel)) sentinel += "_";
1220
+ replacements.push({ sentinel, raw: number, start: cursor, end: cursor + number.length });
1221
+ }
1222
+ }
1223
+ i = end;
1224
+ continue;
1225
+ }
1226
+ if (ch === "{" || ch === "[") stack.push(ch);
1227
+ else if (ch === "}" || ch === "]") stack.pop();
1228
+ i++;
1229
+ }
1230
+ let protectedBody = body;
1231
+ for (const replacement of replacements.slice().reverse()) {
1232
+ protectedBody = protectedBody.slice(0, replacement.start) + JSON.stringify(replacement.sentinel) + protectedBody.slice(replacement.end);
1233
+ }
1234
+ return { body: protectedBody, ids: replacements.map(({ sentinel, raw }) => ({ sentinel, raw })) };
1235
+ }
1236
+ function isSafelyRoundTrippableInteger(token) {
1237
+ if (!/^-?(?:0|[1-9]\d*)$/.test(token)) return false;
1238
+ if (token === "-0") return false;
1239
+ try {
1240
+ const value = BigInt(token);
1241
+ return value <= BigInt(Number.MAX_SAFE_INTEGER) && value >= BigInt(Number.MIN_SAFE_INTEGER);
1242
+ } catch {
1243
+ return false;
1244
+ }
1245
+ }
1246
+ function isJsonContentType(value) {
1247
+ if (!value) return false;
1248
+ const token = String.raw`[!#$%&'*+.^_\x60|~0-9A-Za-z-]+`;
1249
+ const quoted = String.raw`"(?:[^"\\]|\\.)*"`;
1250
+ return new RegExp(String.raw`^\s*application/json\s*(?:;\s*${token}\s*=\s*(?:${token}|${quoted}))*\s*$`, "i").test(value);
1251
+ }
1252
+ function stringifyJsonRpc(payload, exactIds = []) {
1253
+ let body = JSON.stringify(payload);
1254
+ for (const { sentinel, raw } of exactIds) {
1255
+ body = body.replace(`"id":${JSON.stringify(sentinel)}`, `"id":${raw}`);
1256
+ }
1257
+ return body;
1258
+ }
1259
+ function reply(id, result) {
1260
+ return { jsonrpc: "2.0", id, result };
1261
+ }
1262
+ function rpcError(id, code, message) {
1263
+ return { jsonrpc: "2.0", id, error: { code, message } };
1264
+ }
1265
+
1266
+ // src/mcp/tool-surface.ts
1267
+ function withClosedMcpInputSchema(tool) {
1268
+ return { ...tool, inputSchema: { ...tool.inputSchema, additionalProperties: false } };
1269
+ }
1270
+ var MCP_SERVER_NAME = "agentic-mermaid-mcp";
1271
+ var MCP_SERVER_VERSION = PACKAGE_VERSION;
1272
+ var PURE_COMPUTE_ANNOTATIONS = {
1273
+ readOnlyHint: true,
1274
+ destructiveHint: false,
1275
+ idempotentHint: true,
1276
+ openWorldHint: false
1277
+ };
1278
+ var SANDBOX_EXECUTE_ANNOTATIONS = {
1279
+ readOnlyHint: true,
1280
+ destructiveHint: false,
1281
+ idempotentHint: false,
1282
+ openWorldHint: false
1283
+ };
1284
+ var MANAGED_ARTIFACT_ANNOTATIONS = {
1285
+ // output=file/url creates a managed file and repeated calls can create
1286
+ // different time-addressed artifacts, so the tool as a whole is neither
1287
+ // read-only nor idempotent even though output=base64 is pure.
1288
+ readOnlyHint: false,
1289
+ destructiveHint: false,
1290
+ idempotentHint: false,
1291
+ openWorldHint: false
1292
+ };
1293
+ var EXECUTE_TIMEOUT_ERROR = "execute timeoutMs must be a positive integer";
1294
+ function isValidExecuteTimeout(value) {
1295
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
1296
+ }
1297
+ function mcpRenderOptionSchemaProperties(optionsDescription) {
1298
+ return {
1299
+ options: { ...sharedRenderOptionsJsonSchema(), description: optionsDescription }
1300
+ };
1301
+ }
1302
+ function projectMcpRenderOptions(args) {
1303
+ const nested = args.options === void 0 ? {} : args.options;
1304
+ const nestedProblems = validateSerializableRenderOptions(nested);
1305
+ if (nestedProblems.length > 0) throw new Error(`invalid render options: ${nestedProblems.join("; ")}`);
1306
+ const projected = { ...nested };
1307
+ const problems = validateSerializableRenderOptions(projected);
1308
+ if (problems.length > 0) throw new Error(`invalid render options: ${problems.join("; ")}`);
1309
+ return projected;
1310
+ }
1311
+ var FORBIDDEN_JSON_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
1312
+ function plainJsonObject(value) {
1313
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1314
+ const prototype = Object.getPrototypeOf(value);
1315
+ return prototype === Object.prototype || prototype === null;
1316
+ }
1317
+ function schemaRecord(value) {
1318
+ return plainJsonObject(value) ? value : void 0;
1319
+ }
1320
+ function dereferenceSchema(schema, root) {
1321
+ const reference = schema.$ref;
1322
+ if (typeof reference !== "string" || !reference.startsWith("#/")) return void 0;
1323
+ let cursor = root;
1324
+ for (const encoded of reference.slice(2).split("/")) {
1325
+ if (!plainJsonObject(cursor)) return void 0;
1326
+ cursor = cursor[encoded.replaceAll("~1", "/").replaceAll("~0", "~")];
1327
+ }
1328
+ return schemaRecord(cursor);
1329
+ }
1330
+ function validateSchemaValue(value, schema, inheritedRoot, path, ancestors) {
1331
+ const root = schemaRecord(schema.$defs) ? schema : inheritedRoot;
1332
+ if (schema.$ref !== void 0) {
1333
+ const resolved = dereferenceSchema(schema, root);
1334
+ return resolved ? validateSchemaValue(value, resolved, root, path, ancestors) : [{ path, message: `uses unresolved schema reference ${String(schema.$ref)}` }];
1335
+ }
1336
+ const anyOf = Array.isArray(schema.anyOf) ? schema.anyOf.map(schemaRecord).filter((entry) => entry !== void 0) : [];
1337
+ if (anyOf.length > 0) {
1338
+ const alternatives = anyOf.map((candidate) => validateSchemaValue(value, candidate, root, path, new Set(ancestors)));
1339
+ if (!alternatives.some((problems) => problems.length === 0)) {
1340
+ const expectation = schema["x-agentic-mermaid-validation-expectation"];
1341
+ if (typeof expectation === "string") return [{ path, message: `must be ${expectation}` }];
1342
+ return alternatives.sort((left, right) => left.length - right.length)[0] ?? [{ path, message: "must match an allowed shape" }];
1343
+ }
1344
+ }
1345
+ const oneOf = Array.isArray(schema.oneOf) ? schema.oneOf.map(schemaRecord).filter((entry) => entry !== void 0) : [];
1346
+ if (oneOf.length > 0) {
1347
+ const matching = oneOf.filter((candidate) => validateSchemaValue(value, candidate, root, path, new Set(ancestors)).length === 0);
1348
+ if (matching.length !== 1) {
1349
+ return [{ path, message: `must match exactly one allowed shape (matched ${matching.length})` }];
1350
+ }
1351
+ }
1352
+ if (Object.prototype.hasOwnProperty.call(schema, "const") && !Object.is(value, schema.const)) {
1353
+ return [{ path, message: `must equal ${String(schema.const)}` }];
1354
+ }
1355
+ if (Array.isArray(schema.enum) && !schema.enum.some((candidate) => Object.is(candidate, value))) {
1356
+ return [{ path, message: `must be one of ${schema.enum.map(String).join(" | ")}` }];
1357
+ }
1358
+ const type = schema.type;
1359
+ const typeIsValid = type === void 0 || type === "null" && value === null || type === "string" && typeof value === "string" || type === "number" && typeof value === "number" && Number.isFinite(value) || type === "integer" && typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) || type === "boolean" && typeof value === "boolean" || type === "array" && Array.isArray(value) || type === "object" && plainJsonObject(value);
1360
+ if (!typeIsValid) {
1361
+ const expected = type === "number" ? "a finite number" : type === "integer" ? "a finite integer" : type === "object" ? "a plain JSON object" : type === "array" ? "an array" : type === "null" ? "null" : `a ${String(type)}`;
1362
+ return [{ path, message: `must be ${expected}` }];
1363
+ }
1364
+ if (typeof value === "number") {
1365
+ if (typeof schema.minimum === "number" && value < schema.minimum) return [{ path, message: `must be at least ${schema.minimum}` }];
1366
+ if (typeof schema.exclusiveMinimum === "number" && value <= schema.exclusiveMinimum) return [{ path, message: `must be greater than ${schema.exclusiveMinimum}` }];
1367
+ if (typeof schema.maximum === "number" && value > schema.maximum) return [{ path, message: `must be at most ${schema.maximum}` }];
1368
+ }
1369
+ if (typeof value === "string") {
1370
+ if (typeof schema.minLength === "number" && value.length < schema.minLength) {
1371
+ return [{ path, message: `must contain at least ${schema.minLength} character${schema.minLength === 1 ? "" : "s"}` }];
1372
+ }
1373
+ if (typeof schema.pattern === "string") {
1374
+ try {
1375
+ if (!new RegExp(schema.pattern, "u").test(value)) {
1376
+ if (schema["x-agentic-mermaid-runtime-validator"] === "portablePngBackground") {
1377
+ return [{ path, message: "must be a portable basic color keyword or 3, 4, 6, or 8 digit hex color" }];
1378
+ }
1379
+ return [{ path, message: `must match ${schema.pattern}` }];
1380
+ }
1381
+ } catch {
1382
+ return [{ path, message: "uses an invalid schema pattern" }];
1383
+ }
1384
+ }
1385
+ if (typeof schema.maxLength === "number" && value.length > schema.maxLength) {
1386
+ return [{ path, message: `must contain at most ${schema.maxLength} characters` }];
1387
+ }
1388
+ }
1389
+ if (Array.isArray(value) && type === "array") {
1390
+ if (typeof schema.minItems === "number" && value.length < schema.minItems) {
1391
+ return [{ path, message: `must contain at least ${schema.minItems} item${schema.minItems === 1 ? "" : "s"}` }];
1392
+ }
1393
+ if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
1394
+ return [{ path, message: `must contain at most ${schema.maxItems} items` }];
1395
+ }
1396
+ if (ancestors.has(value)) return [{ path, message: "must be acyclic" }];
1397
+ const itemSchema = schemaRecord(schema.items);
1398
+ if (itemSchema) {
1399
+ ancestors.add(value);
1400
+ try {
1401
+ const problems = value.flatMap((item, index) => validateSchemaValue(item, itemSchema, root, [...path, index], ancestors));
1402
+ if (problems.length > 0) return problems;
1403
+ } finally {
1404
+ ancestors.delete(value);
1405
+ }
1406
+ }
1407
+ }
1408
+ if (plainJsonObject(value) && (type === "object" || schema.properties !== void 0 || schema.required !== void 0 || schema.additionalProperties !== void 0)) {
1409
+ if (ancestors.has(value)) return [{ path, message: "must be acyclic" }];
1410
+ ancestors.add(value);
1411
+ try {
1412
+ const properties = schemaRecord(schema.properties) ?? {};
1413
+ const required = Array.isArray(schema.required) ? schema.required.filter((entry) => typeof entry === "string") : [];
1414
+ const problems = [];
1415
+ for (const key of required) {
1416
+ if (!Object.prototype.hasOwnProperty.call(value, key)) {
1417
+ problems.push({ path: [...path, key], message: "is required" });
1418
+ }
1419
+ }
1420
+ for (const [key, child] of Object.entries(value)) {
1421
+ if (FORBIDDEN_JSON_KEYS.has(key)) {
1422
+ problems.push({ path: [...path, key], message: "uses a forbidden prototype key" });
1423
+ continue;
1424
+ }
1425
+ const propertySchema = schemaRecord(properties[key]);
1426
+ if (propertySchema) {
1427
+ problems.push(...validateSchemaValue(child, propertySchema, root, [...path, key], ancestors));
1428
+ continue;
1429
+ }
1430
+ if (schema.additionalProperties === false) {
1431
+ problems.push({ path: [...path, key], message: "is not allowed" });
1432
+ continue;
1433
+ }
1434
+ const additionalSchema = schemaRecord(schema.additionalProperties);
1435
+ if (additionalSchema) {
1436
+ problems.push(...validateSchemaValue(child, additionalSchema, root, [...path, key], ancestors));
1437
+ }
1438
+ }
1439
+ if (problems.length > 0) return problems;
1440
+ } finally {
1441
+ ancestors.delete(value);
1442
+ }
1443
+ }
1444
+ const runtimeValidator = schema["x-agentic-mermaid-runtime-validator"];
1445
+ if (runtimeValidator === "safeCssColor" && safeCssColor(value) === void 0) {
1446
+ return [{ path, message: "must be a safe, non-fetching CSS color" }];
1447
+ }
1448
+ if (runtimeValidator === "portablePngBackground" && normalizePortablePngBackground(value) === void 0) {
1449
+ return [{ path, message: "must be a portable basic color keyword or 3, 4, 6, or 8 digit hex color" }];
1450
+ }
1451
+ if (runtimeValidator === "safeCssPaint" && safeCssPaint(value) === void 0) {
1452
+ return [{ path, message: "must be a safe, non-fetching CSS paint" }];
1453
+ }
1454
+ if (runtimeValidator === "safeCssFontFamily" && safeCssFontFamily(value) === void 0) {
1455
+ return [{ path, message: "must be a safe, non-fetching CSS font family or stack" }];
1456
+ }
1457
+ if (runtimeValidator === "styleInput") {
1458
+ try {
1459
+ resolveStyleStack(value);
1460
+ } catch (error) {
1461
+ return [{ path, message: `is invalid: ${error instanceof Error ? error.message : String(error)}` }];
1462
+ }
1463
+ }
1464
+ return [];
1465
+ }
1466
+ function formatSchemaPath(path) {
1467
+ if (path.length === 0) return "arguments";
1468
+ return path.reduce((formatted, part) => typeof part === "number" ? `${formatted}[${part}]` : `${formatted}.${part}`, "arguments");
1469
+ }
1470
+ function validateMcpToolArguments(tool, value) {
1471
+ if (!plainJsonObject(value)) return ["arguments must be a plain JSON object"];
1472
+ const admissionProblems = validateJsonConfigAdmission(value);
1473
+ if (admissionProblems.length > 0) {
1474
+ return limitJsonConfigDiagnostics(admissionProblems.map((problem) => `${formatSchemaPath(problem.path)} ${problem.message}`), "arguments");
1475
+ }
1476
+ const problems = validateSchemaValue(value, tool.inputSchema, tool.inputSchema, [], /* @__PURE__ */ new Set()).map((problem) => `${formatSchemaPath(problem.path)} ${problem.message}`);
1477
+ return limitJsonConfigDiagnostics(problems, "arguments");
1478
+ }
1479
+ async function dispatchMcpRequest(req, context, surface) {
1480
+ const raw = req;
1481
+ const hasId = Boolean(raw && Object.prototype.hasOwnProperty.call(raw, "id"));
1482
+ const rawId = raw?.id;
1483
+ const validId = rawId === void 0 || rawId === null || typeof rawId === "string" || typeof rawId === "number" && Number.isFinite(rawId);
1484
+ const valid = Boolean(raw && raw.jsonrpc === "2.0" && typeof raw.method === "string" && validId);
1485
+ const id = validId && rawId !== void 0 ? rawId : null;
1486
+ if (!valid) return rpcError(null, -32600, "invalid JSON-RPC request");
1487
+ const notification = !hasId;
1488
+ let response;
1489
+ switch (req.method) {
1490
+ case "initialize": {
1491
+ const protocolVersion = typeof surface.protocolVersion === "function" ? surface.protocolVersion(req.params) : surface.protocolVersion;
1492
+ response = reply(id, {
1493
+ protocolVersion,
1494
+ serverInfo: { name: surface.serverName ?? MCP_SERVER_NAME, version: MCP_SERVER_VERSION },
1495
+ capabilities: { tools: {} },
1496
+ instructions: surface.instructions
1497
+ });
1498
+ break;
1499
+ }
1500
+ case "notifications/initialized":
1501
+ response = null;
1502
+ break;
1503
+ case "ping":
1504
+ response = reply(id, {});
1505
+ break;
1506
+ case "tools/list":
1507
+ response = reply(id, { tools: surface.tools });
1508
+ break;
1509
+ case "tools/call": {
1510
+ if (!plainJsonObject(req.params)) {
1511
+ response = rpcError(id, -32602, "Invalid params: tools/call requires an object");
1512
+ break;
1513
+ }
1514
+ const name = req.params.name;
1515
+ if (typeof name !== "string") {
1516
+ response = rpcError(id, -32602, "Invalid params: tools/call requires `name` (string)");
1517
+ break;
1518
+ }
1519
+ const tool = surface.tools.find((candidate) => candidate.name === name);
1520
+ if (!tool) {
1521
+ response = rpcError(id, -32602, `Unknown tool: ${name}`);
1522
+ break;
1523
+ }
1524
+ const args = req.params.arguments ?? {};
1525
+ const problems = validateMcpToolArguments(tool, args);
1526
+ if (problems.length > 0) {
1527
+ response = rpcError(id, -32602, `Invalid arguments for ${name}: ${problems.join("; ")}`);
1528
+ break;
1529
+ }
1530
+ response = await surface.handleToolCall(id, { ...req.params, arguments: args }, context);
1531
+ break;
1532
+ }
1533
+ case "prompts/list":
1534
+ response = reply(id, { prompts: [] });
1535
+ break;
1536
+ case "resources/list":
1537
+ response = reply(id, { resources: [] });
1538
+ break;
1539
+ default:
1540
+ response = rpcError(id, -32601, `Method not found: ${req.method}`);
1541
+ }
1542
+ return notification ? null : response;
1543
+ }
1544
+ function createExecuteTool(options) {
1545
+ const hostedNote = options.hosted ? `Hosted note: execute runs in an on-demand isolate and costs more than the direct
1546
+ render_svg/render_ascii/render_png/verify/describe tools \u2014 prefer those for plain
1547
+ render/verify calls. For straightforward structured edits, prefer the declarative
1548
+ mutate/build tools; reserve execute for logic the ops don't express.
1549
+ Hosted mermaid.renderMermaidSVG*, renderMermaidASCII*, and
1550
+ layoutMermaidWithReceipt calls force security:'strict' and
1551
+ embedFontImport:false; caller code cannot weaken that host policy.
1552
+
1553
+ ` : "";
1554
+ const timeoutDescription = options.hosted ? "Optional CPU-time budget (default 5000ms, max 30000ms)." : "Optional hard timeout (default 5000ms).";
1555
+ const runtime = options.hosted ? "an isolated sandbox" : "a sandboxed node:vm context";
1556
+ return {
1557
+ name: "execute",
1558
+ description: `Run JavaScript in ${runtime}; return a value.
1559
+ One call composes edits. Submit JavaScript; declaration types are guidance.
1560
+ No promises, async/await, dynamic import, or type annotations.
1561
+ ${hostedNote}SDK declaration:
1562
+ ${options.sdkDeclaration}`,
1563
+ inputSchema: {
1564
+ type: "object",
1565
+ additionalProperties: false,
1566
+ properties: {
1567
+ code: { type: "string", description: "JavaScript to execute; mermaid.* SDK is global." },
1568
+ timeoutMs: { type: "integer", minimum: 1, description: timeoutDescription }
1569
+ },
1570
+ required: ["code"]
1571
+ },
1572
+ annotations: SANDBOX_EXECUTE_ANNOTATIONS
1573
+ };
1574
+ }
1575
+ function createRenderPngTool(mode) {
1576
+ const hosted = mode === "hosted";
1577
+ const pngSchema = pngOutputOptionsJsonSchema(hosted ? "portable" : "native");
1578
+ const pngProperties = pngSchema.properties;
1579
+ return {
1580
+ name: "render_png",
1581
+ description: hosted ? `Rasterize a Mermaid source string to PNG. Returns { ok, png_base64 }.
1582
+ Hosted rendering uses resvg-wasm with bundled fonts; bytes may differ from the
1583
+ local napi renderer, so hosted PNG is a convenience surface, not part of the
1584
+ byte-determinism contract. For file/URL artifacts use the local stdio server.` : `Rasterize a Mermaid source string to PNG. By default returns base64-encoded PNG bytes.
1585
+ Set output to "file" or "url" to write a managed artifact instead; artifact responses include
1586
+ {path?, url?, mimeType, bytes, sha256}. File/URL artifacts are generated under the MCP server's
1587
+ artifact directory with safe names, size limits, and TTL cleanup.
1588
+ Uses bundled resvg + Inter (DejaVu Sans fallback) for same-machine cross-runtime determinism where verified.
1589
+ Agentic Mermaid outputs SVG, PNG, ASCII, Unicode, and JSON layout. For non-PNG output, use execute() with mermaid.renderMermaidSVG, mermaid.renderMermaidASCII (useAscii true for ASCII, false for Unicode), or verifyMermaid(...).layout \u2014 those are streaming text/data and don't need a dedicated tool.`,
1590
+ inputSchema: {
1591
+ type: "object",
1592
+ additionalProperties: false,
1593
+ properties: {
1594
+ source: { type: "string", description: "Mermaid source." },
1595
+ ...pngProperties,
1596
+ ...mcpRenderOptionSchemaProperties("Shared advanced RenderOptions object."),
1597
+ ...hosted ? {} : {
1598
+ output: { type: "string", enum: ["base64", "file", "url"], description: "PNG return mode (default base64)." }
1599
+ }
1600
+ },
1601
+ required: ["source"]
1602
+ },
1603
+ annotations: hosted ? PURE_COMPUTE_ANNOTATIONS : MANAGED_ARTIFACT_ANNOTATIONS
1604
+ };
1605
+ }
1606
+ function createDescribeTool() {
1607
+ return {
1608
+ name: "describe",
1609
+ description: `Describe a Mermaid diagram. format=text returns { ok, text } with
1610
+ one or two summary sentences; format=json returns { ok, tree } with the AX tree;
1611
+ format=facts returns { ok, facts } with deterministic semantic fact lines for
1612
+ machine checking (for example edge A -> B : label, member Duck +quack()).`,
1613
+ inputSchema: {
1614
+ type: "object",
1615
+ additionalProperties: false,
1616
+ properties: {
1617
+ source: { type: "string", description: "Mermaid source." },
1618
+ format: { type: "string", enum: ["text", "json", "facts"], description: "text (default), json AX tree, or facts semantic read-back." }
1619
+ },
1620
+ required: ["source"]
1621
+ },
1622
+ annotations: PURE_COMPUTE_ANNOTATIONS
1623
+ };
1624
+ }
1625
+
1626
+ // src/mcp/sdk-decl.ts
1627
+ function sdkFamilyTypeStem(family) {
1628
+ return family.narrower.slice(2);
1629
+ }
1630
+ function sdkFamilyBodyType(family) {
1631
+ return family.id === "flowchart" ? `{ kind: 'flowchart'; graph: FlowchartGraph }` : `${sdkFamilyTypeStem(family)}Body`;
1632
+ }
1633
+ var SDK_DIAGRAM_KIND_DECLARATION = `type DiagramKind = ${BUILTIN_FAMILY_METADATA.map((family) => `'${family.id}'`).join(" | ")}`;
1634
+ var SDK_DIAGRAM_BODY_MEMBERS = BUILTIN_FAMILY_METADATA.map((family) => ` | ${sdkFamilyBodyType(family)}`).join("\n");
1635
+ var SDK_VALID_DIAGRAM_ALIASES = BUILTIN_FAMILY_METADATA.map((family) => `type ${sdkFamilyTypeStem(family)}ValidDiagram = ValidDiagram & { body: ${sdkFamilyBodyType(family)} }`).join("\n");
1636
+ var SDK_NARROWER_METHOD_DECLARATIONS = BUILTIN_FAMILY_METADATA.map((family) => ` ${family.narrower}(d: ValidDiagram): ${sdkFamilyTypeStem(family)}ValidDiagram | null`).join("\n");
1637
+ var SDK_MUTATE_METHOD_DECLARATIONS = BUILTIN_FAMILY_METADATA.map((family) => {
1638
+ const stem = sdkFamilyTypeStem(family);
1639
+ return ` mutate(d: ${stem}ValidDiagram, op: ${stem}MutationOp): Result<${stem}ValidDiagram, { code: string; message: string }>`;
1640
+ }).join("\n");
1641
+ var SDK_ANY_MUTATION_OP_DECLARATION = `type AnyMutationOp = ${BUILTIN_FAMILY_METADATA.map((family) => `${sdkFamilyTypeStem(family)}MutationOp`).join(" | ")}`;
1642
+ var SDK_FAMILY_CONVENTION = `// 3. mutate works on ${BUILTIN_FAMILY_METADATA.map((family) => family.id).join(", ")}. Narrow via
1643
+ // ${BUILTIN_FAMILY_METADATA.map((family) => family.narrower).join("/")}.`;
1644
+ function codeModeRenderMethodDeclarations() {
1645
+ const methods = /* @__PURE__ */ new Map();
1646
+ for (const descriptor of RENDER_OUTPUT_DESCRIPTORS) {
1647
+ const transport = descriptor.transports.codeMode;
1648
+ if (transport.availability !== "direct" && transport.availability !== "projected") continue;
1649
+ const output = `${descriptor.id}: ${transport.selector ?? transport.availability}`;
1650
+ const existing = methods.get(transport.method);
1651
+ if (existing) {
1652
+ if (existing.optionsType !== transport.optionsType || existing.returnType !== transport.returnType) {
1653
+ throw new Error(`Code Mode render contract for ${transport.method} has incompatible signatures`);
1654
+ }
1655
+ existing.outputs.push(output);
1656
+ } else {
1657
+ methods.set(transport.method, {
1658
+ optionsType: transport.optionsType,
1659
+ returnType: transport.returnType,
1660
+ outputs: [output]
1661
+ });
1662
+ }
1663
+ }
1664
+ return [...methods].map(
1665
+ ([method, declaration]) => ` // ${declaration.outputs.join("; ")}
1666
+ ${method}(input: ParsedDiagram | string, opts?: ${declaration.optionsType}): ${declaration.returnType}`
1667
+ ).join("\n");
1668
+ }
1669
+ var CODE_MODE_SHARED_RENDER_OPTIONS_DECLARATION = sharedRenderOptionsTypeScriptDeclaration();
1670
+ var CODE_MODE_OUTPUT_RENDER_OPTION_DECLARATIONS = `interface ConfigDiagnostic { code: 'INEFFECTIVE_CONFIG'; field: string; message: string }
1671
+ interface TerminalProjectionDiagnostic { code: string; feature: string; message: string }
1672
+
1673
+ interface SvgRenderOptions extends SharedRenderOptions {
1674
+ onConfigDiagnostic?: (diagnostic: ConfigDiagnostic) => void
1675
+ }
1676
+
1677
+ interface AsciiRenderOptions extends SharedRenderOptions {
1678
+ useAscii?: boolean
1679
+ paddingX?: number
1680
+ paddingY?: number
1681
+ boxBorderPadding?: number
1682
+ colorMode?: 'auto' | 'none' | 'ansi16' | 'ansi256' | 'truecolor' | 'html'
1683
+ theme?: { fg?: string; border?: string; line?: string; arrow?: string; accent?: string; bg?: string; corner?: string; junction?: string }
1684
+ maxWidth?: number
1685
+ targetWidth?: number
1686
+ onConfigDiagnostic?: (diagnostic: ConfigDiagnostic) => void
1687
+ onProjectionDiagnostic?: (diagnostic: TerminalProjectionDiagnostic) => void
1688
+ }
1689
+
1690
+ interface LayoutRenderOptions extends SharedRenderOptions {
1691
+ debug?: boolean
1692
+ regions?: boolean
1693
+ actions?: boolean
1694
+ onConfigDiagnostic?: (diagnostic: ConfigDiagnostic) => void
1695
+ }`;
1696
+ var CODE_MODE_RENDER_RECEIPT_DECLARATIONS = `interface RenderArtifactDiagnostic { code: string; message?: string; reference?: string; feature?: string; input?: string; canonicalId?: string; removal?: { release: string; date: string } }
1697
+ interface CapabilityResolution { readonly id: \`\${string}:\${string}\`; readonly range: string; readonly level: 'required' | 'preferred' | 'optional'; readonly status: 'selected' | 'unsupported' | 'incompatible'; readonly version?: string }
1698
+ interface CapabilityDecision { readonly version: 1; readonly accepted: boolean; readonly resolutions: readonly CapabilityResolution[] }
1699
+ interface RenderExecutionDecision {
1700
+ readonly family: { readonly id: string; readonly version: string }
1701
+ readonly backend: { readonly mode: 'scene'; readonly requestedId: string; readonly selectedId: string; readonly version: string; readonly hostPolicy: boolean } | { readonly mode: 'family-svg' }
1702
+ readonly digest: string
1703
+ }
1704
+ interface RenderRequestReceipt { version: ${RENDER_CONTRACT_VERSION}; output: 'svg' | 'png' | 'ascii' | 'unicode' | 'html' | 'layout'; sharedRequestDigest: string; requestDigest: string; appearanceDigest: string; capabilityDecision: CapabilityDecision; diagnostics?: readonly RenderArtifactDiagnostic[]; graphicalProjectionDigest?: string; executionDecision?: RenderExecutionDecision }`;
1705
+ function compactInterfaceDeclarations(declaration) {
1706
+ let compact = "";
1707
+ for (const sourceLine of declaration.split("\n")) {
1708
+ const line = sourceLine.trim();
1709
+ if (!line) continue;
1710
+ if (line.startsWith("interface ") && line.endsWith("}")) {
1711
+ compact += `${line}
1712
+ `;
1713
+ } else if (line.endsWith("{")) {
1714
+ compact += `${line} `;
1715
+ } else if (line === "}") {
1716
+ compact += `}
1717
+ `;
1718
+ } else {
1719
+ compact += `${line.replaceAll("?: ", "?:")};`;
1720
+ }
1721
+ }
1722
+ return compact.trimEnd();
1723
+ }
1724
+ var CODE_MODE_CORE_SHARED_RENDER_OPTIONS_DECLARATION = compactInterfaceDeclarations(
1725
+ CODE_MODE_SHARED_RENDER_OPTIONS_DECLARATION
1726
+ );
1727
+ var CODE_MODE_CORE_OUTPUT_RENDER_OPTION_DECLARATIONS = compactInterfaceDeclarations(
1728
+ CODE_MODE_OUTPUT_RENDER_OPTION_DECLARATIONS
1729
+ );
1730
+ var CODE_MODE_CORE_RENDER_RECEIPT_DECLARATIONS = compactInterfaceDeclarations(
1731
+ CODE_MODE_RENDER_RECEIPT_DECLARATIONS
1732
+ );
1733
+ var CODE_MODE_RENDER_OPTION_DECLARATIONS = `${styleSpecTypeScriptDeclaration()}
1734
+
1735
+ ${architectureVisualOverridesTypeScriptDeclaration()}
1736
+
1737
+ ${CODE_MODE_SHARED_RENDER_OPTIONS_DECLARATION}
1738
+
1739
+ ${CODE_MODE_OUTPUT_RENDER_OPTION_DECLARATIONS}
1740
+
1741
+ ${CODE_MODE_RENDER_RECEIPT_DECLARATIONS}
1742
+
1743
+ interface TerminalConnectorProjection {
1744
+ id: string
1745
+ role: string
1746
+ realization: 'native' | 'emulated' | 'projected' | 'lossy' | 'unsupported'
1747
+ topology: 'line' | 'polyline' | 'path'
1748
+ direction: 'forward' | 'reverse' | 'bidirectional' | 'undirected' | 'self'
1749
+ relationship: string
1750
+ markers: { start?: { id: string; shape: string }; mid: readonly { id: string; shape: string }[]; end?: { id: string; shape: string } }
1751
+ labels: readonly { id?: string; text: string }[]
1752
+ lineStyle: 'solid' | 'dotted' | 'dashed' | 'thick' | 'invisible'
1753
+ strokeLosses: readonly string[]
1754
+ diagnostics: readonly string[]
1755
+ }
1756
+ interface ResolvedTerminalStyle {
1757
+ version: 1
1758
+ colorMode: 'none' | 'ansi16' | 'ansi256' | 'truecolor' | 'html'
1759
+ theme: Readonly<{ fg: string; border: string; line: string; arrow: string; accent?: string; bg?: string; corner?: string; junction?: string }>
1760
+ diagnostics: readonly TerminalProjectionDiagnostic[]
1761
+ connectorProjection: { evidence: 'scene' | 'unavailable' | 'not-evaluated'; count: number; topologies: Readonly<Record<'line' | 'polyline' | 'path', number>>; realizations: Readonly<Record<string, number>>; relationships: readonly string[]; directions: readonly string[]; markerPositions: Readonly<{ start: number; mid: number; end: number }>; labelCount: number; connectors: readonly TerminalConnectorProjection[]; digest: string }
1762
+ digest: string
1763
+ }
1764
+ interface ResolvedTerminalOutputPolicy {
1765
+ version: 1
1766
+ useAscii: boolean
1767
+ paddingX: number
1768
+ paddingY: number
1769
+ boxBorderPadding: number
1770
+ colorMode: 'none' | 'ansi16' | 'ansi256' | 'truecolor' | 'html'
1771
+ theme: Readonly<{ fg?: string; border?: string; line?: string; arrow?: string; accent?: string; bg?: string; corner?: string; junction?: string }>
1772
+ maxWidth?: number
1773
+ targetWidth?: number
1774
+ }
1775
+ interface RenderedSvg { svg: string; receipt: RenderRequestReceipt }
1776
+ interface RenderedAscii { text: string; receipt: RenderRequestReceipt; terminalStyle: ResolvedTerminalStyle; outputPolicy: ResolvedTerminalOutputPolicy }
1777
+ interface RenderedLayoutArtifact { layout: VerifyResult['layout']; receipt: RenderRequestReceipt }`;
1778
+ var CODE_MODE_CORE_STYLE_SPEC_DECLARATION = styleSpecTypeScriptDeclaration({ compact: true }).replaceAll(" | ", "|").replaceAll(", ", ",");
1779
+ var CODE_MODE_CORE_RENDER_OPTION_DECLARATIONS = `${CODE_MODE_CORE_STYLE_SPEC_DECLARATION}
1780
+ type ArchitectureVisualOverrides = Readonly<Record<string, unknown>>
1781
+
1782
+ ${CODE_MODE_CORE_SHARED_RENDER_OPTIONS_DECLARATION}
1783
+
1784
+ ${CODE_MODE_CORE_OUTPUT_RENDER_OPTION_DECLARATIONS}
1785
+
1786
+ ${CODE_MODE_CORE_RENDER_RECEIPT_DECLARATIONS}
1787
+
1788
+ interface RenderedSvg { svg: string; receipt: RenderRequestReceipt }
1789
+ interface RenderedAscii { text: string; receipt: RenderRequestReceipt; terminalStyle: Record<string, unknown>; outputPolicy: Record<string, unknown> }
1790
+ interface RenderedLayoutArtifact { layout: VerifyResult['layout']; receipt: RenderRequestReceipt }`;
1791
+ var CODE_MODE_RENDER_METHOD_DECLARATIONS = codeModeRenderMethodDeclarations();
1792
+ var SDK_DECLARATION = `// Mermaid agent SDK available as the global \`mermaid\`. All calls are
1793
+ // synchronous and pure. Compose multi-step edits in one execute() call.
1794
+ // Code Mode is synchronous: async/await, Promise jobs, and dynamic import are not supported.
1795
+
1796
+ type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
1797
+ type CheckMermaidSpec = string[] | {
1798
+ include?: string[]; expected?: string[]; required?: string[]; require?: string[]
1799
+ exclude?: string[]; absent?: string[]; forbidden?: string[]; forbid?: string[]; unexpected?: string[]
1800
+ exact?: boolean
1801
+ }
1802
+ interface CheckMermaidResult { ok: boolean; missing: string[]; unexpected: string[]; facts: string[] }
1803
+
1804
+ type MermaidConfigScalar = string | number | boolean | null
1805
+ type MermaidConfigValue = MermaidConfigScalar | MermaidConfigValue[] | { [key: string]: MermaidConfigValue | undefined }
1806
+ type MermaidRuntimeConfig = {
1807
+ [key: string]: MermaidConfigValue | undefined
1808
+ theme?: string
1809
+ fontFamily?: string
1810
+ themeVariables?: { [key: string]: MermaidConfigValue | undefined; fontFamily?: string }
1811
+ timeline?: { [key: string]: MermaidConfigValue | undefined; disableMulticolor?: boolean; sectionFills?: string[]; sectionColours?: string[] }
1812
+ journey?: { [key: string]: MermaidConfigValue | undefined; diagramMarginX?: number; diagramMarginY?: number; leftMargin?: number; maxLabelWidth?: number; taskMargin?: number; actorColours?: string[]; sectionFills?: string[]; sectionColours?: string[]; useMaxWidth?: boolean }
1813
+ flowchart?: { [key: string]: MermaidConfigValue | undefined; nodeSpacing?: number; rankSpacing?: number; wrappingWidth?: number }
1814
+ // State geometry consumes the faithful ELK/measured-text equivalents;
1815
+ // legacy Dagre calibration keys remain typed and emit INEFFECTIVE_CONFIG.
1816
+ state?: { [key: string]: MermaidConfigValue | undefined; titleTopMargin?: number; arrowMarkerAbsolute?: boolean; dividerMargin?: number; sizeUnit?: number; padding?: number; textHeight?: number; titleShift?: number; noteMargin?: number; nodeSpacing?: number; rankSpacing?: number; forkWidth?: number; forkHeight?: number; miniPadding?: number; fontSizeFactor?: number; fontSize?: number; labelHeight?: number; edgeLengthFactor?: string; compositTitleSize?: number; radius?: number; defaultRenderer?: 'dagre-d3' | 'dagre-wrapper' | 'elk' }
1817
+ class?: { [key: string]: MermaidConfigValue | undefined; nodeSpacing?: number; rankSpacing?: number }
1818
+ er?: { [key: string]: MermaidConfigValue | undefined; layoutDirection?: string; nodeSpacing?: number; rankSpacing?: number }
1819
+ architecture?: { [key: string]: MermaidConfigValue | undefined; padding?: number; iconSize?: number; fontSize?: number; nodeSeparation?: number; idealEdgeLengthMultiplier?: number }
1820
+ xyChart?: { [key: string]: MermaidConfigValue | undefined }
1821
+ pie?: { [key: string]: MermaidConfigValue | undefined; textPosition?: number; donutHole?: number; legendPosition?: 'top' | 'bottom' | 'left' | 'right' | 'center' }
1822
+ quadrantChart?: { [key: string]: MermaidConfigValue | undefined; chartWidth?: number; chartHeight?: number; pointRadius?: number; useMaxWidth?: boolean }
1823
+ gantt?: { [key: string]: MermaidConfigValue | undefined; displayMode?: string }
1824
+ mindmap?: { [key: string]: MermaidConfigValue | undefined; padding?: number; maxNodeWidth?: number }
1825
+ gitGraph?: { [key: string]: MermaidConfigValue | undefined; showBranches?: boolean; showCommitLabel?: boolean; mainBranchName?: string; mainBranchOrder?: number; parallelCommits?: boolean; rotateCommitLabel?: boolean }
1826
+ radar?: { [key: string]: MermaidConfigValue | undefined; width?: number; height?: number; marginTop?: number; marginRight?: number; marginBottom?: number; marginLeft?: number; axisScaleFactor?: number; axisLabelFactor?: number; curveTension?: number; useMaxWidth?: boolean; tickLabels?: boolean }
1827
+ // Wired sequence keys (unlisted documented keys are accepted and named by
1828
+ // verify's INEFFECTIVE_CONFIG lint \u2014 see src/sequence/config.ts).
1829
+ sequence?: { [key: string]: MermaidConfigValue | undefined; actorMargin?: number; width?: number; height?: number; diagramMarginX?: number; diagramMarginY?: number; messageMargin?: number; noteMargin?: number; activationWidth?: number; showSequenceNumbers?: boolean }
1830
+ useMaxWidth?: boolean
1831
+ useWidth?: number
1832
+ /** Recognized for upstream accounting but public renderers reject raw CSS; use StyleSpec. */
1833
+ themeCSS?: string
1834
+ }
1835
+
1836
+ ${CODE_MODE_RENDER_OPTION_DECLARATIONS}
1837
+
1838
+ ${SDK_DIAGRAM_KIND_DECLARATION}
1839
+ type ExternalFamilyId = \`family:\${string}\`
1840
+
1841
+ interface ExtensionCompatibility {
1842
+ readonly [contract: string]: string | undefined
1843
+ readonly core?: string
1844
+ readonly scene?: string
1845
+ }
1846
+
1847
+ interface ExtensionProvenance {
1848
+ readonly owner: string
1849
+ readonly source: string
1850
+ readonly reference?: string
1851
+ }
1852
+
1853
+ interface ExtensionIdentity<Kind extends string = string> {
1854
+ readonly id: \`\${Kind}:\${string}\`
1855
+ readonly kind: Kind
1856
+ readonly version: string
1857
+ readonly compatibility: ExtensionCompatibility
1858
+ readonly provenance: ExtensionProvenance
1859
+ }
1860
+
1861
+ interface SourceSpanPoint {
1862
+ /** UTF-16 offset in the exact authored source; line and col are one-based. */
1863
+ readonly offset: number
1864
+ readonly line: number
1865
+ readonly col: number
1866
+ }
1867
+
1868
+ interface SourceSpan {
1869
+ readonly start: SourceSpanPoint
1870
+ readonly end: SourceSpanPoint
1871
+ }
1872
+
1873
+ interface PreservedSourceSpans {
1874
+ readonly source: SourceSpan
1875
+ readonly wrapper?: SourceSpan
1876
+ readonly frontmatter?: SourceSpan
1877
+ readonly initDirectives?: readonly SourceSpan[]
1878
+ readonly accessibilityDirectives?: readonly SourceSpan[]
1879
+ readonly header: SourceSpan
1880
+ readonly body: SourceSpan
1881
+ }
1882
+
1883
+ interface SourceLocation { readonly line: number; readonly col: number }
1884
+ interface SourceMapSpans {
1885
+ readonly preserved: PreservedSourceSpans
1886
+ readonly nodes: ReadonlyMap<string, SourceSpan>
1887
+ readonly edges: ReadonlyMap<string, SourceSpan>
1888
+ readonly groups: ReadonlyMap<string, SourceSpan>
1889
+ readonly labels: ReadonlyMap<string, SourceSpan>
1890
+ }
1891
+ interface SourceMap {
1892
+ readonly nodes: ReadonlyMap<string, SourceLocation>
1893
+ readonly edges: ReadonlyMap<string, SourceLocation>
1894
+ readonly groups: ReadonlyMap<string, SourceLocation>
1895
+ readonly labels: ReadonlyMap<string, SourceLocation>
1896
+ readonly spans?: SourceMapSpans
1897
+ }
1898
+
1899
+ interface SourcePreservationReceipt {
1900
+ readonly version: 1
1901
+ readonly classification: 'unsupported' | 'inventory-only' | 'unknown'
1902
+ /** Exact authored bytes supplied to the parser. */
1903
+ readonly source: string
1904
+ readonly header: string
1905
+ readonly upstreamFamilyId?: string
1906
+ readonly mermaidVersion: string
1907
+ readonly spans?: PreservedSourceSpans
1908
+ }
1909
+
1910
+ interface ParseError {
1911
+ readonly code: string
1912
+ readonly message: string
1913
+ readonly line?: number
1914
+ readonly col?: number
1915
+ readonly preservation?: SourcePreservationReceipt
1916
+ readonly help?: string
1917
+ }
1918
+
1919
+ interface ValidDiagram {
1920
+ readonly kind: DiagramKind
1921
+ readonly source: SourceMap
1922
+ readonly meta: {
1923
+ frontmatter?: Record<string, unknown>
1924
+ initDirectives: { raw: string; parsed: Record<string, unknown> }[]
1925
+ comments: { text: string; line: number }[]
1926
+ wrapperSource?: string
1927
+ droppedComments?: { text: string; line: number }[]
1928
+ accessibility: { title?: string; descr?: string }
1929
+ }
1930
+ readonly body:
1931
+ ${SDK_DIAGRAM_BODY_MEMBERS}
1932
+ | { kind: 'opaque'; family: DiagramKind; source: string }
1933
+ readonly canonicalSource: string // normalized renderer input; opaque fidelity uses body.source
1934
+ }
1935
+
1936
+ interface ExtensionDiagramBody {
1937
+ readonly kind: 'extension'
1938
+ readonly family: ExternalFamilyId
1939
+ readonly source: string
1940
+ readonly data?: unknown
1941
+ }
1942
+
1943
+ interface ExtensionValidDiagram {
1944
+ readonly kind: ExternalFamilyId
1945
+ readonly descriptorIdentity: ExtensionIdentity<'family'>
1946
+ readonly meta: ValidDiagram['meta']
1947
+ readonly body: ExtensionDiagramBody
1948
+ readonly source: SourceMap
1949
+ readonly canonicalSource: string
1950
+ }
1951
+
1952
+ interface PreservedValidDiagram {
1953
+ readonly kind: ExternalFamilyId
1954
+ readonly meta: ValidDiagram['meta']
1955
+ readonly body: {
1956
+ readonly kind: 'preserved'
1957
+ readonly representation: 'opaque' | 'unknown'
1958
+ readonly source: string
1959
+ readonly preservation: SourcePreservationReceipt
1960
+ readonly spans: PreservedSourceSpans
1961
+ readonly diagnostic: {
1962
+ readonly code: 'UNSUPPORTED_FAMILY' | 'UNKNOWN_HEADER' | 'FAMILY_DESCRIPTOR_MISMATCH'
1963
+ readonly message: string
1964
+ readonly help: string
1965
+ }
1966
+ }
1967
+ readonly source: SourceMap
1968
+ readonly canonicalSource: string
1969
+ }
1970
+
1971
+ type ParsedDiagram = ValidDiagram | ExtensionValidDiagram | PreservedValidDiagram
1972
+
1973
+ ${SDK_VALID_DIAGRAM_ALIASES}
1974
+
1975
+ interface FlowchartGraph {
1976
+ direction: 'TD' | 'TB' | 'LR' | 'BT' | 'RL'
1977
+ // semanticShape/authoredShape carry Mermaid v11 @{ shape } metadata: shape
1978
+ // stays the drawn geometry, semanticShape the canonical v11 id, and
1979
+ // authoredShape the exact spelling that serializes back.
1980
+ nodes: Map<string, { id: string; label: string; shape: string; semanticShape?: string; authoredShape?: string; markdownLabel?: true; icon?: string; image?: string; iconForm?: 'square' | 'circle' | 'rounded'; href?: string }>
1981
+ edges: {
1982
+ // id = authored v11.6 edge ID ('e1@-->'): round-trips verbatim and is a
1983
+ // valid remove_edge/set_label target selector.
1984
+ id?: string
1985
+ source: string; target: string; label?: string; style: string
1986
+ hasArrowStart?: boolean; hasArrowEnd?: boolean; startMarker?: string; endMarker?: string
1987
+ curve?: string; animate?: boolean; animation?: 'fast' | 'slow'; length?: number
1988
+ }[]
1989
+ subgraphs: { id: string; label: string; nodeIds: string[]; children: FlowchartGraph['subgraphs']; direction?: FlowchartGraph['direction']; concurrencyRegion?: true }[]
1990
+ classDefs: Map<string, Record<string, string>>
1991
+ classAssignments: Map<string, string>
1992
+ nodeStyles: Map<string, Record<string, string>>
1993
+ linkStyles: Map<number | 'default', Record<string, string>>
1994
+ }
1995
+
1996
+ interface StateNode { id: string; label?: string; declaredBare?: true; stereotype?: 'fork' | 'join' | 'choice' | 'history' | 'deep-history'; states?: StateNode[]; transitions?: StateTransition[]; regions?: StateRegion[]; className?: string; style?: Record<string, string>; direction?: 'TD' | 'TB' | 'LR' | 'BT' | 'RL' }
1997
+ interface StateRegion { states: StateNode[]; transitions: StateTransition[]; direction?: 'TD' | 'TB' | 'LR' | 'BT' | 'RL' }
1998
+ interface StateTransition { from: string; to: string; label?: string; style?: Record<string, string> } // from/to may be '[*]' or a history ref ('[H]', 'X[H*]')
1999
+ interface StateNote { target: string; side: 'left' | 'right'; text: string }
2000
+ interface StateBody { kind: 'state'; states: StateNode[]; transitions: StateTransition[]; notes?: StateNote[]; direction?: 'TD' | 'TB' | 'LR' | 'BT' | 'RL'; classDefs?: Record<string, Record<string, string>>; defaultTransitionStyle?: Record<string, string> }
2001
+
2002
+ type SeqParticipantKind = 'participant' | 'actor' | 'boundary' | 'control' | 'entity' | 'database' | 'collections' | 'queue'
2003
+ interface SeqParticipant { id: string; label: string; kind: SeqParticipantKind; declaration?: 'participant' | 'actor'; links?: Record<string, string> }
2004
+ interface SeqMessage { from: string; to: string; text: string; style: string; arrow?: string; centralStart?: boolean; centralEnd?: boolean; activate?: boolean; deactivate?: boolean }
2005
+ type SeqFragmentKind = 'alt' | 'opt' | 'loop' | 'par'
2006
+ interface SeqFragmentBranch { label?: string; messages: SeqMessage[] }
2007
+ interface SeqFragment { fragmentKind: SeqFragmentKind; label?: string; branches: SeqFragmentBranch[]; rawLines?: string[] }
2008
+ // BUILD-18: ordered statement list. participant/message refs index into the
2009
+ // participants/messages arrays; direct-message common fragments are typed;
2010
+ // opaque-block carries all remaining unmodeled lines verbatim.
2011
+ type SequenceStatement =
2012
+ | { kind: 'participant'; ref: number }
2013
+ | { kind: 'message'; ref: number }
2014
+ | { kind: 'actor-links'; actorId: string; links: Record<string, string> }
2015
+ | { kind: 'fragment'; fragment: SeqFragment }
2016
+ | { kind: 'opaque-block'; lines: string[] }
2017
+ interface SequenceBody { kind: 'sequence'; participants: SeqParticipant[]; messages: SeqMessage[]; statements: SequenceStatement[] }
2018
+
2019
+ interface TimelineEvent { id: string; text: string }
2020
+ interface TimelinePeriod { id: string; label: string; events: TimelineEvent[] }
2021
+ interface TimelineSection { id: string; label?: string; periods: TimelinePeriod[] }
2022
+ // direction: explicit \`timeline TD\`/\`timeline LR\` header token (TD = vertical, upstream PR #7270); undefined = LR default.
2023
+ interface TimelineBody { kind: 'timeline'; direction?: 'LR' | 'TD'; title?: string; accessibilityTitle?: string; accessibilityDescription?: string; sections: TimelineSection[] }
2024
+
2025
+ interface ClassNode { id: string; generic?: string; label?: string; members: string[]; namespace?: string; className?: string; style?: Record<string, string>; href?: string }
2026
+ type ClassRelationKind = 'inheritance' | 'composition' | 'aggregation' | 'association' | 'dependency' | 'realization' | 'link-solid' | 'link-dashed' | 'lollipop'
2027
+ interface ClassRelation { from: string; to: string; kind: ClassRelationKind; label?: string; fromCardinality?: string; toCardinality?: string; markerAt?: 'from' | 'to' | 'both'; fromKind?: ClassRelationKind; toKind?: ClassRelationKind }
2028
+ interface ClassNote { text: string; for?: string }
2029
+ // namespace paths are dot-joined (e.g. 'Platform.Auth'); namespaces render as
2030
+ // compound boxes and serialize to "namespace path { ... }" blocks.
2031
+ interface ClassNamespaceDecl { name: string; label?: string }
2032
+ interface ClassBody { kind: 'class'; title?: string; classes: ClassNode[]; relations: ClassRelation[]; notes: ClassNote[]; namespaces?: ClassNamespaceDecl[]; classDefs?: Record<string, Record<string, string>> }
2033
+
2034
+ type ErCardinality = 'one-only' | 'zero-or-one' | 'zero-or-many' | 'one-or-many'
2035
+ interface ErAttribute { text: string }
2036
+ interface ErEntity { id: string; label?: string; attributes: ErAttribute[]; className?: string; style?: Record<string, string>; groupId?: string }
2037
+ interface ErGroup { id: string; label: string; parentId?: string; direction?: 'TD' | 'TB' | 'LR' | 'BT' | 'RL' }
2038
+ interface ErRelation { from: string; to: string; leftCard: ErCardinality; rightCard: ErCardinality; dashed: boolean; label?: string }
2039
+ type ErStatement = { kind: 'entity'; id: string } | { kind: 'relation'; ref: number } | { kind: 'direction'; groupId?: string } | { kind: 'group-open'; id: string } | { kind: 'group-close'; id: string } | { kind: 'opaque'; lines: string[] }
2040
+ interface ErBody { kind: 'er'; entities: ErEntity[]; relations: ErRelation[]; groups?: ErGroup[]; direction?: 'TD' | 'TB' | 'LR' | 'BT' | 'RL'; classDefs?: Record<string, Record<string, string>>; statements?: ErStatement[] }
2041
+
2042
+ interface JourneyTask { id: string; text: string; score: number; actors: string[] }
2043
+ interface JourneySection { id: string; label?: string; tasks: JourneyTask[] }
2044
+ interface JourneyBody { kind: 'journey'; title?: string; accessibilityTitle?: string; accessibilityDescription?: string; sections: JourneySection[] }
2045
+
2046
+ type ArchitectureSide = 'L' | 'R' | 'T' | 'B'
2047
+ type ArchitectureEndpointBoundary = 'item' | 'group'
2048
+ interface ArchitectureGroup { id: string; label: string; icon?: string; parentId?: string }
2049
+ interface ArchitectureService { id: string; label: string; icon?: string; parentId?: string }
2050
+ interface ArchitectureJunction { id: string; parentId?: string }
2051
+ interface ArchitectureEndpoint { id: string; side: ArchitectureSide; boundary?: ArchitectureEndpointBoundary }
2052
+ interface ArchitectureEdge { source: ArchitectureEndpoint; target: ArchitectureEndpoint; label?: string; hasArrowStart: boolean; hasArrowEnd: boolean }
2053
+ // alignments: upstream v11.16.0 "align row|column" directives, preserved
2054
+ // losslessly and honored as deterministic center-coordinate constraints.
2055
+ interface ArchitectureAlignment { axis: 'row' | 'column'; members: string[] }
2056
+ interface ArchitectureBody { kind: 'architecture'; title?: string; accessibilityTitle?: string; accessibilityDescription?: string; groups: ArchitectureGroup[]; services: ArchitectureService[]; junctions: ArchitectureJunction[]; edges: ArchitectureEdge[]; alignments?: ArchitectureAlignment[] }
2057
+
2058
+ interface XyChartAxis { name?: string; categories?: string[]; range?: { min: number; max: number } }
2059
+ interface XyChartSeries { id: string; kind: 'bar' | 'line'; name?: string; values: number[]; pointLabels?: Array<string | undefined> }
2060
+ interface XyChartBody { kind: 'xychart'; accessibilityTitle?: string; accessibilityDescription?: string; title?: string; horizontal?: boolean; xAxis?: XyChartAxis; yAxis?: XyChartAxis; series: XyChartSeries[] }
2061
+
2062
+ interface PieSlice { id: string; label: string; value: number } // value > 0
2063
+ interface PieBody { kind: 'pie'; accessibilityTitle?: string; accessibilityDescription?: string; title?: string; showData: boolean; slices: PieSlice[] }
2064
+
2065
+ interface QuadrantAxis { near: string; far?: string }
2066
+ // Upstream per-point styling (direct \`radius:/color:/stroke-color:/stroke-width:\`
2067
+ // tails, \`classDef\` tables, \`:::class\` assignments) is structured content:
2068
+ // preserved by every op and serialized canonically. strokeWidth may carry px.
2069
+ interface QuadrantPointStyle { radius?: number; color?: string; strokeColor?: string; strokeWidth?: string; extra?: string[] }
2070
+ interface QuadrantPoint { label: string; x: number; y: number; className?: string; style?: QuadrantPointStyle } // x,y in [0,1]
2071
+ // quadrants indexed 0-based; index n-1 holds Mermaid quadrant-n
2072
+ // (1=top-right, 2=top-left, 3=bottom-left, 4=bottom-right)
2073
+ interface QuadrantBody { kind: 'quadrant'; accessibilityTitle?: string; accessibilityDescription?: string; title?: string; xAxis?: QuadrantAxis; yAxis?: QuadrantAxis; quadrants: [string?, string?, string?, string?]; points: QuadrantPoint[]; classDefs?: Record<string, QuadrantPointStyle> }
2074
+
2075
+ // Radar (spider) chart: axes = spokes; curves = one value per axis (axis order).
2076
+ interface RadarBodyAxis { id: string; label: string }
2077
+ interface RadarBodyCurve { id: string; label: string; values: number[] }
2078
+ interface RadarBody { kind: 'radar'; title?: string; axes: RadarBodyAxis[]; curves: RadarBodyCurve[]; min: number; max?: number; ticks: number; graticule: 'circle' | 'polygon'; showLegend: boolean }
2079
+
2080
+ type GanttTaskTag = 'active' | 'done' | 'crit' | 'milestone' | 'vert'
2081
+ // start: a date in the diagram's dateFormat or 'after id\u2026'; undefined = previous task's end.
2082
+ // end: a date, a duration token ('3d', '2w'), or 'until id\u2026'.
2083
+ interface GanttTask { id: string; taskId?: string; label: string; tags: GanttTaskTag[]; start?: string; end: string }
2084
+ interface GanttSection { id: string; label?: string; tasks: GanttTask[] }
2085
+ // Segment-preserving body: calendar directives (dateFormat, excludes, weekend\u2026),
2086
+ // click lines, and comments ride along VERBATIM as opaque-block segments \u2014 they
2087
+ // are preserved, not typed-editable. Tasks inside opaque segments are invisible
2088
+ // to mutation ops.
2089
+ type GanttStatement =
2090
+ | { kind: 'title' }
2091
+ | { kind: 'section'; ref: number }
2092
+ | { kind: 'task'; section: number; ref: number }
2093
+ | { kind: 'opaque-block'; lines: string[] }
2094
+ interface GanttBody { kind: 'gantt'; title?: string; sections: GanttSection[]; statements?: GanttStatement[] }
2095
+
2096
+ type MindmapShape = 'default' | 'rect' | 'rounded' | 'circle' | 'cloud' | 'bang' | 'hexagon'
2097
+ interface MindmapNode { id: string; label: string; shape: MindmapShape; markdown?: true; icon?: string; className?: string; children: MindmapNode[] }
2098
+ interface MindmapBody { kind: 'mindmap'; root: MindmapNode; accessibilityTitle?: string; accessibilityDescription?: string }
2099
+
2100
+ type GitGraphCommitType = 'NORMAL' | 'REVERSE' | 'HIGHLIGHT' | 'MERGE' | 'CHERRY_PICK'
2101
+ interface GitGraphCommit { id: string; message?: string; type: GitGraphCommitType; customType?: 'NORMAL' | 'REVERSE' | 'HIGHLIGHT'; tags: string[]; parents: string[]; branch: string; sequence: number; source: 'commit' | 'merge' | 'cherry-pick'; mergeBranch?: string; cherrySource?: string; cherryParent?: string; syntheticCherryTag?: string; customId: boolean }
2102
+ interface GitGraphBranch { name: string; order: number; sequence: number; head?: string }
2103
+ type GitGraphStatement = { kind: 'commit'; ref: string } | { kind: 'branch'; name: string; order?: number } | { kind: 'checkout'; branch: string; keyword: 'checkout' | 'switch' } | { kind: 'merge'; ref: string; branch: string } | { kind: 'cherry-pick'; ref: string; source: string; parent?: string }
2104
+ interface GitGraphBody { kind: 'gitgraph'; direction: 'LR' | 'TB' | 'BT'; mainBranchName: string; title?: string; commits: GitGraphCommit[]; branches: GitGraphBranch[]; statements: GitGraphStatement[]; accessibilityTitle?: string; accessibilityDescription?: string }
2105
+
2106
+ type FlowchartMutationOp =
2107
+ // shape also accepts any Mermaid v11 @{ shape } name/alias (e.g. 'manual-input')
2108
+ | { kind: 'add_node'; id: string; label: string; shape?: string; parent?: string }
2109
+ | { kind: 'remove_node'; id: string }
2110
+ | { kind: 'rename_node'; from: string; to: string }
2111
+ | { kind: 'set_label'; target: string; label: string } // target: node id, authored edge ID (e1), or 'from->to'/'from->to#k'
2112
+ | { kind: 'add_edge'; from: string; to: string; label?: string; style?: 'solid' | 'dotted' | 'thick' | 'invisible' }
2113
+ | { kind: 'remove_edge'; id: string } // id: authored edge ID (e1), or 'from->to'/'from->to#k'
2114
+ | { kind: 'set_shape'; id: string; shape: string } // geometry name or v11 @{ shape } name/alias
2115
+ | { kind: 'set_direction'; direction: 'TD' | 'TB' | 'LR' | 'BT' | 'RL'; subgraph?: string } // omit subgraph = diagram direction
2116
+ | { kind: 'add_subgraph'; id: string; label?: string; parent?: string; members?: string[] } // members MOVE into the new subgraph
2117
+ | { kind: 'remove_subgraph'; id: string; removeMembers?: boolean } // default dissolves; true deletes members + their edges
2118
+ | { kind: 'move_node'; id: string; subgraph: string | null } // null = top level
2119
+ | { kind: 'define_class'; name: string; style: string } // CSS-like pairs 'fill:#f96,stroke:#333'
2120
+ | { kind: 'set_node_class'; id: string; className: string | null } // null removes the assignment
2121
+ | { kind: 'set_node_style'; id: string; style: string | null } // null clears the inline style
2122
+
2123
+ type StateMutationOp =
2124
+ | { kind: 'add_state'; id: string; label?: string | null; parent?: string | null; region?: number }
2125
+ | { kind: 'remove_state'; id: string; recursive?: boolean } // recursive: true removes a non-empty composite's whole subtree
2126
+ | { kind: 'rename_state'; from: string; to: string }
2127
+ | { kind: 'set_state_label'; id: string; label: string | null }
2128
+ | { kind: 'add_transition'; from: string; to: string; label?: string | null; parent?: string | null; region?: number } // from/to may be '[*]' or a history ref ('X[H]')
2129
+ | { kind: 'remove_transition'; index?: number; from?: string; to?: string; parent?: string | null; region?: number }
2130
+ | { kind: 'set_transition_label'; index?: number; from?: string; to?: string; label: string | null; parent?: string | null; region?: number }
2131
+ | { kind: 'make_composite'; id: string; members: string[]; label?: string | null }
2132
+ | { kind: 'set_direction'; direction: 'TD' | 'TB' | 'LR' | 'BT' | 'RL'; state?: string | null } // omit state = diagram direction; composite id = its override
2133
+ | { kind: 'move_state'; id: string; parent: string | null; region?: number } // null = top level; region addresses a concurrent composite
2134
+ | { kind: 'dissolve_composite'; id: string } // hoists children + inner transitions; rejects while referenced
2135
+ | { kind: 'add_note'; target: string; side?: 'left' | 'right'; text: string } // side defaults to 'right'
2136
+ | { kind: 'remove_note'; index: number }
2137
+ | { kind: 'set_note_text'; index: number; text: string }
2138
+ | { kind: 'define_class'; name: string; style: string }
2139
+ | { kind: 'set_state_class'; id: string; className: string | null }
2140
+ | { kind: 'set_state_style'; id: string; style: string | null }
2141
+ | { kind: 'set_transition_style'; index?: number; default?: boolean; style: string | null; parent?: string | null; region?: number }
2142
+
2143
+ type SequenceMutationOp =
2144
+ | { kind: 'add_participant'; id: string; label?: string; participantKind?: 'participant' | 'actor' }
2145
+ | { kind: 'remove_participant'; id: string }
2146
+ | { kind: 'add_message'; from: string; to: string; text: string; style?: 'sync' | 'reply' | 'async' | 'async-dashed' | 'lost' | 'lost-dashed'; index?: number } // index = top-level insert position; omitted = append
2147
+ | { kind: 'remove_message'; index: number }
2148
+ | { kind: 'set_message_text'; index: number; text: string }
2149
+ | { kind: 'move_message'; from: number; to: number } // top-level indices
2150
+ | { kind: 'set_participant_label'; id: string; label: string }
2151
+ | { kind: 'add_fragment'; fragmentKind: SeqFragmentKind; label?: string; index?: number }
2152
+ | { kind: 'remove_fragment'; index: number }
2153
+ | { kind: 'set_fragment_label'; index: number; label: string | null }
2154
+ | { kind: 'add_fragment_branch'; fragmentIndex: number; label?: string }
2155
+ | { kind: 'set_fragment_branch_label'; fragmentIndex: number; branchIndex: number; label: string | null }
2156
+ | { kind: 'add_fragment_message'; fragmentIndex: number; branchIndex?: number; from: string; to: string; text: string; style?: 'sync' | 'reply' | 'async' | 'async-dashed' | 'lost' | 'lost-dashed'; index?: number }
2157
+ | { kind: 'remove_fragment_message'; fragmentIndex: number; branchIndex?: number; index: number }
2158
+ | { kind: 'set_fragment_message_text'; fragmentIndex: number; branchIndex?: number; index: number; text: string }
2159
+
2160
+ type TimelineMutationOp =
2161
+ | { kind: 'set_title'; title: string | null }
2162
+ | { kind: 'add_section'; label: string; index?: number } // index = insert position; omit to append
2163
+ | { kind: 'remove_section'; index: number }
2164
+ | { kind: 'set_section_label'; index: number; label: string }
2165
+ | { kind: 'add_period'; sectionIndex: number; label: string; events?: string[]; index?: number }
2166
+ | { kind: 'remove_period'; sectionIndex: number; periodIndex: number }
2167
+ | { kind: 'set_period_label'; sectionIndex: number; periodIndex: number; label: string }
2168
+ | { kind: 'add_event'; sectionIndex: number; periodIndex: number; text: string; index?: number }
2169
+ | { kind: 'remove_event'; sectionIndex: number; periodIndex: number; eventIndex: number }
2170
+ | { kind: 'set_event_text'; sectionIndex: number; periodIndex: number; eventIndex: number; text: string }
2171
+ // Chronology reorder (journey move_task/move_section convention): toIndex is
2172
+ // the insert position in the target container, applied after removal.
2173
+ | { kind: 'move_period'; fromSection: number; fromIndex: number; toSection: number; toIndex: number }
2174
+ | { kind: 'move_event'; fromSection: number; fromPeriod: number; fromIndex: number; toSection: number; toPeriod: number; toIndex: number }
2175
+ | { kind: 'move_section'; from: number; to: number }
2176
+ | { kind: 'set_accessibility_title'; title: string | null }
2177
+ | { kind: 'set_accessibility_description'; description: string | null }
2178
+
2179
+ type ClassMutationOp =
2180
+ | { kind: 'set_title'; title: string | null }
2181
+ | { kind: 'add_class'; id: string; label?: string; generic?: string; members?: string[]; namespace?: string }
2182
+ | { kind: 'remove_class'; id: string }
2183
+ | { kind: 'rename_class'; from: string; to: string }
2184
+ | { kind: 'set_class_generic'; class: string; generic: string | null }
2185
+ | { kind: 'add_member'; class: string; text: string }
2186
+ | { kind: 'remove_member'; class: string; index: number }
2187
+ | { kind: 'add_relation'; from: string; to: string; relKind: ClassRelationKind; label?: string }
2188
+ | { kind: 'remove_relation'; index: number }
2189
+ | { kind: 'add_note'; text: string; for?: string }
2190
+ | { kind: 'remove_note'; index: number }
2191
+ | { kind: 'set_class_namespace'; class: string; namespace: string | null }
2192
+ | { kind: 'define_class'; name: string; style: string }
2193
+ | { kind: 'set_css_class'; class: string; className: string | null }
2194
+ | { kind: 'set_class_style'; class: string; style: string | null }
2195
+
2196
+ type ErMutationOp =
2197
+ | { kind: 'add_entity'; id: string; label?: string; attributes?: string[] }
2198
+ | { kind: 'remove_entity'; id: string }
2199
+ | { kind: 'rename_entity'; from: string; to: string }
2200
+ | { kind: 'set_entity_label'; entity: string; label: string | null }
2201
+ | { kind: 'add_attribute'; entity: string; text: string }
2202
+ | { kind: 'remove_attribute'; entity: string; index: number }
2203
+ | { kind: 'add_relation'; from: string; to: string; leftCard: ErCardinality; rightCard: ErCardinality; dashed?: boolean; label?: string }
2204
+ | { kind: 'remove_relation'; index: number }
2205
+ | { kind: 'set_direction'; direction: 'TD' | 'TB' | 'LR' | 'BT' | 'RL' }
2206
+ | { kind: 'define_class'; name: string; style: string }
2207
+ | { kind: 'set_entity_class'; entity: string; className: string | null }
2208
+ | { kind: 'set_entity_style'; entity: string; style: string | null }
2209
+
2210
+ type JourneyMutationOp =
2211
+ | { kind: 'set_title'; title: string | null }
2212
+ | { kind: 'add_section'; label: string; index?: number }
2213
+ | { kind: 'remove_section'; index: number }
2214
+ | { kind: 'set_section_label'; index: number; label: string }
2215
+ | { kind: 'add_task'; sectionIndex: number; text: string; score: number; actors?: string[]; index?: number }
2216
+ | { kind: 'remove_task'; sectionIndex: number; taskIndex: number }
2217
+ | { kind: 'set_task_text'; sectionIndex: number; taskIndex: number; text: string }
2218
+ | { kind: 'set_task_score'; sectionIndex: number; taskIndex: number; score: number }
2219
+ | { kind: 'set_task_actors'; sectionIndex: number; taskIndex: number; actors: string[] }
2220
+ | { kind: 'rename_actor'; from: string; to: string }
2221
+ | { kind: 'move_task'; fromSection: number; fromIndex: number; toSection: number; toIndex: number }
2222
+ | { kind: 'move_section'; from: number; to: number }
2223
+ | { kind: 'set_accessibility_title'; title: string | null }
2224
+ | { kind: 'set_accessibility_description'; description: string | null }
2225
+
2226
+ type ArchitectureMutationOp =
2227
+ | { kind: 'set_title'; title: string | null }
2228
+ | { kind: 'set_accessibility_title'; title: string | null }
2229
+ | { kind: 'set_accessibility_description'; description: string | null }
2230
+ | { kind: 'add_service'; id: string; label?: string; icon?: string | null; group?: string | null }
2231
+ | { kind: 'remove_service'; id: string }
2232
+ | { kind: 'rename_service'; from: string; to: string }
2233
+ | { kind: 'set_service_label'; id: string; label: string }
2234
+ | { kind: 'set_service_icon'; id: string; icon: string | null }
2235
+ | { kind: 'move_service'; id: string; group: string | null }
2236
+ | { kind: 'add_junction'; id: string; group?: string | null }
2237
+ | { kind: 'remove_junction'; id: string }
2238
+ | { kind: 'rename_junction'; from: string; to: string }
2239
+ | { kind: 'move_junction'; id: string; group: string | null }
2240
+ | { kind: 'add_group'; id: string; label?: string; icon?: string | null; parent?: string | null }
2241
+ | { kind: 'set_group_label'; id: string; label: string }
2242
+ | { kind: 'remove_group'; id: string }
2243
+ | { kind: 'add_edge'; from: string; to: string; fromSide: ArchitectureSide; toSide: ArchitectureSide; fromBoundary?: ArchitectureEndpointBoundary; toBoundary?: ArchitectureEndpointBoundary; label?: string | null; hasArrowStart?: boolean; hasArrowEnd?: boolean }
2244
+ | { kind: 'update_edge'; index: number; from?: string; to?: string; fromSide?: ArchitectureSide; toSide?: ArchitectureSide; fromBoundary?: ArchitectureEndpointBoundary; toBoundary?: ArchitectureEndpointBoundary; label?: string | null; hasArrowStart?: boolean; hasArrowEnd?: boolean }
2245
+ | { kind: 'remove_edge'; index?: number; id?: string }
2246
+
2247
+ type XyChartAxisSpec = { name?: string | null; categories?: string[]; range?: { min: number; max: number } }
2248
+ type XyChartMutationOp =
2249
+ | { kind: 'set_title'; title: string | null }
2250
+ | { kind: 'set_x_axis'; axis: XyChartAxisSpec | null }
2251
+ | { kind: 'set_y_axis'; axis: XyChartAxisSpec | null }
2252
+ | { kind: 'add_series'; kind2: 'bar' | 'line'; name?: string | null; values: number[] }
2253
+ | { kind: 'remove_series'; index: number }
2254
+ | { kind: 'set_series_values'; index: number; values: number[] }
2255
+ | { kind: 'set_series_name'; index: number; name: string | null }
2256
+ | { kind: 'reorder_series'; from: number; to: number }
2257
+ | { kind: 'set_orientation'; horizontal: boolean }
2258
+ | { kind: 'set_data_point'; seriesIndex: number; index: number; value: number }
2259
+
2260
+ type PieMutationOp =
2261
+ | { kind: 'set_title'; title: string | null }
2262
+ | { kind: 'set_show_data'; showData: boolean }
2263
+ | { kind: 'add_slice'; label: string; value: number } // value > 0
2264
+ | { kind: 'remove_slice'; label: string }
2265
+ | { kind: 'rename_slice'; from: string; to: string }
2266
+ | { kind: 'set_slice_value'; label: string; value: number }
2267
+ | { kind: 'reorder_slice'; from: number; to: number }
2268
+
2269
+ type QuadrantMutationOp =
2270
+ | { kind: 'set_title'; title: string | null }
2271
+ | { kind: 'set_axis_labels'; axis: 'x' | 'y'; near: string | null; far?: string | null }
2272
+ | { kind: 'set_quadrant_label'; quadrant: number; label: string | null } // quadrant 1..4
2273
+ | { kind: 'add_point'; label: string; x: number; y: number } // x,y in [0,1]
2274
+ | { kind: 'remove_point'; label: string }
2275
+ | { kind: 'move_point'; label: string; x: number; y: number }
2276
+ | { kind: 'rename_point'; from: string; to: string }
2277
+
2278
+ type MindmapMutationOp =
2279
+ | { kind: 'add_node'; id: string; label: string; parent: string; shape?: MindmapShape; index?: number }
2280
+ | { kind: 'remove_node'; id: string; recursive?: boolean }
2281
+ | { kind: 'rename_node'; from: string; to: string }
2282
+ | { kind: 'set_label'; id: string; label: string }
2283
+ | { kind: 'move_node'; id: string; parent: string; index?: number }
2284
+ | { kind: 'set_shape'; id: string; shape: MindmapShape }
2285
+ | { kind: 'set_icon'; id: string; icon: string | null }
2286
+ | { kind: 'set_node_class'; id: string; className: string | null }
2287
+ | { kind: 'set_accessibility_title'; title: string | null }
2288
+ | { kind: 'set_accessibility_description'; description: string | null }
2289
+
2290
+ type GitGraphMutationOp =
2291
+ | { kind: 'append_commit'; id?: string; message?: string; type?: 'NORMAL' | 'REVERSE' | 'HIGHLIGHT'; tags?: string[] }
2292
+ | { kind: 'create_branch'; name: string; order?: number }
2293
+ | { kind: 'checkout_branch'; name: string }
2294
+ | { kind: 'merge_branch'; name: string; id?: string; type?: 'NORMAL' | 'REVERSE' | 'HIGHLIGHT'; tags?: string[] }
2295
+ | { kind: 'cherry_pick'; id: string; parent?: string; tags?: string[] }
2296
+ | { kind: 'set_commit_message'; id: string; message: string | null }
2297
+ | { kind: 'set_commit_type'; id: string; type: 'NORMAL' | 'REVERSE' | 'HIGHLIGHT' }
2298
+ | { kind: 'set_commit_tags'; id: string; tags: string[] }
2299
+ | { kind: 'rename_branch'; from: string; to: string }
2300
+ | { kind: 'set_accessibility_title'; title: string | null }
2301
+ | { kind: 'set_accessibility_description'; description: string | null }
2302
+
2303
+ type RadarMutationOp =
2304
+ | { kind: 'set_title'; title: string | null }
2305
+ | { kind: 'add_axis'; id: string; label?: string | null; index?: number; fill?: number }
2306
+ | { kind: 'remove_axis'; id: string }
2307
+ | { kind: 'rename_axis'; from: string; to: string }
2308
+ | { kind: 'set_axis_label'; id: string; label: string | null }
2309
+ | { kind: 'reorder_axis'; from: number; to: number }
2310
+ | { kind: 'add_curve'; id: string; label?: string | null; values: number[]; index?: number }
2311
+ | { kind: 'remove_curve'; id: string }
2312
+ | { kind: 'set_curve_values'; id: string; values: number[] }
2313
+ | { kind: 'set_curve_value'; curve: string; axis: string; value: number }
2314
+ | { kind: 'set_curve_label'; id: string; label: string | null }
2315
+ | { kind: 'rename_curve'; from: string; to: string }
2316
+ | { kind: 'reorder_curve'; from: number; to: number }
2317
+ | { kind: 'set_config'; max?: number | null; min?: number | null; ticks?: number | null; graticule?: 'circle' | 'polygon' | null; showLegend?: boolean | null }
2318
+
2319
+ type GanttMutationOp =
2320
+ | { kind: 'set_title'; title: string | null }
2321
+ | { kind: 'add_section'; label: string }
2322
+ | { kind: 'rename_section'; index: number; label: string }
2323
+ | { kind: 'remove_section'; index: number }
2324
+ | { kind: 'add_task'; sectionIndex: number; label: string; taskId?: string; tags?: GanttTaskTag[]; start?: string; end: string; index?: number }
2325
+ | { kind: 'remove_task'; sectionIndex: number; taskIndex: number }
2326
+ | { kind: 'rename_task'; sectionIndex: number; taskIndex: number; label: string }
2327
+ | { kind: 'set_task_status'; sectionIndex: number; taskIndex: number; status: 'active' | 'done' | 'crit' | null }
2328
+ | { kind: 'set_task_dates'; sectionIndex: number; taskIndex: number; start?: string | null; end?: string }
2329
+ | { kind: 'set_task_flags'; sectionIndex: number; taskIndex: number; milestone?: boolean; vert?: boolean }
2330
+ // set_task_id rewrites structured after/until references on rename; rejects
2331
+ // while referenced from opaque lines (click/comments), and null rejects
2332
+ // while referenced at all.
2333
+ | { kind: 'set_task_id'; sectionIndex: number; taskIndex: number; taskId: string | null }
2334
+ // Source order IS gantt scheduling semantics: moves are rejected with a
2335
+ // prescriptive error when they would change an implicit-start task's
2336
+ // predecessor (materialize an explicit start via set_task_dates first).
2337
+ | { kind: 'move_task'; fromSection: number; fromIndex: number; toSection: number; toIndex: number }
2338
+ | { kind: 'move_section'; from: number; to: number }
2339
+
2340
+ // Tier 1 (structural, reliable): EMPTY_DIAGRAM, EDGE_MISANCHORED, OFF_CANVAS,
2341
+ // GROUP_BREACH, UNKNOWN_SHAPE, LABEL_OVERFLOW (rendered-line char count:
2342
+ // <br> splits lines, XML entities decode to one char),
2343
+ // UNRESOLVABLE_SCHEDULE (gantt: parses but schedule cannot resolve; render would fail),
2344
+ // RENDER_FAILED (strict renderer rejected the canonical source).
2345
+ // Tier 2 (geometric, advisory): NODE_OVERLAP, ROUTE_SELF_CROSS, and the
2346
+ // route-contract tripwires ROUTE_HITCH, ROUTE_UNEXPLAINED_BEND,
2347
+ // ROUTE_LABEL_ON_SHARED_TRUNK, ROUTE_SELF_LOOP_OCCUPANCY, ROUTE_CONTAINER_MISANCHOR,
2348
+ // ROUTE_SHAPE_MISANCHOR, ROUTE_STALE_AFTER_NODE_MOVE.
2349
+ // Tier 3 (lint, advisory): DUPLICATE_EDGE, UNREACHABLE_NODE,
2350
+ // DECISION_BRANCH_UNLABELED, COMMENT_DROPPED, UNSUPPORTED_SYNTAX,
2351
+ // CONTENT_DROPPED_ON_ROUNDTRIP, INEFFECTIVE_CONFIG, LOW_CONTRAST,
2352
+ // BRAND_CONSTRAINT_WARNING. BRAND_CONSTRAINT_ERROR is inspect-only policy
2353
+ // selected explicitly by a Style constraint with action "error".
2354
+ type RenderedRegionKind='node'|'edge'|'label'|'canvas'|'group'|'cluster'|'lane'|'band'|'compartment'|'plot'|'ring'
2355
+ type DiagramActionSecurity='safe'|'unsafe'|'source-only'|'unsupported'
2356
+ interface RenderedRegion { id:string;kind:RenderedRegionKind;elementId?:string;parentId?:string;bounds:{x:number;y:number;w:number;h:number};sourceLine?:number }
2357
+ interface DiagramActionRecord { id?:string;regionId?:string;family:DiagramKind;target:string;action:'href'|'call'|'callback';raw:string;line?:number;href?:string;security:DiagramActionSecurity;executable:false;message?:string }
2358
+ interface RenderedLayout { version: 1; kind: DiagramKind | ExternalFamilyId; nodes: unknown[]; edges: unknown[]; groups: unknown[]; regions?: RenderedRegion[]; actions?: DiagramActionRecord[]; bounds: { w: number; h: number } }
2359
+
2360
+ type WarningCode =
2361
+ | 'EMPTY_DIAGRAM' | 'EDGE_MISANCHORED' | 'OFF_CANVAS' | 'GROUP_BREACH'
2362
+ | 'UNKNOWN_SHAPE' | 'LABEL_OVERFLOW' | 'UNRESOLVABLE_SCHEDULE' | 'RENDER_FAILED'
2363
+ | 'NODE_OVERLAP' | 'ROUTE_SELF_CROSS' | 'ROUTE_HITCH'
2364
+ | 'ROUTE_UNEXPLAINED_BEND' | 'ROUTE_LABEL_ON_SHARED_TRUNK' | 'ROUTE_SELF_LOOP_OCCUPANCY' | 'ROUTE_CONTAINER_MISANCHOR'
2365
+ | 'ROUTE_SHAPE_MISANCHOR' | 'ROUTE_STALE_AFTER_NODE_MOVE'
2366
+ | 'DUPLICATE_EDGE' | 'UNREACHABLE_NODE' | 'DECISION_BRANCH_UNLABELED' | 'COMMENT_DROPPED' | 'UNSUPPORTED_SYNTAX'
2367
+ | 'CONTENT_DROPPED_ON_ROUNDTRIP' | 'INEFFECTIVE_CONFIG' | 'LOW_CONTRAST'
2368
+ | 'BRAND_CONSTRAINT_WARNING' | 'BRAND_CONSTRAINT_ERROR'
2369
+
2370
+ interface VerifyResult {
2371
+ ok: boolean
2372
+ warnings: { code: WarningCode; [field: string]: unknown }[]
2373
+ layout: RenderedLayout
2374
+ }
2375
+
2376
+ interface DiagramAnalysis {
2377
+ kind: DiagramKind | ExternalFamilyId
2378
+ feedbackEdges: Array<{ edgeIndex: number; from: string; to: string; label?: string; routeClass: string }>
2379
+ actions: Array<{ id?: string; regionId?: string; family: DiagramKind; target: string; action: 'href' | 'call' | 'callback'; raw: string; line?: number; href?: string; security: 'safe' | 'unsafe' | 'source-only' | 'unsupported'; executable: false; message?: string }>
2380
+ gantt?: { criticalPathTaskIds: string[]; slackByTaskId: Record<string, number>; projectStart: number; projectEnd: number; entryTaskIds: string[]; sinkTaskIds: string[] }
2381
+ }
2382
+
2383
+ ${SDK_ANY_MUTATION_OP_DECLARATION}
2384
+
2385
+ declare const mermaid: {
2386
+ parseRegisteredMermaid(source: string): Result<ParsedDiagram, ParseError[]>
2387
+ // Blank-slate authoring: createMermaid returns an empty structured diagram
2388
+ // for any DiagramKind (already narrowed \u2014 pass it straight to mutate).
2389
+ // buildMermaid folds a typed op list over that empty diagram; on failure the
2390
+ // error carries opIndex of the op that failed. direction applies to
2391
+ // flowchart/state only.
2392
+ createMermaid(kind: DiagramKind, opts?: { direction?: 'TD' | 'TB' | 'LR' | 'BT' | 'RL' }): ValidDiagram
2393
+ buildMermaid(kind: DiagramKind, ops: AnyMutationOp[], opts?: { direction?: 'TD' | 'TB' | 'LR' | 'BT' | 'RL' }): Result<ValidDiagram, { code: string; message: string; opIndex: number }>
2394
+ ${SDK_NARROWER_METHOD_DECLARATIONS}
2395
+ ${SDK_MUTATE_METHOD_DECLARATIONS}
2396
+ verifyMermaid(input: ParsedDiagram | string, opts?: { suppress?: WarningCode[]; labelCharCap?: number; renderOptions?: SharedRenderOptions }): VerifyResult
2397
+ analyzeMermaid(d: ValidDiagram): DiagramAnalysis
2398
+ analyzeMermaidSource(source: string): Result<DiagramAnalysis, { code: string; message: string }[]>
2399
+ describeMermaidFacts(d: ValidDiagram): string[]
2400
+ describeMermaidFactsSource(source: string): Result<string[], { code: string; message: string }[]>
2401
+ checkMermaid(d: ValidDiagram, spec: CheckMermaidSpec): CheckMermaidResult
2402
+ checkMermaidSource(source: string, spec: CheckMermaidSpec): Result<CheckMermaidResult, { code: string; message: string }[]>
2403
+ serializeMermaid(d: ParsedDiagram): string
2404
+ // Compatibility conveniences return only bytes/text; use the receipt-aware
2405
+ // methods below for transport parity and projection/security evidence.
2406
+ renderMermaidSVG(input: ParsedDiagram | string, opts?: SvgRenderOptions): string
2407
+ renderMermaidASCII(input: ParsedDiagram | string, opts?: AsciiRenderOptions): string
2408
+ ${CODE_MODE_RENDER_METHOD_DECLARATIONS}
2409
+ // Op discovery \u2014 look up exact op shapes at runtime instead of guessing.
2410
+ // describeOps returns every op's field names, required-ness, inlined enum
2411
+ // values, and constraint/default notes (e.g. score "integer 1..5", shape
2412
+ // "default: rectangle"); opSignatures returns compact one-liners like
2413
+ // "add_point(label, x, y)". Read these before authoring an unfamiliar op.
2414
+ describeOps(family: DiagramKind): Record<string, { name: string; required: boolean; type: string; note?: string }[]>
2415
+ opSignatures(family: DiagramKind): string[]
2416
+ }
2417
+
2418
+ // Conventions:
2419
+ // 1. For new diagrams, use buildMermaid(kind, ops) \u2014 or createMermaid(kind)
2420
+ // then mutate step by step \u2014 and verify/render the result. Hand-author
2421
+ // Mermaid source only for syntax the typed ops do not model.
2422
+ // 2. For existing structured diagrams, use mutate() + verify + serializeMermaid();
2423
+ // do not regenerate/concatenate source when a typed op exists.
2424
+ ${SDK_FAMILY_CONVENTION}
2425
+ // State owns a dedicated body (BUILD-19); asFlowchart returns null on it.
2426
+ // Gantt bodies are segment-preserving: directives/click/comment lines ride
2427
+ // along verbatim as opaque-block segments and are edited as source only.
2428
+ // Opaque-fallback
2429
+ // bodies (unmodeled syntax) are source-level only; if explicitly edited as
2430
+ // text, re-parse and verify before returning.
2431
+ // 4. verify.ok is structural, not a visual-quality score; inspect warnings/layout or render artifacts for layout quality.
2432
+ // For semantic task correctness, read back deterministic facts or check them:
2433
+ // checkMermaid(d, ['edge Processing -> [*] : done', 'member Duck +quack()']).
2434
+ // 5. Layout is deterministic and never seeded. The render option seed only
2435
+ // re-rolls stochastic ink of styled looks (render option style: a name,
2436
+ // an inline style record, or a stack merged left-to-right; a colors-only
2437
+ // style is a theme); geometry is identical for identical input. Gantt
2438
+ // never reads the wall clock; pass render option ganttToday to draw a
2439
+ // deterministic today marker.
2440
+ `;
2441
+
2442
+ // src/mcp/sdk-discovery.ts
2443
+ var SDK_FAMILIES = BUILTIN_FAMILY_METADATA.map((family) => family.id);
2444
+ var SDK_FAMILY_SET = new Set(SDK_FAMILIES);
2445
+ var DIAGRAM_KIND = SDK_FAMILIES.map((family) => `'${family}'`).join(" | ");
2446
+ var NARROWERS = BUILTIN_FAMILY_METADATA.map((family) => ` ${family.narrower}(diagram: ValidDiagram): ValidDiagram | null`).join("\n");
2447
+ var SDK_CORE_DECLARATION = `type DiagramKind = ${DIAGRAM_KIND}
2448
+ type MutationOp = { kind: string; [field: string]: unknown }
2449
+ type Result<T, E = { code: string; message: string }> = { ok: true; value: T } | { ok: false; error: E }
2450
+ interface SourceLocation { readonly line: number; readonly col: number }
2451
+ interface SourceMapSpans { readonly preserved: PreservedSourceSpans; readonly nodes: ReadonlyMap<string, SourceSpan>; readonly edges: ReadonlyMap<string, SourceSpan>; readonly groups: ReadonlyMap<string, SourceSpan>; readonly labels: ReadonlyMap<string, SourceSpan> }
2452
+ interface SourceMap { readonly nodes: ReadonlyMap<string, SourceLocation>; readonly edges: ReadonlyMap<string, SourceLocation>; readonly groups: ReadonlyMap<string, SourceLocation>; readonly labels: ReadonlyMap<string, SourceLocation>; readonly spans?: SourceMapSpans }
2453
+ interface ValidDiagram { readonly kind: DiagramKind; readonly source: SourceMap }
2454
+ type ExternalFamilyId = \`family:\${string}\`
2455
+ interface ExtensionCompatibility {
2456
+ readonly [contract: string]: string | undefined
2457
+ readonly core?: string
2458
+ readonly scene?: string
2459
+ }
2460
+ interface ExtensionProvenance { readonly owner: string; readonly source: string; readonly reference?: string }
2461
+ interface ExtensionIdentity<Kind extends string = string> {
2462
+ readonly id: \`\${Kind}:\${string}\`
2463
+ readonly kind: Kind
2464
+ readonly version: string
2465
+ readonly compatibility: ExtensionCompatibility
2466
+ readonly provenance: ExtensionProvenance
2467
+ }
2468
+ interface SourceSpanPoint { readonly offset: number; readonly line: number; readonly col: number }
2469
+ interface SourceSpan { readonly start: SourceSpanPoint; readonly end: SourceSpanPoint }
2470
+ interface PreservedSourceSpans {
2471
+ readonly source: SourceSpan
2472
+ readonly wrapper?: SourceSpan
2473
+ readonly frontmatter?: SourceSpan
2474
+ readonly initDirectives?: readonly SourceSpan[]
2475
+ readonly accessibilityDirectives?: readonly SourceSpan[]
2476
+ readonly header: SourceSpan
2477
+ readonly body: SourceSpan
2478
+ }
2479
+ interface SourcePreservationReceipt {
2480
+ readonly version: 1
2481
+ readonly classification: 'unsupported' | 'inventory-only' | 'unknown'
2482
+ readonly source: string
2483
+ readonly header: string
2484
+ readonly upstreamFamilyId?: string
2485
+ readonly mermaidVersion: string
2486
+ readonly spans?: PreservedSourceSpans
2487
+ }
2488
+ interface ParseError {
2489
+ readonly code: string
2490
+ readonly message: string
2491
+ readonly line?: number
2492
+ readonly col?: number
2493
+ readonly preservation?: SourcePreservationReceipt
2494
+ readonly help?: string
2495
+ }
2496
+ interface ExtensionValidDiagram {
2497
+ readonly kind: ExternalFamilyId
2498
+ readonly descriptorIdentity: ExtensionIdentity<'family'>
2499
+ readonly source: SourceMap
2500
+ }
2501
+ interface PreservedValidDiagram {
2502
+ readonly kind: ExternalFamilyId
2503
+ readonly source: SourceMap
2504
+ readonly body: {
2505
+ readonly kind: 'preserved'
2506
+ readonly representation: 'opaque' | 'unknown'
2507
+ readonly source: string
2508
+ readonly preservation: SourcePreservationReceipt
2509
+ readonly spans: PreservedSourceSpans
2510
+ readonly diagnostic: {
2511
+ readonly code: 'UNSUPPORTED_FAMILY' | 'UNKNOWN_HEADER' | 'FAMILY_DESCRIPTOR_MISMATCH'
2512
+ readonly message: string
2513
+ readonly help: string
2514
+ }
2515
+ }
2516
+ }
2517
+ type ParsedDiagram = ValidDiagram | ExtensionValidDiagram | PreservedValidDiagram
2518
+ type RenderedRegionKind='node'|'edge'|'label'|'canvas'|'group'|'cluster'|'lane'|'band'|'compartment'|'plot'|'ring'
2519
+ type DiagramActionSecurity='safe'|'unsafe'|'source-only'|'unsupported'
2520
+ interface RenderedRegion { id:string;kind:RenderedRegionKind;elementId?:string;parentId?:string;bounds:{x:number;y:number;w:number;h:number};sourceLine?:number }
2521
+ interface DiagramActionRecord { id?:string;regionId?:string;family:DiagramKind;target:string;action:'href'|'call'|'callback';raw:string;line?:number;href?:string;security:DiagramActionSecurity;executable:false;message?:string }
2522
+ interface RenderedLayout { version: 1; kind: DiagramKind | ExternalFamilyId; bounds: { w: number; h: number }; nodes: unknown[]; edges: unknown[]; groups: unknown[]; regions?: RenderedRegion[]; actions?: DiagramActionRecord[] }
2523
+ interface VerifyResult { ok: boolean; warnings: unknown[]; layout: RenderedLayout }
2524
+ type CheckMermaidSpec = string[] | { include?: string[]; exclude?: string[]; exact?: boolean }
2525
+ interface CheckMermaidResult { ok: boolean; missing: string[]; unexpected: string[]; facts: string[] }
2526
+ type MermaidConfigScalar = string | number | boolean | null
2527
+ type MermaidConfigValue = MermaidConfigScalar | MermaidConfigValue[] | { [key: string]: MermaidConfigValue | undefined }
2528
+ type MermaidRuntimeConfig = { [key: string]: MermaidConfigValue | undefined }
2529
+
2530
+ ${CODE_MODE_CORE_RENDER_OPTION_DECLARATIONS}
2531
+
2532
+ declare const mermaid: {
2533
+ parseRegisteredMermaid(source: string): Result<ParsedDiagram, ParseError[]>
2534
+ createMermaid(kind: DiagramKind, opts?: { direction?: 'TD' | 'TB' | 'LR' | 'BT' | 'RL' }): ValidDiagram
2535
+ buildMermaid(kind: DiagramKind, ops: MutationOp[], opts?: { direction?: 'TD' | 'TB' | 'LR' | 'BT' | 'RL' }): Result<ValidDiagram, { code: string; message: string; opIndex: number }>
2536
+ ${NARROWERS}
2537
+ mutate(diagram: ValidDiagram, op: MutationOp): Result<ValidDiagram>
2538
+ verifyMermaid(input: ParsedDiagram | string, opts?: { suppress?: string[]; labelCharCap?: number; renderOptions?: SharedRenderOptions }): VerifyResult
2539
+ analyzeMermaid(diagram: ValidDiagram): Record<string, unknown>
2540
+ analyzeMermaidSource(source: string): Result<Record<string, unknown>>
2541
+ describeMermaidFacts(diagram: ValidDiagram): string[]
2542
+ describeMermaidFactsSource(source: string): Result<string[]>
2543
+ checkMermaid(diagram: ValidDiagram, spec: CheckMermaidSpec): CheckMermaidResult
2544
+ checkMermaidSource(source: string, spec: CheckMermaidSpec): Result<CheckMermaidResult>
2545
+ serializeMermaid(diagram: ParsedDiagram): string
2546
+ renderMermaidSVG(input: ParsedDiagram | string, opts?: SvgRenderOptions): string
2547
+ renderMermaidSVGWithReceipt(input: ParsedDiagram | string, opts?: SvgRenderOptions): RenderedSvg
2548
+ renderMermaidASCII(input: ParsedDiagram | string, opts?: AsciiRenderOptions): string
2549
+ renderMermaidASCIIWithReceipt(input: ParsedDiagram | string, opts?: AsciiRenderOptions): RenderedAscii
2550
+ layoutMermaidWithReceipt(input: ParsedDiagram | string, opts?: LayoutRenderOptions): RenderedLayoutArtifact
2551
+ describeOps(family: DiagramKind): Record<string, { name: string; required: boolean; type: string; note?: string }[]>
2552
+ opSignatures(family: DiagramKind): string[]
2553
+ }`;
2554
+ function createDescribeSdkTool() {
2555
+ return {
2556
+ name: "describe_sdk",
2557
+ description: `Return version-matched mutation operations for one diagram family.
2558
+ Use detail=signatures for the compact op menu or detail=fields (default) for exact
2559
+ field types, required flags, enum values, defaults, and constraints. Call this
2560
+ before build, mutate, or execute when the family schema is not already known.`,
2561
+ inputSchema: {
2562
+ type: "object",
2563
+ properties: {
2564
+ family: { type: "string", enum: [...SDK_FAMILIES], description: "Diagram family whose mutation operations are needed." },
2565
+ detail: { type: "string", enum: ["signatures", "fields"], description: "signatures for a compact menu; fields for the complete schema (default)." }
2566
+ },
2567
+ required: ["family"]
2568
+ },
2569
+ annotations: PURE_COMPUTE_ANNOTATIONS
2570
+ };
2571
+ }
2572
+ function describeSdkPayload(args) {
2573
+ const family = args.family;
2574
+ if (typeof family !== "string" || !SDK_FAMILY_SET.has(family)) {
2575
+ throw new Error(`describe_sdk family must be one of: ${SDK_FAMILIES.join(", ")}`);
2576
+ }
2577
+ const detail = args.detail ?? "fields";
2578
+ if (detail !== "signatures" && detail !== "fields") {
2579
+ throw new Error("describe_sdk detail must be one of: signatures, fields");
2580
+ }
2581
+ if (detail === "signatures") {
2582
+ return { ok: true, family, detail, signatures: opSignatures(family) };
2583
+ }
2584
+ return { ok: true, family, detail, ops: describeOps(family) };
2585
+ }
2586
+
2587
+ // src/mcp/describe-payload.ts
2588
+ var EXTERNAL_FAMILY_DESCRIBE_UNAVAILABLE_CODE = "EXTERNAL_FAMILY_DESCRIBE_UNAVAILABLE";
2589
+ function externalFamilyDescribeUnavailable(family) {
2590
+ return Object.freeze({
2591
+ code: EXTERNAL_FAMILY_DESCRIBE_UNAVAILABLE_CODE,
2592
+ capability: "describe",
2593
+ family,
2594
+ message: `Registered external family "${family}" has no semantic describe contract in FamilyDescriptor v2.`
2595
+ });
2596
+ }
2597
+ function isExtensionDiagram(diagram) {
2598
+ return diagram.body.kind === "extension";
2599
+ }
2600
+ function isPreservedDiagram(diagram) {
2601
+ return diagram.body.kind === "preserved";
2602
+ }
2603
+ function mcpDescribeFormat(args) {
2604
+ const format = args.format ?? "text";
2605
+ if (format === "text" || format === "json" || format === "facts") return format;
2606
+ throw new Error("describe format must be one of: text, json, facts");
2607
+ }
2608
+ function mcpDescribePayload(source, args) {
2609
+ const format = mcpDescribeFormat(args);
2610
+ const parsed = parseRegisteredMermaid(source);
2611
+ if (!parsed.ok) {
2612
+ if (format === "text") return { ok: true, text: describeMermaidSource(source) };
2613
+ return { ok: false, errors: parsed.error };
2614
+ }
2615
+ const diagram = parsed.value;
2616
+ if (isPreservedDiagram(diagram)) {
2617
+ return {
2618
+ ok: false,
2619
+ family: diagram.body.preservation.upstreamFamilyId ?? diagram.kind,
2620
+ error: {
2621
+ ...diagram.body.diagnostic,
2622
+ preservation: diagram.body.preservation
2623
+ }
2624
+ };
2625
+ }
2626
+ if (isExtensionDiagram(diagram)) {
2627
+ return {
2628
+ ok: false,
2629
+ family: diagram.kind,
2630
+ error: externalFamilyDescribeUnavailable(diagram.kind)
2631
+ };
2632
+ }
2633
+ const verification = verifyMermaid(diagram);
2634
+ if (!verification.ok) {
2635
+ return {
2636
+ ok: false,
2637
+ family: diagram.kind,
2638
+ warnings: verification.warnings
2639
+ };
2640
+ }
2641
+ if (format === "text") return { ok: true, text: describeMermaid(diagram), warnings: verification.warnings };
2642
+ if (format === "facts") return { ok: true, facts: describeMermaidFacts(diagram), warnings: verification.warnings };
2643
+ return { ok: true, tree: JSON.parse(describeMermaid(diagram, { format: "json" })), warnings: verification.warnings };
2644
+ }
2645
+
2646
+ // src/mcp/artifacts.ts
2647
+ import { createHash, randomUUID } from "crypto";
2648
+ import {
2649
+ closeSync,
2650
+ existsSync,
2651
+ fstatSync,
2652
+ fsyncSync,
2653
+ lstatSync,
2654
+ mkdirSync,
2655
+ openSync,
2656
+ readFileSync,
2657
+ readdirSync,
2658
+ renameSync,
2659
+ unlinkSync,
2660
+ writeFileSync,
2661
+ writeSync
2662
+ } from "fs";
2663
+ import { hostname, tmpdir } from "os";
2664
+ import { basename, join, resolve, sep } from "path";
2665
+ var DEFAULT_MAX_BYTES = 20 * 1024 * 1024;
2666
+ var DEFAULT_MAX_TOTAL_BYTES = 200 * 1024 * 1024;
2667
+ var DEFAULT_MAX_ARTIFACTS = 1e3;
2668
+ var DEFAULT_TTL_MS = 60 * 60 * 1e3;
2669
+ var MANIFEST_NAME = ".agentic-mermaid-artifacts-v1.json";
2670
+ var LOCK_NAME = ".agentic-mermaid-artifacts-v1.lock";
2671
+ var MAX_MANIFEST_BYTES = 1024 * 1024;
2672
+ var MANAGED_NAME = /^[0-9a-z]+-[0-9a-f-]{36}\.[a-z0-9_-]+$/;
2673
+ function positiveSafeInteger(value, field) {
2674
+ if (!Number.isSafeInteger(value) || value <= 0) throw new Error(`artifact ${field} must be a positive safe integer`);
2675
+ return value;
2676
+ }
2677
+ var ArtifactStore = class {
2678
+ dir;
2679
+ maxBytes;
2680
+ maxTotalBytes;
2681
+ maxArtifacts;
2682
+ ttlMs;
2683
+ baseUrl;
2684
+ now;
2685
+ records = /* @__PURE__ */ new Map();
2686
+ manifestPath;
2687
+ lockPath;
2688
+ lockToken = randomUUID();
2689
+ lockFd = -1;
2690
+ closed = false;
2691
+ constructor(opts = {}) {
2692
+ this.dir = resolve(opts.dir ?? join(tmpdir(), "agentic-mermaid-mcp-artifacts"));
2693
+ this.baseUrl = normalizeBaseUrl(opts.baseUrl);
2694
+ this.maxBytes = positiveSafeInteger(opts.maxBytes ?? DEFAULT_MAX_BYTES, "maxBytes");
2695
+ this.maxTotalBytes = positiveSafeInteger(opts.maxTotalBytes ?? DEFAULT_MAX_TOTAL_BYTES, "maxTotalBytes");
2696
+ this.maxArtifacts = positiveSafeInteger(opts.maxArtifacts ?? DEFAULT_MAX_ARTIFACTS, "maxArtifacts");
2697
+ this.ttlMs = positiveSafeInteger(opts.ttlMs ?? DEFAULT_TTL_MS, "ttlMs");
2698
+ if (this.maxBytes > this.maxTotalBytes) throw new Error("artifact maxBytes must not exceed maxTotalBytes");
2699
+ this.now = opts.now ?? (() => Date.now());
2700
+ mkdirSync(this.dir, { recursive: true, mode: 448 });
2701
+ this.manifestPath = join(this.dir, MANIFEST_NAME);
2702
+ this.lockPath = join(this.dir, LOCK_NAME);
2703
+ this.acquireOwnership();
2704
+ try {
2705
+ this.loadManifest();
2706
+ this.reconcileManagedFiles();
2707
+ this.cleanupExpired();
2708
+ } catch (error) {
2709
+ this.close();
2710
+ throw error;
2711
+ }
2712
+ }
2713
+ setBaseUrl(baseUrl) {
2714
+ this.baseUrl = normalizeBaseUrl(baseUrl);
2715
+ }
2716
+ hasBaseUrl() {
2717
+ return typeof this.baseUrl === "string" && this.baseUrl.length > 0;
2718
+ }
2719
+ write(bytes, opts) {
2720
+ this.assertOpen();
2721
+ if (bytes.byteLength > this.maxBytes) throw new Error(`artifact exceeds maxBytes (${bytes.byteLength} > ${this.maxBytes})`);
2722
+ if (bytes.byteLength > this.maxTotalBytes) throw new Error(`artifact exceeds maxTotalBytes (${bytes.byteLength} > ${this.maxTotalBytes})`);
2723
+ this.cleanupExpired();
2724
+ if (this.records.size >= this.maxArtifacts) throw new Error(`artifact store exceeds maxArtifacts (${this.records.size + 1} > ${this.maxArtifacts})`);
2725
+ const totalBytes = [...this.records.values()].reduce((total, record) => total + record.bytes, 0);
2726
+ if (totalBytes + bytes.byteLength > this.maxTotalBytes) {
2727
+ throw new Error(`artifact store exceeds maxTotalBytes (${totalBytes + bytes.byteLength} > ${this.maxTotalBytes})`);
2728
+ }
2729
+ const buffer = Buffer.from(bytes);
2730
+ const sha256 = digest(buffer);
2731
+ const ext = sanitizeExtension(opts.extension);
2732
+ const createdAt = this.now();
2733
+ const name = `${createdAt.toString(36)}-${randomUUID()}${ext}`;
2734
+ const path = safePath(this.dir, name);
2735
+ const temp = safePath(this.dir, `.${name}.${randomUUID()}.tmp`);
2736
+ const tracked = {
2737
+ name,
2738
+ path,
2739
+ mimeType: opts.mimeType,
2740
+ bytes: buffer.length,
2741
+ sha256,
2742
+ createdAt,
2743
+ expiresAt: createdAt + this.ttlMs
2744
+ };
2745
+ try {
2746
+ writeFileSync(temp, buffer, { mode: 384 });
2747
+ renameSync(temp, path);
2748
+ this.records.set(name, tracked);
2749
+ this.persistManifest();
2750
+ } catch (error) {
2751
+ this.records.delete(name);
2752
+ try {
2753
+ unlinkSync(temp);
2754
+ } catch {
2755
+ }
2756
+ try {
2757
+ unlinkSync(path);
2758
+ } catch {
2759
+ }
2760
+ throw error;
2761
+ }
2762
+ return this.publicRecord(tracked);
2763
+ }
2764
+ read(name) {
2765
+ this.assertOpen();
2766
+ let path;
2767
+ try {
2768
+ path = safePath(this.dir, name);
2769
+ } catch {
2770
+ return null;
2771
+ }
2772
+ const record = this.records.get(name);
2773
+ if (!record || record.path !== path) return null;
2774
+ const now = this.now();
2775
+ if (record.expiresAt <= now) {
2776
+ this.deleteRecord(name, path, true);
2777
+ return null;
2778
+ }
2779
+ if (!existsSync(path)) {
2780
+ this.records.delete(name);
2781
+ this.persistManifest();
2782
+ return null;
2783
+ }
2784
+ const st = lstatSync(path);
2785
+ if (!st.isFile() || st.isSymbolicLink() || st.size !== record.bytes) {
2786
+ this.deleteRecord(name, path, true);
2787
+ return null;
2788
+ }
2789
+ const bytes = readFileSync(path);
2790
+ if (digest(bytes) !== record.sha256) {
2791
+ this.deleteRecord(name, path, true);
2792
+ return null;
2793
+ }
2794
+ return {
2795
+ path,
2796
+ bytes,
2797
+ mimeType: record.mimeType,
2798
+ expiresAt: record.expiresAt,
2799
+ cacheMaxAgeSeconds: Math.max(0, Math.floor((record.expiresAt - now) / 1e3))
2800
+ };
2801
+ }
2802
+ cleanupExpired() {
2803
+ this.assertOpen();
2804
+ const cutoff = this.now();
2805
+ let changed = false;
2806
+ for (const [name, record] of this.records) {
2807
+ if (record.expiresAt <= cutoff) {
2808
+ this.deleteRecord(name, record.path, false);
2809
+ changed = true;
2810
+ }
2811
+ }
2812
+ if (changed) this.persistManifest();
2813
+ }
2814
+ /** Release exclusive ownership of the artifact directory. Idempotent. */
2815
+ close() {
2816
+ if (this.closed) return;
2817
+ this.closed = true;
2818
+ const fd = this.lockFd;
2819
+ this.lockFd = -1;
2820
+ try {
2821
+ if (fd < 0 || !existsSync(this.lockPath)) return;
2822
+ const held = fstatSync(fd);
2823
+ const current = lstatSync(this.lockPath);
2824
+ if (!current.isFile() || current.isSymbolicLink() || held.dev !== current.dev || held.ino !== current.ino) return;
2825
+ const marker = JSON.parse(readFileSync(this.lockPath, "utf8"));
2826
+ if (marker.token === this.lockToken) unlinkSync(this.lockPath);
2827
+ } catch {
2828
+ } finally {
2829
+ if (fd >= 0) try {
2830
+ closeSync(fd);
2831
+ } catch {
2832
+ }
2833
+ }
2834
+ }
2835
+ assertOpen() {
2836
+ if (this.closed || this.lockFd < 0) throw new Error("artifact store is closed");
2837
+ }
2838
+ acquireOwnership() {
2839
+ let fd = -1;
2840
+ try {
2841
+ fd = openSync(this.lockPath, "wx", 384);
2842
+ const marker = JSON.stringify({ schemaVersion: 1, pid: process.pid, host: hostname(), token: this.lockToken });
2843
+ writeSync(fd, marker);
2844
+ fsyncSync(fd);
2845
+ this.lockFd = fd;
2846
+ } catch (error) {
2847
+ if (fd >= 0) {
2848
+ try {
2849
+ closeSync(fd);
2850
+ } catch {
2851
+ }
2852
+ try {
2853
+ unlinkSync(this.lockPath);
2854
+ } catch {
2855
+ }
2856
+ }
2857
+ const code = error.code;
2858
+ if (code === "EEXIST") {
2859
+ throw new Error(`artifact directory is already owned; remove ${LOCK_NAME} only after confirming no server is using it`);
2860
+ }
2861
+ throw error;
2862
+ }
2863
+ }
2864
+ reconcileManagedFiles() {
2865
+ for (const name of readdirSync(this.dir)) {
2866
+ if (!MANAGED_NAME.test(name) || this.records.has(name)) continue;
2867
+ const path = safePath(this.dir, name);
2868
+ try {
2869
+ const entry = lstatSync(path);
2870
+ if (entry.isFile() || entry.isSymbolicLink()) unlinkSync(path);
2871
+ } catch {
2872
+ }
2873
+ }
2874
+ }
2875
+ publicRecord(record) {
2876
+ const output = {
2877
+ name: record.name,
2878
+ path: record.path,
2879
+ mimeType: record.mimeType,
2880
+ bytes: record.bytes,
2881
+ sha256: record.sha256
2882
+ };
2883
+ if (this.baseUrl) output.url = `${this.baseUrl}/${encodeURIComponent(record.name)}`;
2884
+ return output;
2885
+ }
2886
+ loadManifest() {
2887
+ if (!existsSync(this.manifestPath)) return;
2888
+ const stat = lstatSync(this.manifestPath);
2889
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_MANIFEST_BYTES) {
2890
+ throw new Error("artifact manifest must be a bounded regular file");
2891
+ }
2892
+ let manifest;
2893
+ try {
2894
+ manifest = JSON.parse(readFileSync(this.manifestPath, "utf8"));
2895
+ } catch {
2896
+ throw new Error("artifact manifest is not valid JSON");
2897
+ }
2898
+ if (manifest?.schemaVersion !== 1 || !Array.isArray(manifest.records) || manifest.records.length > this.maxArtifacts) {
2899
+ throw new Error("artifact manifest has an unsupported or oversized shape");
2900
+ }
2901
+ let totalBytes = 0;
2902
+ for (const candidate of manifest.records) {
2903
+ if (!candidate || typeof candidate !== "object" || typeof candidate.name !== "string" || !MANAGED_NAME.test(candidate.name) || typeof candidate.mimeType !== "string" || candidate.mimeType.length === 0 || !Number.isSafeInteger(candidate.bytes) || candidate.bytes < 0 || typeof candidate.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(candidate.sha256) || !Number.isSafeInteger(candidate.createdAt) || !Number.isSafeInteger(candidate.expiresAt) || candidate.expiresAt <= candidate.createdAt) {
2904
+ throw new Error("artifact manifest contains an invalid record");
2905
+ }
2906
+ const path = safePath(this.dir, candidate.name);
2907
+ if (!existsSync(path)) continue;
2908
+ const file = lstatSync(path);
2909
+ if (!file.isFile() || file.isSymbolicLink() || file.size !== candidate.bytes) {
2910
+ throw new Error(`artifact manifest record ${candidate.name} does not match a regular file`);
2911
+ }
2912
+ const bytes = readFileSync(path);
2913
+ if (digest(bytes) !== candidate.sha256) throw new Error(`artifact manifest record ${candidate.name} failed integrity verification`);
2914
+ totalBytes += candidate.bytes;
2915
+ if (totalBytes > this.maxTotalBytes) throw new Error("artifact manifest exceeds maxTotalBytes");
2916
+ this.records.set(candidate.name, { ...candidate, path });
2917
+ }
2918
+ if (this.records.size !== manifest.records.length) this.persistManifest();
2919
+ }
2920
+ persistManifest() {
2921
+ const records = [...this.records.values()].sort((a, b) => a.createdAt - b.createdAt || (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)).map(({ name, mimeType, bytes, sha256, createdAt, expiresAt }) => ({ name, mimeType, bytes, sha256, createdAt, expiresAt }));
2922
+ const body = JSON.stringify({ schemaVersion: 1, records });
2923
+ if (Buffer.byteLength(body) > MAX_MANIFEST_BYTES) throw new Error("artifact manifest exceeds its byte budget");
2924
+ const temp = join(this.dir, `.${MANIFEST_NAME}.${process.pid}.${randomUUID()}.tmp`);
2925
+ try {
2926
+ writeFileSync(temp, body, { mode: 384 });
2927
+ renameSync(temp, this.manifestPath);
2928
+ } finally {
2929
+ try {
2930
+ unlinkSync(temp);
2931
+ } catch {
2932
+ }
2933
+ }
2934
+ }
2935
+ deleteRecord(name, path, persist) {
2936
+ this.records.delete(name);
2937
+ try {
2938
+ unlinkSync(path);
2939
+ } catch {
2940
+ }
2941
+ if (persist) this.persistManifest();
2942
+ }
2943
+ };
2944
+ function createArtifactStore(opts = {}) {
2945
+ return new ArtifactStore(opts);
2946
+ }
2947
+ function digest(bytes) {
2948
+ return createHash("sha256").update(bytes).digest("hex");
2949
+ }
2950
+ function normalizeBaseUrl(url) {
2951
+ if (!url) return void 0;
2952
+ return url.replace(/\/+$/, "");
2953
+ }
2954
+ function sanitizeExtension(extension) {
2955
+ const ext = extension.startsWith(".") ? extension : `.${extension}`;
2956
+ const safe = ext.toLowerCase().replace(/[^.a-z0-9_-]/g, "");
2957
+ return safe && safe !== "." ? safe : ".bin";
2958
+ }
2959
+ function safePath(root, name) {
2960
+ const leaf = basename(name);
2961
+ if (!leaf || leaf !== name || leaf.includes("..")) throw new Error("invalid artifact name");
2962
+ const path = resolve(root, leaf);
2963
+ const prefix = root.endsWith(sep) ? root : `${root}${sep}`;
2964
+ if (!path.startsWith(prefix)) throw new Error("artifact path escaped root");
2965
+ return path;
2966
+ }
2967
+
2968
+ // src/mcp/server.ts
2969
+ var PROTOCOL_VERSION = "2024-11-05";
2970
+ var MAX_RPC_BODY_BYTES = 1024 * 1024;
2971
+ var MAX_SANDBOX_TIMEOUT_MS = 3e4;
2972
+ var MAX_SSE_SESSIONS = 32;
2973
+ var HttpStatusError = class extends Error {
2974
+ constructor(status, message) {
2975
+ super(message);
2976
+ this.status = status;
2977
+ }
2978
+ status;
2979
+ };
2980
+ var LOCAL_TOOLS = [
2981
+ createExecuteTool({ sdkDeclaration: SDK_CORE_DECLARATION }),
2982
+ withClosedMcpInputSchema(createDescribeSdkTool()),
2983
+ createRenderPngTool("local"),
2984
+ createDescribeTool()
2985
+ ];
2986
+ var defaultArtifactStore;
2987
+ var defaultArtifactStoreExitHook = false;
2988
+ var MCP_NARROWERS = BUILTIN_FAMILY_METADATA.map((f) => f.narrower).join("/");
2989
+ var LOCAL_INSTRUCTIONS = `agentic-mermaid Code Mode server. Primary tool execute runs synchronous JavaScript against the typed mermaid.* SDK in a sandbox; async/await and Promise jobs are not supported. describe_sdk progressively discloses one family's version-matched mutation schema; call it before authoring unfamiliar ops. render_png and describe are narrow helpers. render_png can return base64, managed file paths, or managed URLs when the transport config provides an artifact store. There is no mutate tool on this server: structured edits go through the SDK's mermaid.mutate(...) inside execute; narrow via ${MCP_NARROWERS}. Every built-in renderable family ships a typed path when the body narrows; only opaque fallback bodies are source-level only. Layout is deterministic; there is no layout seed (the optional style seed only re-rolls ink of styled looks, never geometry).`;
2990
+ var LOCAL_SURFACE = {
2991
+ protocolVersion: PROTOCOL_VERSION,
2992
+ tools: LOCAL_TOOLS,
2993
+ instructions: LOCAL_INSTRUCTIONS,
2994
+ handleToolCall
2995
+ };
2996
+ async function handleRequest(req, context = {}) {
2997
+ return dispatchMcpRequest(req, context, LOCAL_SURFACE);
2998
+ }
2999
+ async function handleToolCall(id, params, context) {
3000
+ const p = params;
3001
+ const name = p?.name;
3002
+ const args = p?.arguments ?? {};
3003
+ if (name === "describe_sdk") {
3004
+ try {
3005
+ const payload = describeSdkPayload(args);
3006
+ return reply(id, { content: [{ type: "text", text: JSON.stringify(payload) }], isError: false });
3007
+ } catch (e) {
3008
+ return rpcError(id, -32602, e instanceof Error ? e.message : String(e));
3009
+ }
3010
+ }
3011
+ if (name === "execute") {
3012
+ const code = args.code;
3013
+ const requestedTimeoutMs = args.timeoutMs;
3014
+ if (requestedTimeoutMs !== void 0 && !isValidExecuteTimeout(requestedTimeoutMs)) {
3015
+ return rpcError(id, -32602, EXECUTE_TIMEOUT_ERROR);
3016
+ }
3017
+ const timeoutMs = Math.min(
3018
+ requestedTimeoutMs ?? DEFAULT_EXECUTE_TIMEOUT_MS,
3019
+ context.maxSandboxTimeoutMs ?? MAX_SANDBOX_TIMEOUT_MS
3020
+ );
3021
+ if (typeof code !== "string") return rpcError(id, -32602, "execute requires `code` (string)");
3022
+ const r = await executeInSandbox(code, { timeoutMs });
3023
+ return reply(id, { content: [{ type: "text", text: JSON.stringify(r) }], isError: !r.ok });
3024
+ }
3025
+ if (name === "render_png") return handleRenderPng(id, args, context);
3026
+ if (name === "describe") {
3027
+ const source = args.source;
3028
+ if (typeof source !== "string") return rpcError(id, -32602, "describe requires `source` (string)");
3029
+ try {
3030
+ const payload = mcpDescribePayload(source, args);
3031
+ return reply(id, { content: [{ type: "text", text: JSON.stringify(payload) }], isError: !payload.ok });
3032
+ } catch (e) {
3033
+ const msg = e instanceof Error ? e.message : String(e);
3034
+ const payload = { ok: false, error: { code: "DESCRIBE_FAILED", message: msg } };
3035
+ return reply(id, { content: [{ type: "text", text: JSON.stringify(payload) }], isError: true });
3036
+ }
3037
+ }
3038
+ return rpcError(id, -32602, `Unknown tool: ${name ?? "<none>"}`);
3039
+ }
3040
+ function handleRenderPng(id, args, context) {
3041
+ const source = args.source;
3042
+ const output = args.output ?? "base64";
3043
+ if (typeof source !== "string") return rpcError(id, -32602, "render_png requires `source` (string)");
3044
+ if (!["base64", "file", "url"].includes(output)) return rpcError(id, -32602, "render_png output must be one of: base64, file, url");
3045
+ try {
3046
+ const fontWarnings = [];
3047
+ const pngOutput = projectNativePngOutputPolicyInput(args);
3048
+ const rendered = renderMermaidPNGWithReceipt(source, {
3049
+ ...projectMcpRenderOptions(args),
3050
+ ...pngOutput,
3051
+ onWarning: (warning) => fontWarnings.push(warning)
3052
+ });
3053
+ const warnings = [...configWarningsForMermaid(source), ...fontWarnings].filter((warning, index, all) => all.findIndex((candidate) => JSON.stringify(candidate) === JSON.stringify(warning)) === index);
3054
+ if (output === "base64") {
3055
+ const png_base64 = Buffer.from(rendered.png).toString("base64");
3056
+ const payload2 = { ok: true, png_base64, receipt: rendered.receipt, runtime: rendered.runtime, warnings };
3057
+ return reply(id, { content: [{ type: "text", text: JSON.stringify(payload2) }], isError: false });
3058
+ }
3059
+ const store = context.artifactStore ?? getDefaultArtifactStore();
3060
+ if (output === "url" && !store.hasBaseUrl()) return rpcError(id, -32602, "render_png output=url requires an HTTP/SSE artifact base URL");
3061
+ const artifact = store.write(rendered.png, { extension: ".png", mimeType: "image/png" });
3062
+ const payload = { ok: true, artifact: artifactPayload(artifact, output), receipt: rendered.receipt, runtime: rendered.runtime, warnings };
3063
+ return reply(id, { content: [{ type: "text", text: JSON.stringify(payload) }], isError: false });
3064
+ } catch (e) {
3065
+ const payload = {
3066
+ ok: false,
3067
+ error: projectRenderErrorDiagnostic(e)
3068
+ };
3069
+ return reply(id, { content: [{ type: "text", text: JSON.stringify(payload) }], isError: true });
3070
+ }
3071
+ }
3072
+ function artifactPayload(artifact, output) {
3073
+ const base = { mimeType: artifact.mimeType, bytes: artifact.bytes, sha256: artifact.sha256 };
3074
+ if (output === "url") return { ...base, url: artifact.url };
3075
+ return { ...base, path: artifact.path };
3076
+ }
3077
+ function getDefaultArtifactStore() {
3078
+ defaultArtifactStore ??= createArtifactStore({ dir: join2(tmpdir2(), "agentic-mermaid-mcp-artifacts") });
3079
+ if (!defaultArtifactStoreExitHook) {
3080
+ defaultArtifactStoreExitHook = true;
3081
+ process.once("exit", () => defaultArtifactStore?.close());
3082
+ }
3083
+ return defaultArtifactStore;
3084
+ }
3085
+ function warmUpPngRenderer() {
3086
+ try {
3087
+ renderMermaidPNG("flowchart LR\n A --> B");
3088
+ } catch {
3089
+ }
3090
+ }
3091
+ async function runStdio(options = {}) {
3092
+ warmUpPngRenderer();
3093
+ const artifactStore = createArtifactStore({
3094
+ dir: options.artifactDir,
3095
+ maxBytes: options.maxArtifactBytes,
3096
+ maxTotalBytes: options.maxArtifactTotalBytes,
3097
+ maxArtifacts: options.maxArtifacts,
3098
+ ttlMs: options.artifactTtlMs
3099
+ });
3100
+ process.stdin.setEncoding("utf8");
3101
+ let buf = "";
3102
+ process.stdin.on("data", async (chunk) => {
3103
+ buf += chunk;
3104
+ let nl;
3105
+ while ((nl = buf.indexOf("\n")) >= 0) {
3106
+ const line = buf.slice(0, nl).trim();
3107
+ buf = buf.slice(nl + 1);
3108
+ if (!line) continue;
3109
+ try {
3110
+ const exact = preserveExactJsonRpcIds(line);
3111
+ const res = await handleRequest(JSON.parse(exact.body), { artifactStore, maxSandboxTimeoutMs: options.maxSandboxTimeoutMs });
3112
+ if (res) process.stdout.write(stringifyJsonRpc(res, exact.ids) + "\n");
3113
+ } catch (e) {
3114
+ process.stdout.write(JSON.stringify(rpcError(null, -32700, `parse error: ${e.message}`)) + "\n");
3115
+ }
3116
+ }
3117
+ });
3118
+ try {
3119
+ await new Promise((resolve2) => {
3120
+ process.stdin.on("end", () => resolve2());
3121
+ process.stdin.on("close", () => resolve2());
3122
+ });
3123
+ } finally {
3124
+ artifactStore.close();
3125
+ }
3126
+ }
3127
+ async function startHttpServer(options = {}) {
3128
+ warmUpPngRenderer();
3129
+ const host = options.host ?? "127.0.0.1";
3130
+ const port = options.port ?? 3e3;
3131
+ if (!isLoopbackHost(host) && !options.authToken) throw new Error("HTTP MCP remote bind requires --auth-token");
3132
+ const sessions = /* @__PURE__ */ new Map();
3133
+ let baseUrl = "";
3134
+ const maxRpcBodyBytes = options.maxRpcBodyBytes ?? MAX_RPC_BODY_BYTES;
3135
+ const maxSseSessions = options.maxSseSessions ?? MAX_SSE_SESSIONS;
3136
+ const publicOrigin = httpOrigin(options.publicUrl, "publicUrl");
3137
+ if (!Number.isInteger(maxSseSessions) || maxSseSessions <= 0) throw new Error("maxSseSessions must be a positive integer");
3138
+ const artifactStore = createArtifactStore({
3139
+ dir: options.artifactDir,
3140
+ maxBytes: options.maxArtifactBytes,
3141
+ maxTotalBytes: options.maxArtifactTotalBytes,
3142
+ maxArtifacts: options.maxArtifacts,
3143
+ ttlMs: options.artifactTtlMs
3144
+ });
3145
+ const context = { artifactStore, maxSandboxTimeoutMs: options.maxSandboxTimeoutMs };
3146
+ const server = createServer(async (req, res) => {
3147
+ try {
3148
+ const u = new URL(req.url ?? "/", baseUrl || `http://${host}:${port || 0}`);
3149
+ if (req.method === "GET" && u.pathname === "/health") return sendJson(res, 200, { ok: true });
3150
+ if (req.method === "GET" && u.pathname === "/sse") {
3151
+ if (!authorizeHttpAccess(req, res, baseUrl, publicOrigin, options.authToken)) return;
3152
+ return openSse(req, res, sessions, publicOrigin ?? baseUrl, maxSseSessions);
3153
+ }
3154
+ if (req.method === "POST" && u.pathname === "/message") {
3155
+ if (!authorizeHttpRpc(req, res, baseUrl, publicOrigin, options.authToken)) return;
3156
+ return await postSseMessage(req, res, sessions, context, maxRpcBodyBytes);
3157
+ }
3158
+ if (req.method === "POST" && u.pathname === "/rpc") {
3159
+ if (!authorizeHttpRpc(req, res, baseUrl, publicOrigin, options.authToken)) return;
3160
+ return await postRpc(req, res, context, maxRpcBodyBytes);
3161
+ }
3162
+ if (req.method === "GET" && u.pathname.startsWith("/artifacts/")) {
3163
+ if (!authorizeHttpAccess(req, res, baseUrl, publicOrigin, options.authToken)) return;
3164
+ return serveArtifact(res, artifactStore, decodeURIComponent(u.pathname.slice("/artifacts/".length)));
3165
+ }
3166
+ return sendJson(res, 404, { ok: false, error: "not found" });
3167
+ } catch (e) {
3168
+ if (e instanceof HttpStatusError) return sendJson(res, e.status, { ok: false, error: e.message });
3169
+ return sendJson(res, 500, { ok: false, error: e instanceof Error ? e.message : String(e) });
3170
+ }
3171
+ });
3172
+ try {
3173
+ await new Promise((resolve2, reject) => {
3174
+ server.once("error", reject);
3175
+ server.listen(port, host, () => {
3176
+ server.off("error", reject);
3177
+ resolve2();
3178
+ });
3179
+ });
3180
+ const address = server.address();
3181
+ if (!address || typeof address === "string") throw new Error("HTTP MCP server did not expose a TCP address");
3182
+ baseUrl = `http://${host}:${address.port}`;
3183
+ artifactStore.setBaseUrl(options.publicUrl ?? `${baseUrl}/artifacts`);
3184
+ } catch (error) {
3185
+ artifactStore.close();
3186
+ try {
3187
+ server.close();
3188
+ } catch {
3189
+ }
3190
+ throw error;
3191
+ }
3192
+ return {
3193
+ server,
3194
+ url: baseUrl,
3195
+ artifactStore,
3196
+ close: () => new Promise((resolve2, reject) => {
3197
+ for (const sse of sessions.values()) sse.end();
3198
+ sessions.clear();
3199
+ server.close((err) => {
3200
+ artifactStore.close();
3201
+ if (err) reject(err);
3202
+ else resolve2();
3203
+ });
3204
+ })
3205
+ };
3206
+ }
3207
+ async function runHttp(options = {}) {
3208
+ const started = await startHttpServer(options);
3209
+ process.stderr.write(`agentic-mermaid-mcp HTTP/SSE listening at ${started.url} (SSE: ${started.url}/sse, plain JSON-RPC: ${started.url}/rpc)
3210
+ `);
3211
+ return new Promise((resolve2) => {
3212
+ const shutdown = () => {
3213
+ started.close().finally(resolve2);
3214
+ };
3215
+ process.once("SIGINT", shutdown);
3216
+ process.once("SIGTERM", shutdown);
3217
+ });
3218
+ }
3219
+ function isLoopbackHost(host) {
3220
+ return host === "127.0.0.1" || host === "localhost" || host === "::1";
3221
+ }
3222
+ function httpOrigin(value, label) {
3223
+ if (!value) return void 0;
3224
+ let parsed;
3225
+ try {
3226
+ parsed = new URL(value);
3227
+ } catch {
3228
+ throw new Error(`${label} must be an absolute http(s) URL`);
3229
+ }
3230
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
3231
+ throw new Error(`${label} must be an absolute http(s) URL`);
3232
+ }
3233
+ return parsed.origin;
3234
+ }
3235
+ function authorizeHttpAccess(req, res, baseUrl, publicOrigin, authToken) {
3236
+ const origin = req.headers.origin;
3237
+ if (origin && origin !== baseUrl && origin !== publicOrigin) {
3238
+ sendJson(res, 403, { ok: false, error: "origin not allowed" });
3239
+ return false;
3240
+ }
3241
+ if (authToken && req.headers.authorization !== `Bearer ${authToken}`) {
3242
+ sendJson(res, 401, { ok: false, error: "missing or invalid bearer token" });
3243
+ return false;
3244
+ }
3245
+ return true;
3246
+ }
3247
+ function authorizeHttpRpc(req, res, baseUrl, publicOrigin, authToken) {
3248
+ if (!authorizeHttpAccess(req, res, baseUrl, publicOrigin, authToken)) return false;
3249
+ if (!isJsonContentType(String(req.headers["content-type"] ?? ""))) {
3250
+ sendJson(res, 415, { ok: false, error: "HTTP MCP JSON-RPC requires content-type application/json" });
3251
+ return false;
3252
+ }
3253
+ return true;
3254
+ }
3255
+ function openSse(req, res, sessions, baseUrl, maxSessions) {
3256
+ if (sessions.size >= maxSessions) {
3257
+ sendJson(res, 503, { ok: false, error: `SSE session limit reached (${maxSessions})` });
3258
+ return;
3259
+ }
3260
+ const sessionId = randomUUID2();
3261
+ sessions.set(sessionId, res);
3262
+ res.writeHead(200, {
3263
+ "Content-Type": "text/event-stream; charset=utf-8",
3264
+ "Cache-Control": "no-cache, no-transform",
3265
+ Connection: "keep-alive",
3266
+ "X-Accel-Buffering": "no"
3267
+ });
3268
+ res.write(`event: endpoint
3269
+ data: ${baseUrl}/message?sessionId=${encodeURIComponent(sessionId)}
3270
+
3271
+ `);
3272
+ const heartbeat = setInterval(() => res.write(": keepalive\n\n"), 25e3);
3273
+ req.on("close", () => {
3274
+ clearInterval(heartbeat);
3275
+ sessions.delete(sessionId);
3276
+ });
3277
+ }
3278
+ async function postSseMessage(req, res, sessions, context, maxBytes) {
3279
+ const u = new URL(req.url ?? "/", "http://localhost");
3280
+ const sessionId = u.searchParams.get("sessionId") ?? "";
3281
+ const sse = sessions.get(sessionId);
3282
+ if (!sse) return sendJson(res, 404, { ok: false, error: "unknown sessionId" });
3283
+ const body = await readRequestBody(req, maxBytes);
3284
+ const exact = preserveExactJsonRpcIds(body);
3285
+ let parsed;
3286
+ try {
3287
+ parsed = JSON.parse(exact.body);
3288
+ } catch {
3289
+ throw new HttpStatusError(400, "invalid JSON-RPC body");
3290
+ }
3291
+ const response = await handleRequest(parsed, context);
3292
+ if (response) {
3293
+ sse.write(`event: message
3294
+ data: ${stringifyJsonRpc(response, exact.ids)}
3295
+
3296
+ `);
3297
+ return sendJson(res, 202, { ok: true });
3298
+ }
3299
+ res.writeHead(202);
3300
+ res.end();
3301
+ }
3302
+ async function postRpc(req, res, context, maxBytes) {
3303
+ const body = await readRequestBody(req, maxBytes);
3304
+ const exact = preserveExactJsonRpcIds(body);
3305
+ let parsed;
3306
+ try {
3307
+ parsed = JSON.parse(exact.body);
3308
+ } catch {
3309
+ throw new HttpStatusError(400, "invalid JSON-RPC body");
3310
+ }
3311
+ const response = await handleRequest(parsed, context);
3312
+ if (response === null) {
3313
+ res.writeHead(202);
3314
+ res.end();
3315
+ return;
3316
+ }
3317
+ sendJson(res, 200, response, exact.ids);
3318
+ }
3319
+ function serveArtifact(res, store, name) {
3320
+ const artifact = store.read(name);
3321
+ if (!artifact) return sendJson(res, 404, { ok: false, error: "artifact not found" });
3322
+ res.writeHead(200, {
3323
+ "Content-Type": artifact.mimeType,
3324
+ "Content-Length": artifact.bytes.length,
3325
+ "Cache-Control": `private, max-age=${artifact.cacheMaxAgeSeconds}, immutable`
3326
+ });
3327
+ res.end(artifact.bytes);
3328
+ }
3329
+ function sendJson(res, status, payload, exactIds = []) {
3330
+ const body = stringifyJsonRpc(payload, exactIds);
3331
+ res.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Content-Length": Buffer.byteLength(body) });
3332
+ res.end(body);
3333
+ }
3334
+ async function readRequestBody(req, maxBytes = MAX_RPC_BODY_BYTES) {
3335
+ const declared = Number(req.headers["content-length"] ?? 0);
3336
+ if (Number.isFinite(declared) && declared > maxBytes) throw new HttpStatusError(413, `request body exceeds ${maxBytes} bytes`);
3337
+ const chunks = [];
3338
+ let bytes = 0;
3339
+ for await (const chunk of req) {
3340
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
3341
+ bytes += buffer.byteLength;
3342
+ if (bytes > maxBytes) throw new HttpStatusError(413, `request body exceeds ${maxBytes} bytes`);
3343
+ chunks.push(buffer);
3344
+ }
3345
+ return Buffer.concat(chunks).toString("utf8");
3346
+ }
3347
+
3348
+ // src/mcp/mcp-cli.ts
3349
+ var MCP_CLI_HELP = `agentic-mermaid-mcp [--transport stdio|http] [--host 127.0.0.1] [--port 3000]
3350
+
3351
+ Options:
3352
+ --transport stdio|http Transport to run (default stdio).
3353
+ --host <host> HTTP/SSE bind host (default 127.0.0.1).
3354
+ --port <port> HTTP/SSE bind port (default 3000, 0 = ephemeral).
3355
+ --artifact-dir <dir> Managed artifact directory for file/url outputs.
3356
+ --public-url <url> Public artifact prefix; its origin is allowed by HTTP/SSE.
3357
+ --max-artifact-bytes <n> Maximum bytes in one artifact (default 20MiB).
3358
+ --max-artifact-total-bytes <n> Aggregate managed artifact bytes (default 200MiB).
3359
+ --max-artifacts <n> Maximum managed artifact count (default 1000).
3360
+ --artifact-ttl-ms <n> Artifact cleanup TTL (default 1h).
3361
+ --max-rpc-body-bytes <n> Max HTTP JSON-RPC body size (default 1MiB).
3362
+ --auth-token <token> Bearer token required for every non-health HTTP route.
3363
+ --max-sandbox-timeout-ms <n> Max execute timeout (default 30000).
3364
+ --help Show this help.
3365
+ `;
3366
+ var MCP_FLAG_SPECS = Object.freeze({
3367
+ help: { kind: "boolean", applicability: "both" },
3368
+ transport: { kind: "string", applicability: "both" },
3369
+ host: { kind: "string", applicability: "http" },
3370
+ port: { kind: "integer", applicability: "http", min: 0, max: 65535 },
3371
+ "artifact-dir": { kind: "string", applicability: "both" },
3372
+ "public-url": { kind: "string", applicability: "http" },
3373
+ "max-artifact-bytes": { kind: "integer", applicability: "both", min: 1 },
3374
+ "max-artifact-total-bytes": { kind: "integer", applicability: "both", min: 1 },
3375
+ "max-artifacts": { kind: "integer", applicability: "both", min: 1 },
3376
+ "artifact-ttl-ms": { kind: "integer", applicability: "both", min: 1 },
3377
+ "max-rpc-body-bytes": { kind: "integer", applicability: "http", min: 1 },
3378
+ "auth-token": { kind: "string", applicability: "http" },
3379
+ "max-sandbox-timeout-ms": { kind: "integer", applicability: "both", min: 1 }
3380
+ });
3381
+ function parseMcpFlags(argv) {
3382
+ const flags = {};
3383
+ for (let index = 0; index < argv.length; index++) {
3384
+ let token = argv[index];
3385
+ if (token === "-h") token = "--help";
3386
+ if (!token.startsWith("--")) throw new Error(`unexpected positional argument: ${token}`);
3387
+ const equals = token.indexOf("=");
3388
+ const name = token.slice(2, equals < 0 ? void 0 : equals);
3389
+ const spec = MCP_FLAG_SPECS[name];
3390
+ if (!spec) throw new Error(`unknown option: --${name}`);
3391
+ if (Object.hasOwn(flags, name)) throw new Error(`duplicate flag: --${name}`);
3392
+ const inline = equals < 0 ? void 0 : token.slice(equals + 1);
3393
+ if (spec.kind === "boolean") {
3394
+ if (inline !== void 0) throw new Error(`--${name} does not accept a value`);
3395
+ flags[name] = true;
3396
+ continue;
3397
+ }
3398
+ const value = inline ?? argv[++index];
3399
+ if (value === void 0 || value.length === 0 || value.startsWith("-")) {
3400
+ throw new Error(`--${name} requires a value`);
3401
+ }
3402
+ flags[name] = value;
3403
+ }
3404
+ return Object.freeze(flags);
3405
+ }
3406
+ function stringFlag(flags, name) {
3407
+ const value = flags[name];
3408
+ return typeof value === "string" ? value : void 0;
3409
+ }
3410
+ function integerFlag(flags, name) {
3411
+ const raw = stringFlag(flags, name);
3412
+ if (raw === void 0) return void 0;
3413
+ const candidate = MCP_FLAG_SPECS[name];
3414
+ if (candidate.kind !== "integer") throw new Error(`internal MCP flag authority mismatch for --${name}`);
3415
+ const spec = candidate;
3416
+ const value = Number(raw);
3417
+ if (!Number.isSafeInteger(value) || value < spec.min || spec.max !== void 0 && value > spec.max) {
3418
+ throw new Error(`--${name} must be an integer${spec.max === void 0 ? ` >= ${spec.min}` : ` between ${spec.min} and ${spec.max}`}`);
3419
+ }
3420
+ return value;
3421
+ }
3422
+ function parseMcpCliOptions(argv) {
3423
+ const flags = parseMcpFlags(argv);
3424
+ const explicitTransport = stringFlag(flags, "transport");
3425
+ if (explicitTransport !== void 0 && explicitTransport !== "stdio" && explicitTransport !== "http") {
3426
+ throw new Error(`unknown transport: ${explicitTransport}`);
3427
+ }
3428
+ const transport = explicitTransport === "http" ? "http" : "stdio";
3429
+ if (transport === "stdio") {
3430
+ const invalid = Object.keys(flags).filter((name) => MCP_FLAG_SPECS[name]?.applicability === "http");
3431
+ if (invalid.length > 0) throw new Error(`${invalid.map((name) => `--${name}`).join(", ")} ${invalid.length === 1 ? "is" : "are"} valid only with HTTP transport`);
3432
+ }
3433
+ return {
3434
+ transport,
3435
+ httpOptions: {
3436
+ host: stringFlag(flags, "host"),
3437
+ port: integerFlag(flags, "port"),
3438
+ artifactDir: stringFlag(flags, "artifact-dir"),
3439
+ publicUrl: stringFlag(flags, "public-url"),
3440
+ maxArtifactBytes: integerFlag(flags, "max-artifact-bytes"),
3441
+ maxArtifactTotalBytes: integerFlag(flags, "max-artifact-total-bytes"),
3442
+ maxArtifacts: integerFlag(flags, "max-artifacts"),
3443
+ artifactTtlMs: integerFlag(flags, "artifact-ttl-ms"),
3444
+ maxRpcBodyBytes: integerFlag(flags, "max-rpc-body-bytes"),
3445
+ authToken: stringFlag(flags, "auth-token"),
3446
+ maxSandboxTimeoutMs: integerFlag(flags, "max-sandbox-timeout-ms")
3447
+ }
3448
+ };
3449
+ }
3450
+ async function runMcpCli(argv = process.argv.slice(2), io = {}) {
3451
+ const stdout = io.stdout ?? process.stdout;
3452
+ const stderr = io.stderr ?? process.stderr;
3453
+ try {
3454
+ if (argv.includes("--help") || argv.includes("-h")) {
3455
+ stdout.write(MCP_CLI_HELP);
3456
+ return 0;
3457
+ }
3458
+ const { transport, httpOptions } = parseMcpCliOptions(argv);
3459
+ if (transport === "http") {
3460
+ await runHttp(httpOptions);
3461
+ return 0;
3462
+ }
3463
+ await runStdio({
3464
+ artifactDir: httpOptions.artifactDir,
3465
+ maxArtifactBytes: httpOptions.maxArtifactBytes,
3466
+ maxArtifactTotalBytes: httpOptions.maxArtifactTotalBytes,
3467
+ maxArtifacts: httpOptions.maxArtifacts,
3468
+ artifactTtlMs: httpOptions.artifactTtlMs,
3469
+ maxSandboxTimeoutMs: httpOptions.maxSandboxTimeoutMs
3470
+ });
3471
+ return 0;
3472
+ } catch (err) {
3473
+ stderr.write(`agentic-mermaid-mcp: ${err instanceof Error ? err.message : String(err)}
3474
+ `);
3475
+ return 1;
3476
+ }
3477
+ }
3478
+
3479
+ export {
3480
+ MCP_CLI_HELP,
3481
+ MCP_FLAG_SPECS,
3482
+ parseMcpCliOptions,
3483
+ runMcpCli
3484
+ };
3485
+ //# sourceMappingURL=chunk-2P5FKUQC.js.map