waygraph 0.15.4 → 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 +15 -5
- package/dist/pilot-overlay.d.ts +43 -8
- package/dist/pilot-overlay.js +229 -18
- 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/39f352c7.log +4 -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 +14 -4
package/dist/auto-session.js
CHANGED
|
@@ -677,11 +677,21 @@ export class AutoSession {
|
|
|
677
677
|
*/
|
|
678
678
|
async applyHighlight(fixtures) {
|
|
679
679
|
this.page = await ensureLivePage(this.context, this.page, this.startUrl);
|
|
680
|
-
const
|
|
681
|
-
? "clear
|
|
682
|
-
:
|
|
683
|
-
|
|
684
|
-
|
|
680
|
+
const detail = fixtures.clear === true
|
|
681
|
+
? "clear"
|
|
682
|
+
: [
|
|
683
|
+
fixtures.rings?.length ? `${fixtures.rings.length} ring(s)` : null,
|
|
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,
|
|
690
|
+
]
|
|
691
|
+
.filter(Boolean)
|
|
692
|
+
.join(", ") || "fixtures";
|
|
693
|
+
// Same bottom-left activity toast as Running (Dom)/(Block) - agent narration.
|
|
694
|
+
await showPilotActivity(this.page, `Highlighting: ${detail}`);
|
|
685
695
|
try {
|
|
686
696
|
const { painted, missing } = await showPilotFixtures(this.page, fixtures);
|
|
687
697
|
const menu = await this.currentMenu();
|
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,13 +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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
/** Extra caption line (demo `detail`). */
|
|
65
|
+
detail?: string;
|
|
66
|
+
/** Short badge, e.g. AC / BUG / GATE. */
|
|
67
|
+
tag?: string;
|
|
68
|
+
/** Any {@link HighlightTone} or alias (`error`/`blue`/…). Normalized on paint. */
|
|
69
|
+
tone?: HighlightTone | string;
|
|
70
|
+
size?: "sm" | "md" | "lg" | string;
|
|
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;
|
|
67
83
|
};
|
|
68
84
|
/**
|
|
69
85
|
* Agent-sent highlight fixtures for a live Pilot / auto session.
|
|
70
86
|
* Painted by {@link showPilotFixtures}; driven via IPC `op: "highlight"`.
|
|
87
|
+
* Mirrors demo stub surface: rings, todos, zoom, focus, device.
|
|
71
88
|
*/
|
|
72
89
|
export type PilotHighlightFixtures = {
|
|
73
90
|
/** Replace current fixture rings with these (empty + no todos = clear). */
|
|
@@ -78,18 +95,36 @@ export type PilotHighlightFixtures = {
|
|
|
78
95
|
todoIndex?: number;
|
|
79
96
|
/** Optional title above the todo list. */
|
|
80
97
|
todoTitle?: string;
|
|
98
|
+
/** Todo dock side. Default `right`. */
|
|
99
|
+
todoPos?: "left" | "right";
|
|
81
100
|
/**
|
|
82
101
|
* How long fixtures stay visible (ms). `0` = until the next highlight /
|
|
83
|
-
* clear. Default `
|
|
102
|
+
* clear. Default `30000` (30s) unless specified.
|
|
84
103
|
*/
|
|
85
104
|
holdMs?: number;
|
|
86
|
-
/**
|
|
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. */
|
|
87
122
|
clear?: boolean;
|
|
88
123
|
};
|
|
89
124
|
/**
|
|
90
125
|
* Paint (or clear) agent-authored highlight fixtures on the live page.
|
|
91
|
-
* Multi-ring + optional todo strip
|
|
92
|
-
*
|
|
126
|
+
* Multi-ring + optional todo strip + zoom/focus/device - the Pilot equivalent
|
|
127
|
+
* of Block `stubBefore` narration in `waygraph demo`.
|
|
93
128
|
* Does not import `cli.ts` (see file header).
|
|
94
129
|
*/
|
|
95
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 } from "./highlights.js";
|
|
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,25 +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
|
-
const rings = fixtures.clear ? [] : (fixtures.rings ?? [])
|
|
293
|
+
const rings = (fixtures.clear ? [] : (fixtures.rings ?? [])).map((r) => {
|
|
294
|
+
const tone = normalizeHighlightTone(r.tone);
|
|
295
|
+
const size = normalizeHighlightSize(r.size);
|
|
296
|
+
const weight = normalizeHighlightWeight(r.weight);
|
|
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);
|
|
303
|
+
return {
|
|
304
|
+
selector: r.selector,
|
|
305
|
+
label,
|
|
306
|
+
tone,
|
|
307
|
+
size,
|
|
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,
|
|
315
|
+
};
|
|
316
|
+
});
|
|
269
317
|
const todos = fixtures.clear ? [] : (fixtures.todos ?? []);
|
|
270
318
|
const todoIndex = fixtures.todoIndex ?? 0;
|
|
271
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";
|
|
272
370
|
return page
|
|
273
|
-
.evaluate(({ rings, todos, todoIndex, todoTitle, holdMs }) => {
|
|
371
|
+
.evaluate(({ rings, todos, todoIndex, todoTitle, todoPos, holdMs, zoom, zoomSelector, zoomOut, clearAll, deviceLabel, }) => {
|
|
274
372
|
const w = window;
|
|
275
373
|
if (w.__wgPilotFxHideTimer)
|
|
276
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;
|
|
277
434
|
const clearFx = () => {
|
|
278
435
|
document.querySelectorAll(".wg-pilot-fx-ring, .wg-pilot-fx-label").forEach((el) => el.remove());
|
|
279
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
|
+
}
|
|
280
444
|
};
|
|
281
445
|
w.__wgPilotFxClear = clearFx;
|
|
282
446
|
clearFx();
|
|
447
|
+
if (clearAll) {
|
|
448
|
+
return { painted: 0, missing: [] };
|
|
449
|
+
}
|
|
283
450
|
const missing = [];
|
|
284
451
|
let painted = 0;
|
|
452
|
+
let focusBox = null;
|
|
285
453
|
for (const ring of rings) {
|
|
286
454
|
const el = document.querySelector(ring.selector);
|
|
287
455
|
if (!el) {
|
|
@@ -293,14 +461,11 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
293
461
|
missing.push(ring.selector);
|
|
294
462
|
continue;
|
|
295
463
|
}
|
|
296
|
-
const
|
|
297
|
-
const size = ring.size === "sm" || ring.size === "lg" ? ring.size : "md";
|
|
298
|
-
const weight = ring.weight === "bold" ? "bold" : "normal";
|
|
299
|
-
const pad = size === "sm" ? 3 : size === "lg" ? 10 : 6;
|
|
464
|
+
const pad = ring.size === "sm" ? 3 : ring.size === "lg" ? 10 : 6;
|
|
300
465
|
const ringEl = document.createElement("div");
|
|
301
466
|
ringEl.className = "wg-pilot-fx-ring";
|
|
302
|
-
ringEl.dataset.tone = tone;
|
|
303
|
-
ringEl.dataset.size = size;
|
|
467
|
+
ringEl.dataset.tone = ring.tone;
|
|
468
|
+
ringEl.dataset.size = ring.size;
|
|
304
469
|
ringEl.style.left = `${rect.left - pad}px`;
|
|
305
470
|
ringEl.style.top = `${rect.top - pad}px`;
|
|
306
471
|
ringEl.style.width = `${Math.max(4, rect.width + pad * 2)}px`;
|
|
@@ -308,11 +473,14 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
308
473
|
ringEl.style.opacity = "1";
|
|
309
474
|
const labelEl = document.createElement("div");
|
|
310
475
|
labelEl.className = "wg-pilot-fx-label";
|
|
311
|
-
labelEl.dataset.tone = tone;
|
|
312
|
-
labelEl.dataset.size = size;
|
|
313
|
-
labelEl.dataset.weight = weight;
|
|
476
|
+
labelEl.dataset.tone = ring.tone;
|
|
477
|
+
labelEl.dataset.size = ring.size;
|
|
478
|
+
labelEl.dataset.weight = ring.weight;
|
|
314
479
|
labelEl.textContent = ring.label;
|
|
315
480
|
labelEl.style.opacity = "1";
|
|
481
|
+
if (ring.color) {
|
|
482
|
+
labelEl.style.color = ring.color;
|
|
483
|
+
}
|
|
316
484
|
document.documentElement.appendChild(ringEl);
|
|
317
485
|
document.documentElement.appendChild(labelEl);
|
|
318
486
|
const lw = labelEl.offsetWidth;
|
|
@@ -331,10 +499,14 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
331
499
|
labelEl.style.left = `${labelLeft}px`;
|
|
332
500
|
labelEl.style.top = `${labelTop}px`;
|
|
333
501
|
painted += 1;
|
|
502
|
+
if (ring.focus) {
|
|
503
|
+
focusBox = { x: rect.left, y: rect.top, width: rect.width, height: rect.height };
|
|
504
|
+
}
|
|
334
505
|
}
|
|
335
506
|
if (todos.length > 0) {
|
|
336
507
|
const dock = document.createElement("div");
|
|
337
508
|
dock.id = "wg-pilot-fx-todos";
|
|
509
|
+
dock.dataset.pos = todoPos;
|
|
338
510
|
const title = document.createElement("div");
|
|
339
511
|
title.className = "wg-pilot-fx-todo-title";
|
|
340
512
|
title.textContent = todoTitle;
|
|
@@ -352,11 +524,50 @@ export async function showPilotFixtures(page, fixtures) {
|
|
|
352
524
|
dock.appendChild(ol);
|
|
353
525
|
document.documentElement.appendChild(dock);
|
|
354
526
|
}
|
|
355
|
-
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)) {
|
|
356
555
|
w.__wgPilotFxHideTimer = setTimeout(() => clearFx(), holdMs);
|
|
357
556
|
}
|
|
358
557
|
return { painted, missing };
|
|
359
|
-
}, {
|
|
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
|
+
})
|
|
360
571
|
.catch(() => ({ painted: 0, missing: rings.map((r) => r.selector) }));
|
|
361
572
|
}
|
|
362
573
|
/**
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
(node:223602) 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:223602) 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)
|
|
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,25 @@ 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
|
|
|
37
|
-
|
|
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
|
+
|
|
47
|
+
- `tone`: all demo tones - `planned` | `auto` | `info` | `warning` | `danger` | `success` | `orange` (aliases like `error`/`blue`/`green` work too)
|
|
48
|
+
- Bottom-left toast shows `Highlighting: …` (same strip as `Running (Dom): …`)
|
|
39
49
|
- Missing selectors are listed in the JSON response (`missing`) - not a hard failure
|
|
40
50
|
- Does not replace `auto send` - paint, then run the real Block
|
|
41
51
|
|