waygraph 0.15.30 → 0.15.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-explore-run.js +9 -6
- package/dist/auto-session/session.js +2 -1
- package/dist/pilot-overlay/action-ring.d.ts +16 -0
- package/dist/pilot-overlay/action-ring.js +67 -0
- package/dist/pilot-overlay/fixtures.js +17 -17
- package/dist/pilot-overlay/panel.js +3 -3
- package/dist/pilot-overlay/shell.js +27 -27
- package/dist/pilot-overlay.d.ts +1 -0
- package/dist/pilot-overlay.js +1 -0
- package/dist/runner/cursor.js +3 -3
- package/dist/runner/inpage/banner.js +2 -2
- package/dist/runner/inpage/core.js +23 -23
- package/dist/runner/inpage/device.js +11 -11
- package/dist/runner/inpage/panel-chrome.js +3 -3
- package/dist/runner/inpage/stamp.js +2 -2
- package/dist/runner/inpage/swipe-zoom.js +10 -10
- package/dist/runner/inpage/todos.js +6 -6
- package/dist/runner/overlay-css.js +21 -18
- package/dist/runner/overlay-install.js +5 -2
- package/dist/runner/rings.js +1 -1
- package/dist/runner/slides.js +11 -11
- package/dist/runner/step-panels.js +18 -18
- package/dist/runner/teardown.js +8 -8
- package/dist/runner/todo-dock.js +1 -1
- package/dist/step-overlay.js +20 -18
- package/dist/ui/components/ring.js +5 -0
- package/dist/ui/shadow.d.ts +15 -0
- package/dist/ui/shadow.js +42 -0
- package/examples/saucedemo/.waygraph-auto/1bd7b7bf.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2a577961.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2c79c73a.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2c94a05b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/37b56184.log +0 -0
- package/examples/saucedemo/.waygraph-auto/401177a3.log +0 -0
- package/examples/saucedemo/.waygraph-auto/476cff76.log +0 -0
- package/examples/saucedemo/.waygraph-auto/535e8922.json +8 -0
- package/examples/saucedemo/.waygraph-auto/535e8922.log +0 -0
- package/examples/saucedemo/.waygraph-auto/68fa0682.log +0 -0
- package/examples/saucedemo/.waygraph-auto/73a41843.log +0 -0
- package/examples/saucedemo/.waygraph-auto/8598b4c0.log +0 -0
- package/examples/saucedemo/.waygraph-auto/982138cf.log +0 -0
- package/examples/saucedemo/.waygraph-auto/a8645294.log +0 -0
- package/examples/saucedemo/.waygraph-auto/bf8693e7.log +0 -0
- package/examples/saucedemo/.waygraph-auto/f86224c6.log +0 -0
- package/examples/saucedemo/.waygraph-auto/fc917c18.log +0 -0
- package/examples/saucedemo/.waygraph-auto/fe83305d.log +0 -0
- package/package.json +1 -1
package/dist/auto-explore-run.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { ensureShadowRoot } from "./ui/shadow.js";
|
|
2
3
|
import { stdin as input, stdout as output } from "node:process";
|
|
3
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
5
|
import { join } from "node:path";
|
|
@@ -168,7 +169,7 @@ export async function ensureMem(entry, mem, cli) {
|
|
|
168
169
|
async function setAutoPanelRunning(page, label) {
|
|
169
170
|
await page
|
|
170
171
|
.evaluate((label) => {
|
|
171
|
-
const panel =
|
|
172
|
+
const panel = __wgById("wg-auto-panel");
|
|
172
173
|
if (!panel)
|
|
173
174
|
return;
|
|
174
175
|
const body = "<h3>waygraph auto</h3><div style='padding:12px 0;color:#c9a6ff'>" +
|
|
@@ -291,9 +292,10 @@ function memKeysForMenu(menu, library) {
|
|
|
291
292
|
async function syncPanelMem(page, mem, keys) {
|
|
292
293
|
if (keys.length === 0)
|
|
293
294
|
return;
|
|
295
|
+
await ensureShadowRoot(page);
|
|
294
296
|
const edits = (await page.evaluate(() => {
|
|
295
297
|
const out = {};
|
|
296
|
-
|
|
298
|
+
__wgQA("textarea.wg-mem-input").forEach((ta) => {
|
|
297
299
|
const key = ta.getAttribute("data-mem-key");
|
|
298
300
|
if (key)
|
|
299
301
|
out[key] = ta.value;
|
|
@@ -382,14 +384,15 @@ async function headfulPick(page, menu, library, mem, waitPick) {
|
|
|
382
384
|
html =
|
|
383
385
|
`<style id="wg-auto-style">${PANEL_CSS}</style><div id="wg-auto-panel">` +
|
|
384
386
|
html.slice(html.indexOf("<h3>"));
|
|
387
|
+
await ensureShadowRoot(page);
|
|
385
388
|
await page.evaluate(`((inner) => {
|
|
386
|
-
let panel =
|
|
389
|
+
let panel = __wgById("wg-auto-panel");
|
|
387
390
|
if (!panel) {
|
|
388
391
|
panel = document.createElement("div");
|
|
389
|
-
|
|
392
|
+
__wgAdd(panel);
|
|
390
393
|
}
|
|
391
394
|
panel.outerHTML = inner;
|
|
392
|
-
const root =
|
|
395
|
+
const root = __wgById("wg-auto-panel");
|
|
393
396
|
if (!root) return;
|
|
394
397
|
window.__wgWirePanelChrome = (el, storageKey, chromeTitle) => {
|
|
395
398
|
if (!el) return;
|
|
@@ -446,7 +449,7 @@ async function headfulPick(page, menu, library, mem, waitPick) {
|
|
|
446
449
|
window.__wgOverlayBeacon =
|
|
447
450
|
window.__wgOverlayBeacon ||
|
|
448
451
|
(() =>
|
|
449
|
-
Array.from(
|
|
452
|
+
Array.from(__wgQA('[data-wg-ui="1"]')).map((el) => {
|
|
450
453
|
const r = el.getBoundingClientRect();
|
|
451
454
|
const st = getComputedStyle(el);
|
|
452
455
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Split out of the former 1,078-line auto-session.ts (see src/ARCHITECTURE.md). Behavior unchanged.
|
|
2
2
|
import { CONSOLE_LOG_MAX_ENTRIES, FULL_MODE_DEFAULT_DEPTH, FULL_MODE_MAX_NODES, FULL_MODE_MAX_TEXT_LENGTH, TRACE_MAX_STEPS, buildSessionSnapshot, parsePick, stubFilePath, stubPhaseHasContent, walkFullDom } from "./helpers.js";
|
|
3
|
-
import { installPersistentPilotOverlay, showPilotActivity, showPilotFixtures, showPilotVision, updatePilotOverlay } from "../pilot-overlay.js";
|
|
3
|
+
import { instrumentPilotActions, installPersistentPilotOverlay, showPilotActivity, showPilotFixtures, showPilotVision, updatePilotOverlay } from "../pilot-overlay.js";
|
|
4
4
|
import { buildExploreContext, buildExploreMenu } from "../auto-explore.js";
|
|
5
5
|
import { MemPage } from "../mem-page.js";
|
|
6
6
|
import { Engine } from "../engine.js";
|
|
@@ -92,6 +92,7 @@ export class AutoSession {
|
|
|
92
92
|
const context = await browser.newContext(contextOpts);
|
|
93
93
|
await installPersistentPilotOverlay(context);
|
|
94
94
|
const page = await context.newPage();
|
|
95
|
+
instrumentPilotActions(page, headless ? 0 : 450);
|
|
95
96
|
if (startUrl) {
|
|
96
97
|
await page.goto(startUrl, { waitUntil: "domcontentloaded" }).catch(() => { });
|
|
97
98
|
await page.waitForLoadState("load").catch(() => { });
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Page } from "@playwright/test";
|
|
2
|
+
type Box = {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
};
|
|
8
|
+
/** Paint the gray "auto" ring (Playwright is about to act here) at a viewport rectangle. */
|
|
9
|
+
export declare function showPilotRect(page: Page, box: Box, label: string, tone?: string): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Every Playwright instruction a Block runs against this session's page gets a gray (auto) ring + robot
|
|
12
|
+
* label first, so a human watching a pilot window sees WHAT is being driven. `dwellMs` holds the ring
|
|
13
|
+
* long enough to read before the action fires (0 for headless).
|
|
14
|
+
*/
|
|
15
|
+
export declare function instrumentPilotActions(page: Page, dwellMs: number): void;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ensureInstalled } from "./shell.js";
|
|
2
|
+
/** Paint the gray "auto" ring (Playwright is about to act here) at a viewport rectangle. */
|
|
3
|
+
export async function showPilotRect(page, box, label, tone = "auto") {
|
|
4
|
+
await ensureInstalled(page);
|
|
5
|
+
await page
|
|
6
|
+
.evaluate(({ box, label, tone }) => {
|
|
7
|
+
const ring = __wgById("wg-ring");
|
|
8
|
+
const tag = __wgById("wg-ring-label");
|
|
9
|
+
if (!ring || !tag)
|
|
10
|
+
return;
|
|
11
|
+
const w = window;
|
|
12
|
+
if (w.__wgVisionHideTimer)
|
|
13
|
+
clearTimeout(w.__wgVisionHideTimer);
|
|
14
|
+
ring.dataset.tone = tone;
|
|
15
|
+
ring.dataset.size = "md";
|
|
16
|
+
tag.dataset.tone = tone;
|
|
17
|
+
tag.dataset.size = "md";
|
|
18
|
+
tag.dataset.weight = "normal";
|
|
19
|
+
ring.style.left = `${box.x - 3}px`;
|
|
20
|
+
ring.style.top = `${box.y - 3}px`;
|
|
21
|
+
ring.style.width = `${box.width + 6}px`;
|
|
22
|
+
ring.style.height = `${box.height + 6}px`;
|
|
23
|
+
tag.textContent = label;
|
|
24
|
+
tag.style.left = `${Math.max(0, box.x)}px`;
|
|
25
|
+
tag.style.top = `${Math.max(0, box.y - 24)}px`;
|
|
26
|
+
ring.style.opacity = "1";
|
|
27
|
+
tag.style.opacity = "1";
|
|
28
|
+
w.__wgVisionHideTimer = setTimeout(() => {
|
|
29
|
+
ring.style.opacity = "0";
|
|
30
|
+
tag.style.opacity = "0";
|
|
31
|
+
}, 4_000);
|
|
32
|
+
}, { box, label, tone })
|
|
33
|
+
.catch(() => { });
|
|
34
|
+
}
|
|
35
|
+
const LOCATOR_ACTIONS = ["click", "dblclick", "hover", "tap", "fill", "check", "uncheck", "selectOption", "press", "pressSequentially", "setInputFiles"];
|
|
36
|
+
const patched = new WeakSet();
|
|
37
|
+
/**
|
|
38
|
+
* Every Playwright instruction a Block runs against this session's page gets a gray (auto) ring + robot
|
|
39
|
+
* label first, so a human watching a pilot window sees WHAT is being driven. `dwellMs` holds the ring
|
|
40
|
+
* long enough to read before the action fires (0 for headless).
|
|
41
|
+
*/
|
|
42
|
+
export function instrumentPilotActions(page, dwellMs) {
|
|
43
|
+
const proto = Object.getPrototypeOf(page.locator("html"));
|
|
44
|
+
if (patched.has(proto))
|
|
45
|
+
return;
|
|
46
|
+
patched.add(proto);
|
|
47
|
+
for (const action of LOCATOR_ACTIONS) {
|
|
48
|
+
const original = proto[action];
|
|
49
|
+
if (typeof original !== "function")
|
|
50
|
+
continue;
|
|
51
|
+
proto[action] = async function (...args) {
|
|
52
|
+
try {
|
|
53
|
+
const box = await this.first().boundingBox({ timeout: 1_500 });
|
|
54
|
+
if (box) {
|
|
55
|
+
const desc = String(this).replace(/^locator\(['"]?|['"]?\)$/g, "").slice(0, 60);
|
|
56
|
+
await showPilotRect(this.page(), box, `${action} ${desc}`);
|
|
57
|
+
if (dwellMs > 0)
|
|
58
|
+
await this.page().waitForTimeout(dwellMs);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
/* decoration only - never block the real action */
|
|
63
|
+
}
|
|
64
|
+
return original.apply(this, args);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -98,22 +98,22 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
98
98
|
if (w.__wgPilotFxHideTimer)
|
|
99
99
|
clearTimeout(w.__wgPilotFxHideTimer);
|
|
100
100
|
const clearFocus = () => {
|
|
101
|
-
const veil =
|
|
101
|
+
const veil = __wgById("wg-pilot-fx-focus");
|
|
102
102
|
if (!veil)
|
|
103
103
|
return;
|
|
104
104
|
veil.classList.remove("wg-in");
|
|
105
105
|
setTimeout(() => {
|
|
106
|
-
const v =
|
|
106
|
+
const v = __wgById("wg-pilot-fx-focus");
|
|
107
107
|
if (v && !v.classList.contains("wg-in"))
|
|
108
108
|
v.remove();
|
|
109
109
|
}, 320);
|
|
110
110
|
};
|
|
111
111
|
const applyFocus = (box) => {
|
|
112
|
-
let veil =
|
|
112
|
+
let veil = __wgById("wg-pilot-fx-focus");
|
|
113
113
|
if (!veil) {
|
|
114
114
|
veil = document.createElement("div");
|
|
115
115
|
veil.id = "wg-pilot-fx-focus";
|
|
116
|
-
|
|
116
|
+
__wgAdd(veil);
|
|
117
117
|
}
|
|
118
118
|
const pad = 10;
|
|
119
119
|
veil.style.left = `${Math.max(0, box.x - pad)}px`;
|
|
@@ -125,11 +125,11 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
125
125
|
};
|
|
126
126
|
const setZoomBadge = (scale) => {
|
|
127
127
|
const level = Number.isFinite(scale) && scale > 0 ? scale : 1;
|
|
128
|
-
let badge =
|
|
128
|
+
let badge = __wgById("wg-pilot-fx-zoom");
|
|
129
129
|
if (!badge) {
|
|
130
130
|
badge = document.createElement("div");
|
|
131
131
|
badge.id = "wg-pilot-fx-zoom";
|
|
132
|
-
|
|
132
|
+
__wgAdd(badge);
|
|
133
133
|
}
|
|
134
134
|
const zoomed = level > 1.001 || level < 0.999;
|
|
135
135
|
badge.dataset.zoomed = zoomed ? "1" : "0";
|
|
@@ -143,27 +143,27 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
143
143
|
root.style.removeProperty("transform");
|
|
144
144
|
root.style.removeProperty("transform-origin");
|
|
145
145
|
root.style.removeProperty("transition");
|
|
146
|
-
|
|
146
|
+
__wgById("wg-pilot-fx-zoom")?.remove();
|
|
147
147
|
};
|
|
148
148
|
const setDeviceChip = (label) => {
|
|
149
|
-
|
|
149
|
+
__wgById("wg-pilot-fx-device")?.remove();
|
|
150
150
|
if (!label)
|
|
151
151
|
return;
|
|
152
152
|
const chip = document.createElement("div");
|
|
153
153
|
chip.id = "wg-pilot-fx-device";
|
|
154
154
|
chip.dataset.preset = label;
|
|
155
155
|
chip.textContent = `device \u00b7 ${label}`;
|
|
156
|
-
|
|
156
|
+
__wgAdd(chip);
|
|
157
157
|
};
|
|
158
158
|
w.__wgPilotFxZoomOutOnHide = zoomOut;
|
|
159
159
|
const clearFx = () => {
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
__wgQA(".wg-pilot-fx-ring, .wg-pilot-fx-label").forEach((el) => el.remove());
|
|
161
|
+
__wgById("wg-pilot-fx-todos")?.remove();
|
|
162
162
|
clearFocus();
|
|
163
163
|
if (w.__wgPilotFxZoomOutOnHide !== false || clearAll)
|
|
164
164
|
clearZoom();
|
|
165
165
|
if (clearAll) {
|
|
166
|
-
|
|
166
|
+
__wgById("wg-pilot-fx-device")?.remove();
|
|
167
167
|
clearZoom();
|
|
168
168
|
}
|
|
169
169
|
};
|
|
@@ -206,8 +206,8 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
206
206
|
if (ring.color) {
|
|
207
207
|
labelEl.style.color = ring.color;
|
|
208
208
|
}
|
|
209
|
-
|
|
210
|
-
|
|
209
|
+
__wgAdd(ringEl);
|
|
210
|
+
__wgAdd(labelEl);
|
|
211
211
|
const lw = labelEl.offsetWidth;
|
|
212
212
|
const lh = labelEl.offsetHeight;
|
|
213
213
|
let labelLeft = rect.left - pad;
|
|
@@ -266,18 +266,18 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
266
266
|
more.textContent = "+" + (todos.length - (end - start)) + " more";
|
|
267
267
|
dock.appendChild(more);
|
|
268
268
|
}
|
|
269
|
-
|
|
269
|
+
__wgAdd(dock);
|
|
270
270
|
}
|
|
271
271
|
if (focusBox)
|
|
272
272
|
applyFocus(focusBox);
|
|
273
273
|
// Dim todos under rings / focus so captions stay readable.
|
|
274
|
-
const dockEl =
|
|
274
|
+
const dockEl = __wgById("wg-pilot-fx-todos");
|
|
275
275
|
if (dockEl && todoUi.behindRing !== false && (painted > 0 || focusBox)) {
|
|
276
276
|
dockEl.classList.add("wg-todo-behind");
|
|
277
277
|
}
|
|
278
278
|
// Collision flip: if a painted ring intersects the dock, flip side once.
|
|
279
279
|
if (dockEl && todoUi.collision !== false && painted > 0) {
|
|
280
|
-
const firstRing =
|
|
280
|
+
const firstRing = __wgQ(".wg-pilot-fx-ring");
|
|
281
281
|
if (firstRing) {
|
|
282
282
|
const rr = firstRing.getBoundingClientRect();
|
|
283
283
|
const dr = dockEl.getBoundingClientRect();
|
|
@@ -10,9 +10,9 @@ export async function updatePilotOverlay(page, info) {
|
|
|
10
10
|
await ensureInstalled(page);
|
|
11
11
|
await page
|
|
12
12
|
.evaluate(async ({ sessionId, snapshot, graph }) => {
|
|
13
|
-
const badge =
|
|
14
|
-
const current =
|
|
15
|
-
const graphPanel =
|
|
13
|
+
const badge = __wgById("wg-pilot-badge");
|
|
14
|
+
const current = __wgById("wg-pilot-panel-current");
|
|
15
|
+
const graphPanel = __wgById("wg-pilot-panel-graph");
|
|
16
16
|
if (!badge || !current || !graphPanel)
|
|
17
17
|
return;
|
|
18
18
|
const idPart = sessionId ? `session ${sessionId}` : "no session id";
|
|
@@ -1,5 +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
|
+
import { ensureShadowRoot, installShadowRoot } from "../ui/shadow.js";
|
|
3
4
|
import { pilotFxRingCss } from "../ui/components/ring.js";
|
|
4
5
|
import { WAYGRAPH_RING_CSS } from "../highlights.js";
|
|
5
6
|
// Real, direct user request: this overlay's own colors were an improvised
|
|
@@ -109,12 +110,9 @@ ${pilotFxRingCss()}
|
|
|
109
110
|
` + WAYGRAPH_RING_CSS;
|
|
110
111
|
/** Browser-side shell install — runs on every document via context.addInitScript. */
|
|
111
112
|
function installPilotOverlayShell(css) {
|
|
112
|
-
if (
|
|
113
|
+
if (__wgById("wg-pilot-overlay"))
|
|
113
114
|
return;
|
|
114
|
-
|
|
115
|
-
style.id = "wg-pilot-overlay-css";
|
|
116
|
-
style.textContent = css;
|
|
117
|
-
document.documentElement.appendChild(style);
|
|
115
|
+
__wgCss(css, "wg-pilot-overlay-css");
|
|
118
116
|
const root = document.createElement("div");
|
|
119
117
|
root.id = "wg-pilot-overlay";
|
|
120
118
|
root.innerHTML =
|
|
@@ -125,36 +123,36 @@ function installPilotOverlayShell(css) {
|
|
|
125
123
|
'<div id="wg-pilot-panel-current"></div>' +
|
|
126
124
|
'<div id="wg-pilot-panel-graph" style="display:none"></div>' +
|
|
127
125
|
"</div>";
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
__wgAdd(root);
|
|
127
|
+
__wgById("wg-pilot-badge").addEventListener("click", () => {
|
|
128
|
+
__wgById("wg-pilot-panel").classList.toggle("wg-pilot-open");
|
|
131
129
|
});
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
130
|
+
__wgById("wg-pilot-view-current").addEventListener("click", () => {
|
|
131
|
+
__wgById("wg-pilot-view-current").classList.add("wg-pilot-tab-active");
|
|
132
|
+
__wgById("wg-pilot-view-graph").classList.remove("wg-pilot-tab-active");
|
|
133
|
+
__wgById("wg-pilot-panel-current").style.display = "";
|
|
134
|
+
__wgById("wg-pilot-panel-graph").style.display = "none";
|
|
137
135
|
});
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
136
|
+
__wgById("wg-pilot-view-graph").addEventListener("click", () => {
|
|
137
|
+
__wgById("wg-pilot-view-graph").classList.add("wg-pilot-tab-active");
|
|
138
|
+
__wgById("wg-pilot-view-current").classList.remove("wg-pilot-tab-active");
|
|
139
|
+
__wgById("wg-pilot-panel-graph").style.display = "";
|
|
140
|
+
__wgById("wg-pilot-panel-current").style.display = "none";
|
|
143
141
|
});
|
|
144
|
-
if (!
|
|
142
|
+
if (!__wgById("wg-pilot-activity")) {
|
|
145
143
|
const toast = document.createElement("div");
|
|
146
144
|
toast.id = "wg-pilot-activity";
|
|
147
|
-
|
|
145
|
+
__wgAdd(toast);
|
|
148
146
|
}
|
|
149
|
-
if (!
|
|
147
|
+
if (!__wgById("wg-ring")) {
|
|
150
148
|
const ring = document.createElement("div");
|
|
151
149
|
ring.id = "wg-ring";
|
|
152
|
-
|
|
150
|
+
__wgAdd(ring);
|
|
153
151
|
}
|
|
154
|
-
if (!
|
|
152
|
+
if (!__wgById("wg-ring-label")) {
|
|
155
153
|
const ringLabel = document.createElement("div");
|
|
156
154
|
ringLabel.id = "wg-ring-label";
|
|
157
|
-
|
|
155
|
+
__wgAdd(ringLabel);
|
|
158
156
|
}
|
|
159
157
|
}
|
|
160
158
|
/**
|
|
@@ -163,10 +161,12 @@ function installPilotOverlayShell(css) {
|
|
|
163
161
|
* page is blank or replaced.
|
|
164
162
|
*/
|
|
165
163
|
export async function installPersistentPilotOverlay(context) {
|
|
164
|
+
await context.addInitScript(installShadowRoot);
|
|
166
165
|
await context.addInitScript(installPilotOverlayShell, OVERLAY_CSS);
|
|
167
166
|
}
|
|
168
167
|
/** Idempotent - safe to call before every update, matching narrate mode's own precedent. */
|
|
169
168
|
export async function ensureInstalled(page) {
|
|
169
|
+
await ensureShadowRoot(page);
|
|
170
170
|
await page.evaluate(installPilotOverlayShell, OVERLAY_CSS).catch(() => { });
|
|
171
171
|
}
|
|
172
172
|
/**
|
|
@@ -183,7 +183,7 @@ export async function showPilotActivity(page, text) {
|
|
|
183
183
|
await ensureInstalled(page);
|
|
184
184
|
await page
|
|
185
185
|
.evaluate((text) => {
|
|
186
|
-
const toast =
|
|
186
|
+
const toast = __wgById("wg-pilot-activity");
|
|
187
187
|
if (!toast)
|
|
188
188
|
return;
|
|
189
189
|
toast.textContent = text;
|
|
@@ -227,8 +227,8 @@ export async function showPilotVision(page, selector, label, tone = "auto") {
|
|
|
227
227
|
await ensureInstalled(page);
|
|
228
228
|
await page
|
|
229
229
|
.evaluate(({ selector, label, tone }) => {
|
|
230
|
-
const ring =
|
|
231
|
-
const tag =
|
|
230
|
+
const ring = __wgById("wg-ring");
|
|
231
|
+
const tag = __wgById("wg-ring-label");
|
|
232
232
|
if (!ring || !tag)
|
|
233
233
|
return;
|
|
234
234
|
const w = window;
|
package/dist/pilot-overlay.d.ts
CHANGED
package/dist/pilot-overlay.js
CHANGED
package/dist/runner/cursor.js
CHANGED
|
@@ -48,7 +48,7 @@ export async function playSwipeTrail(page, opts) {
|
|
|
48
48
|
: "left";
|
|
49
49
|
const ms = Math.max(280, Math.min(1400, Number(payload.ms) || 720));
|
|
50
50
|
const label = payload.label || "swipe";
|
|
51
|
-
let layer =
|
|
51
|
+
let layer = __wgById("wg-swipe-layer");
|
|
52
52
|
if (layer) layer.remove();
|
|
53
53
|
layer = document.createElement("div");
|
|
54
54
|
layer.id = "wg-swipe-layer";
|
|
@@ -67,7 +67,7 @@ export async function playSwipeTrail(page, opts) {
|
|
|
67
67
|
"border:1px solid rgba(56,189,248,.55);font:700 12px/1.2 system-ui,sans-serif;";
|
|
68
68
|
layer.appendChild(lab);
|
|
69
69
|
layer.appendChild(finger);
|
|
70
|
-
|
|
70
|
+
__wgAdd(layer);
|
|
71
71
|
const vw = window.innerWidth || 390;
|
|
72
72
|
const vh = window.innerHeight || 844;
|
|
73
73
|
const pad = Math.min(vw, vh) * 0.18;
|
|
@@ -121,7 +121,7 @@ export async function playSwipeTrail(page, opts) {
|
|
|
121
121
|
});
|
|
122
122
|
if (i === steps) {
|
|
123
123
|
setTimeout(() => {
|
|
124
|
-
const el =
|
|
124
|
+
const el = __wgById("wg-swipe-layer");
|
|
125
125
|
if (el) el.remove();
|
|
126
126
|
}, 400);
|
|
127
127
|
}
|
|
@@ -12,7 +12,7 @@ export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay,
|
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
14
|
if (title) {
|
|
15
|
-
let banner =
|
|
15
|
+
let banner = __wgById("wg-banner");
|
|
16
16
|
if (!banner) {
|
|
17
17
|
banner = document.createElement("div");
|
|
18
18
|
banner.id = "wg-banner";
|
|
@@ -39,7 +39,7 @@ export function installBanner({ title, favicon, bannerPos, todoPos, envAutoplay,
|
|
|
39
39
|
text.textContent = title;
|
|
40
40
|
banner.appendChild(tag);
|
|
41
41
|
banner.appendChild(text);
|
|
42
|
-
|
|
42
|
+
__wgAdd(banner);
|
|
43
43
|
} else {
|
|
44
44
|
// Fixture / episode title changes every step - update in place
|
|
45
45
|
// (banner is created once; do not leave the first step's text stuck).
|
|
@@ -19,17 +19,17 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
19
19
|
} catch {
|
|
20
20
|
/* private mode / blocked storage - falls back to manual gating */
|
|
21
21
|
}
|
|
22
|
-
if (!
|
|
22
|
+
if (!__wgById("wg-ring")) {
|
|
23
23
|
const ring = document.createElement("div");
|
|
24
24
|
ring.id = "wg-ring";
|
|
25
|
-
|
|
25
|
+
__wgAdd(ring);
|
|
26
26
|
}
|
|
27
|
-
if (!
|
|
27
|
+
if (!__wgById("wg-ring-label")) {
|
|
28
28
|
const ringLabel = document.createElement("div");
|
|
29
29
|
ringLabel.id = "wg-ring-label";
|
|
30
|
-
|
|
30
|
+
__wgAdd(ringLabel);
|
|
31
31
|
}
|
|
32
|
-
if (!
|
|
32
|
+
if (!__wgById("wg-cursor")) {
|
|
33
33
|
const cursor = document.createElement("div");
|
|
34
34
|
cursor.id = "wg-cursor";
|
|
35
35
|
// Dark fill + white stroke, same as help-center-clip-engine's own
|
|
@@ -39,15 +39,15 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
39
39
|
"<svg viewBox='0 0 32 32' width='24' height='24'>" +
|
|
40
40
|
"<path fill='#0C0C1A' stroke='#fff' stroke-width='1.4' stroke-linejoin='round' " +
|
|
41
41
|
"d='M6 3.5l1.4 22.5 5.8-5.4 4.2 9.4 3.6-1.6-4.2-9.2H26z'/></svg>";
|
|
42
|
-
|
|
42
|
+
__wgAdd(cursor);
|
|
43
43
|
}
|
|
44
|
-
if (!
|
|
44
|
+
if (!__wgById("wg-click-pulse")) {
|
|
45
45
|
const pulse = document.createElement("div");
|
|
46
46
|
pulse.id = "wg-click-pulse";
|
|
47
|
-
|
|
47
|
+
__wgAdd(pulse);
|
|
48
48
|
}
|
|
49
49
|
window.__wgMoveCursorTo = (x, y, ms, instant) => {
|
|
50
|
-
const cursor =
|
|
50
|
+
const cursor = __wgById("wg-cursor");
|
|
51
51
|
if (!cursor) return;
|
|
52
52
|
cursor.style.setProperty("--wg-cursor-ms", (ms || 600) + "ms");
|
|
53
53
|
if (instant) {
|
|
@@ -62,12 +62,12 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
62
62
|
cursor.style.opacity = "1";
|
|
63
63
|
};
|
|
64
64
|
window.__wgHideCursor = () => {
|
|
65
|
-
const cursor =
|
|
65
|
+
const cursor = __wgById("wg-cursor");
|
|
66
66
|
if (cursor) cursor.style.opacity = "0";
|
|
67
67
|
};
|
|
68
68
|
window.__wgPositionRing = (box, label, tone, style) => {
|
|
69
|
-
const ring =
|
|
70
|
-
const ringLabel =
|
|
69
|
+
const ring = __wgById("wg-ring");
|
|
70
|
+
const ringLabel = __wgById("wg-ring-label");
|
|
71
71
|
if (!ring || !ringLabel || !box) return;
|
|
72
72
|
const raw = (tone || "planned") + "";
|
|
73
73
|
const t =
|
|
@@ -119,12 +119,12 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
119
119
|
window.__wgTodosSetBehind = (on) => {
|
|
120
120
|
const ui = window.__wgTodoDockUi || {};
|
|
121
121
|
if (ui.behindRing === false) {
|
|
122
|
-
|
|
122
|
+
__wgQA(".wg-todo-dock, #wg-todo-dock").forEach((el) => {
|
|
123
123
|
el.classList.remove("wg-todo-behind");
|
|
124
124
|
});
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
|
-
|
|
127
|
+
__wgQA(".wg-todo-dock, #wg-todo-dock").forEach((el) => {
|
|
128
128
|
el.classList.toggle("wg-todo-behind", !!on);
|
|
129
129
|
});
|
|
130
130
|
};
|
|
@@ -145,7 +145,7 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
145
145
|
const r = el.getBoundingClientRect();
|
|
146
146
|
return !(r.right < rx1 || r.left > rx2 || r.bottom < ry1 || r.top > ry2);
|
|
147
147
|
};
|
|
148
|
-
const docks = [...
|
|
148
|
+
const docks = [...__wgQA(".wg-todo-dock, #wg-todo-dock")].filter(
|
|
149
149
|
(el, i, arr) => arr.indexOf(el) === i,
|
|
150
150
|
);
|
|
151
151
|
for (const dock of docks) {
|
|
@@ -194,7 +194,7 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
194
194
|
tick();
|
|
195
195
|
};
|
|
196
196
|
window.__wgClickPulse = (x, y, tone) => {
|
|
197
|
-
const pulse =
|
|
197
|
+
const pulse = __wgById("wg-click-pulse");
|
|
198
198
|
if (!pulse) return;
|
|
199
199
|
const raw = (tone || "planned") + "";
|
|
200
200
|
pulse.dataset.tone =
|
|
@@ -214,14 +214,14 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
214
214
|
// action finishes, not just its first sub-step.
|
|
215
215
|
if (window.__wgNarrateOwnsRing) return;
|
|
216
216
|
if (window.__wgStopRingFollow) window.__wgStopRingFollow();
|
|
217
|
-
const ring =
|
|
218
|
-
const ringLabel =
|
|
217
|
+
const ring = __wgById("wg-ring");
|
|
218
|
+
const ringLabel = __wgById("wg-ring-label");
|
|
219
219
|
if (ring) ring.style.opacity = "0";
|
|
220
220
|
if (ringLabel) ringLabel.style.opacity = "0";
|
|
221
221
|
if (window.__wgClearFocus) window.__wgClearFocus();
|
|
222
222
|
if (window.__wgTodosSetBehind) window.__wgTodosSetBehind(false);
|
|
223
223
|
window.__wgTodoCollisionLocked = false;
|
|
224
|
-
|
|
224
|
+
__wgQA(".wg-todo-dock[data-tucked], #wg-todo-dock[data-tucked]").forEach((el) => {
|
|
225
225
|
delete el.dataset.tucked;
|
|
226
226
|
});
|
|
227
227
|
// Honor zoomOut:false - keep camera until next zoom / desktop clear.
|
|
@@ -236,11 +236,11 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
236
236
|
}
|
|
237
237
|
};
|
|
238
238
|
window.__wgClearFocus = () => {
|
|
239
|
-
const veil =
|
|
239
|
+
const veil = __wgById("wg-focus-veil");
|
|
240
240
|
if (!veil) return;
|
|
241
241
|
veil.classList.remove("wg-in");
|
|
242
242
|
setTimeout(() => {
|
|
243
|
-
const v =
|
|
243
|
+
const v = __wgById("wg-focus-veil");
|
|
244
244
|
if (v && !v.classList.contains("wg-in")) v.remove();
|
|
245
245
|
}, 320);
|
|
246
246
|
};
|
|
@@ -249,12 +249,12 @@ export function installCore({ title, favicon, bannerPos, todoPos, envAutoplay, t
|
|
|
249
249
|
if (window.__wgClearFocus) window.__wgClearFocus();
|
|
250
250
|
return;
|
|
251
251
|
}
|
|
252
|
-
let veil =
|
|
252
|
+
let veil = __wgById("wg-focus-veil");
|
|
253
253
|
if (!veil) {
|
|
254
254
|
veil = document.createElement("div");
|
|
255
255
|
veil.id = "wg-focus-veil";
|
|
256
256
|
veil.setAttribute("data-wg-ui", "1");
|
|
257
|
-
|
|
257
|
+
__wgAdd(veil);
|
|
258
258
|
}
|
|
259
259
|
const pad = 10;
|
|
260
260
|
veil.style.left = Math.max(0, box.x - pad) + "px";
|