stream_weaver 0.3.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 (381) hide show
  1. checksums.yaml +7 -0
  2. data/.beads/.gitignore +77 -0
  3. data/.beads/README.md +81 -0
  4. data/.beads/config.yaml +54 -0
  5. data/.beads/metadata.json +7 -0
  6. data/.rspec +3 -0
  7. data/AGENTS.md +91 -0
  8. data/CHANGELOG.md +294 -0
  9. data/CLAUDE.md +67 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +565 -0
  12. data/Rakefile +13 -0
  13. data/assets/streamweaver-hero.jpg +0 -0
  14. data/bench/baselines/ledger.rb +58 -0
  15. data/bench/baselines/warroom.rb +51 -0
  16. data/bench/fixtures/ledger.rb +76 -0
  17. data/bench/fixtures/warroom.rb +60 -0
  18. data/bench/results/6daf8b8.md +102 -0
  19. data/bench/results/c8d749b.md +102 -0
  20. data/bench/results/eb06ab9.md +102 -0
  21. data/bench/run.rb +151 -0
  22. data/bench/support.rb +84 -0
  23. data/copy_this/dto_run_sample_run_7631.html +220 -0
  24. data/docs/SERVICE_MODE.md +302 -0
  25. data/docs/architecture/how_streamweaver_works.md +772 -0
  26. data/docs/blog/2026-01-16-streamweaver-introduction.md +515 -0
  27. data/docs/bug-2026-08-31-canvas-bridge-socket-collision.md +83 -0
  28. data/docs/canvas-ipc-session-summary.md +127 -0
  29. data/docs/canvas-panel-workflow.md +172 -0
  30. data/docs/canvas-read.md +147 -0
  31. data/docs/canvas-roadmap.md +275 -0
  32. data/docs/case-studies/2026-09-03-didx-canvas-read-shelf.md +147 -0
  33. data/docs/claude-code-companion-skill-spec.md +567 -0
  34. data/docs/components_reference.md +1223 -0
  35. data/docs/crud-patterns.md +265 -0
  36. data/docs/endpoints.md +122 -0
  37. data/docs/for_llms.md +1 -0
  38. data/docs/form-patterns.md +165 -0
  39. data/docs/frontend-only.md +169 -0
  40. data/docs/html-artifact-audit.md +238 -0
  41. data/docs/ideas/2025-01-01-as-a-service.md +203 -0
  42. data/docs/ideas/2026-01-16-charm-tui-exploration.md +542 -0
  43. data/docs/ideas/2026-08-27-static-doc-shelf-export.md +153 -0
  44. data/docs/ideas/dhh-review-future-refactors.md +142 -0
  45. data/docs/opal-jamstack.md +47 -0
  46. data/docs/opal-npm-direction.md +184 -0
  47. data/docs/opal-spike-findings.md +194 -0
  48. data/docs/plans/2025-12-16-form-blocks-design.md +124 -0
  49. data/docs/plans/2025-12-30-examples-browser-design.md +152 -0
  50. data/docs/plans/2026-01-02-charts-design.md +288 -0
  51. data/docs/plans/2026-01-10-canvas-ipc-design.md +247 -0
  52. data/docs/plans/2026-01-19-cabinet-control-components.md +176 -0
  53. data/docs/plans/2026-01-26-gem-release-and-panel.md +140 -0
  54. data/docs/plans/canvas-claude-project-design.md +238 -0
  55. data/docs/plans/canvas-doc-location-and-discovery.md +32 -0
  56. data/docs/plans/org-doc-preview-surfaces.md +293 -0
  57. data/docs/plans/shadcn-polish-plan.md +417 -0
  58. data/docs/porting-artifacts.md +252 -0
  59. data/docs/reference/agent-skills-comparison.md +369 -0
  60. data/docs/reference/travel-state-prd.artifact.html +780 -0
  61. data/docs/research/2026-08-17-hotwire-alike-landscape.md +268 -0
  62. data/docs/research/2026-08-17-hotwire-concept-map.md +404 -0
  63. data/docs/research/2026-08-22-lazy-fragments-trigger-decision.md +246 -0
  64. data/docs/research/2026-08-22-learnhotwire-syllabus-coverage.md +239 -0
  65. data/docs/research/frontend-only-matrix.md +278 -0
  66. data/docs/research/streamweaver-way-spike-findings.md +529 -0
  67. data/docs/resource-dsl.md +342 -0
  68. data/docs/routing.md +302 -0
  69. data/docs/ruby-ui-comparison.md +319 -0
  70. data/docs/shared-dsl-fragments.md +356 -0
  71. data/docs/streamweaver-for-ai-agents.md +401 -0
  72. data/docs/streamweaver-frontend-vision.md +123 -0
  73. data/docs/streamweaver_canvas/glimmer_initial_final_layer.rb +77 -0
  74. data/docs/streamweaver_canvas/save_example.rb +9 -0
  75. data/docs/templates.md +213 -0
  76. data/docs/testing.md +155 -0
  77. data/docs/theming-hooks.md +281 -0
  78. data/docs/tutorials/the-streamweaver-way.md +882 -0
  79. data/docs/university/capability-inventory.md +137 -0
  80. data/docs/university/dependency-survey.md +114 -0
  81. data/docs/university/design-spec.md +217 -0
  82. data/docs/university/mockups/code-block-doc-theme-dark.png +0 -0
  83. data/docs/university/mockups/code-block-doc-theme-light.png +0 -0
  84. data/docs/university/mockups/course-list-dark.png +0 -0
  85. data/docs/university/mockups/course-list-light.png +0 -0
  86. data/docs/university/mockups/course_canvas_mockup.rb +741 -0
  87. data/docs/university/mockups/step-screen-dark.png +0 -0
  88. data/docs/university/mockups/step-screen-light.png +0 -0
  89. data/docs/university/roadmap.md +72 -0
  90. data/docs/university/send-to-coworker.md +77 -0
  91. data/docs/university/worker-session-mining.md +109 -0
  92. data/docs/visual/browser-rendering-spike.md +173 -0
  93. data/docs/visual/builder-visual-plan-analysis.md +378 -0
  94. data/docs/visual/sw-plan-format-exploration.md +511 -0
  95. data/docs/visual/sw-plan-rendering-deep-dive.md +453 -0
  96. data/docs/visual-skills/PROGRESS.md +60 -0
  97. data/docs/visual-skills/SESSION-CONTEXT.md +207 -0
  98. data/docs/visual-skills/analysis/components.md +317 -0
  99. data/docs/visual-skills/analysis/overlap.md +360 -0
  100. data/docs/visual-skills/analysis/pi-design-deck.md +1102 -0
  101. data/docs/visual-skills/analysis/streamweaver-inventory.md +93 -0
  102. data/docs/visual-skills/analysis/unified-specs.feature +1003 -0
  103. data/docs/visual-skills/analysis/visual-explainer.md +964 -0
  104. data/docs/visual-skills/blog/blog-series-outline.md +39 -0
  105. data/docs/visual-skills/blog/token-efficiency.md +73 -0
  106. data/docs/visual-skills/design/architecture.md +1725 -0
  107. data/docs/visual-skills/design/codex-review.md +340 -0
  108. data/docs/visual-skills/design/dhh-review.md +209 -0
  109. data/docs/visual-skills/design/evolution.md +100 -0
  110. data/docs/visual-skills/design/gemini-review.md +55 -0
  111. data/docs/visual-skills/design/review-synthesis.md +149 -0
  112. data/docs/visual-skills/implementation/STATE.md +22 -0
  113. data/docs/visual-skills/implementation/plan.md +347 -0
  114. data/docs/visual-skills/implementation/spike-findings.md +237 -0
  115. data/docs/visual-skills/implementation/tasks.md +702 -0
  116. data/docs/visual-skills/lessons-learned/process.md +145 -0
  117. data/examples/README.md +96 -0
  118. data/examples/advanced/all_components.rb +177 -0
  119. data/examples/advanced/examples_browser.rb +394 -0
  120. data/examples/advanced/teachables_browser.rb +261 -0
  121. data/examples/advanced/theme_tweaker.rb +366 -0
  122. data/examples/advanced/tutorial.rb +1528 -0
  123. data/examples/agentic/agentic_form.rb +30 -0
  124. data/examples/agentic/agentic_form_autoclose.rb +30 -0
  125. data/examples/agentic/cultivation_tracker.rb +69 -0
  126. data/examples/basic/hello_world.rb +22 -0
  127. data/examples/basic/opal_tabs_table.rb +44 -0
  128. data/examples/basic/todo_list.rb +39 -0
  129. data/examples/button_loading_test.rb +36 -0
  130. data/examples/canvas/mermaid_canvas_demo.sh +151 -0
  131. data/examples/charts/bar_chart_demo.rb +57 -0
  132. data/examples/charts/line_chart_demo.rb +73 -0
  133. data/examples/charts/pie_area_demo.rb +87 -0
  134. data/examples/charts/stacked_bar_chart_demo.rb +69 -0
  135. data/examples/claude_code/README.md +85 -0
  136. data/examples/claude_code/codebreaker/.claude/commands/infiltrate.md +632 -0
  137. data/examples/claude_code/codebreaker/.claude/settings.json +11 -0
  138. data/examples/claude_code/codebreaker/.claude/settings.local.json +17 -0
  139. data/examples/claude_code/codebreaker/.claude/skills/infiltrate.md +0 -0
  140. data/examples/claude_code/codebreaker/README.md +213 -0
  141. data/examples/claude_code/tutorial/.claude/commands/learn.md +453 -0
  142. data/examples/claude_code/tutorial/README.md +102 -0
  143. data/examples/claude_code/verification_flow/.claude/commands/verify.md +171 -0
  144. data/examples/claude_code/verification_flow/README.md +126 -0
  145. data/examples/components/annotated_code_demo.rb +54 -0
  146. data/examples/components/callout_demo.rb +33 -0
  147. data/examples/components/checkbox_group_demo.rb +46 -0
  148. data/examples/components/design_review.css +468 -0
  149. data/examples/components/design_review_demo.rb +44 -0
  150. data/examples/components/design_review_dsl.rb +300 -0
  151. data/examples/components/diff_block_demo.rb +112 -0
  152. data/examples/components/events_demo.rb +184 -0
  153. data/examples/components/form_demo.rb +62 -0
  154. data/examples/components/lesson_demo.rb +53 -0
  155. data/examples/components/markdown_demo.rb +110 -0
  156. data/examples/components/mermaid_demo.rb +166 -0
  157. data/examples/components/pareto_set.rb +64 -0
  158. data/examples/components/prd_demo.rb +21 -0
  159. data/examples/components/prd_dsl.rb +385 -0
  160. data/examples/components/quiz_demo.rb +47 -0
  161. data/examples/components/run_viewer_demo.rb +100 -0
  162. data/examples/components/score_and_collapsible_demo.rb +82 -0
  163. data/examples/components/select_stale_value_smoke_test.rb +39 -0
  164. data/examples/components/table_demo.rb +247 -0
  165. data/examples/components/timer_with_state_demo.rb +58 -0
  166. data/examples/components/todo_due_dates.rb +63 -0
  167. data/examples/components/uat_gaps_demo.rb +112 -0
  168. data/examples/dashboard/feed_simulator.rb +60 -0
  169. data/examples/dashboard/live_dashboard.rb +80 -0
  170. data/examples/dashboard_components.rb +108 -0
  171. data/examples/deferred_fragments_demo.rb +62 -0
  172. data/examples/generate_more_spike/README.md +63 -0
  173. data/examples/generate_more_spike/app.rb +441 -0
  174. data/examples/git_health.sh +401 -0
  175. data/examples/layout/layout_components_demo.rb +174 -0
  176. data/examples/layout/modal_demo.rb +215 -0
  177. data/examples/layout/navigation_demo.rb +227 -0
  178. data/examples/layout/route_tabs_demo.rb +52 -0
  179. data/examples/layout/routing_demo.rb +52 -0
  180. data/examples/layout/scroll_box_demo.rb +154 -0
  181. data/examples/lazy_fragments_demo.rb +151 -0
  182. data/examples/my_todos/README.md +29 -0
  183. data/examples/my_todos/my_todos.rb +312 -0
  184. data/examples/my_todos/store.rb +86 -0
  185. data/examples/opal/reactive_demo.rb +62 -0
  186. data/examples/opal/scenarios/s1_counter.rb +15 -0
  187. data/examples/opal/scenarios/s2_search_filter.rb +17 -0
  188. data/examples/opal/scenarios/s3_sibling_tabs.rb +25 -0
  189. data/examples/opal/scenarios/s4_shopping_cart.rb +34 -0
  190. data/examples/opal/scenarios/s5_watch.rb +39 -0
  191. data/examples/opal/scenarios/s6_on_start.rb +20 -0
  192. data/examples/opal/scenarios/s7_wizard.rb +33 -0
  193. data/examples/opal/scenarios/s8_loan_calculator.rb +21 -0
  194. data/examples/opal/scenarios/s9_dashboard.rb +27 -0
  195. data/examples/operations_dashboard_demo.rb +167 -0
  196. data/examples/panel_demo.sh +447 -0
  197. data/examples/parity/assets/tyrion_slice.css +86 -0
  198. data/examples/parity/rivet_people_slice.rb +182 -0
  199. data/examples/parity/tyrion_components.css +777 -0
  200. data/examples/parity/tyrion_warroom_components.rb +414 -0
  201. data/examples/parity/tyrion_warroom_slice.rb +549 -0
  202. data/examples/puma_dev/README.md +124 -0
  203. data/examples/puma_dev/config.ru +34 -0
  204. data/examples/puma_dev/standalone_app.rb +34 -0
  205. data/examples/scaffolding/blog.rb +49 -0
  206. data/examples/scaffolding/utf_lite.rb +105 -0
  207. data/examples/styling/feedback_demo.rb +229 -0
  208. data/examples/styling/style_showcase.rb +172 -0
  209. data/examples/styling/theme_demo.rb +508 -0
  210. data/examples/timer_health_checker.rb +111 -0
  211. data/examples/timer_showcase.rb +131 -0
  212. data/examples/tutorials/render_markdown.rb +112 -0
  213. data/examples/tutorials/streamweaver_way_tutorial.rb +44 -0
  214. data/examples/tutorials/tutorial_content.rb +1082 -0
  215. data/examples/visual_skills/design_deck_demo.rb +314 -0
  216. data/examples/visual_skills/explainer_demo.rb +499 -0
  217. data/exe/streamweaver +9 -0
  218. data/gsd/ROADMAP-1.0.md +167 -0
  219. data/gsd/STATE.md +13 -0
  220. data/gsd/research/market-positioning-research.md +139 -0
  221. data/gsd/research/production-patterns-research.md +270 -0
  222. data/gsd/research/repo-audit-1.0.md +274 -0
  223. data/lib/stream_weaver/action_token.rb +58 -0
  224. data/lib/stream_weaver/adapter/alpinejs.rb +8249 -0
  225. data/lib/stream_weaver/adapter/base.rb +591 -0
  226. data/lib/stream_weaver/adapter/opal.rb +334 -0
  227. data/lib/stream_weaver/adapter/static.rb +1118 -0
  228. data/lib/stream_weaver/admin.rb +176 -0
  229. data/lib/stream_weaver/app.rb +1821 -0
  230. data/lib/stream_weaver/assets/js/sw-copy.js +50 -0
  231. data/lib/stream_weaver/assets/js/sw-heredoc-rewrite.js +68 -0
  232. data/lib/stream_weaver/assets/js/sw-keyboard.js +165 -0
  233. data/lib/stream_weaver/assets/js/sw-mermaid-zoom.js +621 -0
  234. data/lib/stream_weaver/assets/js/sw-route-tabs.js +53 -0
  235. data/lib/stream_weaver/assets/js/sw-sidebar-toc.js +116 -0
  236. data/lib/stream_weaver/assets/js/sw-slide-nav.js +103 -0
  237. data/lib/stream_weaver/canvas/bridge.rb +239 -0
  238. data/lib/stream_weaver/canvas/bridge_server.rb +646 -0
  239. data/lib/stream_weaver/canvas/client.rb +298 -0
  240. data/lib/stream_weaver/canvas/doc_roots.rb +233 -0
  241. data/lib/stream_weaver/canvas/doc_store.rb +252 -0
  242. data/lib/stream_weaver/canvas/gist_publisher.rb +264 -0
  243. data/lib/stream_weaver/canvas/gist_save_handler.rb +89 -0
  244. data/lib/stream_weaver/canvas/gist_store.rb +135 -0
  245. data/lib/stream_weaver/canvas/helpers.rb +109 -0
  246. data/lib/stream_weaver/canvas/history.rb +90 -0
  247. data/lib/stream_weaver/canvas/protocol.rb +86 -0
  248. data/lib/stream_weaver/canvas/reader.rb +853 -0
  249. data/lib/stream_weaver/canvas/save_doc_widget.rb +457 -0
  250. data/lib/stream_weaver/canvas/scroll_top_hint.rb +21 -0
  251. data/lib/stream_weaver/canvas/session.rb +132 -0
  252. data/lib/stream_weaver/cli.rb +3235 -0
  253. data/lib/stream_weaver/component_assets.rb +70 -0
  254. data/lib/stream_weaver/component_registry.rb +67 -0
  255. data/lib/stream_weaver/component_renderer.rb +48 -0
  256. data/lib/stream_weaver/components/annotated_code.rb +53 -0
  257. data/lib/stream_weaver/components/api_endpoint.rb +42 -0
  258. data/lib/stream_weaver/components/callout.rb +59 -0
  259. data/lib/stream_weaver/components/chart.rb +84 -0
  260. data/lib/stream_weaver/components/code_block.rb +77 -0
  261. data/lib/stream_weaver/components/comparison.rb +39 -0
  262. data/lib/stream_weaver/components/decision.rb +38 -0
  263. data/lib/stream_weaver/components/deck/close_overlay.rb +84 -0
  264. data/lib/stream_weaver/components/deck/confirmation_bar.rb +60 -0
  265. data/lib/stream_weaver/components/deck/deck_option.rb +61 -0
  266. data/lib/stream_weaver/components/deck/deck_slide.rb +77 -0
  267. data/lib/stream_weaver/components/deck/deck_state.rb +469 -0
  268. data/lib/stream_weaver/components/deck/deck_summary.rb +73 -0
  269. data/lib/stream_weaver/components/deck/design_deck.rb +60 -0
  270. data/lib/stream_weaver/components/deck/generate_more_controls.rb +84 -0
  271. data/lib/stream_weaver/components/deck/model_selector.rb +84 -0
  272. data/lib/stream_weaver/components/deck/skeleton_placeholder.rb +36 -0
  273. data/lib/stream_weaver/components/diff_block.rb +125 -0
  274. data/lib/stream_weaver/components/doc_header.rb +57 -0
  275. data/lib/stream_weaver/components/image_block.rb +70 -0
  276. data/lib/stream_weaver/components/implementation_map.rb +33 -0
  277. data/lib/stream_weaver/components/keyboard_shortcuts.rb +94 -0
  278. data/lib/stream_weaver/components/kpi_dashboard.rb +78 -0
  279. data/lib/stream_weaver/components/mermaid.rb +79 -0
  280. data/lib/stream_weaver/components/pipeline.rb +63 -0
  281. data/lib/stream_weaver/components/sidebar_toc.rb +46 -0
  282. data/lib/stream_weaver/components/slide_container.rb +141 -0
  283. data/lib/stream_weaver/components/timeline_event.rb +58 -0
  284. data/lib/stream_weaver/components/wireframe.rb +29 -0
  285. data/lib/stream_weaver/components/wireframe_block.rb +34 -0
  286. data/lib/stream_weaver/components.rb +2711 -0
  287. data/lib/stream_weaver/css.rb +230 -0
  288. data/lib/stream_weaver/dev_fallback_overlay.rb +61 -0
  289. data/lib/stream_weaver/display_dsl.rb +1004 -0
  290. data/lib/stream_weaver/export/html_exporter.rb +478 -0
  291. data/lib/stream_weaver/feed.rb +34 -0
  292. data/lib/stream_weaver/feed_builder.rb +31 -0
  293. data/lib/stream_weaver/fonts.rb +33 -0
  294. data/lib/stream_weaver/interaction_runner.rb +487 -0
  295. data/lib/stream_weaver/iterm.rb +460 -0
  296. data/lib/stream_weaver/layout_registry.rb +92 -0
  297. data/lib/stream_weaver/opal/bridge.rb +52 -0
  298. data/lib/stream_weaver/opal/builder.rb +193 -0
  299. data/lib/stream_weaver/opal/env.rb +29 -0
  300. data/lib/stream_weaver/opal/reactive_state.rb +75 -0
  301. data/lib/stream_weaver/opal/regexp_anchor_patch.rb +62 -0
  302. data/lib/stream_weaver/opal/renderer.rb +77 -0
  303. data/lib/stream_weaver/opal/runtime.rb +250 -0
  304. data/lib/stream_weaver/opal/shell.rb +145 -0
  305. data/lib/stream_weaver/opal/string_bridge.rb +50 -0
  306. data/lib/stream_weaver/opal/stubs/diff.min.js +1 -0
  307. data/lib/stream_weaver/opal/stubs/digest.rb +15 -0
  308. data/lib/stream_weaver/opal/stubs/marked.umd.js +79 -0
  309. data/lib/stream_weaver/opal/stubs/md5.rb +3 -0
  310. data/lib/stream_weaver/opal/stubs/morphdom.min.js +775 -0
  311. data/lib/stream_weaver/opal/stubs/prism-tomorrow.min.css +1 -0
  312. data/lib/stream_weaver/opal/stubs/prism.min.js +1967 -0
  313. data/lib/stream_weaver/opal_entry.rb +136 -0
  314. data/lib/stream_weaver/org/inline.rb +95 -0
  315. data/lib/stream_weaver/org/reader.rb +561 -0
  316. data/lib/stream_weaver/org/recording_context.rb +86 -0
  317. data/lib/stream_weaver/org/source_splitter.rb +63 -0
  318. data/lib/stream_weaver/org/writer.rb +300 -0
  319. data/lib/stream_weaver/page_shell.rb +530 -0
  320. data/lib/stream_weaver/portfile.rb +79 -0
  321. data/lib/stream_weaver/pushable.rb +42 -0
  322. data/lib/stream_weaver/resource/default_views.rb +111 -0
  323. data/lib/stream_weaver/resource/field_input.rb +25 -0
  324. data/lib/stream_weaver/resource/state_keys.rb +16 -0
  325. data/lib/stream_weaver/resource/store.rb +18 -0
  326. data/lib/stream_weaver/resource.rb +104 -0
  327. data/lib/stream_weaver/server.rb +1471 -0
  328. data/lib/stream_weaver/service.rb +1240 -0
  329. data/lib/stream_weaver/service_client.rb +104 -0
  330. data/lib/stream_weaver/session_store.rb +186 -0
  331. data/lib/stream_weaver/skills/streamweaver-canvas-safe/SKILL.md +66 -0
  332. data/lib/stream_weaver/skills/streamweaver-canvas-safe/examples/canvas-safe-showcase.rb +98 -0
  333. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/actions-and-buttons.md +47 -0
  334. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/charts-and-diagrams.md +38 -0
  335. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/deck.md +32 -0
  336. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/inputs-and-forms.md +65 -0
  337. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/tabs-and-navigation.md +53 -0
  338. data/lib/stream_weaver/skills/streamweaver-doc-builder/SKILL.md +298 -0
  339. data/lib/stream_weaver/skills/streamweaver-visual-companion/SKILL.md +130 -0
  340. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.css +468 -0
  341. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.rb +39 -0
  342. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example_dsl.rb +300 -0
  343. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example.rb +24 -0
  344. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example_dsl.rb +385 -0
  345. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/checkpoints-and-forms.md +28 -0
  346. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/cleanup-and-panel.md +44 -0
  347. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/example-gallery.md +8 -0
  348. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/persistence.md +58 -0
  349. data/lib/stream_weaver/skills/streamweaver-way/SKILL.md +396 -0
  350. data/lib/stream_weaver/skills/visual-plan/SKILL.md +201 -0
  351. data/lib/stream_weaver/skills/visual-recap/SKILL.md +244 -0
  352. data/lib/stream_weaver/streamer.rb +63 -0
  353. data/lib/stream_weaver/templates/choices.rb +149 -0
  354. data/lib/stream_weaver/templates/code.rb +157 -0
  355. data/lib/stream_weaver/templates/confirm.rb +110 -0
  356. data/lib/stream_weaver/templates/diff.rb +195 -0
  357. data/lib/stream_weaver/templates/info.rb +142 -0
  358. data/lib/stream_weaver/templates/table.rb +169 -0
  359. data/lib/stream_weaver/templates/wizard.rb +271 -0
  360. data/lib/stream_weaver/theme/auto_mode.rb +116 -0
  361. data/lib/stream_weaver/theme/presets.rb +555 -0
  362. data/lib/stream_weaver/theme.rb +639 -0
  363. data/lib/stream_weaver/university/canvas.rb +924 -0
  364. data/lib/stream_weaver/university/course.rb +699 -0
  365. data/lib/stream_weaver/university/demos/counter.rb +33 -0
  366. data/lib/stream_weaver/university/demos/dashboard.rb +147 -0
  367. data/lib/stream_weaver/university/demos/decision_form.rb +143 -0
  368. data/lib/stream_weaver/university/demos.rb +50 -0
  369. data/lib/stream_weaver/university/listener.rb +467 -0
  370. data/lib/stream_weaver/university/progress.rb +201 -0
  371. data/lib/stream_weaver/university/runner.rb +138 -0
  372. data/lib/stream_weaver/university/scripts/growing_doc.rb +609 -0
  373. data/lib/stream_weaver/university/scripts/growing_doc_state.rb +91 -0
  374. data/lib/stream_weaver/utils.rb +31 -0
  375. data/lib/stream_weaver/version.rb +5 -0
  376. data/lib/stream_weaver/views/canvas/reader_layout.erb +800 -0
  377. data/lib/stream_weaver/views.rb +3940 -0
  378. data/lib/stream_weaver.rb +122 -0
  379. data/llms.txt +1269 -0
  380. data/sig/stream_weaver.rbs +4 -0
  381. metadata +598 -0
@@ -0,0 +1,300 @@
1
+ # frozen_string_literal: true
2
+ # Inner DSL for a fictional design-review document: "Getting Wayfinder and
3
+ # Beacon in front of every agent" -- a genre example proving StreamWeaver's
4
+ # doc component family can reach 1:1 visual parity with a claude.ai-hosted
5
+ # Artifact for editorial "design review" documents specifically: option
6
+ # cards with chips, pick states on both a card and a table row, a
7
+ # two-column checklist split, and a full re-skin via one unlayered CSS
8
+ # file. Wayfinder/Beacon, the reviewers, and the citations below are
9
+ # entirely invented for this example -- see docs/porting-artifacts.md for
10
+ # the process this was ported through.
11
+ #
12
+ # Intended for canvas-push:
13
+ # streamweaver canvas-push <session> < examples/components/design_review_dsl.rb
14
+ # CAVEAT: the canvas bridge injects only master-theme CSS -- it cannot carry
15
+ # this example's own stylesheet yet (stream_weaver-9uk), so a canvas push shows
16
+ # correct structure without the bespoke re-skin. The standalone app is the
17
+ # faithful rendering: ruby examples/components/design_review_demo.rb
18
+
19
+ # ---------------------------------------------------------------------------
20
+ # Small helpers, local to this DSL body (same pattern as
21
+ # examples/parity/tyrion_warroom_components.rb's inline `def art_glyph`).
22
+ # ---------------------------------------------------------------------------
23
+
24
+ # A "chip": dim dimension label + colored status dot + value text.
25
+ # color: is one of :green/:yellow/:red (good/mid/weak).
26
+ def ad_chip(dim, color, value)
27
+ div(class: "ad-chip") do
28
+ phrase(dim, class: "ad-chip-dim")
29
+ status_dot(status: color, size: :sm)
30
+ phrase(value)
31
+ end
32
+ end
33
+
34
+ # One option card (section 03). Chips + prose are supplied via the block.
35
+ #
36
+ # `mechanism` (the subtitle line) is rendered via `md`, not card_header's
37
+ # own `meta:` -- CardHeader's meta: renders as escaped plain text
38
+ # (view.span { @meta }), so backtick-quoted terms in the subtitle (e.g.
39
+ # "the existing `beacon init` pattern") would show up as literal backtick
40
+ # characters instead of code pills. Routing it through `md` as an extra
41
+ # header child gets the same markdown-to-<code> handling every other prose
42
+ # paragraph in this doc already gets.
43
+ def ad_option(letter, title, mechanism, recommended: false)
44
+ classes = ["ad-option"]
45
+ classes << "ad-option--pick" if recommended
46
+ card(class: classes.join(" ")) do
47
+ card_header(title, badge: letter) do
48
+ div(class: "ad-option-mech") { md mechanism }
49
+ badge("Recommended", variant: :info) if recommended
50
+ end
51
+ card_body { yield if block_given? }
52
+ end
53
+ end
54
+
55
+ # A raw rating cell for the comparison-matrix table (section 04): colored
56
+ # status dot + text, matching the chip's dot but laid out for a table cell.
57
+ # Table's own markdown: true option renders cell HTML raw (already used by
58
+ # the framework to turn `[text](url)` into <a> tags) -- this reuses that
59
+ # same sanctioned escape hatch rather than hand-building component objects
60
+ # outside the DSL.
61
+ def ad_rate(color, value)
62
+ %(<span class="ad-cell-rating"><span class="sw-status-dot sw-status-dot-#{color} sw-status-dot-sm"></span>#{value}</span>)
63
+ end
64
+
65
+ # One checklist tile (section 06): fixed-width mark glyph + prose line.
66
+ def ad_check(mark, text)
67
+ div(class: "ad-check-item") do
68
+ phrase(mark, class: "ad-check-mark")
69
+ md text
70
+ end
71
+ end
72
+
73
+ div(class: "ad-doc") do
74
+ # =========================================================================
75
+ # Header
76
+ # =========================================================================
77
+ doc_header(
78
+ eyebrow: "Design options — internal review",
79
+ title: "Getting Wayfinder and Beacon in front of every agent, without a human having to introduce them"
80
+ )
81
+ div(class: "ad-dek") do
82
+ md "Six ways to make the project registry and the federated knowledge base self-discoverable to Claude Code, Codex, Gemini CLI, and Copilot — scored against discovery, friction, and cognitive-load principles, drafted by a research subagent, July 2026."
83
+ end
84
+ div(class: "ad-meta-row") do
85
+ div { phrase("Subject", class: "ad-meta-label"); phrase(" Wayfinder + Beacon, pre-launch") }
86
+ div { phrase("Client", class: "ad-meta-label"); phrase(" the agent, not the human") }
87
+ div { phrase("Options", class: "ad-meta-label"); phrase(" 6, one recommended") }
88
+ end
89
+
90
+ # =========================================================================
91
+ # 01 — The actual problem
92
+ # =========================================================================
93
+ doc_section_header "01 — The actual problem", "", id: "problem"
94
+ callout(title: "Framing") do
95
+ md "The customer whose friction has to hit zero is **the agent itself** — not a human reading a README. Any of the four CLIs, dropped cold into an arbitrary project, needs to (a) discover Wayfinder/Beacon exist, (b) know how to query them, and (c) develop the habit of *writing* durable knowledge back in — with no per-project hand-authoring by a maintainer. The only human cost allowed is `gem install wayfinder` once, plus at most one machine-level setup command. Anything that requires remembering a per-repo step decays under real-world attention scarcity — the cognitive-load principle applied to the maintainer, not just the end user."
96
+ end
97
+
98
+ # =========================================================================
99
+ # 02 — Verified landscape, July 2026
100
+ # =========================================================================
101
+ doc_section_header "02 — Verified landscape, July 2026", "What each CLI actually reads on its own", id: "landscape"
102
+ md "Two structural facts fall out of this: a repo with both `AGENTS.md` and a `CLAUDE.md` that imports it covers Claude Code, Codex, *and* Copilot with one canonical body of text — Gemini is the lone holdout needing its own file. And MCP is the only surface all four share, and the only one that's machine-global rather than per-repo."
103
+ div(class: "ad-tbl-scroll") do
104
+ table(
105
+ class: "ad-landscape-table",
106
+ markdown: true,
107
+ headers: ["CLI", "Repo context file", "User-global context", "MCP", "Plugin / skill surface"],
108
+ rows: [
109
+ [
110
+ "Claude Code",
111
+ "<code>CLAUDE.md</code> only — no native AGENTS.md read (tracked in the public issue queue, thousands of reactions); <code>@AGENTS.md</code> import works",
112
+ "<code>~/.claude/CLAUDE.md</code>",
113
+ "Yes — <code>claude mcp add</code>",
114
+ "Skills, plugins, marketplaces"
115
+ ],
116
+ [
117
+ "Codex CLI",
118
+ "<code>AGENTS.md</code> — native, root + nested",
119
+ "<code>~/.codex/AGENTS.md</code>",
120
+ "Yes — can run <em>as</em> an MCP server too",
121
+ "AGENTS.md is the spec it champions"
122
+ ],
123
+ [
124
+ "Gemini CLI",
125
+ "<code>GEMINI.md</code> by default — AGENTS.md not out-of-box (tracked as an open feature request)",
126
+ "<code>~/.gemini/GEMINI.md</code>",
127
+ "Yes — <code>~/.gemini/settings.json</code>",
128
+ "Extensions bundle MCP config + context file together"
129
+ ],
130
+ [
131
+ "Copilot CLI",
132
+ "<code>AGENTS.md</code>, <code>.github/copilot-instructions.md</code> — <em>and also</em> CLAUDE.md &amp; GEMINI.md",
133
+ "user-level instruction files",
134
+ "Yes — command + HTTP",
135
+ "Custom agents, skills, MCP marketplace"
136
+ ]
137
+ ]
138
+ )
139
+ end
140
+
141
+ # =========================================================================
142
+ # 03 — Six options
143
+ # =========================================================================
144
+ doc_section_header "03 — Six options", "What “batteries included” could actually mean", id: "options"
145
+
146
+ ad_option("A", "Universal context-file writer", "Generalize the existing `beacon init` pattern to every convention that matters") do
147
+ div(class: "ad-chips") do
148
+ ad_chip("Discovery", :green, "Strong")
149
+ ad_chip("Friction", :yellow, "1 cmd/repo")
150
+ ad_chip("Load·user", :green, "Good")
151
+ ad_chip("Load·maint.", :green, "Low burden")
152
+ ad_chip("Cost", :green, "~1 day")
153
+ ad_chip("Robustness", :yellow, "Medium")
154
+ end
155
+ md "One command writes a canonical section into every file that matters: a full section in `AGENTS.md` (covers Codex + Copilot natively), a `CLAUDE.md` created with an `@AGENTS.md` import if missing (covers Claude Code), a thin pointer stub in `GEMINI.md`, and a section in `.github/copilot-instructions.md` if one already exists. All four render from one template in the gem, fenced with `<!-- wayfinder:begin -->` markers so re-runs update in place — the same idiom `lib/wayfinder/beacon/init.rb` already uses for AGENTS.md alone. The section has to state the *write* directive explicitly (\"when you learn something durable, register it; when you produce reusable knowledge, add a page and reindex\") — a context file is the only place you can install a habit, not just a capability. Weakness: someone still has to run it, once, per repo, and static prose drifts from the CLI's real surface over time."
156
+ end
157
+
158
+ ad_option("B", "Universal MCP server", "Ship the registry and Beacon as live, structured tools every CLI can call") do
159
+ div(class: "ad-chips") do
160
+ ad_chip("Discovery·find", :green, "Strong")
161
+ ad_chip("Discovery·digest", :yellow, "Weaker")
162
+ ad_chip("Friction", :green, "1 cmd/machine")
163
+ ad_chip("Load·user", :green, "Excellent")
164
+ ad_chip("Load·maint.", :green, "Very low")
165
+ ad_chip("Cost", :yellow, "2–4 days")
166
+ ad_chip("Robustness", :green, "Highest")
167
+ end
168
+ md "`wayfinder mcp` (stdio) exposes structured tools — `wayfinder_locate`, `wayfinder_search`, `wayfinder_show`, `beacon_search`, `beacon_resolve`, plus write tools like `wayfinder_update` and `beacon_register`. A one-time `wayfinder agents install-mcp` writes client config for whichever CLIs it detects, idempotently, the same way `install-hooks` already chains onto an existing pre-commit hook. The property worth dwelling on: once registered at user scope, *every* session of *all four* CLIs, in every directory, sees these tools in its list — no per-repo file, nobody remembering anything. And because the tools *are* the real behavior, they can never drift out of sync with it the way a static snippet can. Cost is real (verify the Ruby MCP SDK's maturity first), and a tool list alone teaches an agent to *read* more readily than to *write*."
169
+ end
170
+
171
+ ad_option("C", "Native skill / plugin bundles, one per ecosystem", "A Claude Skill, a Gemini extension, a Copilot agent — each in its own idiom") do
172
+ div(class: "ad-chips") do
173
+ ad_chip("Discovery", :green, "Excellent")
174
+ ad_chip("Friction", :green, "1 cmd/machine")
175
+ ad_chip("Load·user", :green, "Good")
176
+ ad_chip("Load·maint.", :red, "High — 4 formats")
177
+ ad_chip("Cost", :red, "High + ongoing")
178
+ ad_chip("Robustness", :red, "Low–medium")
179
+ end
180
+ md "`wayfinder agents install [claude|gemini|codex|copilot|all]` would drop a real Claude Skill (which can trigger *contextually* — \"when the user references a project by name\" — something a static file can't do), a Gemini extension bundling both MCP config and a GEMINI.md, and a Copilot custom agent. This is the best per-ecosystem experience on the list, and the worst maintenance profile: four young, fast-moving vendor formats, each a separate artifact to keep in sync, each liable to drift exactly as the cognitive-load principle predicts for the maintainer. The seductive trap — skip until one ecosystem clearly earns the investment."
181
+ end
182
+
183
+ ad_option("D", "Docs-only bet", "An excellent README and `docs/for-agents.md`, nothing mechanical") do
184
+ div(class: "ad-chips") do
185
+ ad_chip("Discovery", :red, "Weak")
186
+ ad_chip("Friction", :red, "Fails")
187
+ ad_chip("Load·user", :red, "Fails")
188
+ ad_chip("Load·maint.", :green, "~zero")
189
+ ad_chip("Cost", :green, "~zero")
190
+ ad_chip("Robustness", :yellow, "n/a")
191
+ end
192
+ md "Fails the friction principle outright: the agent has to already know to look, and in practice only discovers Wayfinder from *inside* the Wayfinder repo itself — the entire point was discovery from *other* projects. Fails the cognitive-load principle too, since it relies on a human remembering to paste a snippet somewhere. Keep the good README regardless of what else ships — but this alone is the absence of a mechanism, not one."
193
+ end
194
+
195
+ ad_option("E", "The tool teaches itself", "Error messages and help output as onboarding, at the moment of contact") do
196
+ div(class: "ad-chips") do
197
+ ad_chip("Discovery", :green, "Perfect in-moment")
198
+ ad_chip("Friction", :green, "Zero / instant")
199
+ ad_chip("Load·user", :green, "Excellent")
200
+ ad_chip("Load·maint.", :green, "Very low")
201
+ ad_chip("Cost", :green, "Hours")
202
+ ad_chip("Robustness", :green, "High")
203
+ end
204
+ md "Orthogonal to every other option, cheap, and compounds with all of them. `beacon check` gate failures already interrupt an agent mid-commit — that's the highest-attention channel it will ever give you, so make the failure text a complete, copy-pasteable remediation plus one line of \"what Beacon is and why.\" Add `wayfinder help --agent` / `beacon help --agent` emitting exactly Option A's canonical snippet. End `wayfinder init` with \"next: run `wayfinder agents init`.\" Give empty `--json` results a `_hint` field. It's an amplifier, not a discovery mechanism on its own — something else still has to cause first contact — but there's no version of \"batteries included\" that shouldn't include it."
205
+ end
206
+
207
+ ad_option("F", "Hybrid — MCP as source of truth, context files as habit", "B + A + E, layered in that priority order", recommended: true) do
208
+ div(class: "ad-chips") do
209
+ ad_chip("Discovery", :green, "Excellent")
210
+ ad_chip("Friction", :green, "~zero after setup")
211
+ ad_chip("Load·user", :green, "Excellent")
212
+ ad_chip("Load·maint.", :green, "Low")
213
+ ad_chip("Cost", :yellow, "~1 week total")
214
+ ad_chip("Robustness", :green, "High")
215
+ end
216
+ md "The full story: `gem install wayfinder` puts the binaries on PATH. `wayfinder agents setup`, run once per machine, registers the MCP server with every detected CLI *and* appends a short section to each CLI's user-global context file — global prose installs the habit (\"these tools exist, use them, write back what you learn\"), MCP tools keep the capability always fresh. `wayfinder agents init` stays available per-repo for project-specific pointers (hub location, Beacon membership), and both `beacon init` and `wayfinder init` suggest running it — so it self-propagates. Self-teaching output (E) runs through all of it. Static prose is kept deliberately thin and stable; everything that changes with the CLI's surface lives behind MCP descriptions and `help --agent`, so the sync burden the cognitive-load principle warns about approaches zero."
217
+ end
218
+
219
+ # =========================================================================
220
+ # 04 — Comparison
221
+ # =========================================================================
222
+ doc_section_header "04 — Comparison", "Side by side", id: "matrix"
223
+ div(class: "ad-legend") do
224
+ div(class: "ad-legend-item") { status_dot(status: :green, size: :sm); phrase("Strong / low cost") }
225
+ div(class: "ad-legend-item") { status_dot(status: :yellow, size: :sm); phrase("Mixed / moderate") }
226
+ div(class: "ad-legend-item") { status_dot(status: :red, size: :sm); phrase("Weak / high cost") }
227
+ end
228
+ div(class: "ad-tbl-scroll") do
229
+ table(
230
+ class: "ad-matrix-table mono",
231
+ markdown: true,
232
+ headers: ["Option", "Discovery", "Friction", "Load·user", "Load·maint.", "Cost", "Robustness"],
233
+ rows: [
234
+ ["A — Context writer", ad_rate(:green, "Strong"), ad_rate(:yellow, "1/repo"), ad_rate(:green, "Good"), ad_rate(:green, "Low"), ad_rate(:green, "~1 day"), ad_rate(:yellow, "Medium")],
235
+ ["B — MCP server", ad_rate(:yellow, "Find ↑ / digest ↓"), ad_rate(:green, "1/machine"), ad_rate(:green, "Excellent"), ad_rate(:green, "V. low"), ad_rate(:yellow, "2–4 days"), ad_rate(:green, "Highest")],
236
+ ["C — Native bundles", ad_rate(:green, "Excellent"), ad_rate(:green, "1/machine"), ad_rate(:green, "Good"), ad_rate(:red, "High"), ad_rate(:red, "High+ongoing"), ad_rate(:red, "Low–med")],
237
+ ["D — Docs only", ad_rate(:red, "Weak"), ad_rate(:red, "Fails"), ad_rate(:red, "Fails"), ad_rate(:green, "~zero"), ad_rate(:green, "~zero"), ad_rate(:yellow, "n/a")],
238
+ ["E — Self-teaching", ad_rate(:green, "Perfect*"), ad_rate(:green, "Zero"), ad_rate(:green, "Excellent"), ad_rate(:green, "V. low"), ad_rate(:green, "Hours"), ad_rate(:green, "High")],
239
+ ["F — Hybrid (B+A+E)", ad_rate(:green, "Excellent"), ad_rate(:green, "~zero*"), ad_rate(:green, "Excellent"), ad_rate(:green, "Low"), ad_rate(:yellow, "~1 week"), ad_rate(:green, "High")]
240
+ ]
241
+ )
242
+ end
243
+ md "*E: perfect only at the moment an agent already touches the tool — it doesn't cause first contact. F: zero friction only after the one machine-level setup command."
244
+
245
+ # =========================================================================
246
+ # 05 — Recommendation
247
+ # =========================================================================
248
+ doc_section_header "05 — Recommendation", "", id: "reco"
249
+ div(class: "ad-reco") do
250
+ callout(title: "Top pick — Option F, built in order E → A → B") do
251
+ md <<~MD
252
+ Two failure modes matter: the agent never hears about the tool, and the maintainer has to keep four vendor artifacts in sync and stops (the cognitive-load principle, maintainer edition). The hybrid solves the first one twice over — global context prose installs the write-back habit in every session on the machine, MCP tools make the capability ambient and self-describing — and solves the second by keeping the volatile parts live (MCP, `help --agent`) and the static parts thin and stable. Option C's per-vendor bundles are the trap: best-in-class UX per ecosystem, worst-in-class rot profile. Skip it until one ecosystem clearly earns it — a Claude Skill is the strongest later candidate, since skills uniquely encode *when* to write, and it can be dogfooded privately first.
253
+
254
+ ### Ship-now fallback
255
+
256
+ A weekend, pre-launch: Option E (hours — `--agent` help mode, gate-failure remediation text, `_hint` fields) plus Option A (`wayfinder agents init`, generalizing the existing `init.rb` machinery to the CLAUDE.md-imports-AGENTS.md pattern and a GEMINI.md stub). That alone takes Codex from "incidentally best-served" to all four CLIs covered per-repo, from one template. Layer in the MCP server (B) as the flagship feature for the actual launch — it also happens to be the strongest marketing artifact for a public gem, since MCP is what 2026 readers scan for first.
257
+ MD
258
+ end
259
+ end
260
+ div(class: "ad-aside") do
261
+ callout(title: "One note, regardless of which option wins") do
262
+ md "Tool availability alone gets an agent *reading* the registry. The *writing*-knowledge-back behavior — the part that actually builds toward the friction/cognitive-load UX — only happens when instructions say *when* to write: \"learned something durable → registry or wiki, then reindex.\" That sentence belongs in every surface: the AGENTS.md section, the global stub, the MCP tool descriptions, and any Skill built later."
263
+ end
264
+ end
265
+
266
+ # =========================================================================
267
+ # 06 — Confidence check
268
+ # =========================================================================
269
+ doc_section_header "06 — Confidence check", "Verified this session, vs. still open", id: "confidence"
270
+ columns(class: "ad-split", gap: "1.2rem") do
271
+ column do
272
+ phrase("Verified via search, July 2026", class: "ad-col-h ad-col-h--v")
273
+ div(class: "ad-checklist ad-checklist--verified") do
274
+ ad_check("✓", "Claude Code has no native AGENTS.md read — tracked in the public issue queue, thousands of reactions; `@AGENTS.md` import and symlinking are the working patterns")
275
+ ad_check("✓", "Gemini CLI's sole out-of-box context filename is GEMINI.md; AGENTS.md support is an open feature request. A per-user `contextFileName` override exists in settings but isn't the out-of-box default other users will have")
276
+ ad_check("✓", "Copilot CLI reads AGENTS.md, .github/copilot-instructions.md, .github/instructions/**, and even CLAUDE.md/GEMINI.md, per its own docs")
277
+ ad_check("✓", "All four CLIs support MCP; Codex can run *as* an MCP server; config lives at `~/.gemini/settings.json`, via `claude mcp add`, and in Copilot's command/HTTP server config")
278
+ ad_check("✓", "Gemini CLI extensions (`gemini extensions install org/repo`) bundle MCP config + context file with vendor-managed updates")
279
+ ad_check("✓", "Claude Code plugins/marketplaces are the current skill-distribution format (`/plugin`, bundling SKILL.md + hooks + MCP config)")
280
+ end
281
+ end
282
+ column do
283
+ phrase("Needs a second reviewer's confirmation", class: "ad-col-h ad-col-h--u")
284
+ div(class: "ad-checklist ad-checklist--unverified") do
285
+ ad_check("?", "Whether the `@AGENTS.md` import works in a freshly-created CLAUDE.md exactly as documented, on the currently installed Claude Code version — test empirically")
286
+ ad_check("?", "Copilot CLI's exact user-level (machine-global) instruction file path and MCP config format — docs found cover the IDE surface best, not the standalone CLI")
287
+ ad_check("?", "Codex's `config.toml` MCP schema's current shape — check against the installed version before writing `install-mcp`")
288
+ ad_check("?", "Whether a maintained official Ruby MCP SDK gem exists to build Option B on — a 10-minute check before committing to that estimate")
289
+ end
290
+ end
291
+ end
292
+ div(class: "ad-sources") do
293
+ md "Sources: notes.example.dev/agent-cli-notes (context-file survey) · github.com/example-cli/example-cli/issues/8841 · cli-docs.example.dev/gemini-md · github.com/example-cli/gemini-cli/issues/5210 · docs.example.dev/copilot-cli/custom-instructions · changelog.example.dev/2025-08-28 · cli-docs.example.dev/extensions · docs.example.dev/plugin-marketplaces · surveys.example.dev/cli-comparison"
294
+ end
295
+
296
+ div(class: "ad-footer") do
297
+ phrase("Wayfinder / Beacon — agent discovery options")
298
+ phrase("drafted by a research subagent · reviewed for Priya Osei, Platform Team")
299
+ end
300
+ end
@@ -0,0 +1,112 @@
1
+ # Usage: streamweaver canvas-push <session> < examples/components/diff_block_demo.rb
2
+ # Or: streamweaver panel diff-block-demo && streamweaver canvas-push diff-block-demo < examples/components/diff_block_demo.rb
3
+
4
+ header2 "DiffBlock — Unified Diff Viewer"
5
+ md "Server-side diff via diffy gem. Removed lines red, added lines green, context neutral. Two-column line-number gutter. Prism.js syntax highlighting per line."
6
+
7
+ header3 "Ruby method refactor"
8
+
9
+ diff(language: "ruby") do
10
+ before do
11
+ <<~'RUBY'
12
+ def greet
13
+ puts 'hi'
14
+ end
15
+ RUBY
16
+ end
17
+ after do
18
+ <<~'RUBY'
19
+ def greet(name)
20
+ puts "Hello, #{name}"
21
+ end
22
+ RUBY
23
+ end
24
+ end
25
+
26
+ header3 "Multi-hunk diff (large file excerpt)"
27
+
28
+ diff(language: "ruby") do
29
+ before do
30
+ <<~'RUBY'
31
+ class User
32
+ attr_reader :name, :email
33
+
34
+ def initialize(name, email)
35
+ @name = name
36
+ @email = email
37
+ end
38
+
39
+ def display
40
+ "#{name} <#{email}>"
41
+ end
42
+
43
+ def active?
44
+ true
45
+ end
46
+ end
47
+ RUBY
48
+ end
49
+ after do
50
+ <<~'RUBY'
51
+ class User
52
+ attr_reader :name, :email, :role
53
+
54
+ def initialize(name, email, role: :viewer)
55
+ @name = name
56
+ @email = email
57
+ @role = role
58
+ end
59
+
60
+ def display
61
+ "#{name} <#{email}> [#{role}]"
62
+ end
63
+
64
+ def active?
65
+ @role != :suspended
66
+ end
67
+ end
68
+ RUBY
69
+ end
70
+ end
71
+
72
+ header3 "JavaScript"
73
+
74
+ diff(language: "javascript") do
75
+ before do
76
+ <<~JS
77
+ function fetchUser(id) {
78
+ return fetch('/users/' + id)
79
+ .then(function(res) { return res.json(); });
80
+ }
81
+ JS
82
+ end
83
+ after do
84
+ <<~JS
85
+ async function fetchUser(id) {
86
+ const res = await fetch(`/users/${id}`);
87
+ return res.json();
88
+ }
89
+ JS
90
+ end
91
+ end
92
+
93
+ header3 "No language (plain text / pseudocode)"
94
+
95
+ diff do
96
+ before do
97
+ <<~TEXT
98
+ push start onto stack
99
+ while stack not empty
100
+ node = stack.pop
101
+ visit node
102
+ TEXT
103
+ end
104
+ after do
105
+ <<~TEXT
106
+ enqueue start
107
+ while queue not empty
108
+ node = queue.dequeue
109
+ visit node
110
+ TEXT
111
+ end
112
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Events Demo - demonstrates on_change, on_blur, debounce, and hover callbacks
4
+ #
5
+ # Run with: ruby examples/events_demo.rb
6
+
7
+ require_relative '../../lib/stream_weaver'
8
+
9
+ app = StreamWeaver.app "Events Demo" do
10
+ header1 "Events & Callbacks Demo"
11
+
12
+ md "This example demonstrates **event callbacks** for form components and **hover effects** for containers."
13
+
14
+ # Initialize state
15
+ state[:change_count] ||= 0
16
+ state[:blur_count] ||= 0
17
+ state[:last_change] ||= ""
18
+ state[:validated_email] ||= ""
19
+ state[:email_valid] ||= nil
20
+ state[:search_results] ||= []
21
+
22
+ # =========================================
23
+ # on_change Example
24
+ # =========================================
25
+ header2 "on_change Callback"
26
+ md "The text field below triggers a callback on every change (debounced):"
27
+
28
+ text_field :search_query,
29
+ placeholder: "Type to search...",
30
+ debounce: 300,
31
+ on_change: ->(s, value) {
32
+ s[:change_count] += 1
33
+ s[:last_change] = value
34
+
35
+ # Simulate search results
36
+ if value.length >= 2
37
+ s[:search_results] = [
38
+ "Result for '#{value}' #1",
39
+ "Result for '#{value}' #2",
40
+ "Result for '#{value}' #3"
41
+ ]
42
+ else
43
+ s[:search_results] = []
44
+ end
45
+ }
46
+
47
+ card do
48
+ text "Change count: #{state[:change_count]}"
49
+ text "Last change: #{state[:last_change]}"
50
+
51
+ if state[:search_results].any?
52
+ header4 "Search Results:"
53
+ vstack spacing: :xs do
54
+ state[:search_results].each do |result|
55
+ text "• #{result}"
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ # =========================================
62
+ # on_blur Example
63
+ # =========================================
64
+ header2 "on_blur Callback"
65
+ md "The email field below validates when you leave the field (blur):"
66
+
67
+ text_field :email,
68
+ placeholder: "Enter email address...",
69
+ on_blur: ->(s, value) {
70
+ s[:blur_count] += 1
71
+ s[:validated_email] = value
72
+
73
+ # Simple email validation
74
+ if value.empty?
75
+ s[:email_valid] = nil
76
+ elsif value.include?("@") && value.include?(".")
77
+ s[:email_valid] = true
78
+ else
79
+ s[:email_valid] = false
80
+ end
81
+ }
82
+
83
+ card do
84
+ text "Blur count: #{state[:blur_count]}"
85
+
86
+ if state[:email_valid] == true
87
+ text "✅ Valid email: #{state[:validated_email]}"
88
+ elsif state[:email_valid] == false
89
+ text "❌ Invalid email format"
90
+ else
91
+ text "Enter an email and click outside the field to validate"
92
+ end
93
+ end
94
+
95
+ # =========================================
96
+ # Checkbox on_change
97
+ # =========================================
98
+ header2 "Checkbox on_change"
99
+ md "Checkboxes can also have change callbacks:"
100
+
101
+ state[:features] ||= []
102
+
103
+ checkbox :dark_mode, "Enable dark mode",
104
+ on_change: ->(s, value) {
105
+ if value
106
+ s[:features] << "dark_mode" unless s[:features].include?("dark_mode")
107
+ else
108
+ s[:features].delete("dark_mode")
109
+ end
110
+ }
111
+
112
+ checkbox :notifications, "Enable notifications",
113
+ on_change: ->(s, value) {
114
+ if value
115
+ s[:features] << "notifications" unless s[:features].include?("notifications")
116
+ else
117
+ s[:features].delete("notifications")
118
+ end
119
+ }
120
+
121
+ card do
122
+ text "Enabled features: #{state[:features].empty? ? 'none' : state[:features].join(', ')}"
123
+ end
124
+
125
+ # =========================================
126
+ # Select on_change
127
+ # =========================================
128
+ header2 "Select on_change"
129
+ md "Select dropdowns also support change callbacks:"
130
+
131
+ state[:theme_history] ||= []
132
+
133
+ select :theme, %w[Light Dark System],
134
+ default: "Light",
135
+ on_change: ->(s, value) {
136
+ s[:theme_history] << value
137
+ s[:theme_history] = s[:theme_history].last(5) # Keep last 5
138
+ }
139
+
140
+ card do
141
+ text "Theme history: #{state[:theme_history].join(' → ')}"
142
+ end
143
+
144
+ # =========================================
145
+ # Hover Effects
146
+ # =========================================
147
+ header2 "Hover Effects"
148
+ md "Containers can have hover classes for visual feedback:"
149
+
150
+ hstack spacing: :md do
151
+ div hover_class: "sw-hover-highlight", class: "hover-demo-box" do
152
+ text "Hover me!"
153
+ end
154
+
155
+ div hover_class: "sw-hover-lift", class: "hover-demo-box" do
156
+ text "I lift on hover"
157
+ end
158
+
159
+ div hover_class: "sw-hover-glow", class: "hover-demo-box" do
160
+ text "I glow on hover"
161
+ end
162
+ end
163
+
164
+ # =========================================
165
+ # Custom CSS for demo
166
+ # =========================================
167
+ md """
168
+ ---
169
+ **How it works:**
170
+ - **on_change**: Callback fires when input value changes (with optional debounce delay)
171
+ - **on_blur**: Callback fires when input loses focus (good for validation)
172
+ - **debounce**: Milliseconds to wait before firing on_change (default: 500ms)
173
+ - **hover_class**: CSS class added on mouseenter, removed on mouseleave
174
+
175
+ Built-in hover classes: `sw-hover-highlight`, `sw-hover-lift`, `sw-hover-glow`
176
+ """
177
+
178
+ md "---"
179
+ button "Reset Demo", style: :secondary do |s|
180
+ s.clear
181
+ end
182
+ end
183
+
184
+ app.run!
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Form Block Demo - demonstrates deferred submission forms
4
+ #
5
+ # Run with: ruby examples/form_demo.rb
6
+
7
+ require_relative '../../lib/stream_weaver'
8
+
9
+ app = StreamWeaver.app "Form Block Demo" do
10
+ header1 "Form Blocks Demo"
11
+
12
+ md "This example demonstrates **deferred submission forms**. Form fields don't sync with the server until you click Submit."
13
+
14
+ # Pre-populate form state (simulating loading from database)
15
+ state[:edit_profile] ||= {
16
+ name: "Alice",
17
+ status: "active",
18
+ notes: "Initial notes..."
19
+ }
20
+
21
+ header2 "Edit Profile"
22
+
23
+ form :edit_profile do
24
+ text_field :name, placeholder: 'Your name'
25
+ select :status, %w[active paused archived]
26
+ text_area :notes, placeholder: 'Notes about this person...', rows: 4
27
+
28
+ submit 'Save Changes' do |form_values|
29
+ # This runs AFTER state[:edit_profile] is updated
30
+ puts "Form submitted with: #{form_values.inspect}"
31
+ end
32
+
33
+ cancel 'Reset'
34
+ end
35
+
36
+ # Show current state (updates after form submit)
37
+ header2 "Current State"
38
+ card do
39
+ text "Name: #{state.dig(:edit_profile, :name)}"
40
+ text "Status: #{state.dig(:edit_profile, :status)}"
41
+ text "Notes: #{state.dig(:edit_profile, :notes)}"
42
+ end
43
+
44
+ md "---"
45
+ md "**How it works:**"
46
+ md "- Type in the fields - nothing syncs to server yet"
47
+ md "- Click **Save Changes** - all values sent in one request"
48
+ md "- Click **Reset** - fields revert to original values (client-side only)"
49
+
50
+ md "---"
51
+ md "**Note:** State persists in browser cookies across server restarts. Click below to start fresh:"
52
+ button "Reset Demo", style: :secondary do |s|
53
+ s.clear
54
+ end
55
+
56
+ header2 "Standalone Field (for comparison)"
57
+ md "This field syncs immediately on change:"
58
+ text_field :standalone_field, placeholder: "Type here - syncs immediately"
59
+ text "Standalone value: #{state[:standalone_field]}"
60
+ end
61
+
62
+ app.run!