@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,68 @@
1
+ /**
2
+ * Store-layer typed error.
3
+ *
4
+ * `FacetStoreError` extends `FacetError` so the store's wire-relevant
5
+ * codes flow through `FacetError.from()` unchanged. The class lives
6
+ * here (not in `service/store/`) so both `facet-error.ts` and the store
7
+ * can reference it without an upward dependency from `shared/` to
8
+ * `service/`. The bridge is the inheritance: `instanceof FacetError`
9
+ * matches a `FacetStoreError`, the typed code + `retryable` + `details`
10
+ * are preserved, and the router's `statusFor()` arms become live.
11
+ */
12
+
13
+ import { FacetError, type FacetErrorCode, type FacetErrorOptions } from "./facet-error";
14
+
15
+ export type StoreErrorCode = Extract<
16
+ FacetErrorCode,
17
+ | "database_corrupt"
18
+ | "database_busy"
19
+ | "disk_full"
20
+ | "duplicate_revision"
21
+ | "foreign_key"
22
+ | "immutable_revision"
23
+ | "migration_failed"
24
+ | "invalid_artifact_type"
25
+ | "constraint"
26
+ | "revision_capacity_pinned"
27
+ >;
28
+
29
+ export class FacetStoreError extends FacetError {
30
+ override readonly name = "FacetStoreError" as const;
31
+
32
+ constructor(code: StoreErrorCode, message: string, options: FacetErrorOptions = {}) {
33
+ super(code, message, options);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Coerce any thrown value into a typed store error. Recognizes a
39
+ * pre-existing `FacetStoreError`; for a generic `Error` it string-matches
40
+ * the common SQLite failure messages to a specific store code. Any
41
+ * unrecognized error falls back to `constraint` (the generic catch-all
42
+ * that surfaces as a 409 on the wire).
43
+ */
44
+ export function asStoreError(error: unknown): FacetStoreError {
45
+ if (error instanceof FacetStoreError) return error;
46
+ const message = error instanceof Error ? error.message : String(error);
47
+ const lower = message.toLowerCase();
48
+ if (
49
+ lower.includes("not a database") ||
50
+ lower.includes("malformed") ||
51
+ lower.includes("corrupt")
52
+ ) {
53
+ return new FacetStoreError("database_corrupt", message, { cause: error });
54
+ }
55
+ if (lower.includes("busy") || lower.includes("locked")) {
56
+ return new FacetStoreError("database_busy", message, { cause: error });
57
+ }
58
+ if (lower.includes("no space") || lower.includes("enospc") || lower.includes("disk full")) {
59
+ return new FacetStoreError("disk_full", message, { cause: error });
60
+ }
61
+ if (lower.includes("foreign key")) {
62
+ return new FacetStoreError("foreign_key", message, { cause: error });
63
+ }
64
+ if (lower.includes("unique constraint")) {
65
+ return new FacetStoreError("duplicate_revision", message, { cause: error });
66
+ }
67
+ return new FacetStoreError("constraint", message, { cause: error });
68
+ }
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+
3
+ export const EvidenceImageFormatSchema = z.enum(["png", "webp"]);
4
+ export type EvidenceImageFormat = z.infer<typeof EvidenceImageFormatSchema>;
5
+
6
+ const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
7
+
8
+ export function sniffEvidenceImageFormat(bytes: Uint8Array): EvidenceImageFormat | null {
9
+ if (PNG_SIGNATURE.every((value, index) => bytes[index] === value)) return "png";
10
+ if (
11
+ bytes.length >= 12 &&
12
+ bytes[0] === 0x52 &&
13
+ bytes[1] === 0x49 &&
14
+ bytes[2] === 0x46 &&
15
+ bytes[3] === 0x46 &&
16
+ bytes[8] === 0x57 &&
17
+ bytes[9] === 0x45 &&
18
+ bytes[10] === 0x42 &&
19
+ bytes[11] === 0x50
20
+ )
21
+ return "webp";
22
+ return null;
23
+ }
24
+
25
+ export function mediaTypeForEvidenceImage(format: EvidenceImageFormat): "image/png" | "image/webp" {
26
+ return format === "png" ? "image/png" : "image/webp";
27
+ }
28
+
29
+ export function evidenceImageFormatForMediaType(mediaType: string): EvidenceImageFormat | null {
30
+ if (mediaType === "image/png") return "png";
31
+ if (mediaType === "image/webp") return "webp";
32
+ return null;
33
+ }
34
+
35
+ export function extensionForEvidenceImage(format: EvidenceImageFormat): ".png" | ".webp" {
36
+ return format === "png" ? ".png" : ".webp";
37
+ }
@@ -0,0 +1,31 @@
1
+ import type { ArtifactType } from "./contracts/artifact-types";
2
+ import type { ExportFormat, ExportSidecar } from "./contracts/commands";
3
+ import { ExportSidecarSchema } from "./contracts/commands/results";
4
+ import { extensionForEvidenceImage, type EvidenceImageFormat } from "./evidence-image";
5
+
6
+ const SOURCE_EXTENSION_BY_ARTIFACT = {
7
+ markdown: ".md",
8
+ mermaid: ".md",
9
+ svg: ".svg",
10
+ chart: ".json",
11
+ html: ".html",
12
+ tsx: ".tsx",
13
+ } as const satisfies Record<ArtifactType, ".md" | ".svg" | ".json" | ".html" | ".tsx">;
14
+
15
+ export function extensionForExport(
16
+ format: ExportFormat,
17
+ artifactType: ArtifactType,
18
+ renderFormat?: EvidenceImageFormat,
19
+ ): ".md" | ".svg" | ".json" | ".html" | ".tsx" | ".png" | ".webp" {
20
+ return format === "render"
21
+ ? extensionForEvidenceImage(renderFormat ?? "png")
22
+ : SOURCE_EXTENSION_BY_ARTIFACT[artifactType];
23
+ }
24
+
25
+ export function sidecarFilenameForArtifact(artifactPath: string): string {
26
+ return `${artifactPath}.facet.json`;
27
+ }
28
+
29
+ export function buildExportSidecar(input: ExportSidecar): ExportSidecar {
30
+ return ExportSidecarSchema.parse(input);
31
+ }
@@ -0,0 +1,108 @@
1
+ export const HTML_DENIED_ELEMENTS = [
2
+ "script",
3
+ "iframe",
4
+ "object",
5
+ "embed",
6
+ "form",
7
+ "link",
8
+ "meta",
9
+ "base",
10
+ "style",
11
+ ] as const;
12
+
13
+ export const HTML_STRUCTURAL_GROUPS = {
14
+ headings: ["h1", "h2", "h3", "h4", "h5", "h6"],
15
+ tables: ["table"],
16
+ lists: ["ul", "ol"],
17
+ images: ["img"],
18
+ canvases: ["canvas"],
19
+ } as const;
20
+
21
+ export const HTML_URL_BEARING_ATTRIBUTES = {
22
+ img: ["src", "srcset"],
23
+ source: ["srcset"],
24
+ a: ["href"],
25
+ } as const;
26
+
27
+ export const HTML_ALLOWED_ANCHOR_SCHEMES = ["https:", "mailto:"] as const;
28
+ export const HTML_ALLOWED_IMAGE_SCHEMES = ["data:", "https:"] as const;
29
+
30
+ type HtmlUrlBearingElement = keyof typeof HTML_URL_BEARING_ATTRIBUTES;
31
+
32
+ function htmlUrlBearingElement(name: string): HtmlUrlBearingElement | null {
33
+ const normalized = name.toLowerCase();
34
+ return normalized in HTML_URL_BEARING_ATTRIBUTES ? (normalized as HtmlUrlBearingElement) : null;
35
+ }
36
+
37
+ export function isHtmlDeniedElement(name: string): boolean {
38
+ return (HTML_DENIED_ELEMENTS as readonly string[]).includes(name.toLowerCase());
39
+ }
40
+
41
+ export function isHtmlUrlBearingAttribute(elementName: string, attributeName: string): boolean {
42
+ const element = htmlUrlBearingElement(elementName);
43
+ return (
44
+ element !== null &&
45
+ HTML_URL_BEARING_ATTRIBUTES[element].includes(attributeName.toLowerCase() as never)
46
+ );
47
+ }
48
+
49
+ export function isHtmlUrlAttributeName(attributeName: string): boolean {
50
+ const normalized = attributeName.toLowerCase();
51
+ return Object.values(HTML_URL_BEARING_ATTRIBUTES).some((attributes) =>
52
+ attributes.includes(normalized as never),
53
+ );
54
+ }
55
+
56
+ export function isHtmlEventHandlerAttribute(name: string): boolean {
57
+ return name.toLowerCase().startsWith("on");
58
+ }
59
+
60
+ export function isHtmlInlineStyleAttribute(name: string): boolean {
61
+ return name.toLowerCase() === "style";
62
+ }
63
+
64
+ export function isAllowedHtmlUrl(
65
+ elementName: string,
66
+ attributeName: string,
67
+ value: string,
68
+ ): boolean {
69
+ const element = htmlUrlBearingElement(elementName);
70
+ if (element === null || !isHtmlUrlBearingAttribute(element, attributeName)) return false;
71
+ const trimmed = value.trim();
72
+ if (trimmed.startsWith("//")) return false;
73
+ let url: URL;
74
+ try {
75
+ url = new URL(trimmed, "https://facet.invalid/");
76
+ } catch {
77
+ return false;
78
+ }
79
+ const scheme = url.protocol.toLowerCase();
80
+ switch (element) {
81
+ case "img":
82
+ case "source":
83
+ if (scheme === "data:") return isImageDataUrl(url);
84
+ return (HTML_ALLOWED_IMAGE_SCHEMES as readonly string[]).includes(scheme);
85
+ case "a":
86
+ return (HTML_ALLOWED_ANCHOR_SCHEMES as readonly string[]).includes(scheme);
87
+ default: {
88
+ const _: never = element;
89
+ return _;
90
+ }
91
+ }
92
+ }
93
+
94
+ function isImageDataUrl(url: URL): boolean {
95
+ const comma = url.pathname.indexOf(",");
96
+ if (comma < 0) return false;
97
+ const metadata = url.pathname.slice(0, comma);
98
+ const separator = metadata.indexOf(";");
99
+ const encodedMediaType = (separator < 0 ? metadata : metadata.slice(0, separator)).trim();
100
+ let mediaType: string;
101
+ try {
102
+ mediaType = decodeURIComponent(encodedMediaType).toLowerCase();
103
+ } catch {
104
+ return false;
105
+ }
106
+ const parts = mediaType.split("/");
107
+ return parts.length === 2 && parts[0] === "image" && parts[1]!.length > 0;
108
+ }
@@ -0,0 +1,352 @@
1
+ export const HTML_TAILWIND_CLASSES = [
2
+ "block",
3
+ "flex",
4
+ "grid",
5
+ "inline-flex",
6
+ "flex-col",
7
+ "flex-wrap",
8
+ "items-center",
9
+ "justify-between",
10
+ "justify-center",
11
+ "grid-cols-1",
12
+ "grid-cols-2",
13
+ "grid-cols-3",
14
+ "gap-2",
15
+ "gap-3",
16
+ "gap-4",
17
+ "gap-6",
18
+ "p-2",
19
+ "p-3",
20
+ "p-4",
21
+ "p-6",
22
+ "px-3",
23
+ "px-4",
24
+ "py-2",
25
+ "py-3",
26
+ "m-0",
27
+ "mt-2",
28
+ "mt-4",
29
+ "mb-2",
30
+ "mb-4",
31
+ "w-full",
32
+ "max-w-prose",
33
+ "max-w-2xl",
34
+ "text-xs",
35
+ "text-sm",
36
+ "text-base",
37
+ "text-lg",
38
+ "text-xl",
39
+ "text-2xl",
40
+ "font-medium",
41
+ "font-semibold",
42
+ "font-bold",
43
+ "leading-relaxed",
44
+ "text-left",
45
+ "text-center",
46
+ "text-right",
47
+ "text-legion-ink",
48
+ "text-legion-muted",
49
+ "text-legion-cyan",
50
+ "bg-legion-paper",
51
+ "bg-legion-ink",
52
+ "bg-legion-cyan",
53
+ "border",
54
+ "border-2",
55
+ "border-legion-line",
56
+ "rounded",
57
+ "rounded-box",
58
+ "overflow-x-auto",
59
+ "table",
60
+ "table-zebra",
61
+ ] as const;
62
+
63
+ export const HTML_DAISY_COMPONENTS = ["alert", "badge", "btn", "card", "stat", "table"] as const;
64
+
65
+ const HTML_DAISY_BUILD_COMPONENT_CLASSES = [
66
+ "alert",
67
+ "aura",
68
+ "avatar",
69
+ "badge",
70
+ "breadcrumbs",
71
+ "btn",
72
+ "calendar",
73
+ "card",
74
+ "carousel",
75
+ "chat",
76
+ "checkbox",
77
+ "collapse",
78
+ "countdown",
79
+ "diff",
80
+ "divider",
81
+ "dock",
82
+ "drawer",
83
+ "dropdown",
84
+ "fab",
85
+ "fieldset",
86
+ "file-input",
87
+ "filter",
88
+ "footer",
89
+ "hero",
90
+ "hover-3d",
91
+ "hover-gallery",
92
+ "indicator",
93
+ "input",
94
+ "kbd",
95
+ "label",
96
+ "link",
97
+ "list",
98
+ "loading",
99
+ "mask",
100
+ "mega-menu",
101
+ "menu",
102
+ "mockup-browser",
103
+ "modal",
104
+ "navbar",
105
+ "input-otp",
106
+ "progress",
107
+ "radial-progress",
108
+ "radio",
109
+ "range",
110
+ "rating",
111
+ "select",
112
+ "skeleton",
113
+ "stack",
114
+ "stat",
115
+ "stats",
116
+ "status",
117
+ "steps",
118
+ "swap",
119
+ "tab",
120
+ "table",
121
+ "textarea",
122
+ "text-rotate",
123
+ "timeline",
124
+ "toast",
125
+ "toggle",
126
+ "tooltip",
127
+ "validator",
128
+ ] as const;
129
+
130
+ const SPACING_VALUES = [
131
+ "0",
132
+ "0.5",
133
+ "1",
134
+ "1.5",
135
+ "2",
136
+ "2.5",
137
+ "3",
138
+ "3.5",
139
+ "4",
140
+ "5",
141
+ "6",
142
+ "7",
143
+ "8",
144
+ "9",
145
+ "10",
146
+ "11",
147
+ "12",
148
+ "14",
149
+ "16",
150
+ ] as const;
151
+
152
+ const SPACING_PREFIXES = [
153
+ "p",
154
+ "px",
155
+ "py",
156
+ "pt",
157
+ "pr",
158
+ "pb",
159
+ "pl",
160
+ "m",
161
+ "mx",
162
+ "my",
163
+ "mt",
164
+ "mr",
165
+ "mb",
166
+ "ml",
167
+ "gap",
168
+ "gap-x",
169
+ "gap-y",
170
+ ] as const;
171
+
172
+ const SEMANTIC_COLORS = [
173
+ "base-100",
174
+ "base-200",
175
+ "base-300",
176
+ "base-content",
177
+ "primary",
178
+ "primary-content",
179
+ "secondary",
180
+ "secondary-content",
181
+ "accent",
182
+ "accent-content",
183
+ "neutral",
184
+ "neutral-content",
185
+ "info",
186
+ "info-content",
187
+ "success",
188
+ "success-content",
189
+ "warning",
190
+ "warning-content",
191
+ "error",
192
+ "error-content",
193
+ ] as const;
194
+
195
+ const STANDARD_COLORS = [
196
+ "slate-300",
197
+ "slate-500",
198
+ "slate-700",
199
+ "gray-300",
200
+ "gray-500",
201
+ "gray-700",
202
+ "blue-300",
203
+ "blue-500",
204
+ "blue-700",
205
+ "green-300",
206
+ "green-500",
207
+ "green-700",
208
+ "amber-300",
209
+ "amber-500",
210
+ "amber-700",
211
+ "red-300",
212
+ "red-500",
213
+ "red-700",
214
+ "white",
215
+ "black",
216
+ ] as const;
217
+
218
+ const DAISY_COLOR_VARIANTS = [
219
+ "primary",
220
+ "secondary",
221
+ "accent",
222
+ "neutral",
223
+ "info",
224
+ "success",
225
+ "warning",
226
+ "error",
227
+ ] as const;
228
+
229
+ const DAISY_COLOR_COMPONENTS = ["alert", "badge", "btn", "checkbox", "radio", "toggle"] as const;
230
+
231
+ const DAISY_VARIANTS = [
232
+ "alert-soft",
233
+ "alert-outline",
234
+ "alert-vertical",
235
+ "alert-horizontal",
236
+ "badge-outline",
237
+ "badge-dash",
238
+ "badge-soft",
239
+ "badge-ghost",
240
+ "badge-xs",
241
+ "badge-sm",
242
+ "badge-md",
243
+ "badge-lg",
244
+ "badge-xl",
245
+ "btn-outline",
246
+ "btn-dash",
247
+ "btn-soft",
248
+ "btn-ghost",
249
+ "btn-link",
250
+ "btn-active",
251
+ "btn-xs",
252
+ "btn-sm",
253
+ "btn-md",
254
+ "btn-lg",
255
+ "btn-xl",
256
+ "card-border",
257
+ "card-dash",
258
+ "card-xs",
259
+ "card-sm",
260
+ "card-md",
261
+ "card-lg",
262
+ "card-xl",
263
+ "stats-horizontal",
264
+ "stats-vertical",
265
+ "table-zebra",
266
+ "table-pin-rows",
267
+ "table-pin-cols",
268
+ "table-xs",
269
+ "table-sm",
270
+ "table-md",
271
+ "table-lg",
272
+ "table-xl",
273
+ ] as const;
274
+
275
+ export const HTML_TAILWIND_BUILD_CLASSES = [
276
+ ...HTML_TAILWIND_CLASSES,
277
+ ...HTML_DAISY_BUILD_COMPONENT_CLASSES,
278
+ ...SPACING_PREFIXES.flatMap((prefix) => SPACING_VALUES.map((value) => `${prefix}-${value}`)),
279
+ ...SEMANTIC_COLORS.flatMap((color) => [`bg-${color}`, `text-${color}`, `border-${color}`]),
280
+ ...STANDARD_COLORS.flatMap((color) => [`bg-${color}`, `text-${color}`, `border-${color}`]),
281
+ ...DAISY_COLOR_COMPONENTS.flatMap((component) =>
282
+ DAISY_COLOR_VARIANTS.map((variant) => `${component}-${variant}`),
283
+ ),
284
+ ...DAISY_VARIANTS,
285
+ "hidden",
286
+ "inline-block",
287
+ "inline-grid",
288
+ "flex-row",
289
+ "flex-1",
290
+ "flex-none",
291
+ "grow",
292
+ "shrink-0",
293
+ "items-start",
294
+ "items-end",
295
+ "justify-start",
296
+ "justify-end",
297
+ "justify-around",
298
+ "justify-evenly",
299
+ "content-start",
300
+ "content-center",
301
+ "self-start",
302
+ "self-center",
303
+ "self-end",
304
+ "grid-cols-4",
305
+ "grid-cols-5",
306
+ "grid-cols-6",
307
+ "col-span-2",
308
+ "col-span-3",
309
+ "col-span-full",
310
+ "w-auto",
311
+ "w-1/2",
312
+ "w-1/3",
313
+ "w-2/3",
314
+ "w-screen",
315
+ "min-w-0",
316
+ "max-w-none",
317
+ "max-w-sm",
318
+ "max-w-md",
319
+ "max-w-lg",
320
+ "max-w-xl",
321
+ "max-w-3xl",
322
+ "h-auto",
323
+ "h-full",
324
+ "min-h-screen",
325
+ "text-3xl",
326
+ "text-4xl",
327
+ "font-normal",
328
+ "font-extrabold",
329
+ "leading-tight",
330
+ "leading-normal",
331
+ "uppercase",
332
+ "lowercase",
333
+ "tracking-wide",
334
+ "shadow",
335
+ "shadow-sm",
336
+ "shadow-md",
337
+ "shadow-lg",
338
+ "rounded-sm",
339
+ "rounded-md",
340
+ "rounded-lg",
341
+ "rounded-xl",
342
+ "rounded-full",
343
+ "overflow-auto",
344
+ "overflow-hidden",
345
+ "overflow-y-auto",
346
+ ] as const;
347
+
348
+ export const HTML_STYLE_CLASSES_DISTINCT = [
349
+ ...new Set<string>([...HTML_TAILWIND_CLASSES, ...HTML_DAISY_COMPONENTS]),
350
+ ] as const;
351
+
352
+ export const HTML_STYLE_CLASSES = [...HTML_TAILWIND_CLASSES, ...HTML_DAISY_COMPONENTS] as const;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Structured JSON logger.
3
+ *
4
+ * Diagnostics go to STDERR, ONE JSON object per line. STDOUT is reserved
5
+ * for CLI envelopes — never pollute it from here. Every payload is piped
6
+ * through `redact()` before serialization so a token accidentally logged
7
+ * inside a `details` block is scrubbed at the source.
8
+ *
9
+ * Required fields: level, event, component, timestamp, pid.
10
+ * Optional fields: requestId, artifactId, revisionSha, durationMs, errorCode,
11
+ * rssBytes, pssBytes, dbBytes, evidenceBytes.
12
+ */
13
+
14
+ import { redact } from "./redact";
15
+
16
+ export type LogLevel = "debug" | "info" | "warn" | "error";
17
+
18
+ export interface LoggerFields {
19
+ readonly requestId?: string;
20
+ readonly artifactId?: string;
21
+ readonly revisionSha?: string;
22
+ readonly durationMs?: number;
23
+ readonly errorCode?: string;
24
+ readonly rssBytes?: number | null;
25
+ readonly pssBytes?: number | null;
26
+ readonly dbBytes?: number;
27
+ readonly evidenceBytes?: number;
28
+ readonly [key: string]: unknown;
29
+ }
30
+
31
+ export interface FacetLoggerOptions {
32
+ readonly component: string;
33
+ readonly baseFields?: LoggerFields;
34
+ }
35
+
36
+ export interface FacetLogger {
37
+ debug(event: string, fields?: LoggerFields): void;
38
+ info(event: string, fields?: LoggerFields): void;
39
+ warn(event: string, fields?: LoggerFields): void;
40
+ error(event: string, fields?: LoggerFields): void;
41
+ child(component: string): FacetLogger;
42
+ }
43
+
44
+ class FacetLoggerImpl implements FacetLogger {
45
+ constructor(
46
+ private readonly component: string,
47
+ private readonly baseFields: LoggerFields = {},
48
+ ) {}
49
+
50
+ child(component: string): FacetLogger {
51
+ return new FacetLoggerImpl(component, this.baseFields);
52
+ }
53
+
54
+ debug(event: string, fields: LoggerFields = {}): void {
55
+ this.emit("debug", event, fields);
56
+ }
57
+ info(event: string, fields: LoggerFields = {}): void {
58
+ this.emit("info", event, fields);
59
+ }
60
+ warn(event: string, fields: LoggerFields = {}): void {
61
+ this.emit("warn", event, fields);
62
+ }
63
+ error(event: string, fields: LoggerFields = {}): void {
64
+ this.emit("error", event, fields);
65
+ }
66
+
67
+ private emit(level: LogLevel, event: string, fields: LoggerFields): void {
68
+ const merged: Record<string, unknown> = {
69
+ level,
70
+ event,
71
+ component: this.component,
72
+ timestamp: new Date().toISOString(),
73
+ pid: process.pid,
74
+ ...this.baseFields,
75
+ ...fields,
76
+ };
77
+ // drop undefined keys so JSON.stringify never emits "key":undefined
78
+ for (const [k, v] of Object.entries(merged)) {
79
+ if (v === undefined) delete merged[k];
80
+ }
81
+ const scrubbed = redact(merged);
82
+ process.stderr.write(`${JSON.stringify(scrubbed)}\n`);
83
+ }
84
+ }
85
+
86
+ export function createLogger(options: FacetLoggerOptions): FacetLogger {
87
+ return new FacetLoggerImpl(options.component, options.baseFields ?? {});
88
+ }
89
+
90
+ const QUIET_NOOP = (): void => {};
91
+
92
+ /**
93
+ * No-op logger. Used by integration tests so the test gate is
94
+ * pristine — the real stderr logger spams JSON lines on every service
95
+ * event, which drowns the test reporter.
96
+ */
97
+ export function createQuietLogger(
98
+ options: FacetLoggerOptions = { component: "test" },
99
+ ): FacetLogger {
100
+ void options;
101
+ return {
102
+ debug: QUIET_NOOP,
103
+ info: QUIET_NOOP,
104
+ warn: QUIET_NOOP,
105
+ error: QUIET_NOOP,
106
+ child: () => createQuietLogger(),
107
+ };
108
+ }