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,274 @@
|
|
|
1
|
+
# StreamWeaver Repo Audit — 1.0 Readiness
|
|
2
|
+
|
|
3
|
+
Audited 2026-07-02. Scope: factual inventory only, no design recommendations. This
|
|
4
|
+
report is input for a separate roadmap/strategy pass. Related existing research
|
|
5
|
+
already in this repo (not duplicated here): `gsd/research/market-positioning-research.md`
|
|
6
|
+
(HTML-vs-Markdown positioning) and `gsd/research/production-patterns-research.md`
|
|
7
|
+
(precedent survey for state/URLs/escape-hatch, written to inform exactly the gaps
|
|
8
|
+
this audit documents in sections 2-4).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Modes Inventory
|
|
13
|
+
|
|
14
|
+
StreamWeaver has evolved into **four distinct run modes**, documented in `README.md:67-72`:
|
|
15
|
+
|
|
16
|
+
| Mode | Invocation | Entry point | Maturity | Test coverage |
|
|
17
|
+
|---|---|---|---|---|
|
|
18
|
+
| Standalone script | `ruby app.rb` | `App#run!` in `lib/stream_weaver/app.rb`, own Sinatra server via `server.rb` | Mature — the original/primary mode | Broad, exercised by most of `spec/` |
|
|
19
|
+
| Agentic (popup input) | `app.run_once!` | Same `App` class, `run_once!` method | Mature, narrow use case | Covered by CLI eval/agentic specs |
|
|
20
|
+
| Service mode (multi-app-in-one-server) | `streamweaver app.rb` / `streamweaver serve` / `streamweaver run` | `lib/stream_weaver/service.rb`, dispatched via `lib/stream_weaver/cli.rb:15-107` (`case command`) | Functional but has the URL-slug gap (see section 3) | `spec/cli_spec.rb` and service-level specs |
|
|
21
|
+
| Canvas/panel push mode | `streamweaver live`, `streamweaver push`, `streamweaver panel`, `streamweaver canvas-*` (9 subcommands) | `lib/stream_weaver/canvas/{bridge.rb,bridge_server.rb,protocol.rb,session.rb,client.rb,doc_store.rb,history.rb,helpers.rb,reader.rb}` (2,231 lines total), CLI dispatch at `lib/stream_weaver/cli.rb:60-78` and `:1081-1467` | Actively developed, unevenly tested (see section 6) | `spec/canvas/` (9 files, ~1,196 lines, ~117 examples) + `spec/cli_canvas_push_spec.rb` + `spec/cli_canvas_read_default_spec.rb` — but **no direct spec file for `bridge_server.rb`** (1,111 lines, the largest and most load-bearing file in the subsystem) |
|
|
22
|
+
|
|
23
|
+
`lib/stream_weaver/cli.rb` is 1,897 lines and dispatches ~30 subcommands total
|
|
24
|
+
(`serve`, `run`, `list`, `remove`, `clear`, `admin`, `showcase`, `tutorial`, `stop`,
|
|
25
|
+
`status`, `llm`, `eval`, `prompt`, `live`, `push`, `live-list`, `live-close`, `wait`,
|
|
26
|
+
`template`, `canvas`, `canvas-push`, `canvas-wait`, `canvas-close`, `canvas-toast`,
|
|
27
|
+
`canvas-list`, `canvas-reset`, `canvas-stop`, `canvas-read`, `pick`, `confirm`,
|
|
28
|
+
`panel`, `opal-build`, `install-skill`, `setup`) — this is a large, sprawling CLI
|
|
29
|
+
surface for a single `exe/streamweaver` entry point.
|
|
30
|
+
|
|
31
|
+
A fifth mode exists at the deployment level rather than the DSL level: **Puma-dev
|
|
32
|
+
mode** (`README.md:156-188`, `examples/puma_dev/`), which runs a standard `config.ru`
|
|
33
|
+
under Puma-dev for memorable `http://myapp.test` URLs. This isn't a new run mode so
|
|
34
|
+
much as a deployment wrapper around standalone mode — but it's the one place in the
|
|
35
|
+
repo where a human-memorable URL story already works (see section 3 for why service
|
|
36
|
+
mode doesn't get the same treatment).
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 2. State Management
|
|
41
|
+
|
|
42
|
+
Two pluggable session stores exist, selected via `SW_SESSION_STORE` env var
|
|
43
|
+
(default `file`):
|
|
44
|
+
|
|
45
|
+
- **File store (current default)**: `StreamWeaver::FileSession < Rack::Session::Abstract::PersistedSecure`, `lib/stream_weaver/session_store.rb:66-165`. One `Marshal`-serialized file per session under `~/.config/stream_weaver/sessions/session_<id>`. No hard size limit. Sessions auto-expire after 24h (`expire_after: 86_400`); a startup cleanup in `lib/stream_weaver/server.rb:33-34` removes files older than 7 days.
|
|
46
|
+
- **Cookie store (legacy, opt-in)**: plain Sinatra `enable :sessions` (`server.rb:38-41`), hard-capped at 4096 bytes (`session_store.rb:34`). A `CookieStore#filter` (`session_store.rb:32-50`) strips blank values, known transient keys (`code_content`, `current_file_path`, `examples`, `_deck_state`, any `*_edited_code` key), and warns to stderr at 75% capacity (3,072B). No user-facing error on overflow — data is silently dropped past the filtered set.
|
|
47
|
+
|
|
48
|
+
**The "cookie too large" history is documented**: `CHANGELOG.md:205` records a
|
|
49
|
+
2026-01-02 incident — *"Tutorial session overflow - Session cookie was exceeding
|
|
50
|
+
4KB limit due to `*_edited_code` keys; now filtered from session storage."* The
|
|
51
|
+
`--reset` flag and `SW_DEBUG` env var (`CHANGELOG.md:36-37`) were added specifically
|
|
52
|
+
to troubleshoot this class of problem. A debug endpoint `GET /sw/session/size`
|
|
53
|
+
(`server.rb:862-878`) reports per-key byte sizes and an `over_limit` flag.
|
|
54
|
+
|
|
55
|
+
**Current state**: the file store is now default and effectively removes the 4KB
|
|
56
|
+
ceiling for standard installs. The cookie store remains available and still
|
|
57
|
+
silently truncates past 4KB with only a stderr warning — a data-loss risk if
|
|
58
|
+
`SW_SESSION_STORE=cookie` is set in production. Neither store is a shared/external
|
|
59
|
+
store (Redis, DB-backed) — file store is single-machine, filesystem-based, which is
|
|
60
|
+
adequate for local/dev use but not for multi-instance deployment.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 3. Multi-App Server URL Generation (the hash-URL complaint)
|
|
65
|
+
|
|
66
|
+
**Exact generation point**: `lib/stream_weaver/service.rb:114-115`
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
def load_app(file_path, name: nil, source: nil)
|
|
70
|
+
app_id = SecureRandom.hex(4)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This produces an 8-hex-character id (e.g. `a3f9c2e1`), used directly as the URL
|
|
74
|
+
segment in the `/load-app` response (`service.rb:405-412`):
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
url: "/apps/#{app_id}",
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The route is defined at `service.rb:868` (`get '/apps/:app_id' do ... end`), and
|
|
81
|
+
the CLI prints the raw hash URL directly to the user at `cli.rb:158-159`.
|
|
82
|
+
|
|
83
|
+
**A partial fix already exists in the code but isn't wired to the default path**:
|
|
84
|
+
`aliased_path_for` (`service.rb:186-196`) builds a human-readable `/source/name`
|
|
85
|
+
route from an app's `name`/`source` fields, matched by a Sinatra route at
|
|
86
|
+
`service.rb:814-825` (`get '/:source/:name'` redirects to `/apps/:app_id`). This
|
|
87
|
+
only activates when `load_app` is called with an explicit `source:` — used by
|
|
88
|
+
`examples_browser` and `tutorial` internally — but the ordinary `streamweaver run
|
|
89
|
+
<file.rb>` CLI path (`cli.rb:123-166`) never passes `source:`, so everyday usage
|
|
90
|
+
always surfaces the raw hex `app_id` URL rather than a memorable slug.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 4. "Escape to Sinatra" Gaps
|
|
95
|
+
|
|
96
|
+
No `TODO`/`FIXME`/"escape hatch" comments exist anywhere in `lib/` — the framework
|
|
97
|
+
doesn't self-document its own limits. Gaps identified by inspecting the DSL surface:
|
|
98
|
+
|
|
99
|
+
- **No custom HTTP route DSL for app authors.** `App#route` (`app.rb:134`) and
|
|
100
|
+
`App#page` (`app.rb:119`) only register state-driven view matches, not arbitrary
|
|
101
|
+
HTTP endpoints. There is no `get`/`post`/`put`/`patch`/`delete` method exposed on
|
|
102
|
+
`App`. All real Sinatra routes (`/`, `/update`, `/action/:button_id`, `/submit`,
|
|
103
|
+
`/event/:key`, `/form/:form_name`, `/theme/:theme_name`, `/deck/*` in `server.rb`;
|
|
104
|
+
`/load-app`, `/live/*`, `/admin/*`, `/apps/:app_id/*` in `service.rb`) are
|
|
105
|
+
framework-internal and not extensible from the DSL block.
|
|
106
|
+
- **No file upload support.** No multipart/`params[:file]` handling anywhere in
|
|
107
|
+
`lib/` for app authors (only unrelated internal `Tempfile` usage and one unrelated
|
|
108
|
+
`params[:file]` lookup in `canvas/reader.rb:107`).
|
|
109
|
+
- **No authentication/authorization layer.** No auth/authorize/CSRF concept in
|
|
110
|
+
`lib/` beyond `set :protection, false if ENV['RACK_ENV'] == 'test'`
|
|
111
|
+
(`server.rb:46`), which only disables Sinatra's built-in protection in tests.
|
|
112
|
+
- **No custom middleware DSL.** `use` appears only internally (session store
|
|
113
|
+
wiring, `SW_DEBUG` logger) — never exposed to app authors.
|
|
114
|
+
- **Resource DSL is CRUD-only, single-table.** `docs/resource-dsl.md`'s store
|
|
115
|
+
protocol (`all`/`find`/`create`/`update`/`destroy`) has no joins, relations, or
|
|
116
|
+
nested resources — this is the newest subsystem (see gsd/plan.md /
|
|
117
|
+
gsd/tasks.md / gsd/STATE.md below) and is intentionally scoped narrow.
|
|
118
|
+
- **Routing is explicitly documented as limited in one place.**
|
|
119
|
+
`docs/routing.md:42`: *"One state key only. Doesn't handle parameterized paths
|
|
120
|
+
like `/initiative/:id`"* for `route_by` — `route_with` is offered as the
|
|
121
|
+
alternative but is still state-mapping, not general routing.
|
|
122
|
+
|
|
123
|
+
Net: any developer needing a webhook receiver, custom JSON API, non-GET/POST verb,
|
|
124
|
+
file upload, or auth has no documented in-framework path — they write raw Sinatra
|
|
125
|
+
alongside/instead of StreamWeaver. This is the gap `gsd/research/production-patterns-research.md`
|
|
126
|
+
was written to address (point "(c)" in that doc).
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 5. Gem Readiness
|
|
131
|
+
|
|
132
|
+
| Item | Status |
|
|
133
|
+
|---|---|
|
|
134
|
+
| Version | gemspec + `lib/stream_weaver/version.rb` both say **0.1.1**, but CHANGELOG.md has only ever cut `[0.1.0] - 2025-11-08` — everything since (including whatever justified the 0.1.1 bump) is still sitting in `[Unreleased]`. Version file and changelog are out of sync. |
|
|
135
|
+
| Dependencies | 10 runtime deps (sinatra, sinatra-contrib, phlex, puma, rackup, kramdown, kramdown-parser-gfm, ostruct, iterm2_ruby, diffy). **`iterm2_ruby ~> 0.1` is pointed at a local filesystem path in `Gemfile:9`** (`~/work/iterm2_ruby`), not published to rubygems.org — this is a hard blocker for `gem install stream_weaver` working for anyone but the author, since it's a runtime (not dev) dependency. |
|
|
136
|
+
| CI | **None.** No `.github/workflows/` directory exists. No automated tests, lint, or Ruby-version matrix on push/PR. |
|
|
137
|
+
| Test suite | Runs clean: **2,090 examples, 0 failures, 1 pending** (pending spec is an intentionally browser-only Opal test, not a real gap). ~5 second run time. Healthy suite size/health for a gem this size, but with zero CI it's only as good as manual discipline. |
|
|
138
|
+
| README | Hybrid — strong marketing/philosophy framing up top (mode comparison tables, "why StreamWeaver," collapsible longer story) with real Quick Start/install instructions further down. Reads more like a pitch/essay than a terse installation-first gem README; a first-time `gem install` user has to scroll past narrative to reach setup. |
|
|
139
|
+
| CHANGELOG | Real, substantial `[Unreleased]` section (~200 lines) with concrete entries, consistent Keep-a-Changelog formatting. Only one actual version cut (`0.1.0`) exists despite VERSION saying 0.1.1. |
|
|
140
|
+
| Docs tree | 73 files under `docs/`. Roughly 9 are genuine user-facing reference (`SERVICE_MODE.md`, `components_reference.md`, `crud-patterns.md`, `form-patterns.md`, `resource-dsl.md`, `routing.md`, `templates.md`, `testing.md`, `architecture/how_streamweaver_works.md`); the remainder is accumulated internal planning/scratch content — `docs/plans/*` (7 files), `docs/superpowers/plans/*` + `docs/superpowers/specs/*` (10 files, and per `.gitignore` these are supposed to be excluded from git but show up tracked in the working tree — worth reconciling), `docs/visual-skills/*` (25 files, session/build logs including `implementation/STATE.md`, `PROGRESS.md`, `SESSION-CONTEXT.md`), `docs/visual/*` (3 files), `docs/ideas/*` (3 files), `docs/blog/*`, stray `.rb` files inside `docs/streamweaver_canvas/`, and various spike/exploration docs (`opal-*`, `canvas-roadmap.md`, `canvas-ipc-session-summary.md`, `html-artifact-audit.md`, `ruby-ui-comparison.md`). This is not a coherent user-facing docs/ tree as-is. |
|
|
141
|
+
| exe/bin | `exe/streamweaver` is the actual packaged CLI entry point (wired via `spec.bindir = "exe"`). `bin/` (`build_scenarios`, `console`, `setup`, `opal_spike.rb`) is dev-only, correctly excluded from the gem by the gemspec's `spec.files` filter. |
|
|
142
|
+
| .gitignore | `*.gem` and `/pkg/` correctly ignored, none tracked. **`dist/` (2.7MB of built JS assets) is untracked but NOT in `.gitignore`** — currently shows as `?? dist/` in git status, one `git add -A` away from being accidentally committed. |
|
|
143
|
+
| Stray files at repo root | Two built `.gem` files sit at the repo root (`stream_weaver-0.1.0.gem`, `stream_weaver-0.1.1.gem`) — not tracked by git per the check above, but present on disk and should be confirmed as build artifacts, not something to ship. |
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 6. Canvas Mode Specifics
|
|
148
|
+
|
|
149
|
+
**Wire protocol** (`lib/stream_weaver/canvas/protocol.rb`, 74 lines): newline-delimited
|
|
150
|
+
JSON over a Unix domain socket (`~/.streamweaver/canvas.sock`) for Claude-to-Bridge
|
|
151
|
+
communication, plus WebSocket for Bridge-to-Browser. `Protocol.encode`/`.decode`/
|
|
152
|
+
`.parse_buffer` handle framing.
|
|
153
|
+
|
|
154
|
+
**Bridge architecture** (`bridge.rb`, 220 lines): `Bridge` holds an in-memory
|
|
155
|
+
`@sessions` hash (name to `Session`, no disk persistence — a crash loses all open
|
|
156
|
+
canvas sessions), dispatches messages by `type`. `handle_push` (line 112)
|
|
157
|
+
`instance_eval`s pushed DSL into a throwaway `App`, renders via the AlpineJS
|
|
158
|
+
adapter, and only persists the DSL on successful render — a bad push doesn't
|
|
159
|
+
clobber the last-good display state.
|
|
160
|
+
|
|
161
|
+
**Sessions**: `VALID_LAYOUTS = %i[default wide full fluid]` (`session.rb:9`);
|
|
162
|
+
theme is stored as a symbol with no validation against the actual theme registry.
|
|
163
|
+
|
|
164
|
+
**CLI surface**: 13 canvas-related subcommands in `cli.rb`, all functioning and
|
|
165
|
+
none stubbed.
|
|
166
|
+
|
|
167
|
+
**Documentation inconsistency found**: `docs/canvas-ipc-session-summary.md` is
|
|
168
|
+
headed "Status: OUTDATED — Canvas is now working and actively used" but its body
|
|
169
|
+
still documents a plan to delete `protocol.rb`, `session.rb`, `bridge.rb`,
|
|
170
|
+
`client.rb`, `bridge_server.rb`, `helpers.rb` in favor of an abandoned "templates"
|
|
171
|
+
approach — this actively contradicts the current (correct) architecture and should
|
|
172
|
+
be reconciled or removed before 1.0. `docs/canvas-roadmap.md` and
|
|
173
|
+
`docs/canvas-panel-workflow.md` are current and accurate.
|
|
174
|
+
|
|
175
|
+
**Relationship to the "visual companion" skill**: `lib/stream_weaver/skills/streamweaver-visual-companion/SKILL.md`
|
|
176
|
+
is a repo-shipped Claude Code skill built directly on canvas mode — it's an explicit
|
|
177
|
+
drop-in replacement for a Chrome-based visual companion, routing all interaction
|
|
178
|
+
through `panel`/`canvas-push`/`canvas-wait`. Canvas mode is therefore a dependency
|
|
179
|
+
of a shipped skill, not just an internal dev convenience, which raises the bar on
|
|
180
|
+
its required stability.
|
|
181
|
+
|
|
182
|
+
**Test coverage gap**: `spec/canvas/` covers session/doc_store/reader/history
|
|
183
|
+
behavior well, but **`bridge_server.rb` (1,111 lines, the largest and most
|
|
184
|
+
architecturally load-bearing file in the subsystem) has no dedicated spec file** —
|
|
185
|
+
only indirect coverage via CLI specs. Error handling across the small canvas files
|
|
186
|
+
is thin (13 `rescue` sites total across bridge/client/doc_store/helpers/history/reader).
|
|
187
|
+
|
|
188
|
+
**Overall**: an actively developed, real subsystem (not a throwaway experiment) —
|
|
189
|
+
but not fully mature for 1.0. In-memory-only session state (no crash recovery),
|
|
190
|
+
unvalidated theme/layout wire values, the largest file untested directly, and one
|
|
191
|
+
actively misleading doc file are the concrete gaps.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 7. Tutorials
|
|
196
|
+
|
|
197
|
+
**CLI command**: `streamweaver tutorial` (`cli.rb:306`, `self.tutorial`) execs
|
|
198
|
+
`examples/advanced/tutorial.rb` as a standalone script.
|
|
199
|
+
|
|
200
|
+
**Content files**:
|
|
201
|
+
- `examples/advanced/tutorial.rb` (1,068 lines) — the live tutorial, 10 lessons
|
|
202
|
+
(Philosophy, Hello World, Getting Input, Making Choices, Taking Action, Layout,
|
|
203
|
+
Cards, Tables, Modals, Themes, Patterns). Last touched 2026-01-02 (the
|
|
204
|
+
cookie-overflow fix commit).
|
|
205
|
+
- `examples_playground/advanced/tutorial.rb` — near-duplicate copy for the
|
|
206
|
+
examples/showcase playground.
|
|
207
|
+
- `examples/claude_code/tutorial/README.md` — separate, small, Claude-Code-agent-oriented walkthrough.
|
|
208
|
+
|
|
209
|
+
**Staleness — confirmed stale.** The tutorial predates essentially all of the
|
|
210
|
+
`CHANGELOG.md` `[Unreleased]` section (there has been no version cut since 0.1.0
|
|
211
|
+
on 2025-11-08, so everything shipped since is "Unreleased"). Grep for
|
|
212
|
+
`canvas|navbar|doc theme|CardHeader|resource\b|route_by|route_with|opal` in
|
|
213
|
+
`tutorial.rb` returns zero real hits. The Themes lesson (`tutorial.rb:350-358`)
|
|
214
|
+
lists only `:default`, `:dashboard`, `:document` — missing the newer `:doc` theme
|
|
215
|
+
(added this cycle, commit `e98df87`) and the `:sketch` preset. No coverage of the
|
|
216
|
+
`resource` DSL/CRUD scaffolding, `navbar`/`nav_item`/`link_to`, `card_header`
|
|
217
|
+
badge/meta options, canvas/panel mode, or theme_switcher/theme_toggle — all
|
|
218
|
+
shipped after the tutorial's last edit. Roughly six months of feature growth is
|
|
219
|
+
undocumented in the one onboarding path that's wired into the CLI.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 8. Theming/Styling
|
|
224
|
+
|
|
225
|
+
**`auto_mode.rb`** (`lib/stream_weaver/theme/auto_mode.rb`): generates inline JS
|
|
226
|
+
for OS-following dark/light mode, sets `data-sw-theme`/`dark` attributes on
|
|
227
|
+
`<html>` before `DOMContentLoaded` (avoiding flash-of-wrong-theme), persists
|
|
228
|
+
preference to `localStorage`, exposes `window.swToggleTheme`/`swGetTheme`. The
|
|
229
|
+
`mode:` parameter was a documented dead parameter until a fix landed this cycle
|
|
230
|
+
(`CHANGELOG.md:21`).
|
|
231
|
+
|
|
232
|
+
**Theme registry**: `lib/stream_weaver/theme.rb:151-206`, `BUILT_IN_THEMES` hash
|
|
233
|
+
with four entries — `:default` ("Warm Industrial"), `:dashboard` ("Data Dense"),
|
|
234
|
+
`:document` ("Reading Mode"), and `:doc` ("Compact Editorial" — added this cycle,
|
|
235
|
+
commit `e98df87`). No `register_theme` custom-theme API was found in the audited
|
|
236
|
+
region of `theme.rb`, despite CHANGELOG history referencing one previously —
|
|
237
|
+
worth confirming this API's current status before 1.0 messaging.
|
|
238
|
+
|
|
239
|
+
**Recent churn — actively in flux, not stable.** Three consecutive recent commits
|
|
240
|
+
(`e98df87`, `83be0bf`, `365e13a`) built the `:doc` theme and "doc-parity" polish
|
|
241
|
+
(a git-commit-message tag for matching an external artifact's editorial styling
|
|
242
|
+
pixel-for-pixel: ALL-CAPS table headers, `DocHeader` component, sticky-sidebar CSS
|
|
243
|
+
grid). The working tree at time of audit has uncommitted changes to
|
|
244
|
+
`auto_mode.rb`, `views.rb`, `components.rb`, and new/modified specs
|
|
245
|
+
(`theme_enhanced_spec.rb`, `theme_switcher_spec.rb`, `theme_toggle_spec.rb`,
|
|
246
|
+
`card_header_spec.rb`) — theming is mid-iteration right now, not settled.
|
|
247
|
+
|
|
248
|
+
**Test coverage**: `spec/theme_enhanced_spec.rb` (presets, AutoMode, ThemeToggle,
|
|
249
|
+
backward-compat), `spec/canvas/theme_support_spec.rb` (canvas session theme
|
|
250
|
+
carrying), `spec/components/theme_switcher_spec.rb` and `theme_toggle_spec.rb`
|
|
251
|
+
(narrow HTML-rendering checks).
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Existing Plans Found (so this audit doesn't duplicate them)
|
|
256
|
+
|
|
257
|
+
- **`docs/for_llms.md`** and **`llms.txt`** — both are LLM-oriented quick-reference
|
|
258
|
+
docs (port auto-detection warning, "the DSL block re-executes on every
|
|
259
|
+
interaction" mental model, minimal examples). Overlapping content between the
|
|
260
|
+
two; not a planning doc.
|
|
261
|
+
- **`gsd/plan.md`, `gsd/tasks.md`, `gsd/STATE.md`** — a completed GSD Ralph-loop
|
|
262
|
+
execution plan for the **Resource DSL** feature (routing chain, `page`/`route`
|
|
263
|
+
DSL, `ResourceDefinition`, `DefaultViews`, override blocks, scaffolding
|
|
264
|
+
examples). All 6 tasks (T1-T6) are marked **DONE** with commit hashes in
|
|
265
|
+
`gsd/STATE.md` — this work is finished and merged, not in flight.
|
|
266
|
+
- **`gsd/research/production-patterns-research.md`** — a precedent survey
|
|
267
|
+
(Streamlit, Rails "Solid" trio, etc.) written specifically to address the three
|
|
268
|
+
pain points this audit independently confirmed: (a) cookie-session overflow
|
|
269
|
+
history, (b) hash-based multi-app URLs, (c) users dropping to raw Sinatra. This
|
|
270
|
+
is strategy input already sitting in the repo, not something to re-derive.
|
|
271
|
+
- **`gsd/research/market-positioning-research.md`** — positioning research
|
|
272
|
+
(Anthropic's Markdown-to-HTML shift, docs-site template survey, demo-video
|
|
273
|
+
stack) — orthogonal to the technical gaps in this audit, useful for the
|
|
274
|
+
marketing/positioning side of a 1.0 roadmap.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "base64"
|
|
4
|
+
require "json"
|
|
5
|
+
require "openssl"
|
|
6
|
+
require "securerandom"
|
|
7
|
+
|
|
8
|
+
module StreamWeaver
|
|
9
|
+
module ActionToken
|
|
10
|
+
class Invalid < StandardError; end
|
|
11
|
+
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def encode(payload)
|
|
15
|
+
body = Base64.urlsafe_encode64(JSON.generate(payload), padding: false)
|
|
16
|
+
"#{body}.#{signature(body)}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def decode(token)
|
|
20
|
+
body, supplied = token.to_s.split(".", 2)
|
|
21
|
+
raise Invalid unless body && supplied && secure_compare(signature(body), supplied)
|
|
22
|
+
|
|
23
|
+
JSON.parse(Base64.urlsafe_decode64(body), symbolize_names: true)
|
|
24
|
+
rescue JSON::ParserError, ArgumentError
|
|
25
|
+
raise Invalid
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def fingerprint(token)
|
|
29
|
+
OpenSSL::Digest::SHA256.hexdigest(token.to_s)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def secret
|
|
33
|
+
@secret ||= begin
|
|
34
|
+
configured = ENV["SW_SECRET"]
|
|
35
|
+
unless configured && !configured.empty?
|
|
36
|
+
warn "StreamWeaver: SW_SECRET is not set; action tokens will not work across multiple workers."
|
|
37
|
+
configured = SecureRandom.hex(32)
|
|
38
|
+
end
|
|
39
|
+
configured
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def reset_secret!
|
|
44
|
+
@secret = nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def signature(body)
|
|
48
|
+
Base64.urlsafe_encode64(OpenSSL::HMAC.digest("SHA256", secret, body), padding: false)
|
|
49
|
+
end
|
|
50
|
+
private_class_method :signature
|
|
51
|
+
|
|
52
|
+
def secure_compare(left, right)
|
|
53
|
+
return false unless left.bytesize == right.bytesize
|
|
54
|
+
OpenSSL.fixed_length_secure_compare(left, right)
|
|
55
|
+
end
|
|
56
|
+
private_class_method :secure_compare
|
|
57
|
+
end
|
|
58
|
+
end
|