waygraph 0.15.5 → 0.15.7
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-session.js +5 -0
- package/dist/pilot-overlay.d.ts +39 -5
- package/dist/pilot-overlay.js +217 -19
- package/examples/saucedemo/.waygraph-auto/03710cfc.json +8 -0
- package/examples/saucedemo/.waygraph-auto/03710cfc.log +0 -0
- package/examples/saucedemo/.waygraph-auto/2d45a578.log +0 -0
- package/examples/saucedemo/.waygraph-auto/4258d26d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/605d965b.json +8 -0
- package/examples/saucedemo/.waygraph-auto/605d965b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/6443943b.log +0 -0
- package/examples/saucedemo/.waygraph-auto/6b667734.json +8 -0
- package/examples/saucedemo/.waygraph-auto/6b667734.log +0 -0
- package/examples/saucedemo/.waygraph-auto/90141d7e.log +4 -0
- package/package.json +1 -1
- package/templates/skills/waygraph-pilot.skill.md +12 -3
package/dist/auto-session.js
CHANGED
|
@@ -682,6 +682,11 @@ export class AutoSession {
|
|
|
682
682
|
: [
|
|
683
683
|
fixtures.rings?.length ? `${fixtures.rings.length} ring(s)` : null,
|
|
684
684
|
fixtures.todos?.length ? `${fixtures.todos.length} todo(s)` : null,
|
|
685
|
+
fixtures.zoom && fixtures.zoom > 1.001 ? `zoom ${fixtures.zoom}` : null,
|
|
686
|
+
fixtures.device
|
|
687
|
+
? `device ${typeof fixtures.device === "string" ? fixtures.device : fixtures.device.preset || "custom"}`
|
|
688
|
+
: null,
|
|
689
|
+
fixtures.rings?.some((r) => r.focus) ? "focus" : null,
|
|
685
690
|
]
|
|
686
691
|
.filter(Boolean)
|
|
687
692
|
.join(", ") || "fixtures";
|
package/dist/pilot-overlay.d.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import type { Page } from "@playwright/test";
|
|
20
20
|
import type { SessionSnapshot } from "./auto-session.js";
|
|
21
|
-
import { type HighlightTone } from "./highlights.js";
|
|
21
|
+
import { type HighlightTone, type DevicePreset, type DeviceState } from "./highlights.js";
|
|
22
22
|
/**
|
|
23
23
|
* Bottom-left transient toast, separate from the persistent bottom-right
|
|
24
24
|
* badge - real, direct user request: something that visibly flags "a
|
|
@@ -61,14 +61,30 @@ export declare function showPilotVision(page: Page, selector: string, label: str
|
|
|
61
61
|
export type PilotFixtureRing = {
|
|
62
62
|
selector: string;
|
|
63
63
|
label: string;
|
|
64
|
+
/** Extra caption line (demo `detail`). */
|
|
65
|
+
detail?: string;
|
|
66
|
+
/** Short badge, e.g. AC / BUG / GATE. */
|
|
67
|
+
tag?: string;
|
|
64
68
|
/** Any {@link HighlightTone} or alias (`error`/`blue`/…). Normalized on paint. */
|
|
65
69
|
tone?: HighlightTone | string;
|
|
66
70
|
size?: "sm" | "md" | "lg" | string;
|
|
67
71
|
weight?: "normal" | "bold" | string;
|
|
72
|
+
/** Caption text color (CSS). Overrides tone label color when set. */
|
|
73
|
+
color?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Camera zoom while this ring is up (demo parity: scroll + zoom badge;
|
|
76
|
+
* does not CSS-scale the page). Typical `1.25`..`2`.
|
|
77
|
+
*/
|
|
78
|
+
zoom?: number;
|
|
79
|
+
/** When false, keep zoom after this paint / holdMs. Default true. */
|
|
80
|
+
zoomOut?: boolean;
|
|
81
|
+
/** Spotlight: dim the rest of the page around this target. */
|
|
82
|
+
focus?: boolean;
|
|
68
83
|
};
|
|
69
84
|
/**
|
|
70
85
|
* Agent-sent highlight fixtures for a live Pilot / auto session.
|
|
71
86
|
* Painted by {@link showPilotFixtures}; driven via IPC `op: "highlight"`.
|
|
87
|
+
* Mirrors demo stub surface: rings, todos, zoom, focus, device.
|
|
72
88
|
*/
|
|
73
89
|
export type PilotHighlightFixtures = {
|
|
74
90
|
/** Replace current fixture rings with these (empty + no todos = clear). */
|
|
@@ -79,18 +95,36 @@ export type PilotHighlightFixtures = {
|
|
|
79
95
|
todoIndex?: number;
|
|
80
96
|
/** Optional title above the todo list. */
|
|
81
97
|
todoTitle?: string;
|
|
98
|
+
/** Todo dock side. Default `right`. */
|
|
99
|
+
todoPos?: "left" | "right";
|
|
82
100
|
/**
|
|
83
101
|
* How long fixtures stay visible (ms). `0` = until the next highlight /
|
|
84
|
-
* clear. Default `
|
|
102
|
+
* clear. Default `30000` (30s) unless specified.
|
|
85
103
|
*/
|
|
86
104
|
holdMs?: number;
|
|
87
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* Camera zoom toward a selector (demo parity: scrollIntoView + zoom badge).
|
|
107
|
+
* Defaults the zoom target to {@link zoomSelector}, else the last ring's
|
|
108
|
+
* selector (or a ring that sets its own `zoom`). Cleared on `clear: true`
|
|
109
|
+
* or when holdMs expires (if zoomOut).
|
|
110
|
+
*/
|
|
111
|
+
zoom?: number;
|
|
112
|
+
/** Element to zoom toward when {@link zoom} is set (defaults to last ring). */
|
|
113
|
+
zoomSelector?: string;
|
|
114
|
+
/** When false, keep zoom after fixtures clear/expire. Default true. */
|
|
115
|
+
zoomOut?: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Viewport / device fixture (`mobile` | `tablet` | `desktop`, or a full
|
|
118
|
+
* {@link DeviceState}). Applied via Playwright `setViewportSize`.
|
|
119
|
+
*/
|
|
120
|
+
device?: DevicePreset | DeviceState;
|
|
121
|
+
/** Drop every agent fixture ring/todo/focus/zoom immediately. */
|
|
88
122
|
clear?: boolean;
|
|
89
123
|
};
|
|
90
124
|
/**
|
|
91
125
|
* Paint (or clear) agent-authored highlight fixtures on the live page.
|
|
92
|
-
* Multi-ring + optional todo strip
|
|
93
|
-
*
|
|
126
|
+
* Multi-ring + optional todo strip + zoom/focus/device - the Pilot equivalent
|
|
127
|
+
* of Block `stubBefore` narration in `waygraph demo`.
|
|
94
128
|
* Does not import `cli.ts` (see file header).
|
|
95
129
|
*/
|
|
96
130
|
export declare function showPilotFixtures(page: Page, fixtures: PilotHighlightFixtures): Promise<{
|
package/dist/pilot-overlay.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WAYGRAPH_RING_CSS, normalizeHighlightTone, normalizeHighlightSize, normalizeHighlightWeight,
|
|
1
|
+
import { WAYGRAPH_RING_CSS, normalizeHighlightTone, normalizeHighlightSize, normalizeHighlightWeight, formatHighlightCaption, resolveDeviceState, } from "./highlights.js";
|
|
2
2
|
// Real, direct user request: this overlay's own colors were an improvised
|
|
3
3
|
// purple/white scheme (#a78bfa / #1a1033) that didn't match anything else -
|
|
4
4
|
// "our design here seems like barely shares with the ui on the stepper
|
|
@@ -88,16 +88,41 @@ const OVERLAY_CSS = `
|
|
|
88
88
|
.wg-pilot-fx-label[data-size=lg]{font-size:16px;padding:8px 14px;}
|
|
89
89
|
.wg-pilot-fx-label[data-weight=bold]{font-weight:800;}
|
|
90
90
|
#wg-pilot-fx-todos{
|
|
91
|
-
position:fixed;z-index:2147483645;top:72px;
|
|
91
|
+
position:fixed;z-index:2147483645;top:72px;max-width:280px;
|
|
92
92
|
font:12px/1.4 ui-sans-serif,system-ui,sans-serif;color:#fff;
|
|
93
93
|
background:rgba(20,10,40,.94);border-radius:10px;padding:10px 12px;
|
|
94
94
|
box-shadow:0 2px 10px rgba(0,0,0,.3);pointer-events:none;
|
|
95
95
|
}
|
|
96
|
+
#wg-pilot-fx-todos[data-pos=left]{left:14px;right:auto;}
|
|
97
|
+
#wg-pilot-fx-todos[data-pos=right]{right:14px;left:auto;}
|
|
96
98
|
#wg-pilot-fx-todos .wg-pilot-fx-todo-title{font-weight:700;color:#c9a6ff;margin-bottom:6px;}
|
|
97
99
|
#wg-pilot-fx-todos ol{margin:0;padding-left:18px;}
|
|
98
100
|
#wg-pilot-fx-todos li{margin:3px 0;color:#ddd;}
|
|
99
101
|
#wg-pilot-fx-todos li.wg-pilot-fx-todo-done{color:#888;text-decoration:line-through;}
|
|
100
102
|
#wg-pilot-fx-todos li.wg-pilot-fx-todo-now{color:#fff;font-weight:700;}
|
|
103
|
+
/* Spotlight (demo focus:true) - dim page, cutout around target. */
|
|
104
|
+
#wg-pilot-fx-focus{position:fixed;z-index:2147483644;pointer-events:none;
|
|
105
|
+
border-radius:12px;box-shadow:0 0 0 9999px rgba(8,4,20,.62);
|
|
106
|
+
opacity:0;transition:opacity .3s ease,left .3s ease,top .3s ease,width .3s ease,height .3s ease;}
|
|
107
|
+
#wg-pilot-fx-focus.wg-in{opacity:1;}
|
|
108
|
+
/* Zoom HUD (demo parity - badge only; no CSS scale of the page). */
|
|
109
|
+
#wg-pilot-fx-zoom{position:fixed;z-index:2147483646;bottom:14px;right:14px;
|
|
110
|
+
display:flex;align-items:center;gap:7px;padding:6px 11px 6px 8px;
|
|
111
|
+
border-radius:999px;background:rgba(20,10,40,.94);color:#f0e8ff;
|
|
112
|
+
border:1px solid rgba(250,204,21,.6);box-shadow:0 6px 18px rgba(0,0,0,.4);
|
|
113
|
+
font:700 12px/1.2 system-ui,sans-serif;pointer-events:none;}
|
|
114
|
+
#wg-pilot-fx-zoom .wg-pilot-fx-zoom-ico{width:18px;height:18px;display:flex;align-items:center;justify-content:center;
|
|
115
|
+
border-radius:6px;background:rgba(250,204,21,.22);}
|
|
116
|
+
#wg-pilot-fx-zoom .wg-pilot-fx-zoom-ico svg{width:14px;height:14px;display:block;}
|
|
117
|
+
#wg-pilot-fx-zoom .wg-pilot-fx-zoom-val{color:#fde68a;font-variant-numeric:tabular-nums;font-weight:800;min-width:3.2em;}
|
|
118
|
+
#wg-pilot-fx-zoom[data-zoomed="1"]{border-color:#fbbf24;}
|
|
119
|
+
#wg-pilot-fx-device{position:fixed;z-index:2147483646;top:14px;right:14px;
|
|
120
|
+
padding:8px 12px;border-radius:10px;background:rgba(20,10,40,.94);color:#f0e8ff;
|
|
121
|
+
border:1px solid rgba(124,58,237,.55);font:700 12px/1.2 system-ui,sans-serif;
|
|
122
|
+
pointer-events:none;box-shadow:0 6px 18px rgba(0,0,0,.35);}
|
|
123
|
+
#wg-pilot-fx-device[data-preset=mobile]{border-color:#3B82F6;}
|
|
124
|
+
#wg-pilot-fx-device[data-preset=tablet]{border-color:#22C55E;}
|
|
125
|
+
#wg-pilot-fx-device[data-preset=desktop]{border-color:#9CA3AF;}
|
|
101
126
|
` + WAYGRAPH_RING_CSS;
|
|
102
127
|
/** Idempotent - safe to call before every update, matching narrate mode's own precedent. */
|
|
103
128
|
async function ensureInstalled(page) {
|
|
@@ -254,8 +279,8 @@ export async function showPilotVision(page, selector, label, tone = "auto") {
|
|
|
254
279
|
}
|
|
255
280
|
/**
|
|
256
281
|
* Paint (or clear) agent-authored highlight fixtures on the live page.
|
|
257
|
-
* Multi-ring + optional todo strip
|
|
258
|
-
*
|
|
282
|
+
* Multi-ring + optional todo strip + zoom/focus/device - the Pilot equivalent
|
|
283
|
+
* of Block `stubBefore` narration in `waygraph demo`.
|
|
259
284
|
* Does not import `cli.ts` (see file header).
|
|
260
285
|
*/
|
|
261
286
|
export async function showPilotFixtures(page, fixtures) {
|
|
@@ -263,38 +288,168 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
263
288
|
const holdMs = fixtures.clear === true
|
|
264
289
|
? 0
|
|
265
290
|
: fixtures.holdMs === undefined
|
|
266
|
-
?
|
|
291
|
+
? 30_000
|
|
267
292
|
: Math.max(0, fixtures.holdMs);
|
|
268
293
|
const rings = (fixtures.clear ? [] : (fixtures.rings ?? [])).map((r) => {
|
|
269
294
|
const tone = normalizeHighlightTone(r.tone);
|
|
270
295
|
const size = normalizeHighlightSize(r.size);
|
|
271
296
|
const weight = normalizeHighlightWeight(r.weight);
|
|
272
|
-
const
|
|
273
|
-
|
|
297
|
+
const caption = { label: r.label, tone };
|
|
298
|
+
if (r.detail)
|
|
299
|
+
caption.detail = r.detail;
|
|
300
|
+
if (r.tag)
|
|
301
|
+
caption.tag = r.tag;
|
|
302
|
+
const label = formatHighlightCaption(caption);
|
|
274
303
|
return {
|
|
275
304
|
selector: r.selector,
|
|
276
305
|
label,
|
|
277
306
|
tone,
|
|
278
307
|
size,
|
|
279
308
|
weight,
|
|
309
|
+
color: typeof r.color === "string" && r.color.trim() ? r.color.trim() : "",
|
|
310
|
+
zoom: typeof r.zoom === "number" && Number.isFinite(r.zoom) && r.zoom > 0
|
|
311
|
+
? r.zoom
|
|
312
|
+
: undefined,
|
|
313
|
+
zoomOut: r.zoomOut,
|
|
314
|
+
focus: r.focus === true,
|
|
280
315
|
};
|
|
281
316
|
});
|
|
282
317
|
const todos = fixtures.clear ? [] : (fixtures.todos ?? []);
|
|
283
318
|
const todoIndex = fixtures.todoIndex ?? 0;
|
|
284
319
|
const todoTitle = fixtures.todoTitle ?? "Plan";
|
|
320
|
+
const todoPos = fixtures.todoPos === "left" ? "left" : "right";
|
|
321
|
+
// Effective zoom: phase zoom, else last ring that authored zoom.
|
|
322
|
+
let zoom = fixtures.clear === true
|
|
323
|
+
? 1
|
|
324
|
+
: typeof fixtures.zoom === "number" && Number.isFinite(fixtures.zoom)
|
|
325
|
+
? fixtures.zoom
|
|
326
|
+
: 1;
|
|
327
|
+
let zoomSelector = fixtures.zoomSelector ??
|
|
328
|
+
(rings.length > 0 ? rings[rings.length - 1].selector : undefined);
|
|
329
|
+
let zoomOut = fixtures.zoomOut !== false;
|
|
330
|
+
if (!fixtures.clear && zoom <= 1.001) {
|
|
331
|
+
for (let i = rings.length - 1; i >= 0; i--) {
|
|
332
|
+
const r = rings[i];
|
|
333
|
+
if (r.zoom !== undefined && r.zoom > 1.001) {
|
|
334
|
+
zoom = r.zoom;
|
|
335
|
+
zoomSelector = r.selector;
|
|
336
|
+
if (r.zoomOut !== undefined)
|
|
337
|
+
zoomOut = r.zoomOut !== false;
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else if (!fixtures.clear) {
|
|
343
|
+
// Phase zoomOut can still be overridden by the targeted ring.
|
|
344
|
+
const hit = rings.find((r) => r.selector === zoomSelector);
|
|
345
|
+
if (hit?.zoomOut !== undefined)
|
|
346
|
+
zoomOut = hit.zoomOut !== false;
|
|
347
|
+
}
|
|
348
|
+
// Device viewport (Node-side) before paint so rings land on the new size.
|
|
349
|
+
if (fixtures.clear === true) {
|
|
350
|
+
// Leave viewport alone on clear - only drop overlays.
|
|
351
|
+
}
|
|
352
|
+
else if (fixtures.device !== undefined) {
|
|
353
|
+
const d = resolveDeviceState(fixtures.device);
|
|
354
|
+
if (d) {
|
|
355
|
+
await page
|
|
356
|
+
.setViewportSize({
|
|
357
|
+
width: Math.max(200, Math.floor(d.viewport.width)),
|
|
358
|
+
height: Math.max(200, Math.floor(d.viewport.height)),
|
|
359
|
+
})
|
|
360
|
+
.catch(() => { });
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
const deviceLabel = fixtures.clear === true
|
|
364
|
+
? ""
|
|
365
|
+
: fixtures.device === undefined
|
|
366
|
+
? ""
|
|
367
|
+
: typeof fixtures.device === "string"
|
|
368
|
+
? fixtures.device
|
|
369
|
+
: fixtures.device.preset || "device";
|
|
285
370
|
return page
|
|
286
|
-
.evaluate(({ rings, todos, todoIndex, todoTitle, holdMs }) => {
|
|
371
|
+
.evaluate(({ rings, todos, todoIndex, todoTitle, todoPos, holdMs, zoom, zoomSelector, zoomOut, clearAll, deviceLabel, }) => {
|
|
287
372
|
const w = window;
|
|
288
373
|
if (w.__wgPilotFxHideTimer)
|
|
289
374
|
clearTimeout(w.__wgPilotFxHideTimer);
|
|
375
|
+
const clearFocus = () => {
|
|
376
|
+
const veil = document.getElementById("wg-pilot-fx-focus");
|
|
377
|
+
if (!veil)
|
|
378
|
+
return;
|
|
379
|
+
veil.classList.remove("wg-in");
|
|
380
|
+
setTimeout(() => {
|
|
381
|
+
const v = document.getElementById("wg-pilot-fx-focus");
|
|
382
|
+
if (v && !v.classList.contains("wg-in"))
|
|
383
|
+
v.remove();
|
|
384
|
+
}, 320);
|
|
385
|
+
};
|
|
386
|
+
const applyFocus = (box) => {
|
|
387
|
+
let veil = document.getElementById("wg-pilot-fx-focus");
|
|
388
|
+
if (!veil) {
|
|
389
|
+
veil = document.createElement("div");
|
|
390
|
+
veil.id = "wg-pilot-fx-focus";
|
|
391
|
+
document.documentElement.appendChild(veil);
|
|
392
|
+
}
|
|
393
|
+
const pad = 10;
|
|
394
|
+
veil.style.left = `${Math.max(0, box.x - pad)}px`;
|
|
395
|
+
veil.style.top = `${Math.max(0, box.y - pad)}px`;
|
|
396
|
+
veil.style.width = `${Math.max(8, box.width + pad * 2)}px`;
|
|
397
|
+
veil.style.height = `${Math.max(8, box.height + pad * 2)}px`;
|
|
398
|
+
void veil.offsetWidth;
|
|
399
|
+
veil.classList.add("wg-in");
|
|
400
|
+
};
|
|
401
|
+
const setZoomBadge = (scale) => {
|
|
402
|
+
const level = Number.isFinite(scale) && scale > 0 ? scale : 1;
|
|
403
|
+
let badge = document.getElementById("wg-pilot-fx-zoom");
|
|
404
|
+
if (!badge) {
|
|
405
|
+
badge = document.createElement("div");
|
|
406
|
+
badge.id = "wg-pilot-fx-zoom";
|
|
407
|
+
document.documentElement.appendChild(badge);
|
|
408
|
+
}
|
|
409
|
+
const zoomed = level > 1.001 || level < 0.999;
|
|
410
|
+
badge.dataset.zoomed = zoomed ? "1" : "0";
|
|
411
|
+
badge.innerHTML =
|
|
412
|
+
'<span class="wg-pilot-fx-zoom-ico"><svg viewBox="0 0 24 24" fill="none" stroke="#fde68a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg></span>' +
|
|
413
|
+
`<span class="wg-pilot-fx-zoom-val">${level.toFixed(2)}\u00d7</span>`;
|
|
414
|
+
};
|
|
415
|
+
const clearZoom = () => {
|
|
416
|
+
// Undo any leftover CSS-scale from older Pilot zoom path.
|
|
417
|
+
const root = document.documentElement;
|
|
418
|
+
root.style.removeProperty("transform");
|
|
419
|
+
root.style.removeProperty("transform-origin");
|
|
420
|
+
root.style.removeProperty("transition");
|
|
421
|
+
document.getElementById("wg-pilot-fx-zoom")?.remove();
|
|
422
|
+
};
|
|
423
|
+
const setDeviceChip = (label) => {
|
|
424
|
+
document.getElementById("wg-pilot-fx-device")?.remove();
|
|
425
|
+
if (!label)
|
|
426
|
+
return;
|
|
427
|
+
const chip = document.createElement("div");
|
|
428
|
+
chip.id = "wg-pilot-fx-device";
|
|
429
|
+
chip.dataset.preset = label;
|
|
430
|
+
chip.textContent = `device \u00b7 ${label}`;
|
|
431
|
+
document.documentElement.appendChild(chip);
|
|
432
|
+
};
|
|
433
|
+
w.__wgPilotFxZoomOutOnHide = zoomOut;
|
|
290
434
|
const clearFx = () => {
|
|
291
435
|
document.querySelectorAll(".wg-pilot-fx-ring, .wg-pilot-fx-label").forEach((el) => el.remove());
|
|
292
436
|
document.getElementById("wg-pilot-fx-todos")?.remove();
|
|
437
|
+
clearFocus();
|
|
438
|
+
if (w.__wgPilotFxZoomOutOnHide !== false || clearAll)
|
|
439
|
+
clearZoom();
|
|
440
|
+
if (clearAll) {
|
|
441
|
+
document.getElementById("wg-pilot-fx-device")?.remove();
|
|
442
|
+
clearZoom();
|
|
443
|
+
}
|
|
293
444
|
};
|
|
294
445
|
w.__wgPilotFxClear = clearFx;
|
|
295
446
|
clearFx();
|
|
447
|
+
if (clearAll) {
|
|
448
|
+
return { painted: 0, missing: [] };
|
|
449
|
+
}
|
|
296
450
|
const missing = [];
|
|
297
451
|
let painted = 0;
|
|
452
|
+
let focusBox = null;
|
|
298
453
|
for (const ring of rings) {
|
|
299
454
|
const el = document.querySelector(ring.selector);
|
|
300
455
|
if (!el) {
|
|
@@ -306,14 +461,11 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
306
461
|
missing.push(ring.selector);
|
|
307
462
|
continue;
|
|
308
463
|
}
|
|
309
|
-
const
|
|
310
|
-
const size = ring.size;
|
|
311
|
-
const weight = ring.weight;
|
|
312
|
-
const pad = size === "sm" ? 3 : size === "lg" ? 10 : 6;
|
|
464
|
+
const pad = ring.size === "sm" ? 3 : ring.size === "lg" ? 10 : 6;
|
|
313
465
|
const ringEl = document.createElement("div");
|
|
314
466
|
ringEl.className = "wg-pilot-fx-ring";
|
|
315
|
-
ringEl.dataset.tone = tone;
|
|
316
|
-
ringEl.dataset.size = size;
|
|
467
|
+
ringEl.dataset.tone = ring.tone;
|
|
468
|
+
ringEl.dataset.size = ring.size;
|
|
317
469
|
ringEl.style.left = `${rect.left - pad}px`;
|
|
318
470
|
ringEl.style.top = `${rect.top - pad}px`;
|
|
319
471
|
ringEl.style.width = `${Math.max(4, rect.width + pad * 2)}px`;
|
|
@@ -321,11 +473,14 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
321
473
|
ringEl.style.opacity = "1";
|
|
322
474
|
const labelEl = document.createElement("div");
|
|
323
475
|
labelEl.className = "wg-pilot-fx-label";
|
|
324
|
-
labelEl.dataset.tone = tone;
|
|
325
|
-
labelEl.dataset.size = size;
|
|
326
|
-
labelEl.dataset.weight = weight;
|
|
476
|
+
labelEl.dataset.tone = ring.tone;
|
|
477
|
+
labelEl.dataset.size = ring.size;
|
|
478
|
+
labelEl.dataset.weight = ring.weight;
|
|
327
479
|
labelEl.textContent = ring.label;
|
|
328
480
|
labelEl.style.opacity = "1";
|
|
481
|
+
if (ring.color) {
|
|
482
|
+
labelEl.style.color = ring.color;
|
|
483
|
+
}
|
|
329
484
|
document.documentElement.appendChild(ringEl);
|
|
330
485
|
document.documentElement.appendChild(labelEl);
|
|
331
486
|
const lw = labelEl.offsetWidth;
|
|
@@ -344,10 +499,14 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
344
499
|
labelEl.style.left = `${labelLeft}px`;
|
|
345
500
|
labelEl.style.top = `${labelTop}px`;
|
|
346
501
|
painted += 1;
|
|
502
|
+
if (ring.focus) {
|
|
503
|
+
focusBox = { x: rect.left, y: rect.top, width: rect.width, height: rect.height };
|
|
504
|
+
}
|
|
347
505
|
}
|
|
348
506
|
if (todos.length > 0) {
|
|
349
507
|
const dock = document.createElement("div");
|
|
350
508
|
dock.id = "wg-pilot-fx-todos";
|
|
509
|
+
dock.dataset.pos = todoPos;
|
|
351
510
|
const title = document.createElement("div");
|
|
352
511
|
title.className = "wg-pilot-fx-todo-title";
|
|
353
512
|
title.textContent = todoTitle;
|
|
@@ -365,11 +524,50 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
365
524
|
dock.appendChild(ol);
|
|
366
525
|
document.documentElement.appendChild(dock);
|
|
367
526
|
}
|
|
368
|
-
if (
|
|
527
|
+
if (focusBox)
|
|
528
|
+
applyFocus(focusBox);
|
|
529
|
+
if (zoom > 1.001 && zoomSelector) {
|
|
530
|
+
const target = document.querySelector(zoomSelector);
|
|
531
|
+
if (target) {
|
|
532
|
+
target.scrollIntoView({
|
|
533
|
+
block: "center",
|
|
534
|
+
inline: "center",
|
|
535
|
+
behavior: "instant",
|
|
536
|
+
});
|
|
537
|
+
// Re-apply focus after scroll so the cutout tracks the new rect.
|
|
538
|
+
if (focusBox) {
|
|
539
|
+
const r = target.getBoundingClientRect();
|
|
540
|
+
applyFocus({ x: r.left, y: r.top, width: r.width, height: r.height });
|
|
541
|
+
}
|
|
542
|
+
setZoomBadge(zoom);
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
missing.push(zoomSelector);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
else if (zoom > 1.001) {
|
|
549
|
+
setZoomBadge(zoom);
|
|
550
|
+
}
|
|
551
|
+
if (deviceLabel)
|
|
552
|
+
setDeviceChip(deviceLabel);
|
|
553
|
+
if (holdMs > 0 &&
|
|
554
|
+
(painted > 0 || todos.length > 0 || zoom > 1.001 || !!deviceLabel)) {
|
|
369
555
|
w.__wgPilotFxHideTimer = setTimeout(() => clearFx(), holdMs);
|
|
370
556
|
}
|
|
371
557
|
return { painted, missing };
|
|
372
|
-
}, {
|
|
558
|
+
}, {
|
|
559
|
+
rings,
|
|
560
|
+
todos,
|
|
561
|
+
todoIndex,
|
|
562
|
+
todoTitle,
|
|
563
|
+
todoPos,
|
|
564
|
+
holdMs,
|
|
565
|
+
zoom,
|
|
566
|
+
zoomSelector: zoomSelector ?? "",
|
|
567
|
+
zoomOut,
|
|
568
|
+
clearAll: fixtures.clear === true,
|
|
569
|
+
deviceLabel,
|
|
570
|
+
})
|
|
373
571
|
.catch(() => ({ painted: 0, missing: rings.map((r) => r.selector) }));
|
|
374
572
|
}
|
|
375
573
|
/**
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
(node:254673) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
2
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
|
3
|
+
(node:254673) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
|
|
4
|
+
(Use `node --trace-warnings ...` to show where the warning was created)
|
package/package.json
CHANGED
|
@@ -27,15 +27,24 @@ sending picks.
|
|
|
27
27
|
|
|
28
28
|
Block `stubBefore` / `withHighlightFixtures` only paint in `waygraph demo`. In Pilot they
|
|
29
29
|
land in `auto trace` as metadata but do **not** draw on the page. When a human is watching
|
|
30
|
-
a headful session (or you want to narrate intent before a send), paint yourself
|
|
30
|
+
a headful session (or you want to narrate intent before a send), paint yourself with the
|
|
31
|
+
same fixture surface:
|
|
31
32
|
|
|
32
33
|
```
|
|
33
|
-
waygraph auto highlight <sessionId> '{"rings":[{"selector":"#user-name","label":"Username","tone":"planned"},{"selector":"#password","label":"Password","tone":"info"}],"todos":["Fill username","Fill password","Submit"],"todoIndex":0,"holdMs":0}'
|
|
34
|
+
waygraph auto highlight <sessionId> '{"rings":[{"selector":"#user-name","label":"Username","tone":"planned","focus":true},{"selector":"#password","label":"Password","tone":"info","detail":"secret"}],"todos":["Fill username","Fill password","Submit"],"todoIndex":0,"zoom":1.5,"holdMs":0}'
|
|
35
|
+
waygraph auto highlight <sessionId> '{"device":"mobile","rings":[{"selector":".inventory_item:last-child","label":"Last item","zoom":1.6,"focus":true}],"holdMs":30000}'
|
|
34
36
|
waygraph auto highlight <sessionId> '{"clear":true}'
|
|
35
37
|
```
|
|
36
38
|
|
|
39
|
+
Supported fields (demo parity):
|
|
40
|
+
- `rings[]`: `selector`, `label`, `detail`, `tag`, `tone`, `size`, `weight`, `color`, `zoom`, `zoomOut`, `focus`
|
|
41
|
+
- `todos` / `todoIndex` / `todoTitle` / `todoPos` (`right` default | `left`)
|
|
42
|
+
- `zoom` / `zoomSelector` / `zoomOut` - scroll + zoom badge (not CSS page scale)
|
|
43
|
+
- `device`: `mobile` | `tablet` | `desktop` (Playwright viewport)
|
|
44
|
+
- `holdMs`: ms to keep fixtures; `0` = until the next highlight / clear (default 30000)
|
|
45
|
+
- `clear`: true drops rings/todos/focus/zoom badge
|
|
46
|
+
|
|
37
47
|
- `tone`: all demo tones - `planned` | `auto` | `info` | `warning` | `danger` | `success` | `orange` (aliases like `error`/`blue`/`green` work too)
|
|
38
|
-
- `holdMs`: ms to keep fixtures; `0` = until the next highlight / clear (default 12000)
|
|
39
48
|
- Bottom-left toast shows `Highlighting: …` (same strip as `Running (Dom): …`)
|
|
40
49
|
- Missing selectors are listed in the JSON response (`missing`) - not a hard failure
|
|
41
50
|
- Does not replace `auto send` - paint, then run the real Block
|