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.
- checksums.yaml +7 -0
- data/.beads/.gitignore +77 -0
- data/.beads/README.md +81 -0
- data/.beads/config.yaml +54 -0
- data/.beads/metadata.json +7 -0
- data/.rspec +3 -0
- data/AGENTS.md +91 -0
- data/CHANGELOG.md +294 -0
- data/CLAUDE.md +67 -0
- data/LICENSE.txt +21 -0
- data/README.md +565 -0
- data/Rakefile +13 -0
- data/assets/streamweaver-hero.jpg +0 -0
- data/bench/baselines/ledger.rb +58 -0
- data/bench/baselines/warroom.rb +51 -0
- data/bench/fixtures/ledger.rb +76 -0
- data/bench/fixtures/warroom.rb +60 -0
- data/bench/results/6daf8b8.md +102 -0
- data/bench/results/c8d749b.md +102 -0
- data/bench/results/eb06ab9.md +102 -0
- data/bench/run.rb +151 -0
- data/bench/support.rb +84 -0
- data/copy_this/dto_run_sample_run_7631.html +220 -0
- data/docs/SERVICE_MODE.md +302 -0
- data/docs/architecture/how_streamweaver_works.md +772 -0
- data/docs/blog/2026-01-16-streamweaver-introduction.md +515 -0
- data/docs/bug-2026-08-31-canvas-bridge-socket-collision.md +83 -0
- data/docs/canvas-ipc-session-summary.md +127 -0
- data/docs/canvas-panel-workflow.md +172 -0
- data/docs/canvas-read.md +147 -0
- data/docs/canvas-roadmap.md +275 -0
- data/docs/case-studies/2026-09-03-didx-canvas-read-shelf.md +147 -0
- data/docs/claude-code-companion-skill-spec.md +567 -0
- data/docs/components_reference.md +1223 -0
- data/docs/crud-patterns.md +265 -0
- data/docs/endpoints.md +122 -0
- data/docs/for_llms.md +1 -0
- data/docs/form-patterns.md +165 -0
- data/docs/frontend-only.md +169 -0
- data/docs/html-artifact-audit.md +238 -0
- data/docs/ideas/2025-01-01-as-a-service.md +203 -0
- data/docs/ideas/2026-01-16-charm-tui-exploration.md +542 -0
- data/docs/ideas/2026-08-27-static-doc-shelf-export.md +153 -0
- data/docs/ideas/dhh-review-future-refactors.md +142 -0
- data/docs/opal-jamstack.md +47 -0
- data/docs/opal-npm-direction.md +184 -0
- data/docs/opal-spike-findings.md +194 -0
- data/docs/plans/2025-12-16-form-blocks-design.md +124 -0
- data/docs/plans/2025-12-30-examples-browser-design.md +152 -0
- data/docs/plans/2026-01-02-charts-design.md +288 -0
- data/docs/plans/2026-01-10-canvas-ipc-design.md +247 -0
- data/docs/plans/2026-01-19-cabinet-control-components.md +176 -0
- data/docs/plans/2026-01-26-gem-release-and-panel.md +140 -0
- data/docs/plans/canvas-claude-project-design.md +238 -0
- data/docs/plans/canvas-doc-location-and-discovery.md +32 -0
- data/docs/plans/org-doc-preview-surfaces.md +293 -0
- data/docs/plans/shadcn-polish-plan.md +417 -0
- data/docs/porting-artifacts.md +252 -0
- data/docs/reference/agent-skills-comparison.md +369 -0
- data/docs/reference/travel-state-prd.artifact.html +780 -0
- data/docs/research/2026-08-17-hotwire-alike-landscape.md +268 -0
- data/docs/research/2026-08-17-hotwire-concept-map.md +404 -0
- data/docs/research/2026-08-22-lazy-fragments-trigger-decision.md +246 -0
- data/docs/research/2026-08-22-learnhotwire-syllabus-coverage.md +239 -0
- data/docs/research/frontend-only-matrix.md +278 -0
- data/docs/research/streamweaver-way-spike-findings.md +529 -0
- data/docs/resource-dsl.md +342 -0
- data/docs/routing.md +302 -0
- data/docs/ruby-ui-comparison.md +319 -0
- data/docs/shared-dsl-fragments.md +356 -0
- data/docs/streamweaver-for-ai-agents.md +401 -0
- data/docs/streamweaver-frontend-vision.md +123 -0
- data/docs/streamweaver_canvas/glimmer_initial_final_layer.rb +77 -0
- data/docs/streamweaver_canvas/save_example.rb +9 -0
- data/docs/templates.md +213 -0
- data/docs/testing.md +155 -0
- data/docs/theming-hooks.md +281 -0
- data/docs/tutorials/the-streamweaver-way.md +882 -0
- data/docs/university/capability-inventory.md +137 -0
- data/docs/university/dependency-survey.md +114 -0
- data/docs/university/design-spec.md +217 -0
- data/docs/university/mockups/code-block-doc-theme-dark.png +0 -0
- data/docs/university/mockups/code-block-doc-theme-light.png +0 -0
- data/docs/university/mockups/course-list-dark.png +0 -0
- data/docs/university/mockups/course-list-light.png +0 -0
- data/docs/university/mockups/course_canvas_mockup.rb +741 -0
- data/docs/university/mockups/step-screen-dark.png +0 -0
- data/docs/university/mockups/step-screen-light.png +0 -0
- data/docs/university/roadmap.md +72 -0
- data/docs/university/send-to-coworker.md +77 -0
- data/docs/university/worker-session-mining.md +109 -0
- data/docs/visual/browser-rendering-spike.md +173 -0
- data/docs/visual/builder-visual-plan-analysis.md +378 -0
- data/docs/visual/sw-plan-format-exploration.md +511 -0
- data/docs/visual/sw-plan-rendering-deep-dive.md +453 -0
- data/docs/visual-skills/PROGRESS.md +60 -0
- data/docs/visual-skills/SESSION-CONTEXT.md +207 -0
- data/docs/visual-skills/analysis/components.md +317 -0
- data/docs/visual-skills/analysis/overlap.md +360 -0
- data/docs/visual-skills/analysis/pi-design-deck.md +1102 -0
- data/docs/visual-skills/analysis/streamweaver-inventory.md +93 -0
- data/docs/visual-skills/analysis/unified-specs.feature +1003 -0
- data/docs/visual-skills/analysis/visual-explainer.md +964 -0
- data/docs/visual-skills/blog/blog-series-outline.md +39 -0
- data/docs/visual-skills/blog/token-efficiency.md +73 -0
- data/docs/visual-skills/design/architecture.md +1725 -0
- data/docs/visual-skills/design/codex-review.md +340 -0
- data/docs/visual-skills/design/dhh-review.md +209 -0
- data/docs/visual-skills/design/evolution.md +100 -0
- data/docs/visual-skills/design/gemini-review.md +55 -0
- data/docs/visual-skills/design/review-synthesis.md +149 -0
- data/docs/visual-skills/implementation/STATE.md +22 -0
- data/docs/visual-skills/implementation/plan.md +347 -0
- data/docs/visual-skills/implementation/spike-findings.md +237 -0
- data/docs/visual-skills/implementation/tasks.md +702 -0
- data/docs/visual-skills/lessons-learned/process.md +145 -0
- data/examples/README.md +96 -0
- data/examples/advanced/all_components.rb +177 -0
- data/examples/advanced/examples_browser.rb +394 -0
- data/examples/advanced/teachables_browser.rb +261 -0
- data/examples/advanced/theme_tweaker.rb +366 -0
- data/examples/advanced/tutorial.rb +1528 -0
- data/examples/agentic/agentic_form.rb +30 -0
- data/examples/agentic/agentic_form_autoclose.rb +30 -0
- data/examples/agentic/cultivation_tracker.rb +69 -0
- data/examples/basic/hello_world.rb +22 -0
- data/examples/basic/opal_tabs_table.rb +44 -0
- data/examples/basic/todo_list.rb +39 -0
- data/examples/button_loading_test.rb +36 -0
- data/examples/canvas/mermaid_canvas_demo.sh +151 -0
- data/examples/charts/bar_chart_demo.rb +57 -0
- data/examples/charts/line_chart_demo.rb +73 -0
- data/examples/charts/pie_area_demo.rb +87 -0
- data/examples/charts/stacked_bar_chart_demo.rb +69 -0
- data/examples/claude_code/README.md +85 -0
- data/examples/claude_code/codebreaker/.claude/commands/infiltrate.md +632 -0
- data/examples/claude_code/codebreaker/.claude/settings.json +11 -0
- data/examples/claude_code/codebreaker/.claude/settings.local.json +17 -0
- data/examples/claude_code/codebreaker/.claude/skills/infiltrate.md +0 -0
- data/examples/claude_code/codebreaker/README.md +213 -0
- data/examples/claude_code/tutorial/.claude/commands/learn.md +453 -0
- data/examples/claude_code/tutorial/README.md +102 -0
- data/examples/claude_code/verification_flow/.claude/commands/verify.md +171 -0
- data/examples/claude_code/verification_flow/README.md +126 -0
- data/examples/components/annotated_code_demo.rb +54 -0
- data/examples/components/callout_demo.rb +33 -0
- data/examples/components/checkbox_group_demo.rb +46 -0
- data/examples/components/design_review.css +468 -0
- data/examples/components/design_review_demo.rb +44 -0
- data/examples/components/design_review_dsl.rb +300 -0
- data/examples/components/diff_block_demo.rb +112 -0
- data/examples/components/events_demo.rb +184 -0
- data/examples/components/form_demo.rb +62 -0
- data/examples/components/lesson_demo.rb +53 -0
- data/examples/components/markdown_demo.rb +110 -0
- data/examples/components/mermaid_demo.rb +166 -0
- data/examples/components/pareto_set.rb +64 -0
- data/examples/components/prd_demo.rb +21 -0
- data/examples/components/prd_dsl.rb +385 -0
- data/examples/components/quiz_demo.rb +47 -0
- data/examples/components/run_viewer_demo.rb +100 -0
- data/examples/components/score_and_collapsible_demo.rb +82 -0
- data/examples/components/select_stale_value_smoke_test.rb +39 -0
- data/examples/components/table_demo.rb +247 -0
- data/examples/components/timer_with_state_demo.rb +58 -0
- data/examples/components/todo_due_dates.rb +63 -0
- data/examples/components/uat_gaps_demo.rb +112 -0
- data/examples/dashboard/feed_simulator.rb +60 -0
- data/examples/dashboard/live_dashboard.rb +80 -0
- data/examples/dashboard_components.rb +108 -0
- data/examples/deferred_fragments_demo.rb +62 -0
- data/examples/generate_more_spike/README.md +63 -0
- data/examples/generate_more_spike/app.rb +441 -0
- data/examples/git_health.sh +401 -0
- data/examples/layout/layout_components_demo.rb +174 -0
- data/examples/layout/modal_demo.rb +215 -0
- data/examples/layout/navigation_demo.rb +227 -0
- data/examples/layout/route_tabs_demo.rb +52 -0
- data/examples/layout/routing_demo.rb +52 -0
- data/examples/layout/scroll_box_demo.rb +154 -0
- data/examples/lazy_fragments_demo.rb +151 -0
- data/examples/my_todos/README.md +29 -0
- data/examples/my_todos/my_todos.rb +312 -0
- data/examples/my_todos/store.rb +86 -0
- data/examples/opal/reactive_demo.rb +62 -0
- data/examples/opal/scenarios/s1_counter.rb +15 -0
- data/examples/opal/scenarios/s2_search_filter.rb +17 -0
- data/examples/opal/scenarios/s3_sibling_tabs.rb +25 -0
- data/examples/opal/scenarios/s4_shopping_cart.rb +34 -0
- data/examples/opal/scenarios/s5_watch.rb +39 -0
- data/examples/opal/scenarios/s6_on_start.rb +20 -0
- data/examples/opal/scenarios/s7_wizard.rb +33 -0
- data/examples/opal/scenarios/s8_loan_calculator.rb +21 -0
- data/examples/opal/scenarios/s9_dashboard.rb +27 -0
- data/examples/operations_dashboard_demo.rb +167 -0
- data/examples/panel_demo.sh +447 -0
- data/examples/parity/assets/tyrion_slice.css +86 -0
- data/examples/parity/rivet_people_slice.rb +182 -0
- data/examples/parity/tyrion_components.css +777 -0
- data/examples/parity/tyrion_warroom_components.rb +414 -0
- data/examples/parity/tyrion_warroom_slice.rb +549 -0
- data/examples/puma_dev/README.md +124 -0
- data/examples/puma_dev/config.ru +34 -0
- data/examples/puma_dev/standalone_app.rb +34 -0
- data/examples/scaffolding/blog.rb +49 -0
- data/examples/scaffolding/utf_lite.rb +105 -0
- data/examples/styling/feedback_demo.rb +229 -0
- data/examples/styling/style_showcase.rb +172 -0
- data/examples/styling/theme_demo.rb +508 -0
- data/examples/timer_health_checker.rb +111 -0
- data/examples/timer_showcase.rb +131 -0
- data/examples/tutorials/render_markdown.rb +112 -0
- data/examples/tutorials/streamweaver_way_tutorial.rb +44 -0
- data/examples/tutorials/tutorial_content.rb +1082 -0
- data/examples/visual_skills/design_deck_demo.rb +314 -0
- data/examples/visual_skills/explainer_demo.rb +499 -0
- data/exe/streamweaver +9 -0
- data/gsd/ROADMAP-1.0.md +167 -0
- data/gsd/STATE.md +13 -0
- data/gsd/research/market-positioning-research.md +139 -0
- data/gsd/research/production-patterns-research.md +270 -0
- data/gsd/research/repo-audit-1.0.md +274 -0
- data/lib/stream_weaver/action_token.rb +58 -0
- data/lib/stream_weaver/adapter/alpinejs.rb +8249 -0
- data/lib/stream_weaver/adapter/base.rb +591 -0
- data/lib/stream_weaver/adapter/opal.rb +334 -0
- data/lib/stream_weaver/adapter/static.rb +1118 -0
- data/lib/stream_weaver/admin.rb +176 -0
- data/lib/stream_weaver/app.rb +1821 -0
- data/lib/stream_weaver/assets/js/sw-copy.js +50 -0
- data/lib/stream_weaver/assets/js/sw-heredoc-rewrite.js +68 -0
- data/lib/stream_weaver/assets/js/sw-keyboard.js +165 -0
- data/lib/stream_weaver/assets/js/sw-mermaid-zoom.js +621 -0
- data/lib/stream_weaver/assets/js/sw-route-tabs.js +53 -0
- data/lib/stream_weaver/assets/js/sw-sidebar-toc.js +116 -0
- data/lib/stream_weaver/assets/js/sw-slide-nav.js +103 -0
- data/lib/stream_weaver/canvas/bridge.rb +239 -0
- data/lib/stream_weaver/canvas/bridge_server.rb +646 -0
- data/lib/stream_weaver/canvas/client.rb +298 -0
- data/lib/stream_weaver/canvas/doc_roots.rb +233 -0
- data/lib/stream_weaver/canvas/doc_store.rb +252 -0
- data/lib/stream_weaver/canvas/gist_publisher.rb +264 -0
- data/lib/stream_weaver/canvas/gist_save_handler.rb +89 -0
- data/lib/stream_weaver/canvas/gist_store.rb +135 -0
- data/lib/stream_weaver/canvas/helpers.rb +109 -0
- data/lib/stream_weaver/canvas/history.rb +90 -0
- data/lib/stream_weaver/canvas/protocol.rb +86 -0
- data/lib/stream_weaver/canvas/reader.rb +853 -0
- data/lib/stream_weaver/canvas/save_doc_widget.rb +457 -0
- data/lib/stream_weaver/canvas/scroll_top_hint.rb +21 -0
- data/lib/stream_weaver/canvas/session.rb +132 -0
- data/lib/stream_weaver/cli.rb +3235 -0
- data/lib/stream_weaver/component_assets.rb +70 -0
- data/lib/stream_weaver/component_registry.rb +67 -0
- data/lib/stream_weaver/component_renderer.rb +48 -0
- data/lib/stream_weaver/components/annotated_code.rb +53 -0
- data/lib/stream_weaver/components/api_endpoint.rb +42 -0
- data/lib/stream_weaver/components/callout.rb +59 -0
- data/lib/stream_weaver/components/chart.rb +84 -0
- data/lib/stream_weaver/components/code_block.rb +77 -0
- data/lib/stream_weaver/components/comparison.rb +39 -0
- data/lib/stream_weaver/components/decision.rb +38 -0
- data/lib/stream_weaver/components/deck/close_overlay.rb +84 -0
- data/lib/stream_weaver/components/deck/confirmation_bar.rb +60 -0
- data/lib/stream_weaver/components/deck/deck_option.rb +61 -0
- data/lib/stream_weaver/components/deck/deck_slide.rb +77 -0
- data/lib/stream_weaver/components/deck/deck_state.rb +469 -0
- data/lib/stream_weaver/components/deck/deck_summary.rb +73 -0
- data/lib/stream_weaver/components/deck/design_deck.rb +60 -0
- data/lib/stream_weaver/components/deck/generate_more_controls.rb +84 -0
- data/lib/stream_weaver/components/deck/model_selector.rb +84 -0
- data/lib/stream_weaver/components/deck/skeleton_placeholder.rb +36 -0
- data/lib/stream_weaver/components/diff_block.rb +125 -0
- data/lib/stream_weaver/components/doc_header.rb +57 -0
- data/lib/stream_weaver/components/image_block.rb +70 -0
- data/lib/stream_weaver/components/implementation_map.rb +33 -0
- data/lib/stream_weaver/components/keyboard_shortcuts.rb +94 -0
- data/lib/stream_weaver/components/kpi_dashboard.rb +78 -0
- data/lib/stream_weaver/components/mermaid.rb +79 -0
- data/lib/stream_weaver/components/pipeline.rb +63 -0
- data/lib/stream_weaver/components/sidebar_toc.rb +46 -0
- data/lib/stream_weaver/components/slide_container.rb +141 -0
- data/lib/stream_weaver/components/timeline_event.rb +58 -0
- data/lib/stream_weaver/components/wireframe.rb +29 -0
- data/lib/stream_weaver/components/wireframe_block.rb +34 -0
- data/lib/stream_weaver/components.rb +2711 -0
- data/lib/stream_weaver/css.rb +230 -0
- data/lib/stream_weaver/dev_fallback_overlay.rb +61 -0
- data/lib/stream_weaver/display_dsl.rb +1004 -0
- data/lib/stream_weaver/export/html_exporter.rb +478 -0
- data/lib/stream_weaver/feed.rb +34 -0
- data/lib/stream_weaver/feed_builder.rb +31 -0
- data/lib/stream_weaver/fonts.rb +33 -0
- data/lib/stream_weaver/interaction_runner.rb +487 -0
- data/lib/stream_weaver/iterm.rb +460 -0
- data/lib/stream_weaver/layout_registry.rb +92 -0
- data/lib/stream_weaver/opal/bridge.rb +52 -0
- data/lib/stream_weaver/opal/builder.rb +193 -0
- data/lib/stream_weaver/opal/env.rb +29 -0
- data/lib/stream_weaver/opal/reactive_state.rb +75 -0
- data/lib/stream_weaver/opal/regexp_anchor_patch.rb +62 -0
- data/lib/stream_weaver/opal/renderer.rb +77 -0
- data/lib/stream_weaver/opal/runtime.rb +250 -0
- data/lib/stream_weaver/opal/shell.rb +145 -0
- data/lib/stream_weaver/opal/string_bridge.rb +50 -0
- data/lib/stream_weaver/opal/stubs/diff.min.js +1 -0
- data/lib/stream_weaver/opal/stubs/digest.rb +15 -0
- data/lib/stream_weaver/opal/stubs/marked.umd.js +79 -0
- data/lib/stream_weaver/opal/stubs/md5.rb +3 -0
- data/lib/stream_weaver/opal/stubs/morphdom.min.js +775 -0
- data/lib/stream_weaver/opal/stubs/prism-tomorrow.min.css +1 -0
- data/lib/stream_weaver/opal/stubs/prism.min.js +1967 -0
- data/lib/stream_weaver/opal_entry.rb +136 -0
- data/lib/stream_weaver/org/inline.rb +95 -0
- data/lib/stream_weaver/org/reader.rb +561 -0
- data/lib/stream_weaver/org/recording_context.rb +86 -0
- data/lib/stream_weaver/org/source_splitter.rb +63 -0
- data/lib/stream_weaver/org/writer.rb +300 -0
- data/lib/stream_weaver/page_shell.rb +530 -0
- data/lib/stream_weaver/portfile.rb +79 -0
- data/lib/stream_weaver/pushable.rb +42 -0
- data/lib/stream_weaver/resource/default_views.rb +111 -0
- data/lib/stream_weaver/resource/field_input.rb +25 -0
- data/lib/stream_weaver/resource/state_keys.rb +16 -0
- data/lib/stream_weaver/resource/store.rb +18 -0
- data/lib/stream_weaver/resource.rb +104 -0
- data/lib/stream_weaver/server.rb +1471 -0
- data/lib/stream_weaver/service.rb +1240 -0
- data/lib/stream_weaver/service_client.rb +104 -0
- data/lib/stream_weaver/session_store.rb +186 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/SKILL.md +66 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/examples/canvas-safe-showcase.rb +98 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/actions-and-buttons.md +47 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/charts-and-diagrams.md +38 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/deck.md +32 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/inputs-and-forms.md +65 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/tabs-and-navigation.md +53 -0
- data/lib/stream_weaver/skills/streamweaver-doc-builder/SKILL.md +298 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/SKILL.md +130 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.css +468 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.rb +39 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example_dsl.rb +300 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example.rb +24 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example_dsl.rb +385 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/checkpoints-and-forms.md +28 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/cleanup-and-panel.md +44 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/example-gallery.md +8 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/persistence.md +58 -0
- data/lib/stream_weaver/skills/streamweaver-way/SKILL.md +396 -0
- data/lib/stream_weaver/skills/visual-plan/SKILL.md +201 -0
- data/lib/stream_weaver/skills/visual-recap/SKILL.md +244 -0
- data/lib/stream_weaver/streamer.rb +63 -0
- data/lib/stream_weaver/templates/choices.rb +149 -0
- data/lib/stream_weaver/templates/code.rb +157 -0
- data/lib/stream_weaver/templates/confirm.rb +110 -0
- data/lib/stream_weaver/templates/diff.rb +195 -0
- data/lib/stream_weaver/templates/info.rb +142 -0
- data/lib/stream_weaver/templates/table.rb +169 -0
- data/lib/stream_weaver/templates/wizard.rb +271 -0
- data/lib/stream_weaver/theme/auto_mode.rb +116 -0
- data/lib/stream_weaver/theme/presets.rb +555 -0
- data/lib/stream_weaver/theme.rb +639 -0
- data/lib/stream_weaver/university/canvas.rb +924 -0
- data/lib/stream_weaver/university/course.rb +699 -0
- data/lib/stream_weaver/university/demos/counter.rb +33 -0
- data/lib/stream_weaver/university/demos/dashboard.rb +147 -0
- data/lib/stream_weaver/university/demos/decision_form.rb +143 -0
- data/lib/stream_weaver/university/demos.rb +50 -0
- data/lib/stream_weaver/university/listener.rb +467 -0
- data/lib/stream_weaver/university/progress.rb +201 -0
- data/lib/stream_weaver/university/runner.rb +138 -0
- data/lib/stream_weaver/university/scripts/growing_doc.rb +609 -0
- data/lib/stream_weaver/university/scripts/growing_doc_state.rb +91 -0
- data/lib/stream_weaver/utils.rb +31 -0
- data/lib/stream_weaver/version.rb +5 -0
- data/lib/stream_weaver/views/canvas/reader_layout.erb +800 -0
- data/lib/stream_weaver/views.rb +3940 -0
- data/lib/stream_weaver.rb +122 -0
- data/llms.txt +1269 -0
- data/sig/stream_weaver.rbs +4 -0
- metadata +598 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Tabs and Navigation
|
|
2
|
+
|
|
3
|
+
## tabs (eager, default) — plays well everywhere
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
tabs :settings_tabs do
|
|
7
|
+
tab "General" do
|
|
8
|
+
text "General settings content"
|
|
9
|
+
end
|
|
10
|
+
tab "Notifications" do
|
|
11
|
+
text "Notification settings content"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Pure client-side `@click activeTab = N` — WORKS identically in A, B, and C. Variants (`variant: :enclosed`, `variant: :"soft-rounded"`) are CSS-only, no change to this. This is the form to reach for in the comprehensive example / any doc that has to survive an export.
|
|
17
|
+
|
|
18
|
+
## tabs url: true — the one component that's MORE capable off the live canvas
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
tabs :view, url: true do
|
|
22
|
+
tab "Overview" do ... end
|
|
23
|
+
tab "Details" do ... end
|
|
24
|
+
end
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
On canvas (A, B) this degrades to plain client-side tabs and logs a warning once per render — to the **agent's** stderr, never shown to the human viewing the page (`route_tabs? = component.url? && !websocket_mode?`). In an export (C), `sw-route-tabs.js` is inlined and runs real `pushState` routing, so the URL updates and the tab state survives a reload. This is intentional and informational (disc-099), not a bug — but if you're diagnosing "why does this tab set behave differently exported vs. on canvas," this is why. Not yet confirmed under `file://` — several browsers throw `SecurityError` for `pushState` on `file://` origins, so an exported doc opened directly from disk (not served over HTTP) may still break tab switching; check by hand if that's how the export will be opened.
|
|
28
|
+
|
|
29
|
+
## collapsible / expandable_card / dropdown — plays well everywhere
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
collapsible "Show Details" do
|
|
33
|
+
text "Detail content"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
expandable_card "Section" do # like collapsible, but the SERVER learns the expanded state
|
|
37
|
+
text "..."
|
|
38
|
+
end
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Pure Alpine `x-show`/`x-data`, no server dependency — WORKS in A, B, C. Use `expandable_card` over `collapsible` only if you need `state` to know whether a section is open; that's a server round-trip and inherits the sendEvent-only-on-live-canvas disposition for that specific bit of state (the panel itself still opens/closes client-side everywhere).
|
|
42
|
+
|
|
43
|
+
## modal — needs a real server, half the time
|
|
44
|
+
|
|
45
|
+
Modal *closing* is Alpine-only and works everywhere. Modal *opening* is server-state driven — on the live canvas an agent has to push the state that opens it; on canvas-read and export there's no way to open one at all (SILENTLY-DEAD). Don't build a doc where the only path to some content is "click to open a modal" if that doc needs to survive being saved and reopened later.
|
|
46
|
+
|
|
47
|
+
## route_by / route / page — needs a real server
|
|
48
|
+
|
|
49
|
+
The SSE client and routing/`popstate` scripts are `AppView`-only. Canvas (A, B) renders through `AppContentView`, export (C) through `ComponentRenderer.render_html` — neither ever gets those scripts, so `route_by` has no client at all backend-less. The initial paint shows and nothing ever updates. Out of scope for this skill's fixes; know it going in rather than debug a page that "isn't routing."
|
|
50
|
+
|
|
51
|
+
## The gotcha
|
|
52
|
+
|
|
53
|
+
Route tabs are the one component in this whole skill where "more functional off the live canvas" is correct and not a regression. Every other asymmetry in this doc runs the other direction (live canvas is the most capable context) — this is the exception, and it's easy to mistake for a bug if you don't know it's by design.
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: streamweaver-doc-builder
|
|
3
|
+
description: Use when building editorial "doc"-style StreamWeaver apps — PRDs, reports, explainers, long-form write-ups — with the :doc theme, doc_header/doc_section_header/sidebar_toc, and the shared-DSL pattern for standalone + canvas delivery
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# StreamWeaver Doc Builder
|
|
7
|
+
|
|
8
|
+
Build long-form, editorial-style documents (PRDs, reports, explainers) as StreamWeaver apps using the `:doc` theme and the document component family. Documents can be authored once as a shared DSL body and delivered two ways — standalone Ruby app or live canvas — without duplicating content.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
Use when the deliverable is a **document**, not a dashboard or a brainstorming canvas:
|
|
13
|
+
|
|
14
|
+
- A PRD, spec, or proposal that needs sections, a table of contents, callouts, and tables
|
|
15
|
+
- A report or explainer meant to be read top-to-bottom
|
|
16
|
+
- Anything you'd otherwise write as a long markdown file, but want scroll-spy navigation, styled callouts, and diagrams rendered live
|
|
17
|
+
|
|
18
|
+
Skip for: dashboards (use standard components), quick visual A/B comparisons or brainstorming (use `streamweaver-visual-companion`), pre-flight implementation plans (use `visual-plan`).
|
|
19
|
+
|
|
20
|
+
## !! DO NOT LAUNCH STANDALONE SERVERS PER QUESTION !!
|
|
21
|
+
|
|
22
|
+
Same rule as the other canvas-based skills: **never** run `ruby app.rb` or `streamweaver <file.rb>` for each content update while iterating on a doc with the user. Use `canvas-push` to update a single persistent session. Only reach for a standalone `ruby` run when you want a permanent, git-tracked app file from the start (see "Two Delivery Modes" below).
|
|
23
|
+
|
|
24
|
+
## The `:doc` Theme
|
|
25
|
+
|
|
26
|
+
`:doc` — "Compact Editorial" — is the theme for document-style apps: Charter/system-ui fonts, 15px base size, `#1E4ED8` primary blue, `#F5F4EF` background. Defined in `lib/stream_weaver/theme.rb`.
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
app "My Document Title", theme: :doc do
|
|
30
|
+
# ... doc components here
|
|
31
|
+
end
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Do not confuse this with the older `:document` theme** (serif Crimson Pro, 19px, "Reading Mode"). `:document` predates `:doc` and some older example files in this repo still reference it — for new doc-style apps, always use `theme: :doc`.
|
|
35
|
+
|
|
36
|
+
Dark mode works automatically — the `:doc` theme has a dark variant, and `theme_toggle` / auto-mode JS sets `data-sw-theme="dark"` on `<html>` for you. Don't hand-roll dark-mode styling; just use `theme: :doc` (standalone) or `--theme=doc` (canvas panel) and it's wired through, including Mermaid diagram dark-sync.
|
|
37
|
+
|
|
38
|
+
## Two Delivery Modes, One DSL Body
|
|
39
|
+
|
|
40
|
+
The core pattern: write your document content **once**, as a bare DSL body file — no `app` wrapper, just a sequence of top-level component calls. Then consume that same file two ways:
|
|
41
|
+
|
|
42
|
+
1. **Standalone app** — `instance_eval` the body inside an `app "...", theme: :doc do ... end` wrapper
|
|
43
|
+
2. **Canvas push** — pipe the body file directly to `streamweaver canvas-push <session>`
|
|
44
|
+
|
|
45
|
+
Because both modes read the exact same file, content never drifts between "the app I can `ruby run.rb`" and "the live canvas I've been iterating on with the user."
|
|
46
|
+
|
|
47
|
+
**Start every DSL body with `# streamweaver-doc: v1`.** A body is bare component calls with no `require` and no `app` wrapper, so nothing about the file says what it is — tooling that meets one out of context (a renderer pointed at a GitHub blob, an editor plugin) can't tell it from ordinary Ruby, and guessing from content is unreliable for short docs. "Save as doc" adds the line automatically; hand-written bodies need it written in. It's a comment, so it costs nothing at eval time.
|
|
48
|
+
|
|
49
|
+
Reference implementation in this repo: `examples/components/prd_dsl.rb` (body only) + `examples/components/prd_demo.rb` (standalone wrapper). Copy the shared-body/`instance_eval` structure — but note `prd_demo.rb` still says `theme: :document`, since it predates the `:doc` theme; use `theme: :doc` in new work.
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
# doc_body.rb — no `app` block, just component calls
|
|
53
|
+
# streamweaver-doc: v1
|
|
54
|
+
sidebar_toc sections: [
|
|
55
|
+
{ id: "problem", label: "Problem Statement" },
|
|
56
|
+
{ id: "architecture", label: "Architecture" }
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
doc_header(title: "My PRD", pills: [{ text: "Draft" }])
|
|
60
|
+
|
|
61
|
+
doc_section_header "01", "Problem Statement", id: "problem"
|
|
62
|
+
md "Prose goes here."
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
# doc_app.rb — standalone wrapper
|
|
67
|
+
require_relative "../../lib/stream_weaver"
|
|
68
|
+
|
|
69
|
+
DOC_BODY_PATH = File.join(__dir__, "doc_body.rb")
|
|
70
|
+
|
|
71
|
+
DocApp = app "My PRD", theme: :doc do
|
|
72
|
+
instance_eval(File.read(DOC_BODY_PATH), DOC_BODY_PATH)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
DocApp.run! if __FILE__ == $0
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Same doc_body.rb, pushed to a live canvas instead
|
|
80
|
+
streamweaver canvas-push my-doc < doc_body.rb
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Shared DSL Fragments (multi-audience docs)
|
|
84
|
+
|
|
85
|
+
When two docs for **different audiences** (a decision memo and its engineering companion, say) must quote the same tables, rules, or numbers, put those tables in ONE fragment file and load it from both bodies. Prose stays per-audience; only the facts are shared.
|
|
86
|
+
|
|
87
|
+
A fragment is a plain `.rb` under `shared/` that defines methods emitting DSL and nothing else: no `app` wrapper, no `doc_header`/`sidebar_toc`, no side effects, no `# streamweaver-doc: v1` marker. Name the methods with a doc-family prefix (`pm_base_rules_table`), because `instance_eval` turns them into singleton methods on the App and they share a namespace with every DSL verb.
|
|
88
|
+
|
|
89
|
+
Consumer snippet, top of each doc body:
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
unless respond_to?(:pm_base_rules_table)
|
|
93
|
+
_root = __dir__ || ENV["SW_DOC_DIR"] || Dir.pwd
|
|
94
|
+
_frag = File.expand_path("shared/pm_discount_shared.rb", _root)
|
|
95
|
+
raise "shared DSL fragment not found: #{_frag}" unless File.file?(_frag)
|
|
96
|
+
instance_eval(File.read(_frag), _frag)
|
|
97
|
+
end
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`export` and `canvas-read` pass the doc's path to `instance_eval`, so `__dir__` resolves the fragment there. `org-export` and the canvas-push bridge do not, so `__dir__` is `nil`: run `org-export` from the doc's directory (or set `SW_DOC_DIR`), and for canvas-push concatenate the fragment ahead of the body, which the `respond_to?` guard makes idempotent:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
cat shared/pm_discount_shared.rb my-doc.rb | streamweaver canvas-push my-doc
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Never hardcode an absolute home-directory path as a fallback. Full rationale, the per-mode `__dir__` truth table with code cites, the org-mode answers, and a proposal for a first-class `dsl_fragment` helper: `docs/shared-dsl-fragments.md` in the stream_weaver repo.
|
|
107
|
+
|
|
108
|
+
## Component Reference
|
|
109
|
+
|
|
110
|
+
### `doc_header` — title block
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
doc_header(
|
|
114
|
+
eyebrow: "Acme Corp · Internal Wiki", # optional small label above the title
|
|
115
|
+
title: "Calendar-Driven Travel State", # required
|
|
116
|
+
pills: [ # optional meta row
|
|
117
|
+
{ text: "Draft" }, # Hash -> colored pill (variant: :default/:warn/:good)
|
|
118
|
+
"June 25, 2026", # String -> plain meta text
|
|
119
|
+
"Author: Jane Doe"
|
|
120
|
+
]
|
|
121
|
+
)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `doc_section_header` — numbered section heading
|
|
125
|
+
|
|
126
|
+
```ruby
|
|
127
|
+
doc_section_header "01", "Problem Statement", id: "problem"
|
|
128
|
+
# number, title positional; id: becomes the DOM anchor id
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `sidebar_toc` — sticky scroll-spy table of contents
|
|
132
|
+
|
|
133
|
+
Call once, near the top of the doc:
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
sidebar_toc sections: [
|
|
137
|
+
{ id: "problem", label: "Problem Statement" },
|
|
138
|
+
{ id: "architecture", label: "Architecture" }
|
|
139
|
+
]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Desktop (>=1000px): sticky 170px sidebar, active section highlighted via `IntersectionObserver`. Mobile (<1000px): horizontal scrollable sticky bar at top. Each `id:` here must exactly match the `id:` on a `doc_section_header` (see Known Gotchas).
|
|
143
|
+
|
|
144
|
+
### `callout` — non-dismissible tip/warning box
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
callout(variant: :warning, title: "Root cause:") do
|
|
148
|
+
text "Explanation text here."
|
|
149
|
+
end
|
|
150
|
+
# variants: :info, :warning, :success, :error, :tip, :decision, :risk
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### `table` — data table
|
|
154
|
+
|
|
155
|
+
```ruby
|
|
156
|
+
table(
|
|
157
|
+
headers: ["Component", "Responsibility", "Owner"],
|
|
158
|
+
rows: [
|
|
159
|
+
["Enforcement", "Require calendar entry", "scheduler secretary"],
|
|
160
|
+
["Sync script", "Read calendars, write state", "launchd"]
|
|
161
|
+
]
|
|
162
|
+
)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### `card` / `card_header` / `card_body` — boxed section
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
card do
|
|
169
|
+
card_header "Component Title", badge: "C1", meta: "owner · trigger"
|
|
170
|
+
# badge: optional small tag before title; meta: optional right-aligned text
|
|
171
|
+
card_body do
|
|
172
|
+
md "Body content, supports **markdown**."
|
|
173
|
+
code_block(<<~TXT, lang: "text")
|
|
174
|
+
inline code sample
|
|
175
|
+
TXT
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### `comparison` — side-by-side before/after panels
|
|
181
|
+
|
|
182
|
+
Useful for "In Scope" / "Out of Scope" grids:
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
comparison(before_label: "In Scope", after_label: "Out of Scope") do
|
|
186
|
+
before { md "- Item 1\n- Item 2" }
|
|
187
|
+
after { md "- Excluded item" }
|
|
188
|
+
end
|
|
189
|
+
# Stacks vertically on viewports <768px.
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### `code_block` — syntax-highlighted code
|
|
193
|
+
|
|
194
|
+
```ruby
|
|
195
|
+
code_block(<<~RUBY, lang: "ruby")
|
|
196
|
+
def hello
|
|
197
|
+
puts "hi"
|
|
198
|
+
end
|
|
199
|
+
RUBY
|
|
200
|
+
# Options: file: "path/to/file.rb" (shows file header bar),
|
|
201
|
+
# truncate: N (thumbnail line limit), scroll: true/false
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### `mermaid` — diagrams (dark-mode aware)
|
|
205
|
+
|
|
206
|
+
```ruby
|
|
207
|
+
mermaid <<~MERMAID
|
|
208
|
+
graph LR
|
|
209
|
+
A["Calendar"] --> B["Sync script"] --> C["state.yaml"]
|
|
210
|
+
style A fill:#EEF2FF,stroke:#1E4ED8,color:#1E4ED8
|
|
211
|
+
MERMAID
|
|
212
|
+
# Options: zoom: true (pan/zoom controls), compact: true (reduced padding
|
|
213
|
+
# for card embedding), layout: :elk
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### `md` — prose
|
|
217
|
+
|
|
218
|
+
Use `md` for all body copy that needs bold/italic/links/lists. **`text` does not render markdown** — see Known Gotchas.
|
|
219
|
+
|
|
220
|
+
## Minimal Copy-Paste Template
|
|
221
|
+
|
|
222
|
+
A complete, runnable doc in under 30 lines. Adapt the titles/sections/content and go.
|
|
223
|
+
|
|
224
|
+
```ruby
|
|
225
|
+
require_relative "../../lib/stream_weaver"
|
|
226
|
+
|
|
227
|
+
MyDoc = app "My Report Title", theme: :doc do
|
|
228
|
+
sidebar_toc sections: [
|
|
229
|
+
{ id: "overview", label: "Overview" },
|
|
230
|
+
{ id: "findings", label: "Findings" }
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
doc_header(
|
|
234
|
+
eyebrow: "Team · Project",
|
|
235
|
+
title: "My Report Title",
|
|
236
|
+
pills: [{ text: "Draft" }, "July 2, 2026"]
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
doc_section_header "01", "Overview", id: "overview"
|
|
240
|
+
md "This report covers **what changed** and *why it matters*."
|
|
241
|
+
|
|
242
|
+
callout(variant: :info, title: "Key takeaway") do
|
|
243
|
+
text "The short version, up front."
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
doc_section_header "02", "Findings", id: "findings"
|
|
247
|
+
table(
|
|
248
|
+
headers: ["Metric", "Before", "After"],
|
|
249
|
+
rows: [["Latency", "220ms", "80ms"]]
|
|
250
|
+
)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
MyDoc.run! if __FILE__ == $0
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
To push the same content live instead of running it standalone: strip the `require_relative`/`app ... do`/`.run!` wrapper down to just the component calls (the body), and pipe it: `streamweaver canvas-push my-doc < doc_body.rb`.
|
|
257
|
+
|
|
258
|
+
## Canvas Workflow
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# 1. Open a themed canvas panel (iTerm2 split pane, or browser tab elsewhere)
|
|
262
|
+
streamweaver panel my-doc --theme=doc --fresh
|
|
263
|
+
|
|
264
|
+
# 2. Push the DSL body (same file used standalone — see shared-DSL pattern above)
|
|
265
|
+
streamweaver canvas-push my-doc < path/to/doc_body.rb
|
|
266
|
+
|
|
267
|
+
# 3. Interact — user can click, scroll, use theme_toggle if included; you can push
|
|
268
|
+
# updates to the SAME session as content evolves (re-run canvas-push with the
|
|
269
|
+
# updated body — never spin up a second session)
|
|
270
|
+
|
|
271
|
+
# 4. Save as doc — a floating 💾 "Save as doc" button sits bottom-right on the canvas.
|
|
272
|
+
# User clicks it, names the doc, and it's written to docs/streamweaver_canvas/<name>.rb
|
|
273
|
+
# — git-tracked, permanent. Don't reinvent this flow for the user; point them at the
|
|
274
|
+
# button. Fallback (only if the button isn't reachable, e.g. non-canvas context) —
|
|
275
|
+
# get <bridge-port> from `streamweaver canvas-list` output:
|
|
276
|
+
curl -sX POST "http://localhost:<bridge-port>/canvas/my-doc/save-doc" \
|
|
277
|
+
-H 'Content-Type: application/json' \
|
|
278
|
+
-d '{"name":"<doc-name>"}'
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
`--theme=doc` on `panel` renders the canvas in the `:doc` theme, dark-mode variant included — the canvas body gets class `sw-theme-doc`, and Mermaid dark-attribute sync wires through automatically.
|
|
282
|
+
|
|
283
|
+
`streamweaver canvas-read` (no args) opens a browsable viewer over `docs/streamweaver_canvas/` — saved Docs and auto-saved History, both promotable/viewable from the same UI.
|
|
284
|
+
|
|
285
|
+
Every `canvas-push` is auto-saved to history (`~/.streamweaver/history/<session>/`, 7-day cleanup, not git-tracked) regardless of whether the user ever clicks Save as doc — this is tier 1 of a two-tier persistence system. Nothing is silently lost even before an explicit save; tier 2 (Save as doc) is what makes it permanent and shared.
|
|
286
|
+
|
|
287
|
+
A saved doc is browsed later via `canvas-read` and can be run through `streamweaver export` — both with no live bridge behind them. Most doc components (`doc_header`, `sidebar_toc`, `callout`, `table`, `mermaid`, `card`) are flat or Alpine-owned and survive that fine, but before adding interactive controls (buttons, forms, chips) to a doc, check the `streamweaver-canvas-safe` skill for what plays well once the bridge is gone.
|
|
288
|
+
|
|
289
|
+
## Known Gotchas
|
|
290
|
+
|
|
291
|
+
- **`text` does not render markdown** — bold, italic, links, and lists all need `md` instead.
|
|
292
|
+
- **`spacer`/`divider` don't exist** — use `div(style: "height:Npx")` for spacing.
|
|
293
|
+
- **Don't launch a new server per update** — use `canvas-push` to update a single persistent session, not `ruby app.rb` repeatedly.
|
|
294
|
+
- **Don't assume port 4567** — StreamWeaver auto-picks a free port; read the actual URL from stdout.
|
|
295
|
+
- **Don't pass `theme: :light`** — it's unrecognized and silently falls back to `:default`. Omit `theme:` entirely, or use `theme_toggle mode: :light` if you want to force light appearance within `:doc`.
|
|
296
|
+
- **`sidebar_toc` section `id:` values must exactly match** the `id:` passed to each `doc_section_header`. A mismatch silently breaks scroll-spy highlighting — no error, it just won't highlight.
|
|
297
|
+
- **Don't hand-roll dark mode** — the `:doc` theme's dark variant and Mermaid dark-sync already work automatically in both standalone and canvas contexts. Just use `theme: :doc` / `--theme=doc`.
|
|
298
|
+
- **Don't confuse `:doc` with `:document`** — `:document` is the older serif "Reading Mode" theme; `:doc` ("Compact Editorial") is the current one to use for new document-style apps.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: streamweaver-visual-companion
|
|
3
|
+
description: Use INSTEAD OF the Artifact tool, and INSTEAD OF writing an HTML mockup and opening/screenshotting it with Chrome browser tools (claude-in-chrome, superpowers-chrome, playwright) — whenever about to show the user something visually (UI mockup, wireframe, diagram, dashboard, layout/design comparison, side-by-side options, long-form doc) and StreamWeaver is available in the project (streamweaver on PATH, or stream_weaver in the Gemfile — one command to check). Also triggers on "show me", "mock it up", "let me see the options", "push to canvas", or the urge to run `ruby app.rb`/`streamweaver <file>` per question. canvas-push is 5-7x cheaper in tokens than the chrome route, with no GEA session conflicts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# StreamWeaver Visual Companion
|
|
7
|
+
|
|
8
|
+
Replaces both the `Artifact` tool and the write-HTML-then-screenshot-via-Chrome pattern for showing things visually in a StreamWeaver project — same "show, don't tell" move, 5-7x fewer tokens, no GEA session conflicts, stays inside the terminal loop you're already running.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
Decision rule: **would the user understand this better by seeing it than reading it?**
|
|
13
|
+
|
|
14
|
+
Use for: UI mockups, architecture diagrams, layout comparisons, side-by-side design options, state machine flows.
|
|
15
|
+
Use terminal for: requirements questions, conceptual A/B text choices, tradeoff lists, anything answered in words.
|
|
16
|
+
|
|
17
|
+
Fall back to `Artifact` only when:
|
|
18
|
+
- StreamWeaver isn't installed/available in this project, or
|
|
19
|
+
- the user needs a claude.ai-hosted link that persists with no local `streamweaver` process running, or that must reach someone without this repo.
|
|
20
|
+
|
|
21
|
+
## !! DO NOT LAUNCH STANDALONE SERVERS PER QUESTION !!
|
|
22
|
+
|
|
23
|
+
**This is the most common failure mode. Read carefully.**
|
|
24
|
+
|
|
25
|
+
**NEVER** run `ruby app.rb` or `streamweaver <file.rb>` for each visual question in a conversation. This creates orphaned processes, port conflicts, and multiple browser windows. The correct approach is **canvas-push** — it updates a single persistent window throughout the conversation.
|
|
26
|
+
|
|
27
|
+
If you find yourself launching a new server for each update, stop. Use `canvas-push` instead.
|
|
28
|
+
|
|
29
|
+
## Starting a Session
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Start a named canvas session (opens browser tab automatically)
|
|
33
|
+
streamweaver panel brainstorm
|
|
34
|
+
|
|
35
|
+
# Push first content
|
|
36
|
+
streamweaver canvas-push brainstorm <<'RUBY'
|
|
37
|
+
header1 "Which layout works better?"
|
|
38
|
+
columns widths: ['50%', '50%'] do
|
|
39
|
+
column do
|
|
40
|
+
header3 "Option A — Current"
|
|
41
|
+
md "- 6 tabs"
|
|
42
|
+
md "- Scanner Tasks separate"
|
|
43
|
+
end
|
|
44
|
+
column do
|
|
45
|
+
header3 "Option B — Proposed"
|
|
46
|
+
md "- 5 tabs"
|
|
47
|
+
md "- Scanner Tasks merged into Home"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
RUBY
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Tell the user: "Take a look at [url printed by StreamWeaver] and let me know what you think in the terminal."
|
|
54
|
+
|
|
55
|
+
## Layout
|
|
56
|
+
|
|
57
|
+
Canvas sessions default to **`:fluid` (full viewport width)** — the best choice for side-by-side comparisons. Override with `--layout=` if you need a narrower centered card:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
streamweaver panel brainstorm # fluid (default, full-width)
|
|
61
|
+
streamweaver panel brainstorm --layout=default # 900px centered card
|
|
62
|
+
streamweaver panel brainstorm --layout=wide # 1100px
|
|
63
|
+
streamweaver panel brainstorm --layout=full # 1400px
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## The Loop
|
|
67
|
+
|
|
68
|
+
1. Push DSL content via `canvas-push`
|
|
69
|
+
2. Tell user what to expect, give the URL, end your turn
|
|
70
|
+
3. User responds in terminal — use their text as feedback
|
|
71
|
+
4. Push updated content or next question
|
|
72
|
+
5. Repeat until done
|
|
73
|
+
|
|
74
|
+
Blocking selection: `radio_group` + `button`, then `canvas-wait <session>` to get their click as JSON. Ending a push with more than one question? Bundle into one form instead of one round-trip each — see `references/checkpoints-and-forms.md`.
|
|
75
|
+
|
|
76
|
+
Every push auto-saves to history; the user can promote it to a permanent doc with the canvas's own Save-as-doc button (their action, never yours) — see `references/persistence.md`.
|
|
77
|
+
|
|
78
|
+
## Returning to Terminal
|
|
79
|
+
|
|
80
|
+
When the next step is text-only, push a placeholder so the user isn't staring at a resolved mockup:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
streamweaver canvas-push brainstorm <<'RUBY'
|
|
84
|
+
div(style: "display:flex;align-items:center;justify-content:center;min-height:60vh") do
|
|
85
|
+
text "Continuing in terminal..."
|
|
86
|
+
end
|
|
87
|
+
RUBY
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## DSL Quick Reference
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
header1 "Title" # h1–h6 available
|
|
94
|
+
text "Plain text" # NEVER put markdown in text — use md instead
|
|
95
|
+
md "**Bold** and *italic*" # markdown renderer
|
|
96
|
+
div(style: "height:16px") # spacing (spacer/divider not available)
|
|
97
|
+
|
|
98
|
+
columns widths: ['50%','50%'] do # side-by-side comparison
|
|
99
|
+
column { header3 "Left" }
|
|
100
|
+
column { header3 "Right" }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
card do # boxed section
|
|
104
|
+
header3 "Section"
|
|
105
|
+
text "Content"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
table headers: ["Col","Col2"], rows: [["a","b"],["c","d"]]
|
|
109
|
+
radio_group :choice, ["Option A", "Option B", "Option C"]
|
|
110
|
+
button "Select"
|
|
111
|
+
badge "New", color: :green
|
|
112
|
+
status_dot :green, "Active"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Known Gotchas
|
|
116
|
+
|
|
117
|
+
- `spacer` and `divider` don't exist — use `div(style: "height:Npx")`
|
|
118
|
+
- `theme: :light` unrecognized — omit, defaults to `:default`
|
|
119
|
+
- StreamWeaver auto-selects an available port (not always 4567) — capture the URL from stdout
|
|
120
|
+
- Canvas sessions default to `:fluid` (full-width) — use `--layout=default` if you want the 900px centered card
|
|
121
|
+
- Numbered/bulleted list items split across **separate `md()` calls don't continue** — each `md()` call is its own independent markdown block, so three calls each starting `"1. ..."` render as three separate one-item lists (all showing "1.") instead of counting up 1/2/3. Put a multi-item list in **one** `md()` call, one item per line, e.g. `md "1. First\n2. Second\n3. Third"`.
|
|
122
|
+
|
|
123
|
+
## Reference Files — Load On Demand
|
|
124
|
+
|
|
125
|
+
| Doing... | Read |
|
|
126
|
+
|---|---|
|
|
127
|
+
| Porting a claude.ai Artifact 1:1, or building a long-form doc | `references/example-gallery.md` |
|
|
128
|
+
| Ending a push with more than one question | `references/checkpoints-and-forms.md` |
|
|
129
|
+
| Saving/persisting a canvas doc, sharing DSL across two docs | `references/persistence.md` |
|
|
130
|
+
| Cleaning up orphaned processes, or how `panel` opens the browser | `references/cleanup-and-panel.md` |
|