waygraph 0.15.52 → 0.15.54

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.
Files changed (156) hide show
  1. package/README.md +8 -1
  2. package/dist/analysis/graph.d.ts +3 -0
  3. package/dist/analysis/map-check.d.ts +3 -2
  4. package/dist/auto-session/helpers.d.ts +10 -0
  5. package/dist/blocks-select.d.ts +3 -0
  6. package/dist/blocks-select.js +2 -0
  7. package/dist/cli/flags.js +3 -1
  8. package/dist/cli/usage.js +4 -1
  9. package/dist/cli.js +4 -1
  10. package/dist/commands/agent-dive-scaffold.d.ts +0 -20
  11. package/dist/commands/agent-dive-scaffold.js +3 -3
  12. package/dist/commands/init.js +1 -1
  13. package/dist/commands/upgrade.d.ts +1 -1
  14. package/dist/commands/upgrade.js +7 -1
  15. package/dist/config.d.ts +55 -19
  16. package/dist/config.js +55 -13
  17. package/dist/core/block.d.ts +7 -2
  18. package/dist/core/block.js +7 -3
  19. package/dist/core/blocks/api.d.ts +1 -0
  20. package/dist/core/blocks/method.d.ts +2 -0
  21. package/dist/core/blocks/method.js +1 -0
  22. package/dist/core/blocks/nav.d.ts +1 -0
  23. package/dist/core/blocks/page.d.ts +1 -0
  24. package/dist/core/branch-regression.d.ts +1 -0
  25. package/dist/core/compose.d.ts +1 -0
  26. package/dist/core/engine.d.ts +2 -0
  27. package/dist/core/engine.js +3 -1
  28. package/dist/core/flow.d.ts +11 -0
  29. package/dist/core/flow.js +32 -8
  30. package/dist/core/map-builder.d.ts +34 -1
  31. package/dist/core/map-builder.js +42 -4
  32. package/dist/core/run-graph.d.ts +2 -0
  33. package/dist/core/run-graph.js +1 -0
  34. package/dist/errors.d.ts +1 -0
  35. package/dist/extensions.d.ts +1 -0
  36. package/dist/extensions.js +1 -0
  37. package/dist/highlights/demo-pace.d.ts +4 -1
  38. package/dist/highlights/demo-pace.js +28 -3
  39. package/dist/highlights/device.d.ts +2 -0
  40. package/dist/highlights/device.js +2 -0
  41. package/dist/highlights/types.d.ts +6 -0
  42. package/dist/index.d.ts +2 -2
  43. package/dist/pilot-overlay/action-ring.d.ts +0 -9
  44. package/dist/pilot-overlay/action-ring.js +1 -1
  45. package/dist/pilot-overlay/panel.d.ts +2 -1
  46. package/dist/runner/interaction-patch.js +32 -1
  47. package/dist/runner/main.js +5 -2
  48. package/dist/runner/step-mode.js +10 -4
  49. package/dist/session/auto-explore-run.js +6 -0
  50. package/dist/session/auto-explore.d.ts +2 -1
  51. package/dist/session/auto-session-ipc.d.ts +1 -2
  52. package/dist/session/auto-session-ipc.js +1 -1
  53. package/dist/session/block-inject.d.ts +0 -13
  54. package/dist/session/block-inject.js +3 -3
  55. package/dist/session/overlay-beacon.d.ts +7 -0
  56. package/dist/session/overlay-beacon.js +5 -0
  57. package/dist/session/pilot.d.ts +1 -2
  58. package/dist/session/pilot.js +1 -2
  59. package/dist/traverse/coverage.d.ts +4 -4
  60. package/dist/traverse/coverage.js +4 -1
  61. package/dist/traverse/lease.d.ts +1 -0
  62. package/dist/traverse/lease.js +1 -0
  63. package/dist/traverse/run.d.ts +3 -0
  64. package/dist/types.d.ts +1 -1
  65. package/examples/routed-demo/src/flows/routed-demo-map.flow.ts +1 -1
  66. package/examples/routed-demo/src/flows/routed-demo.flow.ts +2 -2
  67. package/examples/saucedemo/README.md +11 -12
  68. package/examples/saucedemo/config/waygraph.config.ts +17 -0
  69. package/examples/saucedemo/docs/CONVENTION.md +1 -2
  70. package/examples/saucedemo/docs/HELPERS.md +1 -1
  71. package/examples/saucedemo/package-lock.json +10 -3
  72. package/examples/saucedemo/package.json +12 -29
  73. package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +0 -49
  74. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +22 -25
  75. package/examples/saucedemo/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +0 -6
  76. package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +38 -96
  77. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +1 -26
  78. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +1 -45
  79. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +14 -77
  80. package/examples/saucedemo/src/flows/api-demo.flow.ts +17 -11
  81. package/examples/saucedemo/src/flows/cart-bulk.flow.ts +19 -14
  82. package/examples/saucedemo/src/flows/cart-continue.flow.ts +10 -8
  83. package/examples/saucedemo/src/flows/cart-mem.flow.ts +7 -7
  84. package/examples/saucedemo/src/flows/catalog-logout.flow.ts +13 -8
  85. package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +26 -48
  86. package/examples/saucedemo/src/flows/checkout.flow.ts +70 -86
  87. package/examples/saucedemo/src/flows/device-showcase.flow.ts +24 -25
  88. package/examples/saucedemo/src/flows/login.flow.ts +11 -18
  89. package/examples/saucedemo/src/flows/mem-stub-demo.flow.ts +9 -20
  90. package/examples/saucedemo/src/flows/shop.flow.ts +15 -20
  91. package/examples/saucedemo/src/flows/smoke.flow.ts +12 -27
  92. package/examples/saucedemo/src/flows/stub-on-error.flow.ts +24 -43
  93. package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +26 -34
  94. package/examples/saucedemo/src/states/checkout.mem-stubs.ts +11 -0
  95. package/examples/saucedemo/src/stubs/device-showcase.ts +193 -0
  96. package/examples/saucedemo/src/stubs/login.ts +37 -0
  97. package/examples/saucedemo/tests/chain-flow-episodes.spec.ts +7 -9
  98. package/examples/saucedemo/tests/submit-login-branch.spec.ts +18 -5
  99. package/package.json +12 -5
  100. package/templates/quickstart/README.md +4 -7
  101. package/templates/quickstart/config/waygraph.config.ts +17 -0
  102. package/templates/quickstart/docs/CONVENTION.md +1 -2
  103. package/templates/quickstart/docs/HELPERS.md +1 -1
  104. package/templates/quickstart/package.json +14 -14
  105. package/templates/quickstart/src/blocks/SITE-MAP.md +14 -3
  106. package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +0 -49
  107. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +22 -25
  108. package/templates/quickstart/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +0 -6
  109. package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +38 -96
  110. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +1 -26
  111. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +1 -45
  112. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +14 -77
  113. package/templates/quickstart/src/flows/api-demo.flow.ts +43 -0
  114. package/templates/quickstart/src/flows/cart-bulk.flow.ts +19 -14
  115. package/templates/quickstart/src/flows/cart-continue.flow.ts +10 -8
  116. package/templates/quickstart/src/flows/cart-mem.flow.ts +7 -7
  117. package/templates/quickstart/src/flows/catalog-logout.flow.ts +13 -8
  118. package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +26 -48
  119. package/templates/quickstart/src/flows/checkout.flow.ts +70 -63
  120. package/templates/quickstart/src/flows/device-showcase.flow.ts +24 -25
  121. package/templates/quickstart/src/flows/login.flow.ts +11 -18
  122. package/templates/quickstart/src/flows/mem-stub-demo.flow.ts +12 -0
  123. package/templates/quickstart/src/flows/shop.flow.ts +15 -20
  124. package/templates/quickstart/src/flows/smoke.flow.ts +12 -27
  125. package/templates/quickstart/src/flows/stub-on-error.flow.ts +31 -0
  126. package/templates/quickstart/src/flows/viewer-blocked.flow.ts +26 -34
  127. package/templates/quickstart/src/states/checkout.mem-stubs.ts +11 -0
  128. package/templates/quickstart/src/stubs/device-showcase.ts +193 -0
  129. package/templates/quickstart/src/stubs/login.ts +37 -0
  130. package/templates/quickstart/tests/chain-flow.spec.ts +7 -10
  131. package/templates/scaffold/README.md +1 -1
  132. package/templates/scaffold/STRUCTURE.md +5 -2
  133. package/templates/scaffold/config/waygraph.config.ts +24 -5
  134. package/templates/scaffold/package.json +6 -6
  135. package/templates/scaffold/src/flows/(external)/hoppscotch/auth.flow.ts +36 -0
  136. package/templates/scaffold/src/flows/(external)/hoppscotch/get.flow.ts +24 -0
  137. package/templates/scaffold/src/flows/(external)/hoppscotch/post.flow.ts +34 -0
  138. package/templates/scaffold/src/flows/(user-stories)/email-verification.flow.ts +47 -0
  139. package/templates/scaffold/src/flows/README.md +35 -14
  140. package/templates/scaffold/src/flows/{shop.flow.ts → home/cart.flow.ts} +18 -17
  141. package/templates/scaffold/src/flows/{example.flow.ts → home/hello.flow.ts} +12 -13
  142. package/templates/scaffold/tests/example.spec.ts +5 -5
  143. package/templates/scaffold/tests/hoppscotch.spec.ts +3 -3
  144. package/templates/scaffold/tests/mail-verify.spec.ts +7 -7
  145. package/templates/skills/waygraph-convention.skill.md +14 -6
  146. package/examples/saucedemo/playwright.config.ts +0 -19
  147. package/examples/saucedemo/scripts/drive-auto-cli.mjs +0 -93
  148. package/examples/saucedemo/scripts/prove-add-to-cart-menu.mjs +0 -126
  149. package/examples/saucedemo/scripts/prove-auto-graph.mjs +0 -92
  150. package/examples/saucedemo/scripts/prove-wrong-login-runtime.mjs +0 -63
  151. package/templates/quickstart/playwright.config.ts +0 -14
  152. package/templates/quickstart/scripts/drive-auto-cli.mjs +0 -93
  153. package/templates/scaffold/src/flows/hoppscotch-auth.flow.ts +0 -35
  154. package/templates/scaffold/src/flows/hoppscotch-get.flow.ts +0 -23
  155. package/templates/scaffold/src/flows/hoppscotch-post.flow.ts +0 -33
  156. package/templates/scaffold/src/flows/mail-verify.flow.ts +0 -46
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export { Trait, urlMatches, textEquals, visible, disabled, enabled, frameVisible
9
9
  export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, defineAssertBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, defineApiBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withMemStub, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, withStubBefore, withStubAfter, withStubOnError, withDialog, chainFlow, defineLayout, map, MapBuilder, branchRoutes, collectBranchFlows, runBranchRegression, } from "./core.js";
10
10
  export type { BranchEntry, BranchRunResult, RunBranchRegressionOptions } from "./core/branch-regression.js";
11
11
  export type { ApiBlockOptions, ApiCallResult } from "./core/blocks/api.js";
12
- export type { MapStepOpts } from "./core/map-builder.js";
12
+ export type { MapStepOpts, MapFlowOpts } from "./core/map-builder.js";
13
13
  export { resolveHighlightSlots, resolveSlides, runStubPhase, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, normalizeHighlightSize, normalizeHighlightWeight, applyHighlightStyleDefaults, toneIconPrefix, resolveStepDemoPace, demoPaceScale, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, demoPaceGateMs, formatDemoPaceBadge, formatDemoPaceLabel, normalizeTodos, normalizeTodoPos, normalizeTodoStyle, buildTodoDock, applyTodoPhase, advanceTodoDock, completeSequentialTodoDock, applyDevicePhase, resolveDeviceState, normalizeDevicePreset, normalizeDeviceOrientation, applyOrientation, orientationFromViewport, DEVICE_PRESETS, resolveTodoDockUi, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, WAYGRAPH_RING_CSS, } from "./highlights.js";
14
14
  export type { WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, WaygraphTodoItem, WaygraphTodoInput, WaygraphTodoGroup, WaygraphTodoGroupInput, WaygraphTodosOpts, TodoDockUiOpts, BannerPos, BannerUiOpts, TodoDockUiResolved, TodoDockState, TodoListStyle, FixtureDurationFields, HighlightStubPhase, HighlightStubPhaseName, HighlightFixtureMap, ResolvedHighlight, WaygraphHighlight, HighlightTone, HighlightSize, HighlightWeight, HighlightStyleDefaults, DemoPace, DemoPaceName, StubCtx, StubLifecycleFn, StubPhaseResult, StubPhaseFixtures, DevicePreset, DeviceViewport, DeviceState, DeviceOrientation, } from "./highlights.js";
15
15
  export type { Flow, FlowOptions, EngineConfig, ComposedBlock, FastForwardComposedBlock, RunGraphOptions, BlockInfo, NavBlock, NavBlockOptions, NavClickBlock, NavClickBlockOptions, MethodBlock, ActionBlock, AssertBlock, AssertBlockOptions, PageBlock, PageBlockOptions, PageMethodEntry, EffectBlock, MemEffectBlock, MemNavBlock, Layout, LayoutOptions, MapBuilderOptions, } from "./core.js";
@@ -30,7 +30,7 @@ export type { AutoSessionInit, SessionSnapshot, SessionSnapshotEdge, SessionSnap
30
30
  export { pilotStart } from "./session/pilot.js";
31
31
  export type { PilotStartResult } from "./session/pilot.js";
32
32
  export { defineConfig, resolveBaseUrl } from "./config.js";
33
- export type { WaygraphConfig, ConfigContext } from "./config.js";
33
+ export type { WaygraphConfig, ConfigContext, VideoSettings, RunSettings, DemoSettings } from "./config.js";
34
34
  export { withWebServer } from "./webserver.js";
35
35
  export { chromiumExecutablePath } from "./browser.js";
36
36
  export { resolveExtension, KNOWN_EXTENSIONS } from "./extensions.js";
@@ -1,16 +1,7 @@
1
1
  import type { Page } from "@playwright/test";
2
- type Box = {
3
- x: number;
4
- y: number;
5
- width: number;
6
- height: number;
7
- };
8
- /** Paint the gray "auto" ring (Playwright is about to act here) at a viewport rectangle. */
9
- export declare function showPilotRect(page: Page, box: Box, label: string, tone?: string): Promise<void>;
10
2
  /**
11
3
  * Every Playwright instruction a Block runs against this session's page gets a gray (auto) ring + robot
12
4
  * label first, so a human watching a pilot window sees WHAT is being driven. `dwellMs` holds the ring
13
5
  * long enough to read before the action fires (0 for headless).
14
6
  */
15
7
  export declare function instrumentPilotActions(page: Page, dwellMs: number): void;
16
- export {};
@@ -1,6 +1,6 @@
1
1
  import { ensureInstalled } from "./shell.js";
2
2
  /** Paint the gray "auto" ring (Playwright is about to act here) at a viewport rectangle. */
3
- export async function showPilotRect(page, box, label, tone = "auto") {
3
+ async function showPilotRect(page, box, label, tone = "auto") {
4
4
  await ensureInstalled(page);
5
5
  await page
6
6
  .evaluate(({ box, label, tone }) => {
@@ -1,7 +1,7 @@
1
1
  import type { SessionSnapshot } from "../auto-session.js";
2
2
  import type { Page } from "@playwright/test";
3
3
  /** Minimal shape needed to render the graph tree - matches WaygraphGraph. */
4
- export interface PilotOverlayGraph {
4
+ interface PilotOverlayGraph {
5
5
  nodes: readonly {
6
6
  checkpoint: string;
7
7
  }[];
@@ -32,3 +32,4 @@ export interface PilotOverlayInfo {
32
32
  * operation over.
33
33
  */
34
34
  export declare function updatePilotOverlay(page: Page, info: PilotOverlayInfo): Promise<void>;
35
+ export {};
@@ -21,7 +21,36 @@ export function instrumentInteractionHighlighting(page, mem, slowMo, pacing, stu
21
21
  // (shorter Next/autoplay gates) and must NOT skip theater, or the whole demo
22
22
  // looks like plain waygraph run.
23
23
  const skipTheater = () => !!pacing.skipTheater;
24
- const typeDelay = () => (skipTheater() ? 0 : slowMo ? 0 : 30);
24
+ // `slowMo` here is the demo's own beat: ms to rest after each action (once per call, never per keystroke). The browser
25
+ // itself is launched with slowMo 0 in step mode, so a step whose pace is blitz really does run at full speed.
26
+ const beat = () => (skipTheater() ? 0 : slowMo || 0);
27
+ const pause = (ms) => (ms > 0 ? new Promise((res) => setTimeout(res, ms)) : undefined);
28
+ // Per-character typing delay (WAYGRAPH_TYPING_MS, default 30). 0 for blitz steps.
29
+ const typingMs = () => {
30
+ if (skipTheater()) return 0;
31
+ const n = Number(process.env.WAYGRAPH_TYPING_MS);
32
+ return process.env.WAYGRAPH_TYPING_MS !== undefined && Number.isFinite(n) && n >= 0 ? n : 30;
33
+ };
34
+ const typeDelay = typingMs;
35
+ const keyboard = page.keyboard;
36
+ if (!keyboard.__wgBeatPatched) {
37
+ keyboard.__wgBeatPatched = true;
38
+ const originalType = keyboard.type.bind(keyboard);
39
+ keyboard.type = async (text, options) => {
40
+ await originalType(text, { delay: typingMs(), ...(options || {}) });
41
+ await pause(beat());
42
+ };
43
+ const originalPress = keyboard.press.bind(keyboard);
44
+ keyboard.press = async (key, options) => {
45
+ await originalPress(key, options);
46
+ await pause(beat());
47
+ };
48
+ const originalInsertText = keyboard.insertText.bind(keyboard);
49
+ keyboard.insertText = async (text) => {
50
+ await originalInsertText(text);
51
+ await pause(beat());
52
+ };
53
+ }
25
54
  // Click is a single action, not per-character, so it doesn't compound
26
55
  // the same way - but slowMo still adds its own pause around the actual
27
56
  // click, so trim our own explicit "pop" pauses when it's already active
@@ -155,6 +184,7 @@ export function instrumentInteractionHighlighting(page, mem, slowMo, pacing, stu
155
184
  // it - it was sticking around through the whole rest of the step.
156
185
  await hideRing(page);
157
186
  await restoreTheaterAfterNavigation(page, todoDockRef, deviceRef, stubBeforeRef);
187
+ await pause(beat());
158
188
  return result;
159
189
  };
160
190
  }
@@ -285,6 +315,7 @@ export function instrumentInteractionHighlighting(page, mem, slowMo, pacing, stu
285
315
  await hideRing(page);
286
316
  // Full document navigation drops #wg-todo-dock + rings; restore carry.
287
317
  await restoreTheaterAfterNavigation(page, todoDockRef, deviceRef, stubBeforeRef);
318
+ await pause(beat());
288
319
  return result;
289
320
  };
290
321
  }
@@ -231,6 +231,9 @@ async function runMain() {
231
231
  : "waygraph demo: opaque FFCompose in flow -> Playwright slowMo=0 (blitz); set WAYGRAPH_SLOWMO to override",
232
232
  );
233
233
  }
234
+ // Step (demo) mode: slowMo is waygraph's own beat after each action, not Playwright's per-operation slowMo, so a
235
+ // step's pace can remove it and typing is not taxed per keystroke. The browser launches at 0.
236
+ const launchSlowMo = step ? 0 : slowMo;
234
237
  const baseURL = process.env.WAYGRAPH_BASE_URL;
235
238
  const title = process.env.WAYGRAPH_TITLE;
236
239
  // Comma-separated Block names (their real .name, e.g. "login") that
@@ -263,7 +266,7 @@ async function runMain() {
263
266
  const fixedVideoViewport = videoDir
264
267
  ? (videoViewportParsed ?? (step ? DEFAULT_VIDEO_VIEWPORT : DEFAULT_RUN_VIDEO_VIEWPORT))
265
268
  : null;
266
- const engine = new Engine({ headless: !headed, slowMo });
269
+ const engine = new Engine({ headless: !headed, slowMo: launchSlowMo });
267
270
  let result;
268
271
  // Non-interactive execution (no --step) runs the whole chain as one
269
272
  // composed flow with no per-block loop of its own to defer seeding
@@ -312,7 +315,7 @@ async function runMain() {
312
315
  launcher: chromium,
313
316
  launch: {
314
317
  headless: !headed,
315
- slowMo,
318
+ slowMo: launchSlowMo,
316
319
  args: step || fixedVideoViewport ? ["--start-maximized"] : [],
317
320
  ...(executablePath ? { executablePath } : {}),
318
321
  },
@@ -1,7 +1,7 @@
1
1
  // Moved verbatim from the former CHAIN_RUNNER_SCRIPT template string in cli.ts (see src/ARCHITECTURE.md).
2
2
  // Runs inside the target project's own waygraph copy - keep it dependency-light and self-contained.
3
3
  import { instrumentInteractionHighlighting } from "./interaction-patch.js";
4
- import { applyHighlightStyleDefaults, demoPaceGateMs, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, formatHighlightCaption, hasAuthoredStubAfter, resolveSlides, resolveStepDemoPace, resolveTodoDockUi, runStubPhase } from "../highlights.js";
4
+ import { applyHighlightStyleDefaults, normalizeDemoPace, demoPaceGateMs, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, formatHighlightCaption, hasAuthoredStubAfter, resolveSlides, resolveStepDemoPace, resolveTodoDockUi, runStubPhase } from "../highlights.js";
5
5
  import { markStepRunning, resetPageState, teardownOverlay } from "./teardown.js";
6
6
  import { demoLog, logStubPhaseFixtures, logTodoDockFull, paceSpeakFields, summarizeDevice } from "./demo-log.js";
7
7
  import { extractVerifyHighlights, presentFailPanel, renderAfterStep, renderBeforeStep } from "./step-panels.js";
@@ -26,6 +26,8 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
26
26
  const demoFast = process.env.WAYGRAPH_DEMO_FAST === "1";
27
27
  const stepperMode = process.env.WAYGRAPH_STEPPER === "full" ? "full" : "carousel";
28
28
  const pacing = { gatesFast: demoFast, gatesSlow: false, skipTheater: false, demoPace: "normal" };
29
+ // A title set by a stub (`ctx.title`) names the flow from that step on, until another stub sets a new one.
30
+ let stickyTitle;
29
31
  const stubBeforeRef = { current: [] };
30
32
  /** Live todo dock for Method fill/click advance (same carry as stage.state.lastTodoDock). */
31
33
  const todoDockRef = { current: undefined };
@@ -213,15 +215,18 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
213
215
  }
214
216
  // Episode pace: block > flow > CLI --fast (only when no authored pace).
215
217
  // Authoring wins: withDemoPace("slow"|2|4500) keeps slow dwell even under --fast.
218
+ // `demo.pace` in the config (WAYGRAPH_DEMO_PACE) is the default for flows and steps that set none.
219
+ const defaultPace = process.env.WAYGRAPH_DEMO_PACE ? normalizeDemoPace(process.env.WAYGRAPH_DEMO_PACE) : undefined;
216
220
  const stepPace = resolveStepDemoPace({
217
221
  blockPace: r.block.demoPace,
218
- flowPace: r.demoPace,
222
+ flowPace: r.demoPace ?? defaultPace,
219
223
  fastForward: !!r.block.fastForward,
220
224
  wasFastForward: !!r.wasFastForward,
221
225
  });
222
226
  const authoredPace =
223
227
  (r.block.demoPace != null && r.block.demoPace !== "") ||
224
- (r.demoPace != null && r.demoPace !== "");
228
+ (r.demoPace != null && r.demoPace !== "") ||
229
+ defaultPace != null;
225
230
  const cliFast = demoFast || fastBlockNames.has(r.block.name);
226
231
  pacing.demoPace =
227
232
  stepPace === "normal" && cliFast && !authoredPace
@@ -266,8 +271,9 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
266
271
  (stage.state.lastTodoDock && stage.state.lastTodoDock.groups[0] && stage.state.lastTodoDock.groups[0].items) ||
267
272
  stubBeforePhase.todos ||
268
273
  [];
274
+ if (stubBeforePhase.title && String(stubBeforePhase.title).trim()) stickyTitle = String(stubBeforePhase.title).trim();
269
275
  const overlayTitle =
270
- (stubBeforePhase.title && String(stubBeforePhase.title).trim()) ||
276
+ stickyTitle ||
271
277
  (r.episodeTitle && String(r.episodeTitle).trim()) ||
272
278
  title ||
273
279
  "waygraph demo";
@@ -1,3 +1,4 @@
1
+ import { getMemStub } from "../mem-stub.js";
1
2
  import { createInterface } from "node:readline/promises";
2
3
  import { ensureShadowRoot } from "../ui/shadow.js";
3
4
  import { stdin as input, stdout as output } from "node:process";
@@ -115,6 +116,11 @@ export function seedDefaultMem(library, mem) {
115
116
  mem.set(k, envParsed[k.name]);
116
117
  continue;
117
118
  }
119
+ const stub = getMemStub(k);
120
+ if (stub) {
121
+ mem.set(k, stub());
122
+ continue;
123
+ }
118
124
  const def = defaultMemValueForKey(k.name);
119
125
  if (def !== undefined)
120
126
  mem.set(k, def);
@@ -24,7 +24,7 @@ export interface ExploreEdge extends WaygraphEdge {
24
24
  label?: string;
25
25
  instanceOption?: WaygraphInstanceOption;
26
26
  }
27
- export interface ExploreSection {
27
+ interface ExploreSection {
28
28
  title: string;
29
29
  edges: ExploreEdge[];
30
30
  }
@@ -55,3 +55,4 @@ export declare function buildExploreContext(projectDir: string, opts?: ExploreCo
55
55
  graph: WaygraphGraph;
56
56
  library: Awaited<ReturnType<typeof loadBlockLibrary>>;
57
57
  }>;
58
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { AutoSession, type AutoSessionInit, type SessionSnapshot, type InspectDomOptions, type DomSnapshot, type TraceStep, type ApplyPathResult, type ConsoleLogEntry, type StorageSnapshot, type StubFileKind } from "../auto-session.js";
2
2
  import type { PilotHighlightFixtures } from "../pilot-overlay.js";
3
- export type { PilotHighlightFixtures, PilotFixtureRing } from "../pilot-overlay.js";
3
+ export type { PilotHighlightFixtures } from "../pilot-overlay.js";
4
4
  export interface SessionMeta {
5
5
  sessionId: string;
6
6
  socketPath: string;
@@ -54,7 +54,6 @@ export type HighlightResponse = {
54
54
  ok: false;
55
55
  error: string;
56
56
  };
57
- export declare function readSessionMeta(projectDir: string, sessionId: string): SessionMeta | null;
58
57
  /**
59
58
  * Resolve session metadata from a project hint (cwd) or the global registry.
60
59
  * Fixes "session unreachable" when the agent calls status/send from a different
@@ -58,7 +58,7 @@ function logPathFor(projectDir, sessionId) {
58
58
  function generateSessionId() {
59
59
  return randomBytes(4).toString("hex");
60
60
  }
61
- export function readSessionMeta(projectDir, sessionId) {
61
+ function readSessionMeta(projectDir, sessionId) {
62
62
  const p = metaPath(projectDir, sessionId);
63
63
  if (!existsSync(p))
64
64
  return null;
@@ -1,21 +1,8 @@
1
- /**
2
- * This package's own installed root (contains `templates/`/`examples/`, sibling to `dist/`) -
3
- * this file compiles to `dist/session/block-inject.js`, two levels down, not one. Same class of
4
- * bug as `cli/util.ts`'s own `packageRoot()` (see its comment) - self-inflicted here by moving
5
- * this file into `src/session/` without updating the path math to match the new depth.
6
- */
7
- export declare function packageRoot(): string;
8
- /** Human label for an injected root (used in merged `file` paths). */
9
- export declare function injectLabel(root: string): string;
10
1
  /**
11
2
  * Display path for a Block discovered under an inject root (not the host cwd).
12
3
  * Primary project files stay relative as-is; injected ones are tagged `@label/...`.
13
4
  */
14
5
  export declare function injectTaggedFile(hostDir: string, root: string, relFile: string): string;
15
- /**
16
- * Resolve one `--inject` token to an absolute directory (preset name or path).
17
- */
18
- export declare function resolveInjectRoot(token: string, cwd?: string): string;
19
6
  export declare function resolveInjectRoots(tokens: string[], cwd?: string): string[];
20
7
  /** Roots to scan: host project first, then each inject path (deduped). */
21
8
  export declare function exploreRoots(projectDir: string, inject?: string[]): string[];
@@ -12,11 +12,11 @@ import { homedir } from "node:os";
12
12
  * bug as `cli/util.ts`'s own `packageRoot()` (see its comment) - self-inflicted here by moving
13
13
  * this file into `src/session/` without updating the path math to match the new depth.
14
14
  */
15
- export function packageRoot() {
15
+ function packageRoot() {
16
16
  return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
17
17
  }
18
18
  /** Human label for an injected root (used in merged `file` paths). */
19
- export function injectLabel(root) {
19
+ function injectLabel(root) {
20
20
  return basename(root.replace(/\/$/, ""));
21
21
  }
22
22
  /**
@@ -50,7 +50,7 @@ const PRESETS = {
50
50
  /**
51
51
  * Resolve one `--inject` token to an absolute directory (preset name or path).
52
52
  */
53
- export function resolveInjectRoot(token, cwd = process.cwd()) {
53
+ function resolveInjectRoot(token, cwd = process.cwd()) {
54
54
  const raw = token.trim();
55
55
  if (!raw)
56
56
  throw new Error("waygraph inject: empty --inject value");
@@ -10,11 +10,17 @@
10
10
  * `assertWgOverlayReady(page)` (or WAYGRAPH_PROVE_EXIT=1) passes.
11
11
  */
12
12
  import type { Page } from "@playwright/test";
13
+ /** Selector matching every element waygraph's overlay draws into a page. */
13
14
  export declare const WG_UI_SEL = "[data-wg-ui=\"1\"]";
15
+ /** Selector of the overlay element that appears when the step panel is ready. */
14
16
  export declare const WG_READY_PANEL_SEL = "[data-wg-modal=\"panel\"][data-wg-ready=\"1\"]";
17
+ /** Selector of the overlay element that appears when the auto panel is ready. */
15
18
  export declare const WG_READY_AUTO_SEL = "[data-wg-modal=\"auto-panel\"][data-wg-ready=\"1\"]";
19
+ /** Selector of the overlay element that appears when the banner is ready. */
16
20
  export declare const WG_READY_BANNER_SEL = "[data-wg-modal=\"banner\"][data-wg-ready=\"1\"]";
21
+ /** The kind of modal the overlay beacon reports. */
17
22
  export type WgModalKind = "panel" | "banner" | "auto-panel";
23
+ /** One overlay element a session reports through its beacon. */
18
24
  export type WgBeaconRow = {
19
25
  id: string | null;
20
26
  modal: string | null;
@@ -31,6 +37,7 @@ export type WgBeaconRow = {
31
37
  };
32
38
  /** Browser-side beacon reader (also installed as window.__wgOverlayBeacon). */
33
39
  export declare function readWgOverlayBeaconInPage(): WgBeaconRow[];
40
+ /** Reads the overlay beacon from a page: what waygraph's own UI is showing. */
34
41
  export declare function readWgOverlayBeacon(page: Page): Promise<WgBeaconRow[]>;
35
42
  /**
36
43
  * Hard gate: a blank / missing / opacity-0 modal fails.
@@ -9,9 +9,13 @@
9
9
  * Agents: do not claim the stepper works unless
10
10
  * `assertWgOverlayReady(page)` (or WAYGRAPH_PROVE_EXIT=1) passes.
11
11
  */
12
+ /** Selector matching every element waygraph's overlay draws into a page. */
12
13
  export const WG_UI_SEL = '[data-wg-ui="1"]';
14
+ /** Selector of the overlay element that appears when the step panel is ready. */
13
15
  export const WG_READY_PANEL_SEL = '[data-wg-modal="panel"][data-wg-ready="1"]';
16
+ /** Selector of the overlay element that appears when the auto panel is ready. */
14
17
  export const WG_READY_AUTO_SEL = '[data-wg-modal="auto-panel"][data-wg-ready="1"]';
18
+ /** Selector of the overlay element that appears when the banner is ready. */
15
19
  export const WG_READY_BANNER_SEL = '[data-wg-modal="banner"][data-wg-ready="1"]';
16
20
  /** Browser-side beacon reader (also installed as window.__wgOverlayBeacon). */
17
21
  export function readWgOverlayBeaconInPage() {
@@ -37,6 +41,7 @@ export function readWgOverlayBeaconInPage() {
37
41
  };
38
42
  });
39
43
  }
44
+ /** Reads the overlay beacon from a page: what waygraph's own UI is showing. */
40
45
  export async function readWgOverlayBeacon(page) {
41
46
  return page.evaluate(() => {
42
47
  const w = window;
@@ -29,9 +29,9 @@
29
29
  * new execution primitive.
30
30
  */
31
31
  import { type WaygraphGraph } from "../analysis/graph.js";
32
- import { listBrowserSessions, type SessionMeta } from "./auto-session-ipc.js";
33
32
  import { type BrowserStartInit } from "./browser.js";
34
33
  import type { SessionSnapshot } from "../auto-session.js";
34
+ /** What `pilotStart` returns: the session id, socket path and first snapshot. */
35
35
  export interface PilotStartResult {
36
36
  sessionId: string;
37
37
  socketPath: string;
@@ -51,4 +51,3 @@ export interface PilotStartResult {
51
51
  export declare function pilotStart(init: BrowserStartInit): Promise<PilotStartResult>;
52
52
  /** Reattach to an existing browser session — does not spawn a new browser. */
53
53
  export declare function pilotAttach(projectDir: string, sessionId: string, inject?: string[]): Promise<PilotStartResult>;
54
- export { listBrowserSessions, type SessionMeta };
@@ -29,7 +29,7 @@
29
29
  * new execution primitive.
30
30
  */
31
31
  import { discoverGraph } from "../analysis/graph.js";
32
- import { requestSession, listBrowserSessions, resolveSessionMeta, } from "./auto-session-ipc.js";
32
+ import { requestSession, resolveSessionMeta, } from "./auto-session-ipc.js";
33
33
  import { browserStart } from "./browser.js";
34
34
  /**
35
35
  * Starts a detached session and reads back its own graph + starting
@@ -77,4 +77,3 @@ export async function pilotAttach(projectDir, sessionId, inject) {
77
77
  snapshot: status.snapshot,
78
78
  };
79
79
  }
80
- export { listBrowserSessions };
@@ -1,3 +1,4 @@
1
+ /** The edge-coverage report `traverse` writes: which graph edges were walked. */
1
2
  export interface TraverseCoverageReport {
2
3
  version: 1;
3
4
  generatedAt: string;
@@ -27,10 +28,6 @@ export interface TraverseCoverageReport {
27
28
  leaf?: string;
28
29
  }>;
29
30
  }
30
- /** Static graph edge key = Block runtime name. */
31
- export declare function edgeKeyFromGraphEdge(edge: {
32
- block: string;
33
- }): string;
34
31
  /** Collect unique edge keys from a WaygraphGraph-like edges list. */
35
32
  export declare function collectGraphEdgeKeys(edges: ReadonlyArray<{
36
33
  block: string;
@@ -45,6 +42,7 @@ export declare function normalizeHitKey(hitKey: string, graphKeys: ReadonlySet<s
45
42
  * Returns 0-1 fraction, or null when unset/invalid.
46
43
  */
47
44
  export declare function parseMinEdgeCoverage(raw: unknown): number | null;
45
+ /** Builds the `traverse` coverage report from the edges walked and the graph's edges. */
48
46
  export declare function buildCoverageReport(opts: {
49
47
  projectDir: string;
50
48
  parallel: number;
@@ -55,5 +53,7 @@ export declare function buildCoverageReport(opts: {
55
53
  }): TraverseCoverageReport;
56
54
  /** Greppable one-liner for agents/CI. */
57
55
  export declare function formatCoverageLine(report: TraverseCoverageReport): string;
56
+ /** Where `traverse` writes its coverage report by default. */
58
57
  export declare function defaultCoverageOutPath(projectDir: string): string;
58
+ /** Writes the `traverse` coverage report to disk. */
59
59
  export declare function writeCoverageReport(path: string, report: TraverseCoverageReport): void;
@@ -10,7 +10,7 @@
10
10
  import { mkdirSync, writeFileSync } from "node:fs";
11
11
  import { dirname, join } from "node:path";
12
12
  /** Static graph edge key = Block runtime name. */
13
- export function edgeKeyFromGraphEdge(edge) {
13
+ function edgeKeyFromGraphEdge(edge) {
14
14
  return edge.block;
15
15
  }
16
16
  /** Collect unique edge keys from a WaygraphGraph-like edges list. */
@@ -68,6 +68,7 @@ export function parseMinEdgeCoverage(raw) {
68
68
  return n / 100;
69
69
  return null;
70
70
  }
71
+ /** Builds the `traverse` coverage report from the edges walked and the graph's edges. */
71
72
  export function buildCoverageReport(opts) {
72
73
  const all = [...new Set(opts.allEdgeKeys)].sort();
73
74
  const graphSet = new Set(all);
@@ -118,9 +119,11 @@ export function formatCoverageLine(report) {
118
119
  : "";
119
120
  return `[Coverage edges=${report.edgesHit}/${report.edgesTotal} ratio=${pct}%${minPart}]`;
120
121
  }
122
+ /** Where `traverse` writes its coverage report by default. */
121
123
  export function defaultCoverageOutPath(projectDir) {
122
124
  return join(projectDir, ".waygraph-traverse", "coverage.json");
123
125
  }
126
+ /** Writes the `traverse` coverage report to disk. */
124
127
  export function writeCoverageReport(path, report) {
125
128
  mkdirSync(dirname(path), { recursive: true });
126
129
  writeFileSync(path, JSON.stringify(report, null, 2) + "\n", "utf-8");
@@ -2,6 +2,7 @@ export interface EdgeLeaseRecord {
2
2
  workerId: string;
3
3
  claimedAt: number;
4
4
  }
5
+ /** Hands out graph edges to parallel `traverse` workers so no two workers walk the same edge. */
5
6
  export declare class EdgeLeaseCoordinator {
6
7
  private readonly held;
7
8
  private readonly dir;
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
7
7
  import { join } from "node:path";
8
+ /** Hands out graph edges to parallel `traverse` workers so no two workers walk the same edge. */
8
9
  export class EdgeLeaseCoordinator {
9
10
  held = new Map();
10
11
  dir;
@@ -1,10 +1,13 @@
1
+ /** How `traverse` workers share a browser: one session, or a clone per worker. */
1
2
  export type TraverseSessionMode = "clone" | "inherit";
3
+ /** What one `traverse` worker did: edges walked and failures. */
2
4
  export interface TraverseWorkerResult {
3
5
  exitCode: number;
4
6
  steps: number;
5
7
  edgesHit: string[];
6
8
  leaf?: string;
7
9
  }
10
+ /** Options for `runTraverse`: workers, session mode, step limit, coverage gate. */
8
11
  export interface TraverseOptions {
9
12
  baseURL?: string;
10
13
  startUrl?: string;
package/dist/types.d.ts CHANGED
@@ -2,7 +2,7 @@ import type { Page } from "@playwright/test";
2
2
  import type { MemPage, MemKey } from "./mem-page.js";
3
3
  import type { Trait } from "./trait.js";
4
4
  import type { HighlightStubPhaseOrFn, WaygraphHighlight, WaygraphSlidesOrFn } from "./highlights.js";
5
- export type { WaygraphHighlight, WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, HighlightStubPhase, HighlightStubPhaseOrFn, HighlightFixtureMap, ResolvedHighlight, StubCtx, StubLifecycleFn, StubPhaseResult, StubPhaseFixtures, WaygraphTodoItem, WaygraphTodoInput, } from "./highlights.js";
5
+ export type { WaygraphHighlight } from "./highlights.js";
6
6
  /**
7
7
  * A Checkpoint is identified solely by its string tag - a phantom marker with no
8
8
  * embedded data. Two Checkpoints with the same tag are the same state everywhere.
@@ -13,7 +13,7 @@ const homeOrigin = process.env.WAYGRAPH_BASE_URL || "http://127.0.0.1:4277";
13
13
  /**
14
14
  * Same real Blocks, same real Checkpoints, same real fixture server as
15
15
  * routed-demo.flow.ts - built with `engine.map()` instead of
16
- * `engine.defineFlow([start, ..., end])` to prove the fluent builder
16
+ * the deprecated `engine.defineFlow([start, ..., end])` to prove the fluent builder
17
17
  * against a real browser/DOM, not just the in-memory fakes
18
18
  * tests/nav/map-builder.spec.ts already covers in the main package.
19
19
  *
@@ -1,4 +1,4 @@
1
- import { Engine, start, end } from "waygraph";
1
+ import { Engine } from "waygraph";
2
2
  import { NavDashboardBlock } from "../map/(app_base)/dashboard/_nav.block.js";
3
3
  import { ClickWidgetBlock } from "../map/(app_base)/dashboard/_methods/click-widget.block.js";
4
4
  import { NavDocsBlock } from "../map/(external)/docs/_nav.block.js";
@@ -9,4 +9,4 @@ import "../map/(external)/docs/_page.block.js";
9
9
  const engine = new Engine();
10
10
 
11
11
  /** Smoke: dashboard -> click widget -> docs, all Blocks under the Waygraph Map folder convention. */
12
- export const routedDemoFlow = engine.defineFlow([start, NavDashboardBlock, ClickWidgetBlock, NavDocsBlock, end]);
12
+ export const routedDemoFlow = engine.map().start().gotoPage(NavDashboardBlock).method(ClickWidgetBlock).gotoPage(NavDocsBlock).end();
@@ -7,7 +7,6 @@ the **reference** for waygraph consumer conventions:
7
7
  - **Nav** / **Effect** / **Action** file kinds (helpers are TypeScript salt;
8
8
  runtime is still `Block`)
9
9
  - `instanceOptions` menus for `waygraph auto` (Add/Remove + Open details)
10
- - Detailed Kind / Helper / Route comments on every Block file
11
10
  - Per-route `NAV.md` + root `src/blocks/SITE-MAP.md`
12
11
  - Inline `{ ff: true }` fast-forward, no `.ffStart()/.ffEnd()` bracket - see
13
12
  `checkoutFlow` (`src/flows/checkout.flow.ts`)
@@ -44,30 +43,30 @@ npx playwright install chromium
44
43
  | Graph crawl (Phase B-E) | `npm run traverse` |
45
44
  | Parallel crawl + leases | `npm run traverse:parallel` |
46
45
  | Coverage JSON + min gate (10%) | `npm run traverse:coverage` |
47
- | Shop demo stepper | `npm run demo:step` |
46
+ | Shop demo (login, then shop) | `npm run demo` |
48
47
  | Shop demo autoplay | `npm run demo:auto-next` |
49
- | **Device showcase** (mobile/tablet + portrait/landscape) | `npm run demo:device` |
50
- | Device showcase + `.webm` | `npm run demo:device:video` |
48
+ | **Device showcase** (mobile/tablet + portrait/landscape; narration in `src/stubs/device-showcase.ts`) | `npm run demo:device` |
49
+ | Device showcase + `.webm` | `npm run demo:video` |
51
50
  | **Cart bulk** demo (add-all → remove-all) | `npm run demo:bulk` |
52
- | Cart bulk autoplay | `npm run demo:bulk:auto-next` |
53
51
  | **Owner checkout** (inline `{ ff: true }`, `ctx.caption()`, banner position) | `npm run demo:checkout` |
54
- | Owner checkout + `.webm` | `npm run demo:checkout:video` |
55
52
  | **FE + BE in one Flow** (`defineApiBlock`, live network panel) | `npm run demo:api` |
56
- | FE + BE demo + `.webm` | `npm run demo:api:video` |
53
+ | Record (headless `.webm`) | `npm run record` |
57
54
  | List flows | `npm run flows` |
58
55
 
56
+ Credentials and the selected item come from `registerMemStub` in `src/states/checkout.mem-stubs.ts` (`memStub: true` on the
57
+ flows), so no command needs `--data`. Settings, the base URL and the shared `engine` are in `config/waygraph.config.ts`.
58
+ Narration is chained on Blocks in the flows (`src/flows/`) or shared from `src/stubs/`; the Block files carry none.
59
+
59
60
  **Demo vs auto vs run for cart bulk**
60
61
 
61
62
  | | CLI | Needs `.flow.ts`? |
62
63
  |--|-----|-------------------|
63
- | **`run --blocks`** | `npm run run:bulk` — Block names + `--data` | No |
64
- | **`demo --blocks`** | `npm run demo:bulk` — named flow + `--data` | Optional (`cartBulkFlow`) |
64
+ | **`run --blocks`** | `waygraph run --blocks "loginFlow then add-all-to-cart"` | No |
65
+ | **`demo --blocks`** | `npm run demo:bulk` — named flow | Optional (`cartBulkFlow`) |
65
66
  | **`auto`** | `npm run auto` / `auto:cli` | No — live menu |
66
- | **`traverse`** | `npm run traverse` / `traverse:parallel` / `traverse:coverage` | No — graph crawl + `.waygraph-traverse/coverage.json` |
67
+ | **`traverse`** | `npm run traverse` | No — graph crawl + `.waygraph-traverse/coverage.json` |
67
68
  | **`auto --blocks From To`** | path-find on graph | No — checkpoints only |
68
69
 
69
- QA watch+record: `npm run demo:bulk:video` (`--auto-play-video`).
70
-
71
70
  ## Layout (short)
72
71
 
73
72
  ```text
@@ -0,0 +1,17 @@
1
+ import { Engine, defineConfig } from "waygraph";
2
+
3
+ const config = defineConfig({
4
+ baseUrl: "https://www.saucedemo.com",
5
+ playwright: {
6
+ workers: 1,
7
+ fullyParallel: false,
8
+ timeout: 30_000,
9
+ use: {
10
+ headless: true,
11
+ launchOptions: { args: ["--no-sandbox", "--disable-dev-shm-usage"] },
12
+ },
13
+ },
14
+ });
15
+
16
+ export default config;
17
+ export const engine = new Engine(config);
@@ -106,5 +106,4 @@ waygraph chain "loginFlow" --step --no-autoplay
106
106
 
107
107
  Flags beat env: `--step` / `--no-step`, `--autoplay` / `--no-autoplay`,
108
108
  `--base-url <url>`, `--title <text>`. Default BASE_URL resolution order for
109
- `demo`: `--base-url` > `WAYGRAPH_BASE_URL` > `package.json` `waygraph.baseUrl`
110
- > `playwright.config` `baseURL`.
109
+ `demo`: `--base-url` > `WAYGRAPH_BASE_URL` > `baseUrl` in `config/waygraph.config.ts`.
@@ -110,7 +110,7 @@ branch(SubmitLoginBlock, {
110
110
  });
111
111
  ```
112
112
 
113
- Linear `defineFlow([start, …, end])` usually skips `branch()` (one happy path).
113
+ A linear `map()` chain usually skips `branch()` (one happy path).
114
114
 
115
115
  ---
116
116
 
@@ -16,10 +16,12 @@
16
16
  }
17
17
  },
18
18
  "../..": {
19
- "version": "0.15.19",
19
+ "version": "0.15.53",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "tsx": "^4.0.0"
22
+ "open-props": "^1.7.23",
23
+ "tsx": "^4.0.0",
24
+ "urlpattern-polyfill": "^10.1.0"
23
25
  },
24
26
  "bin": {
25
27
  "waygraph": "bin/waygraph"
@@ -27,7 +29,12 @@
27
29
  "devDependencies": {
28
30
  "@playwright/test": "^1.63.0",
29
31
  "@types/node": "^26.0.0",
30
- "typescript": "^5.6.0"
32
+ "knip": "^6.42.1",
33
+ "typedoc": "^0.28.20",
34
+ "typedoc-plugin-markdown": "^4.14.1",
35
+ "typedoc-vitepress-theme": "^1.1.4",
36
+ "typescript": "^5.6.0",
37
+ "vitepress": "^1.6.4"
31
38
  },
32
39
  "peerDependencies": {
33
40
  "@playwright/test": "^1.40.0"