waygraph 0.12.9 → 0.12.10
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/dist/auto-explore-run.d.ts +2 -0
- package/dist/auto-explore-run.js +5 -1
- package/dist/auto-explore.d.ts +6 -2
- package/dist/auto-explore.js +15 -5
- package/dist/blocks-select.d.ts +22 -0
- package/dist/blocks-select.js +85 -0
- package/dist/cli.js +39 -1
- package/dist/graph.d.ts +4 -1
- package/dist/graph.js +17 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/traverse-run.d.ts +2 -0
- package/dist/traverse-run.js +5 -1
- package/package.json +1 -1
|
@@ -4,6 +4,8 @@ export interface AutoExploreOptions {
|
|
|
4
4
|
baseURL?: string;
|
|
5
5
|
/** Initial URL when the page is blank (defaults to baseURL). */
|
|
6
6
|
startUrl?: string;
|
|
7
|
+
/** Phase C: glob / regex / bare `--blocks` file select for discovery. */
|
|
8
|
+
blocksSelect?: import("./blocks-select.js").BlocksSelect;
|
|
7
9
|
}
|
|
8
10
|
/**
|
|
9
11
|
* Saucedemo-only defaults. Exact key names only — never substring `"login"`
|
package/dist/auto-explore-run.js
CHANGED
|
@@ -491,7 +491,11 @@ export async function runAutoExplore(projectDir, options = {}) {
|
|
|
491
491
|
const cli = options.cli === true;
|
|
492
492
|
const baseURL = options.baseURL ?? resolveBaseUrl(projectDir) ?? process.env.WAYGRAPH_BASE_URL;
|
|
493
493
|
const startUrl = options.startUrl ?? baseURL;
|
|
494
|
-
const { graph, library } = await buildExploreContext(projectDir);
|
|
494
|
+
const { graph, library } = await buildExploreContext(projectDir, options.blocksSelect ? { blocksSelect: options.blocksSelect } : undefined);
|
|
495
|
+
if (options.blocksSelect) {
|
|
496
|
+
console.error(`waygraph auto: --blocks ${options.blocksSelect.raw} → ` +
|
|
497
|
+
`${library.byName.size} block(s), ${graph.edges.length} edge(s)`);
|
|
498
|
+
}
|
|
495
499
|
const mem = new MemPage();
|
|
496
500
|
seedDefaultMem(library.byName, mem);
|
|
497
501
|
const engine = cli ? new Engine({ headless: true }) : new Engine({ headless: false, slowMo: 250 });
|
package/dist/auto-explore.d.ts
CHANGED
|
@@ -32,7 +32,9 @@ export interface ExploreMenu {
|
|
|
32
32
|
/**
|
|
33
33
|
* Import every `*.block.ts` export keyed by runtime Block `.name`.
|
|
34
34
|
*/
|
|
35
|
-
export declare function loadBlockLibrary(projectDir: string
|
|
35
|
+
export declare function loadBlockLibrary(projectDir: string, opts?: {
|
|
36
|
+
blocksSelect?: import("./blocks-select.js").BlocksSelect;
|
|
37
|
+
}): Promise<{
|
|
36
38
|
byName: Map<string, BlockEntry>;
|
|
37
39
|
navBlocks: BlockEntry[];
|
|
38
40
|
}>;
|
|
@@ -46,7 +48,9 @@ export declare function exploreChoices(graph: WaygraphGraph, here: string | null
|
|
|
46
48
|
export declare function buildExploreMenu(page: Page, graph: WaygraphGraph, library: {
|
|
47
49
|
byName: Map<string, BlockEntry>;
|
|
48
50
|
}, here: string | null): Promise<ExploreMenu>;
|
|
49
|
-
export declare function buildExploreContext(projectDir: string
|
|
51
|
+
export declare function buildExploreContext(projectDir: string, opts?: {
|
|
52
|
+
blocksSelect?: import("./blocks-select.js").BlocksSelect;
|
|
53
|
+
}): Promise<{
|
|
50
54
|
graph: WaygraphGraph;
|
|
51
55
|
library: Awaited<ReturnType<typeof loadBlockLibrary>>;
|
|
52
56
|
}>;
|
package/dist/auto-explore.js
CHANGED
|
@@ -81,11 +81,17 @@ async function wildcardActionRunnable(page, entry, here) {
|
|
|
81
81
|
/**
|
|
82
82
|
* Import every `*.block.ts` export keyed by runtime Block `.name`.
|
|
83
83
|
*/
|
|
84
|
-
export async function loadBlockLibrary(projectDir) {
|
|
84
|
+
export async function loadBlockLibrary(projectDir, opts) {
|
|
85
|
+
const { matchBlocksSelect } = await import("./blocks-select.js");
|
|
85
86
|
const byName = new Map();
|
|
86
87
|
const navBlocks = [];
|
|
88
|
+
const select = opts?.blocksSelect;
|
|
87
89
|
for (const file of walkDir(projectDir, /\.block\.ts$/)) {
|
|
88
|
-
const relFile = relative(projectDir, file);
|
|
90
|
+
const relFile = relative(projectDir, file).replace(/\\/g, "/");
|
|
91
|
+
// Glob/bare: path filter before import. Regex: need block name — filter after.
|
|
92
|
+
if (select && select.kind !== "regex" && !matchBlocksSelect(select, { relFile })) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
89
95
|
let mod;
|
|
90
96
|
try {
|
|
91
97
|
mod = await importModule(file);
|
|
@@ -100,6 +106,10 @@ export async function loadBlockLibrary(projectDir) {
|
|
|
100
106
|
for (const [exportName, exported] of Object.entries(mod)) {
|
|
101
107
|
if (!isBlockLike(exported))
|
|
102
108
|
continue;
|
|
109
|
+
if (select &&
|
|
110
|
+
!matchBlocksSelect(select, { relFile, blockName: exported.name })) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
103
113
|
const kind = isNavBlockMarked(exported) ? "nav" : "action";
|
|
104
114
|
const entry = {
|
|
105
115
|
block: exported,
|
|
@@ -317,11 +327,11 @@ export async function buildExploreMenu(page, graph, library, here) {
|
|
|
317
327
|
}
|
|
318
328
|
return { here, sections, flat };
|
|
319
329
|
}
|
|
320
|
-
export async function buildExploreContext(projectDir) {
|
|
330
|
+
export async function buildExploreContext(projectDir, opts) {
|
|
321
331
|
// Sequential: parallel import of the same *.block.ts tree raced Playwright's
|
|
322
332
|
// dual-copy guard in some installs and left graph edges without library entries
|
|
323
333
|
// (LoginPage → "No moves").
|
|
324
|
-
const library = await loadBlockLibrary(projectDir);
|
|
325
|
-
const graph = await discoverGraph(projectDir);
|
|
334
|
+
const library = await loadBlockLibrary(projectDir, opts);
|
|
335
|
+
const graph = await discoverGraph(projectDir, opts);
|
|
326
336
|
return { graph, library };
|
|
327
337
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type BlocksSelectKind = "regex" | "glob" | "bare";
|
|
2
|
+
export interface BlocksSelect {
|
|
3
|
+
kind: BlocksSelectKind;
|
|
4
|
+
/** Original token. */
|
|
5
|
+
raw: string;
|
|
6
|
+
/** For regex: compiled without wrapping slashes. For glob: pattern as given. */
|
|
7
|
+
pattern: string;
|
|
8
|
+
re?: RegExp;
|
|
9
|
+
}
|
|
10
|
+
/** True when the token is file-select (glob/regex), not a bare flow/checkpoint name. */
|
|
11
|
+
export declare function isFileSelectToken(token: string): boolean;
|
|
12
|
+
export declare function parseBlocksSelect(token: string): BlocksSelect;
|
|
13
|
+
/** Glob → RegExp (simple: ** / * / ? only; no brace expansion). */
|
|
14
|
+
export declare function globToRegExp(glob: string): RegExp;
|
|
15
|
+
export declare function matchBlocksSelect(select: BlocksSelect, opts: {
|
|
16
|
+
relFile: string;
|
|
17
|
+
blockName?: string;
|
|
18
|
+
}): boolean;
|
|
19
|
+
export declare function filterByBlocksSelect<T extends {
|
|
20
|
+
file: string;
|
|
21
|
+
block?: string;
|
|
22
|
+
}>(items: T[], select: BlocksSelect | undefined, projectDir: string): T[];
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared `--blocks` select grammar (RFC Phase C).
|
|
3
|
+
*
|
|
4
|
+
* - `/pattern/` -> regex on relative file path OR block name
|
|
5
|
+
* - has `*`/`**` -> glob on relative file path (POSIX-ish)
|
|
6
|
+
* - otherwise -> bare token (flow export / checkpoint / block name) — caller decides
|
|
7
|
+
*/
|
|
8
|
+
import { relative } from "node:path";
|
|
9
|
+
/** True when the token is file-select (glob/regex), not a bare flow/checkpoint name. */
|
|
10
|
+
export function isFileSelectToken(token) {
|
|
11
|
+
if (!token)
|
|
12
|
+
return false;
|
|
13
|
+
if (token.length >= 2 && token.startsWith("/") && token.endsWith("/") && token.length > 2) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
return token.includes("*");
|
|
17
|
+
}
|
|
18
|
+
export function parseBlocksSelect(token) {
|
|
19
|
+
const raw = token.trim();
|
|
20
|
+
if (raw.length >= 2 && raw.startsWith("/") && raw.endsWith("/")) {
|
|
21
|
+
const body = raw.slice(1, -1);
|
|
22
|
+
return { kind: "regex", raw, pattern: body, re: new RegExp(body) };
|
|
23
|
+
}
|
|
24
|
+
if (raw.includes("*")) {
|
|
25
|
+
return { kind: "glob", raw, pattern: raw };
|
|
26
|
+
}
|
|
27
|
+
return { kind: "bare", raw, pattern: raw };
|
|
28
|
+
}
|
|
29
|
+
/** Glob → RegExp (simple: ** / * / ? only; no brace expansion). */
|
|
30
|
+
export function globToRegExp(glob) {
|
|
31
|
+
let out = "";
|
|
32
|
+
for (let i = 0; i < glob.length; i++) {
|
|
33
|
+
const c = glob[i];
|
|
34
|
+
if (c === "*" && glob[i + 1] === "*") {
|
|
35
|
+
out += ".*";
|
|
36
|
+
i++;
|
|
37
|
+
if (glob[i + 1] === "/")
|
|
38
|
+
i++;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (c === "*") {
|
|
42
|
+
out += "[^/]*";
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (c === "?") {
|
|
46
|
+
out += "[^/]";
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (".+^${}()|[]\\".includes(c))
|
|
50
|
+
out += "\\" + c;
|
|
51
|
+
else
|
|
52
|
+
out += c;
|
|
53
|
+
}
|
|
54
|
+
return new RegExp("^" + out + "$");
|
|
55
|
+
}
|
|
56
|
+
export function matchBlocksSelect(select, opts) {
|
|
57
|
+
const file = opts.relFile.replace(/\\/g, "/");
|
|
58
|
+
const name = opts.blockName ?? "";
|
|
59
|
+
if (select.kind === "regex") {
|
|
60
|
+
const re = select.re ?? new RegExp(select.pattern);
|
|
61
|
+
return re.test(file) || (name !== "" && re.test(name));
|
|
62
|
+
}
|
|
63
|
+
if (select.kind === "glob") {
|
|
64
|
+
return globToRegExp(select.pattern.replace(/\\/g, "/")).test(file);
|
|
65
|
+
}
|
|
66
|
+
// bare: match block name equality (case-sensitive) or path substring
|
|
67
|
+
if (name && name === select.pattern)
|
|
68
|
+
return true;
|
|
69
|
+
if (file.includes(select.pattern))
|
|
70
|
+
return true;
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
export function filterByBlocksSelect(items, select, projectDir) {
|
|
74
|
+
if (!select)
|
|
75
|
+
return items;
|
|
76
|
+
return items.filter((it) => {
|
|
77
|
+
const relFile = it.file.startsWith(projectDir)
|
|
78
|
+
? relative(projectDir, it.file)
|
|
79
|
+
: it.file;
|
|
80
|
+
return matchBlocksSelect(select, {
|
|
81
|
+
relFile: relFile.replace(/\\/g, "/"),
|
|
82
|
+
...(it.block !== undefined ? { blockName: it.block } : {}),
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -21,6 +21,7 @@ import { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./gra
|
|
|
21
21
|
import { runAutoExplore } from "./auto-explore-run.js";
|
|
22
22
|
import { runAgentDive } from "./agent-dive.js";
|
|
23
23
|
import { runTraverse } from "./traverse-run.js";
|
|
24
|
+
import { isFileSelectToken, parseBlocksSelect, } from "./blocks-select.js";
|
|
24
25
|
// ---------------------------------------------------------------------------
|
|
25
26
|
// Filesystem
|
|
26
27
|
// ---------------------------------------------------------------------------
|
|
@@ -3673,7 +3674,8 @@ Primary (less is more):
|
|
|
3673
3674
|
|
|
3674
3675
|
Also:
|
|
3675
3676
|
waygraph list | nav | validate | check | graph | init <name>
|
|
3676
|
-
waygraph traverse [project] Serial graph crawl (Phase B)
|
|
3677
|
+
waygraph traverse [project] Serial graph crawl (Phase B+)
|
|
3678
|
+
--blocks <glob|/re/|sub> Phase C: filter *.block.ts discovery
|
|
3677
3679
|
--from <Checkpoint> Seed / start checkpoint
|
|
3678
3680
|
--data '{...}' Mem seed
|
|
3679
3681
|
--max-steps N Cap Block runs (default 50)
|
|
@@ -3697,6 +3699,8 @@ Examples:
|
|
|
3697
3699
|
waygraph auto src/flows/shop.flow.ts --data '{...}' # run by file (same as run)
|
|
3698
3700
|
waygraph auto --cli --data '{"saucedemo.credentials":{...}}'
|
|
3699
3701
|
waygraph auto --blocks LoginPage OrderComplete
|
|
3702
|
+
waygraph auto --blocks '/mailpit/' # Phase C filtered explore
|
|
3703
|
+
waygraph traverse --blocks '**/mailpit/**/*.block.ts' # Phase C filtered crawl
|
|
3700
3704
|
waygraph run --blocks "loginFlow then add-all-to-cart" --data '{...}' --video
|
|
3701
3705
|
|
|
3702
3706
|
Aliases (compat): \`chain <spec>\` -> run --blocks; \`chain auto A B\` -> auto --blocks A B;
|
|
@@ -3790,6 +3794,7 @@ async function main() {
|
|
|
3790
3794
|
let maxEdge;
|
|
3791
3795
|
let headed = false;
|
|
3792
3796
|
let baseUrl;
|
|
3797
|
+
let blocksFilter;
|
|
3793
3798
|
let projectDir = process.cwd();
|
|
3794
3799
|
for (let i = 0; i < rest.length; i++) {
|
|
3795
3800
|
const a = rest[i];
|
|
@@ -3801,6 +3806,20 @@ async function main() {
|
|
|
3801
3806
|
data = a.startsWith("--data=") ? a.slice(7) : rest[++i];
|
|
3802
3807
|
continue;
|
|
3803
3808
|
}
|
|
3809
|
+
if (a === "--blocks" || a.startsWith("--blocks=")) {
|
|
3810
|
+
if (a.startsWith("--blocks=")) {
|
|
3811
|
+
blocksFilter = a.slice("--blocks=".length);
|
|
3812
|
+
}
|
|
3813
|
+
else {
|
|
3814
|
+
const v = rest[++i];
|
|
3815
|
+
if (!v || v.startsWith("-")) {
|
|
3816
|
+
console.error("waygraph traverse: --blocks needs a glob, /regex/, or path substring");
|
|
3817
|
+
process.exit(1);
|
|
3818
|
+
}
|
|
3819
|
+
blocksFilter = v;
|
|
3820
|
+
}
|
|
3821
|
+
continue;
|
|
3822
|
+
}
|
|
3804
3823
|
if (a === "--max-steps" || a.startsWith("--max-steps=")) {
|
|
3805
3824
|
const v = a.startsWith("--max-steps=") ? a.slice(12) : rest[++i];
|
|
3806
3825
|
maxSteps = Number(v);
|
|
@@ -3832,6 +3851,7 @@ async function main() {
|
|
|
3832
3851
|
Serial graph crawl (RFC Phase B). Walks unused legal edges until a leaf,
|
|
3833
3852
|
budget kill, or first broken edge.
|
|
3834
3853
|
|
|
3854
|
+
--blocks <glob|/regex/|substr> Phase C: filter *.block.ts discovery
|
|
3835
3855
|
--from <Checkpoint> start checkpoint (optional)
|
|
3836
3856
|
--data '{...}' Mem seed JSON
|
|
3837
3857
|
--max-steps N default 50
|
|
@@ -3840,6 +3860,10 @@ budget kill, or first broken edge.
|
|
|
3840
3860
|
--non-headless show browser
|
|
3841
3861
|
--base-url URL
|
|
3842
3862
|
|
|
3863
|
+
Examples:
|
|
3864
|
+
waygraph traverse --blocks '**/mailpit/**/*.block.ts'
|
|
3865
|
+
waygraph traverse --blocks '/mailpit|login/'
|
|
3866
|
+
|
|
3843
3867
|
PASS: [Reached Leaf Node[traverse-1] at=... steps=N]
|
|
3844
3868
|
FAIL: [Broke at edge[traverse-1] block=... from=... to=...]
|
|
3845
3869
|
`);
|
|
@@ -3853,6 +3877,9 @@ FAIL: [Broke at edge[traverse-1] block=... from=... to=...]
|
|
|
3853
3877
|
console.error(`waygraph traverse: no such directory: ${projectDir}`);
|
|
3854
3878
|
process.exit(1);
|
|
3855
3879
|
}
|
|
3880
|
+
const blocksSelect = blocksFilter
|
|
3881
|
+
? parseBlocksSelect(blocksFilter)
|
|
3882
|
+
: undefined;
|
|
3856
3883
|
const code = await runTraverse(projectDir, {
|
|
3857
3884
|
...(from ? { from } : {}),
|
|
3858
3885
|
...(data ? { data } : {}),
|
|
@@ -3865,6 +3892,7 @@ FAIL: [Broke at edge[traverse-1] block=... from=... to=...]
|
|
|
3865
3892
|
: {}),
|
|
3866
3893
|
headed,
|
|
3867
3894
|
...(baseUrl ? { baseURL: baseUrl } : {}),
|
|
3895
|
+
...(blocksSelect ? { blocksSelect } : {}),
|
|
3868
3896
|
});
|
|
3869
3897
|
process.exit(code);
|
|
3870
3898
|
}
|
|
@@ -4024,13 +4052,23 @@ Agents shipped: waygraph-planner, waygraph-author, waygraph-healer.
|
|
|
4024
4052
|
process.exit(1);
|
|
4025
4053
|
}
|
|
4026
4054
|
// auto --blocks From To (graph path-find + run)
|
|
4055
|
+
// auto --blocks '/regex/' or '**/*.block.ts' (Phase C file select → explore)
|
|
4027
4056
|
if (command === "auto" && (flags.blocksFromTo || flags.blocks)) {
|
|
4028
4057
|
if (flags.blocksFromTo) {
|
|
4029
4058
|
const [fromTag, toTag] = flags.blocksFromTo;
|
|
4030
4059
|
await runChainAuto(proj, fromTag, toTag);
|
|
4031
4060
|
break;
|
|
4032
4061
|
}
|
|
4062
|
+
if (flags.blocks && isFileSelectToken(flags.blocks)) {
|
|
4063
|
+
const blocksSelect = parseBlocksSelect(flags.blocks);
|
|
4064
|
+
const baseURL = flags.baseUrl ?? process.env.WAYGRAPH_BASE_URL ?? resolveBaseUrl(proj);
|
|
4065
|
+
await runAutoExplore(proj, baseURL
|
|
4066
|
+
? { cli: cliPicker, baseURL, blocksSelect }
|
|
4067
|
+
: { cli: cliPicker, blocksSelect });
|
|
4068
|
+
break;
|
|
4069
|
+
}
|
|
4033
4070
|
console.error("waygraph auto --blocks expects <fromCheckpoint> <toCheckpoint>\n" +
|
|
4071
|
+
" or file select: --blocks '**/mailpit/**/*.block.ts' / --blocks '/mailpit/'\n" +
|
|
4034
4072
|
' e.g. waygraph auto --blocks LoginPage OrderComplete\n' +
|
|
4035
4073
|
' for a hand-named chain use: waygraph run --blocks "a then b"\n' +
|
|
4036
4074
|
" or: waygraph auto src/flows/shop.flow.ts");
|
package/dist/graph.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type BlocksSelect } from "./blocks-select.js";
|
|
1
2
|
/**
|
|
2
3
|
* The state-machine shape `waygraph auto` discovers from a project's own
|
|
3
4
|
* Blocks - Checkpoints are nodes, Blocks are edges. Kept as plain data (not
|
|
@@ -67,4 +68,6 @@ export declare function findBlockPath(graph: WaygraphGraph, fromTag: string, toT
|
|
|
67
68
|
* already is for `check`, unlike `chain`, which spawns a child process
|
|
68
69
|
* specifically because it also EXECUTES Blocks, not just imports them.
|
|
69
70
|
*/
|
|
70
|
-
export declare function discoverGraph(projectDir: string
|
|
71
|
+
export declare function discoverGraph(projectDir: string, opts?: {
|
|
72
|
+
blocksSelect?: BlocksSelect;
|
|
73
|
+
}): Promise<WaygraphGraph>;
|
package/dist/graph.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
2
|
import { join, dirname, relative, resolve } from "node:path";
|
|
3
|
+
import { matchBlocksSelect, } from "./blocks-select.js";
|
|
3
4
|
/**
|
|
4
5
|
* Renders a `WaygraphGraph` as Mermaid `stateDiagram-v2` text - paste
|
|
5
6
|
* straight into a `.md` file's ```mermaid fence or a live editor. `"*"`
|
|
@@ -296,8 +297,15 @@ function extractDefineBlockGenerics(src) {
|
|
|
296
297
|
* already is for `check`, unlike `chain`, which spawns a child process
|
|
297
298
|
* specifically because it also EXECUTES Blocks, not just imports them.
|
|
298
299
|
*/
|
|
299
|
-
export async function discoverGraph(projectDir) {
|
|
300
|
-
|
|
300
|
+
export async function discoverGraph(projectDir, opts) {
|
|
301
|
+
let files = discoverBlocks(projectDir);
|
|
302
|
+
const select = opts?.blocksSelect;
|
|
303
|
+
// Glob/bare: drop files early. Regex needs block names — filter per export below.
|
|
304
|
+
if (select && select.kind !== "regex") {
|
|
305
|
+
files = files.filter((file) => matchBlocksSelect(select, {
|
|
306
|
+
relFile: relative(projectDir, file).replace(/\\/g, "/"),
|
|
307
|
+
}));
|
|
308
|
+
}
|
|
301
309
|
const nodeTags = new Set();
|
|
302
310
|
const edges = [];
|
|
303
311
|
const skipped = [];
|
|
@@ -326,6 +334,13 @@ export async function discoverGraph(projectDir) {
|
|
|
326
334
|
if (!isBlockLike(exported))
|
|
327
335
|
continue;
|
|
328
336
|
const blockName = exported.name;
|
|
337
|
+
if (select &&
|
|
338
|
+
!matchBlocksSelect(select, {
|
|
339
|
+
relFile: relFile.replace(/\\/g, "/"),
|
|
340
|
+
blockName,
|
|
341
|
+
})) {
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
329
344
|
if (isNavBlockMarked(exported)) {
|
|
330
345
|
try {
|
|
331
346
|
// NavBlock / PageBlock resolve() ignores input - always checkpoint(tag).
|
package/dist/index.d.ts
CHANGED
|
@@ -9,3 +9,5 @@ export type { Flow, EngineConfig, ComposedBlock, FastForwardComposedBlock, RunGr
|
|
|
9
9
|
export type { ActionPage } from "./types.js";
|
|
10
10
|
export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./graph.js";
|
|
11
11
|
export type { WaygraphGraph, WaygraphNode, WaygraphEdge, SkippedBlock, OrphanBlock } from "./graph.js";
|
|
12
|
+
export { isFileSelectToken, parseBlocksSelect, matchBlocksSelect, globToRegExp, } from "./blocks-select.js";
|
|
13
|
+
export type { BlocksSelect, BlocksSelectKind } from "./blocks-select.js";
|
package/dist/index.js
CHANGED
|
@@ -4,3 +4,4 @@ export { Trait, urlMatches, textEquals, visible } from "./trait.js";
|
|
|
4
4
|
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withExpectedFailure, withHighlightFixtures, chainFlow, } from "./engine.js";
|
|
5
5
|
export { resolveHighlightSlots, resolveSlides, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, } from "./highlights.js";
|
|
6
6
|
export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./graph.js";
|
|
7
|
+
export { isFileSelectToken, parseBlocksSelect, matchBlocksSelect, globToRegExp, } from "./blocks-select.js";
|
package/dist/traverse-run.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export interface TraverseOptions {
|
|
|
17
17
|
headed?: boolean;
|
|
18
18
|
/** Traverse id for greppable lines (default traverse-1). */
|
|
19
19
|
traverseId?: string;
|
|
20
|
+
/** Phase C: glob / regex / bare `--blocks` file select. */
|
|
21
|
+
blocksSelect?: import("./blocks-select.js").BlocksSelect;
|
|
20
22
|
}
|
|
21
23
|
/**
|
|
22
24
|
* Serial graph crawl. Prints greppable PASS/FAIL lines; non-zero exit on break.
|
package/dist/traverse-run.js
CHANGED
|
@@ -106,7 +106,11 @@ export async function runTraverse(projectDir, options = {}) {
|
|
|
106
106
|
const headed = options.headed === true || process.env.WAYGRAPH_HEADED === "1";
|
|
107
107
|
const baseURL = options.baseURL ?? resolveBaseUrl(projectDir) ?? process.env.WAYGRAPH_BASE_URL;
|
|
108
108
|
const startUrl = options.startUrl ?? baseURL;
|
|
109
|
-
const { graph, library } = await buildExploreContext(projectDir);
|
|
109
|
+
const { graph, library } = await buildExploreContext(projectDir, options.blocksSelect ? { blocksSelect: options.blocksSelect } : undefined);
|
|
110
|
+
if (options.blocksSelect) {
|
|
111
|
+
console.error(`waygraph traverse: --blocks ${options.blocksSelect.raw} → ` +
|
|
112
|
+
`${library.byName.size} block(s), ${graph.edges.length} edge(s)`);
|
|
113
|
+
}
|
|
110
114
|
const mem = new MemPage();
|
|
111
115
|
seedMem(library.byName, mem, options.data);
|
|
112
116
|
const engine = new Engine({ headless: !headed, slowMo: headed ? 100 : 0 });
|