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/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example_dsl.rb
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Inner DSL for the Calendar-Driven Travel State PRD.
|
|
3
|
+
# Intended for canvas-push: streamweaver canvas-push <session> < examples/components/prd_dsl.rb
|
|
4
|
+
# For standalone app with theme: ruby examples/components/prd_demo.rb
|
|
5
|
+
|
|
6
|
+
sidebar_toc sections: [
|
|
7
|
+
{ id: "problem", label: "Problem Statement" },
|
|
8
|
+
{ id: "principle", label: "Design Principle" },
|
|
9
|
+
{ id: "architecture", label: "Architecture" },
|
|
10
|
+
{ id: "c1", label: "Component 1: Enforcement" },
|
|
11
|
+
{ id: "c2", label: "Component 2: Sync Script" },
|
|
12
|
+
{ id: "c3", label: "Component 3: Checkin Gate" },
|
|
13
|
+
{ id: "data-model", label: "Data Model" },
|
|
14
|
+
{ id: "integrations", label: "Integration Points" },
|
|
15
|
+
{ id: "scope", label: "Scope" },
|
|
16
|
+
{ id: "success", label: "Success Criteria" },
|
|
17
|
+
{ id: "open", label: "Open Questions" }
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
doc_header(
|
|
21
|
+
eyebrow: "aria · Personal OS",
|
|
22
|
+
title: "Calendar-Driven Travel State",
|
|
23
|
+
pills: [
|
|
24
|
+
{ text: "Draft" },
|
|
25
|
+
"June 25, 2026",
|
|
26
|
+
"Author: Maya Chen",
|
|
27
|
+
"Owner: scheduler secretary + aria_dev"
|
|
28
|
+
]
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# 01 — Problem Statement
|
|
32
|
+
doc_section_header "01", "Problem Statement", id: "problem"
|
|
33
|
+
md <<~MD
|
|
34
|
+
During the June 24 daily checkin, the grandmaster analysis fabricated "Austin, Texas"
|
|
35
|
+
as Maya's location throughout — she was in Frederick, Maryland. The cause was a
|
|
36
|
+
two-part failure:
|
|
37
|
+
|
|
38
|
+
1. `current-state.yaml` didn't exist at checkin time, so Claude had no ground truth
|
|
39
|
+
2. Claude pattern-matched "the Rio" (a Maryland venue) against prior journal context
|
|
40
|
+
that had mentioned Austin, and confabulated a coherent but entirely wrong narrative
|
|
41
|
+
MD
|
|
42
|
+
callout(variant: :warning, title: "Root cause:") do
|
|
43
|
+
text "Stale or absent location context causes Claude to infer location from indirect signals. " \
|
|
44
|
+
"Confident wrong inferences propagate silently through analysis — they don't look uncertain, " \
|
|
45
|
+
"they look authoritative."
|
|
46
|
+
end
|
|
47
|
+
md "The immediate fix (creating `current-state.yaml` and adding the Ask-Don't-Fabricate directive) " \
|
|
48
|
+
"addresses the symptom. This PRD addresses the cause: `current-state.yaml` was created as a " \
|
|
49
|
+
"manually-maintained file, which will inevitably go stale when juggling 20+ concurrent " \
|
|
50
|
+
"sessions with no bandwidth to remember to update a doc."
|
|
51
|
+
|
|
52
|
+
# 02 — Design Principle
|
|
53
|
+
doc_section_header "02", "Design Principle: Calendar Is Truth", id: "principle"
|
|
54
|
+
md "Maya already maintains two calendars — Outlook (work PTO, flights, meetings) and Google " \
|
|
55
|
+
"(family events). These are the existing ground truth for where she is and what she's doing. " \
|
|
56
|
+
"Rather than maintaining a parallel file, the system should read from what already exists."
|
|
57
|
+
mermaid <<~MERMAID
|
|
58
|
+
graph LR
|
|
59
|
+
A["Calendar<br/>Outlook + Google<br/><i>ground truth</i>"]
|
|
60
|
+
B["bin/sync-travel-state<br/>daily derivation"]
|
|
61
|
+
C["current-state.yaml<br/>read-only cache"]
|
|
62
|
+
D["Claude sessions<br/>consume, never write"]
|
|
63
|
+
A --> B --> C --> D
|
|
64
|
+
style A fill:#EEF2FF,stroke:#1E4ED8,color:#1E4ED8
|
|
65
|
+
MERMAID
|
|
66
|
+
callout(variant: :info, title: "Process change required:") do
|
|
67
|
+
text "Driving trips (e.g., Austin) have no flights to detect. The convention is: all travel — " \
|
|
68
|
+
"personal or work, driving or flying — must have an Outlook PTO block before the system " \
|
|
69
|
+
"will track it. The cabinet enforces this rather than relying on memory."
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# 03 — Architecture
|
|
73
|
+
doc_section_header "03", "Architecture Overview", id: "architecture"
|
|
74
|
+
md "Three components work together. Each has a single responsibility."
|
|
75
|
+
table(
|
|
76
|
+
headers: ["Component", "Responsibility", "Owner", "Trigger"],
|
|
77
|
+
rows: [
|
|
78
|
+
["Enforcement", "Require calendar entry before travel is acknowledged", "scheduler secretary", "Any travel mention"],
|
|
79
|
+
["bin/sync-travel-state", "Read calendars → write current-state.yaml", "launchd / morning brief","Daily 6am + post-checkin"],
|
|
80
|
+
["Checkin gate", "Human confirms derived state is accurate", "aria-checkin Step 0", "Every daily checkin"]
|
|
81
|
+
]
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# 04 — Component 1
|
|
85
|
+
doc_section_header "04", "Component 1: Calendar Entry Enforcement", id: "c1"
|
|
86
|
+
card do
|
|
87
|
+
card_header "Scheduler Secretary Behavior", badge: "C1", meta: "secretary work cycle + direct requests"
|
|
88
|
+
card_body do
|
|
89
|
+
md <<~MD
|
|
90
|
+
When travel is mentioned in any context — daily checkin narrative, voicenote, direct
|
|
91
|
+
message to scheduler — the secretary checks for a corresponding calendar entry before
|
|
92
|
+
acknowledging or routing the trip.
|
|
93
|
+
|
|
94
|
+
### Detection Triggers
|
|
95
|
+
|
|
96
|
+
- User says "I'm going to X" / "we're traveling to X" / "trip to X"
|
|
97
|
+
- Voicenote mentions destination + date range
|
|
98
|
+
- Checkin narrative references upcoming travel not in calendar
|
|
99
|
+
|
|
100
|
+
### Behavior: entry exists
|
|
101
|
+
|
|
102
|
+
Acknowledge and flag for sync script to pick up at next run. No further action.
|
|
103
|
+
|
|
104
|
+
### Behavior: no entry found
|
|
105
|
+
|
|
106
|
+
Create the calendar entry via `aria-outlook` or `aria-google`, confirm with user,
|
|
107
|
+
then acknowledge. Secretary does _not_ write to `current-state.yaml` — that is
|
|
108
|
+
exclusively the sync script's domain.
|
|
109
|
+
|
|
110
|
+
#### Entry format (Outlook PTO)
|
|
111
|
+
MD
|
|
112
|
+
code_block(<<~TXT, lang: "text")
|
|
113
|
+
Title: Maya – PTO [Destination]
|
|
114
|
+
e.g., "Maya – PTO Maryland"
|
|
115
|
+
"Maya – PTO Austin"
|
|
116
|
+
Type: All-day event, multi-day
|
|
117
|
+
Calendar: Outlook personal
|
|
118
|
+
TXT
|
|
119
|
+
md <<~MD
|
|
120
|
+
#### Entry format (work travel)
|
|
121
|
+
MD
|
|
122
|
+
code_block(<<~TXT, lang: "text")
|
|
123
|
+
Title: [Trip name] e.g., "Meridian Analytics summer trip 2026"
|
|
124
|
+
Flight events are detected separately; PTO block still required
|
|
125
|
+
Type: All-day event
|
|
126
|
+
Calendar: Outlook work
|
|
127
|
+
TXT
|
|
128
|
+
md "### Type Inference Rules"
|
|
129
|
+
table(
|
|
130
|
+
headers: ["Title pattern", "Inferred type"],
|
|
131
|
+
rows: [
|
|
132
|
+
["contains \"Meridian\" / \"work\" / trip name from work context", "work"],
|
|
133
|
+
["\"Maya – PTO [Destination]\" with no work keywords", "vacation"],
|
|
134
|
+
["Flight pair without PTO block (day trip)", "work"],
|
|
135
|
+
["Google family calendar multi-day event", "vacation"]
|
|
136
|
+
]
|
|
137
|
+
)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# 05 — Component 2
|
|
142
|
+
doc_section_header "05", "Component 2: bin/sync-travel-state", id: "c2"
|
|
143
|
+
card do
|
|
144
|
+
card_header "Calendar Sync Script", badge: "C2", meta: "bin/sync-travel-state · Ruby"
|
|
145
|
+
card_body do
|
|
146
|
+
md <<~MD
|
|
147
|
+
Reads both calendars, derives travel state, overwrites `current-state.yaml`.
|
|
148
|
+
Idempotent — safe to run multiple times per day.
|
|
149
|
+
|
|
150
|
+
### Calendar Sources
|
|
151
|
+
|
|
152
|
+
- **Outlook** — via `aria-outlook calendar list`. Reads 60-day window. Detects: PTO
|
|
153
|
+
all-day events, flight events (title contains "flight" / airline names / airport codes).
|
|
154
|
+
- **Google** — via `aria-google calendar list`. Reads Maya's primary calendar + Sam's
|
|
155
|
+
shared calendar. Detects: multi-day events (family trips, shared PTO).
|
|
156
|
+
|
|
157
|
+
### Detection Logic
|
|
158
|
+
|
|
159
|
+
- **Active travel:** any PTO event (Outlook) or multi-day non-recurring family event
|
|
160
|
+
(Google) that spans today's date
|
|
161
|
+
- **Upcoming trips:** PTO events or flight pairs within the next 60 days, grouped by
|
|
162
|
+
date proximity (±2 days = same trip)
|
|
163
|
+
- **Trip end date:** last day of PTO block or last flight's arrival date, whichever is later
|
|
164
|
+
- **Destination:** parsed from PTO event title suffix or location field, falling back to
|
|
165
|
+
flight arrival airport city
|
|
166
|
+
|
|
167
|
+
### Schedule
|
|
168
|
+
|
|
169
|
+
- Daily at 6:00am via launchd (runs before any sessions likely to start)
|
|
170
|
+
- After daily checkin completes (hooked into checkin flow)
|
|
171
|
+
- Manual: `bin/sync-travel-state --force`
|
|
172
|
+
|
|
173
|
+
### Staleness guard
|
|
174
|
+
|
|
175
|
+
If `aria-outlook` or `aria-google` returns an auth error (OAuth expired), the script
|
|
176
|
+
logs the failure and exits without overwriting the existing file. It emits a warning to
|
|
177
|
+
the COS inbox. It never writes a stale derivation.
|
|
178
|
+
MD
|
|
179
|
+
code_block(<<~SH, lang: "bash")
|
|
180
|
+
bin/sync-travel-state # normal run
|
|
181
|
+
bin/sync-travel-state --dry-run # print derived state, don't write
|
|
182
|
+
bin/sync-travel-state --force # run even if synced_at is recent
|
|
183
|
+
SH
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# 06 — Component 3
|
|
188
|
+
doc_section_header "06", "Component 3: Checkin Verification Gate", id: "c3"
|
|
189
|
+
card do
|
|
190
|
+
card_header "Daily Checkin — Step 0", badge: "C3", meta: "bin/aria-checkin · before form opens"
|
|
191
|
+
card_body do
|
|
192
|
+
md <<~MD
|
|
193
|
+
A brief confirmation step added before the StreamWeaver form opens. Shows derived state
|
|
194
|
+
and asks for a binary confirm. Catches calendar errors before they flow into analysis.
|
|
195
|
+
|
|
196
|
+
### When to show
|
|
197
|
+
|
|
198
|
+
- `travel.active: true` — confirm travel is still ongoing
|
|
199
|
+
- `travel.ends` is today or yesterday — confirm return status
|
|
200
|
+
- `synced_at` is >24h old — warn and offer to re-sync
|
|
201
|
+
- Upcoming trip starts within 3 days — surface it for awareness
|
|
202
|
+
|
|
203
|
+
### When to skip
|
|
204
|
+
|
|
205
|
+
- `travel.active: false` and no trip starting within 3 days — no confirmation needed,
|
|
206
|
+
proceed directly to form
|
|
207
|
+
|
|
208
|
+
### UI behavior
|
|
209
|
+
|
|
210
|
+
Single yes/no question added to the StreamWeaver form as a pre-flight card. Displayed
|
|
211
|
+
above the main form sections. Estimated time: 5 seconds.
|
|
212
|
+
MD
|
|
213
|
+
code_block(<<~TXT, lang: "text")
|
|
214
|
+
"Derived from calendar: traveling in Maryland through Jun 28.
|
|
215
|
+
Still accurate?"
|
|
216
|
+
→ [Yes, continue] [No, something's wrong]
|
|
217
|
+
TXT
|
|
218
|
+
md "If the user selects \"No\": display a correction prompt, update the calendar entry " \
|
|
219
|
+
"(not the yaml directly), trigger `bin/sync-travel-state --force`, then proceed to the " \
|
|
220
|
+
"main form with updated context."
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# 07 — Data Model
|
|
225
|
+
doc_section_header "07", "Data Model", id: "data-model"
|
|
226
|
+
callout(variant: :warning, title: "Do not hand-edit this file.") do
|
|
227
|
+
text "It is written exclusively by bin/sync-travel-state. Manual edits will be overwritten " \
|
|
228
|
+
"at next sync. For urgent corrections, update the source calendar entry and run " \
|
|
229
|
+
"bin/sync-travel-state --force."
|
|
230
|
+
end
|
|
231
|
+
md "### current-state.yaml schema"
|
|
232
|
+
code_block(<<~YAML, lang: "yaml")
|
|
233
|
+
# ~/aria-os/current-state.yaml
|
|
234
|
+
# DERIVED FROM CALENDAR — do not hand-edit.
|
|
235
|
+
# Run bin/sync-travel-state to refresh.
|
|
236
|
+
|
|
237
|
+
synced_at: "2026-06-25T06:00:00-07:00" # ISO8601, written by sync script
|
|
238
|
+
|
|
239
|
+
location:
|
|
240
|
+
current: "Frederick, MD" # from PTO event location or title suffix
|
|
241
|
+
home: "Ashland, OR" # static — set once in script config
|
|
242
|
+
|
|
243
|
+
# travel.active is the primary flag all Claude sessions check.
|
|
244
|
+
# true = away from home, any type. Repeating calendar events do not occur.
|
|
245
|
+
travel:
|
|
246
|
+
active: true
|
|
247
|
+
type: vacation # vacation | work | mixed
|
|
248
|
+
destination: "Maryland" # parsed from calendar
|
|
249
|
+
ends: "2026-06-28" # PTO end date
|
|
250
|
+
source_event_id: "AAMkADk1..." # Outlook/Google event ID for traceability
|
|
251
|
+
source_calendar: outlook # outlook | google
|
|
252
|
+
|
|
253
|
+
mode: vacation # normal | vacation | work-travel | deadline-crunch
|
|
254
|
+
# Note: deadline-crunch is the only mode not derivable from calendar.
|
|
255
|
+
# It must be set manually via: aria-cabinet cos-state set mode deadline-crunch
|
|
256
|
+
|
|
257
|
+
mode_implications:
|
|
258
|
+
hobby_teaching: skip # auto: true when travel.active is true
|
|
259
|
+
hobby_training: skip # auto: true when travel.type is vacation
|
|
260
|
+
calendar_note: >
|
|
261
|
+
Repeating events (volunteer tutoring, weekend pottery class, etc.) appear
|
|
262
|
+
on calendar but do not occur during travel. Do not log absences.
|
|
263
|
+
|
|
264
|
+
travel_schedule:
|
|
265
|
+
- destination: "Austin, TX"
|
|
266
|
+
start: "2026-07-11"
|
|
267
|
+
end: "2026-07-18"
|
|
268
|
+
type: vacation
|
|
269
|
+
source: outlook_pto
|
|
270
|
+
source_event_id: "BBMkADk2..."
|
|
271
|
+
|
|
272
|
+
- destination: "Denver, CO"
|
|
273
|
+
start: "2026-07-20"
|
|
274
|
+
end: null # return flight not yet booked
|
|
275
|
+
type: work
|
|
276
|
+
source: flight_pair
|
|
277
|
+
flight_departure: "2026-07-20T06:00-04:00"
|
|
278
|
+
flight_return: null
|
|
279
|
+
YAML
|
|
280
|
+
md <<~MD
|
|
281
|
+
### Non-calendar context (separate file)
|
|
282
|
+
|
|
283
|
+
Data that cannot be derived from calendar — active work deadlines, upcoming notes —
|
|
284
|
+
lives in a separate file read by relevant secretaries:
|
|
285
|
+
MD
|
|
286
|
+
code_block(<<~YAML, lang: "yaml")
|
|
287
|
+
# ~/aria-os/cabinet/secretaries/cos/context.yaml
|
|
288
|
+
# Hand-maintained by COS secretary. Not overwritten by sync.
|
|
289
|
+
|
|
290
|
+
deadline_crunch_status:
|
|
291
|
+
status: "Board deck due Friday — deprioritizing non-essential secretary work"
|
|
292
|
+
review_meeting_planned: "2026-06-27"
|
|
293
|
+
YAML
|
|
294
|
+
|
|
295
|
+
# 08 — Integrations
|
|
296
|
+
doc_section_header "08", "Integration Points", id: "integrations"
|
|
297
|
+
md "### Systems that read current-state.yaml"
|
|
298
|
+
table(
|
|
299
|
+
headers: ["Consumer", "What it reads", "Purpose"],
|
|
300
|
+
rows: [
|
|
301
|
+
["bin/aria-checkin", "travel, mode", "Step 0 verification gate; grandmaster analysis context"],
|
|
302
|
+
["SessionStart hook", "synced_at, travel.ends", "Staleness warning before any session"],
|
|
303
|
+
["CLAUDE.md directive", "location.current, travel.active", "Ground truth for location-sensitive reasoning"],
|
|
304
|
+
["Hobby schedule reasoning", "travel.active, travel.type","Skip training/teaching when traveling"],
|
|
305
|
+
["Scheduler secretary", "travel_schedule", "Plan-ahead awareness, avoid scheduling conflicts"]
|
|
306
|
+
]
|
|
307
|
+
)
|
|
308
|
+
md <<~MD
|
|
309
|
+
### SessionStart staleness check
|
|
310
|
+
|
|
311
|
+
Add to the SessionStart hook (alongside `bin/aria-session-nudge`):
|
|
312
|
+
MD
|
|
313
|
+
code_block(<<~'RUBY', lang: "ruby")
|
|
314
|
+
ruby -ryaml -rdate -e '
|
|
315
|
+
f = File.expand_path("~/aria-os/current-state.yaml")
|
|
316
|
+
exit unless File.exist?(f)
|
|
317
|
+
s = YAML.load_file(f)
|
|
318
|
+
synced = Date.parse(s["synced_at"].to_s.split("T").first) rescue nil
|
|
319
|
+
if synced && Date.today - synced > 1
|
|
320
|
+
puts "⚠️ current-state.yaml is stale (#{Date.today - synced}d) — run bin/sync-travel-state"
|
|
321
|
+
end
|
|
322
|
+
ends_str = s.dig("travel", "ends")
|
|
323
|
+
if ends_str && s.dig("travel", "active") && Date.parse(ends_str) < Date.today
|
|
324
|
+
puts "⚠️ travel.ends (#{ends_str}) is past but travel.active is true — run bin/sync-travel-state"
|
|
325
|
+
end
|
|
326
|
+
'
|
|
327
|
+
RUBY
|
|
328
|
+
|
|
329
|
+
# 09 — Scope
|
|
330
|
+
doc_section_header "09", "Scope", id: "scope"
|
|
331
|
+
comparison(before_label: "In Scope", after_label: "Out of Scope") do
|
|
332
|
+
before do
|
|
333
|
+
md <<~MD
|
|
334
|
+
- Outlook PTO event detection
|
|
335
|
+
- Google family calendar detection
|
|
336
|
+
- Outlook flight event detection
|
|
337
|
+
- Trip type inference from event titles
|
|
338
|
+
- Destination extraction from title/location field
|
|
339
|
+
- Checkin verification step
|
|
340
|
+
- Scheduler enforcement (require calendar entry)
|
|
341
|
+
- SessionStart staleness warning
|
|
342
|
+
- launchd schedule (6am daily)
|
|
343
|
+
MD
|
|
344
|
+
end
|
|
345
|
+
after do
|
|
346
|
+
md <<~MD
|
|
347
|
+
- Sub-day location tracking
|
|
348
|
+
- Multi-timezone handling
|
|
349
|
+
- Historical travel reconstruction
|
|
350
|
+
- Automatic deadline-crunch mode detection
|
|
351
|
+
- Seattle trip (not yet booked — tracks once calendar entry exists)
|
|
352
|
+
- Drive trip detection without PTO block (process rule: add PTO)
|
|
353
|
+
MD
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# 10 — Success Criteria
|
|
358
|
+
doc_section_header "10", "Success Criteria", id: "success"
|
|
359
|
+
table(
|
|
360
|
+
headers: ["#", "Criterion"],
|
|
361
|
+
rows: [
|
|
362
|
+
["SC1", "Zero location fabrications in grandmaster analysis after build — Claude reads ground truth or asks, never infers from indirect signals"],
|
|
363
|
+
["SC2", "`current-state.yaml` reflects accurate travel state without manual updates on ≥90% of travel days"],
|
|
364
|
+
["SC3", "Checkin verification gate catches any remaining discrepancies within 24h"],
|
|
365
|
+
["SC4", "New travel appears in `current-state.yaml` within 24h of calendar entry creation"],
|
|
366
|
+
["SC5", "Auth failures (OAuth expired) emit a COS inbox warning rather than silently writing stale data"],
|
|
367
|
+
["SC6", "Hobby absence during travel is not logged — no false 'missed training' entries accumulate"]
|
|
368
|
+
]
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
# 11 — Open Questions
|
|
372
|
+
doc_section_header "11", "Open Questions", id: "open"
|
|
373
|
+
table(
|
|
374
|
+
headers: ["#", "Question", "Context"],
|
|
375
|
+
rows: [
|
|
376
|
+
["Q1", "aria-google headless auth",
|
|
377
|
+
"The sync script runs via launchd (non-interactive). Confirm that aria-google's OAuth token refresh works headlessly. If not, the Google calendar read will silently fail — the script must detect this and fall back to Outlook-only with a warning rather than writing incomplete state."],
|
|
378
|
+
["Q2", "Destination parsing from event title",
|
|
379
|
+
"PTO events may not have a location field set. Title parsing needs a convention: \"Maya – PTO Maryland\" works; \"Maya – PTO\" alone does not yield a destination. Worth establishing the naming convention and adding it to the scheduler secretary's entry template."],
|
|
380
|
+
["Q3", "Sam's Google calendar access",
|
|
381
|
+
"The script needs read access to Sam's shared family calendar to detect joint trips. Confirm aria-google has the correct scope and that the calendar is shared with Maya's Google account."],
|
|
382
|
+
["Q4", "Work trip hobby implications",
|
|
383
|
+
"Work travel (Denver) is different from vacation — Maya may or may not train depending on the trip. Currently the model sets hobby_training: skip only for vacation type. Confirm whether work trips should also skip or leave as ambiguous (requiring checkin verification to clarify)."]
|
|
384
|
+
]
|
|
385
|
+
)
|
data/lib/stream_weaver/skills/streamweaver-visual-companion/references/checkpoints-and-forms.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Checkpoints and Forms
|
|
2
|
+
|
|
3
|
+
## Single choice
|
|
4
|
+
|
|
5
|
+
Add a `radio_group` + `button`, then use `canvas-wait <session>` to block until they click. Returns JSON with the selection.
|
|
6
|
+
|
|
7
|
+
## Multiple questions — prefer a form
|
|
8
|
+
|
|
9
|
+
When a push ends with several questions — a mix of choices and open-ended asks — bundle them into one blocking form instead of making the user read the canvas and type each answer back in the terminal. Combine `radio_group` per choice question and `text_field` per open question, one `button` to submit, and a single `canvas-wait` call to collect everything at once:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
streamweaver canvas-push brainstorm <<'RUBY'
|
|
13
|
+
header1 "A few quick questions"
|
|
14
|
+
radio_group :layout, ["Sidebar nav", "Top nav", "Tabs"]
|
|
15
|
+
radio_group :theme, ["Light", "Dark", "Match system"]
|
|
16
|
+
text_field :notes, label: "Anything else to flag?"
|
|
17
|
+
button "Submit"
|
|
18
|
+
RUBY
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
streamweaver canvas-wait brainstorm
|
|
23
|
+
# {"button":"Submit","state":{"layout":"Top nav","theme":"Dark","notes":"keep it minimal"}}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
One click, one `canvas-wait`, every answer back at once in `.state` — no round-tripping to the terminal per question.
|
|
27
|
+
|
|
28
|
+
**Boundary case:** only bundle questions that are independent of each other. If a later question depends on an earlier answer (e.g. "which of these three do you like?" then, based on that pick, "what should we change about it?"), keep those sequential — push the first, wait for the answer, then push the second.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Cleanup and How `panel` Opens the Browser
|
|
2
|
+
|
|
3
|
+
## Kill orphaned servers
|
|
4
|
+
|
|
5
|
+
If a previous session launched orphaned processes (canvas or standalone), clean them up:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# List active canvas sessions
|
|
9
|
+
streamweaver canvas-list
|
|
10
|
+
|
|
11
|
+
# Close a specific canvas session
|
|
12
|
+
streamweaver canvas-close brainstorm
|
|
13
|
+
|
|
14
|
+
# Stop the entire canvas bridge
|
|
15
|
+
streamweaver canvas-stop
|
|
16
|
+
|
|
17
|
+
# List all loaded StreamWeaver apps
|
|
18
|
+
streamweaver list
|
|
19
|
+
|
|
20
|
+
# Remove all apps from the service
|
|
21
|
+
streamweaver clear
|
|
22
|
+
|
|
23
|
+
# Find orphaned StreamWeaver processes by port range
|
|
24
|
+
lsof -i :4567-4600 -sTCP:LISTEN
|
|
25
|
+
|
|
26
|
+
# Kill a specific port (e.g., 4570)
|
|
27
|
+
lsof -ti :4570 | xargs kill -9
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## How `streamweaver panel` opens the browser
|
|
31
|
+
|
|
32
|
+
**You don't need to detect the terminal or call any helper scripts.** `streamweaver panel <session>` figures out the best experience automatically:
|
|
33
|
+
|
|
34
|
+
- **In iTerm2:** opens as a vertical split pane next to the terminal so the canvas lives alongside the conversation. This is the ideal UX — the user sees diagrams without leaving the terminal context.
|
|
35
|
+
- **Anywhere else (Terminal.app, VSCode terminal, kitty, alacritty, tmux, SSH, Linux):** opens in the default system browser (a new tab/window) and prints the URL.
|
|
36
|
+
|
|
37
|
+
Either way the URL is printed in stdout so the user has a fallback.
|
|
38
|
+
|
|
39
|
+
**Anti-patterns to avoid:**
|
|
40
|
+
- Don't run `python` scripts to drive iTerm — the `iterm2_ruby` gem (on RubyGems) drives iTerm natively and the CLI handles invocation.
|
|
41
|
+
- Don't try to `osascript`/AppleScript the iTerm split yourself — `streamweaver panel` already does this through the iTerm2 Ruby API.
|
|
42
|
+
- Don't open the browser with a shell `open` / `xdg-open` after `streamweaver panel` — it already opened one (or split into one). Doing so creates duplicates.
|
|
43
|
+
|
|
44
|
+
If you specifically need the browser opened externally even when iTerm is available (e.g., for screen sharing on a separate display), that's a feature request — file a bd issue rather than working around it in the skill.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Example Gallery
|
|
2
|
+
|
|
3
|
+
Bundled proof examples, each demonstrating 1:1 visual parity with a real claude.ai Artifact for a different document genre. Read the closer-matching one before generating a new port from scratch, and see `docs/porting-artifacts.md` for the general process behind both (and for adding a new gallery entry).
|
|
4
|
+
|
|
5
|
+
- **`doc-parity-example.rb` + `_dsl.rb`** — long-form PRD/report genre. Techniques proven: `:doc` theme reaching Artifact parity with almost no extra CSS, `doc_header`/`doc_section_header`/`sidebar_toc`, `callout`, `mermaid`, `comparison` (before/after scope grid), `code_block`, `card`/`card_header`/`card_body`.
|
|
6
|
+
- **`design-review-example.rb` + `_dsl.rb` + `.css`** — editorial "design options" review genre (numbered sections, option cards, a comparison matrix, a verified/unverified checklist split). Techniques proven: status-dot chips (`div` + `phrase` + `status_dot`), a "picked/winning" state reused across both a card and a table row, checklist tiles built from `div`/`phrase` (no dedicated component), and a full bespoke re-skin via **one** unlayered CSS file targeting only stable `sw-` hooks — no framework CSS fights (structural hooks documented in `docs/theming-hooks.md`; doc-component hook docs tracked in stream_weaver-d11).
|
|
7
|
+
|
|
8
|
+
Don't assume canvas-push is limited to throwaway mockups — Tier 2 persistence (Save-as-doc, see `persistence.md`) can grow a quick brainstorm into a fully polished, long-form document. `doc-parity-example.rb` is proof: it reached 1:1 visual parity with a real claude.ai Artifact. For building documents like it, hand off to the `streamweaver-doc-builder` skill, which owns the `:doc` theme and component vocabulary in depth.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Persisting Visual Docs
|
|
2
|
+
|
|
3
|
+
Every canvas session has two tiers of persistence — both work without any action from you.
|
|
4
|
+
|
|
5
|
+
## Tier 1: Auto-saved history (always-on)
|
|
6
|
+
|
|
7
|
+
Every `streamweaver canvas-push` call automatically writes the DSL to `~/.streamweaver/history/<session>/<YYYYMMDD_HHMMSS>.rb`. The CLI prints the saved path on stderr:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
$ streamweaver canvas-push brainstorm <<'RUBY' ... RUBY
|
|
11
|
+
saved: /Users/.../streamweaver/history/brainstorm/20260428_153012.rb
|
|
12
|
+
Pushed to brainstorm
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
You don't have to ask the user, configure anything, or run a separate save command. The history is the project's safety net — entries older than 7 days are auto-cleaned. **Never in git, never noisy.** It's the user's "I forgot to save that good diagram from yesterday" insurance.
|
|
16
|
+
|
|
17
|
+
## Tier 2: Persistent project docs (user-driven)
|
|
18
|
+
|
|
19
|
+
Each canvas page has a floating **💾 Save as doc** button in the bottom-right. The user clicks it, names the doc (pre-filled with `<session>-YYYYMMDD-HHMM`), and the DSL is written to:
|
|
20
|
+
|
|
21
|
+
- `<git_root>/docs/streamweaver_canvas/<name>.rb` if invoked inside a git repo
|
|
22
|
+
- `~/.streamweaver/canvas/<name>.rb` otherwise
|
|
23
|
+
|
|
24
|
+
These are the *intentional* keep-forever artifacts that get committed to the repo and shared with teammates. `examples/doc-parity-example.rb` in this skill folder shows what this tier can grow into — a fully polished document, not just a saved sketch.
|
|
25
|
+
|
|
26
|
+
A doc saved this way gets reopened later with no live bridge behind it — the same file also gets browsed via `canvas-read` and can be run through `streamweaver export`. Not every component behaves the same way once the bridge is gone; see the `streamweaver-canvas-safe` skill before building interactivity into anything you expect to Save-as-doc.
|
|
27
|
+
|
|
28
|
+
When the same material ships to two audiences (a decision memo plus its engineering companion), don't keep two docs that each restate the same tables. Put the shared tables in one `shared/*.rb` fragment and `instance_eval` it from both bodies, so they cannot drift. Push with `cat shared/frag.rb my-doc.rb | streamweaver canvas-push my-doc` — the bridge evaluates pushed text with no filename, so `__dir__` is `nil` there and the doc cannot find the fragment on its own. Pattern, per-mode resolution rules, and org-mode caveats: `docs/shared-dsl-fragments.md` in the stream_weaver repo.
|
|
29
|
+
|
|
30
|
+
**Important:** Saving is a user action, not yours. Don't try to "save the canvas" yourself unless the user explicitly asks. If the user says "save this as X" and the button isn't easy to reach, you can fall back to:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
curl -sX POST "http://localhost:<bridge-port>/canvas/<session>/save-doc" \
|
|
34
|
+
-H 'Content-Type: application/json' \
|
|
35
|
+
-d '{"name":"<doc-name>"}'
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The bridge port is shown in `streamweaver canvas-list` output.
|
|
39
|
+
|
|
40
|
+
## Browsing saved docs
|
|
41
|
+
|
|
42
|
+
`streamweaver canvas-read` with no arguments opens the project's `docs/streamweaver_canvas/` directory in a local viewer. The user just runs:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
streamweaver canvas-read
|
|
46
|
+
# canvas-read using default: <git_root>/docs/streamweaver_canvas
|
|
47
|
+
# → opens browser with sidebar listing every saved doc
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
If the user asks "show me what we saved," that's the command. No paths needed.
|
|
51
|
+
|
|
52
|
+
To browse the *history* tier (auto-saved snapshots), pass it explicitly:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
streamweaver canvas-read ~/.streamweaver/history/brainstorm/
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
A combined view (history + docs visible together in one viewer) is on the roadmap (`6m8`, `q4y` in beads).
|