waygraph 0.15.53 → 0.16.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.
- 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 +13 -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/{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/{commands → cli/commands}/run.d.ts +0 -1
- package/dist/cli/commands/run.js +64 -0
- package/dist/{commands → cli/commands}/session.js +61 -88
- 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 +7 -11
- package/dist/{highlights → demo/narration}/demo-pace.js +9 -11
- package/dist/{highlights → demo/narration}/device.d.ts +4 -2
- package/dist/{highlights → demo/narration}/device.js +3 -1
- package/dist/demo/narration/merge.d.ts +8 -0
- package/dist/demo/narration/merge.js +71 -0
- package/dist/{highlights/run-phase.d.ts → demo/narration/narration.d.ts} +10 -14
- 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 +3 -3
- 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/{session/overlay-beacon.d.ts → demo/overlay/beacon.d.ts} +7 -0
- package/dist/{session/overlay-beacon.js → demo/overlay/beacon.js} +5 -0
- package/dist/demo/overlay/cursor.d.ts +12 -0
- package/dist/demo/overlay/cursor.js +142 -0
- package/dist/demo/overlay/device-stage.d.ts +13 -0
- package/dist/demo/overlay/device-stage.js +396 -0
- package/dist/demo/overlay/inpage/banner.d.ts +1 -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 +1 -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 +9 -0
- package/dist/demo/overlay/inpage/network.js +200 -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 +1 -0
- package/dist/demo/overlay/inpage/todos.js +294 -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 +23 -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 +33 -0
- package/dist/demo/overlay/rings.js +448 -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 +113 -0
- package/dist/demo/stepper/banner-log.d.ts +37 -0
- package/dist/demo/stepper/banner-log.js +63 -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 +31 -0
- package/dist/demo/stepper/demo-log.js +309 -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 +3 -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/slides.d.ts +11 -0
- package/dist/demo/stepper/slides.js +233 -0
- package/dist/demo/stepper/step-panels.d.ts +21 -0
- package/dist/demo/stepper/step-panels.js +589 -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 +48 -0
- package/dist/demo/stepper/teardown.js +179 -0
- package/dist/demo/stepper/todo-advance.d.ts +14 -0
- package/dist/demo/stepper/todo-advance.js +110 -0
- package/dist/demo/stepper/view.d.ts +68 -0
- package/dist/demo/stepper/view.js +31 -0
- package/dist/demo/types.d.ts +17 -0
- package/dist/demo/verbose-log.js +15 -0
- package/dist/{types.d.ts → engine/block/block.d.ts} +106 -91
- package/dist/{core → engine/block}/block.js +10 -53
- package/dist/{core → engine/block}/compose.d.ts +10 -7
- package/dist/{core → engine/block}/compose.js +1 -1
- package/dist/{core/blocks → engine/block/kinds}/api.d.ts +17 -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 +19 -29
- package/dist/{core/blocks → engine/block/kinds}/method.js +7 -21
- package/dist/{core/blocks → engine/block/kinds}/nav.d.ts +22 -31
- package/dist/{core/blocks → engine/block/kinds}/nav.js +6 -12
- package/dist/{core/blocks → engine/block/kinds}/page.d.ts +15 -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} +23 -22
- package/dist/{errors.js → engine/errors.js} +22 -22
- package/dist/{core → engine/flow}/branch-regression.d.ts +8 -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/{core → engine/flow}/map-builder.d.ts +42 -40
- package/dist/{core → engine/flow}/map-builder.js +46 -48
- 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} +9 -11
- package/dist/{core/run-graph.js → engine/run/run.js} +22 -11
- 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/index.d.ts +84 -36
- package/dist/index.js +44 -19
- package/dist/{session/auto-explore-run.d.ts → live/auto/auto.d.ts} +10 -16
- package/dist/{session/auto-explore-run.js → live/auto/auto.js} +164 -248
- 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/{auto-session/session.d.ts → live/auto-session/auto-session.d.ts} +1 -1
- package/dist/{auto-session/session.js → live/auto-session/auto-session.js} +27 -24
- package/dist/{auto-session → live/auto-session}/helpers.d.ts +16 -5
- package/dist/{auto-session → live/auto-session}/helpers.js +1 -1
- package/dist/{session/auto-session-ipc.d.ts → live/auto-session/ipc.d.ts} +7 -5
- package/dist/{session/auto-session-ipc.js → live/auto-session/ipc.js} +31 -16
- 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 +4 -3
- package/dist/{session → live/pilot}/pilot.js +4 -4
- package/dist/{traverse → live/traverse}/coverage.d.ts +4 -0
- package/dist/{traverse → live/traverse}/coverage.js +3 -0
- package/dist/{traverse → live/traverse}/lease.d.ts +1 -0
- package/dist/{traverse → live/traverse}/lease.js +1 -0
- package/dist/{traverse/run.d.ts → live/traverse/traverse.d.ts} +4 -1
- package/dist/{traverse/run.js → live/traverse/traverse.js} +26 -43
- 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/{blocks-select.d.ts → manifest/select.d.ts} +3 -0
- package/dist/{blocks-select.js → manifest/select.js} +2 -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} +2 -5
- package/dist/{extensions.js → runtime/extensions.js} +3 -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} +8 -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 +2 -3
- 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/README.md +11 -12
- package/examples/saucedemo/config/waygraph.config.ts +17 -0
- package/examples/saucedemo/docs/CONVENTION.md +5 -7
- package/examples/saucedemo/docs/HELPERS.md +12 -12
- package/examples/saucedemo/package-lock.json +10 -3
- package/examples/saucedemo/package.json +12 -29
- 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 -52
- 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 +21 -27
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +3 -9
- 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 +10 -76
- 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 -29
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +5 -48
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +13 -77
- 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 +26 -18
- package/examples/saucedemo/src/flows/cart-bulk.flow.ts +19 -14
- package/examples/saucedemo/src/flows/cart-continue.flow.ts +10 -8
- package/examples/saucedemo/src/flows/cart-mem.flow.ts +7 -7
- package/examples/saucedemo/src/flows/catalog-logout.flow.ts +13 -8
- package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +26 -48
- package/examples/saucedemo/src/flows/checkout.flow.ts +70 -86
- package/examples/saucedemo/src/flows/device-showcase.flow.ts +24 -25
- package/examples/saucedemo/src/flows/login.flow.ts +11 -18
- package/examples/saucedemo/src/flows/mem-stub-demo.flow.ts +9 -20
- package/examples/saucedemo/src/flows/shop.flow.ts +15 -20
- package/examples/saucedemo/src/flows/smoke.flow.ts +12 -27
- package/examples/saucedemo/src/flows/stub-on-error.flow.ts +24 -43
- package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +26 -34
- package/examples/saucedemo/src/states/checkout.mem-stubs.ts +11 -0
- package/examples/saucedemo/src/states/checkout.states.ts +21 -11
- package/examples/saucedemo/src/stubs/device-showcase.ts +191 -0
- package/examples/saucedemo/src/stubs/login.ts +37 -0
- package/examples/saucedemo/tests/auto-graph.spec.ts +4 -12
- package/examples/saucedemo/tests/chain-flow-episodes.spec.ts +7 -9
- package/examples/saucedemo/tests/submit-login-branch.spec.ts +18 -5
- package/package.json +12 -7
- package/templates/agents/waygraph-planner.agent.md +2 -2
- package/templates/quickstart/README.md +4 -7
- package/templates/quickstart/config/waygraph.config.ts +17 -0
- package/templates/quickstart/docs/CONVENTION.md +5 -6
- package/templates/quickstart/docs/HELPERS.md +11 -9
- package/templates/quickstart/package.json +14 -17
- package/templates/quickstart/src/blocks/SITE-MAP.md +13 -3
- package/templates/quickstart/src/blocks/saucedemo-web/NAV.md +1 -5
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -52
- 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 +21 -27
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +3 -9
- 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 +10 -76
- 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 -29
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +5 -48
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +13 -77
- 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 +45 -0
- package/templates/quickstart/src/flows/cart-bulk.flow.ts +19 -14
- package/templates/quickstart/src/flows/cart-continue.flow.ts +10 -8
- package/templates/quickstart/src/flows/cart-mem.flow.ts +7 -7
- package/templates/quickstart/src/flows/catalog-logout.flow.ts +13 -8
- package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +26 -48
- package/templates/quickstart/src/flows/checkout.flow.ts +70 -63
- package/templates/quickstart/src/flows/device-showcase.flow.ts +24 -25
- package/templates/quickstart/src/flows/login.flow.ts +11 -18
- package/templates/quickstart/src/flows/mem-stub-demo.flow.ts +12 -0
- package/templates/quickstart/src/flows/shop.flow.ts +15 -20
- package/templates/quickstart/src/flows/smoke.flow.ts +12 -27
- package/templates/quickstart/src/flows/stub-on-error.flow.ts +31 -0
- package/templates/quickstart/src/flows/viewer-blocked.flow.ts +26 -34
- package/templates/quickstart/src/states/checkout.mem-stubs.ts +11 -0
- package/templates/quickstart/src/states/checkout.states.ts +21 -11
- package/templates/quickstart/src/stubs/device-showcase.ts +191 -0
- package/templates/quickstart/src/stubs/login.ts +37 -0
- package/templates/quickstart/tests/chain-flow.spec.ts +7 -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/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/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 -293
- package/dist/core/flow.js +0 -432
- 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/stub-ctx.d.ts +0 -10
- package/dist/highlights/stub-ctx.js +0 -331
- package/dist/highlights/types.d.ts +0 -607
- 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/step-overlay.d.ts +0 -37
- package/dist/session/step-overlay.js +0 -244
- package/examples/routed-demo/playwright.config.ts +0 -21
- package/examples/saucedemo/playwright.config.ts +0 -19
- package/examples/saucedemo/scripts/drive-auto-cli.mjs +0 -93
- package/examples/saucedemo/scripts/prove-add-to-cart-menu.mjs +0 -126
- package/examples/saucedemo/scripts/prove-auto-graph.mjs +0 -92
- package/examples/saucedemo/scripts/prove-wrong-login-runtime.mjs +0 -63
- package/examples/saucedemo/src/blocks/saucedemo-web/ff-owner-auth.block.ts +0 -22
- package/templates/quickstart/playwright.config.ts +0 -14
- package/templates/quickstart/scripts/drive-auto-cli.mjs +0 -93
- 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/{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/{trait.js → engine/trait/trait.js} +0 -0
- /package/dist/{session/block-inject.d.ts → manifest/roots.d.ts} +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,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
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { MemPage } from "../../engine/mem/mem.js";
|
|
2
|
+
import type { BlockInfo } from "../../engine/flow/flow.js";
|
|
3
|
+
import type { FoundBlock } from "./find.js";
|
|
4
|
+
export declare function seedMemForBlock(mem: MemPage, resolved: FoundBlock, json: string | undefined, stubActive: boolean): void;
|
|
5
|
+
/**
|
|
6
|
+
* Same idea as seedMemForBlock, but for a whole Flow segment
|
|
7
|
+
* ("loginFlow({...}) then ...") - a Flow has no single .requires of its
|
|
8
|
+
* own, so this unions every constituent Block's requires (deduped by key
|
|
9
|
+
* name) and seeds them all from one JSON payload, same keyed-by-name shape
|
|
10
|
+
* as a multi-key Block payload already uses.
|
|
11
|
+
*/
|
|
12
|
+
export declare function seedMemForFlow(mem: MemPage, flowBlocks: readonly BlockInfo[], json: string | undefined, label: string, stubActive: boolean): void;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { getMemStub } from "../../engine/mem/mem-stub.js";
|
|
2
|
+
import { envString } from "../../engine/env.js";
|
|
3
|
+
const isRecord = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
4
|
+
function seedMemFromRequires(mem, requires, json, label, stubActive) {
|
|
5
|
+
if (requires.length === 0) {
|
|
6
|
+
if (json !== undefined) {
|
|
7
|
+
throw new Error("waygraph chain: \"" + label + "\" takes no input (empty requires) but got a payload: " + json);
|
|
8
|
+
}
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (json === undefined) {
|
|
12
|
+
// --data / WAYGRAPH_DATA supplies the same payload shape as blockName({...}).
|
|
13
|
+
const fromEnv = envString("WAYGRAPH_DATA");
|
|
14
|
+
if (fromEnv && fromEnv.trim())
|
|
15
|
+
json = fromEnv;
|
|
16
|
+
}
|
|
17
|
+
let parsed;
|
|
18
|
+
let haveParsed = false;
|
|
19
|
+
if (json !== undefined) {
|
|
20
|
+
try {
|
|
21
|
+
parsed = JSON.parse(json);
|
|
22
|
+
haveParsed = true;
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
throw new Error("waygraph chain: \"" + label + "\" payload is not valid JSON - " + String(err));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (!haveParsed) {
|
|
29
|
+
// No payload at all - only a hard failure when memStub isn't active for
|
|
30
|
+
// this flow; when it is, fall through with an empty object so the
|
|
31
|
+
// per-key loop below gets a chance to fill each one from the registry.
|
|
32
|
+
if (!stubActive) {
|
|
33
|
+
throw new Error("waygraph chain: \"" + label + "\" requires " + requires.map((k) => k.name).join(", ") +
|
|
34
|
+
" - give a JSON payload (inline blockName({...}) or --data '{...}'), or enable --mem-stub" +
|
|
35
|
+
" with registerMemStub for these keys");
|
|
36
|
+
}
|
|
37
|
+
parsed = {};
|
|
38
|
+
}
|
|
39
|
+
// Keyed-by-name when every require name is a top-level key (preferred for
|
|
40
|
+
// --data and for {"saucedemo.credentials":{...}} even with one require).
|
|
41
|
+
if (isRecord(parsed)) {
|
|
42
|
+
const payload = parsed;
|
|
43
|
+
if (requires.every((k) => k.name in payload)) {
|
|
44
|
+
for (const k of requires)
|
|
45
|
+
mem.set(k, payload[k.name]);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Single-key shorthand: the whole payload IS that one key's value - only
|
|
50
|
+
// when a real payload was actually given (the stub-only "{}" fallback
|
|
51
|
+
// above must fall through to per-key stub resolution instead).
|
|
52
|
+
if (haveParsed && requires.length === 1) {
|
|
53
|
+
mem.set(requires[0], parsed);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (!isRecord(parsed)) {
|
|
57
|
+
throw new Error("waygraph chain: \"" + label + "\" requires " + requires.length + " keys (" +
|
|
58
|
+
requires.map((k) => k.name).join(", ") + ") - payload must be an object keyed by each key's name");
|
|
59
|
+
}
|
|
60
|
+
const payload = parsed;
|
|
61
|
+
const stillMissing = [];
|
|
62
|
+
for (const k of requires) {
|
|
63
|
+
if (k.name in payload) {
|
|
64
|
+
mem.set(k, payload[k.name]);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const fake = stubActive ? getMemStub(k) : undefined;
|
|
68
|
+
if (fake) {
|
|
69
|
+
mem.set(k, fake());
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
stillMissing.push(k);
|
|
73
|
+
}
|
|
74
|
+
if (stillMissing.length > 0) {
|
|
75
|
+
throw new Error("waygraph chain: \"" + label + "\" payload is missing required key(s): " +
|
|
76
|
+
stillMissing.map((k) => "\"" + k.name + "\"").join(", "));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export function seedMemForBlock(mem, resolved, json, stubActive) {
|
|
80
|
+
seedMemFromRequires(mem, resolved.block.requires ?? [], json, resolved.exportName, stubActive);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Same idea as seedMemForBlock, but for a whole Flow segment
|
|
84
|
+
* ("loginFlow({...}) then ...") - a Flow has no single .requires of its
|
|
85
|
+
* own, so this unions every constituent Block's requires (deduped by key
|
|
86
|
+
* name) and seeds them all from one JSON payload, same keyed-by-name shape
|
|
87
|
+
* as a multi-key Block payload already uses.
|
|
88
|
+
*/
|
|
89
|
+
export function seedMemForFlow(mem, flowBlocks, json, label, stubActive) {
|
|
90
|
+
const seen = new Map();
|
|
91
|
+
for (const bi of flowBlocks) {
|
|
92
|
+
for (const k of bi.block.requires ?? []) {
|
|
93
|
+
if (!seen.has(k.name))
|
|
94
|
+
seen.set(k.name, k);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
seedMemFromRequires(mem, Array.from(seen.values()), json, label, stubActive);
|
|
98
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// The CLI chain spec: "login then addToCart({...json...}) then checkoutFlow".
|
|
2
|
+
/** Splits a spec into segments, each a Block or Flow name with optional inline JSON for its mem. */
|
|
3
|
+
export function parseChainSpec(spec) {
|
|
4
|
+
return spec
|
|
5
|
+
.split(/\bthen\b/)
|
|
6
|
+
.map((s) => s.trim())
|
|
7
|
+
.filter((s) => s.length > 0)
|
|
8
|
+
.map((s) => {
|
|
9
|
+
const m = /^([A-Za-z_$][\w-]*)\s*(?:\(([\s\S]*)\))?$/.exec(s);
|
|
10
|
+
if (!m) {
|
|
11
|
+
throw new Error("waygraph chain: could not parse segment \"" + s + "\" - expected \"blockName\" or \"blockName({...json...})\"");
|
|
12
|
+
}
|
|
13
|
+
const ref = m[1];
|
|
14
|
+
const json = m[2] ? m[2].trim() : undefined;
|
|
15
|
+
return json ? { ref, json } : { ref };
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { buildFlow } from "../engine/flow/flow.js";
|
|
2
|
+
import { resetPage } from "./session.js";
|
|
3
|
+
/** Where a "retry" goes back to: the first step of this step's episode, or the start of an ad hoc chain. */
|
|
4
|
+
function episodeStart(steps, index) {
|
|
5
|
+
const episode = steps[index].episodeNumber;
|
|
6
|
+
return episode === undefined ? 0 : steps.findIndex((s) => s.episodeNumber === episode);
|
|
7
|
+
}
|
|
8
|
+
/** Runs one Block through the engine, on the session's page, with its own flow's config. */
|
|
9
|
+
async function runStep(step, session) {
|
|
10
|
+
const flow = buildFlow([step.block], step.config);
|
|
11
|
+
const { result } = await flow.run(session.context, session.mem, { page: session.page, closeOnFinish: false });
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
export async function playSteps(steps, session, mode, clearSession) {
|
|
15
|
+
await mode.begin?.(steps);
|
|
16
|
+
let outcome = { ok: true };
|
|
17
|
+
for (let i = 0; i < steps.length; i++) {
|
|
18
|
+
const step = steps[i];
|
|
19
|
+
// A segment's --data is seeded when it starts, so two segments can give the same key different values.
|
|
20
|
+
step.seedMem?.();
|
|
21
|
+
if ((clearSession || step.resetSession) && i > 0) {
|
|
22
|
+
await resetPage(session);
|
|
23
|
+
await mode.afterReset?.();
|
|
24
|
+
}
|
|
25
|
+
await mode.before?.(i);
|
|
26
|
+
const startedAt = Date.now();
|
|
27
|
+
let result;
|
|
28
|
+
try {
|
|
29
|
+
result = await runStep(step, session);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if ((await mode.failed?.(i, { error }, Date.now() - startedAt)) === "retry") {
|
|
33
|
+
await resetPage(session);
|
|
34
|
+
await mode.afterReset?.();
|
|
35
|
+
i = episodeStart(steps, i) - 1;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
outcome = step.expectedFailureReason
|
|
39
|
+
? { ok: true, expectedFailure: { step, reason: step.expectedFailureReason } }
|
|
40
|
+
: { ok: false, failedAt: { index: i, step, error } };
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
outcome = { ok: true, result };
|
|
44
|
+
// A flow meant to fail can also end on its failure branch without throwing (a login that stays on the login page).
|
|
45
|
+
if (step.expectedFailureReason) {
|
|
46
|
+
if ((await mode.failed?.(i, { result }, Date.now() - startedAt)) === "retry") {
|
|
47
|
+
await resetPage(session);
|
|
48
|
+
await mode.afterReset?.();
|
|
49
|
+
i = episodeStart(steps, i) - 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
outcome = { ok: true, result, expectedFailure: { step, reason: step.expectedFailureReason } };
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
await mode.after?.(i, result, Date.now() - startedAt);
|
|
56
|
+
}
|
|
57
|
+
await mode.end?.(outcome);
|
|
58
|
+
return outcome;
|
|
59
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// How `waygraph run` and `waygraph demo` play a flow. The CLI spawns this inside the project (so the project's own
|
|
2
|
+
// Playwright is used) with the project dir and the spec ("cartFlow", "loginFlow then add-item"). Every mode plays the
|
|
3
|
+
// same steps through the same engine; the mode decides what happens around each step.
|
|
4
|
+
import { MemPage } from "../engine/mem/mem.js";
|
|
5
|
+
import { beginRun, endRun } from "../engine/run/events.js";
|
|
6
|
+
import { withWebServer } from "../runtime/webserver.js";
|
|
7
|
+
import "../runtime/run-log.js";
|
|
8
|
+
import { planSteps } from "./plan/plan.js";
|
|
9
|
+
import { readOptions, slowMoFor } from "./options.js";
|
|
10
|
+
import { openSession } from "./session.js";
|
|
11
|
+
import { playSteps } from "./play-steps.js";
|
|
12
|
+
import { playBranches } from "./modes/branches.js";
|
|
13
|
+
import { runMode } from "./modes/run.js";
|
|
14
|
+
import { demoMode } from "./modes/demo.js";
|
|
15
|
+
import { reportMode } from "./modes/report.js";
|
|
16
|
+
export async function play(projectDir, spec) {
|
|
17
|
+
const options = readOptions();
|
|
18
|
+
const mem = new MemPage();
|
|
19
|
+
const { steps, flows } = await planSteps(projectDir, spec, mem, options);
|
|
20
|
+
if (options.mode === "branches")
|
|
21
|
+
return playBranches(flows, mem, options);
|
|
22
|
+
const slowMo = slowMoFor(options, steps);
|
|
23
|
+
const { session, close } = await openSession(projectDir, options, mem, slowMo.launch);
|
|
24
|
+
let outcome;
|
|
25
|
+
try {
|
|
26
|
+
const mode = await pickMode(options, session, steps, slowMo.demoBeat);
|
|
27
|
+
outcome = await playSteps(steps, session, mode, options.clearSession);
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
await close();
|
|
31
|
+
}
|
|
32
|
+
if (options.mode !== "report")
|
|
33
|
+
finish(outcome);
|
|
34
|
+
}
|
|
35
|
+
function pickMode(options, session, steps, demoBeat) {
|
|
36
|
+
if (options.mode === "demo")
|
|
37
|
+
return demoMode(session, steps, options, demoBeat);
|
|
38
|
+
if (options.mode === "report")
|
|
39
|
+
return reportMode(session);
|
|
40
|
+
return runMode();
|
|
41
|
+
}
|
|
42
|
+
function finish(outcome) {
|
|
43
|
+
if (outcome.failedAt)
|
|
44
|
+
throw outcome.failedAt.error;
|
|
45
|
+
if (outcome.expectedFailure) {
|
|
46
|
+
const { step, reason } = outcome.expectedFailure;
|
|
47
|
+
console.log(`waygraph: chain finished (expected failure on ${step.block.name}) -- ${reason}`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.log("waygraph: chain finished -- " + JSON.stringify(outcome.result));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** The process entry the CLI's bootstrap calls: one run (and one run log) per invocation. */
|
|
54
|
+
export function startRunner() {
|
|
55
|
+
const projectDir = process.argv[2] ?? process.cwd();
|
|
56
|
+
const spec = process.argv[3] ?? "";
|
|
57
|
+
const opened = beginRun(spec);
|
|
58
|
+
withWebServer(projectDir, () => play(projectDir, spec))
|
|
59
|
+
.then(() => endRun(opened, {}), (err) => {
|
|
60
|
+
endRun(opened, { error: err });
|
|
61
|
+
console.error(err && err.stack ? err.stack : String(err));
|
|
62
|
+
process.exitCode = 1;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MemPage } from "../engine/mem/mem.js";
|
|
2
|
+
import type { PlaySession } from "./mode.js";
|
|
3
|
+
import type { PlayOptions } from "./options.js";
|
|
4
|
+
export declare function openSession(projectDir: string, options: PlayOptions, mem: MemPage, launchSlowMo: number | undefined): Promise<{
|
|
5
|
+
session: PlaySession;
|
|
6
|
+
close: () => Promise<void>;
|
|
7
|
+
}>;
|
|
8
|
+
/** A fresh session between episodes: no cookies, no storage, back on the base URL (so the page itself looks fresh too). */
|
|
9
|
+
export declare function resetPage(session: PlaySession): Promise<void>;
|