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.
- package/README.md +8 -1
- package/dist/analysis/graph.d.ts +3 -0
- package/dist/analysis/map-check.d.ts +3 -2
- package/dist/auto-session/helpers.d.ts +10 -0
- package/dist/blocks-select.d.ts +3 -0
- package/dist/blocks-select.js +2 -0
- 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 +55 -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/blocks/api.d.ts +1 -0
- package/dist/core/blocks/method.d.ts +2 -0
- package/dist/core/blocks/method.js +1 -0
- package/dist/core/blocks/nav.d.ts +1 -0
- package/dist/core/blocks/page.d.ts +1 -0
- package/dist/core/branch-regression.d.ts +1 -0
- package/dist/core/compose.d.ts +1 -0
- package/dist/core/engine.d.ts +2 -0
- package/dist/core/engine.js +3 -1
- package/dist/core/flow.d.ts +11 -0
- package/dist/core/flow.js +32 -8
- package/dist/core/map-builder.d.ts +34 -1
- package/dist/core/map-builder.js +42 -4
- package/dist/core/run-graph.d.ts +2 -0
- package/dist/core/run-graph.js +1 -0
- package/dist/errors.d.ts +1 -0
- package/dist/extensions.d.ts +1 -0
- package/dist/extensions.js +1 -0
- package/dist/highlights/demo-pace.d.ts +4 -1
- package/dist/highlights/demo-pace.js +28 -3
- package/dist/highlights/device.d.ts +2 -0
- package/dist/highlights/device.js +2 -0
- package/dist/highlights/types.d.ts +6 -0
- 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-run.js +6 -0
- 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/overlay-beacon.d.ts +7 -0
- package/dist/session/overlay-beacon.js +5 -0
- package/dist/session/pilot.d.ts +1 -2
- package/dist/session/pilot.js +1 -2
- package/dist/traverse/coverage.d.ts +4 -4
- package/dist/traverse/coverage.js +4 -1
- package/dist/traverse/lease.d.ts +1 -0
- package/dist/traverse/lease.js +1 -0
- package/dist/traverse/run.d.ts +3 -0
- package/dist/types.d.ts +1 -1
- package/examples/routed-demo/src/flows/routed-demo-map.flow.ts +1 -1
- package/examples/routed-demo/src/flows/routed-demo.flow.ts +2 -2
- package/examples/saucedemo/README.md +11 -12
- package/examples/saucedemo/config/waygraph.config.ts +17 -0
- package/examples/saucedemo/docs/CONVENTION.md +1 -2
- package/examples/saucedemo/docs/HELPERS.md +1 -1
- package/examples/saucedemo/package-lock.json +10 -3
- package/examples/saucedemo/package.json +12 -29
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +0 -49
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +22 -25
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +0 -6
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +38 -96
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +1 -26
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +1 -45
- package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +14 -77
- package/examples/saucedemo/src/flows/api-demo.flow.ts +17 -11
- package/examples/saucedemo/src/flows/cart-bulk.flow.ts +19 -14
- package/examples/saucedemo/src/flows/cart-continue.flow.ts +10 -8
- package/examples/saucedemo/src/flows/cart-mem.flow.ts +7 -7
- package/examples/saucedemo/src/flows/catalog-logout.flow.ts +13 -8
- package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +26 -48
- package/examples/saucedemo/src/flows/checkout.flow.ts +70 -86
- package/examples/saucedemo/src/flows/device-showcase.flow.ts +24 -25
- package/examples/saucedemo/src/flows/login.flow.ts +11 -18
- package/examples/saucedemo/src/flows/mem-stub-demo.flow.ts +9 -20
- package/examples/saucedemo/src/flows/shop.flow.ts +15 -20
- package/examples/saucedemo/src/flows/smoke.flow.ts +12 -27
- package/examples/saucedemo/src/flows/stub-on-error.flow.ts +24 -43
- package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +26 -34
- package/examples/saucedemo/src/states/checkout.mem-stubs.ts +11 -0
- package/examples/saucedemo/src/stubs/device-showcase.ts +193 -0
- package/examples/saucedemo/src/stubs/login.ts +37 -0
- package/examples/saucedemo/tests/chain-flow-episodes.spec.ts +7 -9
- package/examples/saucedemo/tests/submit-login-branch.spec.ts +18 -5
- package/package.json +12 -5
- package/templates/quickstart/README.md +4 -7
- package/templates/quickstart/config/waygraph.config.ts +17 -0
- package/templates/quickstart/docs/CONVENTION.md +1 -2
- package/templates/quickstart/docs/HELPERS.md +1 -1
- package/templates/quickstart/package.json +14 -14
- package/templates/quickstart/src/blocks/SITE-MAP.md +14 -3
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +0 -49
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +22 -25
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +0 -6
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +38 -96
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +1 -26
- package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +1 -45
- package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +14 -77
- package/templates/quickstart/src/flows/api-demo.flow.ts +43 -0
- package/templates/quickstart/src/flows/cart-bulk.flow.ts +19 -14
- package/templates/quickstart/src/flows/cart-continue.flow.ts +10 -8
- package/templates/quickstart/src/flows/cart-mem.flow.ts +7 -7
- package/templates/quickstart/src/flows/catalog-logout.flow.ts +13 -8
- package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +26 -48
- package/templates/quickstart/src/flows/checkout.flow.ts +70 -63
- package/templates/quickstart/src/flows/device-showcase.flow.ts +24 -25
- package/templates/quickstart/src/flows/login.flow.ts +11 -18
- package/templates/quickstart/src/flows/mem-stub-demo.flow.ts +12 -0
- package/templates/quickstart/src/flows/shop.flow.ts +15 -20
- package/templates/quickstart/src/flows/smoke.flow.ts +12 -27
- package/templates/quickstart/src/flows/stub-on-error.flow.ts +31 -0
- package/templates/quickstart/src/flows/viewer-blocked.flow.ts +26 -34
- package/templates/quickstart/src/states/checkout.mem-stubs.ts +11 -0
- package/templates/quickstart/src/stubs/device-showcase.ts +193 -0
- package/templates/quickstart/src/stubs/login.ts +37 -0
- package/templates/quickstart/tests/chain-flow.spec.ts +7 -10
- package/templates/scaffold/README.md +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/examples/saucedemo/playwright.config.ts +0 -19
- package/examples/saucedemo/scripts/drive-auto-cli.mjs +0 -93
- package/examples/saucedemo/scripts/prove-add-to-cart-menu.mjs +0 -126
- package/examples/saucedemo/scripts/prove-auto-graph.mjs +0 -92
- package/examples/saucedemo/scripts/prove-wrong-login-runtime.mjs +0 -63
- package/templates/quickstart/playwright.config.ts +0 -14
- package/templates/quickstart/scripts/drive-auto-cli.mjs +0 -93
- 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
|
package/dist/analysis/graph.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { type BlocksSelect } from "../blocks-select.js";
|
|
|
8
8
|
export interface WaygraphNode {
|
|
9
9
|
checkpoint: string;
|
|
10
10
|
}
|
|
11
|
+
/** A move in the graph: a Block from one Checkpoint tag to another. */
|
|
11
12
|
export interface WaygraphEdge {
|
|
12
13
|
/** The Block's own runtime `.name`. */
|
|
13
14
|
block: string;
|
|
@@ -18,11 +19,13 @@ export interface WaygraphEdge {
|
|
|
18
19
|
to: string;
|
|
19
20
|
kind: "nav" | "action";
|
|
20
21
|
}
|
|
22
|
+
/** A Block `waygraph graph` found but could not place in the graph, with the reason. */
|
|
21
23
|
export interface SkippedBlock {
|
|
22
24
|
block: string;
|
|
23
25
|
file: string;
|
|
24
26
|
reason: string;
|
|
25
27
|
}
|
|
28
|
+
/** The static graph of a project: Checkpoint nodes, Block edges, skipped and orphan Blocks. */
|
|
26
29
|
export interface WaygraphGraph {
|
|
27
30
|
nodes: WaygraphNode[];
|
|
28
31
|
edges: WaygraphEdge[];
|
|
@@ -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 {};
|
|
@@ -3,6 +3,7 @@ import type { BlockEntry, ExploreMenu } from "../session/auto-explore.js";
|
|
|
3
3
|
import type { PickResult } from "../session/auto-explore-run.js";
|
|
4
4
|
/** True when a stub-phase result actually carries authored content worth keeping. */
|
|
5
5
|
export declare function stubPhaseHasContent(r: StubPhaseResult): boolean;
|
|
6
|
+
/** One available move in a session snapshot: a Block and the Checkpoint it leads to. */
|
|
6
7
|
export interface SessionSnapshotEdge {
|
|
7
8
|
/** 1-based, matching the numbers a human/agent picks by (same as printCliMenu). */
|
|
8
9
|
index: number;
|
|
@@ -12,10 +13,12 @@ export interface SessionSnapshotEdge {
|
|
|
12
13
|
label?: string;
|
|
13
14
|
description?: string;
|
|
14
15
|
}
|
|
16
|
+
/** A group of moves in a session snapshot, by page. */
|
|
15
17
|
export interface SessionSnapshotSection {
|
|
16
18
|
title: string;
|
|
17
19
|
edges: SessionSnapshotEdge[];
|
|
18
20
|
}
|
|
21
|
+
/** The state of a live session: where it is, the moves available from there, and the trace so far. */
|
|
19
22
|
export interface SessionSnapshot {
|
|
20
23
|
here: string | null;
|
|
21
24
|
sections: SessionSnapshotSection[];
|
|
@@ -82,6 +85,7 @@ export declare function walkFullDom(root: Element, caps: FullDomCaps): {
|
|
|
82
85
|
tree: FullDomNode;
|
|
83
86
|
truncated: boolean;
|
|
84
87
|
};
|
|
88
|
+
/** What `AutoSession.start` needs: project, selection, headless mode and the session id. */
|
|
85
89
|
export interface AutoSessionInit {
|
|
86
90
|
projectDir: string;
|
|
87
91
|
baseURL?: string;
|
|
@@ -102,6 +106,7 @@ export interface AutoSessionInit {
|
|
|
102
106
|
*/
|
|
103
107
|
sessionId?: string;
|
|
104
108
|
}
|
|
109
|
+
/** The result of running one menu pick in a live session. */
|
|
105
110
|
export type ApplyPickResult = {
|
|
106
111
|
ok: true;
|
|
107
112
|
snapshot: SessionSnapshot;
|
|
@@ -110,6 +115,7 @@ export type ApplyPickResult = {
|
|
|
110
115
|
ok: false;
|
|
111
116
|
error: string;
|
|
112
117
|
};
|
|
118
|
+
/** The result of running a multi-step route in a live session. */
|
|
113
119
|
export type ApplyPathResult = {
|
|
114
120
|
ok: true;
|
|
115
121
|
path: string[];
|
|
@@ -141,6 +147,7 @@ export interface TraceStep {
|
|
|
141
147
|
stubOnError?: StubPhaseResult;
|
|
142
148
|
}
|
|
143
149
|
export declare const TRACE_MAX_STEPS = 500;
|
|
150
|
+
/** Which stub file a live session wrote: before, after or on-error. */
|
|
144
151
|
export type StubFileKind = "image" | "pdf" | "video";
|
|
145
152
|
/**
|
|
146
153
|
* Real, minimal, valid fixture files bundled at `assets/stubs/` - not
|
|
@@ -180,11 +187,13 @@ export interface ConsoleLogEntry {
|
|
|
180
187
|
timestamp: string;
|
|
181
188
|
}
|
|
182
189
|
export declare const CONSOLE_LOG_MAX_ENTRIES = 200;
|
|
190
|
+
/** One service worker registration as reported by a live session. */
|
|
183
191
|
export interface ServiceWorkerRegistrationInfo {
|
|
184
192
|
scope: string;
|
|
185
193
|
activeUrl?: string;
|
|
186
194
|
state?: string;
|
|
187
195
|
}
|
|
196
|
+
/** One cookie as reported by a live session's `auto cookies`. */
|
|
188
197
|
export interface CookieInfo {
|
|
189
198
|
name: string;
|
|
190
199
|
value: string;
|
|
@@ -193,6 +202,7 @@ export interface CookieInfo {
|
|
|
193
202
|
httpOnly: boolean;
|
|
194
203
|
secure: boolean;
|
|
195
204
|
}
|
|
205
|
+
/** Local and session storage of a live session's page. */
|
|
196
206
|
export interface StorageSnapshot {
|
|
197
207
|
localStorage: Record<string, string>;
|
|
198
208
|
sessionStorage: Record<string, string>;
|
package/dist/blocks-select.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* - otherwise -> bare token (flow export / checkpoint / block name) — caller decides
|
|
7
7
|
*/
|
|
8
8
|
export type BlocksSelectKind = "regex" | "glob" | "bare";
|
|
9
|
+
/** A parsed `--blocks` selector: which Blocks, by name, glob or file, a command should use. */
|
|
9
10
|
export interface BlocksSelect {
|
|
10
11
|
kind: BlocksSelectKind;
|
|
11
12
|
/** Original token. */
|
|
@@ -16,9 +17,11 @@ export interface BlocksSelect {
|
|
|
16
17
|
}
|
|
17
18
|
/** True when the token is file-select (glob/regex), not a bare flow/checkpoint name. */
|
|
18
19
|
export declare function isFileSelectToken(token: string): boolean;
|
|
20
|
+
/** Parses a `--blocks` argument into a selector. */
|
|
19
21
|
export declare function parseBlocksSelect(token: string): BlocksSelect;
|
|
20
22
|
/** Glob → RegExp (simple: ** / * / ? only; no brace expansion). */
|
|
21
23
|
export declare function globToRegExp(glob: string): RegExp;
|
|
24
|
+
/** True when a Block name and file match a parsed `--blocks` selector. */
|
|
22
25
|
export declare function matchBlocksSelect(select: BlocksSelect, opts: {
|
|
23
26
|
relFile: string;
|
|
24
27
|
blockName?: string;
|
package/dist/blocks-select.js
CHANGED
|
@@ -14,6 +14,7 @@ export function isFileSelectToken(token) {
|
|
|
14
14
|
}
|
|
15
15
|
return token.includes("*");
|
|
16
16
|
}
|
|
17
|
+
/** Parses a `--blocks` argument into a selector. */
|
|
17
18
|
export function parseBlocksSelect(token) {
|
|
18
19
|
const raw = token.trim();
|
|
19
20
|
if (raw.length >= 2 && raw.startsWith("/") && raw.endsWith("/")) {
|
|
@@ -52,6 +53,7 @@ export function globToRegExp(glob) {
|
|
|
52
53
|
}
|
|
53
54
|
return new RegExp("^" + out + "$");
|
|
54
55
|
}
|
|
56
|
+
/** True when a Block name and file match a parsed `--blocks` selector. */
|
|
55
57
|
export function matchBlocksSelect(select, opts) {
|
|
56
58
|
const file = opts.relFile.replace(/\\/g, "/");
|
|
57
59
|
const name = opts.blockName ?? "";
|
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,62 @@
|
|
|
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
|
+
/** Where `--video` recordings are saved and at what size. */
|
|
6
|
+
export interface VideoSettings {
|
|
7
|
+
/** 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). */
|
|
8
|
+
dir?: string;
|
|
9
|
+
/** Recording size, e.g. `"1920x1080"` (demo default) or `"1280x720"` (run default). */
|
|
10
|
+
viewport?: string;
|
|
11
|
+
}
|
|
12
|
+
/** Settings `waygraph run` and `waygraph demo` share. */
|
|
13
|
+
export interface RunSettings {
|
|
14
|
+
/** Show the browser window. */
|
|
15
|
+
headed?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* `run`: Playwright's `slowMo`, ms before every operation. `demo`: waygraph's own pause after each action (default 350),
|
|
18
|
+
* applied once per action rather than per keystroke, and removed by a step's `pace: "blitz"`.
|
|
19
|
+
*/
|
|
20
|
+
slowMo?: number;
|
|
21
|
+
video?: VideoSettings;
|
|
22
|
+
}
|
|
23
|
+
/** Settings for `waygraph demo`. */
|
|
24
|
+
export interface DemoSettings extends RunSettings {
|
|
25
|
+
/** 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. */
|
|
26
|
+
pace?: DemoPace;
|
|
27
|
+
/**
|
|
28
|
+
* What the named paces mean, as multipliers of normal dwell and gate time (1 = normal): blitz 0.05, fast 0.33, slow 2 by
|
|
29
|
+
* default. Lower is faster. `blitz` also skips the cursor, ring pops and typing animation.
|
|
30
|
+
* @example speeds: { fast: 0.5, blitz: 0.1 }
|
|
31
|
+
*/
|
|
32
|
+
speeds?: {
|
|
33
|
+
blitz?: number;
|
|
34
|
+
fast?: number;
|
|
35
|
+
slow?: number;
|
|
36
|
+
};
|
|
37
|
+
/** Typing animation: ms per character (default 30). `0` types instantly. */
|
|
38
|
+
typingMs?: number;
|
|
39
|
+
/** Advance steps automatically instead of waiting for Next. */
|
|
40
|
+
autoNext?: boolean;
|
|
41
|
+
/** Shorter Next / auto-next gates; keeps the cursor and typing animation. */
|
|
42
|
+
fast?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** The project config in `config/waygraph.config.ts`: base URL, extensions, run and demo settings, web server and the Playwright block. */
|
|
4
45
|
export interface WaygraphConfig {
|
|
5
46
|
/** Same value `resolveBaseUrl` would otherwise read from package.json's `waygraph.baseUrl`. */
|
|
6
47
|
baseUrl?: string;
|
|
7
48
|
/** Chromium extensions to load in every run: `"hoppscotch"`, a Chrome Web Store id, or `{ path }` to an unpacked one. */
|
|
8
49
|
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. */
|
|
50
|
+
/** Recording with `--video` (`waygraph run` / `demo`); `run` and `demo` below can override it. */
|
|
51
|
+
video?: VideoSettings;
|
|
52
|
+
/** Default for `run` and `demo`: milliseconds to pause around each browser action, so a run is watchable. */
|
|
17
53
|
slowMo?: number;
|
|
18
|
-
/**
|
|
54
|
+
/** Default for `run` and `demo`: show the browser window. Without it `demo` and `auto` are headed and `run` is headless. */
|
|
19
55
|
headed?: boolean;
|
|
20
|
-
/** `waygraph
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
/** Blitz through fast-forward steps. */
|
|
25
|
-
fast?: boolean;
|
|
26
|
-
};
|
|
56
|
+
/** Settings for `waygraph run` only. They override the shared ones above. */
|
|
57
|
+
run?: RunSettings;
|
|
58
|
+
/** Settings for `waygraph demo` only. They override the shared ones above. */
|
|
59
|
+
demo?: DemoSettings;
|
|
27
60
|
/** Folder of test files, relative to the project. Default `"tests"`. */
|
|
28
61
|
testDir?: string;
|
|
29
62
|
/** App to start around `waygraph test`, `run`, `demo` and `auto` (same fields as Playwright's `webServer`). */
|
|
@@ -42,6 +75,8 @@ export interface ConfigContext {
|
|
|
42
75
|
* @example export default defineConfig(({ env }) => ({ baseUrl: env.BASE_URL }))
|
|
43
76
|
*/
|
|
44
77
|
export declare function defineConfig(config: WaygraphConfig | ((context: ConfigContext) => WaygraphConfig)): WaygraphConfig;
|
|
78
|
+
/** Removes `--config <file>` / `--config=<file>` from argv and records it as `WAYGRAPH_CONFIG`, so every command reads that config. */
|
|
79
|
+
export declare function takeConfigFlag(argv: string[]): string[];
|
|
45
80
|
/**
|
|
46
81
|
* Looks for the first `waygraph.config.*` in `projectDir` and imports it - `.ts` works
|
|
47
82
|
* unmodified because `bin/waygraph` already registers `tsx/esm` before `dist/cli.js` ever runs
|
|
@@ -72,7 +107,8 @@ export declare function resolveBaseUrl(projectDir: string): Promise<string | und
|
|
|
72
107
|
/** Unpacked extension directories for a run: `WAYGRAPH_EXTENSIONS` if set, else the config file's `extensions` (fetched on first use). */
|
|
73
108
|
export declare function configuredExtensions(projectDir: string): Promise<string[]>;
|
|
74
109
|
/**
|
|
75
|
-
* Applies the config's run settings as the `WAYGRAPH_*` variables the runner reads
|
|
76
|
-
*
|
|
110
|
+
* Applies the config's run settings as the `WAYGRAPH_*` variables the runner reads, for the command being run
|
|
111
|
+
* (`WAYGRAPH_COMMAND`, set by the CLI). The `run` / `demo` section overrides the shared top-level values. A flag, a shell
|
|
112
|
+
* variable or a `.env` value that is already set always wins, so the config only supplies defaults.
|
|
77
113
|
*/
|
|
78
|
-
export declare function applyConfigEnv(config: WaygraphConfig | undefined): void;
|
|
114
|
+
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
|
}
|
|
@@ -10,6 +10,7 @@ export interface ApiCallResult {
|
|
|
10
10
|
/** `response.json()` if the body parses as JSON, else the raw text (or `undefined` if neither). */
|
|
11
11
|
body: unknown;
|
|
12
12
|
}
|
|
13
|
+
/** Options for `defineApiBlock`: the HTTP call, how its result maps to a Checkpoint, and the demo network panel. */
|
|
13
14
|
export interface ApiBlockOptions<In extends Checkpoint<string>, Out extends Checkpoint<string>> {
|
|
14
15
|
name: string;
|
|
15
16
|
description?: string;
|
|
@@ -24,9 +24,11 @@ export type MethodBlock<In extends Checkpoint<string>, Out extends Checkpoint<st
|
|
|
24
24
|
};
|
|
25
25
|
/** @deprecated Prefer {@link MethodBlock} - same type; Action was the 0.7 name. */
|
|
26
26
|
export type ActionBlock<In extends Checkpoint<string>, Out extends Checkpoint<string>> = MethodBlock<In, Out>;
|
|
27
|
+
/** Builds a Block for one page action (fill, submit, click) that does not navigate. */
|
|
27
28
|
export declare function defineMethodBlock<In extends Checkpoint<string>, Out extends Checkpoint<string>>(base: Parameters<typeof defineBlock<In, Out>>[0]): MethodBlock<In, Out>;
|
|
28
29
|
/** @deprecated Prefer {@link defineMethodBlock} - identical helper (0.7 name). */
|
|
29
30
|
export declare const defineActionBlock: typeof defineMethodBlock;
|
|
31
|
+
/** Options for `defineAssertBlock`: a Checkpoint to stay on and the Traits that must hold. */
|
|
30
32
|
export interface AssertBlockOptions<Out extends Checkpoint<string> = Checkpoint<string>> {
|
|
31
33
|
name: string;
|
|
32
34
|
description?: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Split out of the former 2,900-line engine.ts (see src/ARCHITECTURE.md). Behavior unchanged.
|
|
2
2
|
import { checkpoint } from "../../types.js";
|
|
3
3
|
import { defineBlock } from "../block.js";
|
|
4
|
+
/** Builds a Block for one page action (fill, submit, click) that does not navigate. */
|
|
4
5
|
export function defineMethodBlock(base) {
|
|
5
6
|
const built = defineBlock(base);
|
|
6
7
|
Object.defineProperty(built, "__waygraphSalt", {
|
|
@@ -123,6 +123,7 @@ export type NavClickBlockOptions<Out extends Checkpoint<string>> = {
|
|
|
123
123
|
highlights?: readonly WaygraphHighlight[] | ((out: Out) => readonly WaygraphHighlight[]);
|
|
124
124
|
instanceOptions?: Block<Checkpoint<string>, Out>["instanceOptions"];
|
|
125
125
|
};
|
|
126
|
+
/** A Block whose only action is clicking a link; built with `defineNavClickBlock`. */
|
|
126
127
|
export type NavClickBlock<Out extends Checkpoint<string>> = NavBlock<Out>;
|
|
127
128
|
/** @see {@link NavClickBlockOptions} */
|
|
128
129
|
export declare function defineNavClickBlock<Out extends Checkpoint<string>>(options: NavClickBlockOptions<Out>): NavClickBlock<Out>;
|
|
@@ -4,6 +4,7 @@ import { MemPage } from "../../mem-page.js";
|
|
|
4
4
|
import type { MemKey } from "../../mem-page.js";
|
|
5
5
|
/** One Block (or lazy factory) registered on a {@link PageBlock}. */
|
|
6
6
|
export type PageMethodEntry = DefinedBlock<any, any> | (() => DefinedBlock<any, any>);
|
|
7
|
+
/** Options for `definePageBlock`: the Checkpoint a page hub confirms and the Methods that hang off it. */
|
|
7
8
|
export type PageBlockOptions<Out extends Checkpoint<string>> = {
|
|
8
9
|
name: string;
|
|
9
10
|
description?: string;
|