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,102 @@
|
|
|
1
|
+
# StreamWeaver Canvas Tutorial
|
|
2
|
+
|
|
3
|
+
A conversational, freeform tutorial for learning StreamWeaver through Claude Code.
|
|
4
|
+
|
|
5
|
+
## What This Is
|
|
6
|
+
|
|
7
|
+
Unlike the standalone `tutorial.rb` (which teaches StreamWeaver components in a fixed order), this is a **conversational** tutorial where:
|
|
8
|
+
|
|
9
|
+
- You ask questions naturally in the terminal
|
|
10
|
+
- Claude explains briefly and renders examples to the canvas
|
|
11
|
+
- You iterate: "make it blue", "add more fields", "try something else"
|
|
12
|
+
- No fixed order—explore what interests you
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
cd examples/claude_code/tutorial
|
|
18
|
+
claude
|
|
19
|
+
# /learn
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## How It Works
|
|
23
|
+
|
|
24
|
+
1. **Welcome** - Canvas shows topics you can explore
|
|
25
|
+
2. **You ask** - Type questions/requests in terminal
|
|
26
|
+
3. **Claude renders** - Canvas shows both DSL code AND rendered output
|
|
27
|
+
4. **You iterate** - Modify, explore more, or finish
|
|
28
|
+
|
|
29
|
+
## Example Questions
|
|
30
|
+
|
|
31
|
+
- "Show me how text_field works"
|
|
32
|
+
- "What chart options are there?"
|
|
33
|
+
- "Make a dashboard with 3 stats"
|
|
34
|
+
- "Show me a login form"
|
|
35
|
+
- "Add validation styling to that"
|
|
36
|
+
- "Now try it with a dark theme"
|
|
37
|
+
|
|
38
|
+
## Canvas Layout
|
|
39
|
+
|
|
40
|
+
Each response shows:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
┌─────────────────────────────┐
|
|
44
|
+
│ Component: text_field │
|
|
45
|
+
├─────────────────────────────┤
|
|
46
|
+
│ DSL Code │
|
|
47
|
+
│ ```ruby │
|
|
48
|
+
│ text_field :email, ... │
|
|
49
|
+
│ ``` │
|
|
50
|
+
├─────────────────────────────┤
|
|
51
|
+
│ Rendered Output │
|
|
52
|
+
│ ┌─────────────────────────┐ │
|
|
53
|
+
│ │ Email: [____________] │ │
|
|
54
|
+
│ └─────────────────────────┘ │
|
|
55
|
+
├─────────────────────────────┤
|
|
56
|
+
│ Ask follow-up or try next │
|
|
57
|
+
└─────────────────────────────┘
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Comparison with tutorial.rb
|
|
61
|
+
|
|
62
|
+
| Feature | tutorial.rb | /learn |
|
|
63
|
+
|---------|-------------|--------|
|
|
64
|
+
| Mode | Standalone app | Claude Code canvas |
|
|
65
|
+
| Flow | Fixed sections | Freeform conversation |
|
|
66
|
+
| Learning | Self-guided | Claude-guided |
|
|
67
|
+
| Generation | Pre-built | Dynamic per question |
|
|
68
|
+
| Iteration | Playgrounds | "Make it X" requests |
|
|
69
|
+
|
|
70
|
+
Both are useful—`tutorial.rb` for comprehensive self-study, `/learn` for quick exploration with Claude.
|
|
71
|
+
|
|
72
|
+
`tutorial.rb` isn't just components anymore: it also has lessons on the four
|
|
73
|
+
run modes (standalone/agentic/service/canvas-panel), `navbar`/state routing,
|
|
74
|
+
the `resource` CRUD DSL, the `endpoint` HTTP escape hatch, and service-mode
|
|
75
|
+
slug URLs. If a `/learn` question strays into "how do I run this thing", point
|
|
76
|
+
there first.
|
|
77
|
+
|
|
78
|
+
## Topics Covered
|
|
79
|
+
|
|
80
|
+
**Components:**
|
|
81
|
+
- Forms: text_field, radio_group, checkbox, select, button
|
|
82
|
+
- Data: table, bar_chart, pie_chart, stat_display
|
|
83
|
+
- Status: status_dot, progress_bar, spinner, badge, alert
|
|
84
|
+
- Layout: card, hstack, vstack, columns, collapsible
|
|
85
|
+
|
|
86
|
+
**Patterns:**
|
|
87
|
+
- Login/signup forms
|
|
88
|
+
- Dashboards with stats
|
|
89
|
+
- Status pages
|
|
90
|
+
- Multi-step progress
|
|
91
|
+
- Data tables with charts
|
|
92
|
+
|
|
93
|
+
## Files
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
tutorial/
|
|
97
|
+
├── .claude/
|
|
98
|
+
│ ├── commands/
|
|
99
|
+
│ │ └── learn.md # Slash command instructions
|
|
100
|
+
│ └── settings.local.json # Pre-allowed permissions
|
|
101
|
+
└── README.md # This file
|
|
102
|
+
```
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Account Verification Flow
|
|
2
|
+
|
|
3
|
+
This slash command demonstrates a realistic multi-step workflow with forms, status pages, toasts, and page transitions.
|
|
4
|
+
|
|
5
|
+
## Instructions
|
|
6
|
+
|
|
7
|
+
Execute the following phases in order. Use session name `verify` throughout. Each phase waits for user interaction before proceeding.
|
|
8
|
+
|
|
9
|
+
### Phase 1: Initialize
|
|
10
|
+
|
|
11
|
+
Open the panel with a fresh session. The panel command will output a URL - **show this URL to the user** in case the browser doesn't open automatically:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
streamweaver panel verify --fresh
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
If the browser doesn't open, tell the user: "If the panel didn't open, paste this URL in your browser: [URL from output]"
|
|
18
|
+
|
|
19
|
+
### Phase 2: Sign-Up Form
|
|
20
|
+
|
|
21
|
+
Push the sign-up form:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
streamweaver canvas-push verify <<'RUBY'
|
|
25
|
+
card do
|
|
26
|
+
header1 "Create Account"
|
|
27
|
+
md "Enter your details to get started."
|
|
28
|
+
text_field :email, placeholder: "your@email.com", label: "Email"
|
|
29
|
+
text_field :name, placeholder: "Your Name", label: "Name"
|
|
30
|
+
button "Sign Up", id: "btn_signup", style: :primary
|
|
31
|
+
end
|
|
32
|
+
canvas_continue message: "Creating account..."
|
|
33
|
+
RUBY
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Wait for the user to submit:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
streamweaver canvas-wait verify
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The response will be JSON with `email` and `name` values. Store these for use in subsequent pages.
|
|
43
|
+
|
|
44
|
+
### Phase 3: Provisioning Status Page with Toast
|
|
45
|
+
|
|
46
|
+
This phase demonstrates proper toast usage: the canvas shows a **status page** (not a form) while terminal work happens. The toast alerts the user to check the terminal for permission prompts.
|
|
47
|
+
|
|
48
|
+
Push the provisioning status page (no form, no wait - just status display):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
streamweaver canvas-push verify <<'RUBY'
|
|
52
|
+
card do
|
|
53
|
+
header1 "Provisioning Account"
|
|
54
|
+
status_dot status: :yellow, pulse: true, label: "SETTING UP"
|
|
55
|
+
md "Creating your account infrastructure..."
|
|
56
|
+
md "**Step 1 of 3**: Initializing database"
|
|
57
|
+
end
|
|
58
|
+
RUBY
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Send a toast to alert the user to check the terminal:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
streamweaver canvas-toast verify "⚠️ Grant permission in terminal to continue"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Now run terminal commands (which may require permission). Update the status page as work progresses:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
echo "Initializing database for NAME_VALUE..."
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Update to step 2:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
streamweaver canvas-push verify <<'RUBY'
|
|
77
|
+
card do
|
|
78
|
+
header1 "Provisioning Account"
|
|
79
|
+
status_dot status: :yellow, pulse: true, label: "SETTING UP"
|
|
80
|
+
md "Creating your account infrastructure..."
|
|
81
|
+
md "**Step 2 of 3**: Configuring permissions"
|
|
82
|
+
end
|
|
83
|
+
RUBY
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
echo "Setting up permissions..."
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Update to step 3 complete:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
streamweaver canvas-push verify <<'RUBY'
|
|
94
|
+
card do
|
|
95
|
+
header1 "Provisioning Account"
|
|
96
|
+
status_dot status: :green, pulse: false, label: "COMPLETE"
|
|
97
|
+
md "Creating your account infrastructure..."
|
|
98
|
+
md "**Step 3 of 3**: Sending verification email ✓"
|
|
99
|
+
end
|
|
100
|
+
RUBY
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
(Replace NAME_VALUE with the actual name from Phase 2)
|
|
104
|
+
|
|
105
|
+
### Phase 4: Verification Code Page
|
|
106
|
+
|
|
107
|
+
Push the verification code page, substituting the user's email into the message:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
streamweaver canvas-push verify <<'RUBY'
|
|
111
|
+
card do
|
|
112
|
+
header1 "Verify Your Email"
|
|
113
|
+
status_dot status: :yellow, pulse: true, label: "AWAITING CODE"
|
|
114
|
+
md "We sent a 6-digit code to **EMAIL_VALUE**"
|
|
115
|
+
text_field :code, placeholder: "Enter 6-digit code", label: "Verification Code"
|
|
116
|
+
button "Verify", id: "btn_verify", style: :primary
|
|
117
|
+
end
|
|
118
|
+
canvas_continue message: "Verifying code..."
|
|
119
|
+
RUBY
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
(Replace EMAIL_VALUE with the actual email from Phase 2)
|
|
123
|
+
|
|
124
|
+
Wait for the verification:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
streamweaver canvas-wait verify
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The response will be JSON with the `code` value. After canvas-wait returns, the user sees the "Verifying code..." spinner. **Immediately push the next page** - do NOT wait again.
|
|
131
|
+
|
|
132
|
+
### Phase 5: Welcome Page
|
|
133
|
+
|
|
134
|
+
Push the welcome/success page immediately (this replaces the spinner). Substitute the user's name:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
streamweaver canvas-push verify <<'RUBY'
|
|
138
|
+
card do
|
|
139
|
+
header1 "Welcome, NAME_VALUE!"
|
|
140
|
+
badge "VERIFIED", variant: :success
|
|
141
|
+
md "Your account has been created and verified successfully."
|
|
142
|
+
md "You can now access all features."
|
|
143
|
+
end
|
|
144
|
+
RUBY
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
(Replace NAME_VALUE with the actual name from Phase 2)
|
|
148
|
+
|
|
149
|
+
**Do NOT wait here** - this is an informational page with no form. Pause briefly to let the user see the success message, then close:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
sleep 2
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Phase 6: Cleanup
|
|
156
|
+
|
|
157
|
+
Close the panel:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
streamweaver canvas-close verify
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Notes
|
|
164
|
+
|
|
165
|
+
- All commands use the session name `verify`
|
|
166
|
+
- The `--fresh` flag on panel closes any existing session first
|
|
167
|
+
- If the browser doesn't auto-open, share the URL from the panel command output with the user
|
|
168
|
+
- **Toast usage**: Toasts are for alerting users to check the terminal when their attention is on a status page. Don't use toasts on form pages where the user is already expected to interact with the canvas.
|
|
169
|
+
- `canvas-wait` returns JSON with all form field values
|
|
170
|
+
- **canvas_continue flow**: When a form uses `canvas_continue`, after `canvas-wait` returns, the user sees the spinner. You must **immediately push the next page** to replace the spinner - do NOT call `canvas-wait` again (there's nothing to wait for).
|
|
171
|
+
- **Final pages**: Informational success pages (no form) should NOT use `canvas-wait`. Just display the content briefly with `sleep`, then close.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Account Verification Flow Example
|
|
2
|
+
|
|
3
|
+
A realistic multi-step workflow demonstrating StreamWeaver's canvas capabilities: forms, status pages, toasts, and page transitions.
|
|
4
|
+
|
|
5
|
+
## The Flow
|
|
6
|
+
|
|
7
|
+
1. **Sign-Up Form** → User enters email and name
|
|
8
|
+
2. **Provisioning Status** → Canvas shows progress while terminal work runs (toast alerts user to check terminal)
|
|
9
|
+
3. **Verification Code** → User enters verification code from email
|
|
10
|
+
4. **Welcome Page** → Confirms verification, displays personalized greeting
|
|
11
|
+
|
|
12
|
+
## Key Concepts Demonstrated
|
|
13
|
+
|
|
14
|
+
### Canvas + Terminal Interplay
|
|
15
|
+
Phase 2 shows how to use canvas as a status display while Claude runs terminal commands. The toast alerts the user to check the terminal for permission prompts.
|
|
16
|
+
|
|
17
|
+
### Proper Toast Usage
|
|
18
|
+
Toasts are for alerting users to check the terminal when their attention is on a **status page**. Don't use toasts on form pages where the user is already interacting with the canvas.
|
|
19
|
+
|
|
20
|
+
### canvas_continue
|
|
21
|
+
Use `canvas_continue message: "..."` on form pages to show a spinner after submit (instead of "You can close this window").
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
cd examples/claude_code/verification_flow
|
|
27
|
+
# In Claude Code, run:
|
|
28
|
+
/verify
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Core Patterns
|
|
32
|
+
|
|
33
|
+
### Session Naming
|
|
34
|
+
|
|
35
|
+
All commands use the same session name to route to the same canvas instance:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
streamweaver panel verify --fresh # Opens canvas for session "verify"
|
|
39
|
+
streamweaver canvas-push verify <<... # Pushes content to "verify"
|
|
40
|
+
streamweaver canvas-toast verify "..." # Shows toast on "verify"
|
|
41
|
+
streamweaver canvas-wait verify # Waits for input on "verify"
|
|
42
|
+
streamweaver canvas-close verify # Closes "verify"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Heredoc Syntax for DSL
|
|
46
|
+
|
|
47
|
+
Pass Ruby DSL to canvas-push using heredocs:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
streamweaver canvas-push SESSION_NAME <<'RUBY'
|
|
51
|
+
card do
|
|
52
|
+
header1 "Title"
|
|
53
|
+
text_field :email, label: "Email"
|
|
54
|
+
button "Submit", id: "btn_submit", style: :primary
|
|
55
|
+
end
|
|
56
|
+
RUBY
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Use `<<'RUBY'` (quoted) to prevent shell variable expansion, or `<<RUBY` (unquoted) if you need shell substitution.
|
|
60
|
+
|
|
61
|
+
### Capturing Form Values
|
|
62
|
+
|
|
63
|
+
`canvas-wait` blocks until a button is clicked, then returns JSON with all field values:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
$ streamweaver canvas-wait verify
|
|
67
|
+
{"type":"action","button":"btn_sign_up_1","state":{"email":"user@example.com","name":"Jane Doe"}}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The `state` object contains all text field values keyed by their symbol names (`:email` → `"email"`).
|
|
71
|
+
|
|
72
|
+
### Variable Substitution Between Pages
|
|
73
|
+
|
|
74
|
+
Capture values from one page and substitute into the next:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Page 1: Capture user input
|
|
78
|
+
RESULT=$(streamweaver canvas-wait verify)
|
|
79
|
+
EMAIL=$(echo $RESULT | jq -r '.state.email')
|
|
80
|
+
NAME=$(echo $RESULT | jq -r '.state.name')
|
|
81
|
+
|
|
82
|
+
# Page 2: Use captured values
|
|
83
|
+
streamweaver canvas-push verify <<RUBY
|
|
84
|
+
card do
|
|
85
|
+
header1 "Welcome, $NAME!"
|
|
86
|
+
md "We sent a code to **$EMAIL**"
|
|
87
|
+
end
|
|
88
|
+
RUBY
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### URL Fallback
|
|
92
|
+
|
|
93
|
+
The panel command outputs a URL in case the browser doesn't auto-open:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
$ streamweaver panel verify --fresh
|
|
97
|
+
Canvas 'verify' ready
|
|
98
|
+
Browser opened in split pane
|
|
99
|
+
|
|
100
|
+
URL (if browser didn't open): http://localhost:4570/canvas/verify
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Share this URL with users if the browser pane doesn't appear.
|
|
104
|
+
|
|
105
|
+
## Features Demonstrated
|
|
106
|
+
|
|
107
|
+
| Feature | Command | Purpose |
|
|
108
|
+
|---------|---------|---------|
|
|
109
|
+
| Fresh start | `panel --fresh` | Open panel, close existing session first |
|
|
110
|
+
| Form pages | `canvas-push` | Display forms with text fields and buttons |
|
|
111
|
+
| Status pages | `canvas-push` | Display progress while work happens |
|
|
112
|
+
| Notifications | `canvas-toast` | Alert user to check terminal |
|
|
113
|
+
| User input | `canvas-wait` | Block until button click, capture field values |
|
|
114
|
+
| Spinner feedback | `canvas_continue` | Show spinner after form submit |
|
|
115
|
+
| Cleanup | `canvas-close` | Close panel and browser pane |
|
|
116
|
+
|
|
117
|
+
## DSL Components Used
|
|
118
|
+
|
|
119
|
+
- `card` - Container for content
|
|
120
|
+
- `header1` - Page titles
|
|
121
|
+
- `md` - Markdown text with dynamic substitution
|
|
122
|
+
- `text_field` - Form inputs with labels and placeholders
|
|
123
|
+
- `button` - Actions with primary styling
|
|
124
|
+
- `status_dot` - Visual status indicator (yellow pulsing, green complete)
|
|
125
|
+
- `badge` - Success/status badges
|
|
126
|
+
- `canvas_continue` - Spinner feedback for multi-step flows
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Usage: streamweaver canvas-push <session> < examples/components/annotated_code_demo.rb
|
|
2
|
+
# Or: streamweaver panel annotated-code-demo && streamweaver canvas-push annotated-code-demo < examples/components/annotated_code_demo.rb
|
|
3
|
+
|
|
4
|
+
header2 "AnnotatedCode — Line-Pinned Annotations"
|
|
5
|
+
md "Code block with a side panel of annotation bubbles aligned to specific lines. Annotated lines get a left-border highlight."
|
|
6
|
+
|
|
7
|
+
annotated_code(language: "ruby", annotations: [
|
|
8
|
+
{ line: 2, note: "keyword_init: true means Annotation.new(line:, note:) works" },
|
|
9
|
+
{ line: 5, note: "Memoized — built once on first access, reused on every render call" },
|
|
10
|
+
{ line: 6, note: "Set membership test is O(1); Array#include? would be O(n) per line" }
|
|
11
|
+
]) do
|
|
12
|
+
<<~'RUBY'
|
|
13
|
+
class AnnotatedCode < Base
|
|
14
|
+
Annotation = Struct.new(:line, :note, keyword_init: true)
|
|
15
|
+
|
|
16
|
+
def annotated_lines
|
|
17
|
+
@annotated_lines ||= Set.new(annotations.map(&:line))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
RUBY
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
header3 "Multiple annotations close together"
|
|
24
|
+
md "Annotations at adjacent lines stack without overlap — each gets its own `min-height` slot."
|
|
25
|
+
|
|
26
|
+
annotated_code(language: "javascript", annotations: [
|
|
27
|
+
{ line: 1, note: "Arrow function — implicit return when body is an expression" },
|
|
28
|
+
{ line: 2, note: "Destructuring with default: name falls back to 'World'" },
|
|
29
|
+
{ line: 3, note: "Template literal — backtick syntax, \#{} interpolation" }
|
|
30
|
+
]) do
|
|
31
|
+
<<~'JS'
|
|
32
|
+
const greet = (opts) => {
|
|
33
|
+
const { name = 'World' } = opts;
|
|
34
|
+
return `Hello, ${name}!`;
|
|
35
|
+
};
|
|
36
|
+
JS
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
header3 "No language specified"
|
|
40
|
+
md "Falls back to `language-none` (no Prism highlighting) — useful for plain text or pseudocode."
|
|
41
|
+
|
|
42
|
+
annotated_code(annotations: [
|
|
43
|
+
{ line: 1, note: "Start: O(1) stack push" },
|
|
44
|
+
{ line: 3, note: "Each node visited once — O(n) total" },
|
|
45
|
+
{ line: 5, note: "Stack empty → all reachable nodes visited" }
|
|
46
|
+
]) do
|
|
47
|
+
<<~'TEXT'
|
|
48
|
+
push start node onto stack
|
|
49
|
+
while stack is not empty:
|
|
50
|
+
node = stack.pop
|
|
51
|
+
for each unvisited neighbor:
|
|
52
|
+
push neighbor
|
|
53
|
+
TEXT
|
|
54
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Usage: streamweaver canvas-push <session> < examples/components/callout_demo.rb
|
|
2
|
+
# Or: streamweaver panel callout-demo && streamweaver canvas-push callout-demo < examples/components/callout_demo.rb
|
|
3
|
+
|
|
4
|
+
header2 "Callout Variants"
|
|
5
|
+
md "All seven tone variants — the last two (`:decision` and `:risk`) are new."
|
|
6
|
+
|
|
7
|
+
callout(variant: :info, title: "Info") do
|
|
8
|
+
text "General information. Use for context or background knowledge."
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
callout(variant: :warning, title: "Warning") do
|
|
12
|
+
text "Something needs attention but is not a blocker."
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
callout(variant: :success, title: "Success") do
|
|
16
|
+
text "An operation completed successfully."
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
callout(variant: :error, title: "Error") do
|
|
20
|
+
text "Something went wrong. Action required."
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
callout(variant: :tip, title: "Tip") do
|
|
24
|
+
text "A helpful hint or shortcut worth knowing."
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
callout(variant: :decision, title: "Decision — Guest session storage") do
|
|
28
|
+
text "Chosen approach: opaque token stored in DB. Stateless JWT was rejected because we need revocability for account merges. Hard to reverse — commit before implementing."
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
callout(variant: :risk, title: "Risk — Session expiry") do
|
|
32
|
+
text "Guest sessions must expire. Proposed TTL: 24h. Missing this causes unbounded DB growth. Verify the cleanup job runs before shipping."
|
|
33
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative '../../lib/stream_weaver'
|
|
5
|
+
|
|
6
|
+
# Sample email data
|
|
7
|
+
EMAILS = [
|
|
8
|
+
{ id: "email_1", from: "newsletter@techcrunch.com", subject: "Your Daily Tech Digest - AI News", date: "Jan 25, 10:32am" },
|
|
9
|
+
{ id: "email_2", from: "deals@retailer.com", subject: "Flash Sale: 50% Off Everything!", date: "Jan 25, 9:15am" },
|
|
10
|
+
{ id: "email_3", from: "no-reply@service.com", subject: "Your monthly statement is ready", date: "Jan 25, 8:45am" },
|
|
11
|
+
{ id: "email_4", from: "updates@social.com", subject: "You have 5 new notifications", date: "Jan 24, 4:30pm" },
|
|
12
|
+
{ id: "email_5", from: "support@vendor.com", subject: "Your ticket has been resolved", date: "Jan 24, 2:15pm" }
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
App = app "Spam Triage" do
|
|
16
|
+
header "Spam Triage - #{EMAILS.length} emails to review"
|
|
17
|
+
|
|
18
|
+
checkbox_group :selected_emails, select_all: "Select All", select_none: "Clear Selection" do
|
|
19
|
+
EMAILS.each do |email|
|
|
20
|
+
item email[:id] do
|
|
21
|
+
div class: "email-row" do
|
|
22
|
+
text "#{email[:from]} #{email[:date]}"
|
|
23
|
+
text email[:subject]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Show selected count
|
|
30
|
+
selected = state[:selected_emails] || []
|
|
31
|
+
if selected.any?
|
|
32
|
+
text "#{selected.length} email(s) selected"
|
|
33
|
+
|
|
34
|
+
button "Delete Selected", style: :secondary do |s|
|
|
35
|
+
# In a real app, you'd delete the emails here
|
|
36
|
+
s[:deleted] = s[:selected_emails].dup
|
|
37
|
+
s[:selected_emails] = []
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
if state[:deleted]&.any?
|
|
42
|
+
text "Deleted #{state[:deleted].length} email(s): #{state[:deleted].join(', ')}"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
App.run! if __FILE__ == $0
|