waygraph 0.15.54 → 0.16.1
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.
- package/README.md +8 -3
- package/bin/waygraph +2 -2
- package/dist/analysis/check.d.ts +38 -0
- package/dist/analysis/check.js +87 -0
- package/dist/analysis/coverage-gap.d.ts +1 -1
- package/dist/analysis/coverage-gap.js +14 -37
- package/dist/analysis/flow-source.d.ts +9 -0
- package/dist/analysis/flow-source.js +25 -0
- package/dist/analysis/graph.d.ts +10 -14
- package/dist/analysis/graph.js +48 -371
- package/dist/analysis/map-check.js +4 -39
- package/dist/analysis/practices-check.d.ts +1 -1
- package/dist/analysis/practices-check.js +24 -45
- package/dist/cli/args.d.ts +23 -0
- package/dist/cli/args.js +20 -0
- package/dist/{cli.d.ts → cli/cli.d.ts} +0 -1
- package/dist/{cli.js → cli/cli.js} +10 -9
- package/dist/{commands → cli/commands}/agent-dive-scaffold.js +35 -64
- package/dist/cli/commands/agent-dive.js +42 -0
- package/dist/cli/commands/browser.d.ts +2 -0
- package/dist/cli/commands/browser.js +109 -0
- package/dist/{commands → cli/commands}/check.d.ts +0 -1
- package/dist/cli/commands/check.js +104 -0
- package/dist/cli/commands/codemod-checkpoints.d.ts +18 -0
- package/dist/cli/commands/codemod-checkpoints.js +186 -0
- package/dist/cli/commands/codemod-flows.d.ts +18 -0
- package/dist/cli/commands/codemod-flows.js +284 -0
- package/dist/cli/commands/codemod-stubs.d.ts +10 -0
- package/dist/cli/commands/codemod-stubs.js +187 -0
- package/dist/{commands → cli/commands}/extensions.js +5 -4
- package/dist/{commands → cli/commands}/init.js +1 -2
- package/dist/{commands → cli/commands}/list.js +9 -7
- package/dist/cli/commands/manifest.d.ts +2 -0
- package/dist/cli/commands/manifest.js +20 -0
- package/dist/cli/commands/map.js +57 -0
- package/dist/cli/commands/pilot.d.ts +2 -0
- package/dist/cli/commands/pilot.js +102 -0
- package/dist/{commands → cli/commands}/run.d.ts +0 -1
- package/dist/cli/commands/run.js +64 -0
- package/dist/cli/commands/session-ops.d.ts +3 -0
- package/dist/cli/commands/session-ops.js +257 -0
- package/dist/cli/commands/session.js +132 -0
- package/dist/{commands → cli/commands}/test.js +11 -14
- package/dist/cli/commands/traverse.js +105 -0
- package/dist/{commands → cli/commands}/try.js +29 -25
- package/dist/{commands → cli/commands}/upgrade.js +40 -4
- package/dist/cli/flags.d.ts +193 -16
- package/dist/cli/flags.js +179 -234
- package/dist/cli/run-chain.d.ts +1 -0
- package/dist/cli/run-chain.js +42 -7
- package/dist/cli/usage.d.ts +1 -1
- package/dist/cli/usage.js +21 -53
- package/dist/cli/util.d.ts +2 -2
- package/dist/cli/util.js +2 -3
- package/dist/{highlights → demo/narration}/css.d.ts +1 -1
- package/dist/{highlights → demo/narration}/css.js +2 -3
- package/dist/{highlights → demo/narration}/demo-pace.d.ts +4 -12
- package/dist/{highlights → demo/narration}/demo-pace.js +5 -11
- package/dist/{highlights → demo/narration}/device.d.ts +4 -4
- package/dist/{highlights → demo/narration}/device.js +1 -1
- package/dist/demo/narration/merge.d.ts +10 -0
- package/dist/demo/narration/merge.js +67 -0
- package/dist/demo/narration/narration.d.ts +39 -0
- package/dist/{highlights/run-phase.js → demo/narration/narration.js} +25 -94
- package/dist/{highlights → demo/narration}/shorthand.d.ts +1 -1
- package/dist/demo/narration/stub-ctx.d.ts +8 -0
- package/dist/demo/narration/stub-ctx.js +164 -0
- package/dist/{highlights → demo/narration}/style.d.ts +1 -7
- package/dist/{highlights → demo/narration}/style.js +1 -41
- package/dist/{highlights → demo/narration}/todo-dock.d.ts +8 -8
- package/dist/{highlights → demo/narration}/todo-dock.js +13 -30
- package/dist/demo/overlay/auto-chrome.d.ts +7 -0
- package/dist/demo/overlay/auto-chrome.js +97 -0
- package/dist/demo/overlay/cursor.d.ts +19 -0
- package/dist/demo/overlay/cursor.js +142 -0
- package/dist/demo/overlay/device-stage.d.ts +26 -0
- package/dist/demo/overlay/device-stage.js +396 -0
- package/dist/demo/overlay/inpage/banner.d.ts +2 -0
- package/dist/demo/overlay/inpage/banner.js +160 -0
- package/dist/demo/overlay/inpage/caption.d.ts +2 -0
- package/dist/demo/overlay/inpage/caption.js +24 -0
- package/dist/demo/overlay/inpage/core.d.ts +2 -0
- package/dist/demo/overlay/inpage/core.js +345 -0
- package/dist/demo/overlay/inpage/device-chip.d.ts +1 -0
- package/dist/demo/overlay/inpage/device-chip.js +191 -0
- package/dist/demo/overlay/inpage/network.d.ts +10 -0
- package/dist/demo/overlay/inpage/network.js +189 -0
- package/dist/demo/overlay/inpage/panel-chrome.d.ts +1 -0
- package/dist/demo/overlay/inpage/panel-chrome.js +203 -0
- package/dist/demo/overlay/inpage/stamp.d.ts +1 -0
- package/dist/demo/overlay/inpage/stamp.js +46 -0
- package/dist/demo/overlay/inpage/swipe-zoom.d.ts +1 -0
- package/dist/demo/overlay/inpage/swipe-zoom.js +220 -0
- package/dist/demo/overlay/inpage/todos.d.ts +2 -0
- package/dist/demo/overlay/inpage/todos.js +293 -0
- package/dist/demo/overlay/locator-theater.d.ts +25 -0
- package/dist/demo/overlay/locator-theater.js +76 -0
- package/dist/demo/overlay/network-capture.d.ts +22 -0
- package/dist/demo/overlay/network-capture.js +127 -0
- package/dist/demo/overlay/overlay-css.d.ts +3 -0
- package/dist/demo/overlay/overlay-css.js +369 -0
- package/dist/demo/overlay/overlay-stage.d.ts +31 -0
- package/dist/demo/overlay/overlay-stage.js +106 -0
- package/dist/demo/overlay/overlay.d.ts +10 -0
- package/dist/demo/overlay/overlay.js +89 -0
- package/dist/{pilot-overlay/overlay-fixtures.d.ts → demo/overlay/phase-fixtures.d.ts} +2 -2
- package/dist/{pilot-overlay/overlay-fixtures.js → demo/overlay/phase-fixtures.js} +2 -2
- package/dist/{pilot-overlay/action-ring.js → demo/overlay/pilot/actions.js} +2 -1
- package/dist/{pilot-overlay → demo/overlay/pilot}/fixtures.d.ts +6 -5
- package/dist/{pilot-overlay → demo/overlay/pilot}/fixtures.js +19 -18
- package/dist/{pilot-overlay → demo/overlay/pilot}/shell.d.ts +2 -2
- package/dist/{pilot-overlay → demo/overlay/pilot}/shell.js +13 -22
- package/dist/demo/overlay/reattach.d.ts +7 -0
- package/dist/demo/overlay/reattach.js +23 -0
- package/dist/demo/overlay/rings.d.ts +61 -0
- package/dist/demo/overlay/rings.js +422 -0
- package/dist/{ui → demo/overlay/ui}/components/ring.js +2 -2
- package/dist/{ui → demo/overlay/ui}/overlay.css +4 -4
- package/dist/{ui → demo/overlay/ui}/shadow.d.ts +1 -1
- package/dist/{ui → demo/overlay/ui}/shadow.js +39 -2
- package/dist/demo/stepper/after.d.ts +3 -0
- package/dist/demo/stepper/after.js +103 -0
- package/dist/demo/stepper/banner-log.d.ts +35 -0
- package/dist/demo/stepper/banner-log.js +65 -0
- package/dist/demo/stepper/before.d.ts +4 -0
- package/dist/demo/stepper/before.js +110 -0
- package/dist/demo/stepper/demo-log.d.ts +48 -0
- package/dist/demo/stepper/demo-log.js +292 -0
- package/dist/demo/stepper/gate.d.ts +11 -0
- package/dist/demo/stepper/gate.js +78 -0
- package/dist/demo/stepper/interaction-patch.d.ts +4 -0
- package/dist/demo/stepper/interaction-patch.js +323 -0
- package/dist/demo/stepper/pacing.d.ts +21 -0
- package/dist/demo/stepper/pacing.js +23 -0
- package/dist/demo/stepper/panel-after.d.ts +17 -0
- package/dist/demo/stepper/panel-after.js +166 -0
- package/dist/demo/stepper/panel-before.d.ts +12 -0
- package/dist/demo/stepper/panel-before.js +241 -0
- package/dist/demo/stepper/slides.d.ts +23 -0
- package/dist/demo/stepper/slides.js +233 -0
- package/dist/demo/stepper/step-panels.d.ts +69 -0
- package/dist/demo/stepper/step-panels.js +172 -0
- package/dist/demo/stepper/stepper.d.ts +24 -0
- package/dist/demo/stepper/stepper.js +122 -0
- package/dist/demo/stepper/teardown.d.ts +47 -0
- package/dist/demo/stepper/teardown.js +178 -0
- package/dist/demo/stepper/todo-advance.d.ts +15 -0
- package/dist/demo/stepper/todo-advance.js +110 -0
- package/dist/demo/stepper/view.d.ts +58 -0
- package/dist/demo/stepper/view.js +31 -0
- package/dist/demo/types.d.ts +85 -0
- package/dist/demo/verbose-log.js +15 -0
- package/dist/engine/block/action-page.d.ts +53 -0
- package/dist/engine/block/action-page.js +1 -0
- package/dist/{types.d.ts → engine/block/block.d.ts} +102 -142
- package/dist/{core → engine/block}/block.js +12 -130
- package/dist/engine/block/branch.d.ts +17 -0
- package/dist/engine/block/branch.js +40 -0
- package/dist/{core → engine/block}/compose.d.ts +9 -7
- package/dist/{core → engine/block}/compose.js +1 -1
- package/dist/engine/block/dialog.d.ts +13 -0
- package/dist/engine/block/dialog.js +37 -0
- package/dist/{core/blocks → engine/block/kinds}/api.d.ts +16 -12
- package/dist/{core/blocks → engine/block/kinds}/api.js +26 -18
- package/dist/{core/blocks → engine/block/kinds}/effect.d.ts +13 -18
- package/dist/engine/block/kinds/effect.js +17 -0
- package/dist/{core/blocks → engine/block/kinds}/method.d.ts +17 -29
- package/dist/{core/blocks → engine/block/kinds}/method.js +6 -21
- package/dist/{core/blocks → engine/block/kinds}/nav.d.ts +21 -31
- package/dist/{core/blocks → engine/block/kinds}/nav.js +6 -12
- package/dist/{core/blocks → engine/block/kinds}/page.d.ts +14 -20
- package/dist/{core/blocks → engine/block/kinds}/page.js +5 -7
- package/dist/engine/checkpoint/checkpoint.d.ts +22 -0
- package/dist/engine/checkpoint/checkpoint.js +8 -0
- package/dist/engine/checkpoint/route.d.ts +28 -0
- package/dist/engine/checkpoint/route.js +28 -0
- package/dist/{core → engine}/config.d.ts +7 -2
- package/dist/engine/config.js +6 -0
- package/dist/engine/engine.d.ts +45 -0
- package/dist/{core → engine}/engine.js +6 -10
- package/dist/engine/env.d.ts +59 -0
- package/dist/engine/env.js +83 -0
- package/dist/{errors.d.ts → engine/errors.d.ts} +22 -22
- package/dist/{errors.js → engine/errors.js} +22 -22
- package/dist/{core → engine/flow}/branch-regression.d.ts +7 -7
- package/dist/{core → engine/flow}/branch-regression.js +4 -3
- package/dist/engine/flow/flow.d.ts +162 -0
- package/dist/engine/flow/flow.js +244 -0
- package/dist/engine/flow/map-branch.d.ts +9 -0
- package/dist/engine/flow/map-branch.js +57 -0
- package/dist/{core → engine/flow}/map-builder.d.ts +34 -54
- package/dist/engine/flow/map-builder.js +242 -0
- package/dist/engine/flow/map-steps.d.ts +30 -0
- package/dist/engine/flow/map-steps.js +87 -0
- package/dist/{core → engine}/locate.d.ts +1 -1
- package/dist/{core → engine}/locate.js +1 -2
- package/dist/{mem-stub.d.ts → engine/mem/mem-stub.d.ts} +9 -8
- package/dist/{mem-stub.js → engine/mem/mem-stub.js} +2 -2
- package/dist/{mem-page.d.ts → engine/mem/mem.d.ts} +1 -1
- package/dist/{mem-page.js → engine/mem/mem.js} +2 -1
- package/dist/engine/page-gone.d.ts +5 -0
- package/dist/engine/page-gone.js +20 -0
- package/dist/engine/run/connect.d.ts +28 -0
- package/dist/{types.js → engine/run/connect.js} +11 -10
- package/dist/engine/run/events.d.ts +67 -0
- package/dist/engine/run/events.js +90 -0
- package/dist/engine/run/hooks.d.ts +16 -0
- package/dist/engine/run/hooks.js +8 -0
- package/dist/engine/run/launch.d.ts +13 -0
- package/dist/engine/run/launch.js +27 -0
- package/dist/{core/run-graph.d.ts → engine/run/run.d.ts} +8 -12
- package/dist/{core/run-graph.js → engine/run/run.js} +22 -12
- package/dist/engine/stub/pace.d.ts +12 -0
- package/dist/engine/stub/pace.js +2 -0
- package/dist/engine/stub/ring.d.ts +130 -0
- package/dist/engine/stub/ring.js +41 -0
- package/dist/engine/stub/stub.d.ts +268 -0
- package/dist/engine/stub/stub.js +1 -0
- package/dist/engine/stub/todos.d.ts +104 -0
- package/dist/engine/stub/todos.js +2 -0
- package/dist/engine/stub/viewport.d.ts +26 -0
- package/dist/engine/stub/viewport.js +2 -0
- package/dist/{trait.d.ts → engine/trait/trait.d.ts} +1 -1
- package/dist/{trait.js → engine/trait/trait.js} +1 -1
- package/dist/index.d.ts +88 -36
- package/dist/index.js +46 -19
- package/dist/live/auto/auto.d.ts +22 -0
- package/dist/live/auto/auto.js +207 -0
- package/dist/{session/auto-explore.d.ts → live/auto/explore.d.ts} +4 -14
- package/dist/{session/auto-explore.js → live/auto/explore.js} +21 -127
- package/dist/live/auto/mem.d.ts +11 -0
- package/dist/live/auto/mem.js +85 -0
- package/dist/live/auto/menu.d.ts +30 -0
- package/dist/live/auto/menu.js +335 -0
- package/dist/live/auto-session/auto-session.d.ts +113 -0
- package/dist/live/auto-session/auto-session.js +452 -0
- package/dist/live/auto-session/console.d.ts +4 -0
- package/dist/live/auto-session/console.js +41 -0
- package/dist/live/auto-session/files.d.ts +44 -0
- package/dist/live/auto-session/files.js +145 -0
- package/dist/{auto-session → live/auto-session}/helpers.d.ts +9 -5
- package/dist/{auto-session → live/auto-session}/helpers.js +18 -1
- package/dist/live/auto-session/inspect.d.ts +4 -0
- package/dist/live/auto-session/inspect.js +75 -0
- package/dist/{session/auto-session-ipc.d.ts → live/auto-session/ipc.d.ts} +8 -25
- package/dist/{session/auto-session-ipc.js → live/auto-session/ipc.js} +36 -161
- package/dist/live/auto-session/open-browser.d.ts +6 -0
- package/dist/live/auto-session/open-browser.js +47 -0
- package/dist/{session/browser.d.ts → live/auto-session/start.d.ts} +1 -2
- package/dist/{session/browser.js → live/auto-session/start.js} +2 -3
- package/dist/{pilot-overlay → live/pilot}/panel.d.ts +1 -1
- package/dist/{pilot-overlay → live/pilot}/panel.js +23 -31
- package/dist/{session → live/pilot}/pilot.d.ts +3 -3
- package/dist/{session → live/pilot}/pilot.js +5 -4
- package/dist/{traverse/run.d.ts → live/traverse/traverse.d.ts} +1 -1
- package/dist/live/traverse/traverse.js +212 -0
- package/dist/live/traverse/worker.d.ts +37 -0
- package/dist/live/traverse/worker.js +200 -0
- package/dist/manifest/manifest.d.ts +52 -0
- package/dist/manifest/manifest.js +93 -0
- package/dist/manifest/map-imports.d.ts +7 -0
- package/dist/manifest/map-imports.js +22 -0
- package/dist/manifest/maps.d.ts +33 -0
- package/dist/manifest/maps.js +62 -0
- package/dist/manifest/pack.d.ts +21 -0
- package/dist/manifest/pack.js +109 -0
- package/dist/manifest/project.d.ts +60 -0
- package/dist/manifest/project.js +101 -0
- package/dist/{session/block-inject.js → manifest/roots.js} +1 -18
- package/dist/manifest/scan.d.ts +19 -0
- package/dist/manifest/scan.js +57 -0
- package/dist/manifest/source.d.ts +23 -0
- package/dist/manifest/source.js +86 -0
- package/dist/runner/mode.d.ts +71 -0
- package/dist/runner/mode.js +1 -0
- package/dist/runner/modes/branches.d.ts +5 -0
- package/dist/runner/modes/branches.js +37 -0
- package/dist/runner/modes/demo.d.ts +3 -0
- package/dist/runner/modes/demo.js +13 -0
- package/dist/runner/modes/report.d.ts +2 -0
- package/dist/runner/modes/report.js +54 -0
- package/dist/runner/modes/run.d.ts +2 -0
- package/dist/runner/modes/run.js +3 -0
- package/dist/runner/options.d.ts +31 -0
- package/dist/runner/options.js +42 -0
- package/dist/runner/plan/find.d.ts +18 -0
- package/dist/runner/plan/find.js +65 -0
- package/dist/runner/plan/plan.d.ts +11 -0
- package/dist/runner/plan/plan.js +97 -0
- package/dist/runner/plan/seed-mem.d.ts +12 -0
- package/dist/runner/plan/seed-mem.js +98 -0
- package/dist/runner/plan/spec.d.ts +5 -0
- package/dist/runner/plan/spec.js +17 -0
- package/dist/runner/play-steps.d.ts +2 -0
- package/dist/runner/play-steps.js +59 -0
- package/dist/runner/runner.d.ts +4 -0
- package/dist/runner/runner.js +64 -0
- package/dist/runner/session.d.ts +9 -0
- package/dist/runner/session.js +87 -0
- package/dist/{browser.js → runtime/browser.js} +4 -2
- package/dist/{env-file.js → runtime/env-file.js} +7 -12
- package/dist/{extensions.d.ts → runtime/extensions.d.ts} +1 -5
- package/dist/{extensions.js → runtime/extensions.js} +2 -1
- package/dist/runtime/full-launch.d.ts +1 -0
- package/dist/runtime/full-launch.js +34 -0
- package/dist/runtime/global-flag.d.ts +5 -0
- package/dist/runtime/global-flag.js +18 -0
- package/dist/{playwright-config.d.ts → runtime/playwright-config.d.ts} +1 -1
- package/dist/{playwright.config.js → runtime/playwright.config.js} +3 -2
- package/dist/runtime/run-log.d.ts +2 -0
- package/dist/runtime/run-log.js +17 -0
- package/dist/{video-dir.js → runtime/video-dir.js} +3 -2
- package/dist/{config.d.ts → runtime/waygraph-config.d.ts} +6 -9
- package/dist/{config.js → runtime/waygraph-config.js} +21 -51
- package/dist/{webserver.js → runtime/webserver.js} +5 -30
- package/examples/routed-demo/config/waygraph.config.ts +20 -0
- package/examples/routed-demo/package.json +1 -4
- package/examples/routed-demo/scripts/fixture-server.mjs +1 -1
- package/examples/routed-demo/src/flows/routed-demo-map.flow.ts +2 -4
- package/examples/routed-demo/src/flows/routed-demo.flow.ts +1 -2
- package/examples/routed-demo/src/map/(app_base)/dashboard/_methods/click-widget.block.ts +5 -4
- package/examples/routed-demo/src/map/(app_base)/dashboard/_nav.block.ts +3 -3
- package/examples/routed-demo/src/map/(app_base)/dashboard/_page.block.ts +3 -3
- package/examples/routed-demo/src/map/(external)/docs/_nav.block.ts +3 -3
- package/examples/routed-demo/src/map/(external)/docs/_page.block.ts +3 -3
- package/examples/routed-demo/src/states/routed-demo.states.ts +5 -3
- package/examples/routed-demo/tests/routed-demo.spec.ts +4 -4
- package/examples/routed-demo/tsconfig.json +1 -1
- package/examples/saucedemo/docs/CONVENTION.md +4 -5
- package/examples/saucedemo/docs/HELPERS.md +11 -11
- package/examples/saucedemo/src/blocks/SITE-MAP.md +0 -1
- package/examples/saucedemo/src/blocks/saucedemo-web/NAV.md +1 -5
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +5 -8
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-all-to-cart.method.block.ts +4 -6
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +35 -43
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/remove-all-from-cart.method.block.ts +4 -6
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/remove-from-cart.effect.block.ts +4 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +4 -5
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +5 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/nav-login.block.ts +3 -3
- package/examples/saucedemo/src/flows/api-demo.flow.ts +12 -10
- package/examples/saucedemo/src/states/checkout.states.ts +21 -11
- package/examples/saucedemo/src/stubs/device-showcase.ts +8 -10
- package/examples/saucedemo/tests/auto-graph.spec.ts +4 -12
- package/package.json +14 -6
- package/templates/agents/waygraph-planner.agent.md +2 -2
- package/templates/quickstart/docs/CONVENTION.md +4 -4
- package/templates/quickstart/docs/HELPERS.md +10 -8
- package/templates/quickstart/package.json +0 -3
- package/templates/quickstart/src/blocks/SITE-MAP.md +0 -1
- package/templates/quickstart/src/blocks/saucedemo-web/NAV.md +1 -5
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +5 -8
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-all-to-cart.method.block.ts +4 -6
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +35 -43
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/remove-all-from-cart.method.block.ts +4 -6
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/remove-from-cart.effect.block.ts +4 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +4 -5
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +5 -4
- package/templates/quickstart/src/blocks/saucedemo-web/nav-login.block.ts +3 -3
- package/templates/quickstart/src/flows/api-demo.flow.ts +12 -10
- package/templates/quickstart/src/states/checkout.states.ts +21 -11
- package/templates/quickstart/src/stubs/device-showcase.ts +8 -10
- package/templates/scaffold/README.md +2 -1
- package/templates/scaffold/STRUCTURE.md +5 -4
- package/templates/scaffold/config/waygraph.config.ts +1 -0
- package/templates/scaffold/gitignore +1 -0
- package/templates/scaffold/src/flows/README.md +2 -2
- package/templates/scaffold/src/map/(app_base)/docs/_nav.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/docs/_page.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/home/_methods/add-item.effect.block.ts +4 -4
- package/templates/scaffold/src/map/(app_base)/home/_methods/assert-hello.method.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/home/_methods/assert-item-added.method.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/home/_methods/clear-cart.method.block.ts +5 -4
- package/templates/scaffold/src/map/(app_base)/home/_methods/remove-item.effect.block.ts +4 -4
- package/templates/scaffold/src/map/(app_base)/home/_nav.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/home/_page.block.ts +3 -3
- package/templates/scaffold/src/map/(app_base)/home/nav-verification-link.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_keys.ts +21 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-body.method.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-header.method.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-status.method.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/pick-extension-interceptor.method.block.ts +5 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-body.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-headers.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/send-request.method.block.ts +5 -4
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-bearer-token.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-headers.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-json-body.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-method.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-query-params.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-url.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/hoppscotch/_nav.block.ts +3 -3
- package/templates/scaffold/src/map/(external)/hoppscotch/_page.block.ts +3 -3
- package/templates/scaffold/src/map/(external)/hoppscotch/_states.ts +6 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/settings/_nav.block.ts +3 -3
- package/templates/scaffold/src/map/(external)/mailpit/_keys.ts +13 -0
- package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-content.method.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-received.method.block.ts +4 -4
- package/templates/scaffold/src/map/(external)/mailpit/_methods/extract-email-link.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/mailpit/_methods/open-message.method.block.ts +6 -5
- package/templates/scaffold/src/map/(external)/mailpit/_nav.block.ts +3 -3
- package/templates/scaffold/src/map/(external)/mailpit/_page.block.ts +3 -3
- package/templates/scaffold/src/map/(external)/mailpit/_states.ts +9 -0
- package/templates/scaffold/src/map/README.md +7 -0
- package/templates/scaffold/src/states/README.md +4 -1
- package/templates/scaffold/src/states/demo.mem-keys.ts +1 -29
- package/templates/scaffold/src/states/demo.states.ts +14 -20
- package/templates/scaffold/tests/hoppscotch.spec.ts +1 -11
- package/templates/scaffold/tests/mail-verify.spec.ts +2 -2
- package/templates/skills/waygraph-blind-pilot.skill.md +2 -6
- package/templates/skills/waygraph-convention.skill.md +23 -14
- package/templates/skills/waygraph-pilot.skill.md +7 -4
- package/dist/auto-session/session.d.ts +0 -193
- package/dist/auto-session/session.js +0 -719
- package/dist/auto-session/verbose-log.js +0 -16
- package/dist/auto-session.d.ts +0 -2
- package/dist/auto-session.js +0 -3
- package/dist/cli/discover.d.ts +0 -40
- package/dist/cli/discover.js +0 -148
- package/dist/commands/agent-dive.js +0 -52
- package/dist/commands/check.js +0 -192
- package/dist/commands/map.js +0 -29
- package/dist/commands/run.js +0 -104
- package/dist/commands/session.js +0 -600
- package/dist/commands/traverse.js +0 -177
- package/dist/core/block.d.ts +0 -109
- package/dist/core/blocks/effect.js +0 -23
- package/dist/core/config.js +0 -17
- package/dist/core/engine.d.ts +0 -198
- package/dist/core/flow.d.ts +0 -294
- package/dist/core/flow.js +0 -432
- package/dist/core/map-builder.js +0 -383
- package/dist/core.d.ts +0 -14
- package/dist/core.js +0 -15
- package/dist/highlights/merge.d.ts +0 -8
- package/dist/highlights/merge.js +0 -173
- package/dist/highlights/run-phase.d.ts +0 -43
- package/dist/highlights/stub-ctx.d.ts +0 -10
- package/dist/highlights/stub-ctx.js +0 -331
- package/dist/highlights/types.d.ts +0 -613
- package/dist/highlights.d.ts +0 -9
- package/dist/highlights.js +0 -10
- package/dist/pilot-overlay.d.ts +0 -5
- package/dist/pilot-overlay.js +0 -6
- package/dist/runner/banner-log.js +0 -63
- package/dist/runner/chain-run.js +0 -102
- package/dist/runner/cursor.js +0 -140
- package/dist/runner/demo-log.js +0 -316
- package/dist/runner/device-stage.d.ts +0 -9
- package/dist/runner/device-stage.js +0 -420
- package/dist/runner/discovery.js +0 -105
- package/dist/runner/index.js +0 -2
- package/dist/runner/inpage/banner.d.ts +0 -21
- package/dist/runner/inpage/banner.js +0 -156
- package/dist/runner/inpage/caption.d.ts +0 -3
- package/dist/runner/inpage/caption.js +0 -23
- package/dist/runner/inpage/core.d.ts +0 -4
- package/dist/runner/inpage/core.js +0 -316
- package/dist/runner/inpage/device.d.ts +0 -3
- package/dist/runner/inpage/device.js +0 -211
- package/dist/runner/inpage/network.d.ts +0 -15
- package/dist/runner/inpage/network.js +0 -217
- package/dist/runner/inpage/panel-chrome.js +0 -192
- package/dist/runner/inpage/stamp.js +0 -46
- package/dist/runner/inpage/swipe-zoom.js +0 -220
- package/dist/runner/inpage/todos.js +0 -337
- package/dist/runner/interaction-patch.js +0 -384
- package/dist/runner/main.js +0 -469
- package/dist/runner/network-capture.d.ts +0 -9
- package/dist/runner/network-capture.js +0 -126
- package/dist/runner/overlay-css.d.ts +0 -3
- package/dist/runner/overlay-css.js +0 -377
- package/dist/runner/overlay-install.js +0 -90
- package/dist/runner/overlay-stage.js +0 -110
- package/dist/runner/rings.js +0 -514
- package/dist/runner/seed-mem.js +0 -110
- package/dist/runner/slides.js +0 -278
- package/dist/runner/step-mode.js +0 -703
- package/dist/runner/step-panels.js +0 -729
- package/dist/runner/teardown.js +0 -202
- package/dist/runner/todo-dock.js +0 -142
- package/dist/session/auto-explore-run.d.ts +0 -40
- package/dist/session/auto-explore-run.js +0 -707
- package/dist/session/step-overlay.d.ts +0 -37
- package/dist/session/step-overlay.js +0 -244
- package/dist/traverse/run.js +0 -423
- package/examples/routed-demo/playwright.config.ts +0 -21
- package/examples/saucedemo/src/blocks/saucedemo-web/ff-owner-auth.block.ts +0 -22
- package/templates/quickstart/src/blocks/saucedemo-web/ff-owner-auth.block.ts +0 -22
- /package/dist/{commands → cli/commands}/agent-dive-scaffold.d.ts +0 -0
- /package/dist/{commands → cli/commands}/agent-dive.d.ts +0 -0
- /package/dist/{commands → cli/commands}/extensions.d.ts +0 -0
- /package/dist/{commands → cli/commands}/init.d.ts +0 -0
- /package/dist/{commands → cli/commands}/list.d.ts +0 -0
- /package/dist/{commands → cli/commands}/map.d.ts +0 -0
- /package/dist/{commands → cli/commands}/session.d.ts +0 -0
- /package/dist/{commands → cli/commands}/test.d.ts +0 -0
- /package/dist/{commands → cli/commands}/traverse.d.ts +0 -0
- /package/dist/{commands → cli/commands}/try.d.ts +0 -0
- /package/dist/{commands → cli/commands}/upgrade.d.ts +0 -0
- /package/dist/{highlights → demo/narration}/shorthand.js +0 -0
- /package/dist/{session/overlay-beacon.d.ts → demo/overlay/beacon.d.ts} +0 -0
- /package/dist/{session/overlay-beacon.js → demo/overlay/beacon.js} +0 -0
- /package/dist/{pilot-overlay/action-ring.d.ts → demo/overlay/pilot/actions.d.ts} +0 -0
- /package/dist/{ui → demo/overlay/ui}/components/ring.d.ts +0 -0
- /package/dist/{ui → demo/overlay/ui}/stylesheet.d.ts +0 -0
- /package/dist/{ui → demo/overlay/ui}/stylesheet.js +0 -0
- /package/dist/{ui → demo/overlay/ui}/tokens.d.ts +0 -0
- /package/dist/{ui → demo/overlay/ui}/tokens.js +0 -0
- /package/dist/{highlights → demo}/types.js +0 -0
- /package/dist/{auto-session → demo}/verbose-log.d.ts +0 -0
- /package/dist/{selector.d.ts → engine/trait/selector.d.ts} +0 -0
- /package/dist/{selector.js → engine/trait/selector.js} +0 -0
- /package/dist/{traverse → live/traverse}/coverage.d.ts +0 -0
- /package/dist/{traverse → live/traverse}/coverage.js +0 -0
- /package/dist/{traverse → live/traverse}/lease.d.ts +0 -0
- /package/dist/{traverse → live/traverse}/lease.js +0 -0
- /package/dist/{session/block-inject.d.ts → manifest/roots.d.ts} +0 -0
- /package/dist/{blocks-select.d.ts → manifest/select.d.ts} +0 -0
- /package/dist/{blocks-select.js → manifest/select.js} +0 -0
- /package/dist/{browser.d.ts → runtime/browser.d.ts} +0 -0
- /package/dist/{env-file.d.ts → runtime/env-file.d.ts} +0 -0
- /package/dist/{playwright-config.js → runtime/playwright-config.js} +0 -0
- /package/dist/{playwright.config.d.ts → runtime/playwright.config.d.ts} +0 -0
- /package/dist/{video-dir.d.ts → runtime/video-dir.d.ts} +0 -0
- /package/dist/{webserver.d.ts → runtime/webserver.d.ts} +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// The one place a project's files are walked and imported. Everything that needs the project's Blocks or Flows
|
|
2
|
+
// (graph, check, map, auto, traverse, the runner) goes through here.
|
|
3
|
+
import { readdirSync, statSync } from "node:fs";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
/** Every file under `dir` whose name matches, skipping `node_modules`, `dist` and `.git`. */
|
|
7
|
+
export function walkDir(dir, pattern) {
|
|
8
|
+
const results = [];
|
|
9
|
+
let entries;
|
|
10
|
+
try {
|
|
11
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return results;
|
|
15
|
+
}
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
const full = join(dir, entry.name);
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git")
|
|
20
|
+
continue;
|
|
21
|
+
results.push(...walkDir(full, pattern));
|
|
22
|
+
}
|
|
23
|
+
else if (pattern.test(entry.name)) {
|
|
24
|
+
results.push(full);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return results;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Imports a project file. The file's mtime is part of the URL: Node caches an ESM import per specifier for the life of the
|
|
31
|
+
* process, so a long-running session reloading an edited Block would otherwise keep the first version.
|
|
32
|
+
*/
|
|
33
|
+
export async function importFresh(filePath) {
|
|
34
|
+
const resolved = resolve(filePath);
|
|
35
|
+
const url = pathToFileURL(resolved);
|
|
36
|
+
url.searchParams.set("t", String(statSync(resolved).mtimeMs));
|
|
37
|
+
return (await import(url.href));
|
|
38
|
+
}
|
|
39
|
+
export function isBlockLike(val) {
|
|
40
|
+
if (val === null || typeof val !== "object")
|
|
41
|
+
return false;
|
|
42
|
+
const obj = val;
|
|
43
|
+
if (typeof obj.name !== "string")
|
|
44
|
+
return false;
|
|
45
|
+
const instruction = obj.instruction;
|
|
46
|
+
return instruction !== null && typeof instruction === "object" && typeof instruction?.act === "function";
|
|
47
|
+
}
|
|
48
|
+
export function isFlowLike(val) {
|
|
49
|
+
return (val !== null &&
|
|
50
|
+
typeof val === "object" &&
|
|
51
|
+
typeof val.run === "function" &&
|
|
52
|
+
typeof val.blocks === "function");
|
|
53
|
+
}
|
|
54
|
+
/** The factory kind a Block was built with (`nav`, `page`, `assert`), or undefined for Methods and Effects. */
|
|
55
|
+
export function blockKind(block) {
|
|
56
|
+
return block.__waygraphKind;
|
|
57
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SourceFile } from "ts-morph";
|
|
2
|
+
/** The file as it is on disk now. */
|
|
3
|
+
export declare function parseSource(file: string): SourceFile;
|
|
4
|
+
/** Names the file exports: `export const|let|var|function|class X`, and `export { X }`. */
|
|
5
|
+
export declare function exportedNames(sf: SourceFile): string[];
|
|
6
|
+
/** Every module the file imports or re-exports from, including dynamic `import("x")`. */
|
|
7
|
+
export declare function importSpecifiers(sf: SourceFile): string[];
|
|
8
|
+
/** Names imported from modules whose specifier passes `from`, in source order (the imported name, not an alias). */
|
|
9
|
+
export declare function namedImportsFrom(sf: SourceFile, from: (specifier: string) => boolean): string[];
|
|
10
|
+
/** The string literal at `argIndex` of every call whose callee text passes `callee`, in source order. */
|
|
11
|
+
export declare function stringArgs(sf: SourceFile, callee: (text: string) => boolean, argIndex?: number): string[];
|
|
12
|
+
/** A string property of the object literal passed to every matching call: `Trait.url({ pathname: "/x" })` -> "/x". */
|
|
13
|
+
export declare function objectArgProperty(sf: SourceFile, callee: (text: string) => boolean, property: string): string[];
|
|
14
|
+
/** Every string literal in the file (comments are not strings), with the property name it initializes, if any. */
|
|
15
|
+
export declare function stringLiterals(sf: SourceFile): {
|
|
16
|
+
value: string;
|
|
17
|
+
property: string | undefined;
|
|
18
|
+
}[];
|
|
19
|
+
/** Every call in the file (comments and strings are not calls): its callee as written and whether its first argument is a string. */
|
|
20
|
+
export declare function calls(sf: SourceFile): {
|
|
21
|
+
callee: string;
|
|
22
|
+
literalFirstArg: boolean;
|
|
23
|
+
}[];
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Reads a TypeScript file's shape (its exports, imports, string arguments) from the AST (ts-morph), for the places that
|
|
2
|
+
// need it without importing the file: `list`, `nav`, a flow file's export name, a map group's imports.
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { Node, Project, SyntaxKind } from "ts-morph";
|
|
5
|
+
const project = new Project({ useInMemoryFileSystem: true, skipFileDependencyResolution: true });
|
|
6
|
+
/** The file as it is on disk now. */
|
|
7
|
+
export function parseSource(file) {
|
|
8
|
+
return project.createSourceFile(file.replace(/\\/g, "/").replace(/^[A-Za-z]:/, ""), readFileSync(file, "utf8"), { overwrite: true });
|
|
9
|
+
}
|
|
10
|
+
/** Names the file exports: `export const|let|var|function|class X`, and `export { X }`. */
|
|
11
|
+
export function exportedNames(sf) {
|
|
12
|
+
const names = [];
|
|
13
|
+
for (const statement of sf.getStatements()) {
|
|
14
|
+
if (Node.isVariableStatement(statement) && statement.isExported())
|
|
15
|
+
names.push(...statement.getDeclarations().map((d) => d.getName()));
|
|
16
|
+
else if ((Node.isFunctionDeclaration(statement) || Node.isClassDeclaration(statement)) && statement.isExported() && statement.getName())
|
|
17
|
+
names.push(statement.getName());
|
|
18
|
+
else if (Node.isExportDeclaration(statement) && !statement.getModuleSpecifier())
|
|
19
|
+
names.push(...statement.getNamedExports().map((e) => e.getAliasNode()?.getText() ?? e.getName()));
|
|
20
|
+
}
|
|
21
|
+
return names;
|
|
22
|
+
}
|
|
23
|
+
/** Every module the file imports or re-exports from, including dynamic `import("x")`. */
|
|
24
|
+
export function importSpecifiers(sf) {
|
|
25
|
+
const specs = [
|
|
26
|
+
...sf.getImportDeclarations().map((d) => d.getModuleSpecifierValue()),
|
|
27
|
+
...sf.getExportDeclarations().flatMap((d) => d.getModuleSpecifierValue() ?? []),
|
|
28
|
+
];
|
|
29
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
30
|
+
const arg = call.getArguments()[0];
|
|
31
|
+
if (call.getExpression().getKind() === SyntaxKind.ImportKeyword && Node.isStringLiteral(arg))
|
|
32
|
+
specs.push(arg.getLiteralValue());
|
|
33
|
+
}
|
|
34
|
+
return specs;
|
|
35
|
+
}
|
|
36
|
+
/** Names imported from modules whose specifier passes `from`, in source order (the imported name, not an alias). */
|
|
37
|
+
export function namedImportsFrom(sf, from) {
|
|
38
|
+
return sf
|
|
39
|
+
.getImportDeclarations()
|
|
40
|
+
.filter((d) => from(d.getModuleSpecifierValue()))
|
|
41
|
+
.flatMap((d) => d.getNamedImports().map((n) => n.getName()));
|
|
42
|
+
}
|
|
43
|
+
/** The string literal at `argIndex` of every call whose callee text passes `callee`, in source order. */
|
|
44
|
+
export function stringArgs(sf, callee, argIndex = 0) {
|
|
45
|
+
const out = [];
|
|
46
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
47
|
+
if (!callee(call.getExpression().getText()))
|
|
48
|
+
continue;
|
|
49
|
+
const arg = call.getArguments()[argIndex];
|
|
50
|
+
if (Node.isStringLiteral(arg) || Node.isNoSubstitutionTemplateLiteral(arg))
|
|
51
|
+
out.push(arg.getLiteralValue());
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
/** A string property of the object literal passed to every matching call: `Trait.url({ pathname: "/x" })` -> "/x". */
|
|
56
|
+
export function objectArgProperty(sf, callee, property) {
|
|
57
|
+
const out = [];
|
|
58
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
59
|
+
if (!callee(call.getExpression().getText()))
|
|
60
|
+
continue;
|
|
61
|
+
const arg = call.getArguments()[0];
|
|
62
|
+
const prop = Node.isObjectLiteralExpression(arg) ? arg.getProperty(property) : undefined;
|
|
63
|
+
const value = Node.isPropertyAssignment(prop) ? prop.getInitializer() : undefined;
|
|
64
|
+
if (Node.isStringLiteral(value) || Node.isNoSubstitutionTemplateLiteral(value))
|
|
65
|
+
out.push(value.getLiteralValue());
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
/** Every string literal in the file (comments are not strings), with the property name it initializes, if any. */
|
|
70
|
+
export function stringLiterals(sf) {
|
|
71
|
+
const out = [];
|
|
72
|
+
for (const node of [...sf.getDescendantsOfKind(SyntaxKind.StringLiteral), ...sf.getDescendantsOfKind(SyntaxKind.NoSubstitutionTemplateLiteral)]) {
|
|
73
|
+
const parent = node.getParent();
|
|
74
|
+
if (Node.isImportDeclaration(parent) || Node.isExportDeclaration(parent))
|
|
75
|
+
continue;
|
|
76
|
+
out.push({ value: node.getLiteralValue(), property: Node.isPropertyAssignment(parent) && parent.getInitializer() === node ? parent.getName() : undefined });
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
/** Every call in the file (comments and strings are not calls): its callee as written and whether its first argument is a string. */
|
|
81
|
+
export function calls(sf) {
|
|
82
|
+
return sf.getDescendantsOfKind(SyntaxKind.CallExpression).map((call) => {
|
|
83
|
+
const arg = call.getArguments()[0];
|
|
84
|
+
return { callee: call.getExpression().getText(), literalFirstArg: Node.isStringLiteral(arg) || Node.isTemplateExpression(arg) || Node.isNoSubstitutionTemplateLiteral(arg) };
|
|
85
|
+
});
|
|
86
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { BrowserContext } from "@playwright/test";
|
|
2
|
+
import type { Checkpoint } from "../engine/checkpoint/checkpoint.js";
|
|
3
|
+
import type { EngineConfig } from "../engine/config.js";
|
|
4
|
+
import type { MemPage } from "../engine/mem/mem.js";
|
|
5
|
+
import type { DemoPace } from "../engine/stub/pace.js";
|
|
6
|
+
import type { HighlightStyleDefaults } from "../engine/stub/ring.js";
|
|
7
|
+
import type { WgPage } from "../demo/types.js";
|
|
8
|
+
import type { SomeBlock } from "../engine/block/block.js";
|
|
9
|
+
/** One Block to play, with what its flow says about it. */
|
|
10
|
+
export interface PlayStep {
|
|
11
|
+
block: SomeBlock;
|
|
12
|
+
exportName: string;
|
|
13
|
+
/** The engine config of the flow it came from (its layouts apply when it runs). */
|
|
14
|
+
config: EngineConfig;
|
|
15
|
+
/** Set on a named flow's steps; ad hoc Block chains have no episodes. */
|
|
16
|
+
episodeNumber?: number | undefined;
|
|
17
|
+
episodeTitle?: string | undefined;
|
|
18
|
+
/** Clear cookies and storage before this step (a flow with `sessionReset`, chained after another). */
|
|
19
|
+
resetSession: boolean;
|
|
20
|
+
/** Seeds this segment's `--data` into mem; set on a segment's first step. */
|
|
21
|
+
seedMem?: (() => void) | undefined;
|
|
22
|
+
/** Set on a flow's last step when the flow is meant to fail (`map({ expectedFailure })`). */
|
|
23
|
+
expectedFailureReason?: string | undefined;
|
|
24
|
+
demoPace?: DemoPace | undefined;
|
|
25
|
+
highlightStyle?: HighlightStyleDefaults | undefined;
|
|
26
|
+
/** An inner step of an expanded fast-forward unit (`--ff-expand`). */
|
|
27
|
+
wasFastForward?: boolean | undefined;
|
|
28
|
+
ffSource?: string | undefined;
|
|
29
|
+
}
|
|
30
|
+
/** The browser everything plays in. */
|
|
31
|
+
export interface PlaySession {
|
|
32
|
+
context: BrowserContext;
|
|
33
|
+
page: WgPage;
|
|
34
|
+
mem: MemPage;
|
|
35
|
+
baseURL: string | undefined;
|
|
36
|
+
}
|
|
37
|
+
/** How a step ended, for a mode's `failed` hook: it threw, or it landed on the branch its flow expects to fail on. */
|
|
38
|
+
export type StepFailure = {
|
|
39
|
+
error: unknown;
|
|
40
|
+
result?: undefined;
|
|
41
|
+
} | {
|
|
42
|
+
error?: undefined;
|
|
43
|
+
result: Checkpoint<string>;
|
|
44
|
+
};
|
|
45
|
+
export interface PlayOutcome {
|
|
46
|
+
ok: boolean;
|
|
47
|
+
result?: Checkpoint<string> | undefined;
|
|
48
|
+
/** The step that failed, when one did. */
|
|
49
|
+
failedAt?: {
|
|
50
|
+
index: number;
|
|
51
|
+
step: PlayStep;
|
|
52
|
+
error: unknown;
|
|
53
|
+
} | undefined;
|
|
54
|
+
/** Set when the run stopped where its flow expects to fail. */
|
|
55
|
+
expectedFailure?: {
|
|
56
|
+
step: PlayStep;
|
|
57
|
+
reason: string;
|
|
58
|
+
} | undefined;
|
|
59
|
+
}
|
|
60
|
+
/** A way of playing steps. Every hook is optional; with none, it is a plain Playwright run. */
|
|
61
|
+
export interface Mode {
|
|
62
|
+
name: string;
|
|
63
|
+
begin?(steps: readonly PlayStep[]): Promise<void>;
|
|
64
|
+
/** After the page was reset between episodes. */
|
|
65
|
+
afterReset?(): Promise<void>;
|
|
66
|
+
before?(index: number): Promise<void>;
|
|
67
|
+
after?(index: number, result: Checkpoint<string>, ms: number): Promise<void>;
|
|
68
|
+
/** A step failed (or reached its expected failure): retry its episode, or stop. Without the hook: stop. */
|
|
69
|
+
failed?(index: number, failure: StepFailure, ms: number): Promise<"retry" | "stop">;
|
|
70
|
+
end?(outcome: PlayOutcome): Promise<void>;
|
|
71
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { MemPage } from "../../engine/mem/mem.js";
|
|
2
|
+
import type { Flow } from "../../engine/flow/flow.js";
|
|
3
|
+
import type { PlayOptions } from "../options.js";
|
|
4
|
+
import type { Checkpoint } from "../../engine/checkpoint/checkpoint.js";
|
|
5
|
+
export declare function playBranches(flows: readonly Flow<Checkpoint<string>>[], mem: MemPage, options: PlayOptions): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { branchRoutes, runBranchRegression } from "../../engine/flow/branch-regression.js";
|
|
2
|
+
import { extensionPathsFromEnv } from "../../runtime/browser.js";
|
|
3
|
+
export async function playBranches(flows, mem, options) {
|
|
4
|
+
const flow = flows.length === 1 ? flows[0] : undefined;
|
|
5
|
+
if (!flow) {
|
|
6
|
+
console.error("waygraph run --all-branches: needs a single Flow reference (e.g. --blocks loginFlow), not a multi-segment chain spec - nothing else has one branch tree to explore.");
|
|
7
|
+
process.exitCode = 1;
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (!branchRoutes(flow)) {
|
|
11
|
+
console.error("waygraph run --all-branches: this Flow was not built with MapBuilder.branch() - there is no branch tree to explore. Run it normally instead.");
|
|
12
|
+
process.exitCode = 1;
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (extensionPathsFromEnv().length > 0) {
|
|
16
|
+
console.warn("waygraph run --all-branches: extensions are not loaded (branches run in cloned contexts)");
|
|
17
|
+
}
|
|
18
|
+
const { chromium } = await import("@playwright/test");
|
|
19
|
+
const browser = await chromium.launch({ headless: !options.headed });
|
|
20
|
+
try {
|
|
21
|
+
const context = await browser.newContext(options.baseURL ? { baseURL: options.baseURL } : undefined);
|
|
22
|
+
const results = await runBranchRegression(flow, context, mem, { cloneSession: !options.sharedSession });
|
|
23
|
+
for (const r of results) {
|
|
24
|
+
console.log(`waygraph run --all-branches: ${r.path || "(root)"} -> ${r.status}` +
|
|
25
|
+
(r.result ? ` (${JSON.stringify(r.result)})` : "") +
|
|
26
|
+
(r.error ? ` - ${r.error}` : ""));
|
|
27
|
+
}
|
|
28
|
+
const failed = results.filter((r) => r.status === "failed");
|
|
29
|
+
if (failed.length) {
|
|
30
|
+
console.error(`waygraph run --all-branches: ${failed.length}/${results.length} path(s) failed`);
|
|
31
|
+
process.exitCode = 1;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
await browser.close();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// `waygraph demo`: the same steps, with the waygraph UI around each one (src/demo/stepper/).
|
|
2
|
+
import { createStepper } from "../../demo/stepper/stepper.js";
|
|
3
|
+
export async function demoMode(session, steps, options, beat) {
|
|
4
|
+
const stepper = await createStepper(session.page, session.mem, steps, { title: options.title, fastBlocks: options.fastBlocks, beat });
|
|
5
|
+
return {
|
|
6
|
+
name: "demo",
|
|
7
|
+
afterReset: stepper.afterReset,
|
|
8
|
+
before: stepper.before,
|
|
9
|
+
after: (index, result) => stepper.after(index, result),
|
|
10
|
+
failed: (index, failure) => stepper.failed(index, failure),
|
|
11
|
+
end: () => stepper.end(),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// `waygraph run` with WAYGRAPH_JSON=1: plays like `run` and prints one JSON report (each step's Checkpoint and time,
|
|
2
|
+
// a screenshot on failure). `runId` names the matching `.waygraph/runs/<runId>.jsonl`.
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { currentRunId, recordArtifact } from "../../engine/run/events.js";
|
|
6
|
+
export function reportMode(session) {
|
|
7
|
+
let steps = [];
|
|
8
|
+
const done = [];
|
|
9
|
+
let screenshot = null;
|
|
10
|
+
const message = (error) => (error instanceof Error ? error.message : String(error));
|
|
11
|
+
return {
|
|
12
|
+
name: "report",
|
|
13
|
+
async begin(all) {
|
|
14
|
+
steps = all;
|
|
15
|
+
},
|
|
16
|
+
async after(index, result, ms) {
|
|
17
|
+
done.push({ name: steps[index].block.name, checkpoint: result, ms });
|
|
18
|
+
},
|
|
19
|
+
async failed(index, failure, ms) {
|
|
20
|
+
const step = steps[index];
|
|
21
|
+
if (failure.result) {
|
|
22
|
+
done.push({ name: step.block.name, checkpoint: failure.result, ms });
|
|
23
|
+
}
|
|
24
|
+
else if (step.expectedFailureReason) {
|
|
25
|
+
done.push({ name: step.block.name, expectedFailure: true, error: message(failure.error), ms });
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
screenshot = join(tmpdir(), "waygraph-chain-failure-" + Date.now() + ".png");
|
|
29
|
+
await session.page.screenshot({ path: screenshot, fullPage: true }).then(() => recordArtifact("screenshot", screenshot), () => (screenshot = null));
|
|
30
|
+
}
|
|
31
|
+
return "stop";
|
|
32
|
+
},
|
|
33
|
+
async end(outcome) {
|
|
34
|
+
const runId = currentRunId();
|
|
35
|
+
const report = outcome.failedAt
|
|
36
|
+
? {
|
|
37
|
+
runId,
|
|
38
|
+
ok: false,
|
|
39
|
+
failedAt: outcome.failedAt.step.block.name,
|
|
40
|
+
stepIndex: outcome.failedAt.index,
|
|
41
|
+
totalSteps: steps.length,
|
|
42
|
+
error: message(outcome.failedAt.error),
|
|
43
|
+
steps: done,
|
|
44
|
+
screenshot,
|
|
45
|
+
}
|
|
46
|
+
: outcome.expectedFailure && outcome.result === undefined
|
|
47
|
+
? { runId, ok: true, expectedFailure: true, failedAt: outcome.expectedFailure.step.block.name, reason: outcome.expectedFailure.reason, steps: done }
|
|
48
|
+
: { runId, ok: true, result: done.length > 0 ? done[done.length - 1].checkpoint : null, steps: done };
|
|
49
|
+
console.log(JSON.stringify(report, null, 2));
|
|
50
|
+
if (!report.ok)
|
|
51
|
+
process.exitCode = 1;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { PlayStep } from "./mode.js";
|
|
2
|
+
export type ModeName = "run" | "demo" | "report" | "branches";
|
|
3
|
+
export interface PlayOptions {
|
|
4
|
+
mode: ModeName;
|
|
5
|
+
headed: boolean;
|
|
6
|
+
baseURL: string | undefined;
|
|
7
|
+
title: string | undefined;
|
|
8
|
+
/** Block names that skip the demo's added dwell (WAYGRAPH_FAST_BLOCKS). */
|
|
9
|
+
fastBlocks: Set<string>;
|
|
10
|
+
/** Clear the session before every step after the first (WAYGRAPH_CLEAR_SESSION). */
|
|
11
|
+
clearSession: boolean;
|
|
12
|
+
/** Record a video: the folder, or "1" for the default one. */
|
|
13
|
+
video: string | undefined;
|
|
14
|
+
videoViewport: string | undefined;
|
|
15
|
+
/** Expand fast-forward units into their inner steps (--ff-expand / --ff-disabled). */
|
|
16
|
+
ffExpand: boolean;
|
|
17
|
+
ffDisabled: boolean;
|
|
18
|
+
/** Fill missing `requires` from registerMemStub for every flow (--mem-stub). */
|
|
19
|
+
memStub: boolean;
|
|
20
|
+
/** --all-branches without cloning the session per branch. */
|
|
21
|
+
sharedSession: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function readOptions(): PlayOptions;
|
|
24
|
+
/**
|
|
25
|
+
* The slowMo for the browser launch and the demo's own beat after each action. The demo launches at 0 and paces
|
|
26
|
+
* itself, so a step's pace can remove the beat; a fast-forward unit in the steps drops the beat to 0.
|
|
27
|
+
*/
|
|
28
|
+
export declare function slowMoFor(options: PlayOptions, steps: readonly PlayStep[]): {
|
|
29
|
+
launch: number | undefined;
|
|
30
|
+
demoBeat: number;
|
|
31
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// How to play, read once from the environment the CLI set (flags beat the config file, which beats these defaults).
|
|
2
|
+
import { envFlag, envNumber, envString, envSwitch } from "../engine/env.js";
|
|
3
|
+
function readMode() {
|
|
4
|
+
if (envFlag("WAYGRAPH_ALL_BRANCHES"))
|
|
5
|
+
return "branches";
|
|
6
|
+
if (envFlag("WAYGRAPH_JSON"))
|
|
7
|
+
return "report";
|
|
8
|
+
return envFlag("WAYGRAPH_STEP") ? "demo" : "run";
|
|
9
|
+
}
|
|
10
|
+
export function readOptions() {
|
|
11
|
+
const mode = readMode();
|
|
12
|
+
return {
|
|
13
|
+
mode,
|
|
14
|
+
// A manual demo is watched, so it is headed by default; WAYGRAPH_HEADED=0 (e.g. --auto-play-video) still wins.
|
|
15
|
+
headed: envSwitch("WAYGRAPH_HEADED", mode === "demo"),
|
|
16
|
+
baseURL: envString("WAYGRAPH_BASE_URL"),
|
|
17
|
+
title: envString("WAYGRAPH_TITLE"),
|
|
18
|
+
fastBlocks: new Set((envString("WAYGRAPH_FAST_BLOCKS") || "").split(",").map((s) => s.trim()).filter(Boolean)),
|
|
19
|
+
clearSession: envFlag("WAYGRAPH_CLEAR_SESSION"),
|
|
20
|
+
video: envString("WAYGRAPH_VIDEO"),
|
|
21
|
+
videoViewport: envString("WAYGRAPH_VIDEO_VIEWPORT"),
|
|
22
|
+
ffExpand: envFlag("WAYGRAPH_FF_EXPAND") || envFlag("WAYGRAPH_FF_DISABLED"),
|
|
23
|
+
ffDisabled: envFlag("WAYGRAPH_FF_DISABLED"),
|
|
24
|
+
memStub: envFlag("WAYGRAPH_MEM_STUB"),
|
|
25
|
+
sharedSession: envFlag("WAYGRAPH_SHARED_SESSION"),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The slowMo for the browser launch and the demo's own beat after each action. The demo launches at 0 and paces
|
|
30
|
+
* itself, so a step's pace can remove the beat; a fast-forward unit in the steps drops the beat to 0.
|
|
31
|
+
*/
|
|
32
|
+
export function slowMoFor(options, steps) {
|
|
33
|
+
const demo = options.mode === "demo";
|
|
34
|
+
const hasFastForward = steps.some((s) => s.block.fastForward === true || s.wasFastForward === true);
|
|
35
|
+
const slowMo = envNumber("WAYGRAPH_SLOWMO") ?? (demo ? (hasFastForward ? 0 : 350) : undefined);
|
|
36
|
+
if (demo && hasFastForward && envNumber("WAYGRAPH_SLOWMO") === undefined) {
|
|
37
|
+
console.error(options.ffDisabled
|
|
38
|
+
? "waygraph demo: --ff-disabled (expanded) -> Playwright slowMo=0 on former FF steps (blitz; same acts as opaque FF)"
|
|
39
|
+
: "waygraph demo: opaque FFCompose in flow -> Playwright slowMo=0 (blitz); set WAYGRAPH_SLOWMO to override");
|
|
40
|
+
}
|
|
41
|
+
return { launch: demo ? 0 : slowMo, demoBeat: slowMo ?? 0 };
|
|
42
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AnyBlock } from "../../manifest/scan.js";
|
|
2
|
+
import type { Flow } from "../../engine/flow/flow.js";
|
|
3
|
+
import type { Checkpoint } from "../../engine/checkpoint/checkpoint.js";
|
|
4
|
+
export interface FoundBlock {
|
|
5
|
+
block: AnyBlock;
|
|
6
|
+
exportName: string;
|
|
7
|
+
file: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function findBlock(projectDir: string, ref: string): Promise<FoundBlock>;
|
|
10
|
+
/**
|
|
11
|
+
* Finds an already-defined Flow by its export name (e.g. loginFlow) among
|
|
12
|
+
* the project's *.flow.ts files - "I already have this wired up, just point
|
|
13
|
+
* the stepper at it, no chain spec to hand-write." Flows have no runtime
|
|
14
|
+
* .name of their own (unlike Blocks), so this only matches by export
|
|
15
|
+
* identifier. Returns null (not a throw) when nothing matches - the caller
|
|
16
|
+
* falls back to ordinary block-chain spec parsing.
|
|
17
|
+
*/
|
|
18
|
+
export declare function findFlow(projectDir: string, flowName: string): Promise<Flow<Checkpoint<string>> | null>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Finds a Block or Flow in the project (and its installed map packages) by export name or Block name.
|
|
2
|
+
import { relative } from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { isBlockLike, walkDir } from "../../manifest/scan.js";
|
|
5
|
+
/** A built Flow: what `map().end()` returns. */
|
|
6
|
+
function isFlow(val) {
|
|
7
|
+
return val !== null && typeof val === "object" && typeof val.run === "function" && typeof val.blocks === "function";
|
|
8
|
+
}
|
|
9
|
+
import { installedMapPackages, mapPackageBlockFiles } from "../../manifest/maps.js";
|
|
10
|
+
import { reportImportError } from "../../manifest/project.js";
|
|
11
|
+
export async function findBlock(projectDir, ref) {
|
|
12
|
+
const files = [...walkDir(projectDir, /\.block\.ts$/), ...installedMapPackages(projectDir).flatMap(mapPackageBlockFiles)];
|
|
13
|
+
const byRuntimeName = [];
|
|
14
|
+
for (const file of files) {
|
|
15
|
+
let mod;
|
|
16
|
+
try {
|
|
17
|
+
mod = await import(pathToFileURL(file).href);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
reportImportError(relative(projectDir, file), err);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
for (const [exportName, exported] of Object.entries(mod)) {
|
|
24
|
+
if (!isBlockLike(exported))
|
|
25
|
+
continue;
|
|
26
|
+
if (exportName === ref)
|
|
27
|
+
return { block: exported, exportName, file };
|
|
28
|
+
if (exported.name === ref)
|
|
29
|
+
byRuntimeName.push({ block: exported, exportName, file });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (byRuntimeName.length === 1)
|
|
33
|
+
return byRuntimeName[0];
|
|
34
|
+
if (byRuntimeName.length > 1) {
|
|
35
|
+
throw new Error("waygraph chain: \"" + ref + "\" matches " + byRuntimeName.length + " Blocks by name - " +
|
|
36
|
+
byRuntimeName.map((b) => b.exportName + " (" + b.file + ")").join(", ") +
|
|
37
|
+
". Use the export name to disambiguate.");
|
|
38
|
+
}
|
|
39
|
+
throw new Error("waygraph chain: no Block named \"" + ref + "\" found under " + projectDir);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Finds an already-defined Flow by its export name (e.g. loginFlow) among
|
|
43
|
+
* the project's *.flow.ts files - "I already have this wired up, just point
|
|
44
|
+
* the stepper at it, no chain spec to hand-write." Flows have no runtime
|
|
45
|
+
* .name of their own (unlike Blocks), so this only matches by export
|
|
46
|
+
* identifier. Returns null (not a throw) when nothing matches - the caller
|
|
47
|
+
* falls back to ordinary block-chain spec parsing.
|
|
48
|
+
*/
|
|
49
|
+
export async function findFlow(projectDir, flowName) {
|
|
50
|
+
const files = walkDir(projectDir, /\.flow\.ts$/);
|
|
51
|
+
for (const file of files) {
|
|
52
|
+
let mod;
|
|
53
|
+
try {
|
|
54
|
+
mod = await import(pathToFileURL(file).href);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
reportImportError(relative(projectDir, file), err);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const candidate = mod[flowName];
|
|
61
|
+
if (isFlow(candidate))
|
|
62
|
+
return candidate;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MemPage } from "../../engine/mem/mem.js";
|
|
2
|
+
import type { Flow } from "../../engine/flow/flow.js";
|
|
3
|
+
import type { PlayStep } from "../mode.js";
|
|
4
|
+
import type { PlayOptions } from "../options.js";
|
|
5
|
+
import type { Checkpoint } from "../../engine/checkpoint/checkpoint.js";
|
|
6
|
+
export interface Plan {
|
|
7
|
+
steps: PlayStep[];
|
|
8
|
+
/** One Flow per segment (`--all-branches` needs exactly one). */
|
|
9
|
+
flows: Flow<Checkpoint<string>>[];
|
|
10
|
+
}
|
|
11
|
+
export declare function planSteps(projectDir: string, spec: string, mem: MemPage, options: PlayOptions): Promise<Plan>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { buildFlow, chainFlow } from "../../engine/flow/flow.js";
|
|
2
|
+
import { isFastForwardBlock } from "../../engine/block/compose.js";
|
|
3
|
+
import { findBlock, findFlow } from "./find.js";
|
|
4
|
+
import { seedMemForBlock, seedMemForFlow } from "./seed-mem.js";
|
|
5
|
+
import { parseChainSpec } from "./spec.js";
|
|
6
|
+
export async function planSteps(projectDir, spec, mem, options) {
|
|
7
|
+
const bareFlow = await findBareFlow(projectDir, spec);
|
|
8
|
+
const segments = bareFlow
|
|
9
|
+
? [flowSegment(bareFlow, spec.trim(), undefined, mem, options)]
|
|
10
|
+
: await Promise.all(parseSegments(spec).map((seg) => resolveSegment(projectDir, seg, mem, options)));
|
|
11
|
+
const steps = stepsOf(segments, options, { episodes: !bareFlow });
|
|
12
|
+
if (options.mode !== "report")
|
|
13
|
+
announce(spec, steps, !!bareFlow, options);
|
|
14
|
+
return { steps, flows: segments.map((s) => s.flow) };
|
|
15
|
+
}
|
|
16
|
+
/** A spec that is just a name might be an existing Flow (`cartFlow`); then no chain spec is needed. */
|
|
17
|
+
async function findBareFlow(projectDir, spec) {
|
|
18
|
+
const ref = spec.trim();
|
|
19
|
+
if (!/^[A-Za-z_$][\w]*$/.test(ref))
|
|
20
|
+
return undefined;
|
|
21
|
+
const flow = await findFlow(projectDir, ref);
|
|
22
|
+
return flow && typeof flow.blocks === "function" ? flow : undefined;
|
|
23
|
+
}
|
|
24
|
+
function parseSegments(spec) {
|
|
25
|
+
const segments = parseChainSpec(spec);
|
|
26
|
+
if (segments.length === 0)
|
|
27
|
+
throw new Error("waygraph chain: empty spec - give at least one block name");
|
|
28
|
+
return segments;
|
|
29
|
+
}
|
|
30
|
+
async function resolveSegment(projectDir, seg, mem, options) {
|
|
31
|
+
const flow = await findFlow(projectDir, seg.ref);
|
|
32
|
+
if (flow && typeof flow.blocks === "function")
|
|
33
|
+
return flowSegment(flow, seg.ref, seg.json, mem, options);
|
|
34
|
+
const found = await findBlock(projectDir, seg.ref);
|
|
35
|
+
if (!found)
|
|
36
|
+
throw new Error(`waygraph: no Block or Flow named "${seg.ref}"`);
|
|
37
|
+
return {
|
|
38
|
+
flow: buildFlow([found.block], {}),
|
|
39
|
+
ref: seg.ref,
|
|
40
|
+
named: false,
|
|
41
|
+
// A bare Block has no map({ memStub }) to opt in; only --mem-stub fills its keys.
|
|
42
|
+
seedMem: () => seedMemForBlock(mem, found, seg.json, options.memStub),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function flowSegment(flow, ref, json, mem, options) {
|
|
46
|
+
// seeded when the segment starts, not now: two segments may give the same key different values
|
|
47
|
+
const seedMem = () => seedMemForFlow(mem, flow.blocks(), json, ref, flow.memStub === true || options.memStub);
|
|
48
|
+
return { flow, ref, named: true, seedMem };
|
|
49
|
+
}
|
|
50
|
+
/** A fast-forward unit is one step, unless --ff-expand plays its inner Blocks one by one. */
|
|
51
|
+
function expand(infos, options) {
|
|
52
|
+
if (!options.ffExpand)
|
|
53
|
+
return [...infos];
|
|
54
|
+
return infos.flatMap((info) => isFastForwardBlock(info.block)
|
|
55
|
+
? info.block.steps().map((inner) => ({
|
|
56
|
+
...inner,
|
|
57
|
+
...(info.resetSessionBefore ? { resetSessionBefore: true } : {}),
|
|
58
|
+
wasFastForward: true,
|
|
59
|
+
ffSource: info.block.name,
|
|
60
|
+
}))
|
|
61
|
+
: [info]);
|
|
62
|
+
}
|
|
63
|
+
function stepsOf(segments, options, { episodes }) {
|
|
64
|
+
// chainFlow marks each segment's first Block when that segment wants a fresh session.
|
|
65
|
+
const resets = new Set(chainFlow(...segments.map((s) => s.flow)).blocks().filter((b) => b.resetSessionBefore).map((b) => b.block));
|
|
66
|
+
let episode = 0;
|
|
67
|
+
return segments.flatMap((segment) => {
|
|
68
|
+
const episodeNumber = episodes && segment.named ? ++episode : undefined;
|
|
69
|
+
const infos = expand(segment.flow.blocks(), options);
|
|
70
|
+
return infos.map((info, i) => ({
|
|
71
|
+
block: info.block,
|
|
72
|
+
exportName: info.name,
|
|
73
|
+
config: segment.flow.config,
|
|
74
|
+
episodeNumber,
|
|
75
|
+
episodeTitle: episodeNumber === undefined ? undefined : segment.ref,
|
|
76
|
+
resetSession: i === 0 && resets.has(segment.flow.blocks()[0]?.block),
|
|
77
|
+
seedMem: i === 0 ? segment.seedMem : undefined,
|
|
78
|
+
expectedFailureReason: i === infos.length - 1 ? segment.flow.expectedFailureReason : undefined,
|
|
79
|
+
demoPace: segment.flow.demoPace,
|
|
80
|
+
highlightStyle: segment.flow.highlightStyle,
|
|
81
|
+
...(info.wasFastForward ? { wasFastForward: true, ffSource: info.ffSource } : {}),
|
|
82
|
+
}));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function announce(spec, steps, bare, options) {
|
|
86
|
+
const names = steps.map((s) => s.block.name).join(" -> ");
|
|
87
|
+
const count = steps.length + " block" + (steps.length === 1 ? "" : "s");
|
|
88
|
+
if (bare) {
|
|
89
|
+
console.log(`waygraph: running existing flow "${spec.trim()}" - ${names} (${count}, no chain spec needed)`);
|
|
90
|
+
if (options.ffDisabled) {
|
|
91
|
+
console.error("waygraph demo: --ff-disabled - FFCompose expanded to inners (dispute / step locus); blitz pacing kept on former FF steps");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
console.log(`waygraph: chaining ${names} (${count})`);
|
|
96
|
+
}
|
|
97
|
+
}
|