paseo-plugin-genui 0.0.0-stage → 0.1.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 (375) hide show
  1. package/LICENSE +202 -0
  2. package/OVERVIEW.md +21 -0
  3. package/README.md +77 -2
  4. package/assets/fonts/Excalifont-OFL.txt +109 -0
  5. package/assets/fonts/Excalifont-Regular-latin.woff2 +0 -0
  6. package/assets/icon.png +0 -0
  7. package/assets/icon.svg +1 -0
  8. package/assets/screenshot-chat.png +0 -0
  9. package/assets/screenshot-gallery.png +0 -0
  10. package/assets/screenshot-playground.png +0 -0
  11. package/client/components/content.tsx +468 -0
  12. package/client/components/data.tsx +967 -0
  13. package/client/components/dev.tsx +998 -0
  14. package/client/components/diagram.tsx +513 -0
  15. package/client/components/inputs.tsx +994 -0
  16. package/client/components/layout.tsx +239 -0
  17. package/client/components/media.tsx +428 -0
  18. package/client/components/project.tsx +641 -0
  19. package/client/components/widgets.tsx +836 -0
  20. package/client/gallery.tsx +449 -0
  21. package/client/live-ui.tsx +525 -0
  22. package/client/loaders.ts +342 -0
  23. package/client/markdown.tsx +172 -0
  24. package/client/node-renderer.tsx +149 -0
  25. package/client/render.tsx +186 -0
  26. package/client/runtime.ts +103 -0
  27. package/client/settings.tsx +57 -0
  28. package/client/web.ts +186 -0
  29. package/gallery/Acceptance-baseline.ui +1 -0
  30. package/gallery/Acceptance-checklist.ui +14 -0
  31. package/gallery/Acceptance-evidence.ui +9 -0
  32. package/gallery/Acceptance.ui +1 -0
  33. package/gallery/Badge.ui +3 -0
  34. package/gallery/Benchmark-context.ui +8 -0
  35. package/gallery/Benchmark-hyperfine.ui +1 -0
  36. package/gallery/Benchmark-runs-list.ui +9 -0
  37. package/gallery/Benchmark-runs.ui +1 -0
  38. package/gallery/Benchmark-vitest.ui +1 -0
  39. package/gallery/Benchmark.ui +9 -0
  40. package/gallery/Board-bb-tasks.ui +1 -0
  41. package/gallery/Board-gh-issues.ui +1 -0
  42. package/gallery/Board-gh-prs.ui +1 -0
  43. package/gallery/Board.ui +12 -0
  44. package/gallery/Button-destructive.ui +4 -0
  45. package/gallery/Button.ui +5 -0
  46. package/gallery/Calendar.ui +15 -0
  47. package/gallery/CalendarHeatmap-short.ui +11 -0
  48. package/gallery/CalendarHeatmap.ui +4 -0
  49. package/gallery/Callout.ui +4 -0
  50. package/gallery/Card.ui +4 -0
  51. package/gallery/Carousel.ui +8 -0
  52. package/gallery/Changes-paths.ui +1 -0
  53. package/gallery/Changes-uncommitted.ui +1 -0
  54. package/gallery/Changes.ui +1 -0
  55. package/gallery/Chart-area.ui +3 -0
  56. package/gallery/Chart-funnel.ui +3 -0
  57. package/gallery/Chart-heatmap.ui +11 -0
  58. package/gallery/Chart-pie.ui +3 -0
  59. package/gallery/Chart-radar.ui +3 -0
  60. package/gallery/Chart-scatter.ui +4 -0
  61. package/gallery/Chart-stacked.ui +5 -0
  62. package/gallery/Chart.ui +3 -0
  63. package/gallery/Checklist.ui +6 -0
  64. package/gallery/Choice.ui +8 -0
  65. package/gallery/Code.ui +3 -0
  66. package/gallery/Commits-limit.ui +1 -0
  67. package/gallery/Commits.ui +1 -0
  68. package/gallery/Compare-conditions.ui +4 -0
  69. package/gallery/Compare-three.ui +7 -0
  70. package/gallery/Compare.ui +4 -0
  71. package/gallery/Coverage-go.ui +1 -0
  72. package/gallery/Coverage-lcov.ui +1 -0
  73. package/gallery/Coverage-python.ui +1 -0
  74. package/gallery/Coverage.ui +1 -0
  75. package/gallery/DateInput.ui +5 -0
  76. package/gallery/Decision-percent.ui +10 -0
  77. package/gallery/Decision.ui +12 -0
  78. package/gallery/Dependencies-audit.ui +1 -0
  79. package/gallery/Dependencies-both.ui +1 -0
  80. package/gallery/Dependencies-list.ui +7 -0
  81. package/gallery/Dependencies-pip.ui +1 -0
  82. package/gallery/Dependencies-pnpm.ui +1 -0
  83. package/gallery/Dependencies.ui +1 -0
  84. package/gallery/Details.ui +4 -0
  85. package/gallery/Diagram-flow.ui +16 -0
  86. package/gallery/Diagram-sequence.ui +15 -0
  87. package/gallery/Diagram.ui +16 -0
  88. package/gallery/Diff.ui +3 -0
  89. package/gallery/Divider.ui +5 -0
  90. package/gallery/EditableTable.ui +9 -0
  91. package/gallery/Entity-list.ui +6 -0
  92. package/gallery/Entity.ui +8 -0
  93. package/gallery/Environments.ui +1 -0
  94. package/gallery/Estimate-points.ui +6 -0
  95. package/gallery/Estimate.ui +8 -0
  96. package/gallery/File.ui +4 -0
  97. package/gallery/Findings-biome.ui +1 -0
  98. package/gallery/Findings-eslint.ui +1 -0
  99. package/gallery/Findings-oxlint.ui +1 -0
  100. package/gallery/Findings-review.ui +1 -0
  101. package/gallery/Findings-ruff.ui +1 -0
  102. package/gallery/Findings-sarif.ui +1 -0
  103. package/gallery/Findings-ship.ui +11 -0
  104. package/gallery/Findings-tsc.ui +1 -0
  105. package/gallery/Findings.ui +7 -0
  106. package/gallery/Flashcards.ui +3 -0
  107. package/gallery/FollowUps.ui +4 -0
  108. package/gallery/Form.ui +8 -0
  109. package/gallery/Gallery-links.ui +8 -0
  110. package/gallery/Gallery-strip.ui +14 -0
  111. package/gallery/Gallery.ui +10 -0
  112. package/gallery/Gauge.ui +7 -0
  113. package/gallery/Grid.ui +8 -0
  114. package/gallery/Hotspots-photo.ui +8 -0
  115. package/gallery/Hotspots.ui +11 -0
  116. package/gallery/Icon.ui +5 -0
  117. package/gallery/Image.ui +4 -0
  118. package/gallery/ImageSearch-aspects.ui +6 -0
  119. package/gallery/ImageSearch.ui +4 -0
  120. package/gallery/Input.ui +5 -0
  121. package/gallery/Json-api.ui +1 -0
  122. package/gallery/Json.ui +8 -0
  123. package/gallery/KeyValue.ui +3 -0
  124. package/gallery/List-dots.ui +8 -0
  125. package/gallery/List.ui +8 -0
  126. package/gallery/ListEditor.ui +5 -0
  127. package/gallery/Logs-jsonl.ui +1 -0
  128. package/gallery/Logs-lines.ui +11 -0
  129. package/gallery/Logs-python.ui +1 -0
  130. package/gallery/Logs.ui +1 -0
  131. package/gallery/Map-city.ui +8 -0
  132. package/gallery/Map.ui +8 -0
  133. package/gallery/Metric.ui +3 -0
  134. package/gallery/OptionCards-multi.ui +10 -0
  135. package/gallery/OptionCards.ui +10 -0
  136. package/gallery/Pipeline-checks.ui +1 -0
  137. package/gallery/Pipeline-passed.ui +1 -0
  138. package/gallery/Pipeline-running.ui +1 -0
  139. package/gallery/Pipeline-stages.ui +13 -0
  140. package/gallery/Pipeline.ui +1 -0
  141. package/gallery/Plan.ui +9 -0
  142. package/gallery/Progress.ui +4 -0
  143. package/gallery/Provenance-deploy.ui +6 -0
  144. package/gallery/Provenance-no-receipt.ui +1 -0
  145. package/gallery/Provenance.ui +1 -0
  146. package/gallery/PullRequest.ui +1 -0
  147. package/gallery/Quiz.ui +6 -0
  148. package/gallery/Radio.ui +5 -0
  149. package/gallery/Rating.ui +5 -0
  150. package/gallery/Roadmap-sprint.ui +8 -0
  151. package/gallery/Roadmap-year.ui +9 -0
  152. package/gallery/Roadmap.ui +12 -0
  153. package/gallery/Row.ui +3 -0
  154. package/gallery/SegmentedBar-status.ui +8 -0
  155. package/gallery/SegmentedBar.ui +8 -0
  156. package/gallery/Select.ui +5 -0
  157. package/gallery/Slider.ui +7 -0
  158. package/gallery/Snippet.ui +3 -0
  159. package/gallery/Sources-chips.ui +4 -0
  160. package/gallery/Sources.ui +8 -0
  161. package/gallery/Sparkline.ui +6 -0
  162. package/gallery/Stack.ui +7 -0
  163. package/gallery/StackTrace-aggregate.ui +1 -0
  164. package/gallery/StackTrace-browser.ui +1 -0
  165. package/gallery/StackTrace-go.ui +1 -0
  166. package/gallery/StackTrace-java.ui +1 -0
  167. package/gallery/StackTrace-python.ui +1 -0
  168. package/gallery/StackTrace-rust.ui +1 -0
  169. package/gallery/StackTrace.ui +1 -0
  170. package/gallery/Status.ui +9 -0
  171. package/gallery/Stepper.ui +5 -0
  172. package/gallery/Steps.ui +8 -0
  173. package/gallery/Swatches-long-names.ui +4 -0
  174. package/gallery/Swatches-picker.ui +5 -0
  175. package/gallery/Swatches.ui +10 -0
  176. package/gallery/Table.ui +7 -0
  177. package/gallery/Tabs.ui +8 -0
  178. package/gallery/Tests-junit.ui +1 -0
  179. package/gallery/Tests-vitest-junit.ui +1 -0
  180. package/gallery/Tests-vitest.ui +1 -0
  181. package/gallery/Tests.ui +9 -0
  182. package/gallery/Text.ui +4 -0
  183. package/gallery/TextArea.ui +5 -0
  184. package/gallery/Threads-ids.ui +1 -0
  185. package/gallery/Threads.ui +1 -0
  186. package/gallery/Timeline.ui +8 -0
  187. package/gallery/Timer.ui +4 -0
  188. package/gallery/Toggle.ui +5 -0
  189. package/gallery/Transcript-text.ui +1 -0
  190. package/gallery/Transcript-untimed.ui +1 -0
  191. package/gallery/Transcript-whisper.ui +1 -0
  192. package/gallery/Transcript.ui +1 -0
  193. package/gallery/Tree.ui +3 -0
  194. package/gallery/Treemap-du.ui +1 -0
  195. package/gallery/Treemap-esbuild.ui +1 -0
  196. package/gallery/Treemap-tree.ui +7 -0
  197. package/gallery/Treemap.ui +18 -0
  198. package/gallery/Walkthrough.ui +9 -0
  199. package/gallery/Waterfall-har.ui +1 -0
  200. package/gallery/Waterfall-trace.ui +1 -0
  201. package/gallery/Waterfall.ui +11 -0
  202. package/gallery/data/acceptance/coil/viewport-lifecycle.json +25 -0
  203. package/gallery/data/acceptance/coil-gate.json +153 -0
  204. package/gallery/data/acceptance/orbit-baseline.json +163 -0
  205. package/gallery/data/acceptance/shots/gate-cell-opened.png +0 -0
  206. package/gallery/data/acceptance/shots/gate-light.png +0 -0
  207. package/gallery/data/acceptance/shots/gate-phone-dark.png +0 -0
  208. package/gallery/data/activity.json +1 -0
  209. package/gallery/data/bb-tasks-orb.json +420 -0
  210. package/gallery/data/biome.json +229 -0
  211. package/gallery/data/compare/status-after.png +0 -0
  212. package/gallery/data/compare/status-before.png +0 -0
  213. package/gallery/data/compare/status-dark-2x.png +0 -0
  214. package/gallery/data/compare/status-rerender.png +0 -0
  215. package/gallery/data/coverage-py.json +1 -0
  216. package/gallery/data/coverage-summary.json +1 -0
  217. package/gallery/data/coverage.out +23 -0
  218. package/gallery/data/deploys.json +1 -0
  219. package/gallery/data/device-runs.json +285 -0
  220. package/gallery/data/du-node-modules.txt +359 -0
  221. package/gallery/data/esbuild-meta.json +292 -0
  222. package/gallery/data/eslint.json +266 -0
  223. package/gallery/data/eslint.sarif +343 -0
  224. package/gallery/data/findings-review.json +76 -0
  225. package/gallery/data/gh-issues-nextjs.json +293 -0
  226. package/gallery/data/gh-pr-checks.json +272 -0
  227. package/gallery/data/gh-prs-nextjs.json +419 -0
  228. package/gallery/data/gh-run-failed.json +1 -0
  229. package/gallery/data/gh-run-passed.json +1 -0
  230. package/gallery/data/gh-run-running.json +1 -0
  231. package/gallery/data/github-release.json +57 -0
  232. package/gallery/data/hyperfine-startup.json +187 -0
  233. package/gallery/data/lcov.info +234 -0
  234. package/gallery/data/logs/media-sync.log +127 -0
  235. package/gallery/data/logs/thumbnailer.jsonl +17 -0
  236. package/gallery/data/logs/vitest-run.log +89 -0
  237. package/gallery/data/npm-audit.json +672 -0
  238. package/gallery/data/npm-outdated.json +179 -0
  239. package/gallery/data/oxlint.json +156 -0
  240. package/gallery/data/pip-outdated.json +68 -0
  241. package/gallery/data/pnpm-outdated.json +58 -0
  242. package/gallery/data/provenance/devicectl-install.json +35 -0
  243. package/gallery/data/provenance/install-timeout.log +4 -0
  244. package/gallery/data/provenance/iphone-install.json +72 -0
  245. package/gallery/data/provenance/iphone-no-receipt.json +57 -0
  246. package/gallery/data/provenance/live-home.jpg +0 -0
  247. package/gallery/data/provenance/live-probe.txt +10 -0
  248. package/gallery/data/provenance/xcodebuild-2811.log +19 -0
  249. package/gallery/data/provenance/xcodebuild-4712.log +19 -0
  250. package/gallery/data/pytest-junit.xml +64 -0
  251. package/gallery/data/python-org-trace.json +35 -0
  252. package/gallery/data/python-org.har +31 -0
  253. package/gallery/data/retry.ts +13 -0
  254. package/gallery/data/ruff.json +261 -0
  255. package/gallery/data/src/durations.py +63 -0
  256. package/gallery/data/src/json-logic.ts +156 -0
  257. package/gallery/data/src/mapMath.ts +135 -0
  258. package/gallery/data/src/semver/bump.go +73 -0
  259. package/gallery/data/traces/browser-error.json +5 -0
  260. package/gallery/data/traces/go/main.go +27 -0
  261. package/gallery/data/traces/go-panic.txt +16 -0
  262. package/gallery/data/traces/java-caused-by.txt +15 -0
  263. package/gallery/data/traces/node-aggregate.txt +30 -0
  264. package/gallery/data/traces/node-cause.txt +21 -0
  265. package/gallery/data/traces/py/deploy.json +5 -0
  266. package/gallery/data/traces/py/deploy.py +17 -0
  267. package/gallery/data/traces/py/settings.py +19 -0
  268. package/gallery/data/traces/python-chain.txt +30 -0
  269. package/gallery/data/traces/rust/main.rs +11 -0
  270. package/gallery/data/traces/rust-panic.txt +16 -0
  271. package/gallery/data/traces/shop/cart.mjs +19 -0
  272. package/gallery/data/traces/shop/pricing.mjs +12 -0
  273. package/gallery/data/traces/shop/status.mjs +9 -0
  274. package/gallery/data/traces/web/app.js +11 -0
  275. package/gallery/data/traces/web/index.html +1 -0
  276. package/gallery/data/traces/web/search.js +10 -0
  277. package/gallery/data/transcript/call-noisy.wav +0 -0
  278. package/gallery/data/transcript/call.json +362 -0
  279. package/gallery/data/transcript/call.wav +0 -0
  280. package/gallery/data/transcript/mlx-whisper-tiny.en-noisy.json +1 -0
  281. package/gallery/data/transcript/whisper-cpp-base.en-noisy.json +658 -0
  282. package/gallery/data/transcript/whisper-cpp-base.en.json +658 -0
  283. package/gallery/data/transcript/whisper-cpp-base.en.srt +16 -0
  284. package/gallery/data/transcript/whisper-cpp-tiny.en-noisy.json +619 -0
  285. package/gallery/data/tsc.txt +4 -0
  286. package/gallery/data/vitest-bench.json +119 -0
  287. package/gallery/data/vitest-junit.xml +133 -0
  288. package/gallery/data/vitest-report.json +612 -0
  289. package/gallery/images/bell.svg +10 -0
  290. package/gallery/images/bike.svg +47 -0
  291. package/gallery/images/footer-planet.webp +0 -0
  292. package/gallery/images/front-light.svg +13 -0
  293. package/gallery/images/golden-hour.webp +0 -0
  294. package/gallery/images/option-flowers.webp +0 -0
  295. package/gallery/images/option-hilltop.webp +0 -0
  296. package/gallery/images/option-meadow.webp +0 -0
  297. package/gallery/images/option-sky.webp +0 -0
  298. package/gallery/images/u-lock.svg +10 -0
  299. package/index.client.tsx +164 -0
  300. package/index.server.ts +216 -0
  301. package/package.json +50 -4
  302. package/paseo-plugin.json +14 -0
  303. package/server/data-source.ts +407 -0
  304. package/server/project.ts +981 -0
  305. package/server/web/address.ts +57 -0
  306. package/server/web/cache.ts +85 -0
  307. package/server/web/commons.ts +126 -0
  308. package/server/web/geocode.ts +40 -0
  309. package/server/web/image.ts +35 -0
  310. package/server/web/lookups.ts +248 -0
  311. package/server/web/net.ts +210 -0
  312. package/shared/core/acceptance.ts +744 -0
  313. package/shared/core/ast.ts +76 -0
  314. package/shared/core/benchmark.ts +743 -0
  315. package/shared/core/catalog.ts +733 -0
  316. package/shared/core/compare.ts +225 -0
  317. package/shared/core/coverage.ts +456 -0
  318. package/shared/core/data.ts +334 -0
  319. package/shared/core/decisions.ts +527 -0
  320. package/shared/core/dependencies.ts +604 -0
  321. package/shared/core/diagnostics.ts +24 -0
  322. package/shared/core/environments.ts +212 -0
  323. package/shared/core/evaluate.ts +737 -0
  324. package/shared/core/fields.ts +66 -0
  325. package/shared/core/findings.ts +1172 -0
  326. package/shared/core/form.ts +69 -0
  327. package/shared/core/index.ts +44 -0
  328. package/shared/core/junit.ts +252 -0
  329. package/shared/core/lexer.ts +275 -0
  330. package/shared/core/logs.ts +496 -0
  331. package/shared/core/markdown.ts +2374 -0
  332. package/shared/core/parser.ts +355 -0
  333. package/shared/core/perf-units.ts +228 -0
  334. package/shared/core/pipeline.ts +679 -0
  335. package/shared/core/project.ts +472 -0
  336. package/shared/core/provenance.ts +725 -0
  337. package/shared/core/stack-trace.ts +718 -0
  338. package/shared/core/streaming.ts +136 -0
  339. package/shared/core/test-results.ts +562 -0
  340. package/shared/core/thread-activity.ts +203 -0
  341. package/shared/core/tracking.ts +887 -0
  342. package/shared/core/transcript.ts +1364 -0
  343. package/shared/core/treemap.ts +446 -0
  344. package/shared/core/types.ts +70 -0
  345. package/shared/core/validate.ts +574 -0
  346. package/shared/core/waterfall.ts +536 -0
  347. package/shared/diagram/flowchart.ts +205 -0
  348. package/shared/diagram/layout.ts +440 -0
  349. package/shared/diagram/markdown.ts +135 -0
  350. package/shared/diagram/sequence.ts +122 -0
  351. package/shared/diagram/zoom.ts +114 -0
  352. package/shared/fallback.ts +120 -0
  353. package/shared/genui.test.ts +122 -0
  354. package/shared/instructions.ts +144 -0
  355. package/shared/logic/calendarMath.ts +130 -0
  356. package/shared/logic/chartMath.ts +289 -0
  357. package/shared/logic/choose-logic.ts +196 -0
  358. package/shared/logic/compare-logic.ts +270 -0
  359. package/shared/logic/content-model.ts +227 -0
  360. package/shared/logic/environments-logic.ts +53 -0
  361. package/shared/logic/explain-logic.ts +315 -0
  362. package/shared/logic/fieldLogic.ts +138 -0
  363. package/shared/logic/gallery-search.ts +71 -0
  364. package/shared/logic/icons.ts +322 -0
  365. package/shared/logic/json-logic.ts +153 -0
  366. package/shared/logic/mapMath.ts +133 -0
  367. package/shared/logic/project-logic.ts +39 -0
  368. package/shared/logic/references-model.ts +201 -0
  369. package/shared/logic/sketch.ts +165 -0
  370. package/shared/logic/supersession.ts +77 -0
  371. package/shared/logic/values.ts +133 -0
  372. package/shared/logic/widget-logic.ts +163 -0
  373. package/shared/rpc.ts +252 -0
  374. package/shared/segment.ts +81 -0
  375. package/shared/settings.ts +12 -0
@@ -0,0 +1,612 @@
1
+ {
2
+ "numTotalTestSuites": 19,
3
+ "numPassedTestSuites": 17,
4
+ "numFailedTestSuites": 2,
5
+ "numPendingTestSuites": 0,
6
+ "numTotalTests": 39,
7
+ "numPassedTests": 34,
8
+ "numFailedTests": 3,
9
+ "numPendingTests": 1,
10
+ "numTodoTests": 1,
11
+ "startTime": 1791586341356,
12
+ "success": false,
13
+ "testResults": [
14
+ {
15
+ "assertionResults": [
16
+ {
17
+ "ancestorTitles": [
18
+ "formMessage"
19
+ ],
20
+ "fullName": "formMessage lists every field at any depth in document order",
21
+ "status": "passed",
22
+ "title": "lists every field at any depth in document order",
23
+ "duration": 6.822,
24
+ "failureMessages": [],
25
+ "location": {
26
+ "line": 17,
27
+ "column": 3
28
+ }
29
+ },
30
+ {
31
+ "ancestorTitles": [
32
+ "formMessage"
33
+ ],
34
+ "fullName": "formMessage labels unlabeled fields with their state name",
35
+ "status": "passed",
36
+ "title": "labels unlabeled fields with their state name",
37
+ "duration": 0.903,
38
+ "failureMessages": [],
39
+ "location": {
40
+ "line": 32,
41
+ "column": 3
42
+ }
43
+ },
44
+ {
45
+ "ancestorTitles": [
46
+ "formMessage"
47
+ ],
48
+ "fullName": "formMessage does not add a colon after a question or colon label",
49
+ "status": "passed",
50
+ "title": "does not add a colon after a question or colon label",
51
+ "duration": 0.594,
52
+ "failureMessages": [],
53
+ "location": {
54
+ "line": 40,
55
+ "column": 3
56
+ }
57
+ },
58
+ {
59
+ "ancestorTitles": [
60
+ "formMessage"
61
+ ],
62
+ "fullName": "formMessage writes empty values as a dash",
63
+ "status": "passed",
64
+ "title": "writes empty values as a dash",
65
+ "duration": 1.075,
66
+ "failureMessages": [],
67
+ "location": {
68
+ "line": 48,
69
+ "column": 3
70
+ }
71
+ },
72
+ {
73
+ "ancestorTitles": [
74
+ "formMessage"
75
+ ],
76
+ "fullName": "formMessage joins lists, says Yes/No for booleans and formats numbers",
77
+ "status": "passed",
78
+ "title": "joins lists, says Yes/No for booleans and formats numbers",
79
+ "duration": 1.114,
80
+ "failureMessages": [],
81
+ "location": {
82
+ "line": 58,
83
+ "column": 3
84
+ }
85
+ },
86
+ {
87
+ "ancestorTitles": [
88
+ "formMessage"
89
+ ],
90
+ "fullName": "formMessage is empty for a form without fields",
91
+ "status": "passed",
92
+ "title": "is empty for a form without fields",
93
+ "duration": 0.365,
94
+ "failureMessages": [],
95
+ "location": {
96
+ "line": 79,
97
+ "column": 3
98
+ }
99
+ }
100
+ ],
101
+ "startTime": 1791586341618,
102
+ "endTime": 1791586341629.3645,
103
+ "status": "passed",
104
+ "message": "",
105
+ "name": "/workspace/bb-plugin-genui/core/form.test.ts"
106
+ },
107
+ {
108
+ "assertionResults": [
109
+ {
110
+ "ancestorTitles": [
111
+ "readJUnit"
112
+ ],
113
+ "fullName": "readJUnit reads a pytest report: failures, errors and skips with their messages and output",
114
+ "status": "passed",
115
+ "title": "reads a pytest report: failures, errors and skips with their messages and output",
116
+ "duration": 1.77,
117
+ "failureMessages": [],
118
+ "location": {
119
+ "line": 40,
120
+ "column": 3
121
+ }
122
+ },
123
+ {
124
+ "ancestorTitles": [
125
+ "readJUnit"
126
+ ],
127
+ "fullName": "readJUnit takes a lone testsuite root and inherits nested suite names and files",
128
+ "status": "passed",
129
+ "title": "takes a lone testsuite root and inherits nested suite names and files",
130
+ "duration": 0.149,
131
+ "failureMessages": [],
132
+ "location": {
133
+ "line": 60,
134
+ "column": 3
135
+ }
136
+ },
137
+ {
138
+ "ancestorTitles": [
139
+ "readJUnit"
140
+ ],
141
+ "fullName": "readJUnit keeps the trace and the message when the body does not repeat it",
142
+ "status": "passed",
143
+ "title": "keeps the trace and the message when the body does not repeat it",
144
+ "duration": 0.145,
145
+ "failureMessages": [],
146
+ "location": {
147
+ "line": 72,
148
+ "column": 3
149
+ }
150
+ },
151
+ {
152
+ "ancestorTitles": [
153
+ "readJUnit"
154
+ ],
155
+ "fullName": "readJUnit refuses XML that is not a JUnit report, saying what it is",
156
+ "status": "passed",
157
+ "title": "refuses XML that is not a JUnit report, saying what it is",
158
+ "duration": 0.119,
159
+ "failureMessages": [],
160
+ "location": {
161
+ "line": 79,
162
+ "column": 3
163
+ }
164
+ },
165
+ {
166
+ "ancestorTitles": [
167
+ "readJUnit"
168
+ ],
169
+ "fullName": "readJUnit refuses DOCTYPEs, so entity declarations can never expand",
170
+ "status": "passed",
171
+ "title": "refuses DOCTYPEs, so entity declarations can never expand",
172
+ "duration": 0.166,
173
+ "failureMessages": [],
174
+ "location": {
175
+ "line": 85,
176
+ "column": 3
177
+ }
178
+ },
179
+ {
180
+ "ancestorTitles": [
181
+ "readJUnit"
182
+ ],
183
+ "fullName": "readJUnit reports malformed XML with its line",
184
+ "status": "passed",
185
+ "title": "reports malformed XML with its line",
186
+ "duration": 0.242,
187
+ "failureMessages": [],
188
+ "location": {
189
+ "line": 95,
190
+ "column": 3
191
+ }
192
+ },
193
+ {
194
+ "ancestorTitles": [
195
+ "readJUnit"
196
+ ],
197
+ "fullName": "readJUnit refuses nesting deep enough to matter",
198
+ "status": "passed",
199
+ "title": "refuses nesting deep enough to matter",
200
+ "duration": 0.096,
201
+ "failureMessages": [],
202
+ "location": {
203
+ "line": 107,
204
+ "column": 3
205
+ }
206
+ },
207
+ {
208
+ "ancestorTitles": [
209
+ "readJUnit"
210
+ ],
211
+ "fullName": "readJUnit returns suites when there are more tests than one list holds",
212
+ "status": "passed",
213
+ "title": "returns suites when there are more tests than one list holds",
214
+ "duration": 1.914,
215
+ "failureMessages": [],
216
+ "location": {
217
+ "line": 111,
218
+ "column": 3
219
+ }
220
+ },
221
+ {
222
+ "ancestorTitles": [
223
+ "parseXml"
224
+ ],
225
+ "fullName": "parseXml skips comments and processing instructions and joins text around CDATA",
226
+ "status": "passed",
227
+ "title": "skips comments and processing instructions and joins text around CDATA",
228
+ "duration": 0.328,
229
+ "failureMessages": [],
230
+ "location": {
231
+ "line": 127,
232
+ "column": 3
233
+ }
234
+ }
235
+ ],
236
+ "startTime": 1791586341521,
237
+ "endTime": 1791586341526.3284,
238
+ "status": "passed",
239
+ "message": "",
240
+ "name": "/workspace/bb-plugin-genui/core/junit.test.ts"
241
+ },
242
+ {
243
+ "assertionResults": [
244
+ {
245
+ "ancestorTitles": [
246
+ "readTestRun: plain lists"
247
+ ],
248
+ "fullName": "readTestRun: plain lists reads the catalog shape, splitting `file:line` and counting by status",
249
+ "status": "passed",
250
+ "title": "reads the catalog shape, splitting `file:line` and counting by status",
251
+ "duration": 1.568,
252
+ "failureMessages": [],
253
+ "location": {
254
+ "line": 27,
255
+ "column": 3
256
+ }
257
+ },
258
+ {
259
+ "ancestorTitles": [
260
+ "readTestRun: plain lists"
261
+ ],
262
+ "fullName": "readTestRun: plain lists reads suites of tests, as a very large JUnit report arrives",
263
+ "status": "passed",
264
+ "title": "reads suites of tests, as a very large JUnit report arrives",
265
+ "duration": 0.147,
266
+ "failureMessages": [],
267
+ "location": {
268
+ "line": 47,
269
+ "column": 3
270
+ }
271
+ },
272
+ {
273
+ "ancestorTitles": [
274
+ "readTestRun: plain lists"
275
+ ],
276
+ "fullName": "readTestRun: plain lists says what it needs when nothing in the value is a test",
277
+ "status": "passed",
278
+ "title": "says what it needs when nothing in the value is a test",
279
+ "duration": 0.129,
280
+ "failureMessages": [],
281
+ "location": {
282
+ "line": 55,
283
+ "column": 3
284
+ }
285
+ },
286
+ {
287
+ "ancestorTitles": [
288
+ "readTestRun: plain lists"
289
+ ],
290
+ "fullName": "readTestRun: plain lists locates a failure with no line from the first app frame of its trace",
291
+ "status": "passed",
292
+ "title": "locates a failure with no line from the first app frame of its trace",
293
+ "duration": 1.231,
294
+ "failureMessages": [],
295
+ "location": {
296
+ "line": 64,
297
+ "column": 3
298
+ }
299
+ },
300
+ {
301
+ "ancestorTitles": [
302
+ "readTestRun: vitest and jest JSON"
303
+ ],
304
+ "fullName": "readTestRun: vitest and jest JSON reads files, names with their describe blocks, and the wall-clock duration",
305
+ "status": "passed",
306
+ "title": "reads files, names with their describe blocks, and the wall-clock duration",
307
+ "duration": 0.374,
308
+ "failureMessages": [],
309
+ "location": {
310
+ "line": 118,
311
+ "column": 3
312
+ }
313
+ },
314
+ {
315
+ "ancestorTitles": [
316
+ "testStatus"
317
+ ],
318
+ "fullName": "testStatus maps the reporters' words onto three statuses, keeping the telling ones",
319
+ "status": "passed",
320
+ "title": "maps the reporters' words onto three statuses, keeping the telling ones",
321
+ "duration": 0.129,
322
+ "failureMessages": [],
323
+ "location": {
324
+ "line": 134,
325
+ "column": 3
326
+ }
327
+ },
328
+ {
329
+ "ancestorTitles": [
330
+ "groupTests and text"
331
+ ],
332
+ "fullName": "groupTests and text groups by suite, else file, in first-seen order with counts and time",
333
+ "status": "passed",
334
+ "title": "groups by suite, else file, in first-seen order with counts and time",
335
+ "duration": 0.206,
336
+ "failureMessages": [],
337
+ "location": {
338
+ "line": 161,
339
+ "column": 3
340
+ }
341
+ },
342
+ {
343
+ "ancestorTitles": [
344
+ "groupTests and text"
345
+ ],
346
+ "fullName": "groupTests and text writes counts failures first and durations at a readable precision",
347
+ "status": "passed",
348
+ "title": "writes counts failures first and durations at a readable precision",
349
+ "duration": 0.166,
350
+ "failureMessages": [],
351
+ "location": {
352
+ "line": 175,
353
+ "column": 3
354
+ }
355
+ },
356
+ {
357
+ "ancestorTitles": [
358
+ "ANSI"
359
+ ],
360
+ "fullName": "ANSI splits colour runs and drops every other escape",
361
+ "status": "passed",
362
+ "title": "splits colour runs and drops every other escape",
363
+ "duration": 0.387,
364
+ "failureMessages": [],
365
+ "location": {
366
+ "line": 191,
367
+ "column": 3
368
+ }
369
+ },
370
+ {
371
+ "ancestorTitles": [
372
+ "ANSI"
373
+ ],
374
+ "fullName": "ANSI carries a colour across line breaks",
375
+ "status": "passed",
376
+ "title": "carries a colour across line breaks",
377
+ "duration": 0.216,
378
+ "failureMessages": [],
379
+ "location": {
380
+ "line": 208,
381
+ "column": 3
382
+ }
383
+ },
384
+ {
385
+ "ancestorTitles": [
386
+ "stack frames"
387
+ ],
388
+ "fullName": "stack frames reads the frames of each runtime's traces",
389
+ "status": "passed",
390
+ "title": "reads the frames of each runtime's traces",
391
+ "duration": 1.036,
392
+ "failureMessages": [],
393
+ "location": {
394
+ "line": 219,
395
+ "column": 3
396
+ }
397
+ },
398
+ {
399
+ "ancestorTitles": [
400
+ "stack frames"
401
+ ],
402
+ "fullName": "stack frames finds the first frame of the code under test",
403
+ "status": "passed",
404
+ "title": "finds the first frame of the code under test",
405
+ "duration": 0.36,
406
+ "failureMessages": [],
407
+ "location": {
408
+ "line": 246,
409
+ "column": 3
410
+ }
411
+ },
412
+ {
413
+ "ancestorTitles": [
414
+ "paths"
415
+ ],
416
+ "fullName": "paths gives BB a workspace-relative path or none",
417
+ "status": "passed",
418
+ "title": "gives BB a workspace-relative path or none",
419
+ "duration": 0.165,
420
+ "failureMessages": [],
421
+ "location": {
422
+ "line": 254,
423
+ "column": 3
424
+ }
425
+ },
426
+ {
427
+ "ancestorTitles": [
428
+ "paths"
429
+ ],
430
+ "fullName": "paths shortens absolute paths to the directory they share",
431
+ "status": "passed",
432
+ "title": "shortens absolute paths to the directory they share",
433
+ "duration": 0.124,
434
+ "failureMessages": [],
435
+ "location": {
436
+ "line": 263,
437
+ "column": 3
438
+ }
439
+ }
440
+ ],
441
+ "startTime": 1791586341506,
442
+ "endTime": 1791586341512.36,
443
+ "status": "passed",
444
+ "message": "",
445
+ "name": "/workspace/bb-plugin-genui/core/test-results.test.ts"
446
+ },
447
+ {
448
+ "assertionResults": [
449
+ {
450
+ "ancestorTitles": [
451
+ "report rendering"
452
+ ],
453
+ "fullName": "report rendering formats a minute with a leading zero",
454
+ "status": "failed",
455
+ "title": "formats a minute with a leading zero",
456
+ "duration": 2.888,
457
+ "failureMessages": [
458
+ "AssertionError: expected '1m 01s' to be '1m 1s' // Object.is equality\n at /workspace/bb-plugin-genui/core/report-rendering.test.ts:7:36\n at file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:26\n at file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:2326:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:2323:10)\n at file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20"
459
+ ],
460
+ "location": {
461
+ "line": 6,
462
+ "column": 3
463
+ }
464
+ },
465
+ {
466
+ "ancestorTitles": [
467
+ "report rendering"
468
+ ],
469
+ "fullName": "report rendering reads a JUnit report with a DOCTYPE",
470
+ "status": "failed",
471
+ "title": "reads a JUnit report with a DOCTYPE",
472
+ "duration": 2.6,
473
+ "failureMessages": [
474
+ "AssertionError: expected { ok: false, \u2026(1) } to match object { ok: true, value: [] }\n(1 matching property omitted from actual)\n at Proxy.<anonymous> (file:///workspace/bb-plugin-genui/node_modules/@vitest/expect/dist/index.js:1283:10)\n at Proxy.<anonymous> (file:///workspace/bb-plugin-genui/node_modules/@vitest/expect/dist/index.js:1156:15)\n at Proxy.methodWrapper (file:///workspace/bb-plugin-genui/node_modules/chai/index.js:1737:25)\n at /workspace/bb-plugin-genui/core/report-rendering.test.ts:12:20\n at file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:26"
475
+ ],
476
+ "location": {
477
+ "line": 10,
478
+ "column": 3
479
+ }
480
+ },
481
+ {
482
+ "ancestorTitles": [
483
+ "report rendering"
484
+ ],
485
+ "fullName": "report rendering counts skipped tests as passed",
486
+ "status": "failed",
487
+ "title": "counts skipped tests as passed",
488
+ "duration": 0.92,
489
+ "failureMessages": [
490
+ "AssertionError: expected { passed: +0, failed: +0, skipped: 1 } to deeply equal { passed: 1, failed: +0, skipped: +0 }\n at /workspace/bb-plugin-genui/core/report-rendering.test.ts:17:40\n at file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:26\n at file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:2326:20\n at new Promise (<anonymous>)\n at runWithCancel (file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:2323:10)\n at file:///workspace/bb-plugin-genui/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20"
491
+ ],
492
+ "location": {
493
+ "line": 15,
494
+ "column": 3
495
+ }
496
+ },
497
+ {
498
+ "ancestorTitles": [
499
+ "report rendering"
500
+ ],
501
+ "fullName": "report rendering renders thousands of failures under 16 ms",
502
+ "status": "skipped",
503
+ "title": "renders thousands of failures under 16 ms",
504
+ "failureMessages": [],
505
+ "location": {
506
+ "line": 20,
507
+ "column": 6
508
+ },
509
+ "duration": null
510
+ },
511
+ {
512
+ "ancestorTitles": [
513
+ "report rendering"
514
+ ],
515
+ "fullName": "report rendering streams a report while the run is still going",
516
+ "status": "todo",
517
+ "title": "streams a report while the run is still going",
518
+ "failureMessages": [],
519
+ "location": {
520
+ "line": 21,
521
+ "column": 6
522
+ },
523
+ "duration": null
524
+ }
525
+ ],
526
+ "startTime": 1791586341521,
527
+ "endTime": 1791586341527.9204,
528
+ "status": "failed",
529
+ "message": "",
530
+ "name": "/workspace/bb-plugin-genui/core/report-rendering.test.ts"
531
+ },
532
+ {
533
+ "assertionResults": [
534
+ {
535
+ "ancestorTitles": [
536
+ "childPath"
537
+ ],
538
+ "fullName": "childPath writes JSONPath, bracketing keys that are not identifiers",
539
+ "status": "passed",
540
+ "title": "writes JSONPath, bracketing keys that are not identifiers",
541
+ "duration": 0.947,
542
+ "failureMessages": [],
543
+ "location": {
544
+ "line": 9,
545
+ "column": 3
546
+ }
547
+ },
548
+ {
549
+ "ancestorTitles": [
550
+ "visibleRows"
551
+ ],
552
+ "fullName": "visibleRows shows a container root's entries as the top level and only open containers' children",
553
+ "status": "passed",
554
+ "title": "shows a container root's entries as the top level and only open containers' children",
555
+ "duration": 0.86,
556
+ "failureMessages": [],
557
+ "location": {
558
+ "line": 20,
559
+ "column": 3
560
+ }
561
+ },
562
+ {
563
+ "ancestorTitles": [
564
+ "visibleRows"
565
+ ],
566
+ "fullName": "visibleRows pages long containers with a row for the rest",
567
+ "status": "passed",
568
+ "title": "pages long containers with a row for the rest",
569
+ "duration": 0.208,
570
+ "failureMessages": [],
571
+ "location": {
572
+ "line": 34,
573
+ "column": 3
574
+ }
575
+ },
576
+ {
577
+ "ancestorTitles": [
578
+ "visibleRows"
579
+ ],
580
+ "fullName": "visibleRows shows a scalar root as one row and stays iterative for deep values",
581
+ "status": "passed",
582
+ "title": "shows a scalar root as one row and stays iterative for deep values",
583
+ "duration": 12.935,
584
+ "failureMessages": [],
585
+ "location": {
586
+ "line": 41,
587
+ "column": 3
588
+ }
589
+ },
590
+ {
591
+ "ancestorTitles": [
592
+ "sizeText and copyText"
593
+ ],
594
+ "fullName": "sizeText and copyText counts keys and items, and copies strings bare and containers as JSON",
595
+ "status": "passed",
596
+ "title": "counts keys and items, and copies strings bare and containers as JSON",
597
+ "duration": 0.193,
598
+ "failureMessages": [],
599
+ "location": {
600
+ "line": 52,
601
+ "column": 3
602
+ }
603
+ }
604
+ ],
605
+ "startTime": 1791586341506,
606
+ "endTime": 1791586341521.1934,
607
+ "status": "passed",
608
+ "message": "",
609
+ "name": "/workspace/bb-plugin-genui/ui/components/json-logic.test.ts"
610
+ }
611
+ ]
612
+ }
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300">
2
+ <rect width="400" height="300" fill="#f5edf1"/>
3
+ <ellipse cx="200" cy="246" rx="104" ry="8" fill="#e7dbe1"/>
4
+ <path d="M118 206 a82 92 0 0 1 164 0 Z" fill="#d9a521"/>
5
+ <path d="M140 190 a62 74 0 0 1 52 -66" fill="none" stroke="#f3d27a" stroke-width="9" stroke-linecap="round"/>
6
+ <rect x="108" y="200" width="184" height="16" rx="8" fill="#b9861a"/>
7
+ <rect x="192" y="96" width="16" height="22" rx="5" fill="#8a929c"/>
8
+ <path d="M200 96 V70 H262" fill="none" stroke="#8a929c" stroke-width="10" stroke-linecap="round" stroke-linejoin="round"/>
9
+ <circle cx="268" cy="70" r="11" fill="#262a31"/>
10
+ </svg>
@@ -0,0 +1,47 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="500" viewBox="0 0 800 500">
2
+ <rect width="800" height="500" fill="#eef2f5"/>
3
+ <ellipse cx="400" cy="462" rx="330" ry="10" fill="#d9dfe5"/>
4
+ <g>
5
+ <circle cx="210" cy="330" r="116" fill="none" stroke="#262a31" stroke-width="16"/>
6
+ <circle cx="210" cy="330" r="104" fill="none" stroke="#a7b0ba" stroke-width="4"/>
7
+ <g stroke="#b9c1ca" stroke-width="1.6"><line x1="220.0" y1="330.0" x2="305.8" y2="365.0"/><line x1="219.4" y1="333.4" x2="288.1" y2="395.6"/><line x1="217.7" y1="336.4" x2="260.9" y2="418.4"/><line x1="215.0" y1="338.7" x2="227.6" y2="430.5"/><line x1="211.7" y1="339.8" x2="192.2" y2="430.4"/><line x1="208.3" y1="339.8" x2="158.9" y2="418.3"/><line x1="205.0" y1="338.7" x2="131.8" y2="395.5"/><line x1="202.3" y1="336.4" x2="114.1" y2="364.8"/><line x1="200.6" y1="333.4" x2="108.0" y2="329.9"/><line x1="200.0" y1="330.0" x2="114.2" y2="295.0"/><line x1="200.6" y1="326.6" x2="131.9" y2="264.4"/><line x1="202.3" y1="323.6" x2="159.1" y2="241.6"/><line x1="205.0" y1="321.3" x2="192.4" y2="229.5"/><line x1="208.3" y1="320.2" x2="227.8" y2="229.6"/><line x1="211.7" y1="320.2" x2="261.1" y2="241.7"/><line x1="215.0" y1="321.3" x2="288.2" y2="264.5"/><line x1="217.7" y1="323.6" x2="305.9" y2="295.2"/><line x1="219.4" y1="326.6" x2="312.0" y2="330.1"/></g>
8
+ <circle cx="210" cy="330" r="10" fill="#59616b"/>
9
+ </g>
10
+ <g>
11
+ <circle cx="590" cy="330" r="116" fill="none" stroke="#262a31" stroke-width="16"/>
12
+ <circle cx="590" cy="330" r="104" fill="none" stroke="#a7b0ba" stroke-width="4"/>
13
+ <g stroke="#b9c1ca" stroke-width="1.6"><line x1="600.0" y1="330.0" x2="685.8" y2="365.0"/><line x1="599.4" y1="333.4" x2="668.1" y2="395.6"/><line x1="597.7" y1="336.4" x2="640.9" y2="418.4"/><line x1="595.0" y1="338.7" x2="607.6" y2="430.5"/><line x1="591.7" y1="339.8" x2="572.2" y2="430.4"/><line x1="588.3" y1="339.8" x2="538.9" y2="418.3"/><line x1="585.0" y1="338.7" x2="511.8" y2="395.5"/><line x1="582.3" y1="336.4" x2="494.1" y2="364.8"/><line x1="580.6" y1="333.4" x2="488.0" y2="329.9"/><line x1="580.0" y1="330.0" x2="494.2" y2="295.0"/><line x1="580.6" y1="326.6" x2="511.9" y2="264.4"/><line x1="582.3" y1="323.6" x2="539.1" y2="241.6"/><line x1="585.0" y1="321.3" x2="572.4" y2="229.5"/><line x1="588.3" y1="320.2" x2="607.8" y2="229.6"/><line x1="591.7" y1="320.2" x2="641.1" y2="241.7"/><line x1="595.0" y1="321.3" x2="668.2" y2="264.5"/><line x1="597.7" y1="323.6" x2="685.9" y2="295.2"/><line x1="599.4" y1="326.6" x2="692.0" y2="330.1"/></g>
14
+ <circle cx="590" cy="330" r="10" fill="#59616b"/>
15
+ </g>
16
+ <!-- front disc brake -->
17
+ <circle cx="590" cy="330" r="26" fill="none" stroke="#7d8792" stroke-width="5"/>
18
+ <rect x="572" y="292" width="26" height="14" rx="4" fill="#e4572e" transform="rotate(20 585 299)"/>
19
+ <!-- rear cassette and derailleur -->
20
+ <circle cx="210" cy="330" r="18" fill="none" stroke="#59616b" stroke-width="6"/>
21
+ <path d="M214 352 l-6 34 l18 8" fill="none" stroke="#3b4048" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
22
+ <!-- chain -->
23
+ <g stroke="#3b4048" stroke-width="4" fill="none">
24
+ <line x1="385" y1="310" x2="210" y2="312"/>
25
+ <line x1="385" y1="370" x2="226" y2="392"/>
26
+ </g>
27
+ <!-- frame -->
28
+ <g stroke="#1f8a70" stroke-width="14" stroke-linecap="round" stroke-linejoin="round" fill="none">
29
+ <path d="M210 330 L352 190 L385 340 Z"/>
30
+ <path d="M352 190 L548 178 L560 222 L385 340"/>
31
+ <line x1="340" y1="150" x2="352" y2="192"/>
32
+ </g>
33
+ <!-- fork and stem -->
34
+ <g stroke="#262a31" stroke-linecap="round" fill="none">
35
+ <path d="M560 222 Q575 280 590 330" stroke-width="11"/>
36
+ <path d="M548 178 L542 146" stroke-width="10"/>
37
+ <path d="M530 140 L590 132 Q622 130 618 162 Q614 178 600 178" stroke-width="9" stroke-linejoin="round"/>
38
+ </g>
39
+ <rect x="592" y="132" width="10" height="16" rx="3" fill="#59616b"/>
40
+ <!-- saddle -->
41
+ <path d="M296 146 Q330 132 382 142 Q386 152 372 154 L312 156 Q292 156 296 146 Z" fill="#262a31"/>
42
+ <!-- chainring and crank -->
43
+ <circle cx="385" cy="340" r="30" fill="#eef2f5" stroke="#3b4048" stroke-width="5"/>
44
+ <circle cx="385" cy="340" r="9" fill="#59616b"/>
45
+ <line x1="385" y1="340" x2="412" y2="394" stroke="#3b4048" stroke-width="9" stroke-linecap="round"/>
46
+ <rect x="398" y="392" width="34" height="9" rx="3" fill="#262a31"/>
47
+ </svg>