waygraph 0.15.32 → 0.15.34
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/engine/core.js +5 -0
- package/dist/engine/engine-class.d.ts +37 -0
- package/dist/engine/engine-class.js +98 -0
- package/dist/highlights/run-phase.js +2 -0
- package/dist/highlights/stub-ctx.js +36 -2
- package/dist/highlights/types.d.ts +35 -3
- package/dist/index.d.ts +1 -1
- package/dist/pilot-overlay/fixtures.d.ts +9 -1
- package/dist/pilot-overlay/fixtures.js +38 -1
- package/dist/pilot-overlay/overlay-fixtures.d.ts +9 -0
- package/dist/pilot-overlay/overlay-fixtures.js +45 -0
- package/dist/pilot-overlay/shell.js +4 -23
- package/dist/pilot-overlay.d.ts +1 -0
- package/dist/pilot-overlay.js +1 -0
- package/dist/runner/banner-log.js +62 -0
- package/dist/runner/demo-log.js +9 -1
- package/dist/runner/inpage/banner.js +56 -1
- package/dist/runner/inpage/core.js +2 -0
- package/dist/runner/overlay-css.js +6 -27
- package/dist/runner/overlay-install.js +7 -4
- package/dist/runner/overlay-present.d.ts +8 -0
- package/dist/runner/overlay-present.js +57 -0
- package/dist/runner/overlay-stage.js +105 -0
- package/dist/runner/step-mode.js +35 -126
- package/dist/runner/step-panels.js +3 -3
- package/dist/step-overlay.js +1 -3
- package/dist/ui/overlay.css +209 -0
- package/dist/ui/shadow.d.ts +7 -2
- package/dist/ui/shadow.js +12 -4
- package/dist/ui/stylesheet.d.ts +7 -0
- package/dist/ui/stylesheet.js +18 -0
- package/dist/verbose-log.d.ts +1 -0
- package/dist/verbose-log.js +16 -0
- package/examples/saucedemo/.waygraph-auto/03df352d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/0a8c3719.log +0 -0
- package/examples/saucedemo/.waygraph-auto/102c38ca.log +0 -0
- package/examples/saucedemo/.waygraph-auto/232a1d81.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2553d107.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2f4f531e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2fdbd916.log +0 -0
- package/examples/saucedemo/.waygraph-auto/331c6e8e.log +0 -0
- package/examples/saucedemo/.waygraph-auto/38f6799d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/3bdb2f5a.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5b838485.log +0 -0
- package/examples/saucedemo/.waygraph-auto/5d13bdde.log +0 -0
- package/examples/saucedemo/.waygraph-auto/63b0f4cd.log +0 -0
- package/examples/saucedemo/.waygraph-auto/6f05bdc1.log +0 -0
- package/examples/saucedemo/.waygraph-auto/70279fc3.log +0 -0
- package/examples/saucedemo/.waygraph-auto/731a14bd.log +0 -0
- package/examples/saucedemo/.waygraph-auto/76128a2d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/796ab578.log +0 -0
- package/examples/saucedemo/.waygraph-auto/81257bf0.log +0 -0
- package/examples/saucedemo/.waygraph-auto/859a261d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a1ab5d29.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a4b36275.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a94738b7.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b3d172f3.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b5569336.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b57921c5.log +0 -0
- package/examples/saucedemo/.waygraph-auto/b9ab0983.log +0 -0
- package/examples/saucedemo/.waygraph-auto/d37719a6.log +0 -0
- package/examples/saucedemo/.waygraph-auto/da0a06bf.log +0 -0
- package/examples/saucedemo/.waygraph-auto/dc58eb72.log +0 -0
- package/examples/saucedemo/.waygraph-auto/ff616932.log +0 -0
- package/package.json +3 -2
- package/examples/saucedemo/.waygraph-auto/535e8922.json +0 -8
package/dist/engine/core.js
CHANGED
|
@@ -45,6 +45,11 @@ export function branch(block, routes) {
|
|
|
45
45
|
},
|
|
46
46
|
routes: routesAsData,
|
|
47
47
|
});
|
|
48
|
+
// Without this, branch()'s output carried no __waygraphKind/__waygraphSalt at all (defineBlock
|
|
49
|
+
// never stamps them - factories do, after defineBlock returns), so a branched Block could never
|
|
50
|
+
// pass MapBuilder's assertMapKind/assertMapSalt checks. Real bug: branching was unusable from the
|
|
51
|
+
// Waygraph Map, only from a raw runGraph() call.
|
|
52
|
+
copyWaygraphRuntime(block, routed);
|
|
48
53
|
return routed;
|
|
49
54
|
}
|
|
50
55
|
/**
|
|
@@ -269,6 +269,43 @@ export declare class MapBuilder<Out extends Checkpoint<string>> {
|
|
|
269
269
|
method<NextOut extends Checkpoint<string>>(block: (MethodBlock<Out, NextOut> | EffectBlock<Out, NextOut>) & {
|
|
270
270
|
name: string;
|
|
271
271
|
}): MapBuilder<NextOut>;
|
|
272
|
+
/**
|
|
273
|
+
* Branch: run everything added so far, then continue into whichever `routes[tag]` matches the
|
|
274
|
+
* resolved Checkpoint's tag - same page, same context, same mem. `routes` must cover every tag
|
|
275
|
+
* of `Out` (a missing one is a compile error, matching {@link branch}'s own exhaustiveness);
|
|
276
|
+
* `null` means that tag is terminal (the branched Flow just returns that Checkpoint).
|
|
277
|
+
*
|
|
278
|
+
* Each non-null route is a function, not a ready-made `Flow` - a fresh Flow always starts at the
|
|
279
|
+
* special `S` (start) Checkpoint, but a branch's blocks start from the TAG it routes on (e.g.
|
|
280
|
+
* `LoggedIn`), so the function is handed a brand-new `MapBuilder` already seeded at that exact
|
|
281
|
+
* Checkpoint to chain `.method()/.gotoPage()/.assert()/.end()` (or another `.branch()`) off of.
|
|
282
|
+
*
|
|
283
|
+
* Real gap this fixes: the plain `branch()` helper's `.next` routing is only ever consulted by
|
|
284
|
+
* `runGraph`'s own graph walk - `defineFlow`/`.end()` compose steps pairwise via `connect()`,
|
|
285
|
+
* which never looks at `.next` at all, so a Map-built Flow had no way to branch. This method
|
|
286
|
+
* branches at the Flow level instead: it finalizes the prefix, runs it, and picks the next Flow
|
|
287
|
+
* itself once the real tag is known - no engine-level routing involved.
|
|
288
|
+
*
|
|
289
|
+
* Only the `run(context, mem[, options])` signature is supported - the page must survive across
|
|
290
|
+
* the branch, and the bare `run(mem, config)` convenience form always closes its own browser
|
|
291
|
+
* before a tag is even known, so it throws instead of silently reopening a fresh (state-losing) page.
|
|
292
|
+
*
|
|
293
|
+
* The route's first Block still sees `input.__state === "__start__"` in `act()`, not the tag that
|
|
294
|
+
* routed there - `runGraph` seeds every Flow's entry Block that way unconditionally, the same as
|
|
295
|
+
* any standalone `defineFlow([start, block, end])` already does. Read `page`/`mem`, not `input`,
|
|
296
|
+
* in `act()` - every real Block in this codebase already follows that convention.
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* map({ homeOrigin }).gotoPage(NavCartBlock).branch({
|
|
300
|
+
* ItemInCart: (m) => m.method(RemoveFromCartBlock).end(),
|
|
301
|
+
* LoggedIn: (m) => m.method(AddToCartBlock).end(),
|
|
302
|
+
* });
|
|
303
|
+
*/
|
|
304
|
+
branch<Routes extends {
|
|
305
|
+
[K in Out["__state"]]: ((m: MapBuilder<Extract<Out, Checkpoint<K>>>) => Flow<any>) | null;
|
|
306
|
+
}>(routes: Routes): Flow<{
|
|
307
|
+
[K in keyof Routes & string]: Routes[K] extends (m: any) => Flow<infer R> ? R : Extract<Out, Checkpoint<K>>;
|
|
308
|
+
}[keyof Routes & string]>;
|
|
272
309
|
/**
|
|
273
310
|
* Finalizes this chain into a real, runnable {@link Flow} - same object
|
|
274
311
|
* `defineFlow` returns, so `withBlockVerify`/`modBlockVerify` and every
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { end, start } from "./run-graph.js";
|
|
2
2
|
import { buildFlow } from "./flow.js";
|
|
3
|
+
import { MemPage } from "../mem-page.js";
|
|
3
4
|
import { fastForwardComposeBlock } from "./compose.js";
|
|
4
5
|
/**
|
|
5
6
|
* Holds engine-level configuration shared across every flow defined from it -
|
|
@@ -104,6 +105,59 @@ function assertMapOrigin(block, homeOrigin, expect, method) {
|
|
|
104
105
|
`home origin (${wantOrigin}) - use .gotoPage() for an internal destination.`);
|
|
105
106
|
}
|
|
106
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Builds the `Flow` object `MapBuilder.branch()` returns: run `before`, then dispatch on the
|
|
110
|
+
* resolved tag into whichever `routes` entry matches (same page/context/mem), or return that
|
|
111
|
+
* Checkpoint as-is when its route is `null`. Factored out so `withBlockVerify`/`modBlockVerify`
|
|
112
|
+
* can patch `before` and rebuild the same branched shape, exactly like a plain Flow's own.
|
|
113
|
+
*/
|
|
114
|
+
function buildBranchedFlow(before, routes) {
|
|
115
|
+
const run = (async (contextOrMem, memOrConfig, options) => {
|
|
116
|
+
if (contextOrMem instanceof MemPage) {
|
|
117
|
+
throw new Error("Waygraph map: a .branch()-ed Flow can't run via run(mem, config) - that convenience form " +
|
|
118
|
+
"always closes its own browser/page before a branch's tag is even known. Call " +
|
|
119
|
+
"run(context, mem[, options]) instead, keeping the same page across the branch.");
|
|
120
|
+
}
|
|
121
|
+
const context = contextOrMem;
|
|
122
|
+
const mem = memOrConfig;
|
|
123
|
+
const gotOwnPage = options?.page === undefined;
|
|
124
|
+
const page = options?.page ?? (await context.newPage());
|
|
125
|
+
const closeOnFinish = options?.closeOnFinish ?? gotOwnPage;
|
|
126
|
+
const first = (await before.run(context, mem, { ...options, page, closeOnFinish: false }));
|
|
127
|
+
const branchFlow = routes[first.result.__state];
|
|
128
|
+
if (!branchFlow) {
|
|
129
|
+
if (options?.closeOnFinish === false)
|
|
130
|
+
return { result: first.result, page: first.page };
|
|
131
|
+
if (closeOnFinish)
|
|
132
|
+
await first.page.close();
|
|
133
|
+
return first.result;
|
|
134
|
+
}
|
|
135
|
+
return branchFlow.run(context, mem, { ...options, page: first.page, closeOnFinish });
|
|
136
|
+
});
|
|
137
|
+
return {
|
|
138
|
+
resetSession: before.resetSession,
|
|
139
|
+
...(before.title !== undefined ? { title: before.title } : {}),
|
|
140
|
+
...(before.expectedFailureReason !== undefined ? { expectedFailureReason: before.expectedFailureReason } : {}),
|
|
141
|
+
...(before.highlightFixtures !== undefined ? { highlightFixtures: before.highlightFixtures } : {}),
|
|
142
|
+
...(before.demoPace !== undefined ? { demoPace: before.demoPace } : {}),
|
|
143
|
+
...(before.highlightStyle !== undefined ? { highlightStyle: before.highlightStyle } : {}),
|
|
144
|
+
...(before.memStub !== undefined ? { memStub: before.memStub } : {}),
|
|
145
|
+
// Static introspection (`waygraph graph`/list): the fixed prefix, plus every branch's own
|
|
146
|
+
// Blocks prefixed by the tag that leads to them - can't know at analysis time which one a real
|
|
147
|
+
// run takes, so this shows all of them rather than none.
|
|
148
|
+
blocks: () => [
|
|
149
|
+
...before.blocks(),
|
|
150
|
+
...Object.entries(routes).flatMap(([tag, f]) => f ? f.blocks().map((b) => ({ ...b, name: `${tag} -> ${b.name}` })) : []),
|
|
151
|
+
],
|
|
152
|
+
run,
|
|
153
|
+
withBlockVerify(block, verify) {
|
|
154
|
+
return buildBranchedFlow(before.withBlockVerify(block, verify), routes);
|
|
155
|
+
},
|
|
156
|
+
modBlockVerify(block, nameOrIndex, newCheck) {
|
|
157
|
+
return buildBranchedFlow(before.modBlockVerify(block, nameOrIndex, newCheck), routes);
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
107
161
|
/**
|
|
108
162
|
* Fluent builder over {@link Engine.defineFlow} - see `map()`'s own doc
|
|
109
163
|
* comment for why this exists. Each step method is scoped to exactly the
|
|
@@ -226,6 +280,50 @@ export class MapBuilder {
|
|
|
226
280
|
assertMapSalt(block, ["method", "effect"], "method");
|
|
227
281
|
return this.appendStep(block);
|
|
228
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Branch: run everything added so far, then continue into whichever `routes[tag]` matches the
|
|
285
|
+
* resolved Checkpoint's tag - same page, same context, same mem. `routes` must cover every tag
|
|
286
|
+
* of `Out` (a missing one is a compile error, matching {@link branch}'s own exhaustiveness);
|
|
287
|
+
* `null` means that tag is terminal (the branched Flow just returns that Checkpoint).
|
|
288
|
+
*
|
|
289
|
+
* Each non-null route is a function, not a ready-made `Flow` - a fresh Flow always starts at the
|
|
290
|
+
* special `S` (start) Checkpoint, but a branch's blocks start from the TAG it routes on (e.g.
|
|
291
|
+
* `LoggedIn`), so the function is handed a brand-new `MapBuilder` already seeded at that exact
|
|
292
|
+
* Checkpoint to chain `.method()/.gotoPage()/.assert()/.end()` (or another `.branch()`) off of.
|
|
293
|
+
*
|
|
294
|
+
* Real gap this fixes: the plain `branch()` helper's `.next` routing is only ever consulted by
|
|
295
|
+
* `runGraph`'s own graph walk - `defineFlow`/`.end()` compose steps pairwise via `connect()`,
|
|
296
|
+
* which never looks at `.next` at all, so a Map-built Flow had no way to branch. This method
|
|
297
|
+
* branches at the Flow level instead: it finalizes the prefix, runs it, and picks the next Flow
|
|
298
|
+
* itself once the real tag is known - no engine-level routing involved.
|
|
299
|
+
*
|
|
300
|
+
* Only the `run(context, mem[, options])` signature is supported - the page must survive across
|
|
301
|
+
* the branch, and the bare `run(mem, config)` convenience form always closes its own browser
|
|
302
|
+
* before a tag is even known, so it throws instead of silently reopening a fresh (state-losing) page.
|
|
303
|
+
*
|
|
304
|
+
* The route's first Block still sees `input.__state === "__start__"` in `act()`, not the tag that
|
|
305
|
+
* routed there - `runGraph` seeds every Flow's entry Block that way unconditionally, the same as
|
|
306
|
+
* any standalone `defineFlow([start, block, end])` already does. Read `page`/`mem`, not `input`,
|
|
307
|
+
* in `act()` - every real Block in this codebase already follows that convention.
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* map({ homeOrigin }).gotoPage(NavCartBlock).branch({
|
|
311
|
+
* ItemInCart: (m) => m.method(RemoveFromCartBlock).end(),
|
|
312
|
+
* LoggedIn: (m) => m.method(AddToCartBlock).end(),
|
|
313
|
+
* });
|
|
314
|
+
*/
|
|
315
|
+
branch(routes) {
|
|
316
|
+
if (this.steps.length === 0) {
|
|
317
|
+
throw new Error("Waygraph map: .branch() needs at least one prior step - nothing to branch from. " +
|
|
318
|
+
"Add .gotoPage()/.gotoExternal()/.method()/.assert() first.");
|
|
319
|
+
}
|
|
320
|
+
const before = this.end();
|
|
321
|
+
const resolvedRoutes = {};
|
|
322
|
+
for (const [tag, fn] of Object.entries(routes)) {
|
|
323
|
+
resolvedRoutes[tag] = fn ? fn(new MapBuilder(this.engine, [], this.homeOrigin, null)) : null;
|
|
324
|
+
}
|
|
325
|
+
return buildBranchedFlow(before, resolvedRoutes);
|
|
326
|
+
}
|
|
229
327
|
/**
|
|
230
328
|
* Finalizes this chain into a real, runnable {@link Flow} - same object
|
|
231
329
|
* `defineFlow` returns, so `withBlockVerify`/`modBlockVerify` and every
|
|
@@ -107,6 +107,8 @@ export async function runStubPhase(block, phase, opts) {
|
|
|
107
107
|
...(bag.zoom !== undefined ? { zoom: bag.zoom } : {}),
|
|
108
108
|
...(bag.zoomOut !== undefined ? { zoomOut: bag.zoomOut } : {}),
|
|
109
109
|
...(bag.title !== undefined && bag.title !== "" ? { title: bag.title } : {}),
|
|
110
|
+
...(bag.titlePos !== undefined ? { titlePos: bag.titlePos } : {}),
|
|
111
|
+
...(bag.bannerUi !== undefined ? { bannerUi: bag.bannerUi } : {}),
|
|
110
112
|
...(bag.todoPos !== undefined ? { todoPos: bag.todoPos } : {}),
|
|
111
113
|
...(bag.todoDockUi !== undefined ? { todoDockUi: bag.todoDockUi } : {}),
|
|
112
114
|
...(bag.todoParallel === true ? { todoParallel: true } : {}),
|
|
@@ -162,11 +162,35 @@ export function createStubCtx(bag, opts) {
|
|
|
162
162
|
zoomOut(keep) {
|
|
163
163
|
bag.zoomOut = !!keep;
|
|
164
164
|
},
|
|
165
|
-
title(text) {
|
|
165
|
+
title(text, opts) {
|
|
166
166
|
bag.title = String(text ?? "");
|
|
167
|
+
const p = normalizeBannerPos(opts?.pos);
|
|
168
|
+
if (p)
|
|
169
|
+
bag.titlePos = p;
|
|
167
170
|
},
|
|
168
|
-
banner(text) {
|
|
171
|
+
banner(text, opts) {
|
|
169
172
|
bag.title = String(text ?? "");
|
|
173
|
+
const p = normalizeBannerPos(opts?.pos);
|
|
174
|
+
if (p)
|
|
175
|
+
bag.titlePos = p;
|
|
176
|
+
},
|
|
177
|
+
titlePos(side) {
|
|
178
|
+
const p = normalizeBannerPos(side);
|
|
179
|
+
if (p)
|
|
180
|
+
bag.titlePos = p;
|
|
181
|
+
},
|
|
182
|
+
bannerPos(side) {
|
|
183
|
+
const p = normalizeBannerPos(side);
|
|
184
|
+
if (p)
|
|
185
|
+
bag.titlePos = p;
|
|
186
|
+
},
|
|
187
|
+
bannerUi(opts) {
|
|
188
|
+
if (!opts || typeof opts !== "object")
|
|
189
|
+
return;
|
|
190
|
+
bag.bannerUi = { ...(bag.bannerUi || {}), ...opts };
|
|
191
|
+
},
|
|
192
|
+
hideBanner() {
|
|
193
|
+
bag.bannerUi = { ...(bag.bannerUi || {}), hidden: true };
|
|
170
194
|
},
|
|
171
195
|
todoPos(side) {
|
|
172
196
|
const p = normalizeTodoPos(side);
|
|
@@ -256,6 +280,12 @@ export function createStubCtx(bag, opts) {
|
|
|
256
280
|
bag.zoomOut = !!partial.zoomOut;
|
|
257
281
|
if (partial.title !== undefined)
|
|
258
282
|
bag.title = String(partial.title ?? "");
|
|
283
|
+
const bp = normalizeBannerPos(partial.titlePos);
|
|
284
|
+
if (bp)
|
|
285
|
+
bag.titlePos = bp;
|
|
286
|
+
if (partial.bannerUi && typeof partial.bannerUi === "object") {
|
|
287
|
+
bag.bannerUi = { ...(bag.bannerUi || {}), ...partial.bannerUi };
|
|
288
|
+
}
|
|
259
289
|
const tp = normalizeTodoPos(partial.todoPos);
|
|
260
290
|
if (tp)
|
|
261
291
|
bag.todoPos = tp;
|
|
@@ -279,3 +309,7 @@ export function liftLegacySlotTodos(bag) {
|
|
|
279
309
|
}
|
|
280
310
|
}
|
|
281
311
|
}
|
|
312
|
+
function normalizeBannerPos(raw) {
|
|
313
|
+
const v = String(raw ?? "").toLowerCase();
|
|
314
|
+
return v === "left" || v === "center" || v === "right" ? v : undefined;
|
|
315
|
+
}
|
|
@@ -41,6 +41,15 @@ export type WaygraphTodoInput = string | WaygraphTodoItem;
|
|
|
41
41
|
* - `bullets` - flat bullet list (no arrow/checkbox; open notes / trimmed dock)
|
|
42
42
|
*/
|
|
43
43
|
export type TodoListStyle = "sequential" | "checklist" | "bullets";
|
|
44
|
+
/** Where the top banner sits. */
|
|
45
|
+
export type BannerPos = "left" | "center" | "right";
|
|
46
|
+
/** Banner UX, mirrors {@link TodoDockUiOpts}: pass `false` fields to opt out for this phase. */
|
|
47
|
+
export interface BannerUiOpts {
|
|
48
|
+
/** Move to a free spot while a highlight ring would overlap it (default true). */
|
|
49
|
+
collision?: boolean;
|
|
50
|
+
/** Hide the banner entirely for this phase. */
|
|
51
|
+
hidden?: boolean;
|
|
52
|
+
}
|
|
44
53
|
/** One titled group in the floating todo dock (FR / Scenarios / ACs, etc.). */
|
|
45
54
|
export type WaygraphTodoGroupInput = {
|
|
46
55
|
/** Stable group id -> `data-wg-todo-group`. */
|
|
@@ -146,6 +155,10 @@ export type StubPhaseFixtures = {
|
|
|
146
155
|
zoomOut?: boolean;
|
|
147
156
|
/** Top demo banner title (the purple "waygraph demo" card). */
|
|
148
157
|
title?: string;
|
|
158
|
+
/** Banner side/position (`left` | `center` | `right`). Authored control, like {@link todoPos}. */
|
|
159
|
+
titlePos?: BannerPos;
|
|
160
|
+
/** Banner UX: collision (move away from a ring it overlaps), hidden. See {@link BannerUiOpts}. */
|
|
161
|
+
bannerUi?: BannerUiOpts;
|
|
149
162
|
/**
|
|
150
163
|
* Floating checklist dock side. `left` | `right`.
|
|
151
164
|
* Authored control (also click / WAYGRAPH_TODO_POS / --todo-left|right).
|
|
@@ -373,10 +386,25 @@ export type StubCtx<Out extends Checkpoint<string> = Checkpoint<string>> = {
|
|
|
373
386
|
* Default zoomOut for rings in this phase. `false` = keep camera between rings.
|
|
374
387
|
*/
|
|
375
388
|
zoomOut(keep: boolean): void;
|
|
376
|
-
/** Top banner title (waygraph demo card). */
|
|
377
|
-
title(text: string
|
|
389
|
+
/** Top banner title (waygraph demo card). `opts.pos` also places it (left | center | right). */
|
|
390
|
+
title(text: string, opts?: {
|
|
391
|
+
pos?: BannerPos;
|
|
392
|
+
}): void;
|
|
378
393
|
/** Alias for {@link StubCtx.title}. */
|
|
379
|
-
banner(text: string
|
|
394
|
+
banner(text: string, opts?: {
|
|
395
|
+
pos?: BannerPos;
|
|
396
|
+
}): void;
|
|
397
|
+
/** Place the banner: `left` | `center` | `right` (authored; click / env are fallbacks). */
|
|
398
|
+
titlePos(side: BannerPos): void;
|
|
399
|
+
/** Alias for {@link StubCtx.titlePos}. */
|
|
400
|
+
bannerPos(side: BannerPos): void;
|
|
401
|
+
/**
|
|
402
|
+
* Banner UX: `{ collision: false }` keeps it put even over a ring; `{ hidden: true }` hides it.
|
|
403
|
+
* @example ctx.bannerUi({ collision: false });
|
|
404
|
+
*/
|
|
405
|
+
bannerUi(opts: BannerUiOpts): void;
|
|
406
|
+
/** Shorthand for `bannerUi({ hidden: true })`. */
|
|
407
|
+
hideBanner(): void;
|
|
380
408
|
/**
|
|
381
409
|
* Floating checklist dock side (`left` | `right`). Authors control this in
|
|
382
410
|
* code; click / env / --todo-left|right are fallbacks.
|
|
@@ -433,6 +461,8 @@ export type StubPhaseResult = {
|
|
|
433
461
|
zoom?: number;
|
|
434
462
|
zoomOut?: boolean;
|
|
435
463
|
title?: string;
|
|
464
|
+
titlePos?: BannerPos;
|
|
465
|
+
bannerUi?: BannerUiOpts;
|
|
436
466
|
todoPos?: "left" | "right";
|
|
437
467
|
/** When true, keep other docks (multi-todo). Default false = replace. */
|
|
438
468
|
todoParallel?: boolean;
|
|
@@ -528,6 +558,8 @@ export type StubBagState = {
|
|
|
528
558
|
zoom?: number | undefined;
|
|
529
559
|
zoomOut?: boolean | undefined;
|
|
530
560
|
title?: string | undefined;
|
|
561
|
+
titlePos?: BannerPos | undefined;
|
|
562
|
+
bannerUi?: BannerUiOpts | undefined;
|
|
531
563
|
todoPos?: "left" | "right" | undefined;
|
|
532
564
|
/** Author patched todo-dock UX this phase. */
|
|
533
565
|
todoDockUi?: TodoDockUiOpts | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { registerMemStub, seedMemStub, getMemStub } from "./mem-stub.js";
|
|
|
5
5
|
export { Trait, urlMatches, textEquals, visible, disabled, enabled, frameVisible, frameTextEquals, frameContainsText, } from "./trait.js";
|
|
6
6
|
export { runGraph, spawnTab, narrate, Engine, start, end, branch, withVerify, modVerify, modVerifyAll, defineBlock, defineNavBlock, defineNavClickBlock, defineMethodBlock, defineActionBlock, defineAssertBlock, definePageBlock, defineEffectBlock, defineMemEffectBlock, defineMemNavBlock, locate, composeBlock, fastForwardComposeBlock, isFastForwardBlock, preflight, withSessionReset, withTitle, withMemStub, withDemoPace, withBlockPace, withHighlightStyle, withExpectedFailure, withHighlightFixtures, withStubBefore, withStubAfter, withStubOnError, chainFlow, defineLayout, map, MapBuilder, } from "./engine.js";
|
|
7
7
|
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";
|
|
8
|
-
export type { WaygraphHighlightStub, WaygraphHighlightFixture, WaygraphSlide, WaygraphTodoItem, WaygraphTodoInput, WaygraphTodoGroup, WaygraphTodoGroupInput, WaygraphTodosOpts, TodoDockUiOpts, 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";
|
|
8
|
+
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";
|
|
9
9
|
export type { Flow, EngineConfig, ComposedBlock, FastForwardComposedBlock, RunGraphOptions, BlockInfo, NavBlock, NavBlockOptions, NavClickBlock, NavClickBlockOptions, MethodBlock, ActionBlock, AssertBlock, AssertBlockOptions, PageBlock, PageBlockOptions, PageMethodEntry, EffectBlock, MemEffectBlock, MemNavBlock, Layout, LayoutOptions, MapBuilderOptions, } from "./engine.js";
|
|
10
10
|
export type { ActionPage } from "./types.js";
|
|
11
11
|
export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./graph.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DevicePreset, DeviceState, HighlightTone, TodoDockUiOpts } from "../highlights.js";
|
|
1
|
+
import type { BannerPos, BannerUiOpts, DevicePreset, DeviceState, HighlightTone, TodoDockUiOpts } from "../highlights.js";
|
|
2
2
|
import type { Page } from "@playwright/test";
|
|
3
3
|
/** One ring the Pilot agent wants painted (same fields as demo stub rings). */
|
|
4
4
|
export type PilotFixtureRing = {
|
|
@@ -68,6 +68,14 @@ export type PilotHighlightFixtures = {
|
|
|
68
68
|
device?: DevicePreset | DeviceState;
|
|
69
69
|
/** Drop every agent fixture ring/todo/focus/zoom immediately. */
|
|
70
70
|
clear?: boolean;
|
|
71
|
+
/** Top banner title card (same as `ctx.title`). */
|
|
72
|
+
title?: string;
|
|
73
|
+
/** Banner position (same as `ctx.titlePos`). */
|
|
74
|
+
titlePos?: BannerPos;
|
|
75
|
+
/** Banner UX: collision / hidden (same as `ctx.bannerUi`). */
|
|
76
|
+
bannerUi?: BannerUiOpts;
|
|
77
|
+
/** Alias of {@link todoUi} - the name `ctx.todoDockUi` uses. */
|
|
78
|
+
todoDockUi?: TodoDockUiOpts;
|
|
71
79
|
};
|
|
72
80
|
/**
|
|
73
81
|
* Paint (or clear) agent-authored highlight fixtures on the live page.
|
|
@@ -92,8 +92,41 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
92
92
|
: typeof fixtures.device === "string"
|
|
93
93
|
? fixtures.device
|
|
94
94
|
: fixtures.device.preset || "device";
|
|
95
|
+
const bannerTitle = fixtures.clear ? undefined : fixtures.title;
|
|
96
|
+
const bannerPos = fixtures.clear ? undefined : fixtures.titlePos;
|
|
97
|
+
const bannerHidden = !!fixtures.clear || !!fixtures.bannerUi?.hidden;
|
|
98
|
+
const bannerCollision = fixtures.bannerUi?.collision !== false;
|
|
95
99
|
return page
|
|
96
|
-
.evaluate(({ rings, todos, todoIndex, todoTitle, todoPos, holdMs, zoom, zoomSelector, zoomOut, clearAll, deviceLabel, todoUi, }) => {
|
|
100
|
+
.evaluate(({ rings, todos, todoIndex, todoTitle, todoPos, holdMs, zoom, zoomSelector, zoomOut, clearAll, deviceLabel, todoUi, bannerTitle, bannerPos, bannerHidden, bannerCollision, }) => {
|
|
101
|
+
// Same #wg-banner element/CSS the demo runner paints (ui/css/banner.css, already in the
|
|
102
|
+
// shared bundle) - so ctx.title / ctx.titlePos / ctx.bannerUi behave identically on a Pilot
|
|
103
|
+
// session, not a separate re-implementation.
|
|
104
|
+
if (bannerHidden) {
|
|
105
|
+
const b = __wgById("wg-banner");
|
|
106
|
+
if (b)
|
|
107
|
+
b.style.display = "none";
|
|
108
|
+
}
|
|
109
|
+
else if (bannerTitle) {
|
|
110
|
+
let banner = __wgById("wg-banner");
|
|
111
|
+
if (!banner) {
|
|
112
|
+
banner = document.createElement("div");
|
|
113
|
+
banner.id = "wg-banner";
|
|
114
|
+
const tag = document.createElement("span");
|
|
115
|
+
tag.className = "wg-banner-tag";
|
|
116
|
+
tag.textContent = "waygraph pilot";
|
|
117
|
+
const text = document.createElement("span");
|
|
118
|
+
text.className = "wg-banner-text";
|
|
119
|
+
banner.appendChild(tag);
|
|
120
|
+
banner.appendChild(text);
|
|
121
|
+
__wgAdd(banner);
|
|
122
|
+
}
|
|
123
|
+
banner.style.display = "";
|
|
124
|
+
banner.dataset.pos = bannerPos || banner.dataset.pos || "left";
|
|
125
|
+
banner.dataset.collision = bannerCollision ? "1" : "0";
|
|
126
|
+
const textEl = banner.querySelector(".wg-banner-text");
|
|
127
|
+
if (textEl)
|
|
128
|
+
textEl.textContent = bannerTitle;
|
|
129
|
+
}
|
|
97
130
|
const w = window;
|
|
98
131
|
if (w.__wgPilotFxHideTimer)
|
|
99
132
|
clearTimeout(w.__wgPilotFxHideTimer);
|
|
@@ -329,6 +362,10 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
329
362
|
clearAll: fixtures.clear === true,
|
|
330
363
|
deviceLabel,
|
|
331
364
|
todoUi,
|
|
365
|
+
bannerTitle,
|
|
366
|
+
bannerPos,
|
|
367
|
+
bannerHidden,
|
|
368
|
+
bannerCollision,
|
|
332
369
|
})
|
|
333
370
|
.catch(() => ({ painted: 0, missing: rings.map((r) => r.selector) }));
|
|
334
371
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { StubPhaseResult } from "../highlights.js";
|
|
2
|
+
import type { PilotHighlightFixtures } from "./fixtures.js";
|
|
3
|
+
/**
|
|
4
|
+
* Resolve agent-sent "waygraph overlay fixtures" (`auto highlight` JSON / shorthand) through the SAME
|
|
5
|
+
* stub-ctx path a Block's `stubBefore(ctx)` uses, so ctx.todos / ctx.device / ctx.title / ctx.bannerUi semantics
|
|
6
|
+
* (keep vs set vs clear, defaults, normalisation) cannot diverge between `waygraph demo` and pilot/auto/browser.
|
|
7
|
+
* Not Playwright test fixtures - these describe what the waygraph overlay paints on the page under test.
|
|
8
|
+
*/
|
|
9
|
+
export declare function overlayFixturesToPhase(f: PilotHighlightFixtures): Promise<StubPhaseResult>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { runStubPhase } from "../highlights.js";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve agent-sent "waygraph overlay fixtures" (`auto highlight` JSON / shorthand) through the SAME
|
|
4
|
+
* stub-ctx path a Block's `stubBefore(ctx)` uses, so ctx.todos / ctx.device / ctx.title / ctx.bannerUi semantics
|
|
5
|
+
* (keep vs set vs clear, defaults, normalisation) cannot diverge between `waygraph demo` and pilot/auto/browser.
|
|
6
|
+
* Not Playwright test fixtures - these describe what the waygraph overlay paints on the page under test.
|
|
7
|
+
*/
|
|
8
|
+
export async function overlayFixturesToPhase(f) {
|
|
9
|
+
const lifecycle = (ctx) => {
|
|
10
|
+
if (f.clear) {
|
|
11
|
+
ctx.hideTodos();
|
|
12
|
+
ctx.hideDevice();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (f.title !== undefined)
|
|
16
|
+
ctx.title(f.title, f.titlePos ? { pos: f.titlePos } : undefined);
|
|
17
|
+
else if (f.titlePos)
|
|
18
|
+
ctx.titlePos(f.titlePos);
|
|
19
|
+
if (f.bannerUi)
|
|
20
|
+
ctx.bannerUi(f.bannerUi);
|
|
21
|
+
if (f.todos !== undefined) {
|
|
22
|
+
ctx.todos("pilot", f.todos, {
|
|
23
|
+
title: f.todoTitle ?? "Plan",
|
|
24
|
+
index: f.todoIndex ?? 0,
|
|
25
|
+
pos: f.todoPos === "left" ? "left" : "right",
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const ui = f.todoDockUi ?? f.todoUi;
|
|
29
|
+
if (ui)
|
|
30
|
+
ctx.todoDockUi(ui);
|
|
31
|
+
if (f.device)
|
|
32
|
+
ctx.device(f.device);
|
|
33
|
+
if (typeof f.zoom === "number" && Number.isFinite(f.zoom) && f.zoom > 0)
|
|
34
|
+
ctx.zoom(f.zoom);
|
|
35
|
+
if (f.zoomOut !== undefined)
|
|
36
|
+
ctx.zoomOut(f.zoomOut);
|
|
37
|
+
if (f.rings?.length) {
|
|
38
|
+
f.rings.forEach((r, i) => {
|
|
39
|
+
const { selector, label, ...rest } = r;
|
|
40
|
+
ctx.ring(`ring${i + 1}`, { selector, label, ...rest });
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return runStubPhase({ name: "overlay-fixtures", stubBefore: lifecycle }, "stubBefore");
|
|
45
|
+
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// Split out of the former 950-line pilot-overlay.ts (see src/ARCHITECTURE.md). Behavior unchanged.
|
|
2
2
|
import { SURFACE } from "../ui/tokens.js";
|
|
3
3
|
import { ensureShadowRoot, installShadowRoot } from "../ui/shadow.js";
|
|
4
|
-
import { pilotFxRingCss } from "../ui/components/ring.js";
|
|
5
|
-
import { WAYGRAPH_RING_CSS } from "../highlights.js";
|
|
6
4
|
// Real, direct user request: this overlay's own colors were an improvised
|
|
7
5
|
// purple/white scheme (#a78bfa / #1a1033) that didn't match anything else -
|
|
8
6
|
// "our design here seems like barely shares with the ui on the stepper
|
|
@@ -64,26 +62,9 @@ const OVERLAY_CSS = `
|
|
|
64
62
|
opacity: 0; transform: translateY(4px); transition: opacity 0.15s, transform 0.15s;
|
|
65
63
|
}
|
|
66
64
|
#wg-pilot-activity.wg-pilot-toast-show { opacity: 1; transform: translateY(0); }
|
|
67
|
-
/* Agent
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
position:fixed;z-index:2147483645;top:72px;max-width:280px;max-height:calc(100vh - 100px);overflow:auto;
|
|
71
|
-
font:12px/1.4 ui-sans-serif,system-ui,sans-serif;color:#fff;
|
|
72
|
-
background:${SURFACE};border-radius:10px;padding:10px 12px;
|
|
73
|
-
box-shadow:0 2px 10px rgba(0,0,0,.3);pointer-events:auto;
|
|
74
|
-
transition:opacity .25s ease;
|
|
75
|
-
}
|
|
76
|
-
#wg-pilot-fx-todos.wg-todo-behind{z-index:2147483643;opacity:.42;pointer-events:none;}
|
|
77
|
-
#wg-pilot-fx-todos[data-pos=left]{left:14px;right:auto;}
|
|
78
|
-
#wg-pilot-fx-todos[data-pos=right]{right:14px;left:auto;}
|
|
79
|
-
#wg-pilot-fx-todos .wg-pilot-fx-todo-title{font-weight:700;color:#c9a6ff;margin-bottom:6px;}
|
|
80
|
-
#wg-pilot-fx-todos ol{margin:0;padding-left:18px;}
|
|
81
|
-
#wg-pilot-fx-todos li{margin:3px 0;color:#ddd;}
|
|
82
|
-
#wg-pilot-fx-todos li.wg-pilot-fx-todo-done{color:#888;text-decoration:line-through;}
|
|
83
|
-
#wg-pilot-fx-todos li.wg-pilot-fx-todo-now{color:#fff;font-weight:700;}
|
|
84
|
-
#wg-pilot-fx-todos[data-compact="1"]:not(:hover) li.wg-todo-fold{display:none;}
|
|
85
|
-
#wg-pilot-fx-todos .wg-todo-more{margin-top:6px;padding:4px 8px;border-radius:8px;
|
|
86
|
-
background:rgba(124,58,237,.22);font:700 11px/1.2 system-ui,sans-serif;color:#e8dcff;}
|
|
65
|
+
/* Agent fixture rings (.wg-pilot-fx-ring/label), #wg-pilot-fx-todos, #wg-ring/#wg-ring-label and
|
|
66
|
+
#wg-banner all come from the ONE shared bundle ensureShadowRoot installs (ui/css/*.css) - not
|
|
67
|
+
redefined here. */
|
|
87
68
|
/* Spotlight (demo focus:true) - dim page, cutout around target. */
|
|
88
69
|
#wg-pilot-fx-focus{position:fixed;z-index:2147483644;pointer-events:none;
|
|
89
70
|
border-radius:12px;box-shadow:0 0 0 9999px rgba(8,4,20,.62);
|
|
@@ -107,7 +88,7 @@ ${pilotFxRingCss()}
|
|
|
107
88
|
#wg-pilot-fx-device[data-preset=mobile]{border-color:#3B82F6;}
|
|
108
89
|
#wg-pilot-fx-device[data-preset=tablet]{border-color:#22C55E;}
|
|
109
90
|
#wg-pilot-fx-device[data-preset=desktop]{border-color:#9CA3AF;}
|
|
110
|
-
|
|
91
|
+
`;
|
|
111
92
|
/** Browser-side shell install — runs on every document via context.addInitScript. */
|
|
112
93
|
function installPilotOverlayShell(css) {
|
|
113
94
|
if (__wgById("wg-pilot-overlay"))
|
package/dist/pilot-overlay.d.ts
CHANGED
package/dist/pilot-overlay.js
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Banner (title card) authoring + verbose log helpers. Mirrors the todo dock's probe/log path
|
|
2
|
+
// so an agent without eyes can read banner state from the demo log.
|
|
3
|
+
import { demoLog } from "./demo-log.js";
|
|
4
|
+
|
|
5
|
+
/** Authored banner UX from a stub phase -> the { pos, collision, hidden } shape installOverlay takes. */
|
|
6
|
+
export function bannerUiFromPhase(phase) {
|
|
7
|
+
const ui = {};
|
|
8
|
+
if (phase && phase.titlePos) ui.pos = phase.titlePos;
|
|
9
|
+
if (phase && phase.bannerUi) {
|
|
10
|
+
if (phase.bannerUi.collision !== undefined) ui.collision = !!phase.bannerUi.collision;
|
|
11
|
+
if (phase.bannerUi.hidden !== undefined) ui.hidden = !!phase.bannerUi.hidden;
|
|
12
|
+
}
|
|
13
|
+
return ui;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Read the live banner: text, position, whether it was moved by ring collision; drains the move log. */
|
|
17
|
+
export async function probeBanner(page) {
|
|
18
|
+
return page
|
|
19
|
+
.evaluate(() => {
|
|
20
|
+
const b = __wgById("wg-banner");
|
|
21
|
+
const log = window.__wgBannerLog || [];
|
|
22
|
+
window.__wgBannerLog = [];
|
|
23
|
+
if (!b) return { present: false, log };
|
|
24
|
+
const r = b.getBoundingClientRect();
|
|
25
|
+
const text = b.querySelector(".wg-banner-text");
|
|
26
|
+
return {
|
|
27
|
+
present: true,
|
|
28
|
+
text: text ? text.textContent : "",
|
|
29
|
+
pos: b.dataset.pos || null,
|
|
30
|
+
home: b.dataset.home || null,
|
|
31
|
+
moved: b.dataset.moved || null,
|
|
32
|
+
collision: b.dataset.collision !== "0",
|
|
33
|
+
hidden: b.style.display === "none",
|
|
34
|
+
authored: b.dataset.authored === "1",
|
|
35
|
+
left: Math.round(r.left),
|
|
36
|
+
top: Math.round(r.top),
|
|
37
|
+
w: Math.round(r.width),
|
|
38
|
+
h: Math.round(r.height),
|
|
39
|
+
log,
|
|
40
|
+
};
|
|
41
|
+
})
|
|
42
|
+
.catch(() => ({ present: false, log: [] }));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function logBannerDom(tag, p) {
|
|
46
|
+
if (!p) return;
|
|
47
|
+
if (!p.present) {
|
|
48
|
+
demoLog(" " + tag + " banner-dom absent");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
demoLog(
|
|
52
|
+
" " + tag + " banner-dom " +
|
|
53
|
+
JSON.stringify(String(p.text || "").slice(0, 60)) +
|
|
54
|
+
"@" + p.pos +
|
|
55
|
+
(p.home && p.home !== p.pos ? " (home=" + p.home + ")" : "") +
|
|
56
|
+
" " + p.left + "," + p.top + " " + p.w + "x" + p.h +
|
|
57
|
+
" collision=" + (p.collision ? "on" : "off") +
|
|
58
|
+
(p.hidden ? " HIDDEN" : "") +
|
|
59
|
+
(p.authored ? " authored" : ""),
|
|
60
|
+
);
|
|
61
|
+
for (const line of p.log || []) demoLog(" " + tag + " banner " + line);
|
|
62
|
+
}
|
package/dist/runner/demo-log.js
CHANGED
|
@@ -109,8 +109,14 @@ function demoTs() {
|
|
|
109
109
|
);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
let logSurface = "demo";
|
|
113
|
+
/** Which surface is talking (demo | auto | browser | pilot) - same log format everywhere, only the tag differs. */
|
|
114
|
+
export function setDemoLogSurface(name) {
|
|
115
|
+
logSurface = String(name || "demo");
|
|
116
|
+
}
|
|
117
|
+
|
|
112
118
|
function demoPrefix() {
|
|
113
|
-
return ansiPaint(ANSI.dim, "[" + demoTs() + "]") + " waygraph
|
|
119
|
+
return ansiPaint(ANSI.dim, "[" + demoTs() + "]") + " waygraph " + logSurface + ": ";
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
export function demoLog(msg) {
|
|
@@ -170,6 +176,8 @@ export function logStubPhaseFixtures(phaseName, phase) {
|
|
|
170
176
|
const tag = "stub." + phaseName;
|
|
171
177
|
if (phase.title) demoFixture(tag, "ctx.title(...)", JSON.stringify(phase.title));
|
|
172
178
|
if (phase.banner) demoFixture(tag, "ctx.banner(...)", JSON.stringify(phase.banner));
|
|
179
|
+
if (phase.titlePos) demoFixture(tag, "ctx.titlePos(...)", JSON.stringify(phase.titlePos));
|
|
180
|
+
if (phase.bannerUi) demoFixture(tag, "ctx.bannerUi(...)", JSON.stringify(phase.bannerUi));
|
|
173
181
|
if (phase.deviceSync && phase.deviceSync !== "keep") {
|
|
174
182
|
demoFixture(
|
|
175
183
|
tag,
|