waygraph 0.16.0 → 0.16.1
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/cli/commands/browser.d.ts +2 -0
- package/dist/cli/commands/browser.js +109 -0
- package/dist/cli/commands/pilot.d.ts +2 -0
- package/dist/cli/commands/pilot.js +102 -0
- package/dist/cli/commands/session-ops.d.ts +3 -0
- package/dist/cli/commands/session-ops.js +257 -0
- package/dist/cli/commands/session.js +20 -461
- package/dist/cli/usage.d.ts +1 -1
- package/dist/demo/narration/demo-pace.d.ts +1 -1
- package/dist/demo/narration/device.d.ts +2 -2
- package/dist/demo/narration/merge.d.ts +4 -2
- package/dist/demo/narration/merge.js +2 -6
- package/dist/demo/narration/narration.d.ts +8 -8
- package/dist/demo/narration/todo-dock.d.ts +5 -5
- package/dist/demo/overlay/cursor.d.ts +9 -2
- package/dist/demo/overlay/cursor.js +1 -1
- package/dist/demo/overlay/device-stage.d.ts +15 -2
- package/dist/demo/overlay/inpage/banner.d.ts +2 -1
- package/dist/demo/overlay/inpage/banner.js +3 -3
- package/dist/demo/overlay/inpage/caption.d.ts +1 -1
- package/dist/demo/overlay/inpage/core.d.ts +2 -1
- package/dist/demo/overlay/inpage/core.js +1 -1
- package/dist/demo/overlay/inpage/device-chip.d.ts +1 -1
- package/dist/demo/overlay/inpage/device-chip.js +6 -6
- package/dist/demo/overlay/inpage/network.d.ts +3 -2
- package/dist/demo/overlay/inpage/network.js +1 -12
- package/dist/demo/overlay/inpage/panel-chrome.d.ts +1 -1
- package/dist/demo/overlay/inpage/panel-chrome.js +1 -1
- package/dist/demo/overlay/inpage/stamp.d.ts +1 -1
- package/dist/demo/overlay/inpage/stamp.js +1 -1
- package/dist/demo/overlay/inpage/swipe-zoom.d.ts +1 -1
- package/dist/demo/overlay/inpage/swipe-zoom.js +1 -1
- package/dist/demo/overlay/inpage/todos.d.ts +2 -1
- package/dist/demo/overlay/inpage/todos.js +1 -2
- package/dist/demo/overlay/network-capture.d.ts +2 -2
- package/dist/demo/overlay/network-capture.js +1 -1
- package/dist/demo/overlay/overlay-stage.d.ts +19 -11
- package/dist/demo/overlay/overlay.d.ts +2 -2
- package/dist/demo/overlay/rings.d.ts +38 -10
- package/dist/demo/overlay/rings.js +21 -47
- package/dist/demo/stepper/after.js +9 -19
- package/dist/demo/stepper/banner-log.d.ts +4 -6
- package/dist/demo/stepper/banner-log.js +3 -1
- package/dist/demo/stepper/before.js +3 -3
- package/dist/demo/stepper/demo-log.d.ts +26 -9
- package/dist/demo/stepper/demo-log.js +9 -26
- package/dist/demo/stepper/interaction-patch.d.ts +3 -2
- package/dist/demo/stepper/interaction-patch.js +19 -19
- package/dist/demo/stepper/panel-after.d.ts +17 -0
- package/dist/demo/stepper/panel-after.js +166 -0
- package/dist/demo/stepper/panel-before.d.ts +12 -0
- package/dist/demo/stepper/panel-before.js +241 -0
- package/dist/demo/stepper/slides.d.ts +13 -1
- package/dist/demo/stepper/slides.js +3 -3
- package/dist/demo/stepper/step-panels.d.ts +57 -9
- package/dist/demo/stepper/step-panels.js +10 -427
- package/dist/demo/stepper/stepper.js +1 -1
- package/dist/demo/stepper/teardown.d.ts +4 -5
- package/dist/demo/stepper/teardown.js +4 -5
- package/dist/demo/stepper/todo-advance.d.ts +3 -2
- package/dist/demo/stepper/todo-advance.js +2 -2
- package/dist/demo/stepper/view.d.ts +4 -14
- package/dist/demo/types.d.ts +69 -1
- package/dist/engine/block/action-page.d.ts +53 -0
- package/dist/engine/block/action-page.js +1 -0
- package/dist/engine/block/block.d.ts +24 -79
- package/dist/engine/block/block.js +2 -77
- package/dist/engine/block/branch.d.ts +17 -0
- package/dist/engine/block/branch.js +40 -0
- package/dist/engine/block/dialog.d.ts +13 -0
- package/dist/engine/block/dialog.js +37 -0
- package/dist/engine/flow/map-branch.d.ts +9 -0
- package/dist/engine/flow/map-branch.js +57 -0
- package/dist/engine/flow/map-builder.d.ts +7 -22
- package/dist/engine/flow/map-builder.js +6 -145
- package/dist/engine/flow/map-steps.d.ts +30 -0
- package/dist/engine/flow/map-steps.js +87 -0
- package/dist/engine/trait/trait.js +1 -1
- package/dist/index.d.ts +13 -9
- package/dist/index.js +7 -5
- package/dist/live/auto/auto.d.ts +3 -15
- package/dist/live/auto/auto.js +10 -420
- package/dist/live/auto/explore.d.ts +2 -2
- package/dist/live/auto/mem.d.ts +11 -0
- package/dist/live/auto/mem.js +85 -0
- package/dist/live/auto/menu.d.ts +30 -0
- package/dist/live/auto/menu.js +335 -0
- package/dist/live/auto-session/auto-session.d.ts +23 -103
- package/dist/live/auto-session/auto-session.js +100 -370
- package/dist/live/auto-session/console.d.ts +4 -0
- package/dist/live/auto-session/console.js +41 -0
- package/dist/live/auto-session/files.d.ts +44 -0
- package/dist/live/auto-session/files.js +145 -0
- package/dist/live/auto-session/helpers.d.ts +5 -2
- package/dist/live/auto-session/helpers.js +17 -0
- package/dist/live/auto-session/inspect.d.ts +4 -0
- package/dist/live/auto-session/inspect.js +75 -0
- package/dist/live/auto-session/ipc.d.ts +3 -22
- package/dist/live/auto-session/ipc.js +7 -147
- package/dist/live/auto-session/open-browser.d.ts +6 -0
- package/dist/live/auto-session/open-browser.js +47 -0
- package/dist/live/pilot/pilot.d.ts +1 -1
- package/dist/live/pilot/pilot.js +2 -1
- package/dist/live/traverse/traverse.js +6 -200
- package/dist/live/traverse/worker.d.ts +37 -0
- package/dist/live/traverse/worker.js +200 -0
- package/package.json +5 -1
|
@@ -1,13 +1,26 @@
|
|
|
1
|
+
import type { DeviceState } from "../../engine/stub/viewport.js";
|
|
1
2
|
import type { WgPage } from "../types.js";
|
|
3
|
+
interface Size {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
}
|
|
7
|
+
/** How a device-shell change animates: clear it, shutter out to desktop, enter in, or stay flat. */
|
|
8
|
+
interface DeviceStageOptions {
|
|
9
|
+
clear?: boolean;
|
|
10
|
+
shutterOut?: boolean;
|
|
11
|
+
enterIn?: boolean;
|
|
12
|
+
desktopFlat?: boolean;
|
|
13
|
+
}
|
|
2
14
|
/**
|
|
3
15
|
* Video recording locks Playwright viewport to recordVideo.size. Shrinking
|
|
4
16
|
* setViewportSize to mobile/tablet letterboxes the .webm top-left. Instead keep
|
|
5
17
|
* the stage size and center a device-sized #wg-device-shell inside the frame.
|
|
6
18
|
*/
|
|
7
|
-
export declare function applyVideoDeviceStage(page: WgPage, target:
|
|
19
|
+
export declare function applyVideoDeviceStage(page: WgPage, target: Size, stage: Size, opts?: DeviceStageOptions): Promise<void>;
|
|
8
20
|
/**
|
|
9
21
|
* Apply authored device fixture to the live page (0.13+).
|
|
10
22
|
* Seamless viewport lerp + centered window + toast on set/clear.
|
|
11
23
|
* With --video: keep recordVideo stage size and center a device shell in-frame.
|
|
12
24
|
*/
|
|
13
|
-
export declare function applyDeviceToPage(page: WgPage, device:
|
|
25
|
+
export declare function applyDeviceToPage(page: WgPage, device: DeviceState | null | undefined, sync?: string): Promise<void>;
|
|
26
|
+
export {};
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { OverlayInstallArgs } from "../../types.js";
|
|
2
|
+
export declare function installBanner({ title, favicon, bannerPos, bannerUi, tag: bannerTag }: OverlayInstallArgs): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export function installBanner({ title, favicon, bannerPos,
|
|
1
|
+
export function installBanner({ title, favicon, bannerPos, bannerUi, tag: bannerTag }) {
|
|
2
2
|
const POSITIONS = ["left", "center", "right"];
|
|
3
3
|
const applyPos = (el, pos) => {
|
|
4
4
|
el.dataset.pos = pos;
|
|
@@ -22,7 +22,7 @@ export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay,
|
|
|
22
22
|
catch {
|
|
23
23
|
/* ignore */
|
|
24
24
|
}
|
|
25
|
-
const startPos = saved && POSITIONS.includes(saved) ? saved : bannerPos;
|
|
25
|
+
const startPos = saved && POSITIONS.includes(saved) ? saved : bannerPos || "left";
|
|
26
26
|
applyPos(banner, startPos);
|
|
27
27
|
banner.title = "Click to move: top left / center / right";
|
|
28
28
|
banner.addEventListener("click", (e) => {
|
|
@@ -155,6 +155,6 @@ export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay,
|
|
|
155
155
|
iconLink.rel = "icon";
|
|
156
156
|
document.head.appendChild(iconLink);
|
|
157
157
|
}
|
|
158
|
-
if (iconLink.href !== favicon)
|
|
158
|
+
if (favicon && iconLink.href !== favicon)
|
|
159
159
|
iconLink.href = favicon;
|
|
160
160
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function showCaption(text:
|
|
1
|
+
export declare function showCaption(text: string): void;
|
|
2
2
|
export declare function hideCaption(): void;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { OverlayInstallArgs } from "../../types.js";
|
|
2
|
+
export declare function installCore({ envAutoplay, todoDockUi }: OverlayInstallArgs): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function installDevice(
|
|
1
|
+
export declare function installDevice(): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// In-page (runs inside the browser via page.evaluate, must stay self-contained): the device toast and chip.
|
|
2
|
-
export function installDevice(
|
|
2
|
+
export function installDevice() {
|
|
3
3
|
// Device toast + chip (0.13.2+) - announce on set/clear; quiet chip on keep.
|
|
4
4
|
// Payload: { sync, device?, remain?, announce? }
|
|
5
5
|
window.__wgSyncDevice = (payload) => {
|
|
@@ -114,7 +114,7 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
|
|
|
114
114
|
(device && device.preset === "desktop" && !device.touchMode);
|
|
115
115
|
if (isDesktopClear) {
|
|
116
116
|
setCursor(false);
|
|
117
|
-
const announce = payload
|
|
117
|
+
const announce = payload?.announce !== false && sync !== "keep";
|
|
118
118
|
if (announce) {
|
|
119
119
|
const vp = device && device.viewport ? device.viewport : { width: 1280, height: 720 };
|
|
120
120
|
showToast("desktop", false, "Back to desktop", vp.width + "×" + vp.height + " · mouse", "landscape");
|
|
@@ -144,8 +144,8 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
|
|
|
144
144
|
return;
|
|
145
145
|
const preset = device.preset || "desktop";
|
|
146
146
|
const touch = !!device.touchMode;
|
|
147
|
-
const remain = payload
|
|
148
|
-
const vp = device.viewport || {};
|
|
147
|
+
const remain = payload?.remain !== false;
|
|
148
|
+
const vp = device.viewport || { width: 0, height: 0 };
|
|
149
149
|
const orient = device.orientation === "landscape" || device.orientation === "portrait"
|
|
150
150
|
? device.orientation
|
|
151
151
|
: vp.height > vp.width
|
|
@@ -163,8 +163,8 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
|
|
|
163
163
|
document.documentElement.dataset.wgTouch = touch ? "1" : "0";
|
|
164
164
|
if (window.__wgEnsureZoomBadge)
|
|
165
165
|
window.__wgEnsureZoomBadge();
|
|
166
|
-
const announce = payload
|
|
167
|
-
(payload
|
|
166
|
+
const announce = payload?.announce === true ||
|
|
167
|
+
(payload?.announce !== false && sync === "set" && changed);
|
|
168
168
|
const size = (vp.width || "?") +
|
|
169
169
|
"×" +
|
|
170
170
|
(vp.height || "?") +
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import type { NetworkEntry } from "../../types.js";
|
|
2
|
+
export declare function addNetworkEntry(entry: NetworkEntry): void;
|
|
2
3
|
/**
|
|
3
4
|
* Shows or hides the network-tab panel - capture keeps happening either way (addNetworkEntry
|
|
4
5
|
* always builds the DOM row; this only toggles whether the panel itself is visible). Safe to call
|
|
5
6
|
* before any entry exists yet - it just remembers the flag for addNetworkEntry to check later.
|
|
6
7
|
*/
|
|
7
|
-
export declare function setNetworkTabVisible(visible:
|
|
8
|
+
export declare function setNetworkTabVisible(visible: boolean): void;
|
|
8
9
|
/** Clears every captured entry and removes the panel - a fresh navigation/session starting over. */
|
|
9
10
|
export declare function clearNetworkLog(): void;
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
// In-page installer (page.evaluate target) - must stay self-contained, no module-scope closure
|
|
2
|
-
// (page.evaluate serializes ONLY the passed function's own source, not sibling top-level
|
|
3
|
-
// functions in this file - every helper below is nested inside addNetworkEntry itself for exactly
|
|
4
|
-
// that reason; a row's click handler still works after addNetworkEntry returns because it's a
|
|
5
|
-
// closure over ITS OWN invocation's nested helpers, not a reference to module scope).
|
|
6
|
-
//
|
|
7
|
-
// A real network-tab overlay (`#wg-network-log`): the DevTools Network panel itself can't be
|
|
8
|
-
// embedded (it lives in browser chrome, not reachable from automation), but every entry's real
|
|
9
|
-
// data is - this renders that, on-page: method, url, status, and (click a row) request/response
|
|
10
|
-
// headers + bodies + a "copy as cURL" command, a Postman-style inspector for both real page
|
|
11
|
-
// traffic (installNetworkCapture, network-capture.js) and defineApiBlock's own page.request calls.
|
|
12
1
|
export function addNetworkEntry(entry) {
|
|
13
2
|
// No-op outside a demo/pilot/auto run - ensureShadowRoot() (and its __wgById/__wgAdd globals)
|
|
14
3
|
// is never installed for a plain `waygraph run`/Playwright test, and this must not throw there.
|
|
@@ -113,7 +102,7 @@ export function addNetworkEntry(entry) {
|
|
|
113
102
|
row.dataset.ok = entry.ok ? "1" : "0";
|
|
114
103
|
let path = entry.url;
|
|
115
104
|
try {
|
|
116
|
-
const u = new URL(entry.url);
|
|
105
|
+
const u = new URL(String(entry.url));
|
|
117
106
|
path = u.pathname + u.search;
|
|
118
107
|
}
|
|
119
108
|
catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function installPanelChrome(
|
|
1
|
+
export declare function installPanelChrome(): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// In-page (runs inside the browser via page.evaluate, must stay self-contained): the step panel's Hide/Show chrome and mini Next.
|
|
2
|
-
export function installPanelChrome(
|
|
2
|
+
export function installPanelChrome() {
|
|
3
3
|
// Hide/Show for #wg-panel - call after every panel content refresh.
|
|
4
4
|
// Collapsed = "N / M · block" + Next (when not auto). Never pass
|
|
5
5
|
// forceCollapsed:false - omit so Hide/localStorage wins.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function installStamp(
|
|
1
|
+
export declare function installStamp(): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// In-page (runs inside the browser via page.evaluate, must stay self-contained): readiness stamps agents read to know a panel painted.
|
|
2
|
-
export function installStamp(
|
|
2
|
+
export function installStamp() {
|
|
3
3
|
// Blind-agent overlay beacons: every modal root gets data-wg-ui /
|
|
4
4
|
// data-wg-modal / data-wg-ready so tests can fail on a blank panel.
|
|
5
5
|
window.__wgStampModal = (el, kind, meta) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function installSwipeZoom(
|
|
1
|
+
export declare function installSwipeZoom(): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// In-page (runs inside the browser via page.evaluate, must stay self-contained): swipe trails and ring zoom.
|
|
2
|
-
export function installSwipeZoom(
|
|
2
|
+
export function installSwipeZoom() {
|
|
3
3
|
/**
|
|
4
4
|
* Finger swipe trail for touch theater (orientation rotate / device change).
|
|
5
5
|
* opts: { dir: 'left'|'right'|'up'|'down', label?, ms? }
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { OverlayInstallArgs } from "../../types.js";
|
|
2
|
+
export declare function installTodos({ todoPos }: OverlayInstallArgs): void;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export function installTodos({ title, favicon, bannerPos, todoPos, envAutoplay, todoDockUi }) {
|
|
1
|
+
export function installTodos({ todoPos }) {
|
|
3
2
|
// Floating todo dock - lives outside #wg-panel so --mini / Hide never
|
|
4
3
|
// hide the checklist. Click cycles left <-> right with CSS transform.
|
|
5
4
|
// Authors set side via ctx.todos(id, items, { pos }); env / --todo-* fallback.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WgPage } from "../types.js";
|
|
1
|
+
import type { NetworkEntry, WgPage } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Records one entry AND paints it live - the single place that touches page.__wgNetworkHistory,
|
|
4
4
|
* so every caller (this file's own listeners, defineApiBlock) stays in sync automatically. History
|
|
@@ -7,7 +7,7 @@ import type { WgPage } from "../types.js";
|
|
|
7
7
|
* this, the "network tab" reset to empty on every step that navigated - not what a persistent
|
|
8
8
|
* Network tab is supposed to do.
|
|
9
9
|
*/
|
|
10
|
-
export declare function recordNetworkEntry(page: WgPage, entry:
|
|
10
|
+
export declare function recordNetworkEntry(page: WgPage, entry: NetworkEntry): Promise<void | undefined>;
|
|
11
11
|
/**
|
|
12
12
|
* Replays whatever history survived the last navigation back into a freshly (re)installed panel -
|
|
13
13
|
* call this after ensureShadowRoot, every step, same as the rest of the overlay's own per-step
|
|
@@ -119,7 +119,7 @@ export function installNetworkCapture(page) {
|
|
|
119
119
|
status: 0,
|
|
120
120
|
ok: false,
|
|
121
121
|
reqBody: request.postData() || undefined,
|
|
122
|
-
resBody: request.failure()
|
|
122
|
+
resBody: request.failure()?.errorText,
|
|
123
123
|
});
|
|
124
124
|
});
|
|
125
125
|
}
|
|
@@ -1,22 +1,30 @@
|
|
|
1
|
-
import type { WgPage } from "../types.js";
|
|
2
|
-
|
|
1
|
+
import type { BannerUiState, StepperRefs, WgPage } from "../types.js";
|
|
2
|
+
import type { StubPhaseResult } from "../../engine/stub/stub.js";
|
|
3
|
+
import type { TodoDockState, TodoDockUiOpts } from "../../engine/stub/todos.js";
|
|
4
|
+
import type { DeviceState } from "../../engine/stub/viewport.js";
|
|
5
|
+
export declare function createOverlayStage(page: WgPage, { todoDockRef, deviceRef }: Pick<StepperRefs, never> & {
|
|
6
|
+
todoDockRef: StepperRefs["todoDock"];
|
|
7
|
+
deviceRef: StepperRefs["device"];
|
|
8
|
+
}): {
|
|
3
9
|
state: {
|
|
4
|
-
lastTodoDock:
|
|
5
|
-
lastDevice:
|
|
6
|
-
lastBannerUi:
|
|
10
|
+
lastTodoDock: TodoDockState | undefined;
|
|
11
|
+
lastDevice: DeviceState | undefined;
|
|
12
|
+
lastBannerUi: BannerUiState;
|
|
7
13
|
};
|
|
8
|
-
pushTodoDockUi: (patch:
|
|
9
|
-
rememberTodoDock: (dock:
|
|
10
|
-
syncAllTodoDocks: (opts
|
|
11
|
-
|
|
14
|
+
pushTodoDockUi: (patch: TodoDockUiOpts | undefined) => Promise<void>;
|
|
15
|
+
rememberTodoDock: (dock: TodoDockState | undefined, sync: "set" | "clear" | "keep", parallel: boolean) => void;
|
|
16
|
+
syncAllTodoDocks: (opts?: {
|
|
17
|
+
parallel?: boolean;
|
|
18
|
+
}) => Promise<void>;
|
|
19
|
+
applyPhase: (phase: StubPhaseResult, { reapplyDeviceOnKeep }?: {
|
|
12
20
|
reapplyDeviceOnKeep?: boolean | undefined;
|
|
13
21
|
}) => Promise<{
|
|
14
22
|
appliedTodo: {
|
|
15
|
-
dock:
|
|
23
|
+
dock: TodoDockState | undefined;
|
|
16
24
|
sync: "set" | "clear" | "keep";
|
|
17
25
|
};
|
|
18
26
|
appliedDevice: {
|
|
19
|
-
device:
|
|
27
|
+
device: DeviceState | undefined;
|
|
20
28
|
sync: "set" | "clear" | "keep";
|
|
21
29
|
};
|
|
22
30
|
}>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WgPage } from "../types.js";
|
|
1
|
+
import type { BannerUiState, WgPage } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* `ui` = authored banner UX from the stub phase: { pos, collision, hidden } (all optional).
|
|
4
4
|
* `caption` = bottom subtitle-bar text (ctx.caption()/ctx.hideCaption()) - `undefined` leaves it
|
|
@@ -7,4 +7,4 @@ import type { WgPage } from "../types.js";
|
|
|
7
7
|
* `undefined` leaves it alone (default state is hidden, set the very first time restoreNetworkHistory
|
|
8
8
|
* builds a panel); capture itself is unconditional and unaffected by this either way.
|
|
9
9
|
*/
|
|
10
|
-
export declare function installOverlay(page: WgPage, title?:
|
|
10
|
+
export declare function installOverlay(page: WgPage, title?: string, ui?: BannerUiState | null, caption?: string, networkTabVisible?: boolean): Promise<void>;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { WgBox, WgPage } from "../types.js";
|
|
2
2
|
import type { Locator } from "@playwright/test";
|
|
3
|
+
import type { ResolvedHighlight } from "../../engine/stub/ring.js";
|
|
4
|
+
import type { DemoPace } from "../../engine/stub/pace.js";
|
|
5
|
+
import type { TodoDockState, WaygraphTodoItem } from "../../engine/stub/todos.js";
|
|
6
|
+
import type { Pacing } from "../stepper/pacing.js";
|
|
3
7
|
/**
|
|
4
8
|
* Scroll a locator into view for demo theater.
|
|
5
9
|
* Prefer CSS smooth scroll + scrollend wait. Do NOT call Playwright's
|
|
@@ -8,20 +12,44 @@ import type { Locator } from "@playwright/test";
|
|
|
8
12
|
* noticeable under --fast when dwell is shorter.
|
|
9
13
|
* Pass opts.instant=true only for skipTheater / blitz.
|
|
10
14
|
*/
|
|
11
|
-
export declare function ensureLocatorInView(locator: Locator, opts
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export declare function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export declare function
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
export declare function ensureLocatorInView(locator: Locator, opts?: {
|
|
16
|
+
instant?: boolean;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
export declare function ensureSelectorInView(page: WgPage, selector: string, opts?: {
|
|
19
|
+
instant?: boolean;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
export declare function applyHighlightZoom(page: WgPage, selector: string | undefined, zoom: number | undefined, zoomOut: boolean | undefined): Promise<void>;
|
|
22
|
+
/** How `cycleHighlightRings` plays a step's rings: hold times, pace, and the todo dock it moves along. */
|
|
23
|
+
export interface CycleRingsOptions {
|
|
24
|
+
/** Hold for each ring when it sets none (the failure path holds longer). */
|
|
25
|
+
defaultHoldMs?: number;
|
|
26
|
+
pace?: DemoPace | undefined;
|
|
27
|
+
todoDock?: TodoDockState | undefined;
|
|
28
|
+
todos?: readonly WaygraphTodoItem[] | undefined;
|
|
29
|
+
todoSync?: "set" | "clear" | "keep" | undefined;
|
|
30
|
+
todoDockRef?: {
|
|
31
|
+
current: TodoDockState | undefined;
|
|
32
|
+
} | undefined;
|
|
33
|
+
/** False when the stub already set the dock's progress. */
|
|
34
|
+
advanceTodos?: boolean;
|
|
35
|
+
stepLabel?: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function cycleHighlightRings(page: WgPage, highlights: readonly ResolvedHighlight[] | undefined, gatesFast: boolean, opts?: CycleRingsOptions): Promise<void>;
|
|
38
|
+
export declare function showRing(page: WgPage, box: WgBox, label: string, tone: string | undefined, style?: {
|
|
39
|
+
size?: string | undefined;
|
|
40
|
+
weight?: string | undefined;
|
|
41
|
+
selector?: string | undefined;
|
|
42
|
+
focus?: boolean;
|
|
43
|
+
}): Promise<void>;
|
|
44
|
+
/** The stubBefore ring a locator is, by overlapping bounding boxes: its index, or -1. For a Method's todo advance. */
|
|
45
|
+
export declare function matchStubIndexForLocator(page: WgPage, locator: Locator, stubs: readonly ResolvedHighlight[] | undefined): Promise<number>;
|
|
46
|
+
export declare function captionForLocator(page: WgPage, locator: Locator, stubs: readonly ResolvedHighlight[] | undefined, fallback: string): Promise<{
|
|
47
|
+
label: string;
|
|
20
48
|
tone: string;
|
|
21
49
|
size: string;
|
|
22
50
|
weight: string;
|
|
23
51
|
}>;
|
|
24
|
-
export declare function dwellMatchedStub(page: WgPage, locator: Locator, stubs:
|
|
52
|
+
export declare function dwellMatchedStub(page: WgPage, locator: Locator, stubs: readonly ResolvedHighlight[] | undefined, pacing: Pick<Pacing, "gatesFast" | "demoPace"> | undefined): Promise<void>;
|
|
25
53
|
export declare function hideRing(page: WgPage): Promise<void>;
|
|
26
54
|
/**
|
|
27
55
|
* True if the engine's own narrate() (waygraph's public export, for a Block
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ANSI, ansiPaint, demoFixture, demoHighlight, demoLog } from "../stepper/demo-log.js";
|
|
2
2
|
import { playSwipeTrail } from "./cursor.js";
|
|
3
|
-
import { advanceTodoDock
|
|
3
|
+
import { advanceTodoDock } from "../narration/todo-dock.js";
|
|
4
4
|
import { formatHighlightCaption } from "../narration/style.js";
|
|
5
5
|
import { normalizeHighlightSize, normalizeHighlightTone, normalizeHighlightWeight } from "../../engine/stub/ring.js";
|
|
6
6
|
import { resolveFixtureDwellMs } from "../narration/demo-pace.js";
|
|
7
7
|
import { envNumber } from "../../engine/env.js";
|
|
8
|
-
import { ignorePageGone } from "../../engine/page-gone.js";
|
|
8
|
+
import { ignorePageGone, ignoreTimeout } from "../../engine/page-gone.js";
|
|
9
9
|
/**
|
|
10
10
|
* Scroll a locator into view for demo theater.
|
|
11
11
|
* Prefer CSS smooth scroll + scrollend wait. Do NOT call Playwright's
|
|
@@ -184,8 +184,7 @@ export async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
184
184
|
.catch(ignorePageGone);
|
|
185
185
|
}
|
|
186
186
|
let lastRingEndedAt = null;
|
|
187
|
-
for (
|
|
188
|
-
const h = list[i];
|
|
187
|
+
for (const [i, h] of list.entries()) {
|
|
189
188
|
const ringStarted = Date.now();
|
|
190
189
|
try {
|
|
191
190
|
await ensureSelectorInView(page, h.selector);
|
|
@@ -200,13 +199,13 @@ export async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
200
199
|
// "does it exist right now" check - ensureSelectorInView above already gave the page a real
|
|
201
200
|
// moment to settle.
|
|
202
201
|
const hLoc = page.locator(h.selector).first();
|
|
203
|
-
const box = (await hLoc.count().catch(
|
|
202
|
+
const box = ((await hLoc.count().catch(ignorePageGone)) ?? 0) > 0
|
|
204
203
|
? await hLoc
|
|
205
204
|
.evaluate((el) => {
|
|
206
205
|
const r = el.getBoundingClientRect();
|
|
207
206
|
return { x: r.x, y: r.y, width: r.width, height: r.height };
|
|
208
207
|
})
|
|
209
|
-
.catch(
|
|
208
|
+
.catch(ignorePageGone)
|
|
210
209
|
: null;
|
|
211
210
|
if (box && box.width > 0 && box.height > 0) {
|
|
212
211
|
await showRing(page, box, h.label, h.tone || "planned", {
|
|
@@ -230,10 +229,8 @@ export async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
230
229
|
}, dock)
|
|
231
230
|
.catch(ignorePageGone);
|
|
232
231
|
}
|
|
233
|
-
else if (!dock &&
|
|
234
|
-
const rows = opts
|
|
235
|
-
? opts.todos
|
|
236
|
-
: normalizeTodos(h.todos, h.todoIndex);
|
|
232
|
+
else if (!dock && opts?.todos?.length) {
|
|
233
|
+
const rows = opts.todos;
|
|
237
234
|
await page
|
|
238
235
|
.evaluate((todos) => {
|
|
239
236
|
if (window.__wgSyncTodos)
|
|
@@ -273,16 +270,16 @@ export async function cycleHighlightRings(page, highlights, gatesFast, opts) {
|
|
|
273
270
|
}
|
|
274
271
|
}
|
|
275
272
|
catch (err) {
|
|
276
|
-
demoHighlight(h
|
|
273
|
+
demoHighlight(h, "SKIP " + String(err instanceof Error ? err.message : err).slice(0, 80));
|
|
277
274
|
}
|
|
278
275
|
}
|
|
279
|
-
|
|
280
|
-
|
|
276
|
+
const last = list.at(-1);
|
|
277
|
+
if (last) {
|
|
281
278
|
// Resolved through Playwright's own locator (>> piercing / :has-text() / :visible support),
|
|
282
279
|
// not handed to the page as a string for a raw DOM querySelector to fail silently on - see
|
|
283
280
|
// showRing's own comment (same fix, same reason) and __wgFollowRing's in core.js.
|
|
284
281
|
const handle = last.selector
|
|
285
|
-
? await page.locator(last.selector).first().elementHandle({ timeout: 100 }).catch(
|
|
282
|
+
? await page.locator(last.selector).first().elementHandle({ timeout: 100 }).catch(ignoreTimeout)
|
|
286
283
|
: null;
|
|
287
284
|
await page
|
|
288
285
|
.evaluate(({ h, el }) => {
|
|
@@ -333,7 +330,7 @@ export async function showRing(page, box, label, tone, style) {
|
|
|
333
330
|
// syntax, invisible to document.querySelector. The resolved element handle is passed straight
|
|
334
331
|
// into evaluate (Playwright unwraps it to the real DOM node inside the page), so __wgFollowRing's
|
|
335
332
|
// per-frame RAF loop tracks that exact element directly - no repeated selector re-resolution.
|
|
336
|
-
const handle = selector ? await page.locator(selector).first().elementHandle({ timeout: 100 }).catch(
|
|
333
|
+
const handle = selector ? await page.locator(selector).first().elementHandle({ timeout: 100 }).catch(ignoreTimeout) : null;
|
|
337
334
|
await page
|
|
338
335
|
.evaluate(({ box, label, tone, size, weight, el, focus }) => {
|
|
339
336
|
if (el && window.__wgFollowRing) {
|
|
@@ -352,46 +349,18 @@ export async function showRing(page, box, label, tone, style) {
|
|
|
352
349
|
}, { box, label, tone: tone || "planned", size, weight, el: handle, focus })
|
|
353
350
|
.catch(ignorePageGone);
|
|
354
351
|
}
|
|
355
|
-
/**
|
|
356
|
-
async function matchStubForLocator(page, locator, stubs) {
|
|
357
|
-
if (!stubs || stubs.length === 0)
|
|
358
|
-
return null;
|
|
359
|
-
const box = await locator.boundingBox().catch(() => null);
|
|
360
|
-
if (!box)
|
|
361
|
-
return null;
|
|
362
|
-
for (const s of stubs) {
|
|
363
|
-
try {
|
|
364
|
-
const b = await page.locator(s.selector).first().boundingBox();
|
|
365
|
-
if (b &&
|
|
366
|
-
Math.abs(b.x - box.x) < 4 &&
|
|
367
|
-
Math.abs(b.y - box.y) < 4 &&
|
|
368
|
-
Math.abs(b.width - box.width) < 8) {
|
|
369
|
-
return s;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
catch {
|
|
373
|
-
// A stub selector Playwright can't parse can't be this element either.
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
return null;
|
|
377
|
-
}
|
|
378
|
-
/** 0-based stub index for Method fill/click todo advance; -1 if none. */
|
|
352
|
+
/** The stubBefore ring a locator is, by overlapping bounding boxes: its index, or -1. For a Method's todo advance. */
|
|
379
353
|
export async function matchStubIndexForLocator(page, locator, stubs) {
|
|
380
354
|
if (!stubs || stubs.length === 0)
|
|
381
355
|
return -1;
|
|
382
|
-
const box = await locator.boundingBox().catch(
|
|
356
|
+
const box = await locator.boundingBox().catch(ignorePageGone);
|
|
383
357
|
if (!box)
|
|
384
358
|
return -1;
|
|
385
359
|
for (let i = 0; i < stubs.length; i++) {
|
|
386
|
-
const s = stubs[i];
|
|
387
360
|
try {
|
|
388
|
-
const b = await page.locator(
|
|
389
|
-
if (b &&
|
|
390
|
-
Math.abs(b.x - box.x) < 4 &&
|
|
391
|
-
Math.abs(b.y - box.y) < 4 &&
|
|
392
|
-
Math.abs(b.width - box.width) < 8) {
|
|
361
|
+
const b = await page.locator(stubs[i].selector).first().boundingBox();
|
|
362
|
+
if (b && Math.abs(b.x - box.x) < 4 && Math.abs(b.y - box.y) < 4 && Math.abs(b.width - box.width) < 8)
|
|
393
363
|
return i;
|
|
394
|
-
}
|
|
395
364
|
}
|
|
396
365
|
catch {
|
|
397
366
|
// A stub selector Playwright can't parse can't be this element either.
|
|
@@ -399,6 +368,11 @@ export async function matchStubIndexForLocator(page, locator, stubs) {
|
|
|
399
368
|
}
|
|
400
369
|
return -1;
|
|
401
370
|
}
|
|
371
|
+
/** The stubBefore ring a locator is, or null. */
|
|
372
|
+
async function matchStubForLocator(page, locator, stubs) {
|
|
373
|
+
const i = await matchStubIndexForLocator(page, locator, stubs);
|
|
374
|
+
return i >= 0 && stubs ? stubs[i] : null;
|
|
375
|
+
}
|
|
402
376
|
export async function captionForLocator(page, locator, stubs, fallback) {
|
|
403
377
|
const matched = await matchStubForLocator(page, locator, stubs);
|
|
404
378
|
if (matched) {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { envFlag } from "../../engine/env.js";
|
|
1
2
|
import { hasAuthoredStubAfter, resolveSlides, runStubPhase } from "../narration/narration.js";
|
|
2
3
|
import { applyHighlightStyleDefaults, formatHighlightCaption } from "../narration/style.js";
|
|
3
|
-
import { demoLog, logStubPhaseFixtures, logTodoDockFull, paceSpeakFields, summarizeDevice } from "./demo-log.js";
|
|
4
|
-
import { extractVerifyHighlights, renderAfterStep } from "./step-panels.js";
|
|
5
|
-
import { presentSlides } from "./slides.js";
|
|
6
4
|
import { logBannerDom, probeBanner } from "./banner-log.js";
|
|
7
5
|
import { logDocks } from "./before.js";
|
|
6
|
+
import { demoLog, logStubPhaseFixtures, logTodoDockFull, paceSpeakFields, summarizeDevice } from "./demo-log.js";
|
|
7
|
+
import { renderAfterStep } from "./panel-after.js";
|
|
8
|
+
import { presentSlides } from "./slides.js";
|
|
9
|
+
import { extractVerifyHighlights } from "./step-panels.js";
|
|
8
10
|
import { forceCollapsed } from "./view.js";
|
|
9
|
-
import { envFlag } from "../../engine/env.js";
|
|
10
11
|
const quiet = () => envFlag("WAYGRAPH_JSON");
|
|
11
12
|
export async function showAfter(ctx, view, result) {
|
|
12
13
|
const { stage, refs } = ctx;
|
|
@@ -65,7 +66,7 @@ async function showSlides(ctx, view, result) {
|
|
|
65
66
|
const slides = resolveSlides(view.step.block, { out: result }).map((s) => applyHighlightStyleDefaults(s, view.step.highlightStyle));
|
|
66
67
|
if (slides.length === 0)
|
|
67
68
|
return;
|
|
68
|
-
await presentSlides(ctx.page, slides,
|
|
69
|
+
await presentSlides(ctx.page, slides, {
|
|
69
70
|
title: ctx.title,
|
|
70
71
|
blockName: view.step.block.name,
|
|
71
72
|
fast: ctx.pacing.gatesFast,
|
|
@@ -89,21 +90,10 @@ async function narrateAfter(ctx, view, result) {
|
|
|
89
90
|
}),
|
|
90
91
|
});
|
|
91
92
|
const highlights = phase.highlights.map((h) => {
|
|
93
|
+
// The ring's look and timing only; its todo, gesture and cursor belong to stubBefore.
|
|
92
94
|
const styled = applyHighlightStyleDefaults(h, style);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
label: formatHighlightCaption(styled),
|
|
96
|
-
duration: styled.duration,
|
|
97
|
-
fastMode: styled.fastMode,
|
|
98
|
-
tone: styled.tone,
|
|
99
|
-
size: styled.size,
|
|
100
|
-
weight: styled.weight,
|
|
101
|
-
zoom: styled.zoom,
|
|
102
|
-
zoomOut: styled.zoomOut,
|
|
103
|
-
focus: !!styled.focus,
|
|
104
|
-
color: styled.color,
|
|
105
|
-
detail: styled.detail,
|
|
106
|
-
};
|
|
95
|
+
const { tag: _tag, cursor: _cursor, todo: _todo, slotId: _slotId, gesture: _gesture, ...ring } = styled;
|
|
96
|
+
return { ...ring, label: formatHighlightCaption(styled), focus: !!styled.focus };
|
|
107
97
|
});
|
|
108
98
|
return { phase, highlights };
|
|
109
99
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { WgPage } from "../types.js";
|
|
1
|
+
import type { BannerUiState, WgPage } from "../types.js";
|
|
2
|
+
import type { StubPhaseResult } from "../../engine/stub/stub.js";
|
|
2
3
|
/** Authored banner UX from a stub phase -> the { pos, collision, hidden } shape installOverlay takes. */
|
|
3
|
-
export declare function bannerUiFromPhase(phase:
|
|
4
|
+
export declare function bannerUiFromPhase(phase: Pick<StubPhaseResult, "titlePos" | "bannerUi"> | null | undefined): BannerUiState;
|
|
4
5
|
/** Read the live banner: text, position, whether it was moved by ring collision; drains the move log. */
|
|
5
6
|
export declare function probeBanner(page: WgPage): Promise<{
|
|
6
7
|
present: boolean;
|
|
@@ -30,8 +31,5 @@ export declare function probeBanner(page: WgPage): Promise<{
|
|
|
30
31
|
w: number;
|
|
31
32
|
h: number;
|
|
32
33
|
log: any;
|
|
33
|
-
} | {
|
|
34
|
-
present: boolean;
|
|
35
|
-
log: never[];
|
|
36
34
|
}>;
|
|
37
|
-
export declare function logBannerDom(tag:
|
|
35
|
+
export declare function logBannerDom(tag: string, p: Awaited<ReturnType<typeof probeBanner>> | null | undefined): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { demoLog } from "./demo-log.js";
|
|
2
|
+
import { ignorePageGone } from "../../engine/page-gone.js";
|
|
2
3
|
/** Authored banner UX from a stub phase -> the { pos, collision, hidden } shape installOverlay takes. */
|
|
3
4
|
export function bannerUiFromPhase(phase) {
|
|
4
5
|
const ui = {};
|
|
@@ -41,7 +42,8 @@ export async function probeBanner(page) {
|
|
|
41
42
|
log,
|
|
42
43
|
};
|
|
43
44
|
})
|
|
44
|
-
.catch(
|
|
45
|
+
.catch(ignorePageGone)
|
|
46
|
+
.then((probe) => probe ?? { present: false, log: [] });
|
|
45
47
|
}
|
|
46
48
|
export function logBannerDom(tag, p) {
|
|
47
49
|
if (!p)
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// Before a demo step runs: play the Block's stubBefore narration (rings, todos, device, title, caption) and show the
|
|
2
2
|
// step's panel, then log what was painted so an agent without eyes can check it.
|
|
3
|
+
import { envFlag } from "../../engine/env.js";
|
|
3
4
|
import { runStubPhase } from "../narration/narration.js";
|
|
4
5
|
import { applyHighlightStyleDefaults, formatHighlightCaption } from "../narration/style.js";
|
|
6
|
+
import { logBannerDom, probeBanner } from "./banner-log.js";
|
|
5
7
|
import { demoLog, logStubPhaseFixtures, logTodoDockFull, paceSpeakFields, summarizeDevice } from "./demo-log.js";
|
|
6
|
-
import { renderBeforeStep } from "./
|
|
8
|
+
import { renderBeforeStep } from "./panel-before.js";
|
|
7
9
|
import { probeTodoDocksOnPage } from "./todo-advance.js";
|
|
8
|
-
import { logBannerDom, probeBanner } from "./banner-log.js";
|
|
9
10
|
import { forceCollapsed } from "./view.js";
|
|
10
|
-
import { envFlag } from "../../engine/env.js";
|
|
11
11
|
const quiet = () => envFlag("WAYGRAPH_JSON");
|
|
12
12
|
export async function showBefore(ctx, view) {
|
|
13
13
|
const { stage } = ctx;
|