@crvouga/atlas 0.3.0 → 0.5.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 (429) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +178 -604
  3. package/dist/bun/src/driver.d.ts +41 -7
  4. package/dist/bun/src/driver.js +47 -6
  5. package/dist/bun/src/index.d.ts +8 -0
  6. package/dist/bun/src/index.js +8 -0
  7. package/dist/core/src/cli.d.ts +14 -1
  8. package/dist/core/src/cli.js +30 -1
  9. package/dist/core/src/config.d.ts +70 -4
  10. package/dist/core/src/config.js +62 -3
  11. package/dist/core/src/events/cloudevents.d.ts +54 -9
  12. package/dist/core/src/events/cloudevents.js +60 -9
  13. package/dist/core/src/graph.d.ts +21 -0
  14. package/dist/core/src/graph.js +26 -0
  15. package/dist/core/src/index.d.ts +11 -0
  16. package/dist/core/src/index.js +11 -0
  17. package/dist/core/src/lint.d.ts +30 -0
  18. package/dist/core/src/lint.js +13 -0
  19. package/dist/core/src/plan.d.ts +39 -1
  20. package/dist/core/src/plan.js +28 -1
  21. package/dist/core/src/privacy.d.ts +29 -2
  22. package/dist/core/src/privacy.js +19 -2
  23. package/dist/core/src/report/formats.d.ts +34 -4
  24. package/dist/core/src/report/formats.js +24 -4
  25. package/dist/core/src/report/markdown.d.ts +15 -0
  26. package/dist/core/src/report/markdown.js +8 -0
  27. package/dist/core/src/run/clients.d.ts +44 -5
  28. package/dist/core/src/run/clients.js +46 -2
  29. package/dist/core/src/run/execute.d.ts +69 -16
  30. package/dist/core/src/run/execute.js +67 -16
  31. package/dist/core/src/run/frames.d.ts +13 -4
  32. package/dist/core/src/run/frames.js +19 -4
  33. package/dist/core/src/run/http.d.ts +34 -1
  34. package/dist/core/src/run/http.js +14 -1
  35. package/dist/core/src/run/types.d.ts +76 -3
  36. package/dist/core/src/run/types.js +19 -3
  37. package/dist/core/src/signals.d.ts +49 -5
  38. package/dist/core/src/signals.js +22 -5
  39. package/dist/core/src/spec/compose.d.ts +23 -1
  40. package/dist/core/src/spec/compose.js +10 -1
  41. package/dist/core/src/spec/index.d.ts +9 -1
  42. package/dist/core/src/spec/index.js +9 -1
  43. package/dist/core/src/spec/load.d.ts +22 -1
  44. package/dist/core/src/spec/load.js +31 -1
  45. package/dist/core/src/spec/parse.d.ts +16 -2
  46. package/dist/core/src/spec/parse.js +25 -2
  47. package/dist/core/src/spec/scxml.d.ts +25 -4
  48. package/dist/core/src/spec/scxml.js +36 -4
  49. package/dist/core/src/spec/types.d.ts +52 -1
  50. package/dist/core/src/spec/types.js +24 -0
  51. package/dist/detox/src/index.d.ts +54 -11
  52. package/dist/detox/src/index.js +45 -7
  53. package/dist/playwright/src/driver.d.ts +39 -3
  54. package/dist/playwright/src/driver.js +27 -3
  55. package/dist/playwright/src/index.d.ts +10 -0
  56. package/dist/playwright/src/index.js +10 -0
  57. package/dist/playwright/src/media.d.ts +50 -4
  58. package/dist/playwright/src/media.js +55 -4
  59. package/dist/playwright/src/signals.d.ts +44 -5
  60. package/dist/playwright/src/signals.js +29 -5
  61. package/dist/reports/src/attachment-files.d.ts +44 -0
  62. package/dist/reports/src/attachment-files.js +121 -0
  63. package/dist/reports/src/attachment-response.d.ts +31 -0
  64. package/dist/reports/src/attachment-response.js +55 -0
  65. package/dist/reports/src/aws-credentials.d.ts +48 -0
  66. package/dist/reports/src/aws-credentials.js +221 -0
  67. package/dist/reports/src/browser-navigation.d.ts +14 -0
  68. package/dist/reports/src/browser-navigation.js +7 -0
  69. package/dist/reports/src/bundle.d.ts +34 -2
  70. package/dist/reports/src/bundle.js +38 -2
  71. package/dist/reports/src/catalog.d.ts +34 -3
  72. package/dist/reports/src/catalog.js +17 -3
  73. package/dist/reports/src/cli-stores.d.ts +36 -0
  74. package/dist/reports/src/cli-stores.js +73 -0
  75. package/dist/reports/src/clock.d.ts +7 -2
  76. package/dist/reports/src/clock.js +5 -2
  77. package/dist/reports/src/completion-order.d.ts +18 -5
  78. package/dist/reports/src/completion-order.js +18 -5
  79. package/dist/reports/src/compose.d.ts +80 -0
  80. package/dist/reports/src/compose.js +117 -0
  81. package/dist/reports/src/copy-store.d.ts +29 -0
  82. package/dist/reports/src/copy-store.js +52 -0
  83. package/dist/reports/src/directory-outline.d.ts +38 -0
  84. package/dist/reports/src/directory-outline.js +103 -0
  85. package/dist/reports/src/directory-store.d.ts +20 -0
  86. package/dist/reports/src/directory-store.js +166 -0
  87. package/dist/reports/src/doctor.d.ts +29 -0
  88. package/dist/reports/src/doctor.js +83 -0
  89. package/dist/reports/src/effective-delta.d.ts +34 -0
  90. package/dist/reports/src/effective-delta.js +25 -0
  91. package/dist/reports/src/evidence-detail.d.ts +64 -0
  92. package/dist/reports/src/evidence-detail.js +92 -0
  93. package/dist/reports/src/evidence-live.d.ts +40 -4
  94. package/dist/reports/src/evidence-live.js +52 -4
  95. package/dist/reports/src/evidence-types.d.ts +70 -1
  96. package/dist/reports/src/evidence-types.js +5 -1
  97. package/dist/reports/src/evidence-view.d.ts +58 -6
  98. package/dist/reports/src/evidence-view.js +44 -5
  99. package/dist/reports/src/explorer-types.d.ts +40 -3
  100. package/dist/reports/src/explorer-types.js +8 -0
  101. package/dist/reports/src/explorer-versions.d.ts +9 -1
  102. package/dist/reports/src/explorer-versions.js +18 -1
  103. package/dist/reports/src/export-evidence.d.ts +16 -1
  104. package/dist/reports/src/export-evidence.js +52 -1
  105. package/dist/reports/src/fetcher.d.ts +27 -3
  106. package/dist/reports/src/fetcher.js +11 -3
  107. package/dist/reports/src/format-date.d.ts +6 -0
  108. package/dist/reports/src/format-date.js +6 -0
  109. package/dist/reports/src/format.d.ts +16 -0
  110. package/dist/reports/src/format.js +10 -0
  111. package/dist/reports/src/frames.d.ts +36 -3
  112. package/dist/reports/src/frames.js +22 -3
  113. package/dist/reports/src/hash.d.ts +18 -0
  114. package/dist/reports/src/hash.js +13 -0
  115. package/dist/reports/src/host.d.ts +29 -0
  116. package/dist/reports/src/host.js +64 -0
  117. package/dist/reports/src/html-frame.d.ts +5 -6
  118. package/dist/reports/src/html-frame.js +12 -1
  119. package/dist/reports/src/http-store.d.ts +52 -0
  120. package/dist/reports/src/http-store.js +145 -0
  121. package/dist/reports/src/http.d.ts +7 -0
  122. package/dist/reports/src/http.js +6 -0
  123. package/dist/reports/src/ingest.d.ts +54 -0
  124. package/dist/reports/src/ingest.js +210 -0
  125. package/dist/reports/src/init.d.ts +40 -0
  126. package/dist/reports/src/init.js +364 -0
  127. package/dist/reports/src/junit.d.ts +33 -6
  128. package/dist/reports/src/junit.js +87 -21
  129. package/dist/reports/src/keyboard.d.ts +20 -0
  130. package/dist/reports/src/keyboard.js +11 -0
  131. package/dist/reports/src/keys.d.ts +21 -3
  132. package/dist/reports/src/keys.js +21 -3
  133. package/dist/reports/src/layer-axes.d.ts +48 -0
  134. package/dist/reports/src/layer-axes.js +71 -0
  135. package/dist/reports/src/layer-catalog.d.ts +28 -1
  136. package/dist/reports/src/layer-catalog.js +19 -2
  137. package/dist/reports/src/layer-merge.d.ts +98 -9
  138. package/dist/reports/src/layer-merge.js +154 -33
  139. package/dist/reports/src/layer-source.d.ts +18 -0
  140. package/dist/reports/src/layer-source.js +14 -0
  141. package/dist/reports/src/layer-store.d.ts +42 -0
  142. package/dist/reports/src/layer-store.js +63 -5
  143. package/dist/reports/src/layer-types.d.ts +34 -1
  144. package/dist/reports/src/layers-route.d.ts +47 -4
  145. package/dist/reports/src/layers-route.js +88 -12
  146. package/dist/reports/src/media-types.d.ts +11 -0
  147. package/dist/reports/src/media-types.js +22 -0
  148. package/dist/reports/src/namespace-guard.d.ts +10 -1
  149. package/dist/reports/src/namespace-guard.js +10 -1
  150. package/dist/reports/src/navigation.d.ts +12 -0
  151. package/dist/reports/src/navigation.js +7 -0
  152. package/dist/reports/src/object-io.d.ts +11 -4
  153. package/dist/reports/src/object-io.js +4 -4
  154. package/dist/reports/src/object-store-conformance.d.ts +27 -0
  155. package/dist/reports/src/object-store-conformance.js +87 -0
  156. package/dist/reports/src/object-store.d.ts +33 -24
  157. package/dist/reports/src/object-store.js +17 -24
  158. package/dist/reports/src/parse-with.d.ts +16 -0
  159. package/dist/reports/src/parse-with.js +14 -0
  160. package/dist/reports/src/performance-part.d.ts +25 -1
  161. package/dist/reports/src/performance-part.js +15 -1
  162. package/dist/reports/src/performance.d.ts +22 -2
  163. package/dist/reports/src/performance.js +12 -2
  164. package/dist/reports/src/persist.d.ts +12 -3
  165. package/dist/reports/src/persist.js +12 -3
  166. package/dist/reports/src/phone.d.ts +18 -1
  167. package/dist/reports/src/phone.js +18 -1
  168. package/dist/reports/src/protocol.d.ts +30 -4
  169. package/dist/reports/src/protocol.js +15 -4
  170. package/dist/reports/src/publication.d.ts +21 -1
  171. package/dist/reports/src/publication.js +21 -1
  172. package/dist/reports/src/publish-checks.d.ts +35 -0
  173. package/dist/reports/src/publish-checks.js +122 -0
  174. package/dist/reports/src/publish.d.ts +44 -9
  175. package/dist/reports/src/publish.js +40 -7
  176. package/dist/reports/src/read.d.ts +46 -16
  177. package/dist/reports/src/read.js +38 -14
  178. package/dist/reports/src/recording-bundle.d.ts +13 -2
  179. package/dist/reports/src/recording-bundle.js +4 -2
  180. package/dist/reports/src/recording-keys.d.ts +15 -1
  181. package/dist/reports/src/recording-keys.js +15 -1
  182. package/dist/reports/src/remote-report.d.ts +28 -7
  183. package/dist/reports/src/remote-report.js +15 -7
  184. package/dist/reports/src/report-cli.d.ts +51 -0
  185. package/dist/reports/src/report-cli.js +485 -0
  186. package/dist/reports/src/report-index.d.ts +99 -0
  187. package/dist/reports/src/report-index.js +337 -0
  188. package/dist/reports/src/report-loader.d.ts +10 -0
  189. package/dist/reports/src/report-loader.js +6 -0
  190. package/dist/reports/src/report-parts.d.ts +29 -3
  191. package/dist/reports/src/report-parts.js +40 -3
  192. package/dist/reports/src/report-status.d.ts +48 -0
  193. package/dist/reports/src/report-status.js +156 -0
  194. package/dist/reports/src/report-types.d.ts +73 -0
  195. package/dist/reports/src/report-types.js +3 -0
  196. package/dist/reports/src/reporter.d.ts +67 -0
  197. package/dist/reports/src/reporter.js +128 -0
  198. package/dist/reports/src/reports-explorer-route.d.ts +541 -0
  199. package/dist/reports/src/reports-explorer-route.js +11 -0
  200. package/dist/reports/src/reports-list-route.d.ts +9 -0
  201. package/dist/reports/src/reports-list-route.js +9 -0
  202. package/dist/reports/src/reports-route.d.ts +561 -22
  203. package/dist/reports/src/reports-route.js +11 -3
  204. package/dist/reports/src/reports-store.d.ts +19 -2
  205. package/dist/reports/src/reports-store.js +10 -2
  206. package/dist/reports/src/resilient-cache.d.ts +14 -1
  207. package/dist/reports/src/resilient-cache.js +8 -1
  208. package/dist/reports/src/retention.d.ts +17 -1
  209. package/dist/reports/src/retention.js +5 -1
  210. package/dist/reports/src/run-bundle.d.ts +63 -0
  211. package/dist/reports/src/run-bundle.js +159 -0
  212. package/dist/reports/src/s3-store.d.ts +79 -0
  213. package/dist/reports/src/s3-store.js +295 -0
  214. package/dist/reports/src/scenario.d.ts +14 -4
  215. package/dist/reports/src/scenario.js +5 -4
  216. package/dist/reports/src/sigv4.d.ts +72 -0
  217. package/dist/reports/src/sigv4.js +96 -0
  218. package/dist/reports/src/snapshot-bundle.d.ts +24 -1
  219. package/dist/reports/src/snapshot-bundle.js +27 -2
  220. package/dist/reports/src/snapshot-surface.d.ts +20 -9
  221. package/dist/reports/src/snapshot-surface.js +32 -19
  222. package/dist/reports/src/source-content.d.ts +23 -0
  223. package/dist/reports/src/source-content.js +30 -1
  224. package/dist/reports/src/source-entries.d.ts +13 -0
  225. package/dist/reports/src/source-entries.js +6 -0
  226. package/dist/reports/src/source-part.d.ts +15 -0
  227. package/dist/reports/src/source-part.js +8 -0
  228. package/dist/reports/src/source-reader.d.ts +11 -0
  229. package/dist/reports/src/source-reader.js +5 -0
  230. package/dist/reports/src/spec-evidence.d.ts +12 -2
  231. package/dist/reports/src/spec-evidence.js +6 -2
  232. package/dist/reports/src/spec-inventory.d.ts +15 -1
  233. package/dist/reports/src/spec-inventory.js +22 -1
  234. package/dist/reports/src/spec-link.d.ts +28 -0
  235. package/dist/reports/src/spec-link.js +70 -0
  236. package/dist/reports/src/spec-set.d.ts +63 -0
  237. package/dist/reports/src/spec-set.js +177 -0
  238. package/dist/reports/src/status.d.ts +10 -0
  239. package/dist/reports/src/status.js +5 -0
  240. package/dist/reports/src/store-prefix.d.ts +28 -0
  241. package/dist/reports/src/store-prefix.js +22 -0
  242. package/dist/reports/src/store-url.d.ts +89 -0
  243. package/dist/reports/src/store-url.js +160 -0
  244. package/dist/reports/src/test-catalog-entity.d.ts +11 -0
  245. package/dist/reports/src/test-catalog-entity.js +6 -0
  246. package/dist/reports/src/types.d.ts +6 -1
  247. package/dist/reports/src/use-report-nav.d.ts +35 -0
  248. package/dist/reports/src/use-report-nav.js +12 -0
  249. package/dist/schema/src/api.d.ts +799 -0
  250. package/dist/schema/src/api.js +201 -0
  251. package/dist/schema/src/cli-results.d.ts +210 -0
  252. package/dist/schema/src/cli-results.js +124 -0
  253. package/dist/schema/src/common.d.ts +53 -0
  254. package/dist/schema/src/common.js +42 -0
  255. package/dist/schema/src/index.d.ts +14 -0
  256. package/dist/schema/src/index.js +14 -0
  257. package/dist/schema/src/layer.d.ts +2273 -0
  258. package/dist/schema/src/layer.js +462 -0
  259. package/dist/schema/src/manifest.d.ts +95 -0
  260. package/dist/schema/src/manifest.js +84 -0
  261. package/dist/schema/src/report-sources.d.ts +28 -0
  262. package/dist/schema/src/report-sources.js +25 -0
  263. package/dist/schema/src/runs-index.d.ts +16 -0
  264. package/dist/schema/src/runs-index.js +15 -0
  265. package/dist/schema/src/server-config.d.ts +93 -0
  266. package/dist/schema/src/server-config.js +73 -0
  267. package/dist/schema/src/spec.d.ts +69 -0
  268. package/dist/schema/src/spec.js +58 -0
  269. package/dist/server/src/app.d.ts +62 -0
  270. package/dist/server/src/app.js +419 -0
  271. package/dist/server/src/auth.d.ts +41 -0
  272. package/dist/server/src/auth.js +59 -0
  273. package/dist/server/src/config.d.ts +83 -0
  274. package/dist/server/src/config.js +187 -0
  275. package/dist/server/src/dev.d.ts +12 -0
  276. package/dist/server/src/dev.js +80 -0
  277. package/dist/server/src/events.d.ts +29 -0
  278. package/dist/server/src/events.js +101 -0
  279. package/dist/server/src/host.d.ts +30 -0
  280. package/dist/server/src/host.js +115 -0
  281. package/dist/server/src/index.d.ts +16 -0
  282. package/dist/server/src/index.js +16 -0
  283. package/dist/server/src/llms.d.ts +19 -0
  284. package/dist/server/src/llms.js +63 -0
  285. package/dist/server/src/main.d.ts +30 -0
  286. package/dist/server/src/main.js +112 -0
  287. package/dist/server/src/openapi.d.ts +59 -0
  288. package/dist/server/src/openapi.js +374 -0
  289. package/dist/server/src/problem.d.ts +8 -0
  290. package/dist/server/src/problem.js +39 -0
  291. package/dist/server/src/site.d.ts +13 -0
  292. package/dist/server/src/site.js +43 -0
  293. package/dist/server/src/store-api.d.ts +28 -0
  294. package/dist/server/src/store-api.js +159 -0
  295. package/dist/server/src/validate.d.ts +71 -0
  296. package/dist/server/src/validate.js +197 -0
  297. package/dist/vitest/src/index.d.ts +27 -5
  298. package/dist/vitest/src/index.js +18 -5
  299. package/dist/webdriver/src/driver.d.ts +63 -11
  300. package/dist/webdriver/src/driver.js +57 -6
  301. package/dist/webdriver/src/index.d.ts +8 -0
  302. package/dist/webdriver/src/index.js +1 -0
  303. package/dist/webdriver/src/protocol.d.ts +75 -6
  304. package/dist/webdriver/src/protocol.js +79 -6
  305. package/docs/agents.md +137 -0
  306. package/docs/deploying.md +345 -0
  307. package/docs/dogfooding.md +175 -0
  308. package/docs/extending.md +242 -0
  309. package/docs/integrating.md +485 -0
  310. package/docs/reference/bun.md +141 -0
  311. package/docs/reference/cli.md +146 -0
  312. package/docs/reference/core.md +2426 -0
  313. package/docs/reference/detox.md +150 -0
  314. package/docs/reference/http-api.md +303 -0
  315. package/docs/reference/playwright.md +303 -0
  316. package/docs/reference/reports.md +7098 -0
  317. package/docs/reference/schema.md +1651 -0
  318. package/docs/reference/server.md +685 -0
  319. package/docs/reference/vitest.md +45 -0
  320. package/docs/reference/webdriver.md +330 -0
  321. package/docs/report-backends.md +144 -0
  322. package/docs/report-contract.md +400 -0
  323. package/docs/reporting-issues.md +160 -0
  324. package/docs/server.md +285 -0
  325. package/docs/statecharts.md +641 -0
  326. package/llms-full.txt +3506 -0
  327. package/llms.txt +47 -0
  328. package/package.json +33 -5
  329. package/packages/core/README.md +2 -1
  330. package/packages/reports/README.md +69 -2
  331. package/packages/reports/STORAGE.md +5 -1
  332. package/packages/schema/README.md +14 -0
  333. package/packages/schema/schemas/check-detail.schema.json +1032 -0
  334. package/packages/schema/schemas/checks-result.schema.json +26 -0
  335. package/packages/schema/schemas/command-error.schema.json +35 -0
  336. package/packages/schema/schemas/doctor-result.schema.json +60 -0
  337. package/packages/schema/schemas/effective-delta.schema.json +490 -0
  338. package/packages/schema/schemas/effective-evidence.schema.json +471 -0
  339. package/packages/schema/schemas/evidence-page.schema.json +271 -0
  340. package/packages/schema/schemas/hello-event.schema.json +22 -0
  341. package/packages/schema/schemas/init-plan.schema.json +347 -0
  342. package/packages/schema/schemas/layer-rows.schema.json +199 -0
  343. package/packages/schema/schemas/layer.schema.json +2888 -0
  344. package/packages/schema/schemas/merge-result.schema.json +40 -0
  345. package/packages/schema/schemas/outline.schema.json +62 -0
  346. package/packages/schema/schemas/problem.schema.json +37 -0
  347. package/packages/schema/schemas/publish-checks.schema.json +1413 -0
  348. package/packages/schema/schemas/publish-result.schema.json +168 -0
  349. package/packages/schema/schemas/ready.schema.json +68 -0
  350. package/packages/schema/schemas/report-event.schema.json +100 -0
  351. package/packages/schema/schemas/report-status.schema.json +370 -0
  352. package/packages/schema/schemas/server-config.schema.json +194 -0
  353. package/packages/schema/schemas/server-info.schema.json +114 -0
  354. package/packages/schema/schemas/spec-set.schema.json +103 -0
  355. package/packages/schema/schemas/store-listing.schema.json +29 -0
  356. package/packages/schema/schemas/store-write-result.schema.json +28 -0
  357. package/packages/schema/schemas/stream-result.schema.json +59 -0
  358. package/packages/server/README.md +43 -0
  359. package/packages/server/openapi.json +6699 -0
  360. package/packages/visualizer/README.md +27 -5
  361. package/packages/visualizer/example/specs/coffee/ordering/cart.qnt +7 -0
  362. package/packages/visualizer/example/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  363. package/packages/visualizer/example/specs/coffee/ordering/drink-price.dmn +24 -0
  364. package/packages/visualizer/example/specs/coffee/ordering/loyalty.feature +7 -0
  365. package/packages/visualizer/example/specs/coffee/ordering/ordering.feature +36 -0
  366. package/packages/visualizer/example/specs/coffee/ordering/payment.als +4 -0
  367. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/cart.qnt +7 -0
  368. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  369. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/drink-price.dmn +24 -0
  370. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/loyalty.feature +7 -0
  371. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/ordering.feature +36 -0
  372. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/payment.als +4 -0
  373. package/packages/visualizer/fixtures/full/specs/coffee/ordering/cart.qnt +7 -0
  374. package/packages/visualizer/fixtures/full/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  375. package/packages/visualizer/fixtures/full/specs/coffee/ordering/drink-price.dmn +24 -0
  376. package/packages/visualizer/fixtures/full/specs/coffee/ordering/loyalty.feature +7 -0
  377. package/packages/visualizer/fixtures/full/specs/coffee/ordering/ordering.feature +36 -0
  378. package/packages/visualizer/fixtures/full/specs/coffee/ordering/payment.als +4 -0
  379. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/cart.qnt +7 -0
  380. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  381. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/drink-price.dmn +24 -0
  382. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/loyalty.feature +7 -0
  383. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/ordering.feature +36 -0
  384. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/payment.als +4 -0
  385. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/cart.qnt +7 -0
  386. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  387. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/drink-price.dmn +24 -0
  388. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/loyalty.feature +7 -0
  389. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/ordering.feature +36 -0
  390. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/payment.als +4 -0
  391. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/cart.qnt +7 -0
  392. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  393. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/drink-price.dmn +24 -0
  394. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/loyalty.feature +7 -0
  395. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/ordering.feature +36 -0
  396. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/payment.als +4 -0
  397. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/cart.qnt +7 -0
  398. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  399. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/drink-price.dmn +24 -0
  400. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/loyalty.feature +7 -0
  401. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/ordering.feature +36 -0
  402. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/payment.als +4 -0
  403. package/packages/visualizer/scripts/make-fixtures.ts +2 -0
  404. package/packages/visualizer/scripts/publish-data.ts +1 -2
  405. package/packages/visualizer/src/app/AppShell.tsx +9 -2
  406. package/packages/visualizer/src/app/report-sources.tsx +6 -4
  407. package/packages/visualizer/src/app/router.tsx +3 -3
  408. package/packages/visualizer/src/components/Header.module.css +35 -0
  409. package/packages/visualizer/src/components/Header.tsx +41 -4
  410. package/packages/visualizer/src/data/adapters/adapter.ts +5 -17
  411. package/packages/visualizer/src/data/adapters/index.ts +10 -1
  412. package/packages/visualizer/src/evidence/api.ts +14 -2
  413. package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
  414. package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
  415. package/packages/visualizer/src/evidence/check-detail.tsx +38 -4
  416. package/packages/visualizer/src/evidence/evidence-context.tsx +74 -12
  417. package/packages/visualizer/src/evidence/evidence.module.css +20 -0
  418. package/packages/visualizer/src/evidence/marks.tsx +2 -0
  419. package/packages/visualizer/src/evidence/overview.tsx +3 -3
  420. package/packages/visualizer/src/evidence/sources-panel.tsx +88 -34
  421. package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
  422. package/packages/visualizer/src/find/Finder.tsx +1 -7
  423. package/packages/visualizer/src/find/open.ts +4 -0
  424. package/packages/visualizer/src/live/live-stream.ts +204 -0
  425. package/packages/visualizer/src/runtime.ts +19 -0
  426. package/packages/visualizer/src/state/ui-store.ts +6 -2
  427. package/packages/visualizer/vite/atlas-server-proxy.ts +36 -0
  428. package/packages/visualizer/vite/example-reports.ts +475 -0
  429. package/packages/visualizer/vite.config.ts +18 -2
@@ -0,0 +1,7 @@
1
+ # Cart
2
+ module cart {
3
+ var items: int
4
+ var paid: bool
5
+ action add = items' = items + 1
6
+ action pay = paid' = true
7
+ }
@@ -0,0 +1,10 @@
1
+ # Checkout latency
2
+ apiVersion: openslo/v1
3
+ kind: SLO
4
+ metadata:
5
+ name: checkout-latency
6
+ spec:
7
+ description: Checkout answers within a second.
8
+ objectives:
9
+ - displayName: Checkout latency
10
+ target: 0.99
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/">
3
+ <decision id="drink-price" name="Drink price">
4
+ <decisionTable id="Drink price" hitPolicy="UNIQUE">
5
+ <input label="Size">
6
+ <inputExpression typeRef="string"><text>size</text></inputExpression>
7
+ </input>
8
+ <input label="Milk">
9
+ <inputExpression typeRef="string"><text>milk</text></inputExpression>
10
+ </input>
11
+ <output label="Price" name="price" />
12
+ <rule>
13
+ <inputEntry><text>"Small"</text></inputEntry>
14
+ <inputEntry><text>"None"</text></inputEntry>
15
+ <outputEntry><text>3</text></outputEntry>
16
+ </rule>
17
+ <rule>
18
+ <inputEntry><text>"Large"</text></inputEntry>
19
+ <inputEntry><text>"Oat"</text></inputEntry>
20
+ <outputEntry><text>5</text></outputEntry>
21
+ </rule>
22
+ </decisionTable>
23
+ </decision>
24
+ </definitions>
@@ -0,0 +1,7 @@
1
+ Feature: Loyalty stamps
2
+ A regular earns a free drink. No layer has recorded this yet.
3
+
4
+ Scenario: Tenth drink is free
5
+ Given nine stamps
6
+ When the customer orders
7
+ Then the drink is free
@@ -0,0 +1,36 @@
1
+ Feature: Order a drink
2
+ A customer picks a drink, pays, and picks it up.
3
+
4
+ Rule: Paying for the order
5
+
6
+ Scenario: Pays by card
7
+ Given a drink in the cart
8
+ When the customer pays by card
9
+ Then the barista can start the drink
10
+
11
+ Scenario: Pays with a wallet
12
+ Given a drink in the cart
13
+ When the customer pays with a wallet
14
+ Then the order is paid
15
+
16
+ Scenario: Card declined, then a wallet works
17
+ Given a drink in the cart
18
+ When the card is declined
19
+ And the customer pays with a wallet
20
+ Then the order is paid
21
+
22
+ Scenario: Slow payment
23
+ Given a drink in the cart
24
+ When the payment takes longer than a minute
25
+ Then the customer can check the payment again
26
+
27
+ Scenario: Leaves checkout and comes back
28
+ Given a drink in the cart
29
+ When the customer closes checkout
30
+ And the customer starts checkout again
31
+ Then checkout is open
32
+
33
+ Scenario: Drink left too long
34
+ Given a finished drink
35
+ When nobody picks it up
36
+ Then the drink is thrown away and refunded
@@ -0,0 +1,4 @@
1
+ // An order is paid once.
2
+ sig Order { paid: lone Payment }
3
+ sig Payment {}
4
+ fact { all o: Order | one o.paid }
@@ -30,6 +30,8 @@ import { APP_ROOT, FIXTURES_ROOT, listSpecFiles } from '../vite/atlas-files';
30
30
  * Regenerates every fixture from the example spec in `example/specs` (a coffee-ordering app: an
31
31
  * XState root chart with a parallel region that invokes an SCXML checkout chart) and a generated
32
32
  * large atlas. All media is synthetic: ImageMagick draws the screens and ffmpeg the clips.
33
+ * Gherkin, Quint, DMN, Alloy and OpenSLO documents in that spec are copied with the charts.
34
+ * The visualizer dev server serves the layered report for them; this script does not rebuild it.
33
35
  */
34
36
 
35
37
  const EXAMPLE_SPECS = path.join(APP_ROOT, 'example/specs');
@@ -5,8 +5,7 @@ import { publishData } from '../vite/publish';
5
5
 
6
6
  /**
7
7
  * `pnpm publish-data`: the spec and the newest runs into `public/data` (or `ATLAS_OUT`), where
8
- * `pnpm build` picks them up. Roots come from `ATLAS_SPECS_ROOT` / `ATLAS_RUNS_ROOT` or
9
- * `ATLAS_FIXTURE`, as for the dev server.
8
+ * `pnpm build` picks them up. Roots come from `ATLAS_SPECS_ROOT` / `ATLAS_RUNS_ROOT`, as for the dev server.
10
9
  */
11
10
  try {
12
11
  const roots = resolveRoots();
@@ -1,4 +1,5 @@
1
1
  import { Outlet, useLocation, useSearch } from '@tanstack/react-router';
2
+ import { lazy, Suspense } from 'react';
2
3
 
3
4
  import { Header } from '../components/Header';
4
5
  import { EvidenceProvider } from '../evidence/evidence-context';
@@ -6,10 +7,14 @@ import { SourcesPanel } from '../evidence/sources-panel';
6
7
  import { SpecIndex } from '../evidence/spec-index';
7
8
  import { kindOfAddress } from '../spec-kind';
8
9
  import styles from '../views/views.module.css';
9
- import { Finder } from '../find/Finder';
10
10
  import { AtlasProvider, useAtlas } from './atlas-context';
11
11
  import { Gazetteer } from './gazetteer';
12
12
 
13
+ // The finder brings every spec parser with it. It loads as soon as the page has drawn, long before anyone presses ⌘K.
14
+ const loadFinder = () => import('../find/Finder').then((m) => ({ default: m.Finder }));
15
+ const Finder = lazy(loadFinder);
16
+ if (typeof window !== 'undefined') setTimeout(() => void loadFinder(), 0);
17
+
13
18
  function Index() {
14
19
  const { pathname } = useLocation();
15
20
  const kind = kindOfAddress(pathname);
@@ -47,7 +52,9 @@ export function AppShell() {
47
52
  </main>
48
53
  </div>
49
54
  <SourcesPanel />
50
- <Finder />
55
+ <Suspense fallback={null}>
56
+ <Finder />
57
+ </Suspense>
51
58
  </div>
52
59
  </EvidenceProvider>
53
60
  </AtlasProvider>
@@ -9,6 +9,7 @@ import type { ReportBackend } from '../data/adapters/report-backend';
9
9
  import { getJson, LoadError } from '../data/adapters';
10
10
  import { useAdapter } from '../data/adapters/context';
11
11
  import { createReportBackend } from '../data/adapters/report-backend';
12
+ import { runtimeConfig, runtimeUrl } from '../runtime';
12
13
 
13
14
  const SourceListSchema = z
14
15
  .object({ schemaVersion: z.literal(1), sources: z.array(RemoteReportSourceSchema) })
@@ -35,15 +36,16 @@ export function useReportSources() {
35
36
 
36
37
  export function ReportSourcesProvider({ children }: { children: ReactNode }) {
37
38
  const adapter = useAdapter();
39
+ const server = runtimeUrl(runtimeConfig()?.dataUrl);
38
40
  const defaultConfig = useMemo<RemoteReportSource>(
39
41
  () => ({
40
42
  id: 'workspace',
41
- label: adapter.kind === 'dev' ? 'Workspace runs' : 'Published reports',
43
+ label: server ? 'Atlas server' : adapter.kind === 'dev' ? 'Workspace runs' : 'Published reports',
42
44
  type: 'http',
43
- baseUrl: adapter.kind === 'dev' ? '/__atlas/' : (import.meta.env.VITE_ATLAS_BASE_URL ?? './data/'),
44
- live: adapter.kind === 'dev'
45
+ baseUrl: server ?? (adapter.kind === 'dev' ? '/__atlas/' : (import.meta.env.VITE_ATLAS_BASE_URL ?? './data/')),
46
+ live: server !== undefined || adapter.kind === 'dev'
45
47
  }),
46
- [adapter]
48
+ [adapter, server]
47
49
  );
48
50
  const configBase = defaultConfig.baseUrl.endsWith('/') ? defaultConfig.baseUrl : `${defaultConfig.baseUrl}/`;
49
51
  const configUrl = new URL(import.meta.env.VITE_ATLAS_SOURCES_URL ?? 'sources.json', new URL(configBase, window.location.href)).href;
@@ -1,8 +1,7 @@
1
- import { createHashHistory, createRootRoute, createRoute, createRouter, type RouterHistory } from '@tanstack/react-router';
1
+ import { createHashHistory, createRootRoute, createRoute, createRouter, lazyRouteComponent, type RouterHistory } from '@tanstack/react-router';
2
2
  import { z } from 'zod/v4';
3
3
 
4
4
  import { SpecPage } from '../evidence/spec-page';
5
- import { ChartPage } from '../views/ChartPage';
6
5
  import { ProductPage } from '../views/ProductPage';
7
6
  import { AppShell } from './AppShell';
8
7
 
@@ -44,7 +43,8 @@ function routeTree() {
44
43
  getParentRoute: () => rootRoute,
45
44
  path: '/chart/$chartId',
46
45
  validateSearch: (search) => ChartSearch.parse(search),
47
- component: ChartPage
46
+ // The map (the graph, its layout and its renderer) is the largest part of the page and only this route needs it.
47
+ component: lazyRouteComponent(() => import('../views/ChartPage'), 'ChartPage')
48
48
  });
49
49
  const specRoute = createRoute({
50
50
  getParentRoute: () => rootRoute,
@@ -87,6 +87,40 @@
87
87
  animation: pulse 1.4s var(--ease) infinite;
88
88
  }
89
89
 
90
+ .connection {
91
+ display: inline-flex;
92
+ align-items: center;
93
+ gap: 8px;
94
+ color: var(--ink-3);
95
+ font-size: 0.8125rem;
96
+ font-weight: 600;
97
+ white-space: nowrap;
98
+ }
99
+
100
+ .connectionDot {
101
+ width: 8px;
102
+ height: 8px;
103
+ border-radius: 50%;
104
+ background: var(--ink-3);
105
+ }
106
+
107
+ .connection[data-status='live'] {
108
+ color: var(--place);
109
+ }
110
+
111
+ .connection[data-status='live'] .connectionDot {
112
+ background: var(--place);
113
+ }
114
+
115
+ .connection[data-status='reconnecting'] {
116
+ color: var(--failed-ink);
117
+ }
118
+
119
+ .connection[data-status='reconnecting'] .connectionDot {
120
+ background: currentColor;
121
+ animation: pulse 1.4s var(--ease) infinite;
122
+ }
123
+
90
124
  @keyframes pulse {
91
125
  50% {
92
126
  opacity: 0.35;
@@ -195,6 +229,7 @@
195
229
  }
196
230
 
197
231
  .live,
232
+ .connection,
198
233
  .picker {
199
234
  display: none;
200
235
  }
@@ -1,14 +1,14 @@
1
1
  import { Link, useLocation, useNavigate, useSearch } from '@tanstack/react-router';
2
- import { useEffect, useMemo } from 'react';
2
+ import { useEffect, useMemo, useState } from 'react';
3
3
 
4
4
  import { useAtlas } from '../app/atlas-context';
5
- import { commandKey } from '../find/Finder';
6
- import { setFinderOpen } from '../find/open';
5
+ import { commandKey, setFinderOpen } from '../find/open';
7
6
  import type { AtlasView } from '../data/model';
8
7
  import { LATEST } from '../data/queries';
9
8
  import { useEvidence } from '../evidence/evidence-context';
10
9
  import { plural } from '../evidence/format';
11
10
  import { excludedCount } from '../evidence/sources-panel';
11
+ import { eventsAddress, listenLive, useLiveStatus, type ReportAnnouncement } from '../live/live-stream';
12
12
  import { kindOfAddress, outlinePath, SPEC_KINDS } from '../spec-kind';
13
13
  import { useUiStore } from '../state/ui-store';
14
14
  import { DataIssues } from './DataIssues';
@@ -69,6 +69,42 @@ function LiveRuns() {
69
69
  );
70
70
  }
71
71
 
72
+ /** Is this page being kept up to date by its server, and what arrived last. Nothing at all for a static site. */
73
+ function ServerConnection() {
74
+ const status = useLiveStatus();
75
+ const [arrival, setArrival] = useState<ReportAnnouncement | null>(null);
76
+ useEffect(() => {
77
+ const url = eventsAddress();
78
+ if (!url) return;
79
+ let timer: ReturnType<typeof setTimeout> | undefined;
80
+ const stop = listenLive(url, (event) => {
81
+ if (event.type !== 'report' || !event.report.added.length) return;
82
+ setArrival(event.report);
83
+ clearTimeout(timer);
84
+ timer = setTimeout(() => setArrival(null), 8_000);
85
+ });
86
+ return () => {
87
+ clearTimeout(timer);
88
+ stop();
89
+ };
90
+ }, []);
91
+ if (status === 'off') return null;
92
+ const first = arrival?.added[0];
93
+ const failed = arrival?.added.reduce((sum, layer) => sum + (layer.counts?.failed ?? 0), 0) ?? 0;
94
+ return (
95
+ <span className={styles.connection} data-status={status} role="status" title={status === 'live' ? 'This page updates as results reach the server.' : status === 'connecting' ? 'Connecting to the server.' : 'The connection to the server was lost. Trying again; the report on screen is the last one received.'}>
96
+ <span className={styles.connectionDot} aria-hidden="true" />
97
+ {arrival && first
98
+ ? `${first.producer}${first.environment ? ` · ${first.environment}` : ''}${arrival.addedTotal > 1 ? ` +${arrival.addedTotal - 1}` : ''}${failed ? ` · ${plural(failed, 'failure', 'failures')}` : ' · new results'}`
99
+ : status === 'live'
100
+ ? 'Live'
101
+ : status === 'connecting'
102
+ ? 'Connecting'
103
+ : 'Reconnecting'}
104
+ </span>
105
+ );
106
+ }
107
+
72
108
  function SourcesButton() {
73
109
  const { layers, ready, unavailable, excluded } = useEvidence();
74
110
  const setOpen = useUiStore((s) => s.setSourcesOpen);
@@ -77,7 +113,7 @@ function SourcesButton() {
77
113
  return (
78
114
  <button type="button" className={styles.sources} data-filtered={off > 0 || undefined} onClick={() => setOpen(true)}>
79
115
  Sources
80
- <span>{unavailable ? 'unavailable' : off > 0 ? `${off} off` : plural(layers.length, 'run', 'runs')}</span>
116
+ <span>{unavailable ? 'unavailable' : off > 0 ? `${off} off` : plural(layers.length, 'layer', 'layers')}</span>
81
117
  </button>
82
118
  );
83
119
  }
@@ -116,6 +152,7 @@ export function Header() {
116
152
  ))}
117
153
  </nav>
118
154
  <div className={styles.tools}>
155
+ <ServerConnection />
119
156
  <LiveRuns />
120
157
  {!kind && view && <RunPicker view={view} />}
121
158
  {!kind && view && <DataIssues issues={view.issues} />}
@@ -1,4 +1,6 @@
1
- import { AtlasChangeSchema, type AtlasChange } from '@crvouga/atlas/schema';
1
+ import type { AtlasChange } from '@crvouga/atlas/schema';
2
+
3
+ import { listenChanges } from '../../live/live-stream';
2
4
 
3
5
  export type { AtlasChange } from '@crvouga/atlas/schema';
4
6
 
@@ -93,20 +95,6 @@ export function createHttpAdapter(baseUrl: string, kind: AtlasAdapter['kind'] =
93
95
  function subscribeToEvents(url: string): NonNullable<AtlasAdapter['subscribe']> {
94
96
  const location = new URL(url);
95
97
  if (!['http:', 'https:'].includes(location.protocol) || location.username || location.password) throw new Error('Use an HTTP event URL without credentials.');
96
- return (onChange) => {
97
- if (typeof EventSource === 'undefined') return () => undefined;
98
- const stream = new EventSource(url);
99
- const receive = (event: MessageEvent<string>) => {
100
- try {
101
- const change = AtlasChangeSchema.safeParse(JSON.parse(event.data));
102
- if (change.success) onChange(change.data);
103
- } catch {
104
- return;
105
- }
106
- };
107
- stream.addEventListener('message', receive);
108
- stream.addEventListener('atlas:change', receive);
109
- stream.addEventListener('open', () => onChange({ scope: 'runs', files: [], runIds: [] }));
110
- return () => stream.close();
111
- };
98
+ // One connection per address, however many parts of the page listen to it.
99
+ return (onChange) => listenChanges(url, onChange);
112
100
  }
@@ -1,3 +1,4 @@
1
+ import { runtimeConfig, runtimeUrl } from '../../runtime';
1
2
  import { createHttpAdapter, type AtlasAdapter, type AtlasChange } from './adapter';
2
3
 
3
4
  export * from './adapter';
@@ -22,8 +23,16 @@ export function createDevAdapter(base = DEV_PREFIX, label = 'Live from disk', so
22
23
  };
23
24
  }
24
25
 
25
- /** The dev adapter under `vite dev`, the static adapter everywhere else. */
26
+ /** The server's own files, with its event stream: what a page served by `atlas serve` or `atlas dev` reads. */
27
+ export function createServerAdapter(dataUrl: string, eventsUrl: string | undefined): AtlasAdapter {
28
+ return { ...createHttpAdapter(dataUrl, 'static', eventsUrl), label: 'Atlas server' };
29
+ }
30
+
31
+ /** The server's adapter when the page was served by one, the dev adapter under a bare `vite dev`, the static adapter everywhere else. */
26
32
  export function createAdapter(): AtlasAdapter {
33
+ const config = runtimeConfig();
34
+ const dataUrl = runtimeUrl(config?.dataUrl);
35
+ if (dataUrl) return createServerAdapter(dataUrl, runtimeUrl(config?.eventsUrl));
27
36
  if (import.meta.env.DEV && import.meta.hot) return createDevAdapter();
28
37
  return createHttpAdapter(import.meta.env.VITE_ATLAS_BASE_URL ?? './data/');
29
38
  }
@@ -1,8 +1,20 @@
1
1
  import { evidenceFile } from '@crvouga/atlas/reports/export-evidence';
2
2
 
3
+ import { runtimeConfig } from '../runtime';
4
+
5
+ /**
6
+ * An Atlas server writes its address book into the page it serves (`atlas serve`, and `atlas dev` through
7
+ * Vite), so one build of the viewer works for every project. A build can instead be pointed at a reports
8
+ * API when it is made.
9
+ */
10
+ const runtime = runtimeConfig;
11
+
3
12
  /** A built site without a reports API reads the evidence exported beside it. */
4
- export const staticEvidence = !import.meta.env.DEV && !import.meta.env.VITE_ATLAS_REPORTS_URL;
5
- export const reportsBase = (import.meta.env.VITE_ATLAS_REPORTS_URL as string | undefined)?.replace(/\/$/, '') ?? (staticEvidence ? './data/evidence' : '/api/reports');
13
+ export const staticEvidence = !import.meta.env.DEV && !import.meta.env.VITE_ATLAS_REPORTS_URL && !runtime()?.reportsUrl;
14
+ export const reportsBase = (import.meta.env.VITE_ATLAS_REPORTS_URL as string | undefined)?.replace(/\/$/, '') ?? runtime()?.reportsUrl?.replace(/\/$/, '') ?? (staticEvidence ? './data/evidence' : '/api/reports');
15
+
16
+ /** Does the server answer `/evidence/effective`: the whole report in one request, without per-layer history? */
17
+ export const effectiveEvidence = () => runtime()?.effective === true;
6
18
 
7
19
  export class ReportsError extends Error {
8
20
  constructor(
@@ -0,0 +1,213 @@
1
+ .panel {
2
+ display: grid;
3
+ gap: 14px;
4
+ margin: 12px 0;
5
+ }
6
+
7
+ .panel h4 {
8
+ margin: 0 0 6px;
9
+ font-size: 0.78rem;
10
+ font-weight: 600;
11
+ letter-spacing: 0.04em;
12
+ text-transform: uppercase;
13
+ color: var(--faint);
14
+ }
15
+
16
+ .chips {
17
+ display: flex;
18
+ flex-wrap: wrap;
19
+ gap: 6px;
20
+ margin: 0;
21
+ padding: 0;
22
+ list-style: none;
23
+ }
24
+
25
+ .chip {
26
+ display: inline-flex;
27
+ gap: 4px;
28
+ padding: 2px 8px;
29
+ border-radius: var(--pill);
30
+ background: var(--unrun);
31
+ color: var(--ink-3);
32
+ font-size: 0.78rem;
33
+ }
34
+
35
+ .chip b {
36
+ font-weight: 600;
37
+ color: var(--ink-2, inherit);
38
+ }
39
+
40
+ .links a {
41
+ font-size: 0.85rem;
42
+ }
43
+
44
+ .gallery {
45
+ display: grid;
46
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
47
+ gap: 12px;
48
+ margin: 0;
49
+ padding: 0;
50
+ list-style: none;
51
+ }
52
+
53
+ .figure {
54
+ display: grid;
55
+ gap: 4px;
56
+ margin: 0;
57
+ min-width: 0;
58
+ }
59
+
60
+ .figure[data-wide] {
61
+ grid-column: 1 / -1;
62
+ }
63
+
64
+ .figure img,
65
+ .figure video {
66
+ width: 100%;
67
+ max-height: 420px;
68
+ object-fit: contain;
69
+ border: 1px solid var(--line, #dfe3e8);
70
+ border-radius: 6px;
71
+ background: #f6f7f9;
72
+ }
73
+
74
+ .figure iframe {
75
+ width: 100%;
76
+ height: 360px;
77
+ border: 1px solid var(--line, #dfe3e8);
78
+ border-radius: 6px;
79
+ background: #fff;
80
+ }
81
+
82
+ .figure audio {
83
+ width: 100%;
84
+ }
85
+
86
+ .figure figcaption {
87
+ display: flex;
88
+ flex-wrap: wrap;
89
+ gap: 6px;
90
+ align-items: baseline;
91
+ font-size: 0.8rem;
92
+ color: var(--ink-3);
93
+ }
94
+
95
+ .figure figcaption strong {
96
+ font-weight: 600;
97
+ overflow-wrap: anywhere;
98
+ }
99
+
100
+ .role {
101
+ padding: 0 6px;
102
+ border-radius: var(--pill);
103
+ background: var(--unrun);
104
+ font-size: 0.72rem;
105
+ }
106
+
107
+ .text {
108
+ max-height: 260px;
109
+ margin: 0;
110
+ padding: 8px 10px;
111
+ overflow: auto;
112
+ border: 1px solid var(--line, #dfe3e8);
113
+ border-radius: 6px;
114
+ background: #f6f7f9;
115
+ font: 0.78rem/1.45 ui-monospace, SFMono-Regular, Menlo, monospace;
116
+ white-space: pre-wrap;
117
+ overflow-wrap: anywhere;
118
+ }
119
+
120
+ .timeline,
121
+ .timeline ol {
122
+ display: grid;
123
+ gap: 4px;
124
+ margin: 0;
125
+ padding: 0;
126
+ list-style: none;
127
+ }
128
+
129
+ .timeline ol {
130
+ margin-left: 18px;
131
+ padding-left: 8px;
132
+ border-left: 1px solid var(--line, #dfe3e8);
133
+ }
134
+
135
+ .step {
136
+ display: grid;
137
+ gap: 4px;
138
+ }
139
+
140
+ .stepRow {
141
+ display: flex;
142
+ gap: 8px;
143
+ align-items: center;
144
+ font-size: 0.9rem;
145
+ }
146
+
147
+ .stepRow .spacer {
148
+ flex: 1;
149
+ }
150
+
151
+ .stepKind,
152
+ .stepTime {
153
+ font-size: 0.75rem;
154
+ color: var(--faint);
155
+ }
156
+
157
+ .step[data-status='failed'] > .stepRow .stepName {
158
+ color: var(--failed);
159
+ }
160
+
161
+ .stepDetail {
162
+ margin: 0 0 0 24px;
163
+ font-size: 0.82rem;
164
+ color: var(--ink-3);
165
+ white-space: pre-wrap;
166
+ }
167
+
168
+ .notes {
169
+ display: grid;
170
+ gap: 6px;
171
+ margin: 0;
172
+ padding: 0;
173
+ list-style: none;
174
+ }
175
+
176
+ .note {
177
+ display: flex;
178
+ gap: 8px;
179
+ align-items: baseline;
180
+ font-size: 0.88rem;
181
+ }
182
+
183
+ .level {
184
+ flex: none;
185
+ padding: 0 7px;
186
+ border-radius: var(--pill);
187
+ background: var(--unrun);
188
+ color: var(--ink-3);
189
+ font-size: 0.72rem;
190
+ text-transform: uppercase;
191
+ letter-spacing: 0.04em;
192
+ }
193
+
194
+ .level[data-level='warning'] {
195
+ background: #fff4d6;
196
+ color: #7a5200;
197
+ }
198
+
199
+ .level[data-level='error'] {
200
+ background: #fde4e4;
201
+ color: var(--failed);
202
+ }
203
+
204
+ .where {
205
+ color: var(--faint);
206
+ font-size: 0.78rem;
207
+ }
208
+
209
+ .raw summary {
210
+ cursor: pointer;
211
+ font-size: 0.82rem;
212
+ color: var(--ink-3);
213
+ }