agentic-mermaid 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. package/CHANGELOG.md +144 -4
  2. package/LICENSES/Apache-2.0.txt +202 -0
  3. package/README.md +25 -32
  4. package/THIRD_PARTY_NOTICES.md +29 -0
  5. package/dist/agent-core.d.ts +463 -0
  6. package/dist/agent-core.js +397 -0
  7. package/dist/agent.d.ts +73 -1868
  8. package/dist/agent.js +336 -37325
  9. package/dist/agentic-mermaid-mcp.js +7 -38399
  10. package/dist/am.js +33632 -40445
  11. package/dist/chunk-4QECACIA.js +4702 -0
  12. package/dist/chunk-CDPKJ2BQ.js +37 -0
  13. package/dist/chunk-QKDLMOJJ.js +3487 -0
  14. package/dist/chunk-WI35L7IR.js +615 -0
  15. package/dist/chunk-WN3YDOBG.js +149 -0
  16. package/dist/chunk-ZYMMKQ3I.js +62637 -0
  17. package/dist/index-D54dqSdC.d.ts +6777 -0
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +310 -33014
  20. package/dist/mcp-cli-SBQSTJFC.js +17 -0
  21. package/docs/README.md +14 -6
  22. package/docs/schemas/style-spec.schema.json +1221 -30
  23. package/examples/styles/catalog.json +54 -0
  24. package/examples/styles/cloudflare-workers-inspired-prototype.mmd +9 -0
  25. package/examples/styles/cloudflare-workers-inspired-prototype.style.json +110 -0
  26. package/examples/styles/cupertino-prototype.mmd +10 -0
  27. package/examples/styles/cupertino-prototype.style.json +63 -0
  28. package/examples/styles/mid-century-report.style.json +2 -2
  29. package/examples/styles/star-chart-atlas.style.json +2 -1
  30. package/examples/styles/transit-route-map.style.json +2 -2
  31. package/examples/styles/vercel-inspired-prototype.mmd +6 -0
  32. package/examples/styles/vercel-inspired-prototype.style.json +87 -0
  33. package/package.json +68 -43
  34. package/server.json +2 -2
  35. package/skills/agentic-mermaid-diagram-workflow/SKILL.md +17 -36
  36. package/skills/agentic-mermaid-diagram-workflow/references/cli.md +4 -5
  37. package/skills/agentic-mermaid-diagram-workflow/references/code-mode.md +15 -31
  38. package/skills/agentic-mermaid-diagram-workflow/references/sequence.md +10 -14
  39. package/skills/agentic-mermaid-live-editor/SKILL.md +100 -206
  40. package/AGENT_NATIVE.md +0 -607
  41. package/Instructions_for_agents.md +0 -89
  42. package/TODO.md +0 -684
  43. package/assets/hero.png +0 -0
  44. package/dist/index-wjRjbsP-.d.ts +0 -1102
  45. package/docs/agent-api-cookbook.md +0 -308
  46. package/docs/agent-mutation-policy.md +0 -104
  47. package/docs/agent-workflow-examples.md +0 -46
  48. package/docs/api.md +0 -211
  49. package/docs/ascii.md +0 -103
  50. package/docs/assets/improvements/box-start-connector.png +0 -0
  51. package/docs/assets/improvements/comment-dropped-lint.png +0 -0
  52. package/docs/assets/improvements/er-content-loss.png +0 -0
  53. package/docs/assets/improvements/fan-in-trunks.png +0 -0
  54. package/docs/assets/improvements/gantt-family.png +0 -0
  55. package/docs/assets/improvements/gantt-milestone-clamp.png +0 -0
  56. package/docs/assets/improvements/gantt-verify-seam.png +0 -0
  57. package/docs/assets/improvements/subgraph-container-edges.png +0 -0
  58. package/docs/assets/improvements/wrapper-frontmatter.png +0 -0
  59. package/docs/assets/improvements/wrapper-init-directive.png +0 -0
  60. package/docs/assets/improvements/wrapper-leading-comment.png +0 -0
  61. package/docs/assets/style-cookbook/mid-century-report.png +0 -0
  62. package/docs/assets/style-cookbook/star-chart-atlas.png +0 -0
  63. package/docs/assets/style-cookbook/transit-route-map.png +0 -0
  64. package/docs/comparison.md +0 -94
  65. package/docs/config.md +0 -105
  66. package/docs/contributing/adding-diagram-types.md +0 -144
  67. package/docs/contributing/diagram-family-citizenship.matrix.json +0 -2127
  68. package/docs/contributing/diagram-family-citizenship.md +0 -82
  69. package/docs/contributing/harvesting-upstream-tests.md +0 -126
  70. package/docs/contributing/lessons-learned.md +0 -276
  71. package/docs/contributing/releasing.md +0 -82
  72. package/docs/contributing/visual-review-evidence.md +0 -53
  73. package/docs/custom-style-cookbook.md +0 -154
  74. package/docs/design/families/README.md +0 -26
  75. package/docs/design/families/architecture-beta.md +0 -48
  76. package/docs/design/families/flowchart-parser-conformance.md +0 -22
  77. package/docs/design/families/gantt-research.md +0 -137
  78. package/docs/design/families/gantt.md +0 -329
  79. package/docs/design/families/journey-agentic-cards-before.png +0 -0
  80. package/docs/design/families/journey-experience-curve-implementation.png +0 -0
  81. package/docs/design/families/journey-mermaid-classic-implementation.png +0 -0
  82. package/docs/design/families/journey-mermaid-classic-prototype.png +0 -0
  83. package/docs/design/families/journey-mermaid-classic-prototype.svg +0 -163
  84. package/docs/design/families/journey-mermaid-classic-prototype.svg.png +0 -0
  85. package/docs/design/families/journey-migration-parity.md +0 -439
  86. package/docs/design/families/journey-section-overlap-after.png +0 -0
  87. package/docs/design/families/journey-section-overlap-before.png +0 -0
  88. package/docs/design/families/journey-usage-research.md +0 -423
  89. package/docs/design/families/journey.md +0 -153
  90. package/docs/design/families/xychart.md +0 -85
  91. package/docs/design/system/README.md +0 -45
  92. package/docs/design/system/abstraction-audit.md +0 -224
  93. package/docs/design/system/abstraction-recommendations.md +0 -655
  94. package/docs/design/system/architecture.mmd +0 -29
  95. package/docs/design/system/architecture.svg +0 -137
  96. package/docs/design/system/layout-guarantees-and-robustness.md +0 -351
  97. package/docs/design/system/layout-rubric.md +0 -138
  98. package/docs/design/system/route-contracts.md +0 -848
  99. package/docs/design/system/source-preservation-ladder.md +0 -52
  100. package/docs/design/system/styles-rollout.md +0 -216
  101. package/docs/design/system/ugly-layouts.md +0 -119
  102. package/docs/diagram-families.md +0 -193
  103. package/docs/features.md +0 -147
  104. package/docs/fork-differences.md +0 -130
  105. package/docs/getting-started.md +0 -175
  106. package/docs/issue-derived-test-cases.md +0 -156
  107. package/docs/layout-characterization/README.md +0 -245
  108. package/docs/layout-characterization/contact-sheet-families.md +0 -498
  109. package/docs/layout-characterization/contact-sheet.md +0 -638
  110. package/docs/layout-characterization/properties.md +0 -281
  111. package/docs/layout-characterization/visual-quality.md +0 -160
  112. package/docs/layout-characterization/visual-snapshots/architecture.svg +0 -79
  113. package/docs/layout-characterization/visual-snapshots/class.svg +0 -60
  114. package/docs/layout-characterization/visual-snapshots/er.svg +0 -61
  115. package/docs/layout-characterization/visual-snapshots/flowchart.svg +0 -58
  116. package/docs/layout-characterization/visual-snapshots/gantt.svg +0 -52
  117. package/docs/layout-characterization/visual-snapshots/journey.svg +0 -98
  118. package/docs/layout-characterization/visual-snapshots/pie.svg +0 -36
  119. package/docs/layout-characterization/visual-snapshots/quadrant.svg +0 -47
  120. package/docs/layout-characterization/visual-snapshots/sequence.svg +0 -59
  121. package/docs/layout-characterization/visual-snapshots/state.svg +0 -52
  122. package/docs/layout-characterization/visual-snapshots/timeline.svg +0 -64
  123. package/docs/layout-characterization/visual-snapshots/xychart.svg +0 -97
  124. package/docs/mcp-code-mode-rationale.md +0 -101
  125. package/docs/mcp-http-transport.md +0 -223
  126. package/docs/mermaid-layout-complaints.md +0 -837
  127. package/docs/mutation-testing.md +0 -206
  128. package/docs/project/divergences.md +0 -98
  129. package/docs/project/dogfooding-docs-strategy.md +0 -66
  130. package/docs/project/hosted-mcp-cloudflare-plan.md +0 -338
  131. package/docs/project/lessons-learned.md +0 -1019
  132. package/docs/project/remove-role-styling-plan.md +0 -176
  133. package/docs/quality.md +0 -215
  134. package/docs/react.md +0 -97
  135. package/docs/style-authoring.md +0 -133
  136. package/docs/testing-strategy.md +0 -335
  137. package/docs/theming.md +0 -162
  138. package/examples/agent-improve-auth-flow.ts +0 -206
  139. package/examples/agent-loop.ts +0 -53
  140. package/examples/mcp-vs-cli-complex-diagrams.ts +0 -133
  141. package/llms.txt +0 -104
  142. package/skill-evals/README.md +0 -77
  143. package/skill-evals/fixtures/architecture-cache/input.mmd +0 -5
  144. package/skill-evals/fixtures/class-payment/input.mmd +0 -4
  145. package/skill-evals/fixtures/er-orders/input.mmd +0 -10
  146. package/skill-evals/fixtures/flowchart-cache/input.mmd +0 -3
  147. package/skill-evals/fixtures/gantt-release/input.mmd +0 -7
  148. package/skill-evals/fixtures/journey-checkout/input.mmd +0 -6
  149. package/skill-evals/fixtures/pie-exports/input.mmd +0 -5
  150. package/skill-evals/fixtures/quadrant-priorities/input.mmd +0 -11
  151. package/skill-evals/fixtures/sequence-retry/input.mmd +0 -8
  152. package/skill-evals/fixtures/state-lifecycle/input.mmd +0 -5
  153. package/skill-evals/fixtures/timeline-release/input.mmd +0 -6
  154. package/skill-evals/fixtures/xychart-growth/input.mmd +0 -5
  155. package/skill-evals/shared-benchmark.json +0 -510
  156. package/src/agent/analyze.ts +0 -157
  157. package/src/agent/apply.ts +0 -146
  158. package/src/agent/architecture-body.ts +0 -458
  159. package/src/agent/certificates.ts +0 -110
  160. package/src/agent/class-body.ts +0 -319
  161. package/src/agent/core.ts +0 -207
  162. package/src/agent/create.ts +0 -106
  163. package/src/agent/describe.ts +0 -368
  164. package/src/agent/er-body.ts +0 -224
  165. package/src/agent/facts.ts +0 -360
  166. package/src/agent/families-builtin.ts +0 -920
  167. package/src/agent/families.ts +0 -232
  168. package/src/agent/family-layouts.ts +0 -832
  169. package/src/agent/flowchart-body.ts +0 -372
  170. package/src/agent/flowchart-unsupported.ts +0 -243
  171. package/src/agent/font-coverage.ts +0 -288
  172. package/src/agent/gantt-body.ts +0 -495
  173. package/src/agent/index.ts +0 -10
  174. package/src/agent/journey-body.ts +0 -374
  175. package/src/agent/label-metrics.ts +0 -28
  176. package/src/agent/layout-to-rendered.ts +0 -63
  177. package/src/agent/mutate.ts +0 -97
  178. package/src/agent/mutation-ops.ts +0 -51
  179. package/src/agent/op-schema.ts +0 -443
  180. package/src/agent/parse.ts +0 -223
  181. package/src/agent/pie-body.ts +0 -270
  182. package/src/agent/png.ts +0 -171
  183. package/src/agent/quadrant-body.ts +0 -336
  184. package/src/agent/quality.ts +0 -363
  185. package/src/agent/readability-audit.ts +0 -92
  186. package/src/agent/rendered-route-audit.ts +0 -61
  187. package/src/agent/sequence-body.ts +0 -345
  188. package/src/agent/serialize.ts +0 -214
  189. package/src/agent/state-body.ts +0 -589
  190. package/src/agent/structural-count.ts +0 -150
  191. package/src/agent/timeline-body.ts +0 -280
  192. package/src/agent/trace-log.ts +0 -43
  193. package/src/agent/types.ts +0 -995
  194. package/src/agent/verify.ts +0 -603
  195. package/src/agent/xychart-body.ts +0 -472
  196. package/src/architecture/config.ts +0 -282
  197. package/src/architecture/layout.ts +0 -496
  198. package/src/architecture/parser.ts +0 -375
  199. package/src/architecture/renderer.ts +0 -611
  200. package/src/architecture/types.ts +0 -113
  201. package/src/ascii/ansi.ts +0 -423
  202. package/src/ascii/architecture.ts +0 -210
  203. package/src/ascii/canvas.ts +0 -443
  204. package/src/ascii/class-diagram.ts +0 -697
  205. package/src/ascii/converter.ts +0 -475
  206. package/src/ascii/draw.ts +0 -1693
  207. package/src/ascii/edge-bundling.ts +0 -328
  208. package/src/ascii/edge-routing.ts +0 -330
  209. package/src/ascii/er-diagram.ts +0 -439
  210. package/src/ascii/gantt.ts +0 -276
  211. package/src/ascii/grid.ts +0 -747
  212. package/src/ascii/index.ts +0 -196
  213. package/src/ascii/journey.ts +0 -169
  214. package/src/ascii/meta.ts +0 -244
  215. package/src/ascii/multiline-utils.ts +0 -80
  216. package/src/ascii/pathfinder.ts +0 -301
  217. package/src/ascii/pie.ts +0 -67
  218. package/src/ascii/quadrant.ts +0 -158
  219. package/src/ascii/reverse.ts +0 -216
  220. package/src/ascii/sequence.ts +0 -499
  221. package/src/ascii/shapes/circle.ts +0 -27
  222. package/src/ascii/shapes/corners.ts +0 -143
  223. package/src/ascii/shapes/diamond.ts +0 -27
  224. package/src/ascii/shapes/hexagon.ts +0 -27
  225. package/src/ascii/shapes/index.ts +0 -106
  226. package/src/ascii/shapes/rectangle.ts +0 -168
  227. package/src/ascii/shapes/rounded.ts +0 -27
  228. package/src/ascii/shapes/special.ts +0 -332
  229. package/src/ascii/shapes/stadium.ts +0 -110
  230. package/src/ascii/shapes/state.ts +0 -192
  231. package/src/ascii/shapes/types.ts +0 -73
  232. package/src/ascii/timeline.ts +0 -141
  233. package/src/ascii/types.ts +0 -312
  234. package/src/ascii/validate.ts +0 -120
  235. package/src/ascii/width.ts +0 -81
  236. package/src/ascii/wrap.ts +0 -131
  237. package/src/ascii/xychart.ts +0 -919
  238. package/src/browser.ts +0 -29
  239. package/src/class/layout.ts +0 -240
  240. package/src/class/parser.ts +0 -332
  241. package/src/class/renderer.ts +0 -638
  242. package/src/class/types.ts +0 -129
  243. package/src/cli/agent-instructions.ts +0 -1
  244. package/src/cli/am-bin.ts +0 -6
  245. package/src/cli/exit-codes.ts +0 -18
  246. package/src/cli/index.ts +0 -1132
  247. package/src/cli/init-agent.ts +0 -147
  248. package/src/cli/run-entrypoint.ts +0 -10
  249. package/src/color-resolver.ts +0 -152
  250. package/src/elk-instance.ts +0 -114
  251. package/src/er/layout.ts +0 -187
  252. package/src/er/parser.ts +0 -226
  253. package/src/er/renderer.ts +0 -792
  254. package/src/er/types.ts +0 -99
  255. package/src/family-rubric.ts +0 -425
  256. package/src/font-manifest.ts +0 -31
  257. package/src/gantt/layout.ts +0 -365
  258. package/src/gantt/parser.ts +0 -282
  259. package/src/gantt/pipeline.ts +0 -27
  260. package/src/gantt/renderer.ts +0 -414
  261. package/src/gantt/schedule.ts +0 -513
  262. package/src/gantt/types.ts +0 -255
  263. package/src/index.ts +0 -368
  264. package/src/journey/layout.ts +0 -554
  265. package/src/journey/parse-core.ts +0 -251
  266. package/src/journey/parser.ts +0 -101
  267. package/src/journey/renderer.ts +0 -917
  268. package/src/journey/types.ts +0 -144
  269. package/src/layout/geometry.ts +0 -182
  270. package/src/layout/pass.ts +0 -142
  271. package/src/layout/passes/index.ts +0 -3916
  272. package/src/layout-engine.ts +0 -1565
  273. package/src/layout-rubric.ts +0 -659
  274. package/src/mcp/artifacts.ts +0 -137
  275. package/src/mcp/dynamic-harness.ts +0 -31
  276. package/src/mcp/dynamic-modules.d.ts +0 -7
  277. package/src/mcp/facade.ts +0 -608
  278. package/src/mcp/harness-runtime.ts +0 -203
  279. package/src/mcp/hosted-server.ts +0 -468
  280. package/src/mcp/mcp-bin.ts +0 -3
  281. package/src/mcp/mcp-cli.ts +0 -82
  282. package/src/mcp/protocol.ts +0 -13
  283. package/src/mcp/sandbox.ts +0 -195
  284. package/src/mcp/sdk-decl.ts +0 -391
  285. package/src/mcp/server.ts +0 -362
  286. package/src/mcp/tool-surface.ts +0 -146
  287. package/src/mermaid-source.ts +0 -655
  288. package/src/multiline-utils.ts +0 -228
  289. package/src/parser.ts +0 -1031
  290. package/src/pie/layout.ts +0 -168
  291. package/src/pie/parser.ts +0 -136
  292. package/src/pie/renderer.ts +0 -234
  293. package/src/pie/types.ts +0 -82
  294. package/src/quadrant/layout.ts +0 -191
  295. package/src/quadrant/parser.ts +0 -183
  296. package/src/quadrant/renderer.ts +0 -322
  297. package/src/quadrant/types.ts +0 -113
  298. package/src/render-family-hooks.ts +0 -244
  299. package/src/renderer.ts +0 -1099
  300. package/src/route-contracts.ts +0 -2723
  301. package/src/scene/backend.ts +0 -76
  302. package/src/scene/fidelity.ts +0 -183
  303. package/src/scene/hybrid-backend.ts +0 -174
  304. package/src/scene/ir.ts +0 -181
  305. package/src/scene/marks.ts +0 -127
  306. package/src/scene/rough-backend.ts +0 -378
  307. package/src/scene/seed.ts +0 -46
  308. package/src/scene/style-registry.ts +0 -556
  309. package/src/sequence/layout.ts +0 -456
  310. package/src/sequence/parser.ts +0 -255
  311. package/src/sequence/renderer.ts +0 -604
  312. package/src/sequence/types.ts +0 -154
  313. package/src/shape-clipping.ts +0 -351
  314. package/src/shared/accessibility-directives.ts +0 -22
  315. package/src/shared/batched.ts +0 -61
  316. package/src/shared/color-math.ts +0 -93
  317. package/src/shared/svg-a11y.ts +0 -29
  318. package/src/shared/syntax-error.ts +0 -17
  319. package/src/shared/unicode-ranges.ts +0 -135
  320. package/src/styles.ts +0 -318
  321. package/src/svg-paths.ts +0 -28
  322. package/src/text-metrics.ts +0 -248
  323. package/src/theme.ts +0 -710
  324. package/src/timeline/layout.ts +0 -381
  325. package/src/timeline/parser.ts +0 -215
  326. package/src/timeline/renderer.ts +0 -538
  327. package/src/timeline/types.ts +0 -105
  328. package/src/types.ts +0 -462
  329. package/src/website-worker-modules.d.ts +0 -18
  330. package/src/xychart/axis-utils.ts +0 -109
  331. package/src/xychart/colors.ts +0 -124
  332. package/src/xychart/config.ts +0 -88
  333. package/src/xychart/layout.ts +0 -656
  334. package/src/xychart/parser.ts +0 -504
  335. package/src/xychart/renderer.ts +0 -640
  336. package/src/xychart/types.ts +0 -282
@@ -1,338 +0,0 @@
1
- # Hosted MCP on Cloudflare: plan
2
-
3
- > **Status: shipped (PR #94).** This began as a design plan and is now the
4
- > as-built record of the hosted MCP endpoint live at
5
- > `https://agentic-mermaid.dev/mcp`. The "Where we start" section below is
6
- > preserved as the pre-build starting point; the "Post-review hardening"
7
- > sections (rounds 1–5) track the audit findings applied after the initial
8
- > build.
9
-
10
- Plan for turning the website's `/mcp` 501 placeholder into a real hosted MCP
11
- endpoint at `https://agentic-mermaid.dev/mcp`. The account is on the **Workers
12
- Paid plan with Dynamic Workers** (<https://developers.cloudflare.com/dynamic-workers/>),
13
- which changes the earlier free-tier plan in one fundamental way: hosted Code
14
- Mode (`execute`) is now viable — agent-supplied JavaScript runs in an isolated
15
- dynamic Worker instead of being local-only.
16
-
17
- ## Where we start
18
-
19
- - The website is a Cloudflare Worker with Static Assets
20
- (`website/wrangler.jsonc`, `website/src/worker.js` at the time — now
21
- `worker.ts`); `/mcp` returned an honest 501 before this work.
22
- - The MCP server (`src/mcp/server.ts`) has a transport-agnostic JSON-RPC core,
23
- `handleRequest(req, context)`, plus stdio and node HTTP/SSE transports.
24
- - Tools today: `execute` (Code Mode in a hardened `node:vm` sandbox),
25
- `render_png` (native `@resvg/resvg-js`), `describe`.
26
- - **Viability probe (done):** the pure SDK surface — parse, mutate, verify,
27
- analyze, serialize, describe, `renderMermaidSVG`, `renderMermaidASCII`, the
28
- Code Mode facade — bundles for the workerd target at 2.2 MB raw / 657 KB
29
- gzip with zero Node dependencies, and renders correctly from that bundle.
30
- The only native/VM dependencies in the whole graph are `png.ts` (napi resvg)
31
- and `sandbox.ts` (`node:vm`), both replaced per the table below. elkjs is
32
- the bundled pure-JS build driven synchronously (`src/elk-instance.ts`) and
33
- needs nothing from Node.
34
-
35
- ## Hosted tool surface
36
-
37
- | Tool | Local implementation | Hosted implementation |
38
- |---|---|---|
39
- | `execute` | `node:vm` hardened sandbox | **Dynamic Worker** per code hash: harness module (SDK bundle + the same hardened facade) + agent code as a module, `globalOutbound: null`, `limits: { cpuMs, subRequests: 0 }` |
40
- | `render_png` | native `@resvg/resvg-js` | `@resvg/resvg-wasm` + bundled DejaVu Sans and built-in style faces (convenience surface; wasm output is not covered by the byte-determinism contract) |
41
- | `describe` | pure | same code, unchanged |
42
- | `render_svg` | — (use execute) | pure, hosted-only |
43
- | `render_ascii` | — (use execute) | pure, hosted-only |
44
- | `verify` | — (use execute) | pure, hosted-only |
45
- | `mutate` | — (use execute or CLI `am mutate`) | hosted-only declarative structured edit of an existing `source`; applies an op list, verifies, emits `{ ok, family, source, verify }` only on success |
46
- | `build` | — (use execute or CLI/library `buildMermaid`) | hosted-only declarative authoring from a `family` + op list; same verified envelope as `mutate` |
47
-
48
- The three hosted-only pure render/verify tools exist for cost, not philosophy:
49
- locally, `execute` is free, so Code Mode stays the single entry point
50
- (`docs/mcp-code-mode-rationale.md` still holds). Hosted, every `execute`
51
- spins/bills a dynamic Worker, so the common render/verify paths get direct
52
- tools that cost one ordinary Worker invocation and are edge-cacheable. The
53
- `mutate`/`build` tools are the deliberate structured-edit exception: they give
54
- weak clients a verified op-list path without asking them to write JavaScript,
55
- while still funneling through the same typed mutation core. The implementations
56
- live in the shared hosted core (`src/mcp/hosted-server.ts`), not the website, so
57
- there is exactly one implementation of each.
58
-
59
- ## Hosted `execute` via Dynamic Workers
60
-
61
- Design (API per <https://developers.cloudflare.com/dynamic-workers/api-reference/>):
62
-
63
- - The parent Worker holds a `worker_loaders` binding (`LOADER`). On
64
- `execute`, it calls `env.LOADER.get(id, async () => workerCode)` where:
65
- - `id` = `am-exec-<pkg.version>-<sha256(code)>` — identical code reuses a
66
- warm isolate; the callback only runs on cold load.
67
- - `workerCode.modules` = the prebuilt **harness** (SDK bundle + Code Mode
68
- facade + result plumbing, built by `website/build.ts` and imported into
69
- the parent as a text module) plus the agent code wrapped as ONE module
70
- per isolate. workerd compiles every registry module eagerly at isolate
71
- startup (discovered in the wrangler e2e — a lazy `import()` fallback
72
- inside one isolate is impossible), so the expression-first choice
73
- `sandbox.ts` makes is decided by the loader itself: the parent starts the
74
- expression-form isolate first and falls back to a statement-form isolate
75
- when startup fails with a SyntaxError. Statement-form code costs one
76
- failed isolate attempt; identical repeats never reach the loader thanks
77
- to the response cache.
78
- - `globalOutbound: null` — the isolate cannot `fetch()` or `connect()`
79
- at all; `env` is empty, so there is nothing to reach or leak.
80
- - `getEntrypoint(null, { limits: { cpuMs: min(timeoutMs, 30_000),
81
- subRequests: 0 } })` enforces the compute budget; hitting it throws,
82
- which maps to the same `{ ok: false, error }` shape as a local timeout.
83
- - The harness passes the user function the **same hardened `mermaid` facade**
84
- the vm sandbox uses (`createTracingMermaid`, extracted to a runtime-neutral
85
- `src/mcp/facade.ts`), so read-only results, trusted-diagram checks, and
86
- error messages match local behavior. Sync-only enforcement
87
- (`unsupportedCodeReason`) runs parent-side before any isolate is created —
88
- rejected code costs nothing.
89
- - Result contract is byte-identical in shape to local: `{ ok, value, logs,
90
- error }`, with the same undefined→null promotion and Map/Set JSON
91
- normalization.
92
-
93
- Known, documented divergences from local `execute`:
94
-
95
- 1. `timeoutMs` is enforced as **CPU** milliseconds (`cpuMs`), not wall-clock;
96
- for pure synchronous compute these are close but not identical.
97
- 2. A warm isolate can serve repeated identical code, so module-level global
98
- mutation (`globalThis.x = ...`) may be visible across calls with the same
99
- code — locally every call gets a fresh vm context. Response caching (below)
100
- makes identical requests return the first result anyway; the divergence is
101
- only reachable when the edge cache misses but the isolate is warm.
102
- 3. Isolation authority differs: locally the proxy facade is the security
103
- boundary; hosted, the isolate + `globalOutbound: null` is, and the facade
104
- is kept for behavioral parity.
105
- 4. Hosted output is bounded at the source: console logs cap at 1,000
106
- entries / 256 KB (a truncation marker is appended) and serialized results
107
- at 2 MB, with the parent's capped stream-read of the isolate response as
108
- the backstop. The vm sandbox has no output caps.
109
-
110
- Post-review hardening (external audit, round 1): Worker Loader isolate IDs
111
- carry a `deployTag` — package version **plus a hash of the harness bundle** —
112
- because the Worker Loader contract is that one ID always maps to the same
113
- WorkerCode; without the hash, a harness/SDK change that ships without a
114
- version bump could keep serving stale warm isolates. Request bodies and
115
- isolate responses are stream-read with hard byte caps (no buffering past the
116
- limit), `render_png` clamps `scale` to 0.1–8 and enforces a ~16.7 MP
117
- output-pixel budget, and the e2e probe pins workerd's codegen bans (`eval`,
118
- `Function` constructor) plus the log cap against a live isolate.
119
-
120
- Post-review hardening (external audit, round 2):
121
-
122
- - **Full-deploy cache version.** The harness hash covers Code Mode isolate
123
- IDs, but the /mcp *response* cache also stores `render_svg` / `verify` /
124
- `describe` / `render_png` results, whose implementations live in
125
- `hosted-server.ts`, `mcp-handler.ts`, `png-wasm.ts`, and the wasm/fonts —
126
- none of which are in the harness bundle. `cacheVersion` is now a
127
- `DEPLOY_VERSION` computed at build time (`website/src/deploy-hash.ts`,
128
- emitted to `generated/deploy-version.ts`): a length-prefixed SHA-256 over
129
- the **bundled worker JS closure + harness + wasm + fonts + the main
130
- worker's `compatibility_date`**. Any change to any hosted tool, the
131
- transport, the PNG path, an asset, or the worker's runtime semantics moves
132
- it and invalidates cached results, version bump or not. Isolate IDs keep the
133
- narrower harness hash (they *are* just harness + user module).
134
- - **Cache keys from normalized effective arguments.** The key was a hash of
135
- raw `req.params`; handlers drop unknown args and clamp `scale`/`timeoutMs`,
136
- so a caller could add `{ nonce }` or vary an out-of-range `scale` to force
137
- recompute and defeat the cost control. `cacheKeyFor` (in `hosted-server.ts`,
138
- the single source of truth the handlers also use for clamping) now derives
139
- the key from only the output-affecting arguments, normalized: unknown keys
140
- dropped, `scale` clamped and defaulted to its resolved value (omitted and
141
- explicit `scale: 2` share one entry), `timeoutMs` excluded from `execute`
142
- (it is a budget, not an input). Calls it deems uncacheable (unknown tool,
143
- missing required arg, non-base64 `render_png` output) bypass the cache and
144
- run directly — they error, and errors were never cached.
145
-
146
- **Scope of the cost-control guarantee (external audit, round 3 — adversarial
147
- multi-agent verification found no correctness/poisoning bug; these are the
148
- low-severity refinements it surfaced):**
149
-
150
- - The normalization covers **arguments**, not the `source`/`code` payload,
151
- which is keyed **verbatim by design**. Keying on the raw payload is what
152
- makes a cached response provably correspond to what that exact input
153
- renders; canonicalizing the payload (e.g. stripping Mermaid comments) is
154
- deliberately avoided because two payloads that canonicalize alike are not
155
- guaranteed to render byte-identically — a wrong cached result is far worse
156
- than a missed dedup. A caller can therefore still force recompute by varying
157
- insignificant payload bytes (comments/trailing whitespace). That residual is
158
- bounded by the **WAF rate limit** (the actual abuse backstop; see
159
- `website/README.md`), not by the cache.
160
- - `execute` is cached on `code` alone. Code Mode is intended for deterministic
161
- SDK workflows; a non-deterministic body (`Date`/`Math.random`) has its first
162
- result frozen for the cache TTL. This is pre-existing — `execute` results
163
- were always cached — and inherent to caching arbitrary code; it is not a
164
- cross-caller integrity issue (identical `code` → identical key by definition).
165
- - The response cache is a **cost optimization for legitimate repeat traffic**,
166
- not the abuse control. The WAF rate-limiting rule on `POST /mcp` is the
167
- primary defense against a determined attacker and remains a launch
168
- requirement.
169
-
170
- **Post-review hardening (external audit, round 4 — full-PR multi-agent audit,
171
- 5 lenses):** one P1 (wrapper-breakout containment) and a set of low-severity
172
- test-coverage and transport refinements. The verified fixes:
173
-
174
- - **Wrapper-breakout containment, stated honestly.** Agent code is concatenated
175
- into an ES module, so code that closes the harness function early with `}`
176
- reaches module scope. Two layers close what the isolate boundary already
177
- bounds: (1) the harness wraps the user function in **parentheses** (an
178
- expression position), which makes an injected top-level `import`/`export`/`;`
179
- a **SyntaxError** — so a `import ... from 'cloudflare:sockets'` breakout fails
180
- the isolate start rather than running; and (2) `hardenIsolateGlobals()` runs
181
- at isolate startup, **before** `user.js` is dynamically imported, and strips
182
- capability globals (`fetch`, `caches`, `crypto`, `connect`, …) plus
183
- `Error.prepareStackTrace`. A comma+IIFE tail can still *run* at eval time, but
184
- only against stripped capabilities. These are **defense in depth** — the
185
- guaranteed boundary remains the isolate config (`globalOutbound: null`, empty
186
- env, no bindings, `cpuMs`). `NEUTRALIZED_ISOLATE_GLOBALS` is restricted to
187
- globals provably unused by the harness and the pure SDK at run time (verified
188
- by the wrangler e2e, which still renders after hardening).
189
- - **Test-coverage gaps closed.** The Promise.race wall-clock backstop, the
190
- empty/non-JSON isolate-body malformed guard, `readCapped`'s byte-exact cap
191
- (boundary + cross-chunk + UTF-8 straddle), multi-chunk base64 encoding, and
192
- CORS headers on HTTP-level error responses now have discriminating tests
193
- (each fails when its mechanism is removed).
194
- - **Transport nits.** The Promise.race timer is cleared in a `finally` so a
195
- winning fetch leaves no dangling timer, and an empty/non-JSON isolate body
196
- degrades to `sandbox returned a malformed result` instead of leaking a raw
197
- `JSON.parse` error.
198
-
199
- Residual honesty: `website/e2e-mcp.sh` is a **manual** probe run against a live
200
- `wrangler dev` (it needs the Worker Loader), **not** a CI gate; the CI gate is
201
- `bun test src/__tests__/`. The isolate-level containment (globals stripped on
202
- the real `globalThis`, breakout rejected) is what the e2e pins; the unit suite
203
- pins the pure, runtime-neutral pieces (`neutralizeGlobalsOn` on a throwaway
204
- target, `userModuleSources` rejection, the log cap).
205
-
206
- **Post-review hardening (external audit, round 5 — transport abuse/conformance):**
207
-
208
- - **Batch fan-out cap.** A JSON-RPC array ran every item under `Promise.all`,
209
- so one 128 KB body could pack many `tools/call` items that each spin a
210
- billable isolate/render — a single request amplifying past the per-IP WAF
211
- limit. `MAX_BATCH_ITEMS` (20) now bounds a batch, refused with 400 before any
212
- item runs.
213
- - **`MCP-Protocol-Version` validation + 2025-06-18 batch rule.** The transport
214
- now rejects an explicit unsupported version header with 400, and — because
215
- MCP 2025-06-18 *removed* JSON-RPC batching — refuses an array body when the
216
- header pins that revision. Older negotiated versions (2024-11-05 / 2025-03-26,
217
- or no header) may still batch, so existing clients are unaffected.
218
- - **CORS Origin validation.** Wildcard `Access-Control-Allow-Origin: *` on a
219
- public, credential-less endpoint is not itself an access-control hole — CORS
220
- gates only browser reads and never the agent/server clients that ignore it —
221
- but `*` does let an arbitrary site silently drive a *visitor's* browser
222
- against the endpoint (distributed across visitor IPs, diluting the per-IP WAF
223
- limit). CORS is now **reflective with Origin validation**: a no-Origin client
224
- (agent/server) still gets `*`; a browser Origin is echoed only when it is
225
- same-origin / localhost / allowlisted (`agentic-mermaid.dev`); a disallowed
226
- browser Origin gets no `Access-Control-Allow-Origin` and a 403. This follows
227
- the MCP Streamable HTTP Origin-validation guidance without breaking any
228
- non-browser client (the website itself does not call `/mcp` from the browser).
229
-
230
- ## Transport: stateless Streamable HTTP
231
-
232
- Unchanged from the original plan and still the cheapest correct choice — the
233
- tools are pure functions of their inputs:
234
-
235
- - Single `POST /mcp` accepting JSON-RPC, responding `application/json`.
236
- No sessions, no SSE stream, `GET /mcp` → 405, notifications → 202.
237
- - No Durable Objects, agents SDK, KV, R2, or Queues.
238
- - Protocol version negotiated from a known-good list (the core currently pins
239
- `2024-11-05`; Streamable HTTP clients offer `2025-03-26`+).
240
- - **Response caching:** layout is deterministic, so `tools/call` responses
241
- (except nothing — all eight tools are deterministic) are cached in the Workers
242
- Cache API keyed on SHA-256 of `(tool, canonicalized arguments)`. Repeat
243
- requests skip compute entirely; for `execute` they also skip the dynamic
244
- Worker, which is the biggest cost lever.
245
- - Hygiene: 128 KB body cap, 64 KB Mermaid-source/code caps with structured
246
- errors pointing at the local CLI, `content-type` enforcement, Origin-validated
247
- CORS (no-Origin agent/server clients keep `*`; allowed browser origins are
248
- echoed; disallowed browser origins get 403), one WAF rate-limiting rule
249
- (e.g. 60 req/min/IP on `POST /mcp`, configured in the dashboard and
250
- recorded in `website/README.md`).
251
-
252
- ## Cost model (Workers Paid)
253
-
254
- | Meter | Included | Overage | Our exposure |
255
- |---|---|---|---|
256
- | Worker requests | 10 M/month | $0.30/M | every `/mcp` call + one internal request per uncached `execute` |
257
- | CPU time | 30 M ms/month | $0.02/M ms | renders are ms-scale; `execute` capped at 30 s by `cpuMs` |
258
- | Unique dynamic Workers | 1,000/month | $0.002/Worker/day | one per **unique** `execute` code string per day (hash-keyed + edge-cached; retries and repeats dedupe) |
259
-
260
- Levers that keep this near the plan's $5/month floor: edge caching of
261
- deterministic responses, code-hash isolate reuse, parent-side rejection of
262
- unsupported code, `subRequests: 0`, size caps, and the WAF rate limit as the
263
- abuse backstop. The pure tools keep the high-volume paths (render/verify) off
264
- the dynamic-Worker meter entirely. No other billable primitives are used.
265
-
266
- ## Verification strategy
267
-
268
- Two external toolkits gate this work, per the repo owner's direction:
269
-
270
- - **testing-best-practices** (<https://github.com/adewale/testing-best-practices>):
271
- - Red-green for new behavior: hosted-core tests written to fail without the
272
- implementation; red/green evidence stated in the PR.
273
- - **Differential testing** (`references/differential-testing.md`): the local
274
- `node:vm` sandbox is the reference implementation; a corpus of Code Mode
275
- snippets (happy paths, SDK misuse, mutation attempts, sync violations,
276
- serialization edges) runs through both `executeInSandbox` and the harness
277
- execution semantics, asserting matching `{ ok, value, logs, error }`.
278
- - Error-path tests, not just invalid input: loader failures, cpu-limit
279
- exceptions, oversized bodies, wrong content types, malformed JSON-RPC.
280
- - Real objects over mocks: transport tests drive the actual `fetch` handler
281
- with real `Request`/`Response`; the only faked seam is the Worker Loader
282
- binding (a purpose-built fake implementing `get/getEntrypoint`, since
283
- workerd is not available inside `bun test`), and a `wrangler dev` e2e
284
- covers the real binding.
285
- - **cfdoctor** (<https://github.com/adewale/cfdoctor>): static scan
286
- (`cfdoctor_static_scan.py`) plus the skill's audit playbook run against
287
- `website/` before shipping; findings triaged with evidence and fixed or
288
- explicitly accepted in the audit output.
289
-
290
- Plus the repo's own gates: `bun test src/__tests__/` (existing MCP tests must
291
- stay green through the refactor), `bunx tsc --noEmit`, `bun run
292
- website:check`, and a `wrangler dev` end-to-end pass (`website/e2e-mcp.sh`:
293
- initialize → tools/list → each tool, including a real dynamic-Worker
294
- `execute`). Known local-dev limitation found in that pass: wrangler dev does
295
- not enforce dynamic-worker `cpuMs`, so an unbounded sync loop wedges local
296
- workerd; production enforces `cpuMs` at the runtime and the parent races a
297
- wall-clock backstop so `/mcp` always answers. The e2e also flushed out an
298
- ELK instantiation failure under workerd (fixed in `src/elk-instance.ts` by
299
- flipping elk-worker's environment sniff with a temporary `document` global
300
- instead of deleting the undeletable `self`).
301
-
302
- ## Implementation steps
303
-
304
- 1. **Extract runtime-neutral modules.** `src/mcp/protocol.ts` (JSON-RPC
305
- types + reply/error helpers), `src/mcp/facade.ts` (`createTracingMermaid`,
306
- `unsupportedCodeReason`, wrapping helpers) importing the pure agent
307
- surface, not the barrel (the barrel exports `png.ts`, which drags native
308
- resvg into every graph). `server.ts`/`sandbox.ts` keep their exports and
309
- behavior; existing tests untouched.
310
- 2. **Hosted core** `src/mcp/hosted-server.ts`: `handleHostedRequest(req,
311
- context)` with the eight-tool surface; `execute` and `render_png` accept
312
- injected implementations so the core stays runtime-neutral and testable in
313
- `bun test`.
314
- 3. **Harness** `src/mcp/dynamic-harness.ts` (entry compiled to a single text
315
- asset by `website/build.ts`): fetch handler that builds the facade, imports
316
- the user module (expression-first with `SyntaxError` fallback), executes,
317
- serializes to the `ExecuteResult` contract.
318
- 4. **Website worker** `website/src/worker.ts`: existing static/redirect logic
319
- unchanged; `/mcp` branch implements the streamable-HTTP handler, cache
320
- layer, loader-backed `execute`, wasm `render_png`. `wrangler.jsonc` gains
321
- `worker_loaders`, text/data module rules for the harness and font, and
322
- keeps Static Assets.
323
- 5. **Tests** as described under verification; `src/__tests__/website-build.test.ts`
324
- now asserts the live hosted endpoint (the 501 assertion it carried is gone).
325
- 6. **cfdoctor audit + wrangler dev e2e**, fix findings.
326
- 7. **Docs**: `website/README.md`, `docs/mcp-http-transport.md` cross-link, a
327
- hosted-MCP section documenting the endpoint, tool surface, limits,
328
- divergences, and the dashboard-side rate-limit rule.
329
-
330
- ## Explicit non-goals
331
-
332
- - No REST render API — MCP only.
333
- - No accounts or tokens; abuse control is caps + rate limiting.
334
- - No hosted artifact storage; `render_png` returns base64 only (`output:
335
- "file"/"url"` stay local-server features).
336
- - Durable Object facets, dynamic Workflows, and egress-controlled outbound
337
- fetch (Dynamic Workers features) are all unused — the isolates need no
338
- state and no network.