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,499 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Example: Visual Explainer — Diff Review
5
+ # A comprehensive code review document showcasing every explainer component.
6
+ # Scenario: AI agent reviews a PR that migrates from session-based auth to JWT.
7
+ #
8
+ # Run with: bundle exec ruby examples/visual_skills/explainer_demo.rb
9
+
10
+ require_relative '../../lib/stream_weaver'
11
+
12
+ ExplainerApp = app "Diff Review: feature/auth-migration", theme: :dark do
13
+ # -- Theme & chrome ----------------------------------------------------------
14
+ theme_preset :editorial
15
+ theme_toggle mode: :auto, hotkey: "mod+shift+l"
16
+
17
+ # -- Sidebar TOC with scroll spy ---------------------------------------------
18
+ sidebar_toc sections: [
19
+ { id: "summary", label: "Summary" },
20
+ { id: "kpis", label: "Key Metrics" },
21
+ { id: "architecture", label: "Architecture" },
22
+ { id: "file-changes", label: "File Changes" },
23
+ { id: "auth-before-after", label: "Auth Diff" },
24
+ { id: "middleware", label: "Middleware" },
25
+ { id: "pipeline", label: "CI Pipeline" },
26
+ { id: "test-coverage", label: "Test Coverage" },
27
+ { id: "risks", label: "Risk Analysis" },
28
+ { id: "verdict", label: "Verdict" }
29
+ ]
30
+
31
+ # -- Hero section ------------------------------------------------------------
32
+ div id: "summary" do
33
+ hero do
34
+ header1 "Diff Review: feature/auth-migration"
35
+ md "**PR #347** — Migrate from session-based authentication to JWT tokens"
36
+ hstack spacing: :md, align: :center do
37
+ badge "87 files changed", variant: :info
38
+ badge "+2,041 / -1,388", variant: :warning
39
+ badge "3 open threads", variant: :danger
40
+ badge "CI passing", variant: :success
41
+ end
42
+ end
43
+ end
44
+
45
+ # -- Executive summary (prose) -----------------------------------------------
46
+ prose dropcap: true do
47
+ md <<~MARKDOWN
48
+ This pull request replaces the legacy cookie-based session authentication
49
+ system with a stateless JWT token architecture. The migration touches the
50
+ authentication middleware, all protected API endpoints, the user model,
51
+ and the front-end token refresh logic. Session storage in Redis is replaced
52
+ by short-lived access tokens (15 min) paired with long-lived refresh tokens
53
+ (7 days) stored in an HttpOnly cookie.
54
+
55
+ The change is motivated by three factors: horizontal scaling without sticky
56
+ sessions, enabling a mobile API surface, and reducing Redis operational
57
+ burden. The overall approach is sound, but several security and performance
58
+ concerns require resolution before merge.
59
+ MARKDOWN
60
+ end
61
+
62
+ pullquote(
63
+ "Stateless auth is not free -- you trade server-side revocation for scalability. Make sure the trade is worth it.",
64
+ attribution: "Security Review Bot"
65
+ )
66
+
67
+ # -- KPI dashboard -----------------------------------------------------------
68
+ div id: "kpis" do
69
+ header2 "Key Metrics"
70
+
71
+ kpi_dashboard metrics: [
72
+ { value: "87", label: "Files Changed", color: :blue, trend: :up },
73
+ { value: "+2,041", label: "Lines Added", color: :green, trend: :up },
74
+ { value: "-1,388", label: "Lines Removed", color: :red, trend: :down },
75
+ { value: "94.2%", label: "Test Coverage", color: :green, trend: :up },
76
+ { value: "15 min", label: "Access Token TTL", color: :orange },
77
+ { value: "7 days", label: "Refresh Token TTL", color: :purple }
78
+ ]
79
+ end
80
+
81
+ # -- Test coverage chart -----------------------------------------------------
82
+ div id: "test-coverage" do
83
+ header2 "Test Coverage Trend"
84
+
85
+ chart type: :line, data: {
86
+ labels: ["Week 1", "Week 2", "Week 3", "Week 4", "Week 5", "This PR"],
87
+ datasets: [
88
+ {
89
+ label: "Line Coverage %",
90
+ data: [88.1, 89.3, 90.0, 91.5, 92.8, 94.2],
91
+ borderColor: "#22c55e",
92
+ backgroundColor: "rgba(34, 197, 94, 0.1)",
93
+ fill: true,
94
+ tension: 0.3
95
+ },
96
+ {
97
+ label: "Branch Coverage %",
98
+ data: [72.4, 74.0, 75.2, 78.1, 80.5, 83.7],
99
+ borderColor: "#3b82f6",
100
+ backgroundColor: "rgba(59, 130, 246, 0.1)",
101
+ fill: true,
102
+ tension: 0.3
103
+ }
104
+ ]
105
+ }, options: {
106
+ plugins: { title: { display: true, text: "Coverage Over Sprint" } },
107
+ scales: {
108
+ y: { min: 60, max: 100, ticks: { callback: "function(v){return v+'%'}" } }
109
+ }
110
+ }, height: 280
111
+
112
+ md "*Coverage improved from 88.1% to 94.2% across the sprint. Branch coverage still trails at 83.7%.*"
113
+ end
114
+
115
+ # -- Architecture diagram (Mermaid) ------------------------------------------
116
+ div id: "architecture" do
117
+ header2 "Authentication Architecture"
118
+
119
+ mermaid <<~MERMAID, zoom: true
120
+ graph TD
121
+ Client["Client (Browser / Mobile)"]
122
+ API["API Gateway"]
123
+ AuthSvc["Auth Service"]
124
+ UserDB[("Users DB")]
125
+ TokenStore["Token Blacklist<br/>(Redis)"]
126
+ Protected["Protected Resources"]
127
+
128
+ Client -->|"1. POST /auth/login<br/>email + password"| API
129
+ API -->|"2. Forward"| AuthSvc
130
+ AuthSvc -->|"3. Verify credentials"| UserDB
131
+ AuthSvc -->|"4. Issue JWT pair"| API
132
+ API -->|"5. Set HttpOnly cookie<br/>+ access_token body"| Client
133
+
134
+ Client -->|"6. GET /api/resource<br/>Authorization: Bearer token"| API
135
+ API -->|"7. Verify JWT signature<br/>+ check blacklist"| TokenStore
136
+ API -->|"8. Forward (valid)"| Protected
137
+ Protected -->|"9. Response"| Client
138
+
139
+ Client -->|"10. POST /auth/refresh"| AuthSvc
140
+ AuthSvc -->|"11. Rotate refresh token"| TokenStore
141
+
142
+ style Client fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
143
+ style AuthSvc fill:#dcfce7,stroke:#22c55e,color:#166534
144
+ style TokenStore fill:#fef3c7,stroke:#f59e0b,color:#92400e
145
+ style UserDB fill:#f3e8ff,stroke:#a855f7,color:#6b21a8
146
+ style Protected fill:#e0e7ff,stroke:#6366f1,color:#3730a3
147
+ style API fill:#f1f5f9,stroke:#94a3b8,color:#334155
148
+ MERMAID
149
+ end
150
+
151
+ # -- File changes (dir_tree + legend) ----------------------------------------
152
+ div id: "file-changes" do
153
+ header2 "File Changes"
154
+
155
+ legend items: [
156
+ { color: "#22c55e", label: "New" },
157
+ { color: "#f59e0b", label: "Modified" },
158
+ { color: "#ef4444", label: "Deleted" }
159
+ ]
160
+
161
+ dir_tree <<~TREE
162
+ app/
163
+ controllers/
164
+ auth_controller.rb [modified]
165
+ sessions_controller.rb [deleted]
166
+ api/
167
+ base_controller.rb [modified]
168
+ middleware/
169
+ jwt_authenticator.rb [new]
170
+ session_authenticator.rb [deleted]
171
+ models/
172
+ user.rb [modified]
173
+ refresh_token.rb [new]
174
+ services/
175
+ token_service.rb [new]
176
+ token_blacklist_service.rb [new]
177
+ config/
178
+ initializers/
179
+ jwt.rb [new]
180
+ session_store.rb [deleted]
181
+ routes.rb [modified]
182
+ spec/
183
+ services/
184
+ token_service_spec.rb [new]
185
+ token_blacklist_service_spec.rb [new]
186
+ middleware/
187
+ jwt_authenticator_spec.rb [new]
188
+ requests/
189
+ auth_spec.rb [modified]
190
+ refresh_spec.rb [new]
191
+ lib/
192
+ jwt_encoder.rb [new]
193
+ TREE
194
+ end
195
+
196
+ # -- Before / After comparison -----------------------------------------------
197
+ div id: "auth-before-after" do
198
+ header2 "Authentication Diff"
199
+
200
+ comparison(before_label: "Session Auth (before)", after_label: "JWT Auth (after)") do
201
+ before do
202
+ code_block <<~RUBY, lang: "ruby", file: "app/controllers/application_controller.rb"
203
+ class ApplicationController < ActionController::Base
204
+ before_action :require_login
205
+
206
+ private
207
+
208
+ def require_login
209
+ unless session[:user_id]
210
+ redirect_to login_path
211
+ end
212
+ end
213
+
214
+ def current_user
215
+ @current_user ||= User.find(session[:user_id])
216
+ end
217
+ end
218
+ RUBY
219
+ end
220
+
221
+ after do
222
+ code_block <<~RUBY, lang: "ruby", file: "app/controllers/api/base_controller.rb"
223
+ class Api::BaseController < ActionController::API
224
+ before_action :authenticate!
225
+
226
+ private
227
+
228
+ def authenticate!
229
+ token = extract_token(request)
230
+ payload = TokenService.decode(token)
231
+ raise JWT::DecodeError if TokenBlacklistService.revoked?(payload["jti"])
232
+ @current_user = User.find(payload["sub"])
233
+ rescue JWT::DecodeError, JWT::ExpiredSignature => e
234
+ render json: { error: "Unauthorized" }, status: :unauthorized
235
+ end
236
+
237
+ def extract_token(request)
238
+ request.headers["Authorization"]&.split(" ")&.last
239
+ end
240
+ end
241
+ RUBY
242
+ end
243
+ end
244
+ end
245
+
246
+ # -- Middleware code block ---------------------------------------------------
247
+ div id: "middleware" do
248
+ header2 "New Middleware: JWT Authenticator"
249
+
250
+ code_block <<~RUBY, lang: "ruby", file: "app/middleware/jwt_authenticator.rb"
251
+ # frozen_string_literal: true
252
+
253
+ class JwtAuthenticator
254
+ EXCLUDED_PATHS = %w[/auth/login /auth/refresh /health].freeze
255
+
256
+ def initialize(app)
257
+ @app = app
258
+ end
259
+
260
+ def call(env)
261
+ request = Rack::Request.new(env)
262
+ return @app.call(env) if skip_auth?(request.path)
263
+
264
+ token = extract_bearer_token(env)
265
+ return unauthorized_response unless token
266
+
267
+ payload = TokenService.decode(token)
268
+ return unauthorized_response unless payload
269
+ return unauthorized_response if TokenBlacklistService.revoked?(payload["jti"])
270
+
271
+ env["jwt.payload"] = payload
272
+ env["jwt.user_id"] = payload["sub"]
273
+ @app.call(env)
274
+ rescue JWT::ExpiredSignature
275
+ expired_response
276
+ rescue JWT::DecodeError
277
+ unauthorized_response
278
+ end
279
+
280
+ private
281
+
282
+ def skip_auth?(path)
283
+ EXCLUDED_PATHS.any? { |p| path.start_with?(p) }
284
+ end
285
+
286
+ def extract_bearer_token(env)
287
+ auth = env["HTTP_AUTHORIZATION"]
288
+ return nil unless auth&.start_with?("Bearer ")
289
+ auth.split(" ", 2).last
290
+ end
291
+
292
+ def unauthorized_response
293
+ [401, { "Content-Type" => "application/json" },
294
+ ['{"error":"Unauthorized","code":"invalid_token"}']]
295
+ end
296
+
297
+ def expired_response
298
+ [401, { "Content-Type" => "application/json" },
299
+ ['{"error":"Token expired","code":"token_expired"}']]
300
+ end
301
+ end
302
+ RUBY
303
+
304
+ flow_arrow label: "Token lifecycle"
305
+
306
+ code_block <<~RUBY, lang: "ruby", file: "app/services/token_service.rb", truncate: 20
307
+ # frozen_string_literal: true
308
+
309
+ class TokenService
310
+ ACCESS_TTL = 15.minutes
311
+ REFRESH_TTL = 7.days
312
+
313
+ class << self
314
+ def issue(user)
315
+ jti = SecureRandom.uuid
316
+ access_token = encode(
317
+ sub: user.id,
318
+ jti: jti,
319
+ exp: ACCESS_TTL.from_now.to_i,
320
+ roles: user.roles.pluck(:name)
321
+ )
322
+ refresh_token = RefreshToken.create!(
323
+ user: user,
324
+ token: SecureRandom.hex(32),
325
+ expires_at: REFRESH_TTL.from_now
326
+ )
327
+ { access_token: access_token, refresh_token: refresh_token.token }
328
+ end
329
+
330
+ def decode(token)
331
+ JWT.decode(token, secret_key, true, algorithm: "HS256").first
332
+ end
333
+
334
+ def revoke(jti, exp)
335
+ TokenBlacklistService.revoke(jti, ttl: exp - Time.now.to_i)
336
+ end
337
+
338
+ private
339
+
340
+ def encode(payload)
341
+ JWT.encode(payload, secret_key, "HS256")
342
+ end
343
+
344
+ def secret_key
345
+ Rails.application.credentials.jwt_secret_key
346
+ end
347
+ end
348
+ end
349
+ RUBY
350
+ end
351
+
352
+ # -- CI Pipeline visualization -----------------------------------------------
353
+ div id: "pipeline" do
354
+ header2 "CI Pipeline Status"
355
+
356
+ pipeline steps: [
357
+ { label: "Lint", description: "RuboCop + ESLint", status: :complete },
358
+ { label: "Unit Tests", description: "RSpec (412 examples)", status: :complete },
359
+ { label: "Integration", description: "Request specs + JWT flow", status: :complete },
360
+ { label: "Security Scan", description: "Brakeman + bundler-audit", status: :active },
361
+ { label: "Staging Deploy", description: "Auto-deploy to staging", status: :pending },
362
+ { label: "QA Sign-off", description: "Manual verification", status: :pending }
363
+ ]
364
+ end
365
+
366
+ # -- Callouts (all variants) -------------------------------------------------
367
+ div id: "risks" do
368
+ header2 "Risk Analysis"
369
+
370
+ callout(variant: :error, title: "Critical: Token Revocation Gap") do
371
+ md <<~MD
372
+ Access tokens remain valid for up to **15 minutes** after a user is
373
+ deactivated or their password is changed. The blacklist check mitigates
374
+ this for explicit logouts, but admin-initiated deactivation does not
375
+ currently trigger token revocation.
376
+
377
+ **Recommendation:** Add an `after_update` callback on `User` that
378
+ blacklists all active JTIs when `deactivated_at` changes.
379
+ MD
380
+ end
381
+
382
+ callout(variant: :warning, title: "Refresh Token Rotation") do
383
+ md <<~MD
384
+ The current implementation does **not** rotate refresh tokens on use.
385
+ A stolen refresh token grants persistent access for the full 7-day window.
386
+
387
+ **Recommendation:** Implement refresh token rotation -- issue a new
388
+ refresh token on each `/auth/refresh` call and invalidate the old one.
389
+ Detect token reuse as a sign of compromise and revoke the entire family.
390
+ MD
391
+ end
392
+
393
+ callout(variant: :info, title: "CORS Configuration") do
394
+ md <<~MD
395
+ The JWT-based API will be consumed by the mobile app and potentially
396
+ third-party integrations. Ensure `Access-Control-Allow-Headers` includes
397
+ `Authorization` and that the CORS origin whitelist is properly configured
398
+ in `config/initializers/cors.rb`.
399
+ MD
400
+ end
401
+
402
+ callout(variant: :success, title: "Improved Horizontal Scalability") do
403
+ md <<~MD
404
+ With session state removed from Redis, the application can now be
405
+ load-balanced across any number of instances without sticky sessions.
406
+ Token verification is purely CPU-bound (HMAC-SHA256), enabling true
407
+ stateless horizontal scaling.
408
+ MD
409
+ end
410
+
411
+ callout(variant: :tip, title: "Future Enhancement: Key Rotation") do
412
+ md <<~MD
413
+ Consider implementing JWT signing key rotation using JWK Sets (JWKS).
414
+ This enables zero-downtime key rotation and allows token verification
415
+ by external services without sharing the secret key.
416
+ MD
417
+ end
418
+ end
419
+
420
+ # -- Test breakdown chart ----------------------------------------------------
421
+ chart type: :bar, data: {
422
+ labels: [
423
+ "TokenService", "JwtAuthenticator", "AuthController",
424
+ "RefreshToken", "Blacklist", "Integration"
425
+ ],
426
+ datasets: [
427
+ {
428
+ label: "Tests Added",
429
+ data: [18, 14, 12, 8, 6, 24],
430
+ backgroundColor: "#22c55e"
431
+ },
432
+ {
433
+ label: "Tests Modified",
434
+ data: [0, 0, 8, 3, 0, 12],
435
+ backgroundColor: "#f59e0b"
436
+ },
437
+ {
438
+ label: "Tests Removed",
439
+ data: [0, 0, 6, 0, 0, 4],
440
+ backgroundColor: "#ef4444"
441
+ }
442
+ ]
443
+ }, options: {
444
+ plugins: {
445
+ title: { display: true, text: "Test Suite Changes by Component" }
446
+ },
447
+ scales: {
448
+ x: { stacked: true },
449
+ y: { stacked: true, title: { display: true, text: "Number of Tests" } }
450
+ }
451
+ }, height: 300
452
+
453
+ # -- Verdict -----------------------------------------------------------------
454
+ div id: "verdict" do
455
+ header2 "Review Verdict"
456
+
457
+ hstack spacing: :md, align: :center do
458
+ status_dot status: :yellow, pulse: true
459
+ header3 "Request Changes"
460
+ end
461
+
462
+ prose do
463
+ md <<~MARKDOWN
464
+ The architectural approach is solid and well-structured. The separation
465
+ of concerns between `TokenService`, `TokenBlacklistService`, and the
466
+ `JwtAuthenticator` middleware is clean and testable. Test coverage has
467
+ improved meaningfully.
468
+
469
+ However, **two blocking issues** must be resolved:
470
+
471
+ 1. **Token revocation on user deactivation** -- admin-initiated account
472
+ disabling must immediately invalidate all outstanding tokens.
473
+ 2. **Refresh token rotation** -- the current implementation is vulnerable
474
+ to refresh token theft without rotation and reuse detection.
475
+
476
+ Additionally, the CORS configuration should be verified in a staging
477
+ environment before merging.
478
+ MARKDOWN
479
+ end
480
+
481
+ pullquote(
482
+ "The bones are excellent. Fix the revocation gap and token rotation, and this ships.",
483
+ attribution: "AI Review Agent v2.4"
484
+ )
485
+
486
+ # -- Score summary table ---------------------------------------------------
487
+ header3 "Review Scores"
488
+ score_table scores: [
489
+ { label: "Code Quality", score: 9, max: 10 },
490
+ { label: "Test Coverage", score: 8, max: 10 },
491
+ { label: "Security Posture", score: 6, max: 10 },
492
+ { label: "Architecture", score: 9, max: 10 },
493
+ { label: "Documentation", score: 7, max: 10 },
494
+ { label: "Migration Safety", score: 7, max: 10 }
495
+ ]
496
+ end
497
+ end
498
+
499
+ ExplainerApp.run! if __FILE__ == $0
data/exe/streamweaver ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Add lib to load path for development
5
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
6
+
7
+ require 'stream_weaver'
8
+
9
+ StreamWeaver::CLI.run(ARGV)
@@ -0,0 +1,167 @@
1
+ # StreamWeaver 1.0 Roadmap — The Pareto Production Plan
2
+
3
+ Synthesized 2026-07-02 from three research inputs (all in `gsd/research/`):
4
+ `repo-audit-1.0.md` (facts on the ground), `production-patterns-research.md`
5
+ (proven minimal mechanisms from Streamlit/Rails-Solid/LiveView/Roda), and
6
+ `market-positioning-research.md` (the market moment + site/video strategy).
7
+ Tracked as beads epic `stream_weaver-b9g`.
8
+
9
+ ---
10
+
11
+ ## The Thesis
12
+
13
+ StreamWeaver's moment: the industry is standardizing on **rich HTML as the
14
+ agent-to-human surface** (Anthropic's "Unreasonable Effectiveness of HTML"
15
+ post, May 2026; the ratified MCP Apps standard, Jan 2026 — shipped in Claude,
16
+ ChatGPT, Goose, VS Code) while openly conceding the token cost. Independent
17
+ benchmarks put HTML at **4-8x markdown tokens**. StreamWeaver's claim:
18
+ **markdown-level token cost, HTML-artifact richness, real-time push**.
19
+
20
+ Positioning rule: do NOT say "10x cheaper" until we publish our own benchmark
21
+ (bench script comparing StreamWeaver DSL vs equivalent raw HTML vs markdown
22
+ for the same rendered UI). The independent 4-8x figure is citable; our own
23
+ numbers become the headline.
24
+
25
+ Canvas mode is the flagship of this story — it replaces both the Chrome-based
26
+ visual companion and token-heavy HTML artifacts with a persistent, push-driven,
27
+ interactive surface. 1.0 messaging leads with canvas, not with "Streamlit for
28
+ Ruby."
29
+
30
+ ---
31
+
32
+ ## The Four Modes (and the "where to use what" answer)
33
+
34
+ The audit confirms four legit modes plus a deployment wrapper. The 1.0 docs
35
+ must open with this table — it IS the "where to use what" doc Forrest wants:
36
+
37
+ | Mode | Reach for it when | Maturity gap for 1.0 |
38
+ |---|---|---|
39
+ | Standalone script (`ruby app.rb`) | Quick helper UI, one file, one user | None — this is done |
40
+ | Agentic (`run_once!`) | Agent needs one answer from a human | None |
41
+ | Service mode (`streamweaver run`) | Several apps, one server, lives all day | Hash URLs (fix exists, unwired) |
42
+ | Canvas push (`streamweaver panel` / `canvas-push`) | Agent pushes live UI to a human mid-session | Crash recovery, SSE replay, bridge_server specs |
43
+ | Puma-dev wrapper | Memorable `myapp.test` URLs on your Mac | Docs only |
44
+
45
+ ---
46
+
47
+ ## Tier 0 — Release Blockers (mechanical, do first)
48
+
49
+ These are why `gem install stream_weaver` doesn't work for anyone but Forrest.
50
+
51
+ 1. **Unblock the `iterm2_ruby` dependency** — it's a runtime dep pointed at
52
+ `~/work/iterm2_ruby` (Gemfile:9). Either publish `iterm2_ruby` to
53
+ rubygems.org or demote it to an optional/soft dependency (rescue
54
+ LoadError; iTerm panel features degrade gracefully). Hard blocker.
55
+ 2. **Version/changelog hygiene** — VERSION says 0.1.1, CHANGELOG has only ever
56
+ cut 0.1.0 with ~200 lines sitting in `[Unreleased]`. Cut 0.2.0 honestly,
57
+ then version toward 1.0.
58
+ 3. **CI** — no `.github/workflows/` at all. Add rspec matrix (Ruby 3.3/3.4)
59
+ + rubocop. The 2,090-example suite runs in ~5s; this is cheap insurance.
60
+ 4. **Repo hygiene** — add `dist/` to `.gitignore` (2.7MB one `git add -A` from
61
+ disaster), remove stray root `.gem` files, reconcile the tracked-but-
62
+ supposedly-ignored `docs/superpowers/` files.
63
+
64
+ ## Tier 1 — The Production 20% (the mechanisms)
65
+
66
+ Ordered by leverage-per-effort. Items 5 and 7 are the "never rewrite in
67
+ Sinatra again" fixes.
68
+
69
+ 5. **Human-readable multi-app URLs** — smallest, highest-leverage fix in the
70
+ repo. `aliased_path_for` (service.rb:186) already builds `/:source/:name`
71
+ routes; the CLI just never passes `source:` (cli.rb:123-166). Wire a slug
72
+ derived from the app's declared name (fallback: filename) into the default
73
+ `streamweaver run` path: `/apps/sales-dashboard`, hash kept as canonical
74
+ fallback. This single change revives the whole multi-app feature.
75
+ 6. **SessionStore story** — the cookie-overflow trauma is already 80% solved
76
+ (file store is default, 4KB ceiling gone). Finish it: (a) make the legacy
77
+ cookie store raise loudly on overflow instead of silently dropping keys,
78
+ (b) add a SQLite-backed store behind the same `SW_SESSION_STORE` switch as
79
+ the service-mode/multi-instance default (Rails 8 "Solid" philosophy — DB,
80
+ not Redis), (c) document the graduation path in one page.
81
+ 7. **Escape hatches** — adopt Streamlit's graduated model, stop at two:
82
+ (a) a `raw_html` / iframe component for arbitrary markup, and
83
+ (b) an `endpoint` DSL (`app.get "/webhook" { |req| ... }` style) that
84
+ registers raw Rack endpoints inside the same app — webhooks, JSON APIs,
85
+ file downloads without leaving StreamWeaver. Add multipart file-upload
86
+ support to the form layer. Skip a bidirectional custom-component protocol
87
+ until demand exists.
88
+ 8. **Canvas production hardening** — canvas is a shipped skill's dependency,
89
+ so the bar is higher: (a) persist bridge sessions to disk so a crash
90
+ doesn't lose open canvases (LiveView's "durable recipe" lesson), (b) SSE
91
+ monotonic event `id:` + `Last-Event-ID` replay + `retry:` backoff (the
92
+ classic silent-drop bug), (c) validate theme/layout wire values against
93
+ the registry, (d) a dedicated spec file for `bridge_server.rb` (1,111
94
+ lines, zero direct specs today).
95
+ 9. **Security posture for 1.0 (docs + defaults, not systems)** — keep
96
+ localhost-bind default and document it as a feature; opt-in CSRF for
97
+ auto-submit forms (Roda `route_csrf` as the model); one documented
98
+ middleware slot with a Basic Auth example; one Kamal-ready Dockerfile
99
+ example. Do not build an auth system.
100
+
101
+ ## Tier 2 — Adoption Surface (docs, site, tutorials, videos)
102
+
103
+ 10. **docs/ cleanup** — 73 files, ~9 genuinely user-facing. Archive the
104
+ planning/session logs (`docs/plans`, `docs/visual-skills`, spikes) out of
105
+ the shipping tree; delete or fix `canvas-ipc-session-summary.md`, which
106
+ actively contradicts the current architecture. Merge `llms.txt` /
107
+ `docs/for_llms.md` overlap.
108
+ 11. **Tutorial revamp** — the wired-in tutorial predates ~6 months of
109
+ features: zero coverage of canvas/panel, resource DSL, navbar, `:doc`
110
+ theme, theme_switcher, card_header. Restructure as one lesson per mode
111
+ (the four-modes table above becomes the tutorial's spine), and make it
112
+ the first-outside-tester onboarding path — their first session is the acceptance
113
+ test.
114
+ 12. **Website (charm-ruby.dev pattern)** — shallow 4-item nav; sell with
115
+ runnable code not prose; component cards grouped by function; and the
116
+ charm trick applied literally: the site's visuals ARE StreamWeaver output
117
+ (dogfood the `:doc` theme — the site is a StreamWeaver app or its static
118
+ export). Hero = the token-cost benchmark, side-by-side with the same UI
119
+ as raw HTML.
120
+ 13. **Demo videos (pareto stack)** — VHS `.tape` files for terminal demos +
121
+ Playwright 1.59 screencast for "agent pushes to canvas live" captures +
122
+ ElevenLabs voiceover + Descript assembly. Entire pipeline scriptable:
123
+ `bin/demos` regenerates every asset. Skip Remotion/asciinema for v1.
124
+ 14. **README restructure** — install-first, pitch second (current order
125
+ inverted). Keep the philosophy essay, move it below Quick Start.
126
+ 15. **Token benchmark** — small script + published table: same UI in
127
+ StreamWeaver DSL vs raw HTML vs markdown-equivalent fidelity. This is
128
+ the marketing headline AND a regression guard on DSL verbosity.
129
+ 16. **Opal directive — copyable example + docs** — the Opal mode (Phases
130
+ 2a+2b done; 2c ReactiveState and 2d Mermaid/ChartJS queued) becomes
131
+ useful at 1.0 if a newcomer can copy one polished example, modify it,
132
+ and ship — pick/finish one compelling scenario (the `dist/` demos are
133
+ the seed), document the `opal-build` workflow end to end, and cross-link
134
+ it from the four-modes table as the "client-side Ruby" option.
135
+ 17. **Opal vs React benchmark** — extends item 15 with two more axes:
136
+ (a) authoring token cost — same app written via StreamWeaver+Opal vs
137
+ idiomatic React (an LLM writes both; count tokens), and (b) library
138
+ load — bytes shipped to the browser (Opal runtime + morphdom + marked
139
+ vs react + react-dom + build-toolchain output). Together with item 15
140
+ this becomes one benchmark suite: tokens-to-author, bytes-to-load,
141
+ fidelity delivered.
142
+
143
+ ---
144
+
145
+ ## Triumvirate Check (applies to items 10-14)
146
+
147
+ | Law | Application |
148
+ |---|---|
149
+ | Matt's Law (find it, digest it) | Four-modes table opens every doc surface; shallow nav; one decision guide instead of 73 files |
150
+ | Forrest's Law (zero friction + perks) | `gem install` just works (Tier 0); memorable URLs by default (item 5); value shown not discovered — site leads with live output and the benchmark |
151
+ | Gloria's Law (design for the brain you have) | The site/docs must be as attractive as the `:doc` theme output; videos over walls of text; the want-to threshold is functional, not decorative |
152
+
153
+ ---
154
+
155
+ ## The 20% of the 20% — Buildable Immediately
156
+
157
+ In order, each independently shippable:
158
+
159
+ 1. Tier 0 complete (deps/version/CI/hygiene) → `gem install` works, 0.2.0 cut
160
+ 2. Item 5: slug URLs wired into `streamweaver run`
161
+ 3. Item 7b: `endpoint` DSL escape hatch
162
+ 4. Item 8a+8b: canvas crash recovery + SSE replay
163
+ 5. Item 11: tutorial revamp → first-outside-tester onboarding
164
+ 6. Item 15: token benchmark → unlocks honest positioning copy
165
+
166
+ Everything else (site, videos, SQLite store, CSRF) sequences behind these
167
+ without blocking them.
data/gsd/STATE.md ADDED
@@ -0,0 +1,13 @@
1
+ # Implementation State
2
+
3
+ ## Current Wave: 1
4
+ ## Status: DONE
5
+
6
+ | Task | Status | Commit | Notes |
7
+ |------|--------|--------|-------|
8
+ | T1 | DONE | 34ea6cc | Routing chain + server.rb guards |
9
+ | T2 | DONE | 65d477c | ResourceDefinition + App#resource/page/route + named-route helpers |
10
+ | T3 | DONE | 29b991e | DefaultViews + store validation + override blocks (T4 collapsed) |
11
+ | T4 | DONE | 29b991e | Collapsed into T3 — render_action save/restore implemented |
12
+ | T5 | DONE | 6a89742 | blog.rb + utf_lite.rb scaffolding examples |
13
+ | T6 | DONE | d64c861 | lib requires verified, resource-dsl.md, for_llms.md + crud-patterns.md updated |