agentic-mermaid 0.1.0 → 0.1.2

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