waygraph 0.12.42 → 0.12.44

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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  A typed graph of reusable Blocks for driving a browser through E2E flows, in place of a
4
4
  flat pile of ad hoc helper functions.
5
5
 
6
- **Current:** `0.10.9` — demo carousel stepper (default), `--fast` / `--full`, Hide = compact `N / M`.
6
+ **Current:** `0.12.44` — floating todo dock (visible under `--mini`, `ctx.todoPos` / click / `--todo-left|right`), live `ctx.title` banner updates, instant highlight tone snaps.
7
7
 
8
8
  This repo is the `waygraph` npm package itself. The full live **Sauce Demo** example
9
9
  (Page inventory hub, Effect Add/Remove, MemNav Open details, `waygraph auto`) ships
@@ -429,6 +429,25 @@ npm run test # playwright test
429
429
  npm run build # tsc -p tsconfig.build.json, emits dist/
430
430
  ```
431
431
 
432
+ ### Blind-agent overlay gate (anti-blank)
433
+
434
+ Every live modal (`#wg-panel`, `#wg-banner`, `#wg-auto-panel`) stamps
435
+ `data-wg-ui` / `data-wg-modal` / `data-wg-ready="1"`. Do **not** claim the
436
+ stepper works unless one of these passes:
437
+
438
+ ```bash
439
+ # Playwright helper (exported from waygraph)
440
+ import { assertWgOverlayReady } from "waygraph";
441
+ await assertWgOverlayReady(page); // throws on blank / opacity-0 / missing stamp
442
+
443
+ # Live demo prove (exit 0 = painted, exit 2 = blank)
444
+ WAYGRAPH_PROVE_EXIT=1 WAYGRAPH_PROVE_SHOT=/tmp/wg.png \
445
+ waygraph demo --blocks loginFlow --data '...'
446
+ # stderr: WAYGRAPH_PROVE {"ok":true,"beacons":[...],"readyAttr":"1"}
447
+ ```
448
+
449
+ Tests: `tests/cli/overlay-beacon.spec.ts`. Helpers: `src/overlay-beacon.ts`.
450
+
432
451
  ## Layout
433
452
 
434
453
  ```
@@ -177,6 +177,19 @@ async function setAutoPanelRunning(page, label) {
177
177
  if (typeof window.__wgWirePanelChrome === "function") {
178
178
  window.__wgWirePanelChrome(panel, "wg-auto-panel-hidden", "waygraph auto");
179
179
  }
180
+ if (typeof window.__wgStampModal === "function") {
181
+ window.__wgStampModal(panel, "auto-panel", {
182
+ phase: "running",
183
+ block: label,
184
+ ready: true,
185
+ });
186
+ }
187
+ else {
188
+ panel.setAttribute("data-wg-ui", "1");
189
+ panel.setAttribute("data-wg-modal", "auto-panel");
190
+ panel.setAttribute("data-wg-phase", "running");
191
+ panel.setAttribute("data-wg-ready", "1");
192
+ }
180
193
  }, label)
181
194
  .catch(() => { });
182
195
  }
@@ -399,6 +412,7 @@ async function headfulPick(page, menu, library, mem, waitPick) {
399
412
  }
400
413
  const apply = (hidden) => {
401
414
  el.classList.toggle("wg-collapsed", hidden);
415
+ el.setAttribute("data-wg-collapsed", hidden ? "1" : "0");
402
416
  const t = el.querySelector("[data-wg-toggle]");
403
417
  if (t) t.textContent = hidden ? "Show" : "Hide";
404
418
  try { localStorage.setItem(storageKey, hidden ? "1" : "0"); } catch {}
@@ -416,6 +430,41 @@ async function headfulPick(page, menu, library, mem, waitPick) {
416
430
  }
417
431
  };
418
432
  window.__wgWirePanelChrome(root, "wg-auto-panel-hidden", "waygraph auto");
433
+ if (typeof window.__wgStampModal === "function") {
434
+ window.__wgStampModal(root, "auto-panel", { phase: "pick", ready: true });
435
+ } else {
436
+ root.setAttribute("data-wg-ui", "1");
437
+ root.setAttribute("data-wg-modal", "auto-panel");
438
+ root.setAttribute("data-wg-phase", "pick");
439
+ root.setAttribute(
440
+ "data-wg-collapsed",
441
+ root.classList.contains("wg-collapsed") ? "1" : "0",
442
+ );
443
+ root.setAttribute("data-wg-ready", "1");
444
+ window.__wgOverlayBeacon =
445
+ window.__wgOverlayBeacon ||
446
+ (() =>
447
+ Array.from(document.querySelectorAll('[data-wg-ui="1"]')).map((el) => {
448
+ const r = el.getBoundingClientRect();
449
+ const st = getComputedStyle(el);
450
+ return {
451
+ id: el.id || null,
452
+ modal: el.getAttribute("data-wg-modal"),
453
+ ready: el.getAttribute("data-wg-ready") === "1",
454
+ phase: el.getAttribute("data-wg-phase"),
455
+ step: el.getAttribute("data-wg-step"),
456
+ block: el.getAttribute("data-wg-block"),
457
+ collapsed:
458
+ el.getAttribute("data-wg-collapsed") === "1" ||
459
+ el.classList.contains("wg-collapsed"),
460
+ opacity: st.opacity,
461
+ textLen: (el.innerText || "").trim().length,
462
+ w: Math.round(r.width),
463
+ h: Math.round(r.height),
464
+ visible: r.width > 0 && r.height > 0 && Number(st.opacity) > 0.05,
465
+ };
466
+ }));
467
+ }
419
468
  root.querySelectorAll("button[data-idx]").forEach((btn) => {
420
469
  btn.addEventListener("click", () => {
421
470
  const idx = Number(btn.getAttribute("data-idx"));