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/dist/core/flow.js
CHANGED
|
@@ -2,14 +2,25 @@
|
|
|
2
2
|
import { connect } from "../types.js";
|
|
3
3
|
import { chromiumExecutablePath, extensionPathsFromEnv, launchContext } from "../browser.js";
|
|
4
4
|
import { resolveExtensions } from "../extensions.js";
|
|
5
|
+
import { loadWaygraphConfig } from "../config.js";
|
|
5
6
|
import { WaygraphError, MSG_CHAINFLOW_BLOCK_NOT_FOUND_BY_INDEX, MSG_CHAINFLOW_BLOCK_NOT_FOUND_BY_NAME, MSG_CHAINFLOW_EMPTY, } from "../errors.js";
|
|
6
7
|
import { preflight, runGraph } from "./run-graph.js";
|
|
7
8
|
import { resolveLauncher } from "./config.js";
|
|
8
9
|
import { MemPage } from "../mem-page.js";
|
|
9
|
-
import { findBlockIndex, modVerify, withVerify } from "./block.js";
|
|
10
|
+
import { copyWaygraphRuntime, findBlockIndex, modVerify, withVerify } from "./block.js";
|
|
10
11
|
import { normalizeHighlightSize, normalizeHighlightTone, normalizeHighlightWeight } from "../highlights.js";
|
|
11
12
|
/** Launches the browser and context an Engine uses when the caller gave none, from its config. */
|
|
12
|
-
async function openOwnContext(
|
|
13
|
+
async function openOwnContext(engineConfig) {
|
|
14
|
+
// A config chosen with `--config` / WAYGRAPH_CONFIG wins over the one the Engine was built with, so a flow that imports
|
|
15
|
+
// an engine from one config file still follows the config the run selected.
|
|
16
|
+
const chosen = process.env.WAYGRAPH_CONFIG ? await loadWaygraphConfig(process.cwd()) : undefined;
|
|
17
|
+
const config = chosen
|
|
18
|
+
? {
|
|
19
|
+
...engineConfig,
|
|
20
|
+
...(chosen.baseUrl !== undefined ? { baseUrl: chosen.baseUrl } : {}),
|
|
21
|
+
...(chosen.extensions !== undefined ? { extensions: chosen.extensions } : {}),
|
|
22
|
+
}
|
|
23
|
+
: engineConfig;
|
|
13
24
|
const browserName = config?.browserName ?? "chromium";
|
|
14
25
|
const executablePath = browserName === "chromium" ? chromiumExecutablePath() : undefined;
|
|
15
26
|
const baseURL = config?.baseUrl ?? process.env.WAYGRAPH_BASE_URL;
|
|
@@ -109,7 +120,12 @@ export function buildFlow(middle, engineConfig) {
|
|
|
109
120
|
};
|
|
110
121
|
return {
|
|
111
122
|
resetSession: false,
|
|
112
|
-
blocks: () => middle.map((b) => ({
|
|
123
|
+
blocks: () => middle.map((b) => ({
|
|
124
|
+
name: b.name,
|
|
125
|
+
block: b,
|
|
126
|
+
...(b.routes ? { routes: b.routes } : {}),
|
|
127
|
+
...(b.__waygraphResetBefore ? { resetSessionBefore: true } : {}),
|
|
128
|
+
})),
|
|
113
129
|
run: run,
|
|
114
130
|
withBlockVerify(block, verify) {
|
|
115
131
|
const index = findBlockIndex(middle, block);
|
|
@@ -139,6 +155,7 @@ export function buildFlow(middle, engineConfig) {
|
|
|
139
155
|
* exactly as if a human had opened the app fresh, not wherever the
|
|
140
156
|
* previous Flow in the chain happened to leave the page.
|
|
141
157
|
* @example const loginFlow = withSessionReset(engine.defineFlow([start, LoginBlock, end]));
|
|
158
|
+
* @deprecated Use `map().flow(sub, { reset: true })`; the reset belongs to where flows are joined.
|
|
142
159
|
*/
|
|
143
160
|
export function withSessionReset(flow) {
|
|
144
161
|
return {
|
|
@@ -154,6 +171,7 @@ export function withSessionReset(flow) {
|
|
|
154
171
|
* Blocks are executing, instead of one fixed title for the whole run.
|
|
155
172
|
* Non-destructive, same pattern as {@link withSessionReset}.
|
|
156
173
|
* @example const ticket123 = withTitle(loginFlow, "Ticket #123 - Sales rep signs in");
|
|
174
|
+
* @deprecated Name a flow with `ctx.title(...)` in a stub on its first step.
|
|
157
175
|
*/
|
|
158
176
|
export function withTitle(flow, title) {
|
|
159
177
|
return {
|
|
@@ -172,6 +190,7 @@ export function withTitle(flow, title) {
|
|
|
172
190
|
* this itself - the CLI's `--data`/`--mem-stub` seeding, or a bare-library
|
|
173
191
|
* caller's own explicit `seedMemStub(mem, flow)` call, does the filling.
|
|
174
192
|
* @example const demoLogin = withMemStub(loginFlow);
|
|
193
|
+
* @deprecated Use `engine.map({ memStub: true })`.
|
|
175
194
|
*/
|
|
176
195
|
export function withMemStub(flow) {
|
|
177
196
|
return {
|
|
@@ -189,6 +208,7 @@ export function withMemStub(flow) {
|
|
|
189
208
|
* @example withDemoPace(happyFlow, 0.5) // 2x faster than normal
|
|
190
209
|
* @example withDemoPace(gapFlow, 2.5) // 2.5x slower
|
|
191
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.
|
|
192
212
|
*/
|
|
193
213
|
export function withDemoPace(flow, pace) {
|
|
194
214
|
const demoPace = pace;
|
|
@@ -203,6 +223,7 @@ export function withDemoPace(flow, pace) {
|
|
|
203
223
|
* Default highlight look for a Flow episode (size / weight / optional tone).
|
|
204
224
|
* Per-slot stub or {@link withHighlightFixtures} values win when set.
|
|
205
225
|
* @example withHighlightStyle(withDemoPace(gapFlow, "slow"), { size: "lg", weight: "bold" })
|
|
226
|
+
* @deprecated Use `engine.map({ highlightStyle })`.
|
|
206
227
|
*/
|
|
207
228
|
export function withHighlightStyle(flow, style) {
|
|
208
229
|
const highlightStyle = {
|
|
@@ -220,12 +241,12 @@ export function withHighlightStyle(flow, style) {
|
|
|
220
241
|
/**
|
|
221
242
|
* Demo pacing for one Block or compose unit (not FF - use fastForwardComposeBlock for blitz).
|
|
222
243
|
* @example withBlockPace(composeBlock("gap-review", [...]), "slow")
|
|
244
|
+
* @deprecated Use a step option: `.method(Block, { pace })`.
|
|
223
245
|
*/
|
|
224
246
|
export function withBlockPace(block, pace) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
};
|
|
247
|
+
const next = { ...block, demoPace: pace };
|
|
248
|
+
copyWaygraphRuntime(block, next);
|
|
249
|
+
return next;
|
|
229
250
|
}
|
|
230
251
|
/**
|
|
231
252
|
* Marks a Flow as one that's SUPPOSED to throw - e.g. a locked-out user's
|
|
@@ -244,6 +265,7 @@ export function withBlockPace(block, pace) {
|
|
|
244
265
|
* engine.defineFlow([start, NavLoginBlock, SubmitLoginActionBlock, end]),
|
|
245
266
|
* "locked_out_user stays on LoginPage with the error banner - working as intended.",
|
|
246
267
|
* );
|
|
268
|
+
* @deprecated Use `engine.map({ expectedFailure: reason })`.
|
|
247
269
|
*/
|
|
248
270
|
export function withExpectedFailure(flow, reason) {
|
|
249
271
|
return {
|
|
@@ -259,6 +281,7 @@ export function withExpectedFailure(flow, reason) {
|
|
|
259
281
|
* stubOnError slots. Non-destructive, same pattern as {@link withTitle}.
|
|
260
282
|
* Demo/`chain --step` reads `flow.highlightFixtures`; `run()` ignores it.
|
|
261
283
|
* @example withHighlightFixtures(issueFlow, { "submit-login": { stubBefore: { email: { label: "AC-1" } } } })
|
|
284
|
+
* @deprecated Chain ctx stubs on the Block: `Block.stubAfter((ctx) => …)`.
|
|
262
285
|
*/
|
|
263
286
|
export function withHighlightFixtures(flow, fixtures) {
|
|
264
287
|
return {
|
|
@@ -306,7 +329,7 @@ function locateInChain(flows, block) {
|
|
|
306
329
|
}
|
|
307
330
|
throw new WaygraphError("WG_FLOW_BLOCK_NOT_FOUND", MSG_CHAINFLOW_BLOCK_NOT_FOUND_BY_NAME(blockName));
|
|
308
331
|
}
|
|
309
|
-
async function clearSessionState(context, page) {
|
|
332
|
+
export async function clearSessionState(context, page) {
|
|
310
333
|
await context.clearCookies().catch(() => { });
|
|
311
334
|
await page
|
|
312
335
|
.evaluate(() => {
|
|
@@ -337,6 +360,7 @@ async function clearSessionState(context, page) {
|
|
|
337
360
|
* chain - nothing to reset yet). The combined result is whatever the LAST
|
|
338
361
|
* flow resolved to.
|
|
339
362
|
* @example chainFlow(ticket123Flow, ticket456Flow).run(context, mem)
|
|
363
|
+
* @deprecated Nest flows with `map().flow(a).flow(b, { reset: true })`.
|
|
340
364
|
*/
|
|
341
365
|
export function chainFlow(...flows) {
|
|
342
366
|
if (flows.length === 0) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Block, Checkpoint } from "../types.js";
|
|
2
2
|
import type { EndMarker, StartMarker } from "./run-graph.js";
|
|
3
3
|
import type { Flow, FlowOptions } from "./flow.js";
|
|
4
|
+
import type { DemoPace, HighlightStyleDefaults } from "../highlights.js";
|
|
4
5
|
import type { NavBlock } from "./blocks/nav.js";
|
|
5
6
|
import type { PageBlock } from "./blocks/page.js";
|
|
6
7
|
import type { AssertBlock, MethodBlock } from "./blocks/method.js";
|
|
@@ -13,7 +14,6 @@ type S = Checkpoint<"__start__">;
|
|
|
13
14
|
* defineFlow) - a real cycle check:structure forbids. This type is how that's avoided.
|
|
14
15
|
*/
|
|
15
16
|
export type DefineFlowFn = (blocks: readonly [StartMarker, ...Block<any, any>[], EndMarker], options?: FlowOptions) => Flow<any>;
|
|
16
|
-
/** Per-step options every `MapBuilder` step method (`.gotoPage()`/`.method()`/`.assert()`) takes. */
|
|
17
17
|
export interface MapStepOpts {
|
|
18
18
|
/**
|
|
19
19
|
* Fast-forward just this step, inline - no `.ffStart()/.ffEnd()` bracket needed. Consecutive
|
|
@@ -22,6 +22,12 @@ export interface MapStepOpts {
|
|
|
22
22
|
* @example map().gotoPage(NavLoginBlock, { ff: true }).method(FillUsernameBlock, { ff: true })
|
|
23
23
|
*/
|
|
24
24
|
ff?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Demo pace for just this step (`"blitz"` skips the typing animation and the pause after the action; `"fast"`, `"slow"`,
|
|
27
|
+
* or a number scale the narration gates). The map equivalent of `withBlockPace`, with no wrapper.
|
|
28
|
+
* @example map().method(SetBearerTokenBlock, { pace: "blitz" })
|
|
29
|
+
*/
|
|
30
|
+
pace?: DemoPace;
|
|
25
31
|
}
|
|
26
32
|
export interface MapBuilderOptions {
|
|
27
33
|
/**
|
|
@@ -31,6 +37,19 @@ export interface MapBuilderOptions {
|
|
|
31
37
|
* way; only the internal/external origin distinction is opt-in).
|
|
32
38
|
*/
|
|
33
39
|
homeOrigin?: string;
|
|
40
|
+
/** Fill missing `requires` keys from `registerMemStub` when the flow runs (what `withMemStub` did). */
|
|
41
|
+
memStub?: boolean;
|
|
42
|
+
/** Marks a flow that is supposed to throw, with the reason shown in the demo (what `withExpectedFailure` did). */
|
|
43
|
+
expectedFailure?: string;
|
|
44
|
+
/** Default demo pace for the whole flow (what `withDemoPace` did). */
|
|
45
|
+
demoPace?: DemoPace;
|
|
46
|
+
/** Default ring tone, size and weight for the whole flow (what `withHighlightStyle` did). */
|
|
47
|
+
highlightStyle?: HighlightStyleDefaults;
|
|
48
|
+
}
|
|
49
|
+
/** What `.flow()` takes for the sub-flow it runs inline. */
|
|
50
|
+
export interface MapFlowOpts {
|
|
51
|
+
/** Clear cookies and storage right before the sub-flow, e.g. to start a second user fresh (what `withSessionReset` + `chainFlow` did). */
|
|
52
|
+
reset?: boolean;
|
|
34
53
|
}
|
|
35
54
|
/**
|
|
36
55
|
* Fluent builder over {@link Engine.defineFlow} - see `map()`'s own doc
|
|
@@ -119,6 +138,12 @@ export declare class MapBuilder<Out extends Checkpoint<string>> {
|
|
|
119
138
|
method<NextOut extends Checkpoint<string>>(block: (MethodBlock<Out, NextOut> | EffectBlock<Out, NextOut>) & {
|
|
120
139
|
name: string;
|
|
121
140
|
}, opts?: MapStepOpts): MapBuilder<NextOut>;
|
|
141
|
+
/**
|
|
142
|
+
* Runs another flow's steps inline here, in the same page, browser and `mem`. This is how flows nest:
|
|
143
|
+
* `map().flow(loginFlow).flow(viewerFlow, { reset: true })`. With `{ reset: true }` cookies and storage are cleared
|
|
144
|
+
* right before the sub-flow's first step. Replaces `chainFlow` and `withSessionReset`.
|
|
145
|
+
*/
|
|
146
|
+
flow<NextOut extends Checkpoint<string>>(sub: Flow<NextOut>, opts?: MapFlowOpts): MapBuilder<NextOut>;
|
|
122
147
|
/**
|
|
123
148
|
* Branch: run everything added so far, then continue into whichever `routes[tag]` matches the
|
|
124
149
|
* resolved Checkpoint's tag - same page, same context, same mem. `routes` must cover every tag
|
|
@@ -166,6 +191,7 @@ export declare class MapBuilder<Out extends Checkpoint<string>> {
|
|
|
166
191
|
* left open at `.end()` closes silently; an EXPLICIT `.ffStart()` left open
|
|
167
192
|
* still throws - the author opened that one and needs to close it themselves.
|
|
168
193
|
*/
|
|
194
|
+
/** @param options @deprecated Pass flow settings to `map({ … })` instead. */
|
|
169
195
|
end(options?: FlowOptions): Flow<Out>;
|
|
170
196
|
}
|
|
171
197
|
export {};
|
package/dist/core/map-builder.js
CHANGED
|
@@ -2,6 +2,30 @@ import { WaygraphError, MSG_MAP_WRONG_KIND, MSG_MAP_WRONG_SALT, MSG_MAP_WRONG_OR
|
|
|
2
2
|
import { end, start } from "./run-graph.js";
|
|
3
3
|
import { MemPage } from "../mem-page.js";
|
|
4
4
|
import { fastForwardComposeBlock } from "./compose.js";
|
|
5
|
+
import { clearSessionState, withBlockPace } from "./flow.js";
|
|
6
|
+
import { copyWaygraphRuntime } from "./block.js";
|
|
7
|
+
/** Per-step options every `MapBuilder` step method (`.gotoPage()`/`.method()`/`.assert()`) takes. */
|
|
8
|
+
/** The same Block, but it clears cookies and storage before it acts. Keeps the runtime markers. */
|
|
9
|
+
function resetBefore(block) {
|
|
10
|
+
const act = block.instruction.act.bind(block.instruction);
|
|
11
|
+
const next = {
|
|
12
|
+
...block,
|
|
13
|
+
instruction: {
|
|
14
|
+
...block.instruction,
|
|
15
|
+
async act(page, input, mem) {
|
|
16
|
+
await clearSessionState(page.context(), page);
|
|
17
|
+
return act(page, input, mem);
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
copyWaygraphRuntime(block, next);
|
|
22
|
+
Object.defineProperty(next, "__waygraphResetBefore", { value: true, enumerable: false, configurable: true });
|
|
23
|
+
return next;
|
|
24
|
+
}
|
|
25
|
+
/** Applies a step's `pace` option, keeping the Block's runtime markers. */
|
|
26
|
+
function paced(block, opts) {
|
|
27
|
+
return (opts?.pace === undefined ? block : withBlockPace(block, opts.pace));
|
|
28
|
+
}
|
|
5
29
|
function mapKindOf(block) {
|
|
6
30
|
return block?.__waygraphKind;
|
|
7
31
|
}
|
|
@@ -237,7 +261,7 @@ export class MapBuilder {
|
|
|
237
261
|
gotoPage(block, opts) {
|
|
238
262
|
assertMapKind(block, ["nav", "page"], "gotoPage");
|
|
239
263
|
assertMapOrigin(block, this.homeOrigin, "internal", "gotoPage");
|
|
240
|
-
return this.appendStep(block, opts?.ff);
|
|
264
|
+
return this.appendStep(paced(block, opts), opts?.ff);
|
|
241
265
|
}
|
|
242
266
|
/**
|
|
243
267
|
* Appends a genuinely cross-origin navigation step (e.g. `(external)/`
|
|
@@ -249,7 +273,7 @@ export class MapBuilder {
|
|
|
249
273
|
gotoExternal(block, opts) {
|
|
250
274
|
assertMapKind(block, ["nav", "page"], "gotoExternal");
|
|
251
275
|
assertMapOrigin(block, this.homeOrigin, "external", "gotoExternal");
|
|
252
|
-
return this.appendStep(block, opts?.ff);
|
|
276
|
+
return this.appendStep(paced(block, opts), opts?.ff);
|
|
253
277
|
}
|
|
254
278
|
/**
|
|
255
279
|
* Appends a self-loop verification step - requires a Block from
|
|
@@ -258,7 +282,7 @@ export class MapBuilder {
|
|
|
258
282
|
*/
|
|
259
283
|
assert(block, opts) {
|
|
260
284
|
assertMapKind(block, ["assert"], "assert");
|
|
261
|
-
return this.appendStep(block, opts?.ff);
|
|
285
|
+
return this.appendStep(paced(block, opts), opts?.ff);
|
|
262
286
|
}
|
|
263
287
|
/**
|
|
264
288
|
* Appends a non-navigating page action (submit, upload, add/remove an
|
|
@@ -274,7 +298,20 @@ export class MapBuilder {
|
|
|
274
298
|
throw new WaygraphError("WG_MAP_WRONG_KIND", MSG_MAP_METHOD_GOT_ASSERT(block.name));
|
|
275
299
|
}
|
|
276
300
|
assertMapSalt(block, ["method", "effect"], "method");
|
|
277
|
-
return this.appendStep(block, opts?.ff);
|
|
301
|
+
return this.appendStep(paced(block, opts), opts?.ff);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Runs another flow's steps inline here, in the same page, browser and `mem`. This is how flows nest:
|
|
305
|
+
* `map().flow(loginFlow).flow(viewerFlow, { reset: true })`. With `{ reset: true }` cookies and storage are cleared
|
|
306
|
+
* right before the sub-flow's first step. Replaces `chainFlow` and `withSessionReset`.
|
|
307
|
+
*/
|
|
308
|
+
flow(sub, opts) {
|
|
309
|
+
let next = this;
|
|
310
|
+
sub.blocks().forEach((info, i) => {
|
|
311
|
+
const block = i === 0 && opts?.reset ? resetBefore(info.block) : info.block;
|
|
312
|
+
next = next.appendStep(block);
|
|
313
|
+
});
|
|
314
|
+
return next;
|
|
278
315
|
}
|
|
279
316
|
/**
|
|
280
317
|
* Branch: run everything added so far, then continue into whichever `routes[tag]` matches the
|
|
@@ -329,6 +366,7 @@ export class MapBuilder {
|
|
|
329
366
|
* left open at `.end()` closes silently; an EXPLICIT `.ffStart()` left open
|
|
330
367
|
* still throws - the author opened that one and needs to close it themselves.
|
|
331
368
|
*/
|
|
369
|
+
/** @param options @deprecated Pass flow settings to `map({ … })` instead. */
|
|
332
370
|
end(options) {
|
|
333
371
|
if (this.ff && !this.ff.auto) {
|
|
334
372
|
throw new WaygraphError("WG_MAP_FF_NOT_CLOSED", MSG_MAP_FF_NOT_CLOSED(this.ff.name));
|
|
@@ -10,7 +10,6 @@ export declare const SLIDE_DURATION_MS_DEFAULT = 2000;
|
|
|
10
10
|
/** @deprecated Prefer FIXTURE_DURATION_FAST_MS_DEFAULT */
|
|
11
11
|
export declare const SLIDE_DURATION_FAST_MS_DEFAULT = 600;
|
|
12
12
|
export declare function normalizeDemoPace(raw: unknown): DemoPace;
|
|
13
|
-
/** Named / numeric pace -> scale vs normal (1 = normal). Absolute ms (>20) maps via default dwell. */
|
|
14
13
|
export declare function demoPaceScale(pace: DemoPace): number;
|
|
15
14
|
export declare function demoPaceIsBlitz(pace: DemoPace): boolean;
|
|
16
15
|
/** True when pace should use the short-gate / fast fixture path (not slow authored). */
|
|
@@ -34,6 +34,24 @@ export function normalizeDemoPace(raw) {
|
|
|
34
34
|
return "normal";
|
|
35
35
|
}
|
|
36
36
|
/** Named / numeric pace -> scale vs normal (1 = normal). Absolute ms (>20) maps via default dwell. */
|
|
37
|
+
/**
|
|
38
|
+
* What each named pace means, as a multiplier of normal dwell (1 = normal). `demo.speeds` in the config (or
|
|
39
|
+
* `WAYGRAPH_PACE_SPEEDS`, a JSON object) overrides any of them; the defaults are blitz 0.05, fast 0.33, slow 2.
|
|
40
|
+
*/
|
|
41
|
+
function paceSpeeds() {
|
|
42
|
+
const out = { blitz: 0.05, fast: 0.33, slow: 2 };
|
|
43
|
+
try {
|
|
44
|
+
const raw = process.env.WAYGRAPH_PACE_SPEEDS ? JSON.parse(process.env.WAYGRAPH_PACE_SPEEDS) : {};
|
|
45
|
+
for (const k of ["blitz", "fast", "slow"]) {
|
|
46
|
+
if (typeof raw[k] === "number" && raw[k] > 0)
|
|
47
|
+
out[k] = Math.min(10, raw[k]);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
/* ignore a malformed value: defaults apply */
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
37
55
|
export function demoPaceScale(pace) {
|
|
38
56
|
if (typeof pace === "number") {
|
|
39
57
|
if (pace > 20)
|
|
@@ -41,11 +59,11 @@ export function demoPaceScale(pace) {
|
|
|
41
59
|
return Math.min(10, Math.max(0.05, pace));
|
|
42
60
|
}
|
|
43
61
|
if (pace === "blitz")
|
|
44
|
-
return
|
|
62
|
+
return paceSpeeds().blitz;
|
|
45
63
|
if (pace === "fast")
|
|
46
|
-
return
|
|
64
|
+
return paceSpeeds().fast;
|
|
47
65
|
if (pace === "slow")
|
|
48
|
-
return
|
|
66
|
+
return paceSpeeds().slow;
|
|
49
67
|
return 1;
|
|
50
68
|
}
|
|
51
69
|
export function demoPaceIsBlitz(pace) {
|
|
@@ -73,6 +91,9 @@ export function demoPaceIsSlow(pace) {
|
|
|
73
91
|
}
|
|
74
92
|
/** Autoplay / Next-gate ms for this pace (base is WAYGRAPH_AUTOPLAY_MS or 1800). */
|
|
75
93
|
export function demoPaceGateMs(pace, baseAutoplayMs) {
|
|
94
|
+
if (pace === "blitz" && process.env.WAYGRAPH_PACE_SPEEDS) {
|
|
95
|
+
return Math.min(30000, Math.max(20, Math.round(baseAutoplayMs * paceSpeeds().blitz)));
|
|
96
|
+
}
|
|
76
97
|
if (demoPaceIsBlitz(pace))
|
|
77
98
|
return Math.min(80, baseAutoplayMs);
|
|
78
99
|
if (typeof pace === "number" && pace > 20) {
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { Trait, urlMatches, textEquals, visible, disabled, enabled, frameVisible
|
|
|
9
9
|
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, defineAssertBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, defineApiBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withMemStub, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, withStubBefore, withStubAfter, withStubOnError, withDialog, chainFlow, defineLayout, map, MapBuilder, branchRoutes, collectBranchFlows, runBranchRegression, } from "./core.js";
|
|
10
10
|
export type { BranchEntry, BranchRunResult, RunBranchRegressionOptions } from "./core/branch-regression.js";
|
|
11
11
|
export type { ApiBlockOptions, ApiCallResult } from "./core/blocks/api.js";
|
|
12
|
-
export type { MapStepOpts } from "./core/map-builder.js";
|
|
12
|
+
export type { MapStepOpts, MapFlowOpts } from "./core/map-builder.js";
|
|
13
13
|
export { resolveHighlightSlots, resolveSlides, runStubPhase, resolveFixtureDwellMs, resolveSlideDwellMs, formatHighlightCaption, hasAuthoredStubAfter, hasAuthoredStubOnError, normalizeHighlightTone, normalizeDemoPace, normalizeHighlightSize, normalizeHighlightWeight, applyHighlightStyleDefaults, toneIconPrefix, resolveStepDemoPace, demoPaceScale, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, demoPaceGateMs, formatDemoPaceBadge, formatDemoPaceLabel, normalizeTodos, normalizeTodoPos, normalizeTodoStyle, buildTodoDock, applyTodoPhase, advanceTodoDock, completeSequentialTodoDock, applyDevicePhase, resolveDeviceState, normalizeDevicePreset, normalizeDeviceOrientation, applyOrientation, orientationFromViewport, DEVICE_PRESETS, resolveTodoDockUi, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT, SLIDE_DURATION_MS_DEFAULT, SLIDE_DURATION_FAST_MS_DEFAULT, WAYGRAPH_RING_CSS, } from "./highlights.js";
|
|
14
14
|
export type { WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, WaygraphTodoItem, WaygraphTodoInput, WaygraphTodoGroup, WaygraphTodoGroupInput, WaygraphTodosOpts, TodoDockUiOpts, BannerPos, BannerUiOpts, TodoDockUiResolved, TodoDockState, TodoListStyle, FixtureDurationFields, HighlightStubPhase, HighlightStubPhaseName, HighlightFixtureMap, ResolvedHighlight, WaygraphHighlight, HighlightTone, HighlightSize, HighlightWeight, HighlightStyleDefaults, DemoPace, DemoPaceName, StubCtx, StubLifecycleFn, StubPhaseResult, StubPhaseFixtures, DevicePreset, DeviceViewport, DeviceState, DeviceOrientation, } from "./highlights.js";
|
|
15
15
|
export type { Flow, FlowOptions, EngineConfig, ComposedBlock, FastForwardComposedBlock, RunGraphOptions, BlockInfo, NavBlock, NavBlockOptions, NavClickBlock, NavClickBlockOptions, MethodBlock, ActionBlock, AssertBlock, AssertBlockOptions, PageBlock, PageBlockOptions, PageMethodEntry, EffectBlock, MemEffectBlock, MemNavBlock, Layout, LayoutOptions, MapBuilderOptions, } from "./core.js";
|
|
@@ -30,7 +30,7 @@ export type { AutoSessionInit, SessionSnapshot, SessionSnapshotEdge, SessionSnap
|
|
|
30
30
|
export { pilotStart } from "./session/pilot.js";
|
|
31
31
|
export type { PilotStartResult } from "./session/pilot.js";
|
|
32
32
|
export { defineConfig, resolveBaseUrl } from "./config.js";
|
|
33
|
-
export type { WaygraphConfig, ConfigContext } from "./config.js";
|
|
33
|
+
export type { WaygraphConfig, ConfigContext, VideoSettings, RunSettings, DemoSettings } from "./config.js";
|
|
34
34
|
export { withWebServer } from "./webserver.js";
|
|
35
35
|
export { chromiumExecutablePath } from "./browser.js";
|
|
36
36
|
export { resolveExtension, KNOWN_EXTENSIONS } from "./extensions.js";
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
import type { Page } from "@playwright/test";
|
|
2
|
-
type Box = {
|
|
3
|
-
x: number;
|
|
4
|
-
y: number;
|
|
5
|
-
width: number;
|
|
6
|
-
height: number;
|
|
7
|
-
};
|
|
8
|
-
/** Paint the gray "auto" ring (Playwright is about to act here) at a viewport rectangle. */
|
|
9
|
-
export declare function showPilotRect(page: Page, box: Box, label: string, tone?: string): Promise<void>;
|
|
10
2
|
/**
|
|
11
3
|
* Every Playwright instruction a Block runs against this session's page gets a gray (auto) ring + robot
|
|
12
4
|
* label first, so a human watching a pilot window sees WHAT is being driven. `dwellMs` holds the ring
|
|
13
5
|
* long enough to read before the action fires (0 for headless).
|
|
14
6
|
*/
|
|
15
7
|
export declare function instrumentPilotActions(page: Page, dwellMs: number): void;
|
|
16
|
-
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ensureInstalled } from "./shell.js";
|
|
2
2
|
/** Paint the gray "auto" ring (Playwright is about to act here) at a viewport rectangle. */
|
|
3
|
-
|
|
3
|
+
async function showPilotRect(page, box, label, tone = "auto") {
|
|
4
4
|
await ensureInstalled(page);
|
|
5
5
|
await page
|
|
6
6
|
.evaluate(({ box, label, tone }) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SessionSnapshot } from "../auto-session.js";
|
|
2
2
|
import type { Page } from "@playwright/test";
|
|
3
3
|
/** Minimal shape needed to render the graph tree - matches WaygraphGraph. */
|
|
4
|
-
|
|
4
|
+
interface PilotOverlayGraph {
|
|
5
5
|
nodes: readonly {
|
|
6
6
|
checkpoint: string;
|
|
7
7
|
}[];
|
|
@@ -32,3 +32,4 @@ export interface PilotOverlayInfo {
|
|
|
32
32
|
* operation over.
|
|
33
33
|
*/
|
|
34
34
|
export declare function updatePilotOverlay(page: Page, info: PilotOverlayInfo): Promise<void>;
|
|
35
|
+
export {};
|
|
@@ -21,7 +21,36 @@ export function instrumentInteractionHighlighting(page, mem, slowMo, pacing, stu
|
|
|
21
21
|
// (shorter Next/autoplay gates) and must NOT skip theater, or the whole demo
|
|
22
22
|
// looks like plain waygraph run.
|
|
23
23
|
const skipTheater = () => !!pacing.skipTheater;
|
|
24
|
-
|
|
24
|
+
// `slowMo` here is the demo's own beat: ms to rest after each action (once per call, never per keystroke). The browser
|
|
25
|
+
// itself is launched with slowMo 0 in step mode, so a step whose pace is blitz really does run at full speed.
|
|
26
|
+
const beat = () => (skipTheater() ? 0 : slowMo || 0);
|
|
27
|
+
const pause = (ms) => (ms > 0 ? new Promise((res) => setTimeout(res, ms)) : undefined);
|
|
28
|
+
// Per-character typing delay (WAYGRAPH_TYPING_MS, default 30). 0 for blitz steps.
|
|
29
|
+
const typingMs = () => {
|
|
30
|
+
if (skipTheater()) return 0;
|
|
31
|
+
const n = Number(process.env.WAYGRAPH_TYPING_MS);
|
|
32
|
+
return process.env.WAYGRAPH_TYPING_MS !== undefined && Number.isFinite(n) && n >= 0 ? n : 30;
|
|
33
|
+
};
|
|
34
|
+
const typeDelay = typingMs;
|
|
35
|
+
const keyboard = page.keyboard;
|
|
36
|
+
if (!keyboard.__wgBeatPatched) {
|
|
37
|
+
keyboard.__wgBeatPatched = true;
|
|
38
|
+
const originalType = keyboard.type.bind(keyboard);
|
|
39
|
+
keyboard.type = async (text, options) => {
|
|
40
|
+
await originalType(text, { delay: typingMs(), ...(options || {}) });
|
|
41
|
+
await pause(beat());
|
|
42
|
+
};
|
|
43
|
+
const originalPress = keyboard.press.bind(keyboard);
|
|
44
|
+
keyboard.press = async (key, options) => {
|
|
45
|
+
await originalPress(key, options);
|
|
46
|
+
await pause(beat());
|
|
47
|
+
};
|
|
48
|
+
const originalInsertText = keyboard.insertText.bind(keyboard);
|
|
49
|
+
keyboard.insertText = async (text) => {
|
|
50
|
+
await originalInsertText(text);
|
|
51
|
+
await pause(beat());
|
|
52
|
+
};
|
|
53
|
+
}
|
|
25
54
|
// Click is a single action, not per-character, so it doesn't compound
|
|
26
55
|
// the same way - but slowMo still adds its own pause around the actual
|
|
27
56
|
// click, so trim our own explicit "pop" pauses when it's already active
|
|
@@ -155,6 +184,7 @@ export function instrumentInteractionHighlighting(page, mem, slowMo, pacing, stu
|
|
|
155
184
|
// it - it was sticking around through the whole rest of the step.
|
|
156
185
|
await hideRing(page);
|
|
157
186
|
await restoreTheaterAfterNavigation(page, todoDockRef, deviceRef, stubBeforeRef);
|
|
187
|
+
await pause(beat());
|
|
158
188
|
return result;
|
|
159
189
|
};
|
|
160
190
|
}
|
|
@@ -285,6 +315,7 @@ export function instrumentInteractionHighlighting(page, mem, slowMo, pacing, stu
|
|
|
285
315
|
await hideRing(page);
|
|
286
316
|
// Full document navigation drops #wg-todo-dock + rings; restore carry.
|
|
287
317
|
await restoreTheaterAfterNavigation(page, todoDockRef, deviceRef, stubBeforeRef);
|
|
318
|
+
await pause(beat());
|
|
288
319
|
return result;
|
|
289
320
|
};
|
|
290
321
|
}
|
package/dist/runner/main.js
CHANGED
|
@@ -231,6 +231,9 @@ async function runMain() {
|
|
|
231
231
|
: "waygraph demo: opaque FFCompose in flow -> Playwright slowMo=0 (blitz); set WAYGRAPH_SLOWMO to override",
|
|
232
232
|
);
|
|
233
233
|
}
|
|
234
|
+
// Step (demo) mode: slowMo is waygraph's own beat after each action, not Playwright's per-operation slowMo, so a
|
|
235
|
+
// step's pace can remove it and typing is not taxed per keystroke. The browser launches at 0.
|
|
236
|
+
const launchSlowMo = step ? 0 : slowMo;
|
|
234
237
|
const baseURL = process.env.WAYGRAPH_BASE_URL;
|
|
235
238
|
const title = process.env.WAYGRAPH_TITLE;
|
|
236
239
|
// Comma-separated Block names (their real .name, e.g. "login") that
|
|
@@ -263,7 +266,7 @@ async function runMain() {
|
|
|
263
266
|
const fixedVideoViewport = videoDir
|
|
264
267
|
? (videoViewportParsed ?? (step ? DEFAULT_VIDEO_VIEWPORT : DEFAULT_RUN_VIDEO_VIEWPORT))
|
|
265
268
|
: null;
|
|
266
|
-
const engine = new Engine({ headless: !headed, slowMo });
|
|
269
|
+
const engine = new Engine({ headless: !headed, slowMo: launchSlowMo });
|
|
267
270
|
let result;
|
|
268
271
|
// Non-interactive execution (no --step) runs the whole chain as one
|
|
269
272
|
// composed flow with no per-block loop of its own to defer seeding
|
|
@@ -312,7 +315,7 @@ async function runMain() {
|
|
|
312
315
|
launcher: chromium,
|
|
313
316
|
launch: {
|
|
314
317
|
headless: !headed,
|
|
315
|
-
slowMo,
|
|
318
|
+
slowMo: launchSlowMo,
|
|
316
319
|
args: step || fixedVideoViewport ? ["--start-maximized"] : [],
|
|
317
320
|
...(executablePath ? { executablePath } : {}),
|
|
318
321
|
},
|
package/dist/runner/step-mode.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Moved verbatim from the former CHAIN_RUNNER_SCRIPT template string in cli.ts (see src/ARCHITECTURE.md).
|
|
2
2
|
// Runs inside the target project's own waygraph copy - keep it dependency-light and self-contained.
|
|
3
3
|
import { instrumentInteractionHighlighting } from "./interaction-patch.js";
|
|
4
|
-
import { applyHighlightStyleDefaults, demoPaceGateMs, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, formatHighlightCaption, hasAuthoredStubAfter, resolveSlides, resolveStepDemoPace, resolveTodoDockUi, runStubPhase } from "../highlights.js";
|
|
4
|
+
import { applyHighlightStyleDefaults, normalizeDemoPace, demoPaceGateMs, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, formatHighlightCaption, hasAuthoredStubAfter, resolveSlides, resolveStepDemoPace, resolveTodoDockUi, runStubPhase } from "../highlights.js";
|
|
5
5
|
import { markStepRunning, resetPageState, teardownOverlay } from "./teardown.js";
|
|
6
6
|
import { demoLog, logStubPhaseFixtures, logTodoDockFull, paceSpeakFields, summarizeDevice } from "./demo-log.js";
|
|
7
7
|
import { extractVerifyHighlights, presentFailPanel, renderAfterStep, renderBeforeStep } from "./step-panels.js";
|
|
@@ -26,6 +26,8 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
26
26
|
const demoFast = process.env.WAYGRAPH_DEMO_FAST === "1";
|
|
27
27
|
const stepperMode = process.env.WAYGRAPH_STEPPER === "full" ? "full" : "carousel";
|
|
28
28
|
const pacing = { gatesFast: demoFast, gatesSlow: false, skipTheater: false, demoPace: "normal" };
|
|
29
|
+
// A title set by a stub (`ctx.title`) names the flow from that step on, until another stub sets a new one.
|
|
30
|
+
let stickyTitle;
|
|
29
31
|
const stubBeforeRef = { current: [] };
|
|
30
32
|
/** Live todo dock for Method fill/click advance (same carry as stage.state.lastTodoDock). */
|
|
31
33
|
const todoDockRef = { current: undefined };
|
|
@@ -213,15 +215,18 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
213
215
|
}
|
|
214
216
|
// Episode pace: block > flow > CLI --fast (only when no authored pace).
|
|
215
217
|
// Authoring wins: withDemoPace("slow"|2|4500) keeps slow dwell even under --fast.
|
|
218
|
+
// `demo.pace` in the config (WAYGRAPH_DEMO_PACE) is the default for flows and steps that set none.
|
|
219
|
+
const defaultPace = process.env.WAYGRAPH_DEMO_PACE ? normalizeDemoPace(process.env.WAYGRAPH_DEMO_PACE) : undefined;
|
|
216
220
|
const stepPace = resolveStepDemoPace({
|
|
217
221
|
blockPace: r.block.demoPace,
|
|
218
|
-
flowPace: r.demoPace,
|
|
222
|
+
flowPace: r.demoPace ?? defaultPace,
|
|
219
223
|
fastForward: !!r.block.fastForward,
|
|
220
224
|
wasFastForward: !!r.wasFastForward,
|
|
221
225
|
});
|
|
222
226
|
const authoredPace =
|
|
223
227
|
(r.block.demoPace != null && r.block.demoPace !== "") ||
|
|
224
|
-
(r.demoPace != null && r.demoPace !== "")
|
|
228
|
+
(r.demoPace != null && r.demoPace !== "") ||
|
|
229
|
+
defaultPace != null;
|
|
225
230
|
const cliFast = demoFast || fastBlockNames.has(r.block.name);
|
|
226
231
|
pacing.demoPace =
|
|
227
232
|
stepPace === "normal" && cliFast && !authoredPace
|
|
@@ -266,8 +271,9 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
266
271
|
(stage.state.lastTodoDock && stage.state.lastTodoDock.groups[0] && stage.state.lastTodoDock.groups[0].items) ||
|
|
267
272
|
stubBeforePhase.todos ||
|
|
268
273
|
[];
|
|
274
|
+
if (stubBeforePhase.title && String(stubBeforePhase.title).trim()) stickyTitle = String(stubBeforePhase.title).trim();
|
|
269
275
|
const overlayTitle =
|
|
270
|
-
|
|
276
|
+
stickyTitle ||
|
|
271
277
|
(r.episodeTitle && String(r.episodeTitle).trim()) ||
|
|
272
278
|
title ||
|
|
273
279
|
"waygraph demo";
|
|
@@ -24,7 +24,7 @@ export interface ExploreEdge extends WaygraphEdge {
|
|
|
24
24
|
label?: string;
|
|
25
25
|
instanceOption?: WaygraphInstanceOption;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
interface ExploreSection {
|
|
28
28
|
title: string;
|
|
29
29
|
edges: ExploreEdge[];
|
|
30
30
|
}
|
|
@@ -55,3 +55,4 @@ export declare function buildExploreContext(projectDir: string, opts?: ExploreCo
|
|
|
55
55
|
graph: WaygraphGraph;
|
|
56
56
|
library: Awaited<ReturnType<typeof loadBlockLibrary>>;
|
|
57
57
|
}>;
|
|
58
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AutoSession, type AutoSessionInit, type SessionSnapshot, type InspectDomOptions, type DomSnapshot, type TraceStep, type ApplyPathResult, type ConsoleLogEntry, type StorageSnapshot, type StubFileKind } from "../auto-session.js";
|
|
2
2
|
import type { PilotHighlightFixtures } from "../pilot-overlay.js";
|
|
3
|
-
export type { PilotHighlightFixtures
|
|
3
|
+
export type { PilotHighlightFixtures } from "../pilot-overlay.js";
|
|
4
4
|
export interface SessionMeta {
|
|
5
5
|
sessionId: string;
|
|
6
6
|
socketPath: string;
|
|
@@ -54,7 +54,6 @@ export type HighlightResponse = {
|
|
|
54
54
|
ok: false;
|
|
55
55
|
error: string;
|
|
56
56
|
};
|
|
57
|
-
export declare function readSessionMeta(projectDir: string, sessionId: string): SessionMeta | null;
|
|
58
57
|
/**
|
|
59
58
|
* Resolve session metadata from a project hint (cwd) or the global registry.
|
|
60
59
|
* Fixes "session unreachable" when the agent calls status/send from a different
|
|
@@ -58,7 +58,7 @@ function logPathFor(projectDir, sessionId) {
|
|
|
58
58
|
function generateSessionId() {
|
|
59
59
|
return randomBytes(4).toString("hex");
|
|
60
60
|
}
|
|
61
|
-
|
|
61
|
+
function readSessionMeta(projectDir, sessionId) {
|
|
62
62
|
const p = metaPath(projectDir, sessionId);
|
|
63
63
|
if (!existsSync(p))
|
|
64
64
|
return null;
|
|
@@ -1,21 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This package's own installed root (contains `templates/`/`examples/`, sibling to `dist/`) -
|
|
3
|
-
* this file compiles to `dist/session/block-inject.js`, two levels down, not one. Same class of
|
|
4
|
-
* bug as `cli/util.ts`'s own `packageRoot()` (see its comment) - self-inflicted here by moving
|
|
5
|
-
* this file into `src/session/` without updating the path math to match the new depth.
|
|
6
|
-
*/
|
|
7
|
-
export declare function packageRoot(): string;
|
|
8
|
-
/** Human label for an injected root (used in merged `file` paths). */
|
|
9
|
-
export declare function injectLabel(root: string): string;
|
|
10
1
|
/**
|
|
11
2
|
* Display path for a Block discovered under an inject root (not the host cwd).
|
|
12
3
|
* Primary project files stay relative as-is; injected ones are tagged `@label/...`.
|
|
13
4
|
*/
|
|
14
5
|
export declare function injectTaggedFile(hostDir: string, root: string, relFile: string): string;
|
|
15
|
-
/**
|
|
16
|
-
* Resolve one `--inject` token to an absolute directory (preset name or path).
|
|
17
|
-
*/
|
|
18
|
-
export declare function resolveInjectRoot(token: string, cwd?: string): string;
|
|
19
6
|
export declare function resolveInjectRoots(tokens: string[], cwd?: string): string[];
|
|
20
7
|
/** Roots to scan: host project first, then each inject path (deduped). */
|
|
21
8
|
export declare function exploreRoots(projectDir: string, inject?: string[]): string[];
|
|
@@ -12,11 +12,11 @@ import { homedir } from "node:os";
|
|
|
12
12
|
* bug as `cli/util.ts`'s own `packageRoot()` (see its comment) - self-inflicted here by moving
|
|
13
13
|
* this file into `src/session/` without updating the path math to match the new depth.
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
function packageRoot() {
|
|
16
16
|
return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
17
17
|
}
|
|
18
18
|
/** Human label for an injected root (used in merged `file` paths). */
|
|
19
|
-
|
|
19
|
+
function injectLabel(root) {
|
|
20
20
|
return basename(root.replace(/\/$/, ""));
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
@@ -50,7 +50,7 @@ const PRESETS = {
|
|
|
50
50
|
/**
|
|
51
51
|
* Resolve one `--inject` token to an absolute directory (preset name or path).
|
|
52
52
|
*/
|
|
53
|
-
|
|
53
|
+
function resolveInjectRoot(token, cwd = process.cwd()) {
|
|
54
54
|
const raw = token.trim();
|
|
55
55
|
if (!raw)
|
|
56
56
|
throw new Error("waygraph inject: empty --inject value");
|
package/dist/session/pilot.d.ts
CHANGED
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
* new execution primitive.
|
|
30
30
|
*/
|
|
31
31
|
import { type WaygraphGraph } from "../analysis/graph.js";
|
|
32
|
-
import { listBrowserSessions, type SessionMeta } from "./auto-session-ipc.js";
|
|
33
32
|
import { type BrowserStartInit } from "./browser.js";
|
|
34
33
|
import type { SessionSnapshot } from "../auto-session.js";
|
|
35
34
|
export interface PilotStartResult {
|
|
@@ -51,4 +50,3 @@ export interface PilotStartResult {
|
|
|
51
50
|
export declare function pilotStart(init: BrowserStartInit): Promise<PilotStartResult>;
|
|
52
51
|
/** Reattach to an existing browser session — does not spawn a new browser. */
|
|
53
52
|
export declare function pilotAttach(projectDir: string, sessionId: string, inject?: string[]): Promise<PilotStartResult>;
|
|
54
|
-
export { listBrowserSessions, type SessionMeta };
|