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.
@@ -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";
@@ -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 `12000`. Vision rings (`showPilotVision`) stay separate.
102
+ * clear. Default `30000` (30s) unless specified.
85
103
  */
86
104
  holdMs?: number;
87
- /** Drop every agent fixture ring/todo immediately. */
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 - what Block `stubBefore` does in
93
- * `waygraph demo`, available to the Pilot agent without going through demo.
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<{
@@ -1,4 +1,4 @@
1
- import { WAYGRAPH_RING_CSS, normalizeHighlightTone, normalizeHighlightSize, normalizeHighlightWeight, toneIconPrefix } 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;left:14px;max-width:280px;
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 - what Block `stubBefore` does in
258
- * `waygraph demo`, available to the Pilot agent without going through demo.
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
- ? 12_000
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 icon = toneIconPrefix(tone);
273
- const label = icon && !r.label.startsWith(icon) ? `${icon} ${r.label}` : r.label;
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 tone = ring.tone;
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 (holdMs > 0 && (painted > 0 || todos.length > 0)) {
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
- }, { rings, todos, todoIndex, todoTitle, holdMs })
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
  /**
@@ -0,0 +1,8 @@
1
+ {
2
+ "sessionId": "03710cfc",
3
+ "socketPath": "/tmp/waygraph-auto/03710cfc.sock",
4
+ "pid": 255515,
5
+ "projectDir": "/home/dan/Desktop/Work/zsign/services/waygraph/examples/saucedemo",
6
+ "startedAt": "2026-09-21T09:37:58.750Z",
7
+ "headless": false
8
+ }
File without changes
File without changes
File without changes
@@ -0,0 +1,8 @@
1
+ {
2
+ "sessionId": "605d965b",
3
+ "socketPath": "/tmp/waygraph-auto/605d965b.sock",
4
+ "pid": 247729,
5
+ "projectDir": "/home/dan/Desktop/Work/zsign/services/waygraph/examples/saucedemo",
6
+ "startedAt": "2026-09-21T09:34:04.318Z",
7
+ "headless": false
8
+ }
File without changes
File without changes
@@ -0,0 +1,8 @@
1
+ {
2
+ "sessionId": "6b667734",
3
+ "socketPath": "/tmp/waygraph-auto/6b667734.sock",
4
+ "pid": 245167,
5
+ "projectDir": "/home/dan/Desktop/Work/zsign/services/waygraph/examples/saucedemo",
6
+ "startedAt": "2026-09-21T09:33:13.876Z",
7
+ "headless": false
8
+ }
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waygraph",
3
- "version": "0.15.5",
3
+ "version": "0.15.7",
4
4
  "type": "module",
5
5
  "description": "A typed graph of reusable Blocks for driving a browser through E2E flows.",
6
6
  "license": "MIT",
@@ -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