stream_weaver 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.beads/.gitignore +77 -0
- data/.beads/README.md +81 -0
- data/.beads/config.yaml +54 -0
- data/.beads/metadata.json +7 -0
- data/.rspec +3 -0
- data/AGENTS.md +91 -0
- data/CHANGELOG.md +294 -0
- data/CLAUDE.md +67 -0
- data/LICENSE.txt +21 -0
- data/README.md +565 -0
- data/Rakefile +13 -0
- data/assets/streamweaver-hero.jpg +0 -0
- data/bench/baselines/ledger.rb +58 -0
- data/bench/baselines/warroom.rb +51 -0
- data/bench/fixtures/ledger.rb +76 -0
- data/bench/fixtures/warroom.rb +60 -0
- data/bench/results/6daf8b8.md +102 -0
- data/bench/results/c8d749b.md +102 -0
- data/bench/results/eb06ab9.md +102 -0
- data/bench/run.rb +151 -0
- data/bench/support.rb +84 -0
- data/copy_this/dto_run_sample_run_7631.html +220 -0
- data/docs/SERVICE_MODE.md +302 -0
- data/docs/architecture/how_streamweaver_works.md +772 -0
- data/docs/blog/2026-01-16-streamweaver-introduction.md +515 -0
- data/docs/bug-2026-08-31-canvas-bridge-socket-collision.md +83 -0
- data/docs/canvas-ipc-session-summary.md +127 -0
- data/docs/canvas-panel-workflow.md +172 -0
- data/docs/canvas-read.md +147 -0
- data/docs/canvas-roadmap.md +275 -0
- data/docs/case-studies/2026-09-03-didx-canvas-read-shelf.md +147 -0
- data/docs/claude-code-companion-skill-spec.md +567 -0
- data/docs/components_reference.md +1223 -0
- data/docs/crud-patterns.md +265 -0
- data/docs/endpoints.md +122 -0
- data/docs/for_llms.md +1 -0
- data/docs/form-patterns.md +165 -0
- data/docs/frontend-only.md +169 -0
- data/docs/html-artifact-audit.md +238 -0
- data/docs/ideas/2025-01-01-as-a-service.md +203 -0
- data/docs/ideas/2026-01-16-charm-tui-exploration.md +542 -0
- data/docs/ideas/2026-08-27-static-doc-shelf-export.md +153 -0
- data/docs/ideas/dhh-review-future-refactors.md +142 -0
- data/docs/opal-jamstack.md +47 -0
- data/docs/opal-npm-direction.md +184 -0
- data/docs/opal-spike-findings.md +194 -0
- data/docs/plans/2025-12-16-form-blocks-design.md +124 -0
- data/docs/plans/2025-12-30-examples-browser-design.md +152 -0
- data/docs/plans/2026-01-02-charts-design.md +288 -0
- data/docs/plans/2026-01-10-canvas-ipc-design.md +247 -0
- data/docs/plans/2026-01-19-cabinet-control-components.md +176 -0
- data/docs/plans/2026-01-26-gem-release-and-panel.md +140 -0
- data/docs/plans/canvas-claude-project-design.md +238 -0
- data/docs/plans/canvas-doc-location-and-discovery.md +32 -0
- data/docs/plans/org-doc-preview-surfaces.md +293 -0
- data/docs/plans/shadcn-polish-plan.md +417 -0
- data/docs/porting-artifacts.md +252 -0
- data/docs/reference/agent-skills-comparison.md +369 -0
- data/docs/reference/travel-state-prd.artifact.html +780 -0
- data/docs/research/2026-08-17-hotwire-alike-landscape.md +268 -0
- data/docs/research/2026-08-17-hotwire-concept-map.md +404 -0
- data/docs/research/2026-08-22-lazy-fragments-trigger-decision.md +246 -0
- data/docs/research/2026-08-22-learnhotwire-syllabus-coverage.md +239 -0
- data/docs/research/frontend-only-matrix.md +278 -0
- data/docs/research/streamweaver-way-spike-findings.md +529 -0
- data/docs/resource-dsl.md +342 -0
- data/docs/routing.md +302 -0
- data/docs/ruby-ui-comparison.md +319 -0
- data/docs/shared-dsl-fragments.md +356 -0
- data/docs/streamweaver-for-ai-agents.md +401 -0
- data/docs/streamweaver-frontend-vision.md +123 -0
- data/docs/streamweaver_canvas/glimmer_initial_final_layer.rb +77 -0
- data/docs/streamweaver_canvas/save_example.rb +9 -0
- data/docs/templates.md +213 -0
- data/docs/testing.md +155 -0
- data/docs/theming-hooks.md +281 -0
- data/docs/tutorials/the-streamweaver-way.md +882 -0
- data/docs/university/capability-inventory.md +137 -0
- data/docs/university/dependency-survey.md +114 -0
- data/docs/university/design-spec.md +217 -0
- data/docs/university/mockups/code-block-doc-theme-dark.png +0 -0
- data/docs/university/mockups/code-block-doc-theme-light.png +0 -0
- data/docs/university/mockups/course-list-dark.png +0 -0
- data/docs/university/mockups/course-list-light.png +0 -0
- data/docs/university/mockups/course_canvas_mockup.rb +741 -0
- data/docs/university/mockups/step-screen-dark.png +0 -0
- data/docs/university/mockups/step-screen-light.png +0 -0
- data/docs/university/roadmap.md +72 -0
- data/docs/university/send-to-coworker.md +77 -0
- data/docs/university/worker-session-mining.md +109 -0
- data/docs/visual/browser-rendering-spike.md +173 -0
- data/docs/visual/builder-visual-plan-analysis.md +378 -0
- data/docs/visual/sw-plan-format-exploration.md +511 -0
- data/docs/visual/sw-plan-rendering-deep-dive.md +453 -0
- data/docs/visual-skills/PROGRESS.md +60 -0
- data/docs/visual-skills/SESSION-CONTEXT.md +207 -0
- data/docs/visual-skills/analysis/components.md +317 -0
- data/docs/visual-skills/analysis/overlap.md +360 -0
- data/docs/visual-skills/analysis/pi-design-deck.md +1102 -0
- data/docs/visual-skills/analysis/streamweaver-inventory.md +93 -0
- data/docs/visual-skills/analysis/unified-specs.feature +1003 -0
- data/docs/visual-skills/analysis/visual-explainer.md +964 -0
- data/docs/visual-skills/blog/blog-series-outline.md +39 -0
- data/docs/visual-skills/blog/token-efficiency.md +73 -0
- data/docs/visual-skills/design/architecture.md +1725 -0
- data/docs/visual-skills/design/codex-review.md +340 -0
- data/docs/visual-skills/design/dhh-review.md +209 -0
- data/docs/visual-skills/design/evolution.md +100 -0
- data/docs/visual-skills/design/gemini-review.md +55 -0
- data/docs/visual-skills/design/review-synthesis.md +149 -0
- data/docs/visual-skills/implementation/STATE.md +22 -0
- data/docs/visual-skills/implementation/plan.md +347 -0
- data/docs/visual-skills/implementation/spike-findings.md +237 -0
- data/docs/visual-skills/implementation/tasks.md +702 -0
- data/docs/visual-skills/lessons-learned/process.md +145 -0
- data/examples/README.md +96 -0
- data/examples/advanced/all_components.rb +177 -0
- data/examples/advanced/examples_browser.rb +394 -0
- data/examples/advanced/teachables_browser.rb +261 -0
- data/examples/advanced/theme_tweaker.rb +366 -0
- data/examples/advanced/tutorial.rb +1528 -0
- data/examples/agentic/agentic_form.rb +30 -0
- data/examples/agentic/agentic_form_autoclose.rb +30 -0
- data/examples/agentic/cultivation_tracker.rb +69 -0
- data/examples/basic/hello_world.rb +22 -0
- data/examples/basic/opal_tabs_table.rb +44 -0
- data/examples/basic/todo_list.rb +39 -0
- data/examples/button_loading_test.rb +36 -0
- data/examples/canvas/mermaid_canvas_demo.sh +151 -0
- data/examples/charts/bar_chart_demo.rb +57 -0
- data/examples/charts/line_chart_demo.rb +73 -0
- data/examples/charts/pie_area_demo.rb +87 -0
- data/examples/charts/stacked_bar_chart_demo.rb +69 -0
- data/examples/claude_code/README.md +85 -0
- data/examples/claude_code/codebreaker/.claude/commands/infiltrate.md +632 -0
- data/examples/claude_code/codebreaker/.claude/settings.json +11 -0
- data/examples/claude_code/codebreaker/.claude/settings.local.json +17 -0
- data/examples/claude_code/codebreaker/.claude/skills/infiltrate.md +0 -0
- data/examples/claude_code/codebreaker/README.md +213 -0
- data/examples/claude_code/tutorial/.claude/commands/learn.md +453 -0
- data/examples/claude_code/tutorial/README.md +102 -0
- data/examples/claude_code/verification_flow/.claude/commands/verify.md +171 -0
- data/examples/claude_code/verification_flow/README.md +126 -0
- data/examples/components/annotated_code_demo.rb +54 -0
- data/examples/components/callout_demo.rb +33 -0
- data/examples/components/checkbox_group_demo.rb +46 -0
- data/examples/components/design_review.css +468 -0
- data/examples/components/design_review_demo.rb +44 -0
- data/examples/components/design_review_dsl.rb +300 -0
- data/examples/components/diff_block_demo.rb +112 -0
- data/examples/components/events_demo.rb +184 -0
- data/examples/components/form_demo.rb +62 -0
- data/examples/components/lesson_demo.rb +53 -0
- data/examples/components/markdown_demo.rb +110 -0
- data/examples/components/mermaid_demo.rb +166 -0
- data/examples/components/pareto_set.rb +64 -0
- data/examples/components/prd_demo.rb +21 -0
- data/examples/components/prd_dsl.rb +385 -0
- data/examples/components/quiz_demo.rb +47 -0
- data/examples/components/run_viewer_demo.rb +100 -0
- data/examples/components/score_and_collapsible_demo.rb +82 -0
- data/examples/components/select_stale_value_smoke_test.rb +39 -0
- data/examples/components/table_demo.rb +247 -0
- data/examples/components/timer_with_state_demo.rb +58 -0
- data/examples/components/todo_due_dates.rb +63 -0
- data/examples/components/uat_gaps_demo.rb +112 -0
- data/examples/dashboard/feed_simulator.rb +60 -0
- data/examples/dashboard/live_dashboard.rb +80 -0
- data/examples/dashboard_components.rb +108 -0
- data/examples/deferred_fragments_demo.rb +62 -0
- data/examples/generate_more_spike/README.md +63 -0
- data/examples/generate_more_spike/app.rb +441 -0
- data/examples/git_health.sh +401 -0
- data/examples/layout/layout_components_demo.rb +174 -0
- data/examples/layout/modal_demo.rb +215 -0
- data/examples/layout/navigation_demo.rb +227 -0
- data/examples/layout/route_tabs_demo.rb +52 -0
- data/examples/layout/routing_demo.rb +52 -0
- data/examples/layout/scroll_box_demo.rb +154 -0
- data/examples/lazy_fragments_demo.rb +151 -0
- data/examples/my_todos/README.md +29 -0
- data/examples/my_todos/my_todos.rb +312 -0
- data/examples/my_todos/store.rb +86 -0
- data/examples/opal/reactive_demo.rb +62 -0
- data/examples/opal/scenarios/s1_counter.rb +15 -0
- data/examples/opal/scenarios/s2_search_filter.rb +17 -0
- data/examples/opal/scenarios/s3_sibling_tabs.rb +25 -0
- data/examples/opal/scenarios/s4_shopping_cart.rb +34 -0
- data/examples/opal/scenarios/s5_watch.rb +39 -0
- data/examples/opal/scenarios/s6_on_start.rb +20 -0
- data/examples/opal/scenarios/s7_wizard.rb +33 -0
- data/examples/opal/scenarios/s8_loan_calculator.rb +21 -0
- data/examples/opal/scenarios/s9_dashboard.rb +27 -0
- data/examples/operations_dashboard_demo.rb +167 -0
- data/examples/panel_demo.sh +447 -0
- data/examples/parity/assets/tyrion_slice.css +86 -0
- data/examples/parity/rivet_people_slice.rb +182 -0
- data/examples/parity/tyrion_components.css +777 -0
- data/examples/parity/tyrion_warroom_components.rb +414 -0
- data/examples/parity/tyrion_warroom_slice.rb +549 -0
- data/examples/puma_dev/README.md +124 -0
- data/examples/puma_dev/config.ru +34 -0
- data/examples/puma_dev/standalone_app.rb +34 -0
- data/examples/scaffolding/blog.rb +49 -0
- data/examples/scaffolding/utf_lite.rb +105 -0
- data/examples/styling/feedback_demo.rb +229 -0
- data/examples/styling/style_showcase.rb +172 -0
- data/examples/styling/theme_demo.rb +508 -0
- data/examples/timer_health_checker.rb +111 -0
- data/examples/timer_showcase.rb +131 -0
- data/examples/tutorials/render_markdown.rb +112 -0
- data/examples/tutorials/streamweaver_way_tutorial.rb +44 -0
- data/examples/tutorials/tutorial_content.rb +1082 -0
- data/examples/visual_skills/design_deck_demo.rb +314 -0
- data/examples/visual_skills/explainer_demo.rb +499 -0
- data/exe/streamweaver +9 -0
- data/gsd/ROADMAP-1.0.md +167 -0
- data/gsd/STATE.md +13 -0
- data/gsd/research/market-positioning-research.md +139 -0
- data/gsd/research/production-patterns-research.md +270 -0
- data/gsd/research/repo-audit-1.0.md +274 -0
- data/lib/stream_weaver/action_token.rb +58 -0
- data/lib/stream_weaver/adapter/alpinejs.rb +8249 -0
- data/lib/stream_weaver/adapter/base.rb +591 -0
- data/lib/stream_weaver/adapter/opal.rb +334 -0
- data/lib/stream_weaver/adapter/static.rb +1118 -0
- data/lib/stream_weaver/admin.rb +176 -0
- data/lib/stream_weaver/app.rb +1821 -0
- data/lib/stream_weaver/assets/js/sw-copy.js +50 -0
- data/lib/stream_weaver/assets/js/sw-heredoc-rewrite.js +68 -0
- data/lib/stream_weaver/assets/js/sw-keyboard.js +165 -0
- data/lib/stream_weaver/assets/js/sw-mermaid-zoom.js +621 -0
- data/lib/stream_weaver/assets/js/sw-route-tabs.js +53 -0
- data/lib/stream_weaver/assets/js/sw-sidebar-toc.js +116 -0
- data/lib/stream_weaver/assets/js/sw-slide-nav.js +103 -0
- data/lib/stream_weaver/canvas/bridge.rb +239 -0
- data/lib/stream_weaver/canvas/bridge_server.rb +646 -0
- data/lib/stream_weaver/canvas/client.rb +298 -0
- data/lib/stream_weaver/canvas/doc_roots.rb +233 -0
- data/lib/stream_weaver/canvas/doc_store.rb +252 -0
- data/lib/stream_weaver/canvas/gist_publisher.rb +264 -0
- data/lib/stream_weaver/canvas/gist_save_handler.rb +89 -0
- data/lib/stream_weaver/canvas/gist_store.rb +135 -0
- data/lib/stream_weaver/canvas/helpers.rb +109 -0
- data/lib/stream_weaver/canvas/history.rb +90 -0
- data/lib/stream_weaver/canvas/protocol.rb +86 -0
- data/lib/stream_weaver/canvas/reader.rb +853 -0
- data/lib/stream_weaver/canvas/save_doc_widget.rb +457 -0
- data/lib/stream_weaver/canvas/scroll_top_hint.rb +21 -0
- data/lib/stream_weaver/canvas/session.rb +132 -0
- data/lib/stream_weaver/cli.rb +3235 -0
- data/lib/stream_weaver/component_assets.rb +70 -0
- data/lib/stream_weaver/component_registry.rb +67 -0
- data/lib/stream_weaver/component_renderer.rb +48 -0
- data/lib/stream_weaver/components/annotated_code.rb +53 -0
- data/lib/stream_weaver/components/api_endpoint.rb +42 -0
- data/lib/stream_weaver/components/callout.rb +59 -0
- data/lib/stream_weaver/components/chart.rb +84 -0
- data/lib/stream_weaver/components/code_block.rb +77 -0
- data/lib/stream_weaver/components/comparison.rb +39 -0
- data/lib/stream_weaver/components/decision.rb +38 -0
- data/lib/stream_weaver/components/deck/close_overlay.rb +84 -0
- data/lib/stream_weaver/components/deck/confirmation_bar.rb +60 -0
- data/lib/stream_weaver/components/deck/deck_option.rb +61 -0
- data/lib/stream_weaver/components/deck/deck_slide.rb +77 -0
- data/lib/stream_weaver/components/deck/deck_state.rb +469 -0
- data/lib/stream_weaver/components/deck/deck_summary.rb +73 -0
- data/lib/stream_weaver/components/deck/design_deck.rb +60 -0
- data/lib/stream_weaver/components/deck/generate_more_controls.rb +84 -0
- data/lib/stream_weaver/components/deck/model_selector.rb +84 -0
- data/lib/stream_weaver/components/deck/skeleton_placeholder.rb +36 -0
- data/lib/stream_weaver/components/diff_block.rb +125 -0
- data/lib/stream_weaver/components/doc_header.rb +57 -0
- data/lib/stream_weaver/components/image_block.rb +70 -0
- data/lib/stream_weaver/components/implementation_map.rb +33 -0
- data/lib/stream_weaver/components/keyboard_shortcuts.rb +94 -0
- data/lib/stream_weaver/components/kpi_dashboard.rb +78 -0
- data/lib/stream_weaver/components/mermaid.rb +79 -0
- data/lib/stream_weaver/components/pipeline.rb +63 -0
- data/lib/stream_weaver/components/sidebar_toc.rb +46 -0
- data/lib/stream_weaver/components/slide_container.rb +141 -0
- data/lib/stream_weaver/components/timeline_event.rb +58 -0
- data/lib/stream_weaver/components/wireframe.rb +29 -0
- data/lib/stream_weaver/components/wireframe_block.rb +34 -0
- data/lib/stream_weaver/components.rb +2711 -0
- data/lib/stream_weaver/css.rb +230 -0
- data/lib/stream_weaver/dev_fallback_overlay.rb +61 -0
- data/lib/stream_weaver/display_dsl.rb +1004 -0
- data/lib/stream_weaver/export/html_exporter.rb +478 -0
- data/lib/stream_weaver/feed.rb +34 -0
- data/lib/stream_weaver/feed_builder.rb +31 -0
- data/lib/stream_weaver/fonts.rb +33 -0
- data/lib/stream_weaver/interaction_runner.rb +487 -0
- data/lib/stream_weaver/iterm.rb +460 -0
- data/lib/stream_weaver/layout_registry.rb +92 -0
- data/lib/stream_weaver/opal/bridge.rb +52 -0
- data/lib/stream_weaver/opal/builder.rb +193 -0
- data/lib/stream_weaver/opal/env.rb +29 -0
- data/lib/stream_weaver/opal/reactive_state.rb +75 -0
- data/lib/stream_weaver/opal/regexp_anchor_patch.rb +62 -0
- data/lib/stream_weaver/opal/renderer.rb +77 -0
- data/lib/stream_weaver/opal/runtime.rb +250 -0
- data/lib/stream_weaver/opal/shell.rb +145 -0
- data/lib/stream_weaver/opal/string_bridge.rb +50 -0
- data/lib/stream_weaver/opal/stubs/diff.min.js +1 -0
- data/lib/stream_weaver/opal/stubs/digest.rb +15 -0
- data/lib/stream_weaver/opal/stubs/marked.umd.js +79 -0
- data/lib/stream_weaver/opal/stubs/md5.rb +3 -0
- data/lib/stream_weaver/opal/stubs/morphdom.min.js +775 -0
- data/lib/stream_weaver/opal/stubs/prism-tomorrow.min.css +1 -0
- data/lib/stream_weaver/opal/stubs/prism.min.js +1967 -0
- data/lib/stream_weaver/opal_entry.rb +136 -0
- data/lib/stream_weaver/org/inline.rb +95 -0
- data/lib/stream_weaver/org/reader.rb +561 -0
- data/lib/stream_weaver/org/recording_context.rb +86 -0
- data/lib/stream_weaver/org/source_splitter.rb +63 -0
- data/lib/stream_weaver/org/writer.rb +300 -0
- data/lib/stream_weaver/page_shell.rb +530 -0
- data/lib/stream_weaver/portfile.rb +79 -0
- data/lib/stream_weaver/pushable.rb +42 -0
- data/lib/stream_weaver/resource/default_views.rb +111 -0
- data/lib/stream_weaver/resource/field_input.rb +25 -0
- data/lib/stream_weaver/resource/state_keys.rb +16 -0
- data/lib/stream_weaver/resource/store.rb +18 -0
- data/lib/stream_weaver/resource.rb +104 -0
- data/lib/stream_weaver/server.rb +1471 -0
- data/lib/stream_weaver/service.rb +1240 -0
- data/lib/stream_weaver/service_client.rb +104 -0
- data/lib/stream_weaver/session_store.rb +186 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/SKILL.md +66 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/examples/canvas-safe-showcase.rb +98 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/actions-and-buttons.md +47 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/charts-and-diagrams.md +38 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/deck.md +32 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/inputs-and-forms.md +65 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/tabs-and-navigation.md +53 -0
- data/lib/stream_weaver/skills/streamweaver-doc-builder/SKILL.md +298 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/SKILL.md +130 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.css +468 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.rb +39 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example_dsl.rb +300 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example.rb +24 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example_dsl.rb +385 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/checkpoints-and-forms.md +28 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/cleanup-and-panel.md +44 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/example-gallery.md +8 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/persistence.md +58 -0
- data/lib/stream_weaver/skills/streamweaver-way/SKILL.md +396 -0
- data/lib/stream_weaver/skills/visual-plan/SKILL.md +201 -0
- data/lib/stream_weaver/skills/visual-recap/SKILL.md +244 -0
- data/lib/stream_weaver/streamer.rb +63 -0
- data/lib/stream_weaver/templates/choices.rb +149 -0
- data/lib/stream_weaver/templates/code.rb +157 -0
- data/lib/stream_weaver/templates/confirm.rb +110 -0
- data/lib/stream_weaver/templates/diff.rb +195 -0
- data/lib/stream_weaver/templates/info.rb +142 -0
- data/lib/stream_weaver/templates/table.rb +169 -0
- data/lib/stream_weaver/templates/wizard.rb +271 -0
- data/lib/stream_weaver/theme/auto_mode.rb +116 -0
- data/lib/stream_weaver/theme/presets.rb +555 -0
- data/lib/stream_weaver/theme.rb +639 -0
- data/lib/stream_weaver/university/canvas.rb +924 -0
- data/lib/stream_weaver/university/course.rb +699 -0
- data/lib/stream_weaver/university/demos/counter.rb +33 -0
- data/lib/stream_weaver/university/demos/dashboard.rb +147 -0
- data/lib/stream_weaver/university/demos/decision_form.rb +143 -0
- data/lib/stream_weaver/university/demos.rb +50 -0
- data/lib/stream_weaver/university/listener.rb +467 -0
- data/lib/stream_weaver/university/progress.rb +201 -0
- data/lib/stream_weaver/university/runner.rb +138 -0
- data/lib/stream_weaver/university/scripts/growing_doc.rb +609 -0
- data/lib/stream_weaver/university/scripts/growing_doc_state.rb +91 -0
- data/lib/stream_weaver/utils.rb +31 -0
- data/lib/stream_weaver/version.rb +5 -0
- data/lib/stream_weaver/views/canvas/reader_layout.erb +800 -0
- data/lib/stream_weaver/views.rb +3940 -0
- data/lib/stream_weaver.rb +122 -0
- data/llms.txt +1269 -0
- data/sig/stream_weaver.rbs +4 -0
- metadata +598 -0
|
@@ -0,0 +1,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
|
+
)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative '../../lib/stream_weaver'
|
|
5
|
+
|
|
6
|
+
# Demonstrates the new radio_group and card components for quiz-style UIs
|
|
7
|
+
QuizApp = app "Quiz Demo" do
|
|
8
|
+
header2 "Test your knowledge"
|
|
9
|
+
text "Answer the questions below using the radio buttons."
|
|
10
|
+
|
|
11
|
+
card do
|
|
12
|
+
header3 "1. What does GIP stand for?"
|
|
13
|
+
radio_group :q1, [
|
|
14
|
+
"Growth, Income, Profit",
|
|
15
|
+
"Growth, Inflation, Policy",
|
|
16
|
+
"Gains, Interest, Prices",
|
|
17
|
+
"GDP, Interest rates, Profits"
|
|
18
|
+
]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
card do
|
|
22
|
+
header3 "2. Which programming language is this app built with?"
|
|
23
|
+
radio_group :q2, [
|
|
24
|
+
"Python",
|
|
25
|
+
"Ruby",
|
|
26
|
+
"JavaScript",
|
|
27
|
+
"Go"
|
|
28
|
+
]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
card do
|
|
32
|
+
header3 "3. True or False: StreamWeaver uses Alpine.js"
|
|
33
|
+
radio_group :q3, ["True", "False"]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Show answers when all questions are answered
|
|
37
|
+
if state[:q1] && state[:q2] && state[:q3]
|
|
38
|
+
card class: "results-card" do
|
|
39
|
+
header2 "Your Answers"
|
|
40
|
+
text "Q1: #{state[:q1]}"
|
|
41
|
+
text "Q2: #{state[:q2]}"
|
|
42
|
+
text "Q3: #{state[:q3]}"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
QuizApp.run! if __FILE__ == $0
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Example: Run Viewer Timeline
|
|
5
|
+
# Replicates the DTO Run Viewer event log using the TimelineEvent component.
|
|
6
|
+
# Run with: ruby examples/components/run_viewer_demo.rb
|
|
7
|
+
|
|
8
|
+
require_relative "../../lib/stream_weaver"
|
|
9
|
+
|
|
10
|
+
RunViewerApp = app "Run Viewer — abc-123", theme: :dark do
|
|
11
|
+
# Header metadata
|
|
12
|
+
header1 "Run Viewer"
|
|
13
|
+
hstack spacing: :lg do
|
|
14
|
+
text "run_id: abc-123"
|
|
15
|
+
text "target: codex"
|
|
16
|
+
text "duration: 60.0s"
|
|
17
|
+
text "events: 11"
|
|
18
|
+
end
|
|
19
|
+
hstack spacing: :lg do
|
|
20
|
+
text "interventions: 2"
|
|
21
|
+
text "timeouts: 0"
|
|
22
|
+
text "snapshots: 2"
|
|
23
|
+
end
|
|
24
|
+
text "source: demo/sample_run.jsonl"
|
|
25
|
+
|
|
26
|
+
# Timeline events
|
|
27
|
+
vstack spacing: :none do
|
|
28
|
+
timeline_event index: 0, event_type: :phase, timestamp: "10:00:00",
|
|
29
|
+
label: "launch",
|
|
30
|
+
fields: { run_id: "abc-123", phase: "launch", target: "codex",
|
|
31
|
+
baseline_files: "lib/app.rb", step_id: "launch",
|
|
32
|
+
target_socket_name: "dto-codex", target_session_name: "run-1" }
|
|
33
|
+
|
|
34
|
+
timeline_event index: 1, event_type: :phase, timestamp: "10:00:05",
|
|
35
|
+
label: "settle step=1",
|
|
36
|
+
fields: { run_id: "abc-123", phase: "settle", step: 1, step_id: "step-1" }
|
|
37
|
+
|
|
38
|
+
timeline_event index: 2, event_type: :phase, timestamp: "10:00:15",
|
|
39
|
+
label: "observe step=1",
|
|
40
|
+
fields: { run_id: "abc-123", phase: "observe", step: 1, step_id: "step-1" }
|
|
41
|
+
|
|
42
|
+
timeline_event index: 3, event_type: :snapshot, timestamp: "10:00:16",
|
|
43
|
+
label: "state=working verification_ok=false step=1",
|
|
44
|
+
fields: { run_id: "abc-123", step: 1, step_id: "step-1", state: "working",
|
|
45
|
+
waiting_for_input: false, busy: true, likely_complete: false,
|
|
46
|
+
signals_found: "[]", signals_missing: "test passes",
|
|
47
|
+
verification_ok: false, changed_files: "lib/app.rb",
|
|
48
|
+
last_assistant_lines: "Writing the initial implementation..." }
|
|
49
|
+
|
|
50
|
+
timeline_event index: 4, event_type: :phase, timestamp: "10:00:17",
|
|
51
|
+
label: "decide step=1",
|
|
52
|
+
fields: { run_id: "abc-123", phase: "decide", step: 1, step_id: "step-1",
|
|
53
|
+
driver: "ClaudeDriverBackend" }
|
|
54
|
+
|
|
55
|
+
timeline_event index: 5, event_type: :intervention, timestamp: "10:00:22",
|
|
56
|
+
label: "action=question terminal=false step=1",
|
|
57
|
+
fields: { run_id: "abc-123", step: 1, step_id: "step-1", action: "question",
|
|
58
|
+
intent: "Clarify scope",
|
|
59
|
+
why: "Worker jumped into coding without asking about interface shape",
|
|
60
|
+
next_step: "List the product choices before writing code",
|
|
61
|
+
stop_if: "Worker starts asking clarifying questions",
|
|
62
|
+
rendered_message: "INTENT: Clarify scope\nWHY: You started coding without clarifying the interface shape.\nNEXT: List the product choices first.\nSTOP IF: You start asking clarifying questions.",
|
|
63
|
+
terminal: false }
|
|
64
|
+
|
|
65
|
+
timeline_event index: 6, event_type: :phase, timestamp: "10:00:23",
|
|
66
|
+
label: "send step=1",
|
|
67
|
+
fields: { run_id: "abc-123", phase: "send", step: 1, step_id: "step-1" }
|
|
68
|
+
|
|
69
|
+
timeline_event index: 7, event_type: :phase, timestamp: "10:00:35",
|
|
70
|
+
label: "settle step=2",
|
|
71
|
+
fields: { run_id: "abc-123", phase: "settle", step: 2, step_id: "step-2" }
|
|
72
|
+
|
|
73
|
+
timeline_event index: 8, event_type: :snapshot, timestamp: "10:00:45",
|
|
74
|
+
label: "state=waiting verification_ok=true step=2",
|
|
75
|
+
fields: { run_id: "abc-123", step: 2, step_id: "step-2", state: "waiting",
|
|
76
|
+
waiting_for_input: true, busy: false, likely_complete: false,
|
|
77
|
+
signals_found: "test passes", signals_missing: "[]",
|
|
78
|
+
verification_ok: true,
|
|
79
|
+
changed_files: "lib/app.rb, test/test_app.rb",
|
|
80
|
+
last_assistant_lines: "All tests pass. Here is the summary..." }
|
|
81
|
+
|
|
82
|
+
timeline_event index: 9, event_type: :intervention, timestamp: "10:00:50",
|
|
83
|
+
label: "action=verify terminal=true step=2",
|
|
84
|
+
fields: { run_id: "abc-123", step: 2, step_id: "step-2", action: "verify",
|
|
85
|
+
intent: "Confirm completion",
|
|
86
|
+
why: "Signals met and verification passes",
|
|
87
|
+
next_step: "Summarize what changed",
|
|
88
|
+
stop_if: "nil",
|
|
89
|
+
rendered_message: "INTENT: Confirm completion\nWHY: All signals met.\nNEXT: Summarize.\nSTOP IF: n/a",
|
|
90
|
+
terminal: true }
|
|
91
|
+
|
|
92
|
+
timeline_event index: 10, event_type: :final, timestamp: "10:01:00",
|
|
93
|
+
label: "interventions=2",
|
|
94
|
+
fields: { run_id: "abc-123", interventions: 2,
|
|
95
|
+
final_transcript_tail: "Done. All tests pass.",
|
|
96
|
+
step_id: "final" }
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
RunViewerApp.run! if __FILE__ == $0
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Demo of ScoreTable and Collapsible components
|
|
4
|
+
# Run: ruby examples/score_and_collapsible_demo.rb
|
|
5
|
+
# Open: http://localhost:4567
|
|
6
|
+
|
|
7
|
+
require_relative '../../lib/stream_weaver'
|
|
8
|
+
|
|
9
|
+
app "Review Dashboard" do
|
|
10
|
+
header "Teachable Moment Review"
|
|
11
|
+
|
|
12
|
+
card do
|
|
13
|
+
header3 "Item 1: Debugging Race Conditions"
|
|
14
|
+
|
|
15
|
+
# Score table with color-coded metrics
|
|
16
|
+
score_table scores: [
|
|
17
|
+
{ label: "Novelty", value: 8, max: 10 },
|
|
18
|
+
{ label: "Struggle→Solution", value: 7, max: 10 },
|
|
19
|
+
{ label: "Reusability", value: 9, max: 10 }
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
text "Themes: debugging, concurrency, testing"
|
|
23
|
+
|
|
24
|
+
# Collapsible context section
|
|
25
|
+
collapsible "View Context (127 words)" do
|
|
26
|
+
text "The developer was working on a payment processing system when they encountered intermittent test failures. After investigation, they discovered a race condition in the async checkout flow. The key insight was using condition-based waiting instead of arbitrary sleep timeouts. This pattern proved highly reusable across other async tests in the codebase."
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
checkbox :item_1, "Include in export"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
card do
|
|
33
|
+
header3 "Item 2: API Rate Limiting Strategy"
|
|
34
|
+
|
|
35
|
+
score_table scores: [
|
|
36
|
+
{ label: "Novelty", value: 5, max: 10 },
|
|
37
|
+
{ label: "Struggle→Solution", value: 4, max: 10 },
|
|
38
|
+
{ label: "Reusability", value: 6, max: 10 }
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
text "Themes: API design, performance"
|
|
42
|
+
|
|
43
|
+
collapsible "View Context (89 words)" do
|
|
44
|
+
text "Standard implementation of exponential backoff with jitter for API rate limiting. While not novel, the specific configuration values were tuned based on production metrics."
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
checkbox :item_2, "Include in export"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
card do
|
|
51
|
+
header3 "Item 3: Memory Leak Detection"
|
|
52
|
+
|
|
53
|
+
score_table scores: [
|
|
54
|
+
{ label: "Novelty", value: 3, max: 10 },
|
|
55
|
+
{ label: "Struggle→Solution", value: 2, max: 10 },
|
|
56
|
+
{ label: "Reusability", value: 3, max: 10 }
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
text "Themes: performance, debugging"
|
|
60
|
+
|
|
61
|
+
collapsible "View Context (45 words)", expanded: true do
|
|
62
|
+
text "Basic memory profiling using standard Ruby tools. No novel insights."
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
checkbox :item_3, "Include in export"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Summary
|
|
69
|
+
div class: "summary" do
|
|
70
|
+
text "---"
|
|
71
|
+
selected = [state[:item_1], state[:item_2], state[:item_3]].count { |v| v }
|
|
72
|
+
text "Selected: #{selected} of 3 items"
|
|
73
|
+
|
|
74
|
+
if selected > 0
|
|
75
|
+
button "Export Selected" do |s|
|
|
76
|
+
s[:exported] = true
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
text "Exported successfully!" if state[:exported]
|
|
81
|
+
end
|
|
82
|
+
end.run!
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Smoke test: browser-cached select value should NOT override server default
|
|
4
|
+
#
|
|
5
|
+
# Steps to reproduce the bug (before fix):
|
|
6
|
+
# 1. Run this app, open in Brave/Chrome
|
|
7
|
+
# 2. Change the select to "banana" or "cherry"
|
|
8
|
+
# 3. Navigate away (e.g. open a different URL)
|
|
9
|
+
# 4. Navigate back — WITHOUT the fix, you'll see the stale "banana"/"cherry"
|
|
10
|
+
# instead of the server default "orange"
|
|
11
|
+
#
|
|
12
|
+
# Expected after fix: always shows "orange" on fresh load
|
|
13
|
+
#
|
|
14
|
+
# Run with: ruby examples/components/select_stale_value_smoke_test.rb
|
|
15
|
+
|
|
16
|
+
require_relative "../../lib/stream_weaver"
|
|
17
|
+
|
|
18
|
+
app = StreamWeaver.app "Select Stale Value Smoke Test" do
|
|
19
|
+
header1 "Select Stale Value Smoke Test"
|
|
20
|
+
|
|
21
|
+
md "**Expected:** the select always shows **orange** after a page refresh or navigate-away-and-back."
|
|
22
|
+
md "**Bug symptom:** Brave/Chrome restores the previous selection instead of the server-rendered default."
|
|
23
|
+
|
|
24
|
+
# Default is "orange" — intentionally NOT the first option
|
|
25
|
+
state[:fruit] ||= "orange"
|
|
26
|
+
|
|
27
|
+
select :fruit, %w[apple orange banana cherry], submit: false
|
|
28
|
+
|
|
29
|
+
card do
|
|
30
|
+
text "Server sees: #{state[:fruit]}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
md "---"
|
|
34
|
+
button "Reset to orange", style: :secondary do |s|
|
|
35
|
+
s[:fruit] = "orange"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
app.run!
|