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,300 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Inner DSL for a fictional design-review document: "Getting Wayfinder and
|
|
3
|
+
# Beacon in front of every agent" -- a genre example proving StreamWeaver's
|
|
4
|
+
# doc component family can reach 1:1 visual parity with a claude.ai-hosted
|
|
5
|
+
# Artifact for editorial "design review" documents specifically: option
|
|
6
|
+
# cards with chips, pick states on both a card and a table row, a
|
|
7
|
+
# two-column checklist split, and a full re-skin via one unlayered CSS
|
|
8
|
+
# file. Wayfinder/Beacon, the reviewers, and the citations below are
|
|
9
|
+
# entirely invented for this example -- see docs/porting-artifacts.md for
|
|
10
|
+
# the process this was ported through.
|
|
11
|
+
#
|
|
12
|
+
# Intended for canvas-push:
|
|
13
|
+
# streamweaver canvas-push <session> < examples/components/design_review_dsl.rb
|
|
14
|
+
# CAVEAT: the canvas bridge injects only master-theme CSS -- it cannot carry
|
|
15
|
+
# this example's own stylesheet yet (stream_weaver-9uk), so a canvas push shows
|
|
16
|
+
# correct structure without the bespoke re-skin. The standalone app is the
|
|
17
|
+
# faithful rendering: ruby examples/components/design_review_demo.rb
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
# Small helpers, local to this DSL body (same pattern as
|
|
21
|
+
# examples/parity/tyrion_warroom_components.rb's inline `def art_glyph`).
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
# A "chip": dim dimension label + colored status dot + value text.
|
|
25
|
+
# color: is one of :green/:yellow/:red (good/mid/weak).
|
|
26
|
+
def ad_chip(dim, color, value)
|
|
27
|
+
div(class: "ad-chip") do
|
|
28
|
+
phrase(dim, class: "ad-chip-dim")
|
|
29
|
+
status_dot(status: color, size: :sm)
|
|
30
|
+
phrase(value)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# One option card (section 03). Chips + prose are supplied via the block.
|
|
35
|
+
#
|
|
36
|
+
# `mechanism` (the subtitle line) is rendered via `md`, not card_header's
|
|
37
|
+
# own `meta:` -- CardHeader's meta: renders as escaped plain text
|
|
38
|
+
# (view.span { @meta }), so backtick-quoted terms in the subtitle (e.g.
|
|
39
|
+
# "the existing `beacon init` pattern") would show up as literal backtick
|
|
40
|
+
# characters instead of code pills. Routing it through `md` as an extra
|
|
41
|
+
# header child gets the same markdown-to-<code> handling every other prose
|
|
42
|
+
# paragraph in this doc already gets.
|
|
43
|
+
def ad_option(letter, title, mechanism, recommended: false)
|
|
44
|
+
classes = ["ad-option"]
|
|
45
|
+
classes << "ad-option--pick" if recommended
|
|
46
|
+
card(class: classes.join(" ")) do
|
|
47
|
+
card_header(title, badge: letter) do
|
|
48
|
+
div(class: "ad-option-mech") { md mechanism }
|
|
49
|
+
badge("Recommended", variant: :info) if recommended
|
|
50
|
+
end
|
|
51
|
+
card_body { yield if block_given? }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# A raw rating cell for the comparison-matrix table (section 04): colored
|
|
56
|
+
# status dot + text, matching the chip's dot but laid out for a table cell.
|
|
57
|
+
# Table's own markdown: true option renders cell HTML raw (already used by
|
|
58
|
+
# the framework to turn `[text](url)` into <a> tags) -- this reuses that
|
|
59
|
+
# same sanctioned escape hatch rather than hand-building component objects
|
|
60
|
+
# outside the DSL.
|
|
61
|
+
def ad_rate(color, value)
|
|
62
|
+
%(<span class="ad-cell-rating"><span class="sw-status-dot sw-status-dot-#{color} sw-status-dot-sm"></span>#{value}</span>)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# One checklist tile (section 06): fixed-width mark glyph + prose line.
|
|
66
|
+
def ad_check(mark, text)
|
|
67
|
+
div(class: "ad-check-item") do
|
|
68
|
+
phrase(mark, class: "ad-check-mark")
|
|
69
|
+
md text
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
div(class: "ad-doc") do
|
|
74
|
+
# =========================================================================
|
|
75
|
+
# Header
|
|
76
|
+
# =========================================================================
|
|
77
|
+
doc_header(
|
|
78
|
+
eyebrow: "Design options — internal review",
|
|
79
|
+
title: "Getting Wayfinder and Beacon in front of every agent, without a human having to introduce them"
|
|
80
|
+
)
|
|
81
|
+
div(class: "ad-dek") do
|
|
82
|
+
md "Six ways to make the project registry and the federated knowledge base self-discoverable to Claude Code, Codex, Gemini CLI, and Copilot — scored against discovery, friction, and cognitive-load principles, drafted by a research subagent, July 2026."
|
|
83
|
+
end
|
|
84
|
+
div(class: "ad-meta-row") do
|
|
85
|
+
div { phrase("Subject", class: "ad-meta-label"); phrase(" Wayfinder + Beacon, pre-launch") }
|
|
86
|
+
div { phrase("Client", class: "ad-meta-label"); phrase(" the agent, not the human") }
|
|
87
|
+
div { phrase("Options", class: "ad-meta-label"); phrase(" 6, one recommended") }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# =========================================================================
|
|
91
|
+
# 01 — The actual problem
|
|
92
|
+
# =========================================================================
|
|
93
|
+
doc_section_header "01 — The actual problem", "", id: "problem"
|
|
94
|
+
callout(title: "Framing") do
|
|
95
|
+
md "The customer whose friction has to hit zero is **the agent itself** — not a human reading a README. Any of the four CLIs, dropped cold into an arbitrary project, needs to (a) discover Wayfinder/Beacon exist, (b) know how to query them, and (c) develop the habit of *writing* durable knowledge back in — with no per-project hand-authoring by a maintainer. The only human cost allowed is `gem install wayfinder` once, plus at most one machine-level setup command. Anything that requires remembering a per-repo step decays under real-world attention scarcity — the cognitive-load principle applied to the maintainer, not just the end user."
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# =========================================================================
|
|
99
|
+
# 02 — Verified landscape, July 2026
|
|
100
|
+
# =========================================================================
|
|
101
|
+
doc_section_header "02 — Verified landscape, July 2026", "What each CLI actually reads on its own", id: "landscape"
|
|
102
|
+
md "Two structural facts fall out of this: a repo with both `AGENTS.md` and a `CLAUDE.md` that imports it covers Claude Code, Codex, *and* Copilot with one canonical body of text — Gemini is the lone holdout needing its own file. And MCP is the only surface all four share, and the only one that's machine-global rather than per-repo."
|
|
103
|
+
div(class: "ad-tbl-scroll") do
|
|
104
|
+
table(
|
|
105
|
+
class: "ad-landscape-table",
|
|
106
|
+
markdown: true,
|
|
107
|
+
headers: ["CLI", "Repo context file", "User-global context", "MCP", "Plugin / skill surface"],
|
|
108
|
+
rows: [
|
|
109
|
+
[
|
|
110
|
+
"Claude Code",
|
|
111
|
+
"<code>CLAUDE.md</code> only — no native AGENTS.md read (tracked in the public issue queue, thousands of reactions); <code>@AGENTS.md</code> import works",
|
|
112
|
+
"<code>~/.claude/CLAUDE.md</code>",
|
|
113
|
+
"Yes — <code>claude mcp add</code>",
|
|
114
|
+
"Skills, plugins, marketplaces"
|
|
115
|
+
],
|
|
116
|
+
[
|
|
117
|
+
"Codex CLI",
|
|
118
|
+
"<code>AGENTS.md</code> — native, root + nested",
|
|
119
|
+
"<code>~/.codex/AGENTS.md</code>",
|
|
120
|
+
"Yes — can run <em>as</em> an MCP server too",
|
|
121
|
+
"AGENTS.md is the spec it champions"
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
"Gemini CLI",
|
|
125
|
+
"<code>GEMINI.md</code> by default — AGENTS.md not out-of-box (tracked as an open feature request)",
|
|
126
|
+
"<code>~/.gemini/GEMINI.md</code>",
|
|
127
|
+
"Yes — <code>~/.gemini/settings.json</code>",
|
|
128
|
+
"Extensions bundle MCP config + context file together"
|
|
129
|
+
],
|
|
130
|
+
[
|
|
131
|
+
"Copilot CLI",
|
|
132
|
+
"<code>AGENTS.md</code>, <code>.github/copilot-instructions.md</code> — <em>and also</em> CLAUDE.md & GEMINI.md",
|
|
133
|
+
"user-level instruction files",
|
|
134
|
+
"Yes — command + HTTP",
|
|
135
|
+
"Custom agents, skills, MCP marketplace"
|
|
136
|
+
]
|
|
137
|
+
]
|
|
138
|
+
)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# =========================================================================
|
|
142
|
+
# 03 — Six options
|
|
143
|
+
# =========================================================================
|
|
144
|
+
doc_section_header "03 — Six options", "What “batteries included” could actually mean", id: "options"
|
|
145
|
+
|
|
146
|
+
ad_option("A", "Universal context-file writer", "Generalize the existing `beacon init` pattern to every convention that matters") do
|
|
147
|
+
div(class: "ad-chips") do
|
|
148
|
+
ad_chip("Discovery", :green, "Strong")
|
|
149
|
+
ad_chip("Friction", :yellow, "1 cmd/repo")
|
|
150
|
+
ad_chip("Load·user", :green, "Good")
|
|
151
|
+
ad_chip("Load·maint.", :green, "Low burden")
|
|
152
|
+
ad_chip("Cost", :green, "~1 day")
|
|
153
|
+
ad_chip("Robustness", :yellow, "Medium")
|
|
154
|
+
end
|
|
155
|
+
md "One command writes a canonical section into every file that matters: a full section in `AGENTS.md` (covers Codex + Copilot natively), a `CLAUDE.md` created with an `@AGENTS.md` import if missing (covers Claude Code), a thin pointer stub in `GEMINI.md`, and a section in `.github/copilot-instructions.md` if one already exists. All four render from one template in the gem, fenced with `<!-- wayfinder:begin -->` markers so re-runs update in place — the same idiom `lib/wayfinder/beacon/init.rb` already uses for AGENTS.md alone. The section has to state the *write* directive explicitly (\"when you learn something durable, register it; when you produce reusable knowledge, add a page and reindex\") — a context file is the only place you can install a habit, not just a capability. Weakness: someone still has to run it, once, per repo, and static prose drifts from the CLI's real surface over time."
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
ad_option("B", "Universal MCP server", "Ship the registry and Beacon as live, structured tools every CLI can call") do
|
|
159
|
+
div(class: "ad-chips") do
|
|
160
|
+
ad_chip("Discovery·find", :green, "Strong")
|
|
161
|
+
ad_chip("Discovery·digest", :yellow, "Weaker")
|
|
162
|
+
ad_chip("Friction", :green, "1 cmd/machine")
|
|
163
|
+
ad_chip("Load·user", :green, "Excellent")
|
|
164
|
+
ad_chip("Load·maint.", :green, "Very low")
|
|
165
|
+
ad_chip("Cost", :yellow, "2–4 days")
|
|
166
|
+
ad_chip("Robustness", :green, "Highest")
|
|
167
|
+
end
|
|
168
|
+
md "`wayfinder mcp` (stdio) exposes structured tools — `wayfinder_locate`, `wayfinder_search`, `wayfinder_show`, `beacon_search`, `beacon_resolve`, plus write tools like `wayfinder_update` and `beacon_register`. A one-time `wayfinder agents install-mcp` writes client config for whichever CLIs it detects, idempotently, the same way `install-hooks` already chains onto an existing pre-commit hook. The property worth dwelling on: once registered at user scope, *every* session of *all four* CLIs, in every directory, sees these tools in its list — no per-repo file, nobody remembering anything. And because the tools *are* the real behavior, they can never drift out of sync with it the way a static snippet can. Cost is real (verify the Ruby MCP SDK's maturity first), and a tool list alone teaches an agent to *read* more readily than to *write*."
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
ad_option("C", "Native skill / plugin bundles, one per ecosystem", "A Claude Skill, a Gemini extension, a Copilot agent — each in its own idiom") do
|
|
172
|
+
div(class: "ad-chips") do
|
|
173
|
+
ad_chip("Discovery", :green, "Excellent")
|
|
174
|
+
ad_chip("Friction", :green, "1 cmd/machine")
|
|
175
|
+
ad_chip("Load·user", :green, "Good")
|
|
176
|
+
ad_chip("Load·maint.", :red, "High — 4 formats")
|
|
177
|
+
ad_chip("Cost", :red, "High + ongoing")
|
|
178
|
+
ad_chip("Robustness", :red, "Low–medium")
|
|
179
|
+
end
|
|
180
|
+
md "`wayfinder agents install [claude|gemini|codex|copilot|all]` would drop a real Claude Skill (which can trigger *contextually* — \"when the user references a project by name\" — something a static file can't do), a Gemini extension bundling both MCP config and a GEMINI.md, and a Copilot custom agent. This is the best per-ecosystem experience on the list, and the worst maintenance profile: four young, fast-moving vendor formats, each a separate artifact to keep in sync, each liable to drift exactly as the cognitive-load principle predicts for the maintainer. The seductive trap — skip until one ecosystem clearly earns the investment."
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
ad_option("D", "Docs-only bet", "An excellent README and `docs/for-agents.md`, nothing mechanical") do
|
|
184
|
+
div(class: "ad-chips") do
|
|
185
|
+
ad_chip("Discovery", :red, "Weak")
|
|
186
|
+
ad_chip("Friction", :red, "Fails")
|
|
187
|
+
ad_chip("Load·user", :red, "Fails")
|
|
188
|
+
ad_chip("Load·maint.", :green, "~zero")
|
|
189
|
+
ad_chip("Cost", :green, "~zero")
|
|
190
|
+
ad_chip("Robustness", :yellow, "n/a")
|
|
191
|
+
end
|
|
192
|
+
md "Fails the friction principle outright: the agent has to already know to look, and in practice only discovers Wayfinder from *inside* the Wayfinder repo itself — the entire point was discovery from *other* projects. Fails the cognitive-load principle too, since it relies on a human remembering to paste a snippet somewhere. Keep the good README regardless of what else ships — but this alone is the absence of a mechanism, not one."
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
ad_option("E", "The tool teaches itself", "Error messages and help output as onboarding, at the moment of contact") do
|
|
196
|
+
div(class: "ad-chips") do
|
|
197
|
+
ad_chip("Discovery", :green, "Perfect in-moment")
|
|
198
|
+
ad_chip("Friction", :green, "Zero / instant")
|
|
199
|
+
ad_chip("Load·user", :green, "Excellent")
|
|
200
|
+
ad_chip("Load·maint.", :green, "Very low")
|
|
201
|
+
ad_chip("Cost", :green, "Hours")
|
|
202
|
+
ad_chip("Robustness", :green, "High")
|
|
203
|
+
end
|
|
204
|
+
md "Orthogonal to every other option, cheap, and compounds with all of them. `beacon check` gate failures already interrupt an agent mid-commit — that's the highest-attention channel it will ever give you, so make the failure text a complete, copy-pasteable remediation plus one line of \"what Beacon is and why.\" Add `wayfinder help --agent` / `beacon help --agent` emitting exactly Option A's canonical snippet. End `wayfinder init` with \"next: run `wayfinder agents init`.\" Give empty `--json` results a `_hint` field. It's an amplifier, not a discovery mechanism on its own — something else still has to cause first contact — but there's no version of \"batteries included\" that shouldn't include it."
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
ad_option("F", "Hybrid — MCP as source of truth, context files as habit", "B + A + E, layered in that priority order", recommended: true) do
|
|
208
|
+
div(class: "ad-chips") do
|
|
209
|
+
ad_chip("Discovery", :green, "Excellent")
|
|
210
|
+
ad_chip("Friction", :green, "~zero after setup")
|
|
211
|
+
ad_chip("Load·user", :green, "Excellent")
|
|
212
|
+
ad_chip("Load·maint.", :green, "Low")
|
|
213
|
+
ad_chip("Cost", :yellow, "~1 week total")
|
|
214
|
+
ad_chip("Robustness", :green, "High")
|
|
215
|
+
end
|
|
216
|
+
md "The full story: `gem install wayfinder` puts the binaries on PATH. `wayfinder agents setup`, run once per machine, registers the MCP server with every detected CLI *and* appends a short section to each CLI's user-global context file — global prose installs the habit (\"these tools exist, use them, write back what you learn\"), MCP tools keep the capability always fresh. `wayfinder agents init` stays available per-repo for project-specific pointers (hub location, Beacon membership), and both `beacon init` and `wayfinder init` suggest running it — so it self-propagates. Self-teaching output (E) runs through all of it. Static prose is kept deliberately thin and stable; everything that changes with the CLI's surface lives behind MCP descriptions and `help --agent`, so the sync burden the cognitive-load principle warns about approaches zero."
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# =========================================================================
|
|
220
|
+
# 04 — Comparison
|
|
221
|
+
# =========================================================================
|
|
222
|
+
doc_section_header "04 — Comparison", "Side by side", id: "matrix"
|
|
223
|
+
div(class: "ad-legend") do
|
|
224
|
+
div(class: "ad-legend-item") { status_dot(status: :green, size: :sm); phrase("Strong / low cost") }
|
|
225
|
+
div(class: "ad-legend-item") { status_dot(status: :yellow, size: :sm); phrase("Mixed / moderate") }
|
|
226
|
+
div(class: "ad-legend-item") { status_dot(status: :red, size: :sm); phrase("Weak / high cost") }
|
|
227
|
+
end
|
|
228
|
+
div(class: "ad-tbl-scroll") do
|
|
229
|
+
table(
|
|
230
|
+
class: "ad-matrix-table mono",
|
|
231
|
+
markdown: true,
|
|
232
|
+
headers: ["Option", "Discovery", "Friction", "Load·user", "Load·maint.", "Cost", "Robustness"],
|
|
233
|
+
rows: [
|
|
234
|
+
["A — Context writer", ad_rate(:green, "Strong"), ad_rate(:yellow, "1/repo"), ad_rate(:green, "Good"), ad_rate(:green, "Low"), ad_rate(:green, "~1 day"), ad_rate(:yellow, "Medium")],
|
|
235
|
+
["B — MCP server", ad_rate(:yellow, "Find ↑ / digest ↓"), ad_rate(:green, "1/machine"), ad_rate(:green, "Excellent"), ad_rate(:green, "V. low"), ad_rate(:yellow, "2–4 days"), ad_rate(:green, "Highest")],
|
|
236
|
+
["C — Native bundles", ad_rate(:green, "Excellent"), ad_rate(:green, "1/machine"), ad_rate(:green, "Good"), ad_rate(:red, "High"), ad_rate(:red, "High+ongoing"), ad_rate(:red, "Low–med")],
|
|
237
|
+
["D — Docs only", ad_rate(:red, "Weak"), ad_rate(:red, "Fails"), ad_rate(:red, "Fails"), ad_rate(:green, "~zero"), ad_rate(:green, "~zero"), ad_rate(:yellow, "n/a")],
|
|
238
|
+
["E — Self-teaching", ad_rate(:green, "Perfect*"), ad_rate(:green, "Zero"), ad_rate(:green, "Excellent"), ad_rate(:green, "V. low"), ad_rate(:green, "Hours"), ad_rate(:green, "High")],
|
|
239
|
+
["F — Hybrid (B+A+E)", ad_rate(:green, "Excellent"), ad_rate(:green, "~zero*"), ad_rate(:green, "Excellent"), ad_rate(:green, "Low"), ad_rate(:yellow, "~1 week"), ad_rate(:green, "High")]
|
|
240
|
+
]
|
|
241
|
+
)
|
|
242
|
+
end
|
|
243
|
+
md "*E: perfect only at the moment an agent already touches the tool — it doesn't cause first contact. F: zero friction only after the one machine-level setup command."
|
|
244
|
+
|
|
245
|
+
# =========================================================================
|
|
246
|
+
# 05 — Recommendation
|
|
247
|
+
# =========================================================================
|
|
248
|
+
doc_section_header "05 — Recommendation", "", id: "reco"
|
|
249
|
+
div(class: "ad-reco") do
|
|
250
|
+
callout(title: "Top pick — Option F, built in order E → A → B") do
|
|
251
|
+
md <<~MD
|
|
252
|
+
Two failure modes matter: the agent never hears about the tool, and the maintainer has to keep four vendor artifacts in sync and stops (the cognitive-load principle, maintainer edition). The hybrid solves the first one twice over — global context prose installs the write-back habit in every session on the machine, MCP tools make the capability ambient and self-describing — and solves the second by keeping the volatile parts live (MCP, `help --agent`) and the static parts thin and stable. Option C's per-vendor bundles are the trap: best-in-class UX per ecosystem, worst-in-class rot profile. Skip it until one ecosystem clearly earns it — a Claude Skill is the strongest later candidate, since skills uniquely encode *when* to write, and it can be dogfooded privately first.
|
|
253
|
+
|
|
254
|
+
### Ship-now fallback
|
|
255
|
+
|
|
256
|
+
A weekend, pre-launch: Option E (hours — `--agent` help mode, gate-failure remediation text, `_hint` fields) plus Option A (`wayfinder agents init`, generalizing the existing `init.rb` machinery to the CLAUDE.md-imports-AGENTS.md pattern and a GEMINI.md stub). That alone takes Codex from "incidentally best-served" to all four CLIs covered per-repo, from one template. Layer in the MCP server (B) as the flagship feature for the actual launch — it also happens to be the strongest marketing artifact for a public gem, since MCP is what 2026 readers scan for first.
|
|
257
|
+
MD
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
div(class: "ad-aside") do
|
|
261
|
+
callout(title: "One note, regardless of which option wins") do
|
|
262
|
+
md "Tool availability alone gets an agent *reading* the registry. The *writing*-knowledge-back behavior — the part that actually builds toward the friction/cognitive-load UX — only happens when instructions say *when* to write: \"learned something durable → registry or wiki, then reindex.\" That sentence belongs in every surface: the AGENTS.md section, the global stub, the MCP tool descriptions, and any Skill built later."
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# =========================================================================
|
|
267
|
+
# 06 — Confidence check
|
|
268
|
+
# =========================================================================
|
|
269
|
+
doc_section_header "06 — Confidence check", "Verified this session, vs. still open", id: "confidence"
|
|
270
|
+
columns(class: "ad-split", gap: "1.2rem") do
|
|
271
|
+
column do
|
|
272
|
+
phrase("Verified via search, July 2026", class: "ad-col-h ad-col-h--v")
|
|
273
|
+
div(class: "ad-checklist ad-checklist--verified") do
|
|
274
|
+
ad_check("✓", "Claude Code has no native AGENTS.md read — tracked in the public issue queue, thousands of reactions; `@AGENTS.md` import and symlinking are the working patterns")
|
|
275
|
+
ad_check("✓", "Gemini CLI's sole out-of-box context filename is GEMINI.md; AGENTS.md support is an open feature request. A per-user `contextFileName` override exists in settings but isn't the out-of-box default other users will have")
|
|
276
|
+
ad_check("✓", "Copilot CLI reads AGENTS.md, .github/copilot-instructions.md, .github/instructions/**, and even CLAUDE.md/GEMINI.md, per its own docs")
|
|
277
|
+
ad_check("✓", "All four CLIs support MCP; Codex can run *as* an MCP server; config lives at `~/.gemini/settings.json`, via `claude mcp add`, and in Copilot's command/HTTP server config")
|
|
278
|
+
ad_check("✓", "Gemini CLI extensions (`gemini extensions install org/repo`) bundle MCP config + context file with vendor-managed updates")
|
|
279
|
+
ad_check("✓", "Claude Code plugins/marketplaces are the current skill-distribution format (`/plugin`, bundling SKILL.md + hooks + MCP config)")
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
column do
|
|
283
|
+
phrase("Needs a second reviewer's confirmation", class: "ad-col-h ad-col-h--u")
|
|
284
|
+
div(class: "ad-checklist ad-checklist--unverified") do
|
|
285
|
+
ad_check("?", "Whether the `@AGENTS.md` import works in a freshly-created CLAUDE.md exactly as documented, on the currently installed Claude Code version — test empirically")
|
|
286
|
+
ad_check("?", "Copilot CLI's exact user-level (machine-global) instruction file path and MCP config format — docs found cover the IDE surface best, not the standalone CLI")
|
|
287
|
+
ad_check("?", "Codex's `config.toml` MCP schema's current shape — check against the installed version before writing `install-mcp`")
|
|
288
|
+
ad_check("?", "Whether a maintained official Ruby MCP SDK gem exists to build Option B on — a 10-minute check before committing to that estimate")
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
div(class: "ad-sources") do
|
|
293
|
+
md "Sources: notes.example.dev/agent-cli-notes (context-file survey) · github.com/example-cli/example-cli/issues/8841 · cli-docs.example.dev/gemini-md · github.com/example-cli/gemini-cli/issues/5210 · docs.example.dev/copilot-cli/custom-instructions · changelog.example.dev/2025-08-28 · cli-docs.example.dev/extensions · docs.example.dev/plugin-marketplaces · surveys.example.dev/cli-comparison"
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
div(class: "ad-footer") do
|
|
297
|
+
phrase("Wayfinder / Beacon — agent discovery options")
|
|
298
|
+
phrase("drafted by a research subagent · reviewed for Priya Osei, Platform Team")
|
|
299
|
+
end
|
|
300
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Usage: streamweaver canvas-push <session> < examples/components/diff_block_demo.rb
|
|
2
|
+
# Or: streamweaver panel diff-block-demo && streamweaver canvas-push diff-block-demo < examples/components/diff_block_demo.rb
|
|
3
|
+
|
|
4
|
+
header2 "DiffBlock — Unified Diff Viewer"
|
|
5
|
+
md "Server-side diff via diffy gem. Removed lines red, added lines green, context neutral. Two-column line-number gutter. Prism.js syntax highlighting per line."
|
|
6
|
+
|
|
7
|
+
header3 "Ruby method refactor"
|
|
8
|
+
|
|
9
|
+
diff(language: "ruby") do
|
|
10
|
+
before do
|
|
11
|
+
<<~'RUBY'
|
|
12
|
+
def greet
|
|
13
|
+
puts 'hi'
|
|
14
|
+
end
|
|
15
|
+
RUBY
|
|
16
|
+
end
|
|
17
|
+
after do
|
|
18
|
+
<<~'RUBY'
|
|
19
|
+
def greet(name)
|
|
20
|
+
puts "Hello, #{name}"
|
|
21
|
+
end
|
|
22
|
+
RUBY
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
header3 "Multi-hunk diff (large file excerpt)"
|
|
27
|
+
|
|
28
|
+
diff(language: "ruby") do
|
|
29
|
+
before do
|
|
30
|
+
<<~'RUBY'
|
|
31
|
+
class User
|
|
32
|
+
attr_reader :name, :email
|
|
33
|
+
|
|
34
|
+
def initialize(name, email)
|
|
35
|
+
@name = name
|
|
36
|
+
@email = email
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def display
|
|
40
|
+
"#{name} <#{email}>"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def active?
|
|
44
|
+
true
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
RUBY
|
|
48
|
+
end
|
|
49
|
+
after do
|
|
50
|
+
<<~'RUBY'
|
|
51
|
+
class User
|
|
52
|
+
attr_reader :name, :email, :role
|
|
53
|
+
|
|
54
|
+
def initialize(name, email, role: :viewer)
|
|
55
|
+
@name = name
|
|
56
|
+
@email = email
|
|
57
|
+
@role = role
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def display
|
|
61
|
+
"#{name} <#{email}> [#{role}]"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def active?
|
|
65
|
+
@role != :suspended
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
RUBY
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
header3 "JavaScript"
|
|
73
|
+
|
|
74
|
+
diff(language: "javascript") do
|
|
75
|
+
before do
|
|
76
|
+
<<~JS
|
|
77
|
+
function fetchUser(id) {
|
|
78
|
+
return fetch('/users/' + id)
|
|
79
|
+
.then(function(res) { return res.json(); });
|
|
80
|
+
}
|
|
81
|
+
JS
|
|
82
|
+
end
|
|
83
|
+
after do
|
|
84
|
+
<<~JS
|
|
85
|
+
async function fetchUser(id) {
|
|
86
|
+
const res = await fetch(`/users/${id}`);
|
|
87
|
+
return res.json();
|
|
88
|
+
}
|
|
89
|
+
JS
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
header3 "No language (plain text / pseudocode)"
|
|
94
|
+
|
|
95
|
+
diff do
|
|
96
|
+
before do
|
|
97
|
+
<<~TEXT
|
|
98
|
+
push start onto stack
|
|
99
|
+
while stack not empty
|
|
100
|
+
node = stack.pop
|
|
101
|
+
visit node
|
|
102
|
+
TEXT
|
|
103
|
+
end
|
|
104
|
+
after do
|
|
105
|
+
<<~TEXT
|
|
106
|
+
enqueue start
|
|
107
|
+
while queue not empty
|
|
108
|
+
node = queue.dequeue
|
|
109
|
+
visit node
|
|
110
|
+
TEXT
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Events Demo - demonstrates on_change, on_blur, debounce, and hover callbacks
|
|
4
|
+
#
|
|
5
|
+
# Run with: ruby examples/events_demo.rb
|
|
6
|
+
|
|
7
|
+
require_relative '../../lib/stream_weaver'
|
|
8
|
+
|
|
9
|
+
app = StreamWeaver.app "Events Demo" do
|
|
10
|
+
header1 "Events & Callbacks Demo"
|
|
11
|
+
|
|
12
|
+
md "This example demonstrates **event callbacks** for form components and **hover effects** for containers."
|
|
13
|
+
|
|
14
|
+
# Initialize state
|
|
15
|
+
state[:change_count] ||= 0
|
|
16
|
+
state[:blur_count] ||= 0
|
|
17
|
+
state[:last_change] ||= ""
|
|
18
|
+
state[:validated_email] ||= ""
|
|
19
|
+
state[:email_valid] ||= nil
|
|
20
|
+
state[:search_results] ||= []
|
|
21
|
+
|
|
22
|
+
# =========================================
|
|
23
|
+
# on_change Example
|
|
24
|
+
# =========================================
|
|
25
|
+
header2 "on_change Callback"
|
|
26
|
+
md "The text field below triggers a callback on every change (debounced):"
|
|
27
|
+
|
|
28
|
+
text_field :search_query,
|
|
29
|
+
placeholder: "Type to search...",
|
|
30
|
+
debounce: 300,
|
|
31
|
+
on_change: ->(s, value) {
|
|
32
|
+
s[:change_count] += 1
|
|
33
|
+
s[:last_change] = value
|
|
34
|
+
|
|
35
|
+
# Simulate search results
|
|
36
|
+
if value.length >= 2
|
|
37
|
+
s[:search_results] = [
|
|
38
|
+
"Result for '#{value}' #1",
|
|
39
|
+
"Result for '#{value}' #2",
|
|
40
|
+
"Result for '#{value}' #3"
|
|
41
|
+
]
|
|
42
|
+
else
|
|
43
|
+
s[:search_results] = []
|
|
44
|
+
end
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
card do
|
|
48
|
+
text "Change count: #{state[:change_count]}"
|
|
49
|
+
text "Last change: #{state[:last_change]}"
|
|
50
|
+
|
|
51
|
+
if state[:search_results].any?
|
|
52
|
+
header4 "Search Results:"
|
|
53
|
+
vstack spacing: :xs do
|
|
54
|
+
state[:search_results].each do |result|
|
|
55
|
+
text "• #{result}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# =========================================
|
|
62
|
+
# on_blur Example
|
|
63
|
+
# =========================================
|
|
64
|
+
header2 "on_blur Callback"
|
|
65
|
+
md "The email field below validates when you leave the field (blur):"
|
|
66
|
+
|
|
67
|
+
text_field :email,
|
|
68
|
+
placeholder: "Enter email address...",
|
|
69
|
+
on_blur: ->(s, value) {
|
|
70
|
+
s[:blur_count] += 1
|
|
71
|
+
s[:validated_email] = value
|
|
72
|
+
|
|
73
|
+
# Simple email validation
|
|
74
|
+
if value.empty?
|
|
75
|
+
s[:email_valid] = nil
|
|
76
|
+
elsif value.include?("@") && value.include?(".")
|
|
77
|
+
s[:email_valid] = true
|
|
78
|
+
else
|
|
79
|
+
s[:email_valid] = false
|
|
80
|
+
end
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
card do
|
|
84
|
+
text "Blur count: #{state[:blur_count]}"
|
|
85
|
+
|
|
86
|
+
if state[:email_valid] == true
|
|
87
|
+
text "✅ Valid email: #{state[:validated_email]}"
|
|
88
|
+
elsif state[:email_valid] == false
|
|
89
|
+
text "❌ Invalid email format"
|
|
90
|
+
else
|
|
91
|
+
text "Enter an email and click outside the field to validate"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# =========================================
|
|
96
|
+
# Checkbox on_change
|
|
97
|
+
# =========================================
|
|
98
|
+
header2 "Checkbox on_change"
|
|
99
|
+
md "Checkboxes can also have change callbacks:"
|
|
100
|
+
|
|
101
|
+
state[:features] ||= []
|
|
102
|
+
|
|
103
|
+
checkbox :dark_mode, "Enable dark mode",
|
|
104
|
+
on_change: ->(s, value) {
|
|
105
|
+
if value
|
|
106
|
+
s[:features] << "dark_mode" unless s[:features].include?("dark_mode")
|
|
107
|
+
else
|
|
108
|
+
s[:features].delete("dark_mode")
|
|
109
|
+
end
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
checkbox :notifications, "Enable notifications",
|
|
113
|
+
on_change: ->(s, value) {
|
|
114
|
+
if value
|
|
115
|
+
s[:features] << "notifications" unless s[:features].include?("notifications")
|
|
116
|
+
else
|
|
117
|
+
s[:features].delete("notifications")
|
|
118
|
+
end
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
card do
|
|
122
|
+
text "Enabled features: #{state[:features].empty? ? 'none' : state[:features].join(', ')}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# =========================================
|
|
126
|
+
# Select on_change
|
|
127
|
+
# =========================================
|
|
128
|
+
header2 "Select on_change"
|
|
129
|
+
md "Select dropdowns also support change callbacks:"
|
|
130
|
+
|
|
131
|
+
state[:theme_history] ||= []
|
|
132
|
+
|
|
133
|
+
select :theme, %w[Light Dark System],
|
|
134
|
+
default: "Light",
|
|
135
|
+
on_change: ->(s, value) {
|
|
136
|
+
s[:theme_history] << value
|
|
137
|
+
s[:theme_history] = s[:theme_history].last(5) # Keep last 5
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
card do
|
|
141
|
+
text "Theme history: #{state[:theme_history].join(' → ')}"
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# =========================================
|
|
145
|
+
# Hover Effects
|
|
146
|
+
# =========================================
|
|
147
|
+
header2 "Hover Effects"
|
|
148
|
+
md "Containers can have hover classes for visual feedback:"
|
|
149
|
+
|
|
150
|
+
hstack spacing: :md do
|
|
151
|
+
div hover_class: "sw-hover-highlight", class: "hover-demo-box" do
|
|
152
|
+
text "Hover me!"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
div hover_class: "sw-hover-lift", class: "hover-demo-box" do
|
|
156
|
+
text "I lift on hover"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
div hover_class: "sw-hover-glow", class: "hover-demo-box" do
|
|
160
|
+
text "I glow on hover"
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# =========================================
|
|
165
|
+
# Custom CSS for demo
|
|
166
|
+
# =========================================
|
|
167
|
+
md """
|
|
168
|
+
---
|
|
169
|
+
**How it works:**
|
|
170
|
+
- **on_change**: Callback fires when input value changes (with optional debounce delay)
|
|
171
|
+
- **on_blur**: Callback fires when input loses focus (good for validation)
|
|
172
|
+
- **debounce**: Milliseconds to wait before firing on_change (default: 500ms)
|
|
173
|
+
- **hover_class**: CSS class added on mouseenter, removed on mouseleave
|
|
174
|
+
|
|
175
|
+
Built-in hover classes: `sw-hover-highlight`, `sw-hover-lift`, `sw-hover-glow`
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
md "---"
|
|
179
|
+
button "Reset Demo", style: :secondary do |s|
|
|
180
|
+
s.clear
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
app.run!
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Form Block Demo - demonstrates deferred submission forms
|
|
4
|
+
#
|
|
5
|
+
# Run with: ruby examples/form_demo.rb
|
|
6
|
+
|
|
7
|
+
require_relative '../../lib/stream_weaver'
|
|
8
|
+
|
|
9
|
+
app = StreamWeaver.app "Form Block Demo" do
|
|
10
|
+
header1 "Form Blocks Demo"
|
|
11
|
+
|
|
12
|
+
md "This example demonstrates **deferred submission forms**. Form fields don't sync with the server until you click Submit."
|
|
13
|
+
|
|
14
|
+
# Pre-populate form state (simulating loading from database)
|
|
15
|
+
state[:edit_profile] ||= {
|
|
16
|
+
name: "Alice",
|
|
17
|
+
status: "active",
|
|
18
|
+
notes: "Initial notes..."
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
header2 "Edit Profile"
|
|
22
|
+
|
|
23
|
+
form :edit_profile do
|
|
24
|
+
text_field :name, placeholder: 'Your name'
|
|
25
|
+
select :status, %w[active paused archived]
|
|
26
|
+
text_area :notes, placeholder: 'Notes about this person...', rows: 4
|
|
27
|
+
|
|
28
|
+
submit 'Save Changes' do |form_values|
|
|
29
|
+
# This runs AFTER state[:edit_profile] is updated
|
|
30
|
+
puts "Form submitted with: #{form_values.inspect}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
cancel 'Reset'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Show current state (updates after form submit)
|
|
37
|
+
header2 "Current State"
|
|
38
|
+
card do
|
|
39
|
+
text "Name: #{state.dig(:edit_profile, :name)}"
|
|
40
|
+
text "Status: #{state.dig(:edit_profile, :status)}"
|
|
41
|
+
text "Notes: #{state.dig(:edit_profile, :notes)}"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
md "---"
|
|
45
|
+
md "**How it works:**"
|
|
46
|
+
md "- Type in the fields - nothing syncs to server yet"
|
|
47
|
+
md "- Click **Save Changes** - all values sent in one request"
|
|
48
|
+
md "- Click **Reset** - fields revert to original values (client-side only)"
|
|
49
|
+
|
|
50
|
+
md "---"
|
|
51
|
+
md "**Note:** State persists in browser cookies across server restarts. Click below to start fresh:"
|
|
52
|
+
button "Reset Demo", style: :secondary do |s|
|
|
53
|
+
s.clear
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
header2 "Standalone Field (for comparison)"
|
|
57
|
+
md "This field syncs immediately on change:"
|
|
58
|
+
text_field :standalone_field, placeholder: "Type here - syncs immediately"
|
|
59
|
+
text "Standalone value: #{state[:standalone_field]}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
app.run!
|