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.
- package/README.md +8 -1
- package/dist/analysis/map-check.d.ts +3 -2
- package/dist/cli/flags.js +3 -1
- package/dist/cli/usage.js +4 -1
- package/dist/cli.js +4 -1
- package/dist/commands/agent-dive-scaffold.d.ts +0 -20
- package/dist/commands/agent-dive-scaffold.js +3 -3
- package/dist/commands/init.js +1 -1
- package/dist/commands/upgrade.d.ts +1 -1
- package/dist/commands/upgrade.js +7 -1
- package/dist/config.d.ts +53 -19
- package/dist/config.js +55 -13
- package/dist/core/block.d.ts +7 -2
- package/dist/core/block.js +7 -3
- package/dist/core/engine.d.ts +2 -0
- package/dist/core/engine.js +3 -1
- package/dist/core/flow.d.ts +10 -0
- package/dist/core/flow.js +32 -8
- package/dist/core/map-builder.d.ts +27 -1
- package/dist/core/map-builder.js +42 -4
- package/dist/highlights/demo-pace.d.ts +0 -1
- package/dist/highlights/demo-pace.js +24 -3
- package/dist/index.d.ts +2 -2
- package/dist/pilot-overlay/action-ring.d.ts +0 -9
- package/dist/pilot-overlay/action-ring.js +1 -1
- package/dist/pilot-overlay/panel.d.ts +2 -1
- package/dist/runner/interaction-patch.js +32 -1
- package/dist/runner/main.js +5 -2
- package/dist/runner/step-mode.js +10 -4
- package/dist/session/auto-explore.d.ts +2 -1
- package/dist/session/auto-session-ipc.d.ts +1 -2
- package/dist/session/auto-session-ipc.js +1 -1
- package/dist/session/block-inject.d.ts +0 -13
- package/dist/session/block-inject.js +3 -3
- package/dist/session/pilot.d.ts +0 -2
- package/dist/session/pilot.js +1 -2
- package/dist/traverse/coverage.d.ts +0 -4
- package/dist/traverse/coverage.js +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +11 -5
- package/templates/scaffold/README.md +1 -1
- package/templates/scaffold/STRUCTURE.md +5 -2
- package/templates/scaffold/config/waygraph.config.ts +24 -5
- package/templates/scaffold/package.json +6 -6
- package/templates/scaffold/src/flows/(external)/hoppscotch/auth.flow.ts +36 -0
- package/templates/scaffold/src/flows/(external)/hoppscotch/get.flow.ts +24 -0
- package/templates/scaffold/src/flows/(external)/hoppscotch/post.flow.ts +34 -0
- package/templates/scaffold/src/flows/(user-stories)/email-verification.flow.ts +47 -0
- package/templates/scaffold/src/flows/README.md +35 -14
- package/templates/scaffold/src/flows/{shop.flow.ts → home/cart.flow.ts} +18 -17
- package/templates/scaffold/src/flows/{example.flow.ts → home/hello.flow.ts} +12 -13
- package/templates/scaffold/tests/example.spec.ts +5 -5
- package/templates/scaffold/tests/hoppscotch.spec.ts +3 -3
- package/templates/scaffold/tests/mail-verify.spec.ts +7 -7
- package/templates/skills/waygraph-convention.skill.md +14 -6
- package/templates/scaffold/src/flows/hoppscotch-auth.flow.ts +0 -35
- package/templates/scaffold/src/flows/hoppscotch-get.flow.ts +0 -23
- package/templates/scaffold/src/flows/hoppscotch-post.flow.ts +0 -33
- 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
|
|
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
|
-
|
|
1
|
+
interface MapViolation {
|
|
2
2
|
file: string;
|
|
3
3
|
block: string;
|
|
4
4
|
reason: string;
|
|
5
5
|
}
|
|
6
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
79
|
+
function loadSkillSpecs() {
|
|
80
80
|
const dir = skillsTemplateDir();
|
|
81
81
|
if (!existsSync(dir))
|
|
82
82
|
return [];
|
package/dist/commands/init.js
CHANGED
|
@@ -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
|
|
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
|
*/
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
/**
|
|
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
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
|
76
|
-
*
|
|
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
|
|
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
|
|
112
|
-
*
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
set("
|
|
125
|
-
set("
|
|
126
|
-
set("
|
|
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
|
}
|
package/dist/core/block.d.ts
CHANGED
|
@@ -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
|
package/dist/core/block.js
CHANGED
|
@@ -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
|
}
|
package/dist/core/engine.d.ts
CHANGED
|
@@ -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
|
package/dist/core/engine.js
CHANGED
|
@@ -36,7 +36,9 @@ export class Engine {
|
|
|
36
36
|
* .end();
|
|
37
37
|
*/
|
|
38
38
|
map(options) {
|
|
39
|
-
|
|
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
|
/**
|
package/dist/core/flow.d.ts
CHANGED
|
@@ -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>;
|