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
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// In-page installer (runs inside the browser via page.evaluate): must stay self-contained - no module-scope closure.
|
|
2
2
|
// Split out of the former single installOverlay evaluate (see src/ARCHITECTURE.md). Shares state only via window.__wg*.
|
|
3
3
|
/* eslint-disable no-unused-vars */
|
|
4
|
-
export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay, todoDockUi }) {
|
|
4
|
+
export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay, todoDockUi, bannerUi }) {
|
|
5
5
|
const POSITIONS = ["left", "center", "right"];
|
|
6
6
|
const applyPos = (el, pos) => {
|
|
7
7
|
el.dataset.pos = pos;
|
|
8
|
+
el.dataset.home = pos;
|
|
8
9
|
try {
|
|
9
10
|
localStorage.setItem("wg-banner-pos", pos);
|
|
10
11
|
} catch {
|
|
@@ -52,6 +53,60 @@ export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay,
|
|
|
52
53
|
text.textContent = title;
|
|
53
54
|
}
|
|
54
55
|
}
|
|
56
|
+
// Authored banner UX (StubCtx.titlePos / bannerUi): applied every step, wins over click/env.
|
|
57
|
+
if (bannerUi) {
|
|
58
|
+
const cur = window.__wgBannerUi || {};
|
|
59
|
+
window.__wgBannerUi = { ...cur, ...bannerUi };
|
|
60
|
+
}
|
|
61
|
+
const bui = window.__wgBannerUi || {};
|
|
62
|
+
const bannerEl = __wgById("wg-banner");
|
|
63
|
+
if (bannerEl) {
|
|
64
|
+
if (bui.pos && POSITIONS.includes(bui.pos) && bannerEl.dataset.home !== bui.pos) {
|
|
65
|
+
bannerEl.dataset.pos = bui.pos;
|
|
66
|
+
bannerEl.dataset.home = bui.pos;
|
|
67
|
+
bannerEl.dataset.authored = "1";
|
|
68
|
+
}
|
|
69
|
+
bannerEl.dataset.collision = bui.collision === false ? "0" : "1";
|
|
70
|
+
bannerEl.style.display = bui.hidden ? "none" : "";
|
|
71
|
+
}
|
|
72
|
+
// Move the banner out of the way of a highlight ring (mirrors the todo dock's collision flip).
|
|
73
|
+
window.__wgBannerAvoidRing = (box) => {
|
|
74
|
+
const b = __wgById("wg-banner");
|
|
75
|
+
if (!b || !box || b.dataset.collision === "0" || b.style.display === "none") return;
|
|
76
|
+
const pad = 10;
|
|
77
|
+
const hits = () => {
|
|
78
|
+
const r = b.getBoundingClientRect();
|
|
79
|
+
return !(
|
|
80
|
+
r.right < box.x - pad ||
|
|
81
|
+
r.left > box.x + box.width + pad ||
|
|
82
|
+
r.bottom < box.y - pad ||
|
|
83
|
+
r.top > box.y + box.height + pad
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
const home = b.dataset.home || b.dataset.pos || "left";
|
|
87
|
+
b.dataset.pos = home;
|
|
88
|
+
if (!hits()) {
|
|
89
|
+
delete b.dataset.moved;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
for (const cand of POSITIONS.filter((p) => p !== home)) {
|
|
93
|
+
b.dataset.pos = cand;
|
|
94
|
+
if (!hits()) {
|
|
95
|
+
b.dataset.moved = home + ">" + cand;
|
|
96
|
+
(window.__wgBannerLog = window.__wgBannerLog || []).push("moved " + home + " -> " + cand + " (ring overlap)");
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
b.dataset.pos = home;
|
|
101
|
+
b.dataset.moved = "none-free";
|
|
102
|
+
(window.__wgBannerLog = window.__wgBannerLog || []).push("overlap at every position (kept " + home + ")");
|
|
103
|
+
};
|
|
104
|
+
window.__wgBannerRestore = () => {
|
|
105
|
+
const b = __wgById("wg-banner");
|
|
106
|
+
if (!b) return;
|
|
107
|
+
if (b.dataset.home) b.dataset.pos = b.dataset.home;
|
|
108
|
+
delete b.dataset.moved;
|
|
109
|
+
};
|
|
55
110
|
// Tab title/favicon: a real navigation resets document.title and any
|
|
56
111
|
// <link rel="icon"> the new document brings, so re-check (not
|
|
57
112
|
// re-append) on every call instead of a one-time flag.
|
|
@@ -114,6 +114,7 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
114
114
|
ringLabel.style.top = labelTop + "px";
|
|
115
115
|
if (window.__wgTodosSetBehind) window.__wgTodosSetBehind(true);
|
|
116
116
|
if (window.__wgTodosAvoidRingCollision) window.__wgTodosAvoidRingCollision(box);
|
|
117
|
+
if (window.__wgBannerAvoidRing) window.__wgBannerAvoidRing(box);
|
|
117
118
|
};
|
|
118
119
|
/** Dim/lower floating todo docks while a ring caption is the focus. */
|
|
119
120
|
window.__wgTodosSetBehind = (on) => {
|
|
@@ -220,6 +221,7 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
220
221
|
if (ringLabel) ringLabel.style.opacity = "0";
|
|
221
222
|
if (window.__wgClearFocus) window.__wgClearFocus();
|
|
222
223
|
if (window.__wgTodosSetBehind) window.__wgTodosSetBehind(false);
|
|
224
|
+
if (window.__wgBannerRestore) window.__wgBannerRestore();
|
|
223
225
|
window.__wgTodoCollisionLocked = false;
|
|
224
226
|
__wgQA(".wg-todo-dock[data-tucked], #wg-todo-dock[data-tucked]").forEach((el) => {
|
|
225
227
|
delete el.dataset.tucked;
|
|
@@ -1,7 +1,5 @@
|
|
|
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
|
-
import { WAYGRAPH_RING_CSS } from "../highlights.js";
|
|
4
|
-
import { cursorCss } from "../ui/components/cursor.js";
|
|
5
3
|
import { SURFACE } from "../ui/tokens.js";
|
|
6
4
|
|
|
7
5
|
// ---------------------------------------------------------------------------
|
|
@@ -13,22 +11,11 @@ import { SURFACE } from "../ui/tokens.js";
|
|
|
13
11
|
// label-under-box language, minus everything camera/narration-specific).
|
|
14
12
|
// Purely CLI-level orchestration - no engine changes, no change to the
|
|
15
13
|
// non-STEP path above.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// Mouse cursor icon that travels to a target before it's acted on, plus a
|
|
22
|
-
// quick expanding ripple at the moment of a click - same idea as
|
|
23
|
-
// help-center-clip-engine's #clip-cursor/#clip-ring (video-pipeline). The
|
|
24
|
-
// shape itself is an inline SVG set as innerHTML in installOverlay below
|
|
25
|
-
// (dark fill + white stroke, same as the clip-engine's own cursor) - a
|
|
26
|
-
// plain solid-white CSS clip-path (the first attempt here) had no outline
|
|
27
|
-
// at all and all but disappeared against this app's light background.
|
|
28
|
-
// Travel duration is JS-driven per call via --wg-cursor-ms, same reason
|
|
29
|
-
// the clip engine's own comment gives: a hardcoded CSS duration would
|
|
30
|
-
// make the speed param a no-op.
|
|
31
|
-
cursorCss() +
|
|
14
|
+
// Runner-only chrome (step panel, todo-dock legacy variant, zoom/typing/device chips) - NOT
|
|
15
|
+
// ring/cursor/banner, which come from the one shared bundle every surface installs
|
|
16
|
+
// (ui/css/*.css, see ensureShadowRoot in overlay-install.js). Injected under its own key so it
|
|
17
|
+
// never collides with that bundle.
|
|
18
|
+
export const RUNNER_EXTRA_CSS =
|
|
32
19
|
// Spotlight: dim everything except the highlight target (focus: true).
|
|
33
20
|
"#wg-focus-veil{position:fixed;z-index:2147483644;pointer-events:none;" +
|
|
34
21
|
"border-radius:12px;box-shadow:0 0 0 9999px rgba(8,4,20,.62);" +
|
|
@@ -225,15 +212,7 @@ export const RING_CSS =
|
|
|
225
212
|
"#wg-modules .wg-mod-done{background:#2a1650;color:#9a7ad1;}" +
|
|
226
213
|
"#wg-modules .wg-mod-current{background:#7C3AED;color:#fff;}" +
|
|
227
214
|
"#wg-modules .wg-mod-upcoming{background:transparent;color:#5a4a80;border:1px solid #3a2a60;}" +
|
|
228
|
-
|
|
229
|
-
"background:" + SURFACE + ";color:#fff;border-radius:12px;padding:10px 16px;" +
|
|
230
|
-
"font:14px/1.4 system-ui,sans-serif;box-shadow:0 8px 20px rgba(0,0,0,.3);" +
|
|
231
|
-
"border:1px solid rgba(124,58,237,.4);cursor:pointer;user-select:none;}" +
|
|
232
|
-
"#wg-banner[data-pos=left]{left:14px;right:auto;transform:none;}" +
|
|
233
|
-
"#wg-banner[data-pos=center]{left:50%;right:auto;transform:translateX(-50%);}" +
|
|
234
|
-
"#wg-banner[data-pos=right]{right:14px;left:auto;transform:none;}" +
|
|
235
|
-
"#wg-banner .wg-banner-tag{display:block;font-size:10px;font-weight:700;color:#c9a6ff;" +
|
|
236
|
-
"letter-spacing:.05em;text-transform:uppercase;margin-bottom:2px;}" +
|
|
215
|
+
// #wg-banner: comes from the shared bundle (ui/css/banner.css) now - not redefined here.
|
|
237
216
|
"#wg-panel .wg-key{margin:8px 0;}" +
|
|
238
217
|
// A live, human-readable preview of what's about to be written for this
|
|
239
218
|
// MemKey - Dan: "i want pretty to exist in memkeys too... it shows what
|
|
@@ -1,6 +1,6 @@
|
|
|
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
|
-
import { HOST_CSS,
|
|
3
|
+
import { HOST_CSS, RUNNER_EXTRA_CSS, WAYGRAPH_FAVICON } from "./overlay-css.js";
|
|
4
4
|
import { ensureShadowRoot } from "../ui/shadow.js";
|
|
5
5
|
import { resolveTodoDockUi } from "../highlights.js";
|
|
6
6
|
import { installCore } from "./inpage/core.js";
|
|
@@ -12,9 +12,12 @@ import { installTodos } from "./inpage/todos.js";
|
|
|
12
12
|
import { installDevice } from "./inpage/device.js";
|
|
13
13
|
import { applyVideoDeviceStage } from "./device-stage.js";
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
/** `ui` = authored banner UX from the stub phase: { pos, collision, hidden } (all optional). */
|
|
16
|
+
export async function installOverlay(page, title, ui) {
|
|
17
|
+
// ring/cursor/banner/dock come from the ONE shared bundle every surface installs (ui/css/*.css).
|
|
16
18
|
await ensureShadowRoot(page);
|
|
17
|
-
|
|
19
|
+
// Runner-only chrome (step panel, zoom/typing/device chips) - separate key, no collision.
|
|
20
|
+
await page.evaluate(([css, key]) => __wgCss(css, key), [RUNNER_EXTRA_CSS, "wg-runner-css"]).catch(() => {});
|
|
18
21
|
await page.addStyleTag({ content: HOST_CSS }).catch(() => {});
|
|
19
22
|
// Default top-left; override with WAYGRAPH_TITLE_POS=left|center|right.
|
|
20
23
|
// Click cycles left -> center -> right (persisted in localStorage so a
|
|
@@ -25,7 +28,7 @@ export async function installOverlay(page, title) {
|
|
|
25
28
|
const todoPos = envTodoPos === "right" ? "right" : "left";
|
|
26
29
|
const envAutoplay = process.env.WAYGRAPH_AUTOPLAY === "1";
|
|
27
30
|
const todoDockUi = resolveTodoDockUi();
|
|
28
|
-
const args = { title, favicon: WAYGRAPH_FAVICON, bannerPos, todoPos, envAutoplay, todoDockUi };
|
|
31
|
+
const args = { title, favicon: WAYGRAPH_FAVICON, bannerPos, todoPos, envAutoplay, todoDockUi, bannerUi: ui || null };
|
|
29
32
|
await page.evaluate(installCore, args).catch(() => {});
|
|
30
33
|
await page.evaluate(installSwipeZoom, args).catch(() => {});
|
|
31
34
|
await page.evaluate(installBanner, args).catch(() => {});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Page } from "@playwright/test";
|
|
2
|
+
import type { StubPhaseResult } from "../highlights/types.js";
|
|
3
|
+
|
|
4
|
+
export interface SessionOverlay {
|
|
5
|
+
present(tag: string, phase: Partial<StubPhaseResult>): Promise<void>;
|
|
6
|
+
restore(): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export function createSessionOverlay(page: Page, surface: string): SessionOverlay;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Presents a resolved stub phase ("waygraph overlay fixtures": ctx.todos / device / title / banner ...) on a LIVE page
|
|
2
|
+
// for the session surfaces (auto / browser / pilot). Same OverlayStage + same in-page installers + same verbose log
|
|
3
|
+
// lines as `waygraph demo`, so an overlay fixture behaves identically on every surface. Rings are painted separately
|
|
4
|
+
// (pilot holds them; demo cycles them) - that is the only intended difference.
|
|
5
|
+
import { installOverlay } from "./overlay-install.js";
|
|
6
|
+
import { createOverlayStage } from "./overlay-stage.js";
|
|
7
|
+
import { demoLog, logStubPhaseFixtures, logTodoDockFull, setDemoLogSurface, summarizeDevice } from "./demo-log.js";
|
|
8
|
+
import { logBannerDom, probeBanner } from "./banner-log.js";
|
|
9
|
+
import { probeTodoDocksOnPage } from "./todo-dock.js";
|
|
10
|
+
|
|
11
|
+
export function createSessionOverlay(page, surface) {
|
|
12
|
+
setDemoLogSurface(surface);
|
|
13
|
+
const stage = createOverlayStage(page, { todoDockRef: { current: undefined }, deviceRef: { current: undefined } });
|
|
14
|
+
let title = undefined;
|
|
15
|
+
let painted = false;
|
|
16
|
+
|
|
17
|
+
const paintChrome = async (phaseParallel) => {
|
|
18
|
+
await installOverlay(page, title, stage.state.lastBannerUi);
|
|
19
|
+
await stage.syncAllTodoDocks({ parallel: !!phaseParallel });
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
stage,
|
|
24
|
+
/** Apply one phase (tag = before | after | error | highlight) and log the resulting overlay state. */
|
|
25
|
+
async present(tag, phase) {
|
|
26
|
+
setDemoLogSurface(surface);
|
|
27
|
+
logStubPhaseFixtures(tag, phase);
|
|
28
|
+
await stage.pushTodoDockUi(phase.todoDockUi);
|
|
29
|
+
const { appliedTodo, appliedDevice } = await stage.applyPhase(phase, { reapplyDeviceOnKeep: true });
|
|
30
|
+
if (phase.title && String(phase.title).trim()) title = String(phase.title).trim();
|
|
31
|
+
const wantsChrome = !!(title || stage.state.lastTodoDock || phase.todoSync === "set");
|
|
32
|
+
if (wantsChrome) {
|
|
33
|
+
painted = true;
|
|
34
|
+
await paintChrome(phase.todoParallel);
|
|
35
|
+
}
|
|
36
|
+
logTodoDockFull(stage.state.lastTodoDock, " " + tag);
|
|
37
|
+
demoLog(" " + tag + " device=" + summarizeDevice(stage.state.lastDevice) + " deviceSync=" + appliedDevice.sync);
|
|
38
|
+
demoLog(" " + tag + " todoSync=" + appliedTodo.sync);
|
|
39
|
+
const docks = await probeTodoDocksOnPage(page);
|
|
40
|
+
if (!docks.length && stage.state.lastTodoDock && appliedTodo.sync !== "clear") {
|
|
41
|
+
demoLog(" WARN " + tag + ": todos authored but dock-dom empty (not painted?)");
|
|
42
|
+
}
|
|
43
|
+
for (const d of docks) {
|
|
44
|
+
demoLog(
|
|
45
|
+
" " + tag + " dock-dom " + d.key + "@" + d.pos + " " + d.left + "," + d.top + " " + d.w + "x" + d.h +
|
|
46
|
+
(d.onScreen ? "" : " OFFSCREEN") + " n=" + d.n + (d.current ? ' cur="' + d.current + '"' : ""),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
if (title || painted) logBannerDom(tag, await probeBanner(page));
|
|
50
|
+
},
|
|
51
|
+
/** A navigation wipes the overlay DOM: rebuild what was authored (same job as the demo's post-navigation restore). */
|
|
52
|
+
async restore() {
|
|
53
|
+
if (!painted) return;
|
|
54
|
+
await paintChrome(false);
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// The waygraph OVERLAY stage: one owner of overlay state (todo docks, device, banner UX) and of how a resolved
|
|
2
|
+
// stub phase is applied to the page. demo / auto / browser / pilot all go through this, so a "waygraph overlay
|
|
3
|
+
// fixture" (ctx.todos / ctx.device / ctx.title / ...) means the same thing on every surface.
|
|
4
|
+
// NOT Playwright test fixtures - these paint the waygraph overlay on the page under test.
|
|
5
|
+
import { applyDevicePhase, applyTodoPhase, resolveTodoDockUi } from "../highlights.js";
|
|
6
|
+
import { applyDeviceToPage } from "./device-stage.js";
|
|
7
|
+
import { bannerUiFromPhase } from "./banner-log.js";
|
|
8
|
+
|
|
9
|
+
export function createOverlayStage(page, { todoDockRef, deviceRef }) {
|
|
10
|
+
/** Carried across steps: omitting a fixture in a later phase = keep (todos, device, banner UX). */
|
|
11
|
+
const state = { lastTodoDock: undefined, lastDevice: undefined, lastBannerUi: {} };
|
|
12
|
+
/** Author todoDockUi patches (merged); resolved against env each step. */
|
|
13
|
+
let lastTodoDockUiPatch = undefined;
|
|
14
|
+
/** Multi-todo: every dock keyed by todoId (or "_default"), survives navigation. */
|
|
15
|
+
const todoDockById = new Map();
|
|
16
|
+
|
|
17
|
+
const pushTodoDockUi = async (patch) => {
|
|
18
|
+
if (patch && typeof patch === "object") {
|
|
19
|
+
lastTodoDockUiPatch = { ...(lastTodoDockUiPatch || {}), ...patch };
|
|
20
|
+
}
|
|
21
|
+
const ui = resolveTodoDockUi(lastTodoDockUiPatch);
|
|
22
|
+
await page
|
|
23
|
+
.evaluate((u) => {
|
|
24
|
+
window.__wgTodoDockUi = u;
|
|
25
|
+
}, ui)
|
|
26
|
+
.catch(() => {});
|
|
27
|
+
};
|
|
28
|
+
const dockRegistryKey = (dock) =>
|
|
29
|
+
dock && dock.id && String(dock.id).trim() ? String(dock.id).trim() : "_default";
|
|
30
|
+
const rememberTodoDock = (dock, sync, parallel) => {
|
|
31
|
+
if (sync === "clear") {
|
|
32
|
+
todoDockById.clear();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (sync === "set" && dock) {
|
|
36
|
+
if (!parallel) todoDockById.clear();
|
|
37
|
+
todoDockById.set(dockRegistryKey(dock), dock);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// keep: refresh / re-seed so syncAllTodoDocks never sees an empty map
|
|
41
|
+
// while lastTodoDock still carries (nav wipe + mid-act advance).
|
|
42
|
+
if (sync === "keep" && dock) {
|
|
43
|
+
todoDockById.set(dockRegistryKey(dock), dock);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const syncAllTodoDocks = async (opts) => {
|
|
47
|
+
const docks = [...todoDockById.values()];
|
|
48
|
+
const parallel = !!(opts && opts.parallel);
|
|
49
|
+
if (!docks.length) {
|
|
50
|
+
// Empty registry: do NOT clear the DOM. renderBefore/After may have
|
|
51
|
+
// just painted from lastTodoDock (keep). Clearing here made todos
|
|
52
|
+
// vanish until the next ctx.todos() set (PIA #15).
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
await page
|
|
56
|
+
.evaluate(
|
|
57
|
+
({ list, parallel }) => {
|
|
58
|
+
if (!window.__wgSyncTodos) return;
|
|
59
|
+
for (let i = 0; i < list.length; i++) {
|
|
60
|
+
const d = list[i];
|
|
61
|
+
window.__wgSyncTodos({
|
|
62
|
+
sync: "set",
|
|
63
|
+
dock: d,
|
|
64
|
+
todoId: (d && d.id) || null,
|
|
65
|
+
pos: (d && d.pos) || null,
|
|
66
|
+
// First dock replaces; later ones keep siblings when parallel.
|
|
67
|
+
replace: !(parallel && i > 0),
|
|
68
|
+
parallel: parallel && i > 0,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{ list: docks, parallel },
|
|
73
|
+
)
|
|
74
|
+
.catch(() => {});
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Merge one resolved stub phase (banner UX, todo dock, device) into the carried state and push it to the page.
|
|
79
|
+
* `reapplyDeviceOnKeep`: also re-apply the carried device when the phase says keep (after a navigation wipe).
|
|
80
|
+
*/
|
|
81
|
+
const applyPhase = async (phase, { reapplyDeviceOnKeep = false } = {}) => {
|
|
82
|
+
state.lastBannerUi = { ...state.lastBannerUi, ...bannerUiFromPhase(phase) };
|
|
83
|
+
const appliedTodo = applyTodoPhase(state.lastTodoDock, {
|
|
84
|
+
todoSync: phase.todoSync,
|
|
85
|
+
todoDock: phase.todoDock,
|
|
86
|
+
todos: phase.todos,
|
|
87
|
+
todoPos: phase.todoPos,
|
|
88
|
+
});
|
|
89
|
+
state.lastTodoDock = appliedTodo.dock;
|
|
90
|
+
todoDockRef.current = state.lastTodoDock;
|
|
91
|
+
rememberTodoDock(appliedTodo.dock, appliedTodo.sync, !!phase.todoParallel);
|
|
92
|
+
const appliedDevice = applyDevicePhase(state.lastDevice, {
|
|
93
|
+
deviceSync: phase.deviceSync,
|
|
94
|
+
device: phase.device,
|
|
95
|
+
});
|
|
96
|
+
state.lastDevice = appliedDevice.device;
|
|
97
|
+
deviceRef.current = state.lastDevice;
|
|
98
|
+
if (appliedDevice.sync !== "keep" || (reapplyDeviceOnKeep && state.lastDevice)) {
|
|
99
|
+
await applyDeviceToPage(page, state.lastDevice, appliedDevice.sync);
|
|
100
|
+
}
|
|
101
|
+
return { appliedTodo, appliedDevice };
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
return { state, pushTodoDockUi, rememberTodoDock, syncAllTodoDocks, applyPhase };
|
|
105
|
+
}
|
package/dist/runner/step-mode.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
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 {
|
|
4
|
+
import { applyHighlightStyleDefaults, 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
|
-
import { applyDeviceToPage } from "./device-stage.js";
|
|
8
7
|
import { extractVerifyHighlights, presentFailPanel, renderAfterStep, renderBeforeStep } from "./step-panels.js";
|
|
9
8
|
import { probeTodoDocksOnPage } from "./todo-dock.js";
|
|
9
|
+
import { logBannerDom, probeBanner } from "./banner-log.js";
|
|
10
|
+
import { createOverlayStage } from "./overlay-stage.js";
|
|
10
11
|
import { join } from "node:path";
|
|
11
12
|
import { presentSlides } from "./slides.js";
|
|
12
13
|
|
|
@@ -26,9 +27,9 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
26
27
|
const stepperMode = process.env.WAYGRAPH_STEPPER === "full" ? "full" : "carousel";
|
|
27
28
|
const pacing = { gatesFast: demoFast, gatesSlow: false, skipTheater: false, demoPace: "normal" };
|
|
28
29
|
const stubBeforeRef = { current: [] };
|
|
29
|
-
/** Live todo dock for Method fill/click advance (same carry as lastTodoDock). */
|
|
30
|
+
/** Live todo dock for Method fill/click advance (same carry as stage.state.lastTodoDock). */
|
|
30
31
|
const todoDockRef = { current: undefined };
|
|
31
|
-
/** Live device fixture for touch theater (same carry as lastDevice). */
|
|
32
|
+
/** Live device fixture for touch theater (same carry as stage.state.lastDevice). */
|
|
32
33
|
const deviceRef = { current: undefined };
|
|
33
34
|
instrumentInteractionHighlighting(page, mem, slowMo, pacing, stubBeforeRef, todoDockRef, deviceRef);
|
|
34
35
|
// Force the panel checkbox from this process's flags/env at run start.
|
|
@@ -158,73 +159,8 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
158
159
|
}
|
|
159
160
|
|
|
160
161
|
let result;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
/** Author todoDockUi patches (merged); resolved against env each step. */
|
|
164
|
-
let lastTodoDockUiPatch = undefined;
|
|
165
|
-
/** Multi-todo: every dock keyed by todoId (or "_default"), survives navigation. */
|
|
166
|
-
const todoDockById = new Map();
|
|
167
|
-
const pushTodoDockUi = async (patch) => {
|
|
168
|
-
if (patch && typeof patch === "object") {
|
|
169
|
-
lastTodoDockUiPatch = { ...(lastTodoDockUiPatch || {}), ...patch };
|
|
170
|
-
}
|
|
171
|
-
const ui = resolveTodoDockUi(lastTodoDockUiPatch);
|
|
172
|
-
await page
|
|
173
|
-
.evaluate((u) => {
|
|
174
|
-
window.__wgTodoDockUi = u;
|
|
175
|
-
}, ui)
|
|
176
|
-
.catch(() => {});
|
|
177
|
-
};
|
|
178
|
-
const dockRegistryKey = (dock) =>
|
|
179
|
-
dock && dock.id && String(dock.id).trim() ? String(dock.id).trim() : "_default";
|
|
180
|
-
const rememberTodoDock = (dock, sync, parallel) => {
|
|
181
|
-
if (sync === "clear") {
|
|
182
|
-
todoDockById.clear();
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
if (sync === "set" && dock) {
|
|
186
|
-
if (!parallel) todoDockById.clear();
|
|
187
|
-
todoDockById.set(dockRegistryKey(dock), dock);
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
// keep: refresh / re-seed so syncAllTodoDocks never sees an empty map
|
|
191
|
-
// while lastTodoDock still carries (nav wipe + mid-act advance).
|
|
192
|
-
if (sync === "keep" && dock) {
|
|
193
|
-
todoDockById.set(dockRegistryKey(dock), dock);
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
const syncAllTodoDocks = async (opts) => {
|
|
197
|
-
const docks = [...todoDockById.values()];
|
|
198
|
-
const parallel = !!(opts && opts.parallel);
|
|
199
|
-
if (!docks.length) {
|
|
200
|
-
// Empty registry: do NOT clear the DOM. renderBefore/After may have
|
|
201
|
-
// just painted from lastTodoDock (keep). Clearing here made todos
|
|
202
|
-
// vanish until the next ctx.todos() set (PIA #15).
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
await page
|
|
206
|
-
.evaluate(
|
|
207
|
-
({ list, parallel }) => {
|
|
208
|
-
if (!window.__wgSyncTodos) return;
|
|
209
|
-
for (let i = 0; i < list.length; i++) {
|
|
210
|
-
const d = list[i];
|
|
211
|
-
window.__wgSyncTodos({
|
|
212
|
-
sync: "set",
|
|
213
|
-
dock: d,
|
|
214
|
-
todoId: (d && d.id) || null,
|
|
215
|
-
pos: (d && d.pos) || null,
|
|
216
|
-
// First dock replaces; later ones keep siblings when parallel.
|
|
217
|
-
replace: !(parallel && i > 0),
|
|
218
|
-
parallel: parallel && i > 0,
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
{ list: docks, parallel },
|
|
223
|
-
)
|
|
224
|
-
.catch(() => {});
|
|
225
|
-
};
|
|
226
|
-
/** Carry device / touch fixture across steps (omit = keep, like todos). */
|
|
227
|
-
let lastDevice = undefined;
|
|
162
|
+
const stage = createOverlayStage(page, { todoDockRef, deviceRef });
|
|
163
|
+
const { pushTodoDockUi, rememberTodoDock, syncAllTodoDocks } = stage;
|
|
228
164
|
for (let i = 0; i < resolved.length; i++) {
|
|
229
165
|
const r = resolved[i];
|
|
230
166
|
// The block breadcrumb is scoped to THIS step's own episode, not the
|
|
@@ -322,26 +258,12 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
322
258
|
label: formatHighlightCaption(h),
|
|
323
259
|
})),
|
|
324
260
|
});
|
|
325
|
-
const appliedBefore =
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
todoPos: stubBeforePhase.todoPos,
|
|
330
|
-
});
|
|
331
|
-
lastTodoDock = appliedBefore.dock;
|
|
332
|
-
todoDockRef.current = lastTodoDock;
|
|
333
|
-
rememberTodoDock(appliedBefore.dock, appliedBefore.sync, !!stubBeforePhase.todoParallel);
|
|
334
|
-
const appliedDeviceBefore = applyDevicePhase(lastDevice, {
|
|
335
|
-
deviceSync: stubBeforePhase.deviceSync,
|
|
336
|
-
device: stubBeforePhase.device,
|
|
337
|
-
});
|
|
338
|
-
lastDevice = appliedDeviceBefore.device;
|
|
339
|
-
deviceRef.current = lastDevice;
|
|
340
|
-
if (appliedDeviceBefore.sync !== "keep" || lastDevice) {
|
|
341
|
-
await applyDeviceToPage(page, lastDevice, appliedDeviceBefore.sync);
|
|
342
|
-
}
|
|
261
|
+
const { appliedTodo: appliedBefore, appliedDevice: appliedDeviceBefore } = await stage.applyPhase(
|
|
262
|
+
stubBeforePhase,
|
|
263
|
+
{ reapplyDeviceOnKeep: true },
|
|
264
|
+
);
|
|
343
265
|
const stubBeforeTodos =
|
|
344
|
-
(lastTodoDock && lastTodoDock.groups[0] && lastTodoDock.groups[0].items) ||
|
|
266
|
+
(stage.state.lastTodoDock && stage.state.lastTodoDock.groups[0] && stage.state.lastTodoDock.groups[0].items) ||
|
|
345
267
|
stubBeforePhase.todos ||
|
|
346
268
|
[];
|
|
347
269
|
const overlayTitle =
|
|
@@ -350,7 +272,7 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
350
272
|
title ||
|
|
351
273
|
"waygraph demo";
|
|
352
274
|
const overlayTodoPos =
|
|
353
|
-
(lastTodoDock && lastTodoDock.pos) || stubBeforePhase.todoPos || undefined;
|
|
275
|
+
(stage.state.lastTodoDock && stage.state.lastTodoDock.pos) || stubBeforePhase.todoPos || undefined;
|
|
354
276
|
const isNavBlock = r.block.__waygraphKind === "nav";
|
|
355
277
|
const autoNow = await currentAutoplay();
|
|
356
278
|
// Video / --mini: compact pill. Never pass false - Hide/localStorage wins.
|
|
@@ -391,7 +313,7 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
391
313
|
" gatesFast=" +
|
|
392
314
|
!!pacing.gatesFast,
|
|
393
315
|
);
|
|
394
|
-
demoLog(" " + summarizeDevice(lastDevice));
|
|
316
|
+
demoLog(" " + summarizeDevice(stage.state.lastDevice));
|
|
395
317
|
const phaseZoom =
|
|
396
318
|
stubBeforePhase.zoom != null && Number(stubBeforePhase.zoom) > 0
|
|
397
319
|
? Number(stubBeforePhase.zoom)
|
|
@@ -404,7 +326,7 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
404
326
|
(phaseZoomOut != null ? " zoomOut=" + phaseZoomOut : "") +
|
|
405
327
|
" (StubCtx / API; live chip top-left when ring zoom >1)",
|
|
406
328
|
);
|
|
407
|
-
logTodoDockFull(lastTodoDock, " before");
|
|
329
|
+
logTodoDockFull(stage.state.lastTodoDock, " before");
|
|
408
330
|
demoLog(" todoSync=" + appliedBefore.sync);
|
|
409
331
|
}
|
|
410
332
|
await renderBeforeStep(page, {
|
|
@@ -419,22 +341,23 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
419
341
|
allEpisodes,
|
|
420
342
|
justEnteredEpisode,
|
|
421
343
|
title: overlayTitle,
|
|
344
|
+
bannerUi: stage.state.lastBannerUi,
|
|
422
345
|
todoPos: overlayTodoPos,
|
|
423
346
|
episodeNumber: r.episodeNumber,
|
|
424
347
|
episodeTitle: r.episodeTitle,
|
|
425
348
|
stepperMode,
|
|
426
349
|
forceCollapsed,
|
|
427
350
|
todos: stubBeforeTodos,
|
|
428
|
-
todoDock: lastTodoDock,
|
|
351
|
+
todoDock: stage.state.lastTodoDock,
|
|
429
352
|
todoSync: appliedBefore.sync,
|
|
430
|
-
todoId: lastTodoDock && lastTodoDock.id,
|
|
353
|
+
todoId: stage.state.lastTodoDock && stage.state.lastTodoDock.id,
|
|
431
354
|
...paceSpeak,
|
|
432
355
|
});
|
|
433
356
|
// Re-paint dock(s) - renderBeforeStep syncs the active one; this enforces replace.
|
|
434
357
|
await syncAllTodoDocks({ parallel: !!stubBeforePhase.todoParallel });
|
|
435
358
|
if (process.env.WAYGRAPH_JSON !== "1") {
|
|
436
359
|
const docks = await probeTodoDocksOnPage(page);
|
|
437
|
-
if (!docks.length && lastTodoDock) {
|
|
360
|
+
if (!docks.length && stage.state.lastTodoDock) {
|
|
438
361
|
demoLog(" WARN todos authored but dock-dom empty (not painted?)");
|
|
439
362
|
} else if (docks.length) {
|
|
440
363
|
demoLog(
|
|
@@ -462,6 +385,7 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
462
385
|
);
|
|
463
386
|
}
|
|
464
387
|
}
|
|
388
|
+
if (process.env.WAYGRAPH_JSON !== "1") logBannerDom("before", await probeBanner(page));
|
|
465
389
|
const edits = await gate();
|
|
466
390
|
for (const k of requires) {
|
|
467
391
|
if (edits[k.name] !== undefined) {
|
|
@@ -554,9 +478,9 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
554
478
|
.catch(() => {});
|
|
555
479
|
result = stepOutcome.result;
|
|
556
480
|
// Mid-act Method fill/click advances live on todoDockRef - fold that
|
|
557
|
-
// back into lastTodoDock before stubAfter / next-block keep, or the
|
|
481
|
+
// back into stage.state.lastTodoDock before stubAfter / next-block keep, or the
|
|
558
482
|
// next step reverts to the pre-act (blank / index-0) checklist.
|
|
559
|
-
if (todoDockRef.current) lastTodoDock = todoDockRef.current;
|
|
483
|
+
if (todoDockRef.current) stage.state.lastTodoDock = todoDockRef.current;
|
|
560
484
|
// withExpectedFailure last block that SUCCEEDS on the intentional fail
|
|
561
485
|
// branch (e.g. submit-login -> LoginPage + error banner). Still show
|
|
562
486
|
// stubOnError rings + amber "expected outcome" panel - branching no
|
|
@@ -621,8 +545,8 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
621
545
|
let stubAfterTodos = [];
|
|
622
546
|
let afterOverlayTitle = overlayTitle;
|
|
623
547
|
let afterTodoPos = overlayTodoPos;
|
|
624
|
-
let appliedAfter = { dock: lastTodoDock, sync: "keep" };
|
|
625
|
-
let appliedDeviceAfter = { device: lastDevice, sync: "keep" };
|
|
548
|
+
let appliedAfter = { dock: stage.state.lastTodoDock, sync: "keep" };
|
|
549
|
+
let appliedDeviceAfter = { device: stage.state.lastDevice, sync: "keep" };
|
|
626
550
|
let afterTodoParallel = false;
|
|
627
551
|
if (hasAuthoredStubAfter(r.block, result, fixturesAfter)) {
|
|
628
552
|
const afterPhase = await runStubPhase(r.block, "stubAfter", {
|
|
@@ -641,33 +565,16 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
641
565
|
}),
|
|
642
566
|
});
|
|
643
567
|
afterTodoParallel = !!afterPhase.todoParallel;
|
|
644
|
-
appliedAfter =
|
|
645
|
-
todoSync: afterPhase.todoSync,
|
|
646
|
-
todoDock: afterPhase.todoDock,
|
|
647
|
-
todos: afterPhase.todos,
|
|
648
|
-
todoPos: afterPhase.todoPos,
|
|
649
|
-
});
|
|
650
|
-
lastTodoDock = appliedAfter.dock;
|
|
651
|
-
todoDockRef.current = lastTodoDock;
|
|
652
|
-
rememberTodoDock(appliedAfter.dock, appliedAfter.sync, afterTodoParallel);
|
|
653
|
-
appliedDeviceAfter = applyDevicePhase(lastDevice, {
|
|
654
|
-
deviceSync: afterPhase.deviceSync,
|
|
655
|
-
device: afterPhase.device,
|
|
656
|
-
});
|
|
657
|
-
lastDevice = appliedDeviceAfter.device;
|
|
658
|
-
deviceRef.current = lastDevice;
|
|
659
|
-
if (appliedDeviceAfter.sync !== "keep" || (appliedDeviceAfter.sync === "set" && lastDevice)) {
|
|
660
|
-
await applyDeviceToPage(page, lastDevice, appliedDeviceAfter.sync);
|
|
661
|
-
}
|
|
568
|
+
({ appliedTodo: appliedAfter, appliedDevice: appliedDeviceAfter } = await stage.applyPhase(afterPhase));
|
|
662
569
|
stubAfterTodos =
|
|
663
|
-
(lastTodoDock && lastTodoDock.groups[0] && lastTodoDock.groups[0].items) ||
|
|
570
|
+
(stage.state.lastTodoDock && stage.state.lastTodoDock.groups[0] && stage.state.lastTodoDock.groups[0].items) ||
|
|
664
571
|
afterPhase.todos ||
|
|
665
572
|
[];
|
|
666
573
|
if (afterPhase.title && String(afterPhase.title).trim()) {
|
|
667
574
|
afterOverlayTitle = String(afterPhase.title).trim();
|
|
668
575
|
}
|
|
669
576
|
if (afterPhase.todoPos) afterTodoPos = afterPhase.todoPos;
|
|
670
|
-
if (lastTodoDock && lastTodoDock.pos) afterTodoPos = lastTodoDock.pos;
|
|
577
|
+
if (stage.state.lastTodoDock && stage.state.lastTodoDock.pos) afterTodoPos = stage.state.lastTodoDock.pos;
|
|
671
578
|
highlights = afterPhase.highlights.map((h) => {
|
|
672
579
|
const styled = applyHighlightStyleDefaults(h, r.highlightStyle);
|
|
673
580
|
return {
|
|
@@ -707,14 +614,15 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
707
614
|
moduleIndex,
|
|
708
615
|
allEpisodes,
|
|
709
616
|
title: afterOverlayTitle,
|
|
617
|
+
bannerUi: stage.state.lastBannerUi,
|
|
710
618
|
todoPos: afterTodoPos,
|
|
711
619
|
episodeNumber: r.episodeNumber,
|
|
712
620
|
episodeTitle: r.episodeTitle,
|
|
713
621
|
stepperMode,
|
|
714
622
|
todos: stubAfterTodos,
|
|
715
|
-
todoDock: lastTodoDock,
|
|
623
|
+
todoDock: stage.state.lastTodoDock,
|
|
716
624
|
todoSync: appliedAfter.sync,
|
|
717
|
-
todoId: lastTodoDock && lastTodoDock.id,
|
|
625
|
+
todoId: stage.state.lastTodoDock && stage.state.lastTodoDock.id,
|
|
718
626
|
todoDockRef,
|
|
719
627
|
forceCollapsed:
|
|
720
628
|
!!process.env.WAYGRAPH_VIDEO ||
|
|
@@ -726,20 +634,20 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
726
634
|
await syncAllTodoDocks({ parallel: afterTodoParallel });
|
|
727
635
|
// Ring cycle / stubAfter may have advanced the dock - persist for next block.
|
|
728
636
|
if (todoDockRef.current) {
|
|
729
|
-
lastTodoDock = todoDockRef.current;
|
|
637
|
+
stage.state.lastTodoDock = todoDockRef.current;
|
|
730
638
|
rememberTodoDock(todoDockRef.current, "set", afterTodoParallel);
|
|
731
639
|
}
|
|
732
640
|
if (process.env.WAYGRAPH_JSON !== "1") {
|
|
733
641
|
demoLog(
|
|
734
642
|
" after " +
|
|
735
|
-
summarizeDevice(lastDevice) +
|
|
643
|
+
summarizeDevice(stage.state.lastDevice) +
|
|
736
644
|
" deviceSync=" +
|
|
737
645
|
appliedDeviceAfter.sync,
|
|
738
646
|
);
|
|
739
|
-
logTodoDockFull(lastTodoDock, " after");
|
|
647
|
+
logTodoDockFull(stage.state.lastTodoDock, " after");
|
|
740
648
|
demoLog(" after todoSync=" + appliedAfter.sync);
|
|
741
649
|
const docksAfter = await probeTodoDocksOnPage(page);
|
|
742
|
-
if (!docksAfter.length && lastTodoDock && appliedAfter.sync !== "clear") {
|
|
650
|
+
if (!docksAfter.length && stage.state.lastTodoDock && appliedAfter.sync !== "clear") {
|
|
743
651
|
demoLog(" WARN after: todos authored but dock-dom empty");
|
|
744
652
|
} else if (docksAfter.length) {
|
|
745
653
|
demoLog(
|
|
@@ -769,6 +677,7 @@ export async function runStepMode(engine, start, end, context, page, mem, resolv
|
|
|
769
677
|
demoLog(" after dock-dom cleared (expected)");
|
|
770
678
|
}
|
|
771
679
|
}
|
|
680
|
+
if (process.env.WAYGRAPH_JSON !== "1") logBannerDom("after", await probeBanner(page));
|
|
772
681
|
await gate();
|
|
773
682
|
}
|
|
774
683
|
await teardownOverlay(page);
|