agentic-mermaid 0.4.1 → 0.5.3

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