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,145 @@
|
|
|
1
|
+
# Lessons Learned — Visual Skills Development Process
|
|
2
|
+
|
|
3
|
+
## Meta: This Document
|
|
4
|
+
This captures the process of porting pi-design-deck and visual-explainer into
|
|
5
|
+
StreamWeaver, with the goal of extracting a repeatable skill for
|
|
6
|
+
"analyze N reference projects → design unified solution → implement via subagents."
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Phase 1: Setup & Analysis
|
|
11
|
+
|
|
12
|
+
### Lesson 1: Clone reference repos locally
|
|
13
|
+
**What:** Git clone both projects into the parent workspace so subagents can
|
|
14
|
+
read all source files without web fetch rate limits or API constraints.
|
|
15
|
+
**Why:** WebFetch hit 429 rate limits on the first attempt. Local files are instant
|
|
16
|
+
and unlimited. Subagents need to read *every* file, not just READMEs.
|
|
17
|
+
**Skill extraction:** Any "port from reference" workflow should start with local clones.
|
|
18
|
+
|
|
19
|
+
### Lesson 2: Parallel deep-analysis with shared template
|
|
20
|
+
**What:** Launch one subagent per reference project with identical analysis
|
|
21
|
+
structure (Intent → Features → Architecture → UX → Gherkin → Token Cost).
|
|
22
|
+
**Why:** Consistent output format enables mechanical overlap detection in the next
|
|
23
|
+
phase. If agent A uses one taxonomy and agent B uses another, the diff is noise.
|
|
24
|
+
**Skill extraction:** The analysis template IS the skill's core IP. Standardize it.
|
|
25
|
+
|
|
26
|
+
### Lesson 3: Gherkin as the bridge format
|
|
27
|
+
**What:** Have analysis agents write cucumber/Gherkin scenarios capturing all
|
|
28
|
+
user-facing behavior.
|
|
29
|
+
**Why:** Gherkin is:
|
|
30
|
+
- Precise enough for implementation
|
|
31
|
+
- Readable enough for design review
|
|
32
|
+
- Diff-friendly for overlap analysis
|
|
33
|
+
- Model-friendly (LLMs handle it well)
|
|
34
|
+
- Testable (can become actual integration tests)
|
|
35
|
+
**Skill extraction:** Always produce Gherkin as intermediate artifact.
|
|
36
|
+
|
|
37
|
+
### Lesson 4: Research the orchestration pattern BEFORE designing implementation
|
|
38
|
+
**What:** Researched GSD's ralph-loop / subagent orchestration pattern up front.
|
|
39
|
+
**Why:** The implementation approach (how to break work into subagent-sized chunks)
|
|
40
|
+
constrains the design (how modular the architecture needs to be). Knowing we'll
|
|
41
|
+
use context-sharded subagents means the design MUST be decomposable into
|
|
42
|
+
independently-implementable units.
|
|
43
|
+
**Key GSD insights:**
|
|
44
|
+
- **Context sharding**: Each task gets fresh 200k context, reads specs from files
|
|
45
|
+
- **Atomic tasks**: 2-3 tasks per plan, each fitting ~50% of context window
|
|
46
|
+
- **File-tracked state**: PLAN.md, STATE.md, REQUIREMENTS.md are the handoff
|
|
47
|
+
- **Immediate commits**: Each task commits independently → git bisect works
|
|
48
|
+
- **Orchestrator stays lean**: Main thread only tracks task completion, not implementation
|
|
49
|
+
|
|
50
|
+
### Lesson 5: Track evolution, not just final state
|
|
51
|
+
**What:** Maintain PROGRESS.md with running log, design evolution history,
|
|
52
|
+
and decision rationale at every step.
|
|
53
|
+
**Why:** Future LLMs advancing this work need to understand *why* decisions were made,
|
|
54
|
+
not just what was decided. A design doc without history is a puzzle without context.
|
|
55
|
+
**Skill extraction:** Every phase produces a dated log entry.
|
|
56
|
+
|
|
57
|
+
### Lesson 6: Multi-model vetting before implementation
|
|
58
|
+
**What:** User wants to vet progression/plans with other models before implementing.
|
|
59
|
+
**Why:** Different models catch different things. Codex for second opinions, DHH
|
|
60
|
+
reviewer for Ruby idiom quality, possibly Gemini for a third perspective.
|
|
61
|
+
**Skill extraction:** Build review gates into the process.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Phase 2: Overlap Analysis
|
|
66
|
+
|
|
67
|
+
### Lesson 7: User's intuition was validated by data
|
|
68
|
+
**What:** User predicted ~1/3 code overlap. Analysis yielded 37%.
|
|
69
|
+
**Why this matters:** Domain experts have good intuitions. The analysis doesn't replace intuition — it validates and refines it. If the number had been 15% or 60%, the architecture would change significantly.
|
|
70
|
+
**Skill extraction:** Always ask the user for their hypothesis before running analysis. It calibrates expectations and highlights surprises.
|
|
71
|
+
|
|
72
|
+
### Lesson 8: Asymmetric token savings reveal architectural insight
|
|
73
|
+
**What:** Design deck saves 30-45% (already uses structured JSON). Visual explainer saves 80-85% (reads 30K tokens of reference material per invocation).
|
|
74
|
+
**Why this matters:** The savings aren't uniform. The biggest win comes from moving the design system FROM the prompt INTO the framework. This is an architectural argument, not just an optimization.
|
|
75
|
+
**Skill extraction:** Token cost analysis should be a required section in every analysis. It reveals where the real value is.
|
|
76
|
+
|
|
77
|
+
### Lesson 9: Blog material emerges from process, don't reconstruct later
|
|
78
|
+
**What:** User identified 4 blog posts from the process mid-stream.
|
|
79
|
+
**Why this matters:** The process IS content. Waiting until the end means losing the "in the moment" insights.
|
|
80
|
+
**Skill extraction:** Add "blog-worthy observations" as a running section in the progress doc.
|
|
81
|
+
|
|
82
|
+
## Phase 3: Design
|
|
83
|
+
|
|
84
|
+
### Lesson 10: Parallel reviews catch different things
|
|
85
|
+
**What:** DHH reviewer focused on Ruby idiom/simplicity. Codex focused on edge cases/scalability. Gemini found a race condition and proposed a better architecture for generate-more (push-to-state).
|
|
86
|
+
**Why:** Each model has different strengths. DHH caught over-engineering. Codex caught missing failure modes. Gemini caught a race condition and offered a structural improvement. No single review found everything.
|
|
87
|
+
**Skill extraction:** Always run at least 2 reviews from different angles. Consider: idiom/simplicity, edge cases/scaling, adversarial/what-if.
|
|
88
|
+
|
|
89
|
+
### Lesson 11: "Adversarial perspective" prompt yields best insights
|
|
90
|
+
**What:** Telling Gemini "I've had two favorable reviews, I need the adversarial perspective" produced the session's best architectural insight (push-to-state).
|
|
91
|
+
**Why:** Favorable reviews confirm the design but don't improve it. Adversarial reviews find the improvements. Explicitly requesting adversarial framing overcomes the model's tendency to be agreeable.
|
|
92
|
+
**Skill extraction:** Third review should always request adversarial/contrarian angle.
|
|
93
|
+
|
|
94
|
+
### Lesson 12: Save a SESSION-CONTEXT.md before compaction
|
|
95
|
+
**What:** Before context window fills, write a comprehensive recovery document listing all artifacts, key decisions, current status, and next steps.
|
|
96
|
+
**Why:** Context compaction loses nuance. The recovery doc is the insurance policy. Future sessions read it first to rebuild working context.
|
|
97
|
+
**Skill extraction:** Add "pre-compaction checkpoint" to the process template.
|
|
98
|
+
|
|
99
|
+
## Phase 4: Implementation
|
|
100
|
+
_To be filled as we progress_
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Process Anti-Patterns Observed
|
|
105
|
+
_Running list of things that didn't work_
|
|
106
|
+
|
|
107
|
+
1. WebFetch for GitHub READMEs — rate limited quickly. Use `gh api` + base64 decode instead.
|
|
108
|
+
2. WebFetch for GitHub READMEs — rate limited quickly. Use `gh api` + base64 decode instead.
|
|
109
|
+
3. **Token cost asymmetry reveals the real value proposition.** pi-design-deck saves 30-45% (already somewhat efficient with JSON), but visual-explainer saves 80-85% because it reads ~30K tokens of reference material per invocation. The design system living in framework code (0 prompt tokens) vs in the prompt is the killer advantage. This should be the lead of the blog post.
|
|
110
|
+
4. **Subagent analysis cost is reasonable.** Each deep analysis used ~140-150K tokens and took 5-6 minutes. The output quality (exhaustive feature inventories, Gherkin scenarios, token cost estimates, porting recommendations) would have consumed far more main-thread context if done inline. Good tradeoff.
|
|
111
|
+
5. **Analysis template should request architecture recommendations.** Both agents provided excellent "what maps directly / needs rearchitecting / can be dropped" sections. This wasn't in the original template but emerged organically. Add it to the skill template.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Skill Template (Draft)
|
|
116
|
+
When this process is complete, the repeatable skill should look like:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
/port-from-reference <repo1> <repo2> [--target <our-project>]
|
|
120
|
+
|
|
121
|
+
Phase 1: Clone & Analyze (parallel subagents)
|
|
122
|
+
→ analysis/<project>.md with standardized sections + Gherkin
|
|
123
|
+
|
|
124
|
+
Phase 2: Overlap Analysis (single agent)
|
|
125
|
+
→ overlap.md with shared/unique feature matrix
|
|
126
|
+
→ unified-specs.feature
|
|
127
|
+
|
|
128
|
+
Phase 3: Design (main thread + review agents)
|
|
129
|
+
→ architecture.md
|
|
130
|
+
→ codex-review.md, dhh-review.md
|
|
131
|
+
→ evolution.md
|
|
132
|
+
|
|
133
|
+
Phase 4: Implementation Planning
|
|
134
|
+
→ GSD-style task breakdown
|
|
135
|
+
→ Each task: scope, input files, output files, acceptance criteria
|
|
136
|
+
|
|
137
|
+
Phase 5: Implementation (ralph-loop subagents)
|
|
138
|
+
→ One subagent per task, fresh context, reads specs from disk
|
|
139
|
+
→ Atomic commits per task
|
|
140
|
+
|
|
141
|
+
Phase 6: Verification & Documentation
|
|
142
|
+
→ Run Gherkin scenarios
|
|
143
|
+
→ Blog post / docs
|
|
144
|
+
→ Updated lessons-learned
|
|
145
|
+
```
|
data/examples/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# StreamWeaver Examples
|
|
2
|
+
|
|
3
|
+
## Directory Structure
|
|
4
|
+
|
|
5
|
+
### [basic/](basic/)
|
|
6
|
+
Simple getting-started examples. Hello world, forms, basic layouts.
|
|
7
|
+
|
|
8
|
+
### [components/](components/)
|
|
9
|
+
Individual component showcases. Each file demonstrates a specific component's options and styling.
|
|
10
|
+
|
|
11
|
+
### [layout/](layout/)
|
|
12
|
+
Layout patterns: columns, grids, cards, collapsibles.
|
|
13
|
+
|
|
14
|
+
### [styling/](styling/)
|
|
15
|
+
Theme and styling examples: dark mode, custom CSS, color schemes.
|
|
16
|
+
|
|
17
|
+
### [charts/](charts/)
|
|
18
|
+
Chart components: bar charts, pie charts, stat displays.
|
|
19
|
+
|
|
20
|
+
### [advanced/](advanced/)
|
|
21
|
+
Complex patterns: multi-step wizards, dashboards, tables with sorting.
|
|
22
|
+
|
|
23
|
+
### [agentic/](agentic/)
|
|
24
|
+
Interactive workflows with user input and state management.
|
|
25
|
+
|
|
26
|
+
### [claude_code/](claude_code/)
|
|
27
|
+
**Claude Code slash command integrations**. Interactive canvas workflows powered by Claude Code. See [claude_code/README.md](claude_code/README.md).
|
|
28
|
+
|
|
29
|
+
## Live Streaming Examples
|
|
30
|
+
|
|
31
|
+
### timer_showcase.rb
|
|
32
|
+
Dev Machine Monitor — live CPU, Memory, and Disk metrics updated every few seconds. Demonstrates `every` timers, `add_class`/`remove_class` for spotlight effects, and `prepend` for an alert feed.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bundle exec ruby examples/timer_showcase.rb
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### timer_health_checker.rb
|
|
39
|
+
Endpoint Health Checker — pings GitHub, RubyGems, and Httpbin every 5 seconds, showing response times, SLA badges, and ring effects on degraded endpoints.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bundle exec ruby examples/timer_health_checker.rb
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Standalone Scripts
|
|
46
|
+
|
|
47
|
+
### panel_demo.sh
|
|
48
|
+
Multi-step workflow demonstrating StreamWeaver's visual capabilities:
|
|
49
|
+
- Syntax-highlighted code diffs
|
|
50
|
+
- Animated progress indicators
|
|
51
|
+
- Interactive charts and tables
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
./examples/panel_demo.sh
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### git_health.sh
|
|
58
|
+
Git repository health analyzer with dynamic canvas dashboard:
|
|
59
|
+
- Real git data analysis
|
|
60
|
+
- File structure visualization
|
|
61
|
+
- Contributor stats
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
./examples/git_health.sh [path-to-repo]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### dashboard_components.rb
|
|
68
|
+
Component showcase for operations dashboards.
|
|
69
|
+
|
|
70
|
+
### operations_dashboard_demo.rb
|
|
71
|
+
Full operations dashboard example with dark theme.
|
|
72
|
+
|
|
73
|
+
## Running Examples
|
|
74
|
+
|
|
75
|
+
### Ruby Files
|
|
76
|
+
```bash
|
|
77
|
+
streamweaver examples/basic/hello_world.rb
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Shell Scripts
|
|
81
|
+
```bash
|
|
82
|
+
./examples/panel_demo.sh
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Claude Code Slash Commands
|
|
86
|
+
```bash
|
|
87
|
+
cd examples/claude_code/codebreaker
|
|
88
|
+
claude
|
|
89
|
+
# /infiltrate
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Documentation
|
|
93
|
+
|
|
94
|
+
- [Canvas Panel Workflow](../docs/canvas-panel-workflow.md) - Two-way IPC for Claude Code
|
|
95
|
+
- [Components Reference](../docs/components_reference.md) - All DSL components
|
|
96
|
+
- [How StreamWeaver Works](../docs/architecture/how_streamweaver_works.md) - Architecture overview
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative '../../lib/stream_weaver'
|
|
5
|
+
|
|
6
|
+
# Demo of all StreamWeaver components
|
|
7
|
+
App = app "Component Showcase" do
|
|
8
|
+
header "StreamWeaver Component Showcase"
|
|
9
|
+
|
|
10
|
+
# --- Text Components ---
|
|
11
|
+
header3 "Text (Literal)"
|
|
12
|
+
text "Plain text renders literally - **asterisks** stay as asterisks"
|
|
13
|
+
|
|
14
|
+
header3 "Markdown (Parsed)"
|
|
15
|
+
md "**Bold**, *italic*, `code`, and [links](https://example.com) are parsed"
|
|
16
|
+
|
|
17
|
+
header3 "Headers"
|
|
18
|
+
text "header (h2 default), header1-header6 for explicit levels"
|
|
19
|
+
|
|
20
|
+
# --- Form Components ---
|
|
21
|
+
header3 "Text Field"
|
|
22
|
+
text_field :username, placeholder: "Enter username"
|
|
23
|
+
|
|
24
|
+
header3 "Text Area"
|
|
25
|
+
text_area :bio, placeholder: "Enter bio", rows: 3
|
|
26
|
+
|
|
27
|
+
header3 "Checkbox"
|
|
28
|
+
checkbox :enabled, "Enable feature"
|
|
29
|
+
|
|
30
|
+
header3 "Select Dropdown (with default)"
|
|
31
|
+
select :color, ["Red", "Green", "Blue", "Yellow"], default: "Green"
|
|
32
|
+
|
|
33
|
+
header3 "Radio Group"
|
|
34
|
+
radio_group :size, ["Small", "Medium", "Large"]
|
|
35
|
+
|
|
36
|
+
header3 "Checkbox Group (Multi-Select)"
|
|
37
|
+
checkbox_group :selected_items, select_all: "Select All", select_none: "Clear" do
|
|
38
|
+
item "item_1" do
|
|
39
|
+
text "First item"
|
|
40
|
+
end
|
|
41
|
+
item "item_2" do
|
|
42
|
+
text "Second item"
|
|
43
|
+
end
|
|
44
|
+
item "item_3" do
|
|
45
|
+
text "Third item"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# --- Layout Components ---
|
|
50
|
+
header3 "Div Container"
|
|
51
|
+
div class: "todo-item" do
|
|
52
|
+
text "This is inside a div container"
|
|
53
|
+
text "Multiple components can be nested"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
header3 "Card"
|
|
57
|
+
card do
|
|
58
|
+
text "Cards provide styled containers"
|
|
59
|
+
text "Great for grouping related content"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
header3 "Columns (Monica-style sidebar layout)"
|
|
63
|
+
columns widths: ['30%', '70%'] do
|
|
64
|
+
column class: "sidebar-facts" do
|
|
65
|
+
div class: "sidebar-section" do
|
|
66
|
+
header4 "Work"
|
|
67
|
+
text "Software Engineer at Acme Corp"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
div class: "sidebar-section" do
|
|
71
|
+
header4 "Location"
|
|
72
|
+
text "San Francisco, CA"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
div class: "sidebar-section" do
|
|
76
|
+
header4 "Contact"
|
|
77
|
+
text "email@example.com"
|
|
78
|
+
text "(555) 123-4567"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
div class: "sidebar-section" do
|
|
82
|
+
header4 "Significant Other"
|
|
83
|
+
text "Jane Doe"
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
column do
|
|
88
|
+
collapsible "Background", expanded: true do
|
|
89
|
+
md "This person has been working in tech for **10 years** and specializes in Ruby development."
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
collapsible "Key Facts" do
|
|
93
|
+
md "- Met at RubyConf 2023\n- Interested in open source\n- Coffee enthusiast"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
header3 "Equal-width Columns"
|
|
99
|
+
columns do
|
|
100
|
+
column do
|
|
101
|
+
card do
|
|
102
|
+
text "Column 1"
|
|
103
|
+
text "Equal width flex"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
column do
|
|
107
|
+
card do
|
|
108
|
+
text "Column 2"
|
|
109
|
+
text "Also equal width"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
column do
|
|
113
|
+
card do
|
|
114
|
+
text "Column 3"
|
|
115
|
+
text "Three columns!"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# --- Interactive Components ---
|
|
121
|
+
header3 "Buttons"
|
|
122
|
+
button "Primary Action" do |state|
|
|
123
|
+
state[:clicked] ||= 0
|
|
124
|
+
state[:clicked] += 1
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
button "Secondary Action", style: :secondary do |state|
|
|
128
|
+
state[:secondary_clicked] = true
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
if state[:clicked] && state[:clicked] > 0
|
|
132
|
+
md "Primary button clicked **#{state[:clicked]}** times"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
if state[:secondary_clicked]
|
|
136
|
+
text "Secondary button was clicked!"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# --- Status & Selection Components ---
|
|
140
|
+
header3 "Status Badge"
|
|
141
|
+
text "Visual match indicators with reasoning:"
|
|
142
|
+
div class: "status-badges-demo" do
|
|
143
|
+
status_badge :strong, "Perfect match for your preferences"
|
|
144
|
+
status_badge :maybe, "Good fit, but has some dark themes"
|
|
145
|
+
status_badge :skip, "Not recommended - wrong genre"
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
header3 "Tag Buttons (Single Select)"
|
|
149
|
+
text "Default style:"
|
|
150
|
+
tag_buttons :category, ["Fiction", "Non-fiction", "Mystery", "Sci-Fi"]
|
|
151
|
+
|
|
152
|
+
text "Destructive style (for elimination):"
|
|
153
|
+
tag_buttons :eliminate_reason, ["Too dark", "Wrong genre", "Bad reviews", "Not interested"], style: :destructive
|
|
154
|
+
|
|
155
|
+
text "Selected category: #{state[:category] || '(none)'}"
|
|
156
|
+
text "Elimination reason: #{state[:eliminate_reason] || '(none)'}"
|
|
157
|
+
|
|
158
|
+
header3 "External Link Button"
|
|
159
|
+
text "Opens URL in new tab (no form submit):"
|
|
160
|
+
external_link_button "Visit Example.com", url: "https://example.com"
|
|
161
|
+
|
|
162
|
+
text "Opens URL AND submits form (for agentic mode):"
|
|
163
|
+
external_link_button "Submit & Open Google", url: "https://google.com", submit: true
|
|
164
|
+
|
|
165
|
+
# --- Current State ---
|
|
166
|
+
header3 "Current State"
|
|
167
|
+
text "Username: #{state[:username] || '(none)'}"
|
|
168
|
+
text "Bio: #{state[:bio] || '(none)'}"
|
|
169
|
+
text "Enabled: #{state[:enabled] ? 'Yes' : 'No'}"
|
|
170
|
+
text "Color: #{state[:color] || '(none)'}"
|
|
171
|
+
text "Size: #{state[:size] || '(none)'}"
|
|
172
|
+
text "Selected items: #{(state[:selected_items] || []).join(', ').then { |s| s.empty? ? '(none)' : s }}"
|
|
173
|
+
text "Category: #{state[:category] || '(none)'}"
|
|
174
|
+
text "Elimination reason: #{state[:eliminate_reason] || '(none)'}"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
App.run! if __FILE__ == $0
|