waygraph 0.15.52 → 0.15.53

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 (59) hide show
  1. package/README.md +8 -1
  2. package/dist/analysis/map-check.d.ts +3 -2
  3. package/dist/cli/flags.js +3 -1
  4. package/dist/cli/usage.js +4 -1
  5. package/dist/cli.js +4 -1
  6. package/dist/commands/agent-dive-scaffold.d.ts +0 -20
  7. package/dist/commands/agent-dive-scaffold.js +3 -3
  8. package/dist/commands/init.js +1 -1
  9. package/dist/commands/upgrade.d.ts +1 -1
  10. package/dist/commands/upgrade.js +7 -1
  11. package/dist/config.d.ts +53 -19
  12. package/dist/config.js +55 -13
  13. package/dist/core/block.d.ts +7 -2
  14. package/dist/core/block.js +7 -3
  15. package/dist/core/engine.d.ts +2 -0
  16. package/dist/core/engine.js +3 -1
  17. package/dist/core/flow.d.ts +10 -0
  18. package/dist/core/flow.js +32 -8
  19. package/dist/core/map-builder.d.ts +27 -1
  20. package/dist/core/map-builder.js +42 -4
  21. package/dist/highlights/demo-pace.d.ts +0 -1
  22. package/dist/highlights/demo-pace.js +24 -3
  23. package/dist/index.d.ts +2 -2
  24. package/dist/pilot-overlay/action-ring.d.ts +0 -9
  25. package/dist/pilot-overlay/action-ring.js +1 -1
  26. package/dist/pilot-overlay/panel.d.ts +2 -1
  27. package/dist/runner/interaction-patch.js +32 -1
  28. package/dist/runner/main.js +5 -2
  29. package/dist/runner/step-mode.js +10 -4
  30. package/dist/session/auto-explore.d.ts +2 -1
  31. package/dist/session/auto-session-ipc.d.ts +1 -2
  32. package/dist/session/auto-session-ipc.js +1 -1
  33. package/dist/session/block-inject.d.ts +0 -13
  34. package/dist/session/block-inject.js +3 -3
  35. package/dist/session/pilot.d.ts +0 -2
  36. package/dist/session/pilot.js +1 -2
  37. package/dist/traverse/coverage.d.ts +0 -4
  38. package/dist/traverse/coverage.js +1 -1
  39. package/dist/types.d.ts +1 -1
  40. package/package.json +11 -5
  41. package/templates/scaffold/README.md +1 -1
  42. package/templates/scaffold/STRUCTURE.md +5 -2
  43. package/templates/scaffold/config/waygraph.config.ts +24 -5
  44. package/templates/scaffold/package.json +6 -6
  45. package/templates/scaffold/src/flows/(external)/hoppscotch/auth.flow.ts +36 -0
  46. package/templates/scaffold/src/flows/(external)/hoppscotch/get.flow.ts +24 -0
  47. package/templates/scaffold/src/flows/(external)/hoppscotch/post.flow.ts +34 -0
  48. package/templates/scaffold/src/flows/(user-stories)/email-verification.flow.ts +47 -0
  49. package/templates/scaffold/src/flows/README.md +35 -14
  50. package/templates/scaffold/src/flows/{shop.flow.ts → home/cart.flow.ts} +18 -17
  51. package/templates/scaffold/src/flows/{example.flow.ts → home/hello.flow.ts} +12 -13
  52. package/templates/scaffold/tests/example.spec.ts +5 -5
  53. package/templates/scaffold/tests/hoppscotch.spec.ts +3 -3
  54. package/templates/scaffold/tests/mail-verify.spec.ts +7 -7
  55. package/templates/skills/waygraph-convention.skill.md +14 -6
  56. package/templates/scaffold/src/flows/hoppscotch-auth.flow.ts +0 -35
  57. package/templates/scaffold/src/flows/hoppscotch-get.flow.ts +0 -23
  58. package/templates/scaffold/src/flows/hoppscotch-post.flow.ts +0 -33
  59. package/templates/scaffold/src/flows/mail-verify.flow.ts +0 -46
package/README.md CHANGED
@@ -16,7 +16,14 @@ export const SubmitLoginBlock = defineMethodBlock<LoginPage, LoggedIn>({
16
16
  });
17
17
 
18
18
  // A Flow = Blocks in order.
19
- export const loginFlow = engine.defineFlow([start, NavLoginBlock, FillUsernameBlock, FillPasswordBlock, SubmitLoginBlock, end]);
19
+ export const loginFlow = engine
20
+ .map()
21
+ .start()
22
+ .gotoPage(NavLoginBlock)
23
+ .method(FillUsernameBlock)
24
+ .method(FillPasswordBlock)
25
+ .method(SubmitLoginBlock)
26
+ .end();
20
27
  ```
21
28
 
22
29
  ## Try it in 60 seconds
@@ -1,9 +1,9 @@
1
- export interface MapViolation {
1
+ interface MapViolation {
2
2
  file: string;
3
3
  block: string;
4
4
  reason: string;
5
5
  }
6
- export interface MapNode {
6
+ interface MapNode {
7
7
  block: string;
8
8
  checkpoint: string | undefined;
9
9
  file: string;
@@ -16,3 +16,4 @@ export interface MapCheckResult {
16
16
  violations: MapViolation[];
17
17
  }
18
18
  export declare function checkMap(projectDir: string): Promise<MapCheckResult>;
19
+ export {};
package/dist/cli/flags.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { basename, relative, resolve } from "node:path";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { walkDir } from "./discover.js";
5
- import { resolveBaseUrl } from "../config.js";
5
+ import { loadWaygraphConfig, resolveBaseUrl } from "../config.js";
6
6
  function takeFlagValue(argv, i, a, flag) {
7
7
  if (a.startsWith(flag + "=")) {
8
8
  return { value: a.slice(flag.length + 1), nextI: i };
@@ -323,6 +323,8 @@ export { resolveBaseUrl };
323
323
  * Call after applyRunFlags so explicit flags already won.
324
324
  */
325
325
  export async function applyDemoDefaults(projectDir) {
326
+ // Config first: its defaults (headed, autoNext, pace...) must land before the demo defaults below fill the same variables.
327
+ await loadWaygraphConfig(projectDir);
326
328
  if (process.env.WAYGRAPH_STEP === undefined)
327
329
  process.env.WAYGRAPH_STEP = "1";
328
330
  if (process.env.WAYGRAPH_STEP === "1" && process.env.WAYGRAPH_HEADED === undefined) {
package/dist/cli/usage.js CHANGED
@@ -186,13 +186,16 @@ Primary (less is more):
186
186
  has a trace - test report opens it.
187
187
 
188
188
  Also:
189
+ --config <name|file> (any command) use another config instead of waygraph.config.ts, e.g.
190
+ waygraph test --config staging (config/waygraph.staging.config.ts)
189
191
  --env <mode> (any command) load .env.<mode> / .env.<mode>.local on top of .env, e.g.
190
192
  waygraph test --env staging (default: NODE_ENV, else development)
191
- waygraph upgrade [project] [paths...] [--apply] [--overwrite] [--diff]
193
+ waygraph upgrade [project] [paths...] [--apply] [--overwrite] [--diff] [--skills]
192
194
  Compare a project with the scaffold in this waygraph:
193
195
  lists new and differing files and a stale waygraph
194
196
  dependency. Dry run unless --apply; only the paths you
195
197
  name are copied, differing files only with --overwrite.
198
+ --skills refreshes .agents/skills to this waygraph's.
196
199
  waygraph extensions install [project] [--update]
197
200
  Download the browser extensions listed in
198
201
  waygraph.config.* (extensions: ["hoppscotch"]) into
package/dist/cli.js CHANGED
@@ -16,6 +16,7 @@
16
16
  */
17
17
  import { SKILL_FLAG_MAP, printSkillIndex, readSkillMarkdown } from "./commands/agent-dive-scaffold.js";
18
18
  import { takeEnvFlag } from "./env-file.js";
19
+ import { takeConfigFlag } from "./config.js";
19
20
  import { usage } from "./cli/usage.js";
20
21
  import { listCase, navCase } from "./commands/list.js";
21
22
  import { checkCase, typecheckCase, validateCase } from "./commands/check.js";
@@ -29,8 +30,10 @@ import { tryCase } from "./commands/try.js";
29
30
  import { upgradeCase } from "./commands/upgrade.js";
30
31
  import { extensionsCase } from "./commands/extensions.js";
31
32
  import { mapCase } from "./commands/map.js";
32
- const args = takeEnvFlag(process.argv.slice(2));
33
+ const args = takeConfigFlag(takeEnvFlag(process.argv.slice(2)));
33
34
  const command = args[0];
35
+ if (command)
36
+ process.env.WAYGRAPH_COMMAND = command;
34
37
  async function main() {
35
38
  if (!command || command === "--help" || command === "-h") {
36
39
  usage();
@@ -1,24 +1,4 @@
1
1
  export type AgentDiveLoop = "claude" | "opencode" | "cursor" | "vscode";
2
- export interface AgentSpec {
3
- name: string;
4
- description: string;
5
- model?: string;
6
- color?: string;
7
- tools: string[];
8
- instructions: string;
9
- }
10
- /** Minimal YAML-ish frontmatter parser for `*.agent.md` templates. */
11
- export declare function parseAgentSpec(filePath: string): AgentSpec;
12
- export declare function loadAgentSpecs(): AgentSpec[];
13
- /**
14
- * Claude Code Skills (`.claude/skills/<name>/SKILL.md`) - a different
15
- * mechanism than the agent persona files above: loadable instructions
16
- * triggered by task shape, not a persona. Claude-Code-specific (no
17
- * equivalent in the opencode/cursor/vscode loops), additive to the
18
- * `claude` loop only. Reuses the same `name: .../description: ...` +
19
- * body frontmatter shape `parseAgentSpec` already parses.
20
- */
21
- export declare function loadSkillSpecs(): AgentSpec[];
22
2
  /** CLI flag -> packaged skill file stem (under templates/skills/). */
23
3
  export declare const SKILL_FLAG_MAP: {
24
4
  readonly "--skill-pilot": "waygraph-pilot";
@@ -16,7 +16,7 @@ function skillsTemplateDir() {
16
16
  return join(packageRoot(), "templates", "skills");
17
17
  }
18
18
  /** Minimal YAML-ish frontmatter parser for `*.agent.md` templates. */
19
- export function parseAgentSpec(filePath) {
19
+ function parseAgentSpec(filePath) {
20
20
  const raw = readFileSync(filePath, "utf-8");
21
21
  if (!raw.startsWith("---\n")) {
22
22
  throw new Error(`agent-dive: missing frontmatter in ${filePath}`);
@@ -58,7 +58,7 @@ export function parseAgentSpec(filePath) {
58
58
  instructions: body,
59
59
  };
60
60
  }
61
- export function loadAgentSpecs() {
61
+ function loadAgentSpecs() {
62
62
  const dir = agentsTemplateDir();
63
63
  if (!existsSync(dir)) {
64
64
  throw new Error(`agent-dive: templates missing at ${dir}`);
@@ -76,7 +76,7 @@ export function loadAgentSpecs() {
76
76
  * `claude` loop only. Reuses the same `name: .../description: ...` +
77
77
  * body frontmatter shape `parseAgentSpec` already parses.
78
78
  */
79
- export function loadSkillSpecs() {
79
+ function loadSkillSpecs() {
80
80
  const dir = skillsTemplateDir();
81
81
  if (!existsSync(dir))
82
82
  return [];
@@ -85,7 +85,7 @@ function initCommand(projectName) {
85
85
  console.log(" waygraph typecheck # tsc --noEmit + bad-practice warnings (use --no-practices to skip)");
86
86
  console.log(" waygraph auto # interactive explore (headed panel)");
87
87
  console.log(" waygraph auto --cli # same menus in the terminal");
88
- console.log(" waygraph demo --blocks exampleFlow");
88
+ console.log(" waygraph demo --blocks homeHelloFlow");
89
89
  console.log(" waygraph graph # static state graph JSON");
90
90
  console.log(" .agents/skills/ # waygraph skills for coding agents (waygraph agent-dive adds agent personas)");
91
91
  console.log("");
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `waygraph upgrade [project] [paths...] [--apply] [--overwrite] [--diff]`
2
+ * `waygraph upgrade [project] [paths...] [--apply] [--overwrite] [--diff] [--skills]`
3
3
  * Compares the project with the scaffold shipped in this waygraph. Dry run by default.
4
4
  * Only the paths you name are copied, because a real project deliberately drops parts of the demo.
5
5
  */
@@ -21,13 +21,19 @@ const isOlder = (a, b) => {
21
21
  return false;
22
22
  };
23
23
  /**
24
- * `waygraph upgrade [project] [paths...] [--apply] [--overwrite] [--diff]`
24
+ * `waygraph upgrade [project] [paths...] [--apply] [--overwrite] [--diff] [--skills]`
25
25
  * Compares the project with the scaffold shipped in this waygraph. Dry run by default.
26
26
  * Only the paths you name are copied, because a real project deliberately drops parts of the demo.
27
27
  */
28
28
  export async function upgradeCase(args) {
29
29
  const flags = new Set(args.filter((a) => a.startsWith("--")));
30
30
  const positional = args.slice(1).filter((a) => !a.startsWith("--"));
31
+ // --skills: the agent skills are waygraph's own text, never edited by a project, so refresh them in place.
32
+ if (flags.has("--skills")) {
33
+ flags.add("--apply");
34
+ flags.add("--overwrite");
35
+ positional.push(".agents/skills");
36
+ }
31
37
  const first = positional[0];
32
38
  const hasProject = first !== undefined && existsSync(join(resolve(first), "package.json"));
33
39
  const proj = resolve(hasProject ? first : process.cwd());
package/dist/config.d.ts CHANGED
@@ -1,29 +1,60 @@
1
1
  import type { PlaywrightTestConfig } from "@playwright/test";
2
2
  import type { ExtensionSpec } from "./extensions.js";
3
3
  import type { WebServerConfig } from "./webserver.js";
4
+ import type { DemoPace } from "./highlights.js";
5
+ export interface VideoSettings {
6
+ /** Where recordings are saved: absolute, `~/…`, or relative to the project. Default `~/Downloads/waygraph-videos/<project>` (the project's `.waygraph-videos/` where there is no Downloads folder, and on CI). */
7
+ dir?: string;
8
+ /** Recording size, e.g. `"1920x1080"` (demo default) or `"1280x720"` (run default). */
9
+ viewport?: string;
10
+ }
11
+ /** Settings `waygraph run` and `waygraph demo` share. */
12
+ export interface RunSettings {
13
+ /** Show the browser window. */
14
+ headed?: boolean;
15
+ /**
16
+ * `run`: Playwright's `slowMo`, ms before every operation. `demo`: waygraph's own pause after each action (default 350),
17
+ * applied once per action rather than per keystroke, and removed by a step's `pace: "blitz"`.
18
+ */
19
+ slowMo?: number;
20
+ video?: VideoSettings;
21
+ }
22
+ /** Settings for `waygraph demo`. */
23
+ export interface DemoSettings extends RunSettings {
24
+ /** Default pace for flows and steps that set none: `"fast"`, `"slow"`, `"blitz"`, or a multiplier like `0.5` / `2`. Narration gates and dwell scale with it; `"blitz"` also skips typing animation. */
25
+ pace?: DemoPace;
26
+ /**
27
+ * What the named paces mean, as multipliers of normal dwell and gate time (1 = normal): blitz 0.05, fast 0.33, slow 2 by
28
+ * default. Lower is faster. `blitz` also skips the cursor, ring pops and typing animation.
29
+ * @example speeds: { fast: 0.5, blitz: 0.1 }
30
+ */
31
+ speeds?: {
32
+ blitz?: number;
33
+ fast?: number;
34
+ slow?: number;
35
+ };
36
+ /** Typing animation: ms per character (default 30). `0` types instantly. */
37
+ typingMs?: number;
38
+ /** Advance steps automatically instead of waiting for Next. */
39
+ autoNext?: boolean;
40
+ /** Shorter Next / auto-next gates; keeps the cursor and typing animation. */
41
+ fast?: boolean;
42
+ }
4
43
  export interface WaygraphConfig {
5
44
  /** Same value `resolveBaseUrl` would otherwise read from package.json's `waygraph.baseUrl`. */
6
45
  baseUrl?: string;
7
46
  /** Chromium extensions to load in every run: `"hoppscotch"`, a Chrome Web Store id, or `{ path }` to an unpacked one. */
8
47
  extensions?: ExtensionSpec[];
9
- /** Recording with `--video` (`waygraph run` / `demo`). */
10
- video?: {
11
- /** Where recordings are saved: absolute, `~/…`, or relative to the project. Default `~/Downloads/waygraph-videos/<project>` (the project's `.waygraph-videos/` where there is no Downloads folder, and on CI). */
12
- dir?: string;
13
- /** Recording size, e.g. `"1920x1080"` (demo default) or `"1280x720"` (run default). */
14
- viewport?: string;
15
- };
16
- /** Milliseconds to pause before each browser action in `run` / `demo`, to make it watchable. */
48
+ /** Recording with `--video` (`waygraph run` / `demo`); `run` and `demo` below can override it. */
49
+ video?: VideoSettings;
50
+ /** Default for `run` and `demo`: milliseconds to pause around each browser action, so a run is watchable. */
17
51
  slowMo?: number;
18
- /** Show the browser window. Default: `demo` and `auto` are headed, `run` is headless. */
52
+ /** Default for `run` and `demo`: show the browser window. Without it `demo` and `auto` are headed and `run` is headless. */
19
53
  headed?: boolean;
20
- /** `waygraph demo` defaults. */
21
- demo?: {
22
- /** Advance steps automatically instead of waiting for Next. */
23
- autoNext?: boolean;
24
- /** Blitz through fast-forward steps. */
25
- fast?: boolean;
26
- };
54
+ /** Settings for `waygraph run` only. They override the shared ones above. */
55
+ run?: RunSettings;
56
+ /** Settings for `waygraph demo` only. They override the shared ones above. */
57
+ demo?: DemoSettings;
27
58
  /** Folder of test files, relative to the project. Default `"tests"`. */
28
59
  testDir?: string;
29
60
  /** App to start around `waygraph test`, `run`, `demo` and `auto` (same fields as Playwright's `webServer`). */
@@ -42,6 +73,8 @@ export interface ConfigContext {
42
73
  * @example export default defineConfig(({ env }) => ({ baseUrl: env.BASE_URL }))
43
74
  */
44
75
  export declare function defineConfig(config: WaygraphConfig | ((context: ConfigContext) => WaygraphConfig)): WaygraphConfig;
76
+ /** Removes `--config <file>` / `--config=<file>` from argv and records it as `WAYGRAPH_CONFIG`, so every command reads that config. */
77
+ export declare function takeConfigFlag(argv: string[]): string[];
45
78
  /**
46
79
  * Looks for the first `waygraph.config.*` in `projectDir` and imports it - `.ts` works
47
80
  * unmodified because `bin/waygraph` already registers `tsx/esm` before `dist/cli.js` ever runs
@@ -72,7 +105,8 @@ export declare function resolveBaseUrl(projectDir: string): Promise<string | und
72
105
  /** Unpacked extension directories for a run: `WAYGRAPH_EXTENSIONS` if set, else the config file's `extensions` (fetched on first use). */
73
106
  export declare function configuredExtensions(projectDir: string): Promise<string[]>;
74
107
  /**
75
- * Applies the config's run settings as the `WAYGRAPH_*` variables the runner reads. A flag, a shell variable or a `.env`
76
- * value that is already set always wins, so the config only supplies defaults.
108
+ * Applies the config's run settings as the `WAYGRAPH_*` variables the runner reads, for the command being run
109
+ * (`WAYGRAPH_COMMAND`, set by the CLI). The `run` / `demo` section overrides the shared top-level values. A flag, a shell
110
+ * variable or a `.env` value that is already set always wins, so the config only supplies defaults.
77
111
  */
78
- export declare function applyConfigEnv(config: WaygraphConfig | undefined): void;
112
+ export declare function applyConfigEnv(config: WaygraphConfig | undefined, command?: string | undefined): void;
package/dist/config.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // setting, for consumers who'd rather have a real typed file than a JSON field. Real ask: "I
4
4
  // think its time to add waygraph config now."
5
5
  import { existsSync, readFileSync } from "node:fs";
6
- import { join } from "node:path";
6
+ import { isAbsolute, join } from "node:path";
7
7
  import { pathToFileURL } from "node:url";
8
8
  import { extensionPathsFromEnv } from "./browser.js";
9
9
  import { envMode, loadEnvFiles } from "./env-file.js";
@@ -22,6 +22,33 @@ export function defineConfig(config) {
22
22
  const CONFIG_NAMES = ["waygraph.config.ts", "waygraph.config.mts", "waygraph.config.mjs", "waygraph.config.js", "waygraph.config.cjs"];
23
23
  /** `config/` first, then the project root. */
24
24
  const CONFIG_FILENAMES = [...CONFIG_NAMES.map((n) => join("config", n)), ...CONFIG_NAMES];
25
+ /**
26
+ * Which config file(s) to try. `--config <file>` / `WAYGRAPH_CONFIG` picks one: a path (`config/staging.ts`), or a short name
27
+ * (`staging` -> `config/waygraph.staging.config.ts`, also tried in the project root). Without it, `waygraph.config.*`.
28
+ */
29
+ function configCandidates() {
30
+ const chosen = process.env.WAYGRAPH_CONFIG;
31
+ if (!chosen)
32
+ return CONFIG_FILENAMES;
33
+ if (/[\\/]/.test(chosen) || /\.[cm]?[jt]s$/.test(chosen))
34
+ return [chosen];
35
+ const names = ["ts", "mts", "mjs", "js", "cjs"].map((e) => `waygraph.${chosen}.config.${e}`);
36
+ return [...names.map((n) => join("config", n)), ...names, chosen];
37
+ }
38
+ /** Removes `--config <file>` / `--config=<file>` from argv and records it as `WAYGRAPH_CONFIG`, so every command reads that config. */
39
+ export function takeConfigFlag(argv) {
40
+ const out = [];
41
+ for (let i = 0; i < argv.length; i++) {
42
+ const a = argv[i];
43
+ if (a === "--config" && argv[i + 1] !== undefined)
44
+ process.env.WAYGRAPH_CONFIG = argv[++i];
45
+ else if (a.startsWith("--config="))
46
+ process.env.WAYGRAPH_CONFIG = a.slice("--config=".length);
47
+ else
48
+ out.push(a);
49
+ }
50
+ return out;
51
+ }
25
52
  /**
26
53
  * Looks for the first `waygraph.config.*` in `projectDir` and imports it - `.ts` works
27
54
  * unmodified because `bin/waygraph` already registers `tsx/esm` before `dist/cli.js` ever runs
@@ -32,10 +59,14 @@ const CONFIG_FILENAMES = [...CONFIG_NAMES.map((n) => join("config", n)), ...CONF
32
59
  */
33
60
  export async function loadWaygraphConfig(projectDir) {
34
61
  loadEnvFiles(projectDir);
35
- for (const name of CONFIG_FILENAMES) {
36
- const p = join(projectDir, name);
37
- if (!existsSync(p))
62
+ for (const name of configCandidates()) {
63
+ const p = isAbsolute(name) ? name : join(projectDir, name);
64
+ if (!existsSync(p)) {
65
+ if (process.env.WAYGRAPH_CONFIG && name === process.env.WAYGRAPH_CONFIG) {
66
+ throw new Error(`waygraph: config "${process.env.WAYGRAPH_CONFIG}" not found (looked for ${p})`);
67
+ }
38
68
  continue;
69
+ }
39
70
  let mod;
40
71
  try {
41
72
  mod = (await import(pathToFileURL(p).href));
@@ -108,20 +139,31 @@ export async function configuredExtensions(projectDir) {
108
139
  return resolveExtensions((await loadWaygraphConfig(projectDir))?.extensions, projectDir);
109
140
  }
110
141
  /**
111
- * Applies the config's run settings as the `WAYGRAPH_*` variables the runner reads. A flag, a shell variable or a `.env`
112
- * value that is already set always wins, so the config only supplies defaults.
142
+ * Applies the config's run settings as the `WAYGRAPH_*` variables the runner reads, for the command being run
143
+ * (`WAYGRAPH_COMMAND`, set by the CLI). The `run` / `demo` section overrides the shared top-level values. A flag, a shell
144
+ * variable or a `.env` value that is already set always wins, so the config only supplies defaults.
113
145
  */
114
- export function applyConfigEnv(config) {
146
+ export function applyConfigEnv(config, command = process.env.WAYGRAPH_COMMAND) {
115
147
  if (!config)
116
148
  return;
149
+ const isDemo = command === "demo" || command === "try";
150
+ const section = isDemo ? config.demo : command === "run" ? config.run : undefined;
117
151
  const set = (name, value) => {
118
152
  if (value !== undefined && process.env[name] === undefined)
119
153
  process.env[name] = value;
120
154
  };
121
- set("WAYGRAPH_VIDEO_DIR", config.video?.dir);
122
- set("WAYGRAPH_VIDEO_VIEWPORT", config.video?.viewport);
123
- set("WAYGRAPH_SLOWMO", config.slowMo === undefined ? undefined : String(config.slowMo));
124
- set("WAYGRAPH_HEADED", config.headed === undefined ? undefined : config.headed ? "1" : "0");
125
- set("WAYGRAPH_AUTOPLAY", config.demo?.autoNext === undefined ? undefined : config.demo.autoNext ? "1" : "0");
126
- set("WAYGRAPH_DEMO_FAST", config.demo?.fast ? "1" : undefined);
155
+ const flag = (b) => (b === undefined ? undefined : b ? "1" : "0");
156
+ const video = { ...config.video, ...section?.video };
157
+ const slowMo = section?.slowMo ?? config.slowMo;
158
+ set("WAYGRAPH_VIDEO_DIR", video.dir);
159
+ set("WAYGRAPH_VIDEO_VIEWPORT", video.viewport);
160
+ set("WAYGRAPH_SLOWMO", slowMo === undefined ? undefined : String(slowMo));
161
+ set("WAYGRAPH_HEADED", flag(section?.headed ?? config.headed));
162
+ if (isDemo) {
163
+ set("WAYGRAPH_AUTOPLAY", flag(config.demo?.autoNext));
164
+ set("WAYGRAPH_DEMO_FAST", config.demo?.fast ? "1" : undefined);
165
+ set("WAYGRAPH_DEMO_PACE", config.demo?.pace === undefined ? undefined : String(config.demo.pace));
166
+ set("WAYGRAPH_PACE_SPEEDS", config.demo?.speeds ? JSON.stringify(config.demo.speeds) : undefined);
167
+ set("WAYGRAPH_TYPING_MS", config.demo?.typingMs === undefined ? undefined : String(config.demo.typingMs));
168
+ }
127
169
  }
@@ -18,6 +18,8 @@ export declare function findBlockIndex(middle: readonly Block<any, any>[], block
18
18
  export declare function branch<In extends Checkpoint<string>, Out extends Checkpoint<string>>(block: Block<In, Out>, routes: {
19
19
  [K in Out["__state"]]: Block<Extract<Out, Checkpoint<K>>, any> | null;
20
20
  }): DefinedBlock<In, any>;
21
+ /** Copy non-enumerable waygraph markers so decorate/withVerify keep map() kind checks. */
22
+ export declare function copyWaygraphRuntime(from: object, to: object): void;
21
23
  /**
22
24
  * Builds a Block with `withVerify`/`modVerify`/`modVerifyAll` attached as
23
25
  * methods - `LoginBlock.withVerify([...])`, discoverable by typing
@@ -60,11 +62,14 @@ type StubPhaseFn<Out extends Checkpoint<string>> = import("../highlights.js").Hi
60
62
  * Attach / chain a stubBefore lifecycle on a Block. Prefer
61
63
  * `(ctx) => { ctx.ring(...); const x = ctx.mem?.get(Key); }`.
62
64
  * @example FillUsernameBlock.stubBefore((ctx) => { ctx.ring("username", { ... }) })
65
+ * @deprecated Use the chained method: `Block.stubBefore((ctx) => …)`.
63
66
  */
64
67
  export declare function withStubBefore<B extends Block<any, any>>(block: B, stub: StubPhaseFn<any>): B;
65
- /** @see {@link withStubBefore} */
68
+ /** @see {@link withStubBefore} * @deprecated Use the chained method: `Block.stubAfter((ctx) => …)`.
69
+ */
66
70
  export declare function withStubAfter<B extends Block<any, any>>(block: B, stub: StubPhaseFn<any>): B;
67
- /** @see {@link withStubBefore} */
71
+ /** @see {@link withStubBefore} * @deprecated Use the chained method: `Block.stubOnError((ctx) => …)`.
72
+ */
68
73
  export declare function withStubOnError<B extends Block<any, any>>(block: B, stub: StubPhaseFn<any>): B;
69
74
  /**
70
75
  * Answers the browser's own dialog (`confirm`, `alert`, `prompt`, `beforeunload`) that this Block's action
@@ -75,12 +75,13 @@ function stripMethods(block) {
75
75
  };
76
76
  }
77
77
  /** Copy non-enumerable waygraph markers so decorate/withVerify keep map() kind checks. */
78
- function copyWaygraphRuntime(from, to) {
78
+ export function copyWaygraphRuntime(from, to) {
79
79
  for (const key of [
80
80
  "__waygraphKind",
81
81
  "__waygraphSalt",
82
82
  "__waygraphNavUrl",
83
83
  "__waygraphNavClick",
84
+ "__waygraphNavFrom",
84
85
  ]) {
85
86
  const desc = Object.getOwnPropertyDescriptor(from, key);
86
87
  if (!desc)
@@ -201,15 +202,18 @@ function withStubPhase(block, phase, stub) {
201
202
  * Attach / chain a stubBefore lifecycle on a Block. Prefer
202
203
  * `(ctx) => { ctx.ring(...); const x = ctx.mem?.get(Key); }`.
203
204
  * @example FillUsernameBlock.stubBefore((ctx) => { ctx.ring("username", { ... }) })
205
+ * @deprecated Use the chained method: `Block.stubBefore((ctx) => …)`.
204
206
  */
205
207
  export function withStubBefore(block, stub) {
206
208
  return withStubPhase(block, "stubBefore", stub);
207
209
  }
208
- /** @see {@link withStubBefore} */
210
+ /** @see {@link withStubBefore} * @deprecated Use the chained method: `Block.stubAfter((ctx) => …)`.
211
+ */
209
212
  export function withStubAfter(block, stub) {
210
213
  return withStubPhase(block, "stubAfter", stub);
211
214
  }
212
- /** @see {@link withStubBefore} */
215
+ /** @see {@link withStubBefore} * @deprecated Use the chained method: `Block.stubOnError((ctx) => …)`.
216
+ */
213
217
  export function withStubOnError(block, stub) {
214
218
  return withStubPhase(block, "stubOnError", stub);
215
219
  }
@@ -16,6 +16,8 @@ export declare class Engine {
16
16
  private readonly config;
17
17
  constructor(config?: EngineConfig);
18
18
  /**
19
+ * @deprecated Build flows with `engine.map()`, which checks each step's Block kind and nests flows with `.flow()`.
20
+ *
19
21
  * Builds a runnable {@link Flow} from `[start, ...Blocks, end]`, typechecked
20
22
  * so each Block's `In` must match the previous Block's `Out` - the same
21
23
  * check `connect()` does, just declared as a flat array instead of hand-nested
@@ -36,7 +36,9 @@ export class Engine {
36
36
  * .end();
37
37
  */
38
38
  map(options) {
39
- return MapBuilder.begin(this.defineFlow.bind(this), options?.homeOrigin);
39
+ const { homeOrigin, ...flowOptions } = options ?? {};
40
+ const define = this.defineFlow.bind(this);
41
+ return MapBuilder.begin((blocks, extra) => define(blocks, { ...flowOptions, ...extra }), homeOrigin);
40
42
  }
41
43
  }
42
44
  /**
@@ -176,6 +176,7 @@ export declare function buildFlow<Out extends Checkpoint<string>>(middle: readon
176
176
  * exactly as if a human had opened the app fresh, not wherever the
177
177
  * previous Flow in the chain happened to leave the page.
178
178
  * @example const loginFlow = withSessionReset(engine.defineFlow([start, LoginBlock, end]));
179
+ * @deprecated Use `map().flow(sub, { reset: true })`; the reset belongs to where flows are joined.
179
180
  */
180
181
  export declare function withSessionReset<Out extends Checkpoint<string>>(flow: Flow<Out>): Flow<Out>;
181
182
  /**
@@ -184,6 +185,7 @@ export declare function withSessionReset<Out extends Checkpoint<string>>(flow: F
184
185
  * Blocks are executing, instead of one fixed title for the whole run.
185
186
  * Non-destructive, same pattern as {@link withSessionReset}.
186
187
  * @example const ticket123 = withTitle(loginFlow, "Ticket #123 - Sales rep signs in");
188
+ * @deprecated Name a flow with `ctx.title(...)` in a stub on its first step.
187
189
  */
188
190
  export declare function withTitle<Out extends Checkpoint<string>>(flow: Flow<Out>, title: string): Flow<Out>;
189
191
  /**
@@ -195,6 +197,7 @@ export declare function withTitle<Out extends Checkpoint<string>>(flow: Flow<Out
195
197
  * this itself - the CLI's `--data`/`--mem-stub` seeding, or a bare-library
196
198
  * caller's own explicit `seedMemStub(mem, flow)` call, does the filling.
197
199
  * @example const demoLogin = withMemStub(loginFlow);
200
+ * @deprecated Use `engine.map({ memStub: true })`.
198
201
  */
199
202
  export declare function withMemStub<Out extends Checkpoint<string>>(flow: Flow<Out>): Flow<Out>;
200
203
  /**
@@ -205,17 +208,20 @@ export declare function withMemStub<Out extends Checkpoint<string>>(flow: Flow<O
205
208
  * @example withDemoPace(happyFlow, 0.5) // 2x faster than normal
206
209
  * @example withDemoPace(gapFlow, 2.5) // 2.5x slower
207
210
  * @example withDemoPace(gapFlow, 4500) // absolute ~4.5s gates/dwells
211
+ * @deprecated Use `engine.map({ demoPace })`, a step `{ pace }`, or `demo.pace` in the config.
208
212
  */
209
213
  export declare function withDemoPace<Out extends Checkpoint<string>>(flow: Flow<Out>, pace: DemoPace): Flow<Out>;
210
214
  /**
211
215
  * Default highlight look for a Flow episode (size / weight / optional tone).
212
216
  * Per-slot stub or {@link withHighlightFixtures} values win when set.
213
217
  * @example withHighlightStyle(withDemoPace(gapFlow, "slow"), { size: "lg", weight: "bold" })
218
+ * @deprecated Use `engine.map({ highlightStyle })`.
214
219
  */
215
220
  export declare function withHighlightStyle<Out extends Checkpoint<string>>(flow: Flow<Out>, style: HighlightStyleDefaults): Flow<Out>;
216
221
  /**
217
222
  * Demo pacing for one Block or compose unit (not FF - use fastForwardComposeBlock for blitz).
218
223
  * @example withBlockPace(composeBlock("gap-review", [...]), "slow")
224
+ * @deprecated Use a step option: `.method(Block, { pace })`.
219
225
  */
220
226
  export declare function withBlockPace<In extends Checkpoint<string>, Out extends Checkpoint<string>>(block: Block<In, Out>, pace: DemoPace): Block<In, Out>;
221
227
  /**
@@ -235,6 +241,7 @@ export declare function withBlockPace<In extends Checkpoint<string>, Out extends
235
241
  * engine.defineFlow([start, NavLoginBlock, SubmitLoginActionBlock, end]),
236
242
  * "locked_out_user stays on LoginPage with the error banner - working as intended.",
237
243
  * );
244
+ * @deprecated Use `engine.map({ expectedFailure: reason })`.
238
245
  */
239
246
  export declare function withExpectedFailure<Out extends Checkpoint<string>>(flow: Flow<Out>, reason: string): Flow<Out>;
240
247
  /**
@@ -243,6 +250,7 @@ export declare function withExpectedFailure<Out extends Checkpoint<string>>(flow
243
250
  * stubOnError slots. Non-destructive, same pattern as {@link withTitle}.
244
251
  * Demo/`chain --step` reads `flow.highlightFixtures`; `run()` ignores it.
245
252
  * @example withHighlightFixtures(issueFlow, { "submit-login": { stubBefore: { email: { label: "AC-1" } } } })
253
+ * @deprecated Chain ctx stubs on the Block: `Block.stubAfter((ctx) => …)`.
246
254
  */
247
255
  export declare function withHighlightFixtures<Out extends Checkpoint<string>>(flow: Flow<Out>, fixtures: import("../highlights.js").HighlightFixtureMap): Flow<Out>;
248
256
  /** Everything a `with*` wrapper can set, given up front: `engine.defineFlow([...], { title, memStub, ... })`. */
@@ -262,6 +270,7 @@ export interface FlowOptions {
262
270
  }
263
271
  /** Applies each set option through its `with*` wrapper, so both spellings produce the same Flow. */
264
272
  export declare function applyFlowOptions<Out extends Checkpoint<string>>(flow: Flow<Out>, options: FlowOptions | undefined): Flow<Out>;
273
+ export declare function clearSessionState(context: BrowserContext, page: Page): Promise<void>;
265
274
  /**
266
275
  * Runs several complete, independent Flows one after another, reusing the
267
276
  * same page/context/mem in order - each remains its own validated
@@ -279,5 +288,6 @@ export declare function applyFlowOptions<Out extends Checkpoint<string>>(flow: F
279
288
  * chain - nothing to reset yet). The combined result is whatever the LAST
280
289
  * flow resolved to.
281
290
  * @example chainFlow(ticket123Flow, ticket456Flow).run(context, mem)
291
+ * @deprecated Nest flows with `map().flow(a).flow(b, { reset: true })`.
282
292
  */
283
293
  export declare function chainFlow(...flows: readonly Flow<any>[]): Flow<any>;