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,33 @@
1
+ require 'stream_weaver'
2
+
3
+ app "Counter" do
4
+ callout "This whole app is the file your agent just ran -- nothing hidden. Click +1 -- the whole block re-runs on the server and the count updates. When you're done playing: come back to your Claude session and say \"done\".", variant: :info
5
+ state[:count] ||= 0
6
+ header1 "Six lines of Ruby"
7
+ text "Count: #{state[:count]}"
8
+ button("+1") { |s| s[:count] += 1 }
9
+ end.run!
10
+
11
+ # ^ The mechanism above is still the whole app: a six-line block (four
12
+ # statements wrapped by `app "Counter" do` and `end.run!`), in an eight-line
13
+ # file. Nothing has been elided, and nothing below this line runs -- `.run!`
14
+ # blocks. StreamWeaver University, step 2 (story: step-2-dsl-reexec). The
15
+ # worker runs THIS file, verbatim, rather than writing its own: two real
16
+ # worker sessions each lost a debug cycle to the "six-line app" framing, one
17
+ # by omitting `require 'stream_weaver'` (NoMethodError: undefined method
18
+ # 'app') and the other by omitting `.run!` (builds the app, starts no
19
+ # server, exits silently). Both lines are above, on purpose.
20
+ #
21
+ # ruby "$(streamweaver university-demo counter)"
22
+ #
23
+ # There is no event-handler code here and no route. The block on line 5 is
24
+ # re-executed on every click; `state[:count]` is one higher when it runs, so
25
+ # line 7 renders a different number. That single idea -- the block re-runs
26
+ # -- is every other thing StreamWeaver does, wearing different clothes.
27
+ #
28
+ # Round-6 UAT (2026-09-03): the app used to pop up with no explanation of
29
+ # its own, so anyone who tabbed over before the agent's narration caught up
30
+ # saw a bare counter and nothing else. The `callout` above is the file's
31
+ # ninth line -- deliberately not part of the six-line mechanism, and not one
32
+ # of the two bookend lines named above either. It is the one line meant to
33
+ # be read on screen, not walked through.
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ # StreamWeaver University -- step 1's dashboard demo (story:
4
+ # step-1-canvas-push).
5
+ #
6
+ # Three things a terminal cannot draw, in one push: a 2x2 grid of KPI tiles,
7
+ # a Chart.js bar chart, and a mermaid sequence diagram of the very
8
+ # canvas-push that put them there. Then the same layout again with different
9
+ # numbers, so the pane mutates in place while the worker narrates.
10
+ #
11
+ # streamweaver panel dashboard # open the pane first
12
+ # ruby "$(streamweaver university-demo dashboard)" dashboard # week 1
13
+ # ruby "$(streamweaver university-demo dashboard)" dashboard 2 # mutate
14
+ # ruby "$(streamweaver university-demo dashboard)" dashboard 3 # mutate
15
+ #
16
+ # ARGV: SESSION_NAME (default "dashboard"), SNAPSHOT (1-3, default 1).
17
+ #
18
+ # Why a push script rather than three DSL files piped through
19
+ # `canvas-push`: the DSL is rendered inside the bridge process, so a file
20
+ # cannot read the caller's environment, and three near-identical DSL files
21
+ # would be three places for the layout to drift. One parameterized script,
22
+ # three snapshots of the same layout.
23
+ #
24
+ # Design constraints baked in:
25
+ #
26
+ # - Pane width. This renders in a ~750-800px split pane
27
+ # (features/university-getting-started.context.md, "Pane-width rule"), so
28
+ # the tiles are two rows of two rather than one row of four -- `.sw-columns`
29
+ # only stacks below 640px, and four tiles across 750px is unreadable.
30
+ # - `chart type:` explicitly, never the `bar_chart` shorthand: the shorthand
31
+ # family renders through Alpine `x-init`, and disc-094 kills it on export.
32
+ # The explicit form is what commit 51beb6c fixed for bridge poll swaps.
33
+
34
+ require 'stream_weaver/canvas/client'
35
+
36
+ module StreamWeaver
37
+ module University
38
+ module Demos
39
+ module Dashboard
40
+ # Each snapshot is one frame of the same dashboard. Same tile
41
+ # labels, same chart series, different numbers -- so a re-push reads
42
+ # as "the data moved", not "a different page".
43
+ SNAPSHOTS = [
44
+ {
45
+ caption: 'Sprint 14 · Monday standup',
46
+ tiles: [
47
+ { value: 128, label: 'PUSHES', color: :default },
48
+ { value: 12, label: 'SESSIONS', color: :blue },
49
+ { value: 3, label: 'BLOCKED', color: :red },
50
+ { value: 41, label: 'DOCS SAVED', color: :purple }
51
+ ],
52
+ bars: [18, 24, 31, 22, 33]
53
+ },
54
+ {
55
+ caption: 'Sprint 14 · Wednesday standup',
56
+ tiles: [
57
+ { value: 164, label: 'PUSHES', color: :default },
58
+ { value: 15, label: 'SESSIONS', color: :blue },
59
+ { value: 1, label: 'BLOCKED', color: :red },
60
+ { value: 52, label: 'DOCS SAVED', color: :purple }
61
+ ],
62
+ bars: [18, 24, 31, 29, 47]
63
+ },
64
+ {
65
+ caption: 'Sprint 14 · Friday standup',
66
+ tiles: [
67
+ { value: 203, label: 'PUSHES', color: :default },
68
+ { value: 19, label: 'SESSIONS', color: :blue },
69
+ { value: 0, label: 'BLOCKED', color: :red },
70
+ { value: 68, label: 'DOCS SAVED', color: :purple }
71
+ ],
72
+ bars: [18, 24, 31, 29, 61]
73
+ }
74
+ ].freeze
75
+
76
+ DAYS = %w[Mon Tue Wed Thu Fri].freeze
77
+
78
+ # One flat DSL body for the given snapshot. Flat and
79
+ # one-statement-per-component on purpose (same rule the growing-doc
80
+ # script follows) so the text stays legible when a curious user
81
+ # reads the file this course just ran.
82
+ def self.dsl(index = 0)
83
+ snap = SNAPSHOTS[index]
84
+ top, bottom = snap[:tiles].each_slice(2).to_a
85
+
86
+ <<~RUBY
87
+ header1 "Canvas activity"
88
+
89
+ text #{snap[:caption].inspect}
90
+
91
+ columns 2 do
92
+ column { stat_display value: #{top[0][:value]}, label: #{top[0][:label].inspect}, color: :#{top[0][:color]}, size: :lg }
93
+ column { stat_display value: #{top[1][:value]}, label: #{top[1][:label].inspect}, color: :#{top[1][:color]}, size: :lg }
94
+ end
95
+
96
+ columns 2 do
97
+ column { stat_display value: #{bottom[0][:value]}, label: #{bottom[0][:label].inspect}, color: :#{bottom[0][:color]}, size: :lg }
98
+ column { stat_display value: #{bottom[1][:value]}, label: #{bottom[1][:label].inspect}, color: :#{bottom[1][:color]}, size: :lg }
99
+ end
100
+
101
+ chart type: :bar, data: {
102
+ labels: #{DAYS.inspect},
103
+ datasets: [
104
+ { label: "Pushes", data: #{snap[:bars].inspect}, backgroundColor: "#6366f1" }
105
+ ]
106
+ }, height: 240
107
+
108
+ md "**How this got here.** Not a screenshot, not a file your agent opened in a browser -- one command, and the pane you are looking at redrew itself:"
109
+
110
+ mermaid <<~DIAGRAM
111
+ sequenceDiagram
112
+ participant A as Your agent
113
+ participant C as streamweaver CLI
114
+ participant B as canvas bridge
115
+ participant P as this pane
116
+ A->>C: ruby dashboard.rb dashboard #{index + 1}
117
+ C->>B: push(session, DSL)
118
+ B->>B: render DSL -> HTML
119
+ B-->>P: poll swap, in place
120
+ P-->>A: no reload, no flicker
121
+ DIAGRAM
122
+ RUBY
123
+ end
124
+
125
+ def self.run!(session_name: ARGV[0] || 'dashboard',
126
+ snapshot: Integer(ARGV[1] || 1))
127
+ index = snapshot.clamp(1, SNAPSHOTS.length) - 1
128
+
129
+ ::StreamWeaver::Canvas::Client.ensure_bridge_running
130
+ ::StreamWeaver::Canvas::Client.send_message(
131
+ ::StreamWeaver::Canvas::Protocol::Messages.create(session_name, layout: :fluid)
132
+ )
133
+ ::StreamWeaver::Canvas::Client.send_message(
134
+ ::StreamWeaver::Canvas::Protocol::Messages.push(session_name, dsl(index), source_dir: nil)
135
+ )
136
+ puts "Pushed snapshot #{index + 1} of #{SNAPSHOTS.length} (#{SNAPSHOTS[index][:caption]}) to canvas session '#{session_name}'."
137
+ rescue ::StreamWeaver::Canvas::Client::NotRunningError,
138
+ ::StreamWeaver::Canvas::Client::ConnectionError => e
139
+ warn "dashboard: could not reach the canvas bridge (#{e.message}) -- " \
140
+ "run `streamweaver panel #{session_name}` first"
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ StreamWeaver::University::Demos::Dashboard.run! if $PROGRAM_NAME == __FILE__
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ # StreamWeaver University -- step 3's decision form (story:
4
+ # step-3-form-modes).
5
+ #
6
+ # ONE artifact, two surfaces. The same question -- a mermaid diagram of two
7
+ # candidate architectures, a comparison table, a radio_group and a rationale
8
+ # text_field -- is rendered either as a standalone blocking app or as a
9
+ # canvas push. Nothing is duplicated between the two modes; that identity is
10
+ # the lesson, and the worker is told to say so out loud.
11
+ #
12
+ # Mode 1, the founding loop (step 3's opening move):
13
+ #
14
+ # ruby "$(streamweaver university-demo decision-form)"
15
+ #
16
+ # `run_once!` finds a free port, OPENS the browser itself, and BLOCKS. The
17
+ # user answers in the page that just appeared; the process prints the
18
+ # submitted state as JSON and exits. The user never opens a page and never
19
+ # has to tell the agent "done" -- round-5 UAT found both of those to be
20
+ # homework the course was silently assigning.
21
+ #
22
+ # Mode 2, the same form on the canvas:
23
+ #
24
+ # streamweaver panel decision
25
+ # ruby "$(streamweaver university-demo decision-form)" canvas decision
26
+ # streamweaver canvas-wait decision
27
+ #
28
+ # Input components are radio_group / text_field only. disc-098 and disc-105:
29
+ # checkbox_group and multi chip_group harvest the wrong values back through
30
+ # canvas-wait.
31
+
32
+ require 'stream_weaver'
33
+ require 'stream_weaver/canvas/client'
34
+
35
+ module StreamWeaver
36
+ module University
37
+ module Demos
38
+ module DecisionForm
39
+ # The question and its evidence. Everything a terminal prompt cannot
40
+ # carry: a rendered diagram of both designs, and a table putting them
41
+ # side by side on three axes.
42
+ CONTEXT = <<~RUBY
43
+ header1 "Which way should the canvas bridge hold sessions?"
44
+
45
+ md "This is a real decision, not a demo prompt -- and it is the kind an agent normally has to ask you in prose, one option per paragraph, hoping you can hold both designs in your head at once."
46
+
47
+ mermaid <<~DIAGRAM
48
+ graph TB
49
+ subgraph A["A · One shared bridge"]
50
+ A1["streamweaver CLI"] --> A2["single bridge process"]
51
+ A2 --> A3["session: dashboard"]
52
+ A2 --> A4["session: decision"]
53
+ A2 --> A5["session: doc-demo"]
54
+ end
55
+ subgraph B["B · A process per session"]
56
+ B1["streamweaver CLI"] --> B2["bridge: dashboard"]
57
+ B1 --> B3["bridge: decision"]
58
+ B1 --> B4["bridge: doc-demo"]
59
+ end
60
+ DIAGRAM
61
+
62
+ table [
63
+ { axis: "Memory", shared: "One process, one Puma", per_session: "N processes, N Pumas" },
64
+ { axis: "Blast radius", shared: "A crash takes every pane", per_session: "A crash takes one pane" },
65
+ { axis: "Cross-session reads", shared: "Free -- same object graph", per_session: "Needs IPC or a store" }
66
+ ]
67
+ RUBY
68
+
69
+ # The inputs. Shared verbatim by both surfaces -- change a label here
70
+ # and both the standalone app and the canvas form change with it.
71
+ FORM = <<~RUBY
72
+ radio_group :architecture, [
73
+ "A -- one shared bridge, all sessions inside it",
74
+ "B -- one bridge process per session"
75
+ ]
76
+
77
+ md "**Why?** One line. Your agent reads this back to you verbatim and reacts to it."
78
+
79
+ text_field :rationale, placeholder: "Because..."
80
+ RUBY
81
+
82
+ # The canvas surface says out loud what is happening to the worker's
83
+ # terminal, because on the canvas there is nothing else to tell you.
84
+ # The standalone surface does not need it: `run_once!` prints
85
+ # "Waiting for form submission" in the very terminal that is stuck.
86
+ BLOCKING_CALLOUT = <<~RUBY
87
+ callout(variant: :warning, title: "Your agent is frozen right now") do
88
+ md "This is a **blocking** form. The worker terminal is sitting inside `streamweaver canvas-wait decision` and will not print another line until you press Submit. Look over at it -- nothing is moving."
89
+ end
90
+ RUBY
91
+
92
+ SUBMIT = <<~RUBY
93
+ button "Submit decision"
94
+ RUBY
95
+
96
+ # Standalone gets no explicit button: agentic mode (`run_once!`)
97
+ # renders its own submit control and uses it to unblock.
98
+ def self.standalone_dsl
99
+ "#{CONTEXT}\n#{FORM}"
100
+ end
101
+
102
+ def self.canvas_dsl
103
+ "#{BLOCKING_CALLOUT}\n#{CONTEXT}\n#{FORM}\n#{SUBMIT}"
104
+ end
105
+
106
+ # Mode 1. Blocks; opens the browser; prints the submitted state as
107
+ # JSON on stdout when the user submits.
108
+ def self.standalone!
109
+ dsl = standalone_dsl
110
+ ::StreamWeaver.app("A real decision") { instance_eval(dsl) }.run_once!
111
+ end
112
+
113
+ # Mode 2. Pushes the same question into a canvas session, for
114
+ # `streamweaver canvas-wait <session>` to block on.
115
+ def self.push!(session_name)
116
+ ::StreamWeaver::Canvas::Client.ensure_bridge_running
117
+ ::StreamWeaver::Canvas::Client.send_message(
118
+ ::StreamWeaver::Canvas::Protocol::Messages.create(session_name, layout: :fluid)
119
+ )
120
+ ::StreamWeaver::Canvas::Client.send_message(
121
+ ::StreamWeaver::Canvas::Protocol::Messages.push(session_name, canvas_dsl, source_dir: nil)
122
+ )
123
+ puts "Pushed the same decision form to canvas session '#{session_name}'. " \
124
+ "Block on it with: streamweaver canvas-wait #{session_name}"
125
+ rescue ::StreamWeaver::Canvas::Client::NotRunningError,
126
+ ::StreamWeaver::Canvas::Client::ConnectionError => e
127
+ warn "decision_form: could not reach the canvas bridge (#{e.message}) -- " \
128
+ "run `streamweaver panel #{session_name}` first"
129
+ end
130
+
131
+ def self.run!(argv = ARGV)
132
+ if argv.first == 'canvas'
133
+ push!(argv[1] || 'decision')
134
+ else
135
+ standalone!
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ StreamWeaver::University::Demos::DecisionForm.run! if $PROGRAM_NAME == __FILE__
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StreamWeaver
4
+ module University
5
+ # The canned artifacts every Getting Started step demonstrates.
6
+ #
7
+ # Round-5 UAT (2026-09-03) took ~5 minutes to reach first paint because
8
+ # each worker session *composed* its demo live, and one of them went
9
+ # looking for the source repo to do it. Both are now designed out: every
10
+ # demo ships inside the gem as a finished, runnable file, so the worker's
11
+ # job is to RUN it and NARRATE it -- never to invent it, and never to
12
+ # need a checkout.
13
+ #
14
+ # `streamweaver university-demo <name>` prints the absolute path of one
15
+ # of these inside the installed gem, which is what the course prompts
16
+ # interpolate:
17
+ #
18
+ # ruby "$(streamweaver university-demo dashboard)" dashboard
19
+ #
20
+ # Names are normalized (`decision-form` and `decision_form` are the same
21
+ # demo) so a prompt, a spec and a human can each spell it the way that
22
+ # reads best where they are.
23
+ module Demos
24
+ ROOT = File.expand_path('demos', __dir__)
25
+
26
+ # name => path, relative to this file's directory. `doc` deliberately
27
+ # points at the growing-doc script that already shipped for step 4
28
+ # rather than a second copy of it -- one artifact, one place it can
29
+ # rot.
30
+ PATHS = {
31
+ 'dashboard' => File.join(ROOT, 'dashboard.rb'),
32
+ 'counter' => File.join(ROOT, 'counter.rb'),
33
+ 'decision-form' => File.join(ROOT, 'decision_form.rb'),
34
+ 'doc' => File.expand_path('scripts/growing_doc.rb', __dir__)
35
+ }.freeze
36
+
37
+ NAMES = PATHS.keys.freeze
38
+
39
+ # `decision_form`, `decision-form` and `DECISION FORM` all resolve.
40
+ def self.normalize(name)
41
+ name.to_s.strip.downcase.tr('_ ', '--')
42
+ end
43
+
44
+ # @return [String, nil] absolute path, or nil for an unknown name
45
+ def self.path(name)
46
+ PATHS[normalize(name)]
47
+ end
48
+ end
49
+ end
50
+ end