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
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.3.0] - 2026-09-04
|
|
11
|
+
|
|
12
|
+
First published RubyGems release.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **`streamweaver get-started` — three steps to a guided course** - `gem install stream_weaver; streamweaver install; streamweaver get-started` opens StreamWeaver University: an interactive 5-step course driven from a live canvas controller that launches and directs an agent (Claude Code or Codex) in a worker session. Premier experience on macOS + iTerm2 (auto-arranged windows, one-click step runs, automatic hand-back); degraded browser-tab path everywhere else. Course demos ship in the gem (`streamweaver university-demo <name>`); progress persists across reboots; `streamweaver university-reset` starts over.
|
|
16
|
+
- **`streamweaver install`** - friendlier alias of `setup`: installs the bundled agent skills to both the Claude Code and cross-tool (`.agents/`) skill roots.
|
|
17
|
+
- **`streamweaver canvas-snapshot` / `canvas-restore` / `canvas-restart`** - snapshot every live canvas session (theme + layout + content), restore them, or restart the bridge onto newly installed code without losing sessions.
|
|
18
|
+
- **`streamweaver canvas-raise` / `focus-me`** - bring a canvas pane or the calling iTerm session to the front from the CLI; used by the course choreography, handy anywhere.
|
|
19
|
+
- **Charts render on the live canvas bridge** - `chart type:` initialization now survives poll-driven content swaps (previously charts only rendered on a first page load).
|
|
20
|
+
- **Canvas auto-scroll** - a growing doc follows the bottom when the viewer is already there (and never yanks a reader who scrolled up); full-page reshapes land at the top.
|
|
21
|
+
- **Platform support matrix + canvas-read guide** - README states what is tested (macOS + iTerm2), what degrades, and what is future; `docs/canvas-read.md` documents the document-shelf workflow, with a real-world case study.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
- **Tutorial: "Build My Todos: the StreamWeaver Way"** - The narrated twin of the `streamweaver-way` skill. Where the skill *prescribes* — here are the six laws, here are the four recipes, copy them — the tutorial *narrates*: it rebuilds inline editing, scoped live search, lazy hover cards, and Russian-doll infinite scroll in the order you'd hit them building the app yourself, and every step names three things: the law it obeys, the gotcha it avoids, and the measured number where one exists (deferring a 1.5s region: 0.018s shell vs a 1.508s fragment fetch; hover cards: a 0.085s shell vs 9.151s eager; search: an 800-byte scoped morph vs a 2,123-byte whole-body swap; inline edit: an 806-byte save vs a 108,792-byte page; infinite scroll: O(1) per page vs O(n) per click). The infinite-scroll section teaches Turbo's real shape — current page inline, only the *next* page lazy — and uses the empty-shell bug a clean-room agent hit as its teaching moment: wrapping page N itself in the lazy fragment serves HTML with zero rows in it and only *looks* correct, because page 1's placeholder starts in the viewport, so the reader must `curl` the page rather than trust the screen. Ships in two forms from one outline (`examples/tutorials/tutorial_content.rb`): a `:doc`-theme StreamWeaver app at `examples/tutorials/streamweaver_way_tutorial.rb` and a markdown twin at `docs/tutorials/the-streamweaver-way.md`, regenerated by `ruby examples/tutorials/render_markdown.rb`. `spec/tutorial_twins_spec.rb` fails if the checked-in markdown drifts from the outline, so the twins can't quietly disagree. Every code sample is an extract from `examples/my_todos/`, verified by assembling them into a running four-feature app. Linked from `llms.txt`.
|
|
25
|
+
- **`streamweaver-way` skill — the conventions layer, taught** - A third bundled agent skill (alongside `streamweaver-visual-companion` and `streamweaver-doc-builder`), installed by the same `streamweaver setup` / `streamweaver install-skill` command to both Claude Code's path and the `.agents/skills/` cross-tool alias. It codifies "The StreamWeaver Way" with progressive disclosure: one screen of laws up front — key by what is unique per *position* not by what the content is *about*; deferred over hand-rolled timers; lazy means visible; dev loud, prod self-heals; state your intent in DSL verbs (zero custom JavaScript is the default, not an aspiration); trilaws as design filters — then the four benchmark Turbo Frames recipes (inline editing via `form_for` + `fragment`, scoped live search, lazy hover cards, Russian-doll infinite scroll), each complete and runnable with the two or three gotchas that actually bite, then pointers to the long tail. The gotchas are the ones the parity spike paid for: `text_field ..., updates:` is silently accepted and silently ignored (an input can target only its own enclosing fragment or `#app-container`, so a field placed outside the results fragment swaps the whole container), a lazy fragment inside a tab goes *inside* a `tab` block and never beside one, a named-action button inside a deferred fragment doesn't fire, and hiding a hover card with `visibility: hidden` instead of `display: none` makes every card fetch eagerly. The infinite-scroll recipe teaches Turbo's real shape — **the page the reader is on renders inline, and only the *next* page is lazy** — and names the wrong-but-tempting alternative: wrapping page N itself in the lazy fragment serves HTML with no rows in it at all, and only looks correct because page 1's placeholder starts in the viewport, so the IntersectionObserver fires immediately. `llms.txt` gains a matching "The StreamWeaver Way" section near the top linking each law to its detailed section. Worked example set: `examples/my_todos/`.
|
|
26
|
+
- **Deferred fragments — `fragment :name, defer: true`** - The Turbo `turbo_frame_tag ..., src:` equivalent: the deferred block does not run during the page render at all, so a slow region can't hold the shell hostage. The page ships immediately with a placeholder, and the fragment fetches its own content right after — with no custom JavaScript in app code, just the one option on the verb you already use. Measured on a page with one `sleep 1.5` fragment: initial GET 0.018s (was 1.5s), fragment endpoint 1.508s. `placeholder:` takes a String (rendered as text), a Proc (evaluated as DSL), or nothing (a small spinner). The auto-fetch is an `hx-trigger="load"` POST to the same signed `_sw_fragment` endpoint every in-fragment interaction already uses, so there's no new route and no new authorization path. Nesting works and chains — a deferred fragment inside another loads after its parent — though each fetch re-runs its ancestors' blocks, so nest for staging, not to split one expensive block. Two things to know: the block is skipped on the shell render, so keep action/timer registration outside it; and a *named*-action button (`action: :foo`) inside a deferred fragment does not fire (its token is minted outside the session's action manifest) — use a block button (`button('X') { |s| ... }`), which is unaffected. Static exports run every deferred block inline, since nothing will fetch them later. See `llms.txt` and `examples/deferred_fragments_demo.rb`.
|
|
27
|
+
- **Lazy fragments — `fragment :name, lazy: true`** - Turbo's `loading="lazy"` for deferred fragments: the fetch waits until the fragment is *visible*, whatever made it visible — scrolled into the viewport, or a CSS rule flipping an ancestor out of `display: none`. Two guarantees follow. A CSS-hidden fragment **never** fetches while it stays hidden, which is what makes a zero-JavaScript hover card cost nothing on page load: `display: none` until `:hover`, and revealing it is what fires the fetch. And it fetches **exactly once** — the content lands in the DOM and stays, so hiding and re-showing the region doesn't refetch. Nesting gives you infinite scroll for free, in Turbo's own shape: the page the reader is on renders inline and its block ends by declaring only the *next* page as a lazy fragment, so page N+1 doesn't exist until page N has been scrolled past — no scroll handler, no page counter in state, and the served HTML still carries real rows. (Wrapping page N itself in the lazy fragment is the tempting shape and it's wrong: the block is skipped on the shell render, so nothing but a placeholder goes out.) `lazy: true` implies `defer: true`, so you only write one option. Under the hood the placeholder wrapper carries `hx-trigger="intersect once"` (htmx's `IntersectionObserver`-backed trigger, the same browser API Turbo uses) rather than `hx-trigger="load"`; htmx's other visibility trigger, `revealed`, reads `getBoundingClientRect()` and so counts a hidden element as revealed, which would fetch every hidden fragment on load. A full-container swap re-arms a lazy fragment the way it re-arms a deferred one, but lazily — off-screen when the re-render lands means it waits. See `llms.txt`, `examples/lazy_fragments_demo.rb`, and `docs/research/2026-08-22-lazy-fragments-trigger-decision.md` (which also sketches how route tabs adopt this as the deprecated `tabs ..., lazy: true` mode's successor).
|
|
28
|
+
- **Route tabs — `tabs :view, url: true`** - A tab group's active index lives in a query param (`?view=2`), so a tab is bookmarkable, shareable, and back/forward-aware. Switching is pure client-side History API (`pushState`/`popstate`) — zero requests — and multiple groups compose, one param per key (`/?view=2&panel=1`). On a full GET the URL is authoritative: the param wins when present and valid, and an absent or invalid param means tab 0, *never* the session's value, so the same URL always renders the same tabs. Invalid values degrade rather than error (`?view=999`, `?view=abc`, `?view[]=` all return 200 on tab 0). Two consequences worth knowing: read `state[:view]` *below* the declaration (above it the key still holds the raw pre-authority value), and a `url: true` group can't be server-side preset — `state[:view] ||= 1` above the declaration is overwritten by URL authority. Raises at build time on reserved keys (`app_id`, `splat`, `captures`, `button_id`), duplicate `url:` keys, or `url: true` with `lazy: true`. Ignored on canvas pages (plain client tabs plus one logged warning per render pass), which have no app URL to carry the tab. See `docs/components_reference.md#route-tabs-url-true` and `examples/layout/route_tabs_demo.rb`.
|
|
29
|
+
- **`canvas-read`: live file browser** - A "📁 Browse files…" link in the reader's nav rail opens a live filesystem browser inside the already-running reader — breadcrumbs, folder navigation, and shortcuts to "This repo" and "StreamWeaver (global)" — so you can open a doc saved somewhere else without restarting `canvas-read` with a new path. No index or registered locations: browsing computes fresh on every request, so it finds anything, including docs saved before this shipped. Deliberately read-only (no move/copy/delete — a plain `mv` still does that). Guarded by a new cross-origin request check (Host + `Sec-Fetch-Site`) on every `canvas-read` route, since the file browser's `/open` route evaluates the `.rb` file it's handed and that's now reachable from any tab in your browser, not just a CLI argument you typed yourself.
|
|
30
|
+
- **Mermaid diagrams: expand to full screen** - Every mermaid diagram, regardless of `zoom:`, now gets an expand button that opens it in a full-viewport modal with no width constraint. The in-place `zoom: true` pan/zoom controls help but don't fix the actual problem — a wide diagram's fixed-px labels shrink proportionally to fit whatever doc column width it renders in, no matter how the layout is tuned. Expand re-hosts the already-rendered SVG at natural size with real scroll (scroll/drag to pan, Ctrl+scroll to zoom further, Escape/backdrop-click/close-button to exit). Pure client-side, no new dependency — works identically in the live canvas, `canvas-read`, and any exported doc (including `--offline`).
|
|
31
|
+
- **`--offline` HTML export: mermaid diagrams render in viewers that block every external script** - `streamweaver export <file.rb> --offline` (also `?offline=1` on the reader's `GET /export`, and a second "⬇ Export HTML (offline)" nav link shown only on docs with a mermaid diagram) fetches mermaid's own library at export time and inlines it as a plain `<script>`, instead of referencing its CDN. A plain inline script is covered by a CSP's `unsafe-inline`, so the diagram renders even in a viewer (SharePoint's built-in HTML preview is the motivating case) whose CSP doesn't allowlist any external host at all — the gap the Alpine/htmx fix below couldn't close on its own, since it still referenced mermaid's CDN URL. Doesn't cover `elk: true` diagrams (ELK has no equivalent inlinable build) or any other CDN asset (Chart.js, Prism); needs network access once, at export time, not at view time.
|
|
32
|
+
- **Export a canvas doc to standalone HTML** - "⬇ Export HTML" in `canvas-read`'s nav rail (every file, not just history snapshots) downloads the doc you're viewing as a single self-contained HTML file — same theme/layout, same look, no server required to view it. Same capability from the CLI: `streamweaver export <file.rb> [-o out.html] [--inline-images] [--offline]`. `--inline-images` embeds local images as base64 data URIs so the file is fully portable.
|
|
33
|
+
- **`use_theme`/`use_layout` DSL directives, plus `canvas-read --theme=/--layout=`** - A canvas doc's theme now travels with it: `use_theme :doc` / `use_layout :wide` declared in the DSL (or automatically prepended when you use the "Save as doc" button on a themed canvas session) makes the doc render with that theme wherever it's later opened — `canvas-read` no longer has no way to know a saved file was meant to be `:doc` themed. `canvas-read --theme=doc --layout=wide` sets a fallback for files that declare neither. Precedence: DSL directive > CLI flag > `:default`/`:fluid`.
|
|
34
|
+
- **Human-readable service-mode URLs** - `streamweaver run <file.rb>` now serves apps at slug URLs like `/apps/sales-dashboard` (derived from the app's declared name, falling back to the filename) instead of opaque hashes. The hex `/apps/:app_id` URL still resolves as a canonical fallback. Slugs that collide across different files get a numeric suffix (`-2`, `-3`, ...); re-loading the same file reuses its existing slug.
|
|
35
|
+
- **`endpoint` DSL — the "never rewrite in Sinatra" escape hatch** - Register a real HTTP route (webhook receiver, JSON API, file download) directly from the app DSL: `endpoint(:get, "/api/status") { |req| { ok: true } }`. Supports `:get`/`:post`/`:put`/`:patch`/`:delete`; the block receives the raw `Rack::Request` and its return value maps to a response (`Hash` -> JSON 200, `String` -> HTML 200, `[status, headers, body]` -> passed through verbatim). Endpoints bypass StreamWeaver's state/session/CSRF machinery entirely and always lose to a colliding internal route (`/update`, `/action/*`, `/submit`, `/event/*`, `/form/*`, `/theme/*`, `/sw/*`), with a warning at registration time if that happens. Works in both standalone (`run!`) and multi-app service mode (scoped under `/apps/:app_id/...`). See `docs/endpoints.md`.
|
|
36
|
+
- **`canvas-read` renders `.org` docs, not just `.rb`** - StreamWeaver-flavored org files (marked with `#+STREAMWEAVER_DSL:`) now open in the reader everywhere `.rb` docs do — file lists, the browser, `GET /open`, and rendering — via a server-side detect-then-convert path (`Org::Reader.to_dsl`), the same conversion the browser extension's sandbox has done client-side since it shipped.
|
|
37
|
+
- **`canvas-read` multi-repo doc discovery with repo filter** - The reader now shows every docs root on the machine, grouped by repo and filterable, instead of only the repo it was launched in. Discovery unions two sources: a one-level scan of `$STREAMWEAVER_DOCS_SCAN_ROOTS` (default `~/work`) for `*/docs/streamweaver_canvas`, and an append-only registry at `~/.streamweaver/docs_roots.log` written automatically by "Save as doc" and by `canvas-read <explicit path>` — visiting a doc once backfills its repo, so there is no registration command. Deleted or moved repos drop off on read.
|
|
38
|
+
- **iTerm split-pane install hint** - When `streamweaver panel` falls back to the system browser because the optional `iterm2_ruby` gem isn't installed (but you ARE in iTerm2 on macOS), the CLI now prints a one-line `gem install iterm2_ruby` tip so the split-pane perk is discoverable.
|
|
39
|
+
- **`bin/smoke` — executable UAT smoke test** - Freezes a manual UAT battery into a repeatable script: boots a fixture app in both standalone (`run!`) and multi-app service (`streamweaver serve`) mode on ephemeral ports and drives it over real HTTP, checking the `endpoint` DSL, the reserved-path boot warning, slug/hex `/apps/:id` resolution, endpoint dispatch scoping, and slug collision/reuse. Prints one check/x check line per assertion plus a final summary; exits nonzero on any failure. Wired into CI as the `smoke` job. See `docs/testing.md`.
|
|
40
|
+
|
|
41
|
+
- **`strict_ids` as a global setting, and it degrades in production** - `StreamWeaver.strict_ids = true` (or `SW_STRICT_IDS=1`) opts every app into strict interactive-id checking without threading `strict_ids:` through each `App.new`; an explicit `strict_ids:` still wins. A strict violation now raises in development and test but only warns when `RACK_ENV=production` — a live page shouldn't 500 over an id the framework already auto-disambiguated. Ids stay unique either way. Documented in `llms.txt` under "Interactive IDs and keying".
|
|
42
|
+
- **Feed/canvas-pushed buttons get the same id guarantees as app buttons** - `DisplayDSL#button` (the `FeedBuilder` path behind `feed`, `streamer`, and `canvas-push`) previously had no auto-disambiguation, no `key:`, and no scalar-key validation, so same-label buttons pushed in a loop shared one id. It now shares the App's identity helpers: `key:` for content-stable ids, verbatim `id:`, occurrence-based auto-disambiguation, and `ArgumentError` on a non-scalar key.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
- **`button id:` is now a verbatim id override, and outranks `key:`** - Previously `id:` was an alias for `key:` (hashed into the derived id, and *lost* to `key:` when both were passed). It now sets the emitted id directly — `button "Delete", id: "row-7"` renders `id="btn_delete_row-7"` — which is what you want when SSE pushes, CSS, or tests target the element by selector. Precedence is `id:` > `key:` > auto-derivation from label + block source location. Existing `id:` callers keep working (dispatch has always used the emitted id); only the *shape* of that id changes, from an MD5 hash to your literal value.
|
|
46
|
+
- **`tabs lazy: true` is deprecated** - The POST-morph lazy mode now warns once per process, naming route tabs (`url: true`) as the direction and a future lazy route-tab mode as its replacement. Lazy tabs fetch the newly-active panel with an `hx-post` morph that canvas has no route for, so inactive lazy panels on a canvas page can never receive content (`stream_weaver-pkh`). The warning is the only change — the mode behaves exactly as before, and a compat spec locks that (active-only panel evaluation, the placeholder comment for inactive panels, and the full `hx-post`/`hx-include`/`hx-vals`/`hx-target`/`hx-swap` attribute set).
|
|
47
|
+
- **Built-in tutorial (`streamweaver tutorial`) revamped for the last ~6 months of features** - Refreshed the Themes and Layout/Cards lessons (`:doc` theme, `:sketch` preset, `theme_switcher`/`theme_toggle` auto dark mode, `card_header` `badge:`/`meta:`) and added six new lessons: The Four Modes (standalone/agentic/service/canvas-panel orientation), Navigation (`navbar`/`nav_item`/`link_to` + `route_by`/`route_with`), Resource DSL, Endpoints (the tutorial now registers and self-demonstrates a real `GET /tutorial/api/hello` endpoint), Service Mode, and Canvas/Panel. Also fixed an invalid-Ruby one-liner in the Resource DSL quick-start example (`docs/resource-dsl.md`).
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
- **`route_with`: a `/now`-style dedicated view left open in one tab no longer poisons every sibling tab's clicks** - Session state is one hash per browser (one cookie), not per tab, but `route_with`'s special-view flags were only ever reset by `parser` on a real GET — every POST (`/update`, `/action/:button_id`, `/event/:key`, `/form/:form_name`, and any future POST route) only read them via `builder`. So a tab that navigated to a dedicated view (e.g. `/now`) kept that flag true in the shared session forever, and any OTHER tab's next click inherited it and got pushed there too — even a tab that never touched that view. Fixed by re-running `parser` against the requesting tab's own on-screen URL (htmx already sends this as `HX-Current-URL` on every request) before dispatching any POST, wired as a `before` filter (`server.rb`) / path-scoped `before '/apps/:app_id/*'` filter (`service.rb`, mount-prefix aware so a stale URL for a different mounted app is never misapplied) rather than a per-route call, so a future POST route can't be added without the fix. A raw non-htmx POST has no such header and is left exactly as before. Found live in a downstream app's dashboard from real multi-tab usage. See `docs/routing.md` "Pitfall 3 — one session, many tabs".
|
|
51
|
+
- **A design deck no longer confirms a choice the server never got** - Clicking a deck option checked the card — `.sw-deck-option--selected` plus `aria-checked="true"`, and the checkmark taken off whichever sibling really was selected — and *then* fired a `POST /deck/select` whose response it never looked at. Only `server.rb` mounts the `/deck/*` routes and the deck's JS posts to them by absolute path, so on the canvas bridge, in `canvas-read`, under `streamweaver serve`, and in an exported file that call 404s or never lands at all — and the deck sat there showing a decision nobody recorded. Selection, notes, final notes, Submit, generate-more, and the model selector's per-model click are now all gated on the response — the card is marked only once the server has the choice, with `aria-busy` covering the round trip so the click is still acknowledged — and any deck call that fails is reported to the console naming the route and the status instead of being swallowed. Where nothing serves those routes the deck now renders read-only rather than offering the dead call at all: cards carry `aria-disabled` and `title="Read-only: deck selections need the standalone deck server"`, drop out of the tab order, and the note/generate/submit controls are disabled. That covers the bridge and the reader (known from the render mode) plus exports, service-mode apps, and canvas live-push (each of which builds its own adapter and now declares `deck_server: false`, since an export and the standalone server are otherwise indistinguishable at render time). Standalone deck markup is unchanged, pinned by golden-string specs; the emitted JS is exercised for real under node.
|
|
52
|
+
- **`ComponentRenderer` can render fragments** - `Components::Fragment` asks the view it renders into to track fragment scope, which only the app views implemented — so any app using `fragment` raised `NoMethodError` when rendered through `ComponentRenderer` (static HTML export, `Streamer`, `Feed`). It now tracks scope the same way the app views do.
|
|
53
|
+
- **The bare `defer { ... }` verb raises instead of silently dropping its block** - It was never implemented (an empty method sitting alongside real verbs like `every` and `watch`), so content written inside it simply never appeared, with no error. It now raises and names the real verb, `fragment(:name, defer: true)`.
|
|
54
|
+
- **`canvas-read` no longer renders dead interactive controls** - Buttons and radio groups in a doc opened in the reader used to render as fully live canvas controls, but the reader deliberately omits the canvas bridge's scripts — so clicking a button greyed it out and then threw `ReferenceError: sendEvent is not defined`, and a radio moved its selection for nothing. The reader now renders those controls disabled with a `title="Interactive on live canvas only"` tooltip: honest about being a preview instead of pretending to work. Live canvas rendering (where the bridge *does* define `sendEvent`) is byte-for-byte unchanged.
|
|
55
|
+
- **Tab indices are clamped everywhere** - An out-of-range active tab index (a stale session value, or a group that shrank between renders) now renders tab 0 instead of matching no panel and blanking the group. Applies to plain tabs, not just route tabs.
|
|
56
|
+
- **Standalone param sync no longer leaks route-owned params into state** - Standalone mode strips `app_id`, `splat`, `captures`, and `button_id` from the request params it syncs into state, matching what service mode already did. Previously a route's own plumbing could land in a state key of the same name.
|
|
57
|
+
- **HTML export no longer needs htmx or an unconditional Alpine.js, and mermaid renders without either** - A static export never talks to a server, so `htmx`/`idiomorph` are dropped from every export entirely. Alpine.js now loads only when the rendered doc actually contains an `x-data` directive (checked against the rendered markup itself, not a hardcoded list of component classes, so it can't silently drift as new Alpine-using components are added). Mermaid no longer depends on Alpine at all: `sw-mermaid-zoom.js` self-initializes on `DOMContentLoaded`/`htmx:afterSwap` instead of relying on an `x-init` directive, so a mermaid-only export loads no Alpine and a mermaid diagram never again silently fails to render just because Alpine's external `<script>` didn't load in some CSP-locked-down viewer (e.g. SharePoint's built-in HTML preview). Note: mermaid's own CDN-hosted library is still an external load, so a CSP that blocks *all* external hosts (not just Alpine's) needs the `--offline` diagram-inlining flag above to actually render there.
|
|
58
|
+
- **HTML export no longer silently discards every component** - `HtmlExporter` unconditionally rebuilt the app before rendering, which re-runs the block a standalone `App.new { ... }` was built from — but a canvas doc/history snapshot is `instance_eval`'d from a DSL string into a bare `App` with no block, so the rebuild re-evaluated nothing and wiped every component, exporting an empty page with none of your content. Only rebuilds when there's a block to rebuild from.
|
|
59
|
+
- **`canvas-read` now renders docs the way canvas actually does** - The reader was missing the framework's theme CSS entirely (no `master_theme_css`, no cascade-layer pin) and nested its content wrapper inside an extra `<div>`, so every selector depending on `#app-container` being a direct `<body>` child was dead — `sidebar_toc` rendered as a full-width block instead of a sticky rail, and a doc's declared theme never applied. `canvas-read` now emits the same framework CSS as canvas, keeps `#app-container` a direct body child, and its own file-browser sidebar is a separate collapsible rail (collapses below ~1100px viewport width) that doesn't interfere with a doc's own `sidebar_toc`.
|
|
60
|
+
- **Canvas `sidebar_toc` nav stays sticky again** - Two cascade-layer/specificity bugs caused the TOC sidebar to scroll away instead of staying pinned (desktop) and bounce to the top on every scroll-spy update (mobile). The framework's base CSS is now layer-wrapped alongside `master_theme_css`/`visual_skills_css` (previously it was left unlayered and silently outranked them), and the sidebar's `overflow: visible` override now out-specifies the `#app-container` rule it needs to beat and applies below 1000px too, not just on desktop.
|
|
61
|
+
- **`date_field` now works inside `form`/`scope` blocks** - Previously `date_field` ignored `form_context`/`scope_name` and always emitted a flat top-level `name`/`x-model`, so a date picker inside a `form` or `scope` block silently landed its value outside the intended nested state instead of `state[scope][key]`. It now branches the same way `text_field` does, and also gained `on_change`/`on_blur`/`debounce` callback support and a `render_date_field` stub on `Adapter::Base`/the Opal adapter. `resource`/`form_for` `:date` fields now render a real date picker instead of a plain text field. See `docs/components_reference.md#dates`.
|
|
62
|
+
- **`streamweaver serve` auto-selects a free port** - When 4567 (or the default) is busy, `serve` now increments to the next free port like standalone mode instead of crashing with EADDRINUSE; an explicit `--port` is still honored strictly
|
|
63
|
+
- **`streamweaver panel` browser fallback works beyond macOS** - The fallback now uses the cross-platform `open_browser` helper (`open`/`xdg-open`/`start`) instead of macOS-only `open`
|
|
64
|
+
- **Canvas history ignores empty `STREAMWEAVER_HISTORY_ROOT`** - An empty-string env var no longer redirects history writes to filesystem-root-relative paths
|
|
65
|
+
- **Canvas history writes are atomic** - `History.record` claims snapshot paths with `File::EXCL`, so concurrent writers in the same second get distinct files instead of clobbering each other
|
|
66
|
+
- **Loading a `.run!` app file no longer kills service mode** - `Service.load_app` evaluates app files with a `service_loading` flag set, and `run!` is now a warn-and-no-op while it's active. Previously a file ending in `end.run!` (the documented standalone pattern) started a second server inside the service process and took the whole service down on exit. Standalone `ruby app.rb` behavior is unchanged.
|
|
67
|
+
|
|
68
|
+
### Fixed
|
|
69
|
+
- Plain `gem install` no longer crashes on load: the Opal compiler is now an optional, lazily-required dependency (`gem install opal` only if you use `opal-build`).
|
|
70
|
+
- Org export tolerates interactive components (forms save cleanly as `.org`, controls omitted with a marker; the `.rb` sibling keeps full fidelity).
|
|
71
|
+
|
|
72
|
+
## [0.2.0] - 2026-07-05
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
- **`iterm2_ruby` is now an optional enhancement, not a runtime dependency** - `gem install stream_weaver` no longer requires it; iTerm2 split-pane browser panes activate when the (now published) `iterm2_ruby` gem is installed (`gem install iterm2_ruby`), otherwise panel/canvas commands fall back to opening the system browser
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
- **Canvas theme support** - Canvas/panel sessions can now use the `:doc` theme (and any registered theme): `streamweaver panel my-session --theme=doc`. Canvas sessions default to `:default` as before; the canvas page now reuses the same theme CSS (including dark-mode variants) as full-page rendering, so the mermaid dark-mode fix also applies in canvas mode.
|
|
79
|
+
- **`CardHeader` `badge:` / `meta:` options** - `card_header "Title", badge: "C1", meta: "right-aligned text"` renders a mono badge before the title and right-aligned meta text after it, for compact labeled card headers.
|
|
80
|
+
- **Puma-dev support** - Run StreamWeaver apps with memorable URLs like `http://myapp.test`:
|
|
81
|
+
- Detects `PORT` environment variable (set by Puma-dev and PaaS platforms)
|
|
82
|
+
- Skips auto-browser opening when `PORT` is set for on-demand access
|
|
83
|
+
- Provides `config.ru` example in `examples/puma_dev/`
|
|
84
|
+
- See [examples/puma_dev/README.md](examples/puma_dev/README.md) for setup guide
|
|
85
|
+
|
|
86
|
+
### Fixed
|
|
87
|
+
- **Mermaid diagrams stayed light in dark mode** - Diagrams didn't re-render when the page switched to dark mode, and modern CSS color functions (`oklch()`, `color-mix()`) in theme tokens crashed Mermaid's color parser. Diagrams now re-render on theme change, and colors are resolved through a canvas probe so Mermaid always receives plain `rgb()`.
|
|
88
|
+
- **`theme_toggle` `mode:` was a dead parameter** - `theme_toggle mode: :light` (or `:dark`) had no effect on first-page-load behavior; the page always defaulted to following OS `prefers-color-scheme` regardless of `mode:`. `AutoMode.inline_script`/`.alpine_data` now accept the component's `mode:` as the localStorage-fallback default, so `mode: :light`/`:dark` actually forces that theme until the user toggles.
|
|
89
|
+
- **Puma thread pool exhaustion** - SSE streaming apps could hang when opening multiple browser tabs; increased default Puma thread pool from 5 to 16 to accommodate long-lived SSE connections
|
|
90
|
+
- **Canvas-push error feedback** - DSL errors now reported to stderr with exit code 1, enabling Claude to see and fix syntax errors
|
|
91
|
+
- **Tutorial checkbox syntax** - Fixed incorrect `checkbox :key, label: "text"` to correct `checkbox :key, "text"` in learn.md examples
|
|
92
|
+
- **iTerm panel stability** - AppleScript keystrokes could hang or type into wrong window; now opens URL in external browser instead
|
|
93
|
+
|
|
94
|
+
### Added
|
|
95
|
+
- **`navbar` / `nav_item` / `link_to` components** - Cross-app navigation bar DSL. `navbar` renders a horizontal nav bar; `nav_item` renders as a bold non-clickable span when `active: true` or a link otherwise; `link_to` renders an inline anchor element.
|
|
96
|
+
```ruby
|
|
97
|
+
navbar do
|
|
98
|
+
nav_item "Dashboard", active: true
|
|
99
|
+
nav_item "Settings", href: "/settings"
|
|
100
|
+
end
|
|
101
|
+
link_to "Docs", href: "https://example.com"
|
|
102
|
+
```
|
|
103
|
+
- **`--reset` flag** - Clear corrupted session state on any app: `ruby my_app.rb --reset`. One-shot clear on first page load, then normal operation resumes
|
|
104
|
+
- **`SW_DEBUG` env var** - Request-level debug logging for troubleshooting: `SW_DEBUG=1 ruby my_app.rb`. Logs request method, path, cookie/state sizes, and SSE connection counts
|
|
105
|
+
- **StatusDot `label:` option** - Display text labels below status dots:
|
|
106
|
+
```ruby
|
|
107
|
+
status_dot status: :green, pulse: true, label: "billing.rb"
|
|
108
|
+
```
|
|
109
|
+
- **Canvas Mode CSS** - Full component styling in canvas/panel mode:
|
|
110
|
+
- Progress bars with animated stripes
|
|
111
|
+
- Spinners with rotation animation
|
|
112
|
+
- Status dots with pulse animation and labels
|
|
113
|
+
- Badges, alerts, activity items
|
|
114
|
+
- Tables with striped rows and sortable headers
|
|
115
|
+
- Collapsible sections, hstack/vstack spacing
|
|
116
|
+
- **Canvas Syntax Highlighting** - Code blocks in canvas mode now have syntax highlighting via highlight.js (github theme)
|
|
117
|
+
- **Canvas Charts** - Chart.js support in canvas mode for bar_chart, line_chart, etc.
|
|
118
|
+
- **`git_health.sh` example** - Dynamic git repository analyzer:
|
|
119
|
+
- Scans real git history, generates custom health dashboard
|
|
120
|
+
- Charts showing commit patterns by day of week
|
|
121
|
+
- Author contribution tables with sorting
|
|
122
|
+
- Contextual recommendations based on findings
|
|
123
|
+
- Different results each run based on actual repo state
|
|
124
|
+
- **Enhanced `panel_demo.sh`** - 4-step workflow showcasing canvas capabilities:
|
|
125
|
+
- Step 1: Issue selection (cards, badges, checkboxes, radio groups)
|
|
126
|
+
- Step 2: Diff preview (side-by-side columns, alerts)
|
|
127
|
+
- Step 3: Progress animation (spinner, progress bar, status dots, activity log)
|
|
128
|
+
- Step 4: Results summary (badges, alerts, sortable table, collapsibles)
|
|
129
|
+
- **Canvas Mode** - IPC system for external apps to push rich UI:
|
|
130
|
+
- Persistent browser canvas for agentic CLIs to display interactive UI
|
|
131
|
+
- WebSocket + HTTP bridge for bidirectional communication
|
|
132
|
+
- `streamweaver panel SESSION` - Open canvas in iTerm2 split pane (side-by-side with terminal)
|
|
133
|
+
- `streamweaver canvas-push SESSION` - Push DSL content to canvas
|
|
134
|
+
- `streamweaver canvas-wait SESSION` - Wait for button click, return JSON (ignores radio/checkbox)
|
|
135
|
+
- `streamweaver setup` - Configure Claude Code with bash permissions and panel skill
|
|
136
|
+
- High-level Ruby helpers: `Canvas.pick(session, options)`, `Canvas.confirm(session, message)`
|
|
137
|
+
- See [docs/canvas-roadmap.md](docs/canvas-roadmap.md) for full documentation
|
|
138
|
+
- **Button `id:` option** - Disambiguate buttons in loops to prevent callback collisions:
|
|
139
|
+
```ruby
|
|
140
|
+
items.each { |i| button "Select", id: i[:name] do |s| ... end }
|
|
141
|
+
```
|
|
142
|
+
- **Templates** - Pre-built UI patterns for common interactions:
|
|
143
|
+
- `wizard` - Multi-step forms with branching (`next: {branch_on: "field_name"}`)
|
|
144
|
+
- `choices` - Quick selection from options, returns `{choice: "Selected"}`
|
|
145
|
+
- `confirm` - Yes/No decisions, returns `{confirmed: true/false}`
|
|
146
|
+
- `info` - Display messages with action buttons, returns `{action: "Clicked"}`
|
|
147
|
+
- `table` - Data display with optional row selection
|
|
148
|
+
- `code` - Code display with syntax highlighting and line numbers
|
|
149
|
+
- `diff` - Unified diff display with add/remove highlighting
|
|
150
|
+
- Usage: `streamweaver template <name> <session> '<json-config>'`
|
|
151
|
+
- See [docs/templates.md](docs/templates.md) for full documentation
|
|
152
|
+
- **Dashboard Components** - Operations dashboard UI elements (best with `theme: :dark`):
|
|
153
|
+
- `status_dot` - Colored status indicators with optional pulse animation
|
|
154
|
+
- `badge` - Pill-shaped badges with variant colors (`:default`, `:danger`, `:warning`, `:success`)
|
|
155
|
+
- `stat_display` - Large value + label statistics (e.g., "42 TASKS")
|
|
156
|
+
- `type_tag` - Activity type badges (`:research`, `:task`, `:decision`, `:planning`)
|
|
157
|
+
- `pulse_indicator` - Animated system status indicators
|
|
158
|
+
- `priority_item` - Priority-colored items (`:critical`, `:high`, `:medium`, `:low`)
|
|
159
|
+
- `activity_item` - Time-stamped activity feed entries
|
|
160
|
+
- `app_shell` - Dashboard layout with main area and collapsible sidebar
|
|
161
|
+
- `expandable_card` - Cards that expand/collapse to show details
|
|
162
|
+
- **Table Component Enhancements**:
|
|
163
|
+
- `markdown: true` option for clickable links in table cells
|
|
164
|
+
- Smart header inference from array of hashes (no need to specify headers)
|
|
165
|
+
- Column DSL with formatters: `column :balance, format: :currency, align: :right`
|
|
166
|
+
- Built-in formatters: `:currency`, `:date`, `:number`, `:percent`, `:boolean`
|
|
167
|
+
- Interactive features: `sortable: true`, `sticky_header: true`
|
|
168
|
+
- Styling options: `striped: true`, `bordered: true`, `hoverable: true`, `compact: true`
|
|
169
|
+
- **Dark Theme** - Full dark mode with deep backgrounds, glow effects, and dashboard styling
|
|
170
|
+
- **`default:` option** for `text_field`, `text_area`, and `code_editor` to set initial values
|
|
171
|
+
- **Service Mode** - Single server renders multiple apps without per-app process management:
|
|
172
|
+
- `streamweaver <file.rb>` - Run app (auto-starts service if needed)
|
|
173
|
+
- `streamweaver list` - List all loaded apps with timing info
|
|
174
|
+
- `streamweaver remove <id>` - Remove a specific app
|
|
175
|
+
- `streamweaver clear` - Remove all apps
|
|
176
|
+
- `streamweaver admin` - Open admin dashboard
|
|
177
|
+
- `streamweaver status` - Show service status
|
|
178
|
+
- `streamweaver stop` - Stop background service
|
|
179
|
+
- Named sessions via `--name` flag for easier identification
|
|
180
|
+
- **Admin Dashboard** - StreamWeaver app managing other StreamWeaver apps (meta!)
|
|
181
|
+
- Shows service stats (apps loaded, PID, port)
|
|
182
|
+
- Lists all apps with timing (loaded/idle duration)
|
|
183
|
+
- Open/Remove buttons for each app
|
|
184
|
+
- Clear All Apps action
|
|
185
|
+
- **Multi-app routing** - Each app gets unique URL (`/apps/:app_id`)
|
|
186
|
+
- **URL prefix support** in adapter for service mode routing
|
|
187
|
+
- **Multi-theme system** with three built-in themes:
|
|
188
|
+
- `:default` - Warm Industrial (Source Sans 3, 17px, generous spacing)
|
|
189
|
+
- `:dashboard` - Data Dense (15px, tighter spacing, minimal accents)
|
|
190
|
+
- `:document` - Reading Mode (Crimson Pro serif, 19px, paper background)
|
|
191
|
+
- **Custom theme registration** via `StreamWeaver.register_theme`
|
|
192
|
+
- **Runtime theme switching** via `theme_switcher` component
|
|
193
|
+
- **Theme Tweaker app** (`examples/theme_tweaker.rb`) - Visual theme editor with live preview and export
|
|
194
|
+
- **`submit: false` option** for form components to disable HTMX auto-submit:
|
|
195
|
+
- `text_field :key, submit: false`
|
|
196
|
+
- `checkbox :key, "Label", submit: false`
|
|
197
|
+
- `select :key, choices, submit: false`
|
|
198
|
+
- `button "Label", submit: false` (display-only button)
|
|
199
|
+
- **Adapter pattern** for rendering - `StreamWeaver::Adapter::AlpineJS` handles all framework-specific rendering
|
|
200
|
+
- **New components**:
|
|
201
|
+
- **Charts** via Chart.js (CDN-loaded only when charts present):
|
|
202
|
+
- `BarChart` / `bar_chart` / `hbar_chart` - Bar charts (vertical/horizontal)
|
|
203
|
+
- `LineChart` / `line_chart` - Line charts with fill, smooth, points options
|
|
204
|
+
- `PieChart` / `pie_chart` / `doughnut_chart` - Pie and doughnut charts
|
|
205
|
+
- `StackedBarChart` / `stacked_bar_chart` - Multi-series stacked/grouped bars
|
|
206
|
+
- `sparkline` - Compact inline trends (no axes/labels)
|
|
207
|
+
- `area_chart` - Line chart with fill (shorthand)
|
|
208
|
+
- Multiple data input modes: inline hash, file+path, explicit labels/values, state-bound
|
|
209
|
+
- File loading with dot-path extraction (e.g., `"entries.-1.phases"`)
|
|
210
|
+
- `Markdown` / `md` - Full GitHub Flavored Markdown via Kramdown
|
|
211
|
+
- `Header` with `header1`-`header6` helpers for semantic headers
|
|
212
|
+
- `TextArea` for multi-line text input
|
|
213
|
+
- `RadioGroup` for single-choice radio buttons
|
|
214
|
+
- `Card` for styled content containers with `card_header`, `card_body`, `card_footer`
|
|
215
|
+
- `Collapsible` for expandable/collapsible sections
|
|
216
|
+
- `Columns` and `Column` for multi-column layouts with custom widths
|
|
217
|
+
- `Form` with `submit`/`cancel` for deferred submission forms (client-side only until submit)
|
|
218
|
+
- `ScoreTable` for color-coded metrics display
|
|
219
|
+
- `LessonText`, `Term`, `Phrase` for educational content with glossary tooltips
|
|
220
|
+
- `CheckboxGroup` with `item` for batch selection with select all/none
|
|
221
|
+
- `StatusBadge` for visual match indicators (🟢 Strong / 🟡 Maybe / 🔴 Skip)
|
|
222
|
+
- `TagButtons` for quick-select tag groups (single-select with destructive style option)
|
|
223
|
+
- `ExternalLinkButton` for buttons that open URLs in new tabs (with optional form submit)
|
|
224
|
+
- **Layout components**:
|
|
225
|
+
- `VStack` for vertical stacking with spacing and dividers
|
|
226
|
+
- `HStack` for horizontal stacking with alignment and justify options
|
|
227
|
+
- `Grid` for responsive grid layouts with breakpoint columns (`[1, 2, 3]`)
|
|
228
|
+
- **Navigation components**:
|
|
229
|
+
- `Tabs` with `tab` for tabbed navigation (variants: `:line`, `:enclosed`, `:soft-rounded`)
|
|
230
|
+
- `Breadcrumbs` with `crumb` for hierarchical navigation trails
|
|
231
|
+
- `Dropdown` with `trigger`, `menu`, `menu_item`, `menu_divider` for action menus
|
|
232
|
+
- **Modal dialogs**:
|
|
233
|
+
- `Modal` with `modal_footer` for overlay dialogs (sizes: `:sm`, `:md`, `:lg`, `:xl`)
|
|
234
|
+
- State-driven open/close via `state[:modal_key_open]`
|
|
235
|
+
- **Feedback components**:
|
|
236
|
+
- `Alert` for static feedback messages (variants: `:info`, `:success`, `:warning`, `:error`)
|
|
237
|
+
- `ToastContainer` with `show_toast`/`clear_toasts` for stacked notifications
|
|
238
|
+
- `ProgressBar` for visual progress indicators with variants and animation
|
|
239
|
+
- `Spinner` for loading indicators with sizes and labels
|
|
240
|
+
- **Event callbacks**:
|
|
241
|
+
- `on_change` callback for text_field, checkbox, select
|
|
242
|
+
- `on_blur` callback for text_field, text_area
|
|
243
|
+
- `debounce:` option for text input callbacks
|
|
244
|
+
- **Custom component modules** via `components:` option on `app`
|
|
245
|
+
- **Layout modes** via `layout:` parameter: `:default` (900px), `:wide` (1100px), `:full` (1400px), `:fluid` (100%)
|
|
246
|
+
- `default:` option for `select` component to set initial value
|
|
247
|
+
- `auto_close_window:` option for `run_once!` to close browser after submit
|
|
248
|
+
- Automatic "Submit to Agent" button in agentic mode
|
|
249
|
+
- CSS custom properties (CSS variables) for theme customization
|
|
250
|
+
- Comprehensive inline CSS with modern styling
|
|
251
|
+
|
|
252
|
+
### Changed
|
|
253
|
+
- `Text` component now renders literal text only (no markdown parsing)
|
|
254
|
+
- Refactored component rendering to use adapter pattern for future extensibility
|
|
255
|
+
- **New "Warm Industrial" theme**: Source Sans 3 font, terracotta primary color (#c2410c), 17px base font with 1.7 line-height
|
|
256
|
+
|
|
257
|
+
### Fixed
|
|
258
|
+
- **Canvas panel iTerm2 integration** - Panel now opens in split pane beside terminal
|
|
259
|
+
- **Canvas bridge port conflicts** - Auto-finds available port instead of hardcoded 4568
|
|
260
|
+
- **Canvas bridge race condition** - Waits for HTTP server health before returning URL
|
|
261
|
+
- **Canvas bridge reuse** - Verifies HTTP health on existing bridge before reusing
|
|
262
|
+
- **iTerm2 URL navigation** - Adds Escape keys to dismiss autocomplete before typing URL
|
|
263
|
+
- **Canvas-wait event filtering** - Now filters for 'action' events by default (button clicks only), ignoring checkbox/radio changes
|
|
264
|
+
- **Canvas 'Submitted' feedback** - Only shows for button clicks, not radio/checkbox changes
|
|
265
|
+
- **Canvas card styling** - Cards now render with proper borders, backgrounds, and the terracotta left accent
|
|
266
|
+
- **Canvas checkbox rendering** - Checkboxes wrapped in proper div with aligned label, inline markdown parsed
|
|
267
|
+
- Checkbox state properly handles unchecked values
|
|
268
|
+
- Agentic mode correctly outputs JSON to STDOUT after form submission
|
|
269
|
+
- Select `default:` now properly initializes Alpine.js state
|
|
270
|
+
- **Table markdown cells** - Use correct Phlex raw/safe pattern for markdown rendering in table cells
|
|
271
|
+
- **Table data: keyword** - Support `data:` keyword argument in table DSL method for explicit data passing
|
|
272
|
+
- **Tutorial session overflow** (2026-01-02) - Session cookie was exceeding 4KB limit due to `*_edited_code` keys; now filtered from session storage
|
|
273
|
+
- **Tutorial button ID mismatch** (2026-01-02) - Button IDs now use stable hash from `block.source_location` instead of render-order counter, preventing action failures when conditional content changes component tree
|
|
274
|
+
- **Tutorial Reset button** (2026-01-02) - Reset always renders with block for stable ID; uses flag pattern to survive session filtering
|
|
275
|
+
|
|
276
|
+
## [0.1.0] - 2025-11-08
|
|
277
|
+
|
|
278
|
+
### Added
|
|
279
|
+
- Initial release of StreamWeaver gem
|
|
280
|
+
- Core DSL for building interactive UIs with `app` helper method
|
|
281
|
+
- MVP components: TextField, Button, Text, Div, Checkbox, Select
|
|
282
|
+
- Sinatra-based web server with automatic port detection
|
|
283
|
+
- Phlex-based HTML rendering with inline CSS
|
|
284
|
+
- HTMX + Alpine.js frontend reactivity
|
|
285
|
+
- Session-based state management
|
|
286
|
+
- Single-file execution with `run!` method
|
|
287
|
+
- Browser auto-opening (cross-platform: macOS/Linux/Windows)
|
|
288
|
+
- **Agentic mode** with `run_once!` method for AI agent workflows
|
|
289
|
+
- Documentation and examples
|
|
290
|
+
- RSpec test suite
|
|
291
|
+
|
|
292
|
+
[Unreleased]: https://github.com/fkchang/stream_weaver/compare/v0.2.0...HEAD
|
|
293
|
+
[0.2.0]: https://github.com/fkchang/stream_weaver/compare/v0.1.0...v0.2.0
|
|
294
|
+
[0.1.0]: https://github.com/fkchang/stream_weaver/releases/tag/v0.1.0
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Project Instructions for AI Agents
|
|
2
|
+
|
|
3
|
+
This file provides instructions and context for AI coding agents working on this project.
|
|
4
|
+
|
|
5
|
+
## Work tracking authority
|
|
6
|
+
|
|
7
|
+
Tyrion is authoritative for all new StreamWeaver work. Run `tyrion prime` and
|
|
8
|
+
`tyrion status` at session start, and use the Tyrion skills for shaping, importing,
|
|
9
|
+
claiming, implementing, gating, checkpointing, and completing stories.
|
|
10
|
+
|
|
11
|
+
Beads remains readable only as a legacy backlog. Existing Beads IDs may be searched,
|
|
12
|
+
updated, and closed, but never use `bd create`, `bd ready`, `bd update --claim`, or
|
|
13
|
+
`bv` to create or select new work. Re-home still-relevant legacy work in Tyrion and
|
|
14
|
+
record the Beads ID in the Tyrion note/evidence trail.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Build & Test
|
|
18
|
+
|
|
19
|
+
_Add your build and test commands here_
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Example:
|
|
23
|
+
# npm install
|
|
24
|
+
# npm test
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Architecture Overview
|
|
28
|
+
|
|
29
|
+
_Add a brief overview of your project architecture_
|
|
30
|
+
|
|
31
|
+
## Visual Output
|
|
32
|
+
|
|
33
|
+
Whenever about to show something visually — a UI mockup, diagram, dashboard, layout/design comparison, or long-form doc — use the `streamweaver-visual-companion` skill. Do NOT use the `Artifact` tool, and do NOT write a local HTML file and open/screenshot it via Chrome browser tools (claude-in-chrome, superpowers-chrome, playwright) for this purpose. StreamWeaver's canvas-push is 5-7x cheaper in tokens than the chrome route and avoids GEA session conflicts. The skill's own "Fall back to Artifact only when..." section covers the rare exceptions (StreamWeaver unavailable, or a claude.ai-hosted link that must persist/reach someone outside this repo).
|
|
34
|
+
|
|
35
|
+
## Conventions & Patterns
|
|
36
|
+
|
|
37
|
+
### Git Hygiene Policy
|
|
38
|
+
|
|
39
|
+
This repo is destined for **open source release**. Every commit is a candidate for public history — git history cannot be sanitized after the fact without rewriting it.
|
|
40
|
+
|
|
41
|
+
**Staging rules:**
|
|
42
|
+
|
|
43
|
+
- NEVER use `git add -A`, `git add .`, or `git add -u`. Stage explicit paths only, and only files you created or intentionally changed for the task at hand.
|
|
44
|
+
- Every staged file must be StreamWeaver-related. Personal tooling state (`.registry/`, `.serena/`, `.beads/`), build artifacts (`dist/`, `*.gem`), and session/agent scratch content stay out (most are gitignored — if you see one in `git status`, add it to `.gitignore` rather than committing it).
|
|
45
|
+
- Do not commit content containing personal info: home directory paths (`/Users/...`), personal emails, employer references, real names of testers/colleagues, travel/location details. Use placeholders or relative paths.
|
|
46
|
+
|
|
47
|
+
**Enforcement:**
|
|
48
|
+
|
|
49
|
+
- `bin/check_git_hygiene` runs automatically from `.githooks/pre-commit`. It BLOCKS on home paths, personal email, personal-system references, secret-shaped strings, and staged files over 500KB; it WARNS on employer/tester-name references (full pattern list lives in the script itself, which is exempt from its own scan).
|
|
50
|
+
- False positive? Bypass once with `SW_HYGIENE_SKIP=1 git commit ...` — never disable the hook itself.
|
|
51
|
+
|
|
52
|
+
**Before the public flip (tracked in epic stream_weaver-b9g):**
|
|
53
|
+
|
|
54
|
+
- Full-history scan for the block patterns (e.g. `gitleaks` or `git log -S`), docs/ cleanup (stream_weaver-wh2), and repo hygiene sweep (stream_weaver-kj0).
|
|
55
|
+
- Decide the public committer identity — history currently uses a work email.
|
|
56
|
+
|
|
57
|
+
<!-- BEGIN TYRION-MANAGED-BLOCK v1 sha256:bc9a54f4421ec81e87306bdadc00e7524d992aaa63e04ed655f8670b5cd1bc0f -->
|
|
58
|
+
## Tyrion
|
|
59
|
+
|
|
60
|
+
This repo is tracked by Tyrion, a resumability ledger for coding agents.
|
|
61
|
+
|
|
62
|
+
Rules:
|
|
63
|
+
- claim before code (tyrion claim-next)
|
|
64
|
+
- evidence via tyrion note/check, not ad hoc
|
|
65
|
+
|
|
66
|
+
Run `tyrion prime` for the live session briefing — active epic/story, next action, unmet criteria.
|
|
67
|
+
<!-- END TYRION-MANAGED-BLOCK -->
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Forrest Chang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|