@legionworks/facet 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. package/LICENSE-APACHE +202 -0
  2. package/LICENSE-MIT +23 -0
  3. package/README.md +158 -0
  4. package/dist/gallery/chunk-4g8rem85.css +656 -0
  5. package/dist/gallery/chunk-c6s9k9ty.js +5970 -0
  6. package/dist/gallery/frame/artifact.css +8424 -0
  7. package/dist/gallery/frame/chunks/abnfDiagram-N423BO3Z-jj74szbm.js +155 -0
  8. package/dist/gallery/frame/chunks/architecture-TIHT7OUA-cvdjn7dt.js +10 -0
  9. package/dist/gallery/frame/chunks/architectureDiagram-T3A2C74G-n4z77eg6.js +8675 -0
  10. package/dist/gallery/frame/chunks/blockDiagram-VBNYF7ZC-7xsqzrd1.js +3529 -0
  11. package/dist/gallery/frame/chunks/c4Diagram-5PPSVZJV-z2zjs7wx.js +2413 -0
  12. package/dist/gallery/frame/chunks/classDiagram-JCYQIIEL-ve8rngqp.js +47 -0
  13. package/dist/gallery/frame/chunks/classDiagram-v2-OCEON4UE-8cfaxb8z.js +47 -0
  14. package/dist/gallery/frame/chunks/cose-bilkent-JH36ORCC-sn92qexx.js +4822 -0
  15. package/dist/gallery/frame/chunks/cynefin-VYW2F7L2-tqjv913d.js +10 -0
  16. package/dist/gallery/frame/chunks/cynefinDiagram-MW4NZA55-c1c0dj12.js +500 -0
  17. package/dist/gallery/frame/chunks/dagre-VZM6K2ZE-7tyg4yt2.js +476 -0
  18. package/dist/gallery/frame/chunks/diagram-7IWD3JNH-y4eng9sc.js +526 -0
  19. package/dist/gallery/frame/chunks/diagram-B4RE2ZJO-rn3p7j5h.js +673 -0
  20. package/dist/gallery/frame/chunks/diagram-LBJQPF4R-w4a2cm9q.js +255 -0
  21. package/dist/gallery/frame/chunks/diagram-Q27KOJAE-aqc2v7wy.js +575 -0
  22. package/dist/gallery/frame/chunks/diagram-UB23O5K3-xncy8nyd.js +355 -0
  23. package/dist/gallery/frame/chunks/ebnfDiagram-BXEA7PRR-acwgxz16.js +175 -0
  24. package/dist/gallery/frame/chunks/erDiagram-JOGREHBK-mzp5nswt.js +1332 -0
  25. package/dist/gallery/frame/chunks/eventmodeling-45OFAUF4-sg07qr0c.js +10 -0
  26. package/dist/gallery/frame/chunks/flowDiagram-UKHOOZJN-2e5ygs44.js +29 -0
  27. package/dist/gallery/frame/chunks/ganttDiagram-PKOTCBZU-p2hhh7hr.js +2620 -0
  28. package/dist/gallery/frame/chunks/gitGraph-TEB2WS4Q-j6kw0naa.js +10 -0
  29. package/dist/gallery/frame/chunks/gitGraphDiagram-DS77QQ5N-4z9z8wjm.js +1347 -0
  30. package/dist/gallery/frame/chunks/info-DKCQHKI2-mpt80jd3.js +10 -0
  31. package/dist/gallery/frame/chunks/infoDiagram-6WML65LV-5rqm3mgg.js +65 -0
  32. package/dist/gallery/frame/chunks/ishikawaDiagram-WSZJBQD7-b51z96jy.js +975 -0
  33. package/dist/gallery/frame/chunks/journeyDiagram-NVQOT4AX-9jbfp0pk.js +1272 -0
  34. package/dist/gallery/frame/chunks/kanban-definition-27J2QSJJ-4x0vx4se.js +1116 -0
  35. package/dist/gallery/frame/chunks/katex-xfgk95tv.js +14034 -0
  36. package/dist/gallery/frame/chunks/markdown-1s5vwkf2.js +9 -0
  37. package/dist/gallery/frame/chunks/markdown-2h6bwsms.js +3239 -0
  38. package/dist/gallery/frame/chunks/markdown-2x113yh8.js +107 -0
  39. package/dist/gallery/frame/chunks/markdown-30b7rwmp.js +1943 -0
  40. package/dist/gallery/frame/chunks/markdown-356bfj4g.js +2031 -0
  41. package/dist/gallery/frame/chunks/markdown-44n9ea69.js +2406 -0
  42. package/dist/gallery/frame/chunks/markdown-56enrf2r.js +39 -0
  43. package/dist/gallery/frame/chunks/markdown-5avymm8t.js +725 -0
  44. package/dist/gallery/frame/chunks/markdown-6r4svars.js +33 -0
  45. package/dist/gallery/frame/chunks/markdown-6zz8efx2.js +24 -0
  46. package/dist/gallery/frame/chunks/markdown-7jp6prnb.js +19 -0
  47. package/dist/gallery/frame/chunks/markdown-809k7q41.js +55 -0
  48. package/dist/gallery/frame/chunks/markdown-82xmzhzd.js +1076 -0
  49. package/dist/gallery/frame/chunks/markdown-92n37gd4.js +7627 -0
  50. package/dist/gallery/frame/chunks/markdown-ag2sssf8.js +36 -0
  51. package/dist/gallery/frame/chunks/markdown-b4s7ntq2.js +19 -0
  52. package/dist/gallery/frame/chunks/markdown-c9k0fvp1.js +100 -0
  53. package/dist/gallery/frame/chunks/markdown-ceefymn8.js +125 -0
  54. package/dist/gallery/frame/chunks/markdown-d1wfbs70.js +243 -0
  55. package/dist/gallery/frame/chunks/markdown-dy5sgjhc.js +11022 -0
  56. package/dist/gallery/frame/chunks/markdown-dz3z5w30.js +30868 -0
  57. package/dist/gallery/frame/chunks/markdown-eg6ngz7y.js +30340 -0
  58. package/dist/gallery/frame/chunks/markdown-ff5wvb43.js +1149 -0
  59. package/dist/gallery/frame/chunks/markdown-ffg06nfz.js +86 -0
  60. package/dist/gallery/frame/chunks/markdown-fvfncadf.js +472 -0
  61. package/dist/gallery/frame/chunks/markdown-gvyszqpv.js +19 -0
  62. package/dist/gallery/frame/chunks/markdown-gx1p0ew0.js +88 -0
  63. package/dist/gallery/frame/chunks/markdown-gxye5frz.js +65 -0
  64. package/dist/gallery/frame/chunks/markdown-h7pzv34e.js +105 -0
  65. package/dist/gallery/frame/chunks/markdown-hab789t9.js +47 -0
  66. package/dist/gallery/frame/chunks/markdown-hjp6sj8t.js +125 -0
  67. package/dist/gallery/frame/chunks/markdown-jka64qgp.js +1993 -0
  68. package/dist/gallery/frame/chunks/markdown-k8xkn8mw.js +56 -0
  69. package/dist/gallery/frame/chunks/markdown-m7frq8x8.js +112 -0
  70. package/dist/gallery/frame/chunks/markdown-p740v4qm.js +36 -0
  71. package/dist/gallery/frame/chunks/markdown-pxfeh231.js +57 -0
  72. package/dist/gallery/frame/chunks/markdown-pzgd8z3s.js +87 -0
  73. package/dist/gallery/frame/chunks/markdown-qx3cngz2.js +1673 -0
  74. package/dist/gallery/frame/chunks/markdown-rawhfvvc.js +85 -0
  75. package/dist/gallery/frame/chunks/markdown-rd8w0ng9.js +49 -0
  76. package/dist/gallery/frame/chunks/markdown-rm2yxfjj.js +2773 -0
  77. package/dist/gallery/frame/chunks/markdown-s1jatrnk.js +993 -0
  78. package/dist/gallery/frame/chunks/markdown-sgfg5vvq.js +59 -0
  79. package/dist/gallery/frame/chunks/markdown-t4ethv9d.js +409 -0
  80. package/dist/gallery/frame/chunks/markdown-tnmabqvz.js +36 -0
  81. package/dist/gallery/frame/chunks/markdown-tvdpppw8.js +5292 -0
  82. package/dist/gallery/frame/chunks/markdown-v0x27twr.js +22 -0
  83. package/dist/gallery/frame/chunks/markdown-v14td68x.js +36 -0
  84. package/dist/gallery/frame/chunks/markdown-w6sgd54z.js +36 -0
  85. package/dist/gallery/frame/chunks/markdown-xw8dsk8b.js +2125 -0
  86. package/dist/gallery/frame/chunks/markdown-y18mve73.js +85 -0
  87. package/dist/gallery/frame/chunks/markdown-yengsms5.js +427 -0
  88. package/dist/gallery/frame/chunks/markdown-z1wc0v0d.js +1826 -0
  89. package/dist/gallery/frame/chunks/markdown-zazx9h4n.js +329 -0
  90. package/dist/gallery/frame/chunks/mermaid-de7p4v0x.js +30 -0
  91. package/dist/gallery/frame/chunks/mindmap-definition-FAOFIHXS-ra44cbem.js +1216 -0
  92. package/dist/gallery/frame/chunks/packet-7NZHBO7P-xppm5913.js +10 -0
  93. package/dist/gallery/frame/chunks/pegDiagram-VL7TDLO6-a2a4wg03.js +163 -0
  94. package/dist/gallery/frame/chunks/pie-RZYD4A2V-hnbxk152.js +10 -0
  95. package/dist/gallery/frame/chunks/pieDiagram-7S7Q4E2Y-f1vxjtmx.js +311 -0
  96. package/dist/gallery/frame/chunks/quadrantDiagram-CIZ2JOQS-ywafa6kh.js +1390 -0
  97. package/dist/gallery/frame/chunks/radar-I7S5WNFK-ewqd27se.js +10 -0
  98. package/dist/gallery/frame/chunks/railroad-3IZDKUUU-5hy4bdx3.js +10 -0
  99. package/dist/gallery/frame/chunks/railroad-abnf-AHOZXSZD-bh5sxz0d.js +10 -0
  100. package/dist/gallery/frame/chunks/railroad-ebnf-EBAXGLYW-6b9c3zeh.js +10 -0
  101. package/dist/gallery/frame/chunks/railroad-peg-LSFZ7HO6-avc8v39s.js +10 -0
  102. package/dist/gallery/frame/chunks/railroadDiagram-AXF67PYL-qc61wax4.js +131 -0
  103. package/dist/gallery/frame/chunks/requirementDiagram-LRYGKXZP-9bs4786c.js +1295 -0
  104. package/dist/gallery/frame/chunks/sankeyDiagram-W5VNT64P-awt1em8b.js +1339 -0
  105. package/dist/gallery/frame/chunks/sequenceDiagram-SI44F4Z6-qaf9mz3t.js +4324 -0
  106. package/dist/gallery/frame/chunks/sizeCapture-X5ZJPWSS-9fq685xd.js +64 -0
  107. package/dist/gallery/frame/chunks/stateDiagram-OKZ733FA-vx7a7hh0.js +456 -0
  108. package/dist/gallery/frame/chunks/stateDiagram-v2-UEYNNEHI-x4m6ws5t.js +46 -0
  109. package/dist/gallery/frame/chunks/swimlanes-SLNWSIFB-e4mxm1gh.js +8287 -0
  110. package/dist/gallery/frame/chunks/swimlanesDiagram-ULZ7WXOC-0h93e2qq.js +42 -0
  111. package/dist/gallery/frame/chunks/timeline-definition-Z64GVDOM-wp0bhbzg.js +1549 -0
  112. package/dist/gallery/frame/chunks/treeView-QDETBFTQ-hcx7n0vt.js +10 -0
  113. package/dist/gallery/frame/chunks/treemap-6X3UGDF4-av02skdw.js +10 -0
  114. package/dist/gallery/frame/chunks/vennDiagram-T6HMQDX7-pmvk1p7n.js +2566 -0
  115. package/dist/gallery/frame/chunks/wardley-OPB4EBWU-njsp6e40.js +10 -0
  116. package/dist/gallery/frame/chunks/wardleyDiagram-T6FBY63Y-eggmnv4z.js +979 -0
  117. package/dist/gallery/frame/chunks/xychartDiagram-ELKLHX3M-q40tnpe5.js +1954 -0
  118. package/dist/gallery/frame/frame.css +183 -0
  119. package/dist/gallery/frame/runtime/chart.js +42744 -0
  120. package/dist/gallery/frame/runtime/html.js +14 -0
  121. package/dist/gallery/frame/runtime/markdown.js +1403 -0
  122. package/dist/gallery/frame/runtime/mermaid.js +32 -0
  123. package/dist/gallery/frame/runtime/svg.js +14 -0
  124. package/dist/gallery/frame/runtime/tsx.js +52 -0
  125. package/dist/gallery/index.html +104 -0
  126. package/docs/reference/cli.md +163 -0
  127. package/docs/reference/export.md +106 -0
  128. package/docs/reference/html.md +215 -0
  129. package/docs/reference/http.md +85 -0
  130. package/docs/reference/mcp.md +78 -0
  131. package/docs/reference/security.md +119 -0
  132. package/docs/reference/storage.md +93 -0
  133. package/docs/reference/tsx.md +101 -0
  134. package/docs/reference/validation.md +212 -0
  135. package/package.json +89 -0
  136. package/scripts/build-gallery.ts +127 -0
  137. package/scripts/launch-netns.sh +67 -0
  138. package/skills/facet/SKILL.md +100 -0
  139. package/src/cli/client.ts +311 -0
  140. package/src/cli/commands/create.ts +49 -0
  141. package/src/cli/commands/doctor.ts +249 -0
  142. package/src/cli/commands/export.ts +179 -0
  143. package/src/cli/commands/instantiate.ts +35 -0
  144. package/src/cli/commands/list.ts +49 -0
  145. package/src/cli/commands/open.ts +75 -0
  146. package/src/cli/commands/pin.ts +39 -0
  147. package/src/cli/commands/promote.ts +49 -0
  148. package/src/cli/commands/publish.ts +122 -0
  149. package/src/cli/commands/read-back.ts +56 -0
  150. package/src/cli/commands/status.ts +114 -0
  151. package/src/cli/commands/watch.ts +146 -0
  152. package/src/cli/main.ts +522 -0
  153. package/src/cli/output.ts +106 -0
  154. package/src/cli/parser.ts +376 -0
  155. package/src/cli/presenter.ts +212 -0
  156. package/src/cli/service-metadata.ts +134 -0
  157. package/src/cli/spawn-service.ts +326 -0
  158. package/src/css.d.ts +4 -0
  159. package/src/gallery-web/app.ts +1581 -0
  160. package/src/gallery-web/export-menu.ts +121 -0
  161. package/src/gallery-web/export.ts +112 -0
  162. package/src/gallery-web/favicon.ts +54 -0
  163. package/src/gallery-web/frame/entries/chart.ts +6 -0
  164. package/src/gallery-web/frame/entries/html.ts +6 -0
  165. package/src/gallery-web/frame/entries/markdown.ts +6 -0
  166. package/src/gallery-web/frame/entries/mermaid.ts +6 -0
  167. package/src/gallery-web/frame/entries/svg.ts +6 -0
  168. package/src/gallery-web/frame/entries/tsx.ts +6 -0
  169. package/src/gallery-web/frame/frame-payload.ts +91 -0
  170. package/src/gallery-web/frame/renderer-validation.ts +13 -0
  171. package/src/gallery-web/frame/renderers/chart.ts +182 -0
  172. package/src/gallery-web/frame/renderers/dompurify-shim.ts +112 -0
  173. package/src/gallery-web/frame/renderers/html.ts +48 -0
  174. package/src/gallery-web/frame/renderers/markdown.ts +81 -0
  175. package/src/gallery-web/frame/renderers/mermaid.ts +120 -0
  176. package/src/gallery-web/frame/renderers/registry.ts +260 -0
  177. package/src/gallery-web/frame/renderers/svg.ts +393 -0
  178. package/src/gallery-web/frame/renderers/tsx.ts +61 -0
  179. package/src/gallery-web/frame/runtime.ts +501 -0
  180. package/src/gallery-web/frame/styles/artifact.css +8424 -0
  181. package/src/gallery-web/frame/styles/frame.css +183 -0
  182. package/src/gallery-web/frame/styles/html-source.css +23 -0
  183. package/src/gallery-web/frame/view-box.ts +33 -0
  184. package/src/gallery-web/frame-html.ts +72 -0
  185. package/src/gallery-web/index.html +104 -0
  186. package/src/gallery-web/session.ts +107 -0
  187. package/src/gallery-web/sse-client.ts +212 -0
  188. package/src/gallery-web/styles/app.css +420 -0
  189. package/src/gallery-web/styles/tokens.css +112 -0
  190. package/src/gallery-web/styles/verdict.css +186 -0
  191. package/src/gallery-web/swap.ts +64 -0
  192. package/src/gallery-web/theme.ts +40 -0
  193. package/src/gallery-web/view-state.ts +93 -0
  194. package/src/harness-adapters/claude-code/README.md +10 -0
  195. package/src/harness-adapters/claude-code/facet.sh +4 -0
  196. package/src/harness-adapters/codex/README.md +10 -0
  197. package/src/harness-adapters/codex/facet.sh +4 -0
  198. package/src/harness-adapters/mcp/README.md +13 -0
  199. package/src/harness-adapters/mcp/cli-bridge.ts +216 -0
  200. package/src/harness-adapters/mcp/main.ts +15 -0
  201. package/src/harness-adapters/mcp/server.ts +164 -0
  202. package/src/harness-adapters/mcp/tool-schemas.ts +53 -0
  203. package/src/harness-adapters/opencode/README.md +10 -0
  204. package/src/harness-adapters/opencode/facet.sh +4 -0
  205. package/src/runtime/compiled-entrypoints.ts +69 -0
  206. package/src/service/dispatcher.ts +717 -0
  207. package/src/service/export.ts +218 -0
  208. package/src/service/http-utils.ts +55 -0
  209. package/src/service/lexical/expectations.ts +210 -0
  210. package/src/service/lifecycle/idle-controller.ts +125 -0
  211. package/src/service/lifecycle/orphan-cleanup.ts +128 -0
  212. package/src/service/lifecycle/process-lock.ts +235 -0
  213. package/src/service/main.ts +136 -0
  214. package/src/service/process.ts +240 -0
  215. package/src/service/router-guards.ts +239 -0
  216. package/src/service/router.ts +627 -0
  217. package/src/service/security/auth.ts +168 -0
  218. package/src/service/security/host-origin.ts +138 -0
  219. package/src/service/security/http-guards.ts +13 -0
  220. package/src/service/security/leases.ts +182 -0
  221. package/src/service/security/token-store.ts +138 -0
  222. package/src/service/server.ts +356 -0
  223. package/src/service/store/database.ts +61 -0
  224. package/src/service/store/evidence-retention.ts +234 -0
  225. package/src/service/store/migrations.ts +167 -0
  226. package/src/service/store/repository-lifecycle.ts +121 -0
  227. package/src/service/store/repository.ts +732 -0
  228. package/src/service/store/schema.ts +218 -0
  229. package/src/service/stored-verdict.ts +97 -0
  230. package/src/service/stream.ts +301 -0
  231. package/src/service/verdict-enrichment.ts +45 -0
  232. package/src/shared/build/frame-bundle-plugins.ts +61 -0
  233. package/src/shared/build-mode.ts +28 -0
  234. package/src/shared/config/evidence-read.ts +98 -0
  235. package/src/shared/config/limits.ts +56 -0
  236. package/src/shared/config/paths.ts +96 -0
  237. package/src/shared/contracts/artifact-types.ts +2 -0
  238. package/src/shared/contracts/artifact.ts +98 -0
  239. package/src/shared/contracts/commands/_shared.ts +59 -0
  240. package/src/shared/contracts/commands/guards.ts +86 -0
  241. package/src/shared/contracts/commands/index.ts +204 -0
  242. package/src/shared/contracts/commands/names.ts +35 -0
  243. package/src/shared/contracts/commands/requests.ts +149 -0
  244. package/src/shared/contracts/commands/results.ts +200 -0
  245. package/src/shared/contracts/envelope.ts +140 -0
  246. package/src/shared/contracts/events.ts +41 -0
  247. package/src/shared/contracts/observed-counts.ts +19 -0
  248. package/src/shared/contracts/renderers.ts +6 -0
  249. package/src/shared/contracts/validation.ts +296 -0
  250. package/src/shared/errors/facet-error.ts +127 -0
  251. package/src/shared/errors/store-error.ts +68 -0
  252. package/src/shared/evidence-image.ts +37 -0
  253. package/src/shared/export.ts +31 -0
  254. package/src/shared/html/policy.ts +108 -0
  255. package/src/shared/html/style-vocabulary.ts +352 -0
  256. package/src/shared/logging/logger.ts +108 -0
  257. package/src/shared/logging/redact.ts +49 -0
  258. package/src/shared/security/frozen-csp.ts +13 -0
  259. package/src/shared/storage-version.ts +2 -0
  260. package/src/shared/tsx/execution.ts +29 -0
  261. package/src/shared/tsx/import-policy.ts +94 -0
  262. package/src/shared/util/dir-permissions.ts +94 -0
  263. package/src/shared/util/mermaid-nodes.ts +230 -0
  264. package/src/shared/util/process.ts +67 -0
  265. package/src/shared/util/time.ts +21 -0
  266. package/src/shared/version.ts +3 -0
  267. package/src/validation/sandbox/limits.ts +41 -0
  268. package/src/validation/sandbox/netns.ts +177 -0
  269. package/src/validation/tier0/chart.ts +177 -0
  270. package/src/validation/tier0/dom-shim.ts +54 -0
  271. package/src/validation/tier0/html.ts +408 -0
  272. package/src/validation/tier0/markdown.ts +285 -0
  273. package/src/validation/tier0/mermaid.ts +98 -0
  274. package/src/validation/tier0/runner.ts +504 -0
  275. package/src/validation/tier0/svg.ts +321 -0
  276. package/src/validation/tier0/tsx/allowlist-resolver.ts +77 -0
  277. package/src/validation/tier0/tsx/ast-policy-capabilities.ts +238 -0
  278. package/src/validation/tier0/tsx/ast-policy-shared.ts +71 -0
  279. package/src/validation/tier0/tsx/ast-policy.ts +181 -0
  280. package/src/validation/tier0/tsx/compiler.ts +156 -0
  281. package/src/validation/tier0/worker-dispatch.ts +211 -0
  282. package/src/validation/tier0/worker-entry.ts +96 -0
  283. package/src/validation/tier0/worker-input.ts +75 -0
  284. package/src/validation/tier1/browser-process.ts +147 -0
  285. package/src/validation/tier1/cdp-pipe.ts +281 -0
  286. package/src/validation/tier1/entries/chart.ts +5 -0
  287. package/src/validation/tier1/entries/html.ts +6 -0
  288. package/src/validation/tier1/entries/markdown.ts +5 -0
  289. package/src/validation/tier1/entries/mermaid.ts +5 -0
  290. package/src/validation/tier1/entries/svg.ts +5 -0
  291. package/src/validation/tier1/entries/tsx.ts +5 -0
  292. package/src/validation/tier1/frame-target.ts +162 -0
  293. package/src/validation/tier1/harness-entry.ts +261 -0
  294. package/src/validation/tier1/harness.ts +215 -0
  295. package/src/validation/tier1/isolated-probe.ts +94 -0
  296. package/src/validation/tier1/launcher.ts +177 -0
  297. package/src/validation/tier1/limits.ts +80 -0
  298. package/src/validation/tier1/nonce.ts +17 -0
  299. package/src/validation/tier1/protocol-probe.ts +519 -0
  300. package/src/validation/tier1/runner.ts +1122 -0
  301. package/src/validation/tier1/verdict.ts +246 -0
  302. package/src/validation/tier1/webp.ts +69 -0
  303. package/templates/README.md +88 -0
  304. package/templates/bar-compare.vl.json +63 -0
  305. package/templates/capacity-report.tsx +102 -0
  306. package/templates/decision-record.md +24 -0
  307. package/templates/deployment-state.mmd +40 -0
  308. package/templates/exemplar.md +91 -0
  309. package/templates/facet-story.tsx +799 -0
  310. package/templates/fleet-dashboard.html +141 -0
  311. package/templates/html-release-ledger.html +91 -0
  312. package/templates/html-status-report.html +114 -0
  313. package/templates/incident-console.tsx +147 -0
  314. package/templates/legion-boundaries.mmd +23 -0
  315. package/templates/legion-flow.mmd +15 -0
  316. package/templates/legion-sequence.mmd +14 -0
  317. package/templates/legion-state.mmd +7 -0
  318. package/templates/metric-card.svg +29 -0
  319. package/templates/observability-map.svg +101 -0
  320. package/templates/pipeline-audit.md +108 -0
  321. package/templates/release-metrics.vl.json +98 -0
  322. package/templates/service-topology.mmd +47 -0
  323. package/templates/status-report.md +32 -0
  324. package/templates/system-map.svg +53 -0
  325. package/templates/timeseries.vl.json +71 -0
  326. package/templates/tsx-interactive-counter.tsx +19 -0
  327. package/templates/tsx-status-report.tsx +31 -0
@@ -0,0 +1,183 @@
1
+ html,
2
+ body {
3
+ margin: 0;
4
+ height: 100%;
5
+ background: var(--facet-frame-surface);
6
+ color: var(--facet-frame-text);
7
+ font:
8
+ 14px/1.55 ui-sans-serif,
9
+ system-ui,
10
+ -apple-system,
11
+ "Segoe UI",
12
+ Roboto,
13
+ sans-serif;
14
+ }
15
+
16
+ :root {
17
+ --facet-frame-surface: #151823;
18
+ --facet-frame-stage: #151823;
19
+ --facet-frame-text: #c8d3f5;
20
+ --facet-frame-muted: #a9b8e8;
21
+ --facet-frame-faint: #737aa2;
22
+ --facet-frame-focus: #82aaff;
23
+ --facet-frame-link: #82aaff;
24
+ --facet-frame-code: #c3e88d;
25
+ --facet-frame-code-surface: #1e2030;
26
+ --facet-frame-rule: #2f334d;
27
+ --facet-frame-quote: #a9b8e8;
28
+ --facet-frame-quote-rule: #444a73;
29
+ }
30
+
31
+ [data-theme="winter"] {
32
+ --facet-frame-surface: #ffffff;
33
+ --facet-frame-stage: #f8fafc;
34
+ --facet-frame-text: #172033;
35
+ --facet-frame-muted: #334155;
36
+ --facet-frame-faint: #475569;
37
+ --facet-frame-focus: #075985;
38
+ --facet-frame-link: #075985;
39
+ --facet-frame-code: #166534;
40
+ --facet-frame-code-surface: #f1f5f9;
41
+ --facet-frame-rule: #cbd5e1;
42
+ --facet-frame-quote: #334155;
43
+ --facet-frame-quote-rule: #64748b;
44
+ }
45
+
46
+ #artifact {
47
+ box-sizing: border-box;
48
+ height: 100%;
49
+ margin: 0;
50
+ padding: 16px;
51
+ overflow: auto;
52
+ }
53
+
54
+ /*
55
+ * Standalone diagrams (mermaid/svg/chart) center on both axes when
56
+ * the rendered root fits the stage. `safe` is load-bearing: it falls
57
+ * back to start-aligned scrolling the moment the root overflows, so
58
+ * zoomed-in or naturally oversized content stays 100% reachable by
59
+ * scroll instead of clipping unreachable off-screen (the regression
60
+ * a plain `center` reintroduces).
61
+ */
62
+ #artifact[data-facet-artifact-type="mermaid"],
63
+ #artifact[data-facet-artifact-type="svg"],
64
+ #artifact[data-facet-artifact-type="chart"] {
65
+ display: flex;
66
+ justify-content: safe center;
67
+ align-items: safe center;
68
+ }
69
+
70
+ /*
71
+ * Markdown reads top-down (no vertical centering) but should not
72
+ * stretch to an unreadable line length at wide viewports: cap the
73
+ * column at a ~92ch measure and center it horizontally. Below that
74
+ * measure the calc() collapses to the original 16px padding, so
75
+ * narrow viewports are unaffected.
76
+ */
77
+ #artifact[data-facet-artifact-type="markdown"] {
78
+ padding-inline: max(16px, calc((100% - 92ch) / 2));
79
+ }
80
+
81
+ /*
82
+ * Native dashboard artifacts (html, interactive tsx) read top-down
83
+ * like markdown — vertical stays start-aligned — but unlike markdown
84
+ * their width is whatever the fixture authored (often a fixed-width
85
+ * `max-w-*` container), not a fluid readable column. Left unstyled,
86
+ * that narrow content sits pinned to the container's left edge,
87
+ * stranding most of a wide desktop stage as dead space.
88
+ *
89
+ * The centering has to land on the renderer-ROOT element
90
+ * (`.facet-html-root` / `#facet-tsx-mount`), not `#artifact` itself:
91
+ * `renderHtml`/`renderTsx` always mount a single full-width wrapper
92
+ * as `#artifact`'s only child, and the fixture's own narrow content
93
+ * (e.g. `<main class="max-w-2xl">`) is a GRANDCHILD of `#artifact`
94
+ * inside that wrapper — centering `#artifact`'s single full-width
95
+ * child does nothing. `safe center` on the horizontal axis only —
96
+ * the same fallback-to-start mechanism the standalone-diagram rule
97
+ * above uses — centers content that fits and never clips content
98
+ * wider than the stage (it start-aligns and stays reachable by
99
+ * scroll instead).
100
+ */
101
+ #artifact[data-facet-artifact-type="html"] > [data-facet-renderer-root],
102
+ #artifact[data-facet-artifact-type="tsx"] > [data-facet-renderer-root] {
103
+ display: flex;
104
+ justify-content: safe center;
105
+ align-items: flex-start;
106
+ min-height: 100%;
107
+ }
108
+
109
+ #artifact > svg {
110
+ display: block;
111
+ width: fit-content;
112
+ max-height: none;
113
+ height: auto;
114
+ /* Flex items shrink by default (min-width: auto); without this a
115
+ wide diagram would squeeze toward the flex container's width
116
+ instead of overflowing it — the exact jail regression `safe
117
+ center` above is meant to prevent. */
118
+ flex-shrink: 0;
119
+ }
120
+
121
+ #artifact > canvas,
122
+ #artifact > iframe {
123
+ display: block;
124
+ flex-shrink: 0;
125
+ }
126
+
127
+ #artifact [data-facet-diagram-region] {
128
+ display: block;
129
+ overflow: hidden;
130
+ outline: 1px solid transparent;
131
+ outline-offset: 2px;
132
+ }
133
+
134
+ #artifact [data-facet-diagram-region][data-facet-diagram-engaged="true"] {
135
+ outline-color: var(--facet-frame-focus);
136
+ }
137
+
138
+ #artifact [data-facet-diagram-region] > svg {
139
+ display: block;
140
+ max-width: none;
141
+ }
142
+
143
+ #artifact a {
144
+ color: var(--facet-frame-link);
145
+ }
146
+
147
+ #artifact code,
148
+ #artifact pre {
149
+ color: var(--facet-frame-code);
150
+ background: var(--facet-frame-code-surface);
151
+ border-radius: 4px;
152
+ }
153
+
154
+ #artifact code {
155
+ padding: 1px 4px;
156
+ }
157
+
158
+ #artifact pre {
159
+ padding: 10px;
160
+ overflow: auto;
161
+ }
162
+
163
+ #artifact table {
164
+ border-collapse: collapse;
165
+ }
166
+
167
+ #artifact th,
168
+ #artifact td {
169
+ padding: 4px 8px;
170
+ border: 1px solid var(--facet-frame-rule);
171
+ }
172
+
173
+ #artifact blockquote {
174
+ margin: 0 0 0 8px;
175
+ padding-left: 12px;
176
+ color: var(--facet-frame-quote);
177
+ border-left: 3px solid var(--facet-frame-quote-rule);
178
+ }
179
+
180
+ #artifact hr {
181
+ border: 0;
182
+ border-top: 1px solid var(--facet-frame-rule);
183
+ }
@@ -0,0 +1,23 @@
1
+ @import "tailwindcss" source(none);
2
+
3
+ @theme {
4
+ --color-legion-ink: var(--facet-frame-text);
5
+ --color-legion-muted: var(--facet-frame-muted);
6
+ --color-legion-cyan: var(--facet-frame-link);
7
+ --color-legion-paper: var(--facet-frame-surface);
8
+ --color-legion-line: var(--facet-frame-rule);
9
+ }
10
+
11
+ [data-theme="winter"] {
12
+ --color-legion-ink: var(--facet-frame-text);
13
+ --color-legion-muted: var(--facet-frame-muted);
14
+ --color-legion-cyan: var(--facet-frame-link);
15
+ --color-legion-paper: var(--facet-frame-surface);
16
+ --color-legion-line: var(--facet-frame-rule);
17
+ }
18
+
19
+ @plugin "daisyui" {
20
+ themes:
21
+ night --default,
22
+ winter;
23
+ }
@@ -0,0 +1,33 @@
1
+ export interface SvgViewBox {
2
+ readonly minX: number;
3
+ readonly minY: number;
4
+ readonly width: number;
5
+ readonly height: number;
6
+ }
7
+
8
+ export interface ViewportSize {
9
+ readonly width: number;
10
+ readonly height: number;
11
+ }
12
+
13
+ export interface NativeViewState {
14
+ readonly zoom: number;
15
+ readonly panX?: number;
16
+ readonly panY?: number;
17
+ }
18
+
19
+ export function applySvgViewBox(
20
+ original: SvgViewBox,
21
+ viewport: ViewportSize,
22
+ state: NativeViewState,
23
+ ): SvgViewBox {
24
+ const zoom = state.zoom;
25
+ const panX = state.panX ?? 0;
26
+ const panY = state.panY ?? 0;
27
+ return {
28
+ minX: original.minX - (panX * original.width) / viewport.width / zoom,
29
+ minY: original.minY - (panY * original.height) / viewport.height / zoom,
30
+ width: original.width / zoom,
31
+ height: original.height / zoom,
32
+ };
33
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Pure frame-HTML helpers — document + attribute generation, hostname
3
+ * guard. No DOM mutation; the shell's createArtifactFrame
4
+ * calls these to assemble the iframe configuration.
5
+ *
6
+ * Kept in a separate file from `app.ts` so frame-document invariants — CSP
7
+ * exactness and artifact-byte absence — are testable without the DOM-touching
8
+ * surface.
9
+ */
10
+
11
+ import { galleryDataTheme, type ResolvedGalleryTheme } from "./theme";
12
+
13
+ /**
14
+ * Frame element attributes. The shell applies these to every iframe it
15
+ * creates.
16
+ */
17
+ export interface FrameAttributes {
18
+ readonly referrerpolicy: "no-referrer";
19
+ readonly allow: "";
20
+ readonly title: string;
21
+ readonly src: string;
22
+ }
23
+
24
+ export function buildFrameAttributes(src = "/gallery/frame"): FrameAttributes {
25
+ return {
26
+ referrerpolicy: "no-referrer",
27
+ allow: "",
28
+ title: "facet artifact frame",
29
+ src,
30
+ };
31
+ }
32
+
33
+ export function buildFrameDocument(options: {
34
+ artifactType: string;
35
+ runtimeUrl: string;
36
+ theme: ResolvedGalleryTheme;
37
+ }): string {
38
+ const { artifactType, runtimeUrl, theme } = options;
39
+ const escapedRuntimeUrl = runtimeUrl
40
+ .replaceAll("&", "&amp;")
41
+ .replaceAll('"', "&quot;")
42
+ .replaceAll("<", "&lt;")
43
+ .replaceAll(">", "&gt;");
44
+ return (
45
+ `<!doctype html><html data-theme="${galleryDataTheme(theme)}"><head>` +
46
+ `<meta charset="utf-8"><link rel="stylesheet" href="/gallery/frame/frame.css">` +
47
+ (artifactType === "html" || artifactType === "tsx"
48
+ ? `<link rel="stylesheet" href="/gallery/frame/artifact.css">`
49
+ : "") +
50
+ "</head><body>" +
51
+ `<main id="artifact" data-facet-artifact-type="${artifactType}"></main>` +
52
+ `<script type="module" src="${escapedRuntimeUrl}"></script>` +
53
+ "</body></html>"
54
+ );
55
+ }
56
+
57
+ /**
58
+ * The shell trusts the loopback only. Anything else is a DNS-rebind or
59
+ * a same-origin-policy escape; the guard fires BEFORE the SSE stream
60
+ * or the iframe is touched.
61
+ */
62
+ export function isLoopbackHostname(hostname: string): boolean {
63
+ return hostname === "127.0.0.1";
64
+ }
65
+
66
+ export function assertLoopbackHostname(hostname: string): void {
67
+ if (!isLoopbackHostname(hostname)) {
68
+ throw new Error(
69
+ `Refusing to run gallery shell: hostname must be 127.0.0.1 (got: ${JSON.stringify(hostname)})`,
70
+ );
71
+ }
72
+ }
@@ -0,0 +1,104 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>facet gallery</title>
7
+ <link id="facet-favicon" rel="icon" />
8
+ <link rel="stylesheet" href="./styles/tokens.css" />
9
+ <link rel="stylesheet" href="./styles/verdict.css" />
10
+ <link rel="stylesheet" href="./styles/app.css" />
11
+ </head>
12
+ <body>
13
+ <div id="facet-shell">
14
+ <header id="facet-status">
15
+ <span id="facet-mark" aria-hidden="true">◆</span>
16
+ <span class="title" id="facet-title">facet</span>
17
+ <span class="sep" aria-hidden="true"></span>
18
+ <span id="facet-artifact-title"></span>
19
+ <span class="revision" id="facet-revision">—</span>
20
+ <span class="status-line" id="facet-status-line">idle</span>
21
+ <!--
22
+ Verdict badge. JS wiring: set data-status to the FULL wire
23
+ enum, text to status.split(":")[0], and the tier span to
24
+ `· T${verdict.tier}` (empty while unverified). The badge
25
+ shows read-back results only — the shell never derives one.
26
+ -->
27
+ <span class="facet-verdict facet-verdict--sm" id="facet-verdict" data-status="unverified"
28
+ >unverified<span class="tier"></span
29
+ ></span>
30
+ </header>
31
+ <!-- Evidence strip — unhidden when a verdict is loaded. -->
32
+ <section id="facet-evidence" hidden>
33
+ <span class="label">OBSERVED</span>
34
+ <span id="facet-evidence-counts"></span>
35
+ <span class="label">CHANNELS</span>
36
+ <span class="facet-channels" id="facet-evidence-channels"></span>
37
+ <span class="divergence" id="facet-evidence-divergence"></span>
38
+ <span class="binding">bound to <span class="sha" id="facet-evidence-sha"></span></span>
39
+ </section>
40
+ <main id="facet-canvas">
41
+ <div id="facet-swapbar" hidden><div class="bar"></div></div>
42
+ <div id="facet-empty">
43
+ <span class="glyph" aria-hidden="true">◌</span>
44
+ <span class="head">No artifact.</span>
45
+ <span class="sub">Publish one to display it here.</span>
46
+ <span class="cmd"
47
+ ><span class="p">$</span> facet publish ./artifact.md
48
+ <span class="p">&amp;&amp;</span> facet open</span
49
+ >
50
+ </div>
51
+ <div id="facet-expired" hidden>
52
+ <span class="glyph" aria-hidden="true">✗</span>
53
+ <span class="head">Session expired.</span>
54
+ <span class="sub">The display lease is no longer valid.</span>
55
+ <span class="cmd"><span class="p">$</span> facet open</span>
56
+ </div>
57
+ <!-- The iframe is created + appended by app.ts. JS wiring:
58
+ hide #facet-empty whenever a frame is mounted. -->
59
+ </main>
60
+ <footer id="facet-controls">
61
+ <span id="facet-live" data-state="idle"
62
+ ><span class="dot" aria-hidden="true">●</span
63
+ ><span id="facet-live-label">idle</span></span
64
+ >
65
+ <span id="facet-error" role="status"></span>
66
+ <span class="spacer"></span>
67
+ <button
68
+ type="button"
69
+ id="facet-panzoom-toggle"
70
+ aria-label="toggle pan and zoom"
71
+ aria-pressed="false"
72
+ >
73
+ pan/zoom
74
+ </button>
75
+ <button type="button" id="facet-zoom-out" aria-label="zoom out">−</button>
76
+ <button type="button" id="facet-zoom-reset" aria-label="reset zoom">100%</button>
77
+ <button type="button" id="facet-zoom-in" aria-label="zoom in">+</button>
78
+ <button type="button" id="facet-theme-toggle" aria-label="theme: system">
79
+ theme: system
80
+ </button>
81
+ <div id="facet-export" class="facet-export">
82
+ <button type="button" id="facet-export-toggle" aria-haspopup="menu" aria-expanded="false">
83
+ export
84
+ </button>
85
+ <div id="facet-export-menu" role="menu" hidden>
86
+ <button type="button" id="facet-export-source" role="menuitem">source</button>
87
+ <button
88
+ type="button"
89
+ id="facet-export-render"
90
+ role="menuitem"
91
+ disabled
92
+ title="no stored render"
93
+ >
94
+ render
95
+ </button>
96
+ <button type="button" id="facet-export-sidecar" role="menuitem">sidecar</button>
97
+ </div>
98
+ </div>
99
+ <button type="button" id="facet-fullscreen" aria-label="fullscreen">fullscreen</button>
100
+ </footer>
101
+ </div>
102
+ <script type="module" src="./app.ts"></script>
103
+ </body>
104
+ </html>
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Session persistence for the gallery shell.
3
+ *
4
+ * The gallery's bootstrap token is single-use: once the shell exchanges
5
+ * it for a lease, the URL fragment is dead. A tab refresh re-submits
6
+ * the consumed token, the service rejects it, and the shell dies.
7
+ *
8
+ * To survive refresh, the shell persists the granted lease to
9
+ * `sessionStorage` (same-origin, per-tab, survives F5, never reaches the
10
+ * URL) AFTER a successful bootstrap exchange. On load the order is:
11
+ * 1. If the URL still carries a fresh `bootstrap=…` token, exchange it.
12
+ * 2. Otherwise, look up the persisted session and validate it against
13
+ * the service (cheap authed source request). A live lease re-renders
14
+ * the artifact exactly as before; an expired or service-restart
15
+ * lease renders the typed "session expired" state.
16
+ *
17
+ * The lease manager is in-memory: a service restart invalidates every
18
+ * outstanding lease. The persisted session therefore reports a TTL
19
+ * window — if the service came back within the lease's nominal expiry
20
+ * the session is still live; otherwise it is honestly expired and the
21
+ * shell tells the user to run `facet open` again.
22
+ *
23
+ * The persisted payload carries the bearer authorization plus the lease
24
+ * id. They are scoped to the same loopback origin and never leave the
25
+ * tab; replacing the tab closes the channel. This matches the existing
26
+ * security rule that leases stay header-only (`X-Gallery-Lease`) and
27
+ * never reach a URL.
28
+ */
29
+
30
+ import { isGalleryThemeMode, type GalleryThemeMode } from "./theme";
31
+
32
+ export const GALLERY_SESSION_STORAGE_KEY = "facet:gallery-session";
33
+
34
+ export interface GallerySession {
35
+ readonly authorization: string;
36
+ readonly artifactId: string;
37
+ readonly revisionSha: string;
38
+ readonly lease: { readonly leaseId: string; readonly expiresAt: number };
39
+ readonly theme: GalleryThemeMode;
40
+ }
41
+
42
+ /**
43
+ * Minimal `sessionStorage`-shaped surface used by the persistence helpers.
44
+ * Production callers pass `window.sessionStorage`; tests pass an in-memory
45
+ * shim so the helpers stay free of any browser global reference.
46
+ */
47
+ export interface SessionStorageLike {
48
+ getItem(key: string): string | null;
49
+ setItem(key: string, value: string): void;
50
+ removeItem(key: string): void;
51
+ clear(): void;
52
+ }
53
+
54
+ export function persistSession(storage: SessionStorageLike, session: GallerySession): void {
55
+ storage.setItem(GALLERY_SESSION_STORAGE_KEY, JSON.stringify(session));
56
+ }
57
+
58
+ export function clearSession(storage: SessionStorageLike): void {
59
+ storage.removeItem(GALLERY_SESSION_STORAGE_KEY);
60
+ }
61
+
62
+ export function readPersistedSession(storage: SessionStorageLike): GallerySession | null {
63
+ const raw = storage.getItem(GALLERY_SESSION_STORAGE_KEY);
64
+ if (raw === null || raw.length === 0) return null;
65
+ let parsed: unknown;
66
+ try {
67
+ parsed = JSON.parse(raw);
68
+ } catch {
69
+ return null;
70
+ }
71
+ if (!isGallerySession(parsed)) return null;
72
+ return {
73
+ authorization: parsed.authorization,
74
+ artifactId: parsed.artifactId,
75
+ revisionSha: parsed.revisionSha,
76
+ lease: parsed.lease,
77
+ theme: isGalleryThemeMode(parsed.theme) ? parsed.theme : "system",
78
+ };
79
+ }
80
+
81
+ export type SessionValidation =
82
+ | { readonly valid: true; readonly session: GallerySession }
83
+ | { readonly valid: false; readonly reason: "expired" | "missing" };
84
+
85
+ export function validatePersistedSession(
86
+ session: GallerySession,
87
+ now: number = Date.now(),
88
+ ): SessionValidation {
89
+ if (session.lease.expiresAt <= now) return { valid: false, reason: "expired" };
90
+ return { valid: true, session };
91
+ }
92
+
93
+ function isGallerySession(
94
+ value: unknown,
95
+ ): value is Omit<GallerySession, "theme"> & { readonly theme?: unknown } {
96
+ if (value === null || typeof value !== "object") return false;
97
+ const record = value as Record<string, unknown>;
98
+ if (typeof record["authorization"] !== "string") return false;
99
+ if (typeof record["artifactId"] !== "string") return false;
100
+ if (typeof record["revisionSha"] !== "string") return false;
101
+ const lease = record["lease"];
102
+ if (lease === null || typeof lease !== "object") return false;
103
+ const leaseRecord = lease as Record<string, unknown>;
104
+ if (typeof leaseRecord["leaseId"] !== "string") return false;
105
+ if (typeof leaseRecord["expiresAt"] !== "number") return false;
106
+ return true;
107
+ }