waygraph 0.10.7 → 0.10.9
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 +3 -2
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +133 -39
- package/package.json +1 -1
- package/templates/quickstart/package.json +1 -1
- package/templates/scaffold/package.json +1 -1
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.
|
|
6
|
+
**Current:** `0.10.9` — demo carousel stepper (default), `--fast` / `--full`, Hide = compact `N / M`.
|
|
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
|
|
@@ -271,7 +271,8 @@ Mermaid) is `waygraph graph [project]` (`--mermaid`). Unattended JSON execution
|
|
|
271
271
|
| Same via `auto` | `waygraph auto src/flows/shop.flow.ts --data '{…}'` |
|
|
272
272
|
| Run by export | `waygraph run --blocks shopFlow` |
|
|
273
273
|
| Manual watch | `waygraph demo src/flows/shop.flow.ts` |
|
|
274
|
-
| Auto-advance | `waygraph demo --blocks shopFlow --auto-next` |
|
|
274
|
+
| Auto-advance | `waygraph demo --blocks shopFlow --auto-next` (nav auto-hides strip) |
|
|
275
|
+
| Fast / full strip | `waygraph demo … --fast` · `--full` (classic chips; default = carousel) |
|
|
275
276
|
| QA watch + record | `waygraph demo --blocks shopFlow --auto-play-video` |
|
|
276
277
|
| Ad-hoc Blocks | `waygraph run --blocks "login then nav-cart" --data '{…}'` |
|
|
277
278
|
| Headed execute | `waygraph run --blocks shopFlow --non-headless --video` |
|
package/dist/cli.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Primary verbs (less is more):
|
|
6
6
|
* auto Explore picker; `.flow.ts` / `--blocks From To` = run that path
|
|
7
|
-
* demo Watch (step overlay); `--blocks` `--data` `--auto-next` `--
|
|
7
|
+
* demo Watch (step overlay); `--blocks` `--data` `--auto-next` `--fast` `--full`
|
|
8
8
|
* run Execute; `--blocks` `--data` `--non-headless` `--video`
|
|
9
9
|
*
|
|
10
10
|
* Also: list / nav / validate / check / graph / init / try
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Primary verbs (less is more):
|
|
6
6
|
* auto Explore picker; `.flow.ts` / `--blocks From To` = run that path
|
|
7
|
-
* demo Watch (step overlay); `--blocks` `--data` `--auto-next` `--
|
|
7
|
+
* demo Watch (step overlay); `--blocks` `--data` `--auto-next` `--fast` `--full`
|
|
8
8
|
* run Execute; `--blocks` `--data` `--non-headless` `--video`
|
|
9
9
|
*
|
|
10
10
|
* Also: list / nav / validate / check / graph / init / try
|
|
@@ -469,12 +469,16 @@ const RING_CSS =
|
|
|
469
469
|
"@keyframes wg-ep-enter{0%{box-shadow:0 0 0 0 rgba(124,58,237,.55);}" +
|
|
470
470
|
"100%{box-shadow:0 0 0 10px rgba(124,58,237,0);}}" +
|
|
471
471
|
"#wg-episodes .wg-ep-entered{border-radius:6px;animation:wg-ep-enter 1.1s ease-out;}" +
|
|
472
|
-
//
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
"#wg-modules{
|
|
477
|
-
"
|
|
472
|
+
// Block strip: carousel (default) or classic wrap (--full).
|
|
473
|
+
"#wg-modules.wg-modules-carousel{display:flex;flex-wrap:nowrap;gap:8px;margin:0 0 10px;" +
|
|
474
|
+
"overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;" +
|
|
475
|
+
"padding:4px 2px 8px;scrollbar-width:thin;}" +
|
|
476
|
+
"#wg-modules.wg-modules-carousel .wg-mod{flex:0 0 auto;scroll-snap-align:center;" +
|
|
477
|
+
"padding:6px 12px;border-radius:999px;font:600 12px system-ui,sans-serif;}" +
|
|
478
|
+
"#wg-modules.wg-modules-carousel .wg-mod-current{transform:scale(1.06);" +
|
|
479
|
+
"box-shadow:0 0 0 2px rgba(124,58,237,.45);}" +
|
|
480
|
+
"#wg-modules.wg-modules-full{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 10px;}" +
|
|
481
|
+
"#wg-modules.wg-modules-full .wg-mod{padding:3px 9px;border-radius:6px;font:600 11px system-ui,sans-serif;}" +
|
|
478
482
|
"#wg-modules .wg-mod-done{background:#2a1650;color:#9a7ad1;}" +
|
|
479
483
|
"#wg-modules .wg-mod-current{background:#7C3AED;color:#fff;}" +
|
|
480
484
|
"#wg-modules .wg-mod-upcoming{background:transparent;color:#5a4a80;border:1px solid #3a2a60;}" +
|
|
@@ -525,22 +529,23 @@ const RING_CSS =
|
|
|
525
529
|
"#wg-panel .wg-expected-heading{color:#ffcf7a;}" +
|
|
526
530
|
"#wg-panel .wg-expected-reason{font:600 12.5px/1.5 system-ui,sans-serif;background:#2a2410;" +
|
|
527
531
|
"color:#ffe6ae;border-radius:8px;padding:10px;margin:0 0 8px;}" +
|
|
528
|
-
// Hide / Show chrome
|
|
532
|
+
// Hide / Show chrome: collapsed = compact "N / M · block" pill (not empty chrome).
|
|
529
533
|
"#wg-panel .wg-chrome{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:0 0 8px;}" +
|
|
530
534
|
"#wg-panel .wg-chrome-title{font:700 11px/1.2 system-ui,sans-serif;color:#c9a6ff;" +
|
|
531
535
|
"letter-spacing:.04em;text-transform:uppercase;}" +
|
|
532
536
|
"#wg-panel button.wg-hide-btn{margin:0;padding:4px 10px;font:600 11px system-ui,sans-serif;" +
|
|
533
537
|
"background:#3a2a60;color:#e8dcff;border:1px solid #5b3aa8;border-radius:6px;cursor:pointer;}" +
|
|
534
538
|
"#wg-panel button.wg-hide-btn:hover{background:#4b2a80;}" +
|
|
535
|
-
"#wg-panel.wg-collapsed{width:auto;max-width:
|
|
539
|
+
"#wg-panel.wg-collapsed{width:auto;max-width:92vw;padding:8px 12px;max-height:none;overflow:hidden;}" +
|
|
536
540
|
"#wg-panel.wg-collapsed .wg-body{display:none;}" +
|
|
537
541
|
"#wg-panel.wg-collapsed .wg-chrome{margin:0;}" +
|
|
542
|
+
"#wg-panel.wg-collapsed .wg-chrome-title{font:700 13px/1.25 system-ui,sans-serif;color:#fff;" +
|
|
543
|
+
"letter-spacing:0;text-transform:none;}" +
|
|
538
544
|
"@media (max-width:640px){" +
|
|
539
545
|
"#wg-panel{left:8px;right:8px;bottom:8px;transform:none;max-width:none;width:auto;" +
|
|
540
546
|
"max-height:min(55vh,calc(100vh - 16px));padding:12px 14px;border-radius:12px;}" +
|
|
541
547
|
"#wg-panel.wg-collapsed{left:50%;right:auto;transform:translateX(-50%);width:auto;}" +
|
|
542
548
|
"#wg-episodes{overflow-x:auto;-webkit-overflow-scrolling:touch;flex-wrap:nowrap;}" +
|
|
543
|
-
"#wg-modules{gap:4px;}" +
|
|
544
549
|
"#wg-panel .wg-narration{font-size:13px;}" +
|
|
545
550
|
"#wg-panel button{width:100%;}" +
|
|
546
551
|
"#wg-panel .wg-error-actions{flex-direction:column;}" +
|
|
@@ -736,8 +741,11 @@ async function installOverlay(page, title) {
|
|
|
736
741
|
}
|
|
737
742
|
if (iconLink.href !== favicon) iconLink.href = favicon;
|
|
738
743
|
// Hide/Show for #wg-panel - call after every panel.innerHTML refresh.
|
|
739
|
-
|
|
744
|
+
// Collapsed title shows "N / M · block" (compact progress). forceCollapsed
|
|
745
|
+
// is for auto-next navs / video - does not overwrite the user's Hide preference.
|
|
746
|
+
window.__wgWirePanelChrome = (panel, storageKey, chromeTitle, opts) => {
|
|
740
747
|
if (!panel) return;
|
|
748
|
+
opts = opts || {};
|
|
741
749
|
if (!panel.querySelector(":scope > .wg-chrome")) {
|
|
742
750
|
const body = document.createElement("div");
|
|
743
751
|
body.className = "wg-body";
|
|
@@ -757,31 +765,56 @@ async function installOverlay(page, title) {
|
|
|
757
765
|
panel.appendChild(chrome);
|
|
758
766
|
panel.appendChild(body);
|
|
759
767
|
}
|
|
760
|
-
const
|
|
768
|
+
const stepLabel = opts.stepLabel || panel.dataset.wgStepLabel || "";
|
|
769
|
+
if (stepLabel) panel.dataset.wgStepLabel = stepLabel;
|
|
770
|
+
const apply = (hidden, persist) => {
|
|
761
771
|
panel.classList.toggle("wg-collapsed", hidden);
|
|
762
772
|
const t = panel.querySelector("[data-wg-toggle]");
|
|
773
|
+
const titleEl = panel.querySelector(".wg-chrome-title");
|
|
774
|
+
const label = panel.dataset.wgStepLabel || stepLabel;
|
|
775
|
+
if (titleEl) {
|
|
776
|
+
titleEl.textContent = hidden
|
|
777
|
+
? (label || chromeTitle || "waygraph demo")
|
|
778
|
+
: (chromeTitle || "waygraph demo");
|
|
779
|
+
}
|
|
763
780
|
if (t) t.textContent = hidden ? "Show" : "Hide";
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
781
|
+
if (persist !== false) {
|
|
782
|
+
try {
|
|
783
|
+
localStorage.setItem(storageKey, hidden ? "1" : "0");
|
|
784
|
+
} catch {
|
|
785
|
+
/* private mode */
|
|
786
|
+
}
|
|
768
787
|
}
|
|
769
788
|
};
|
|
770
789
|
let hidden = false;
|
|
771
|
-
|
|
772
|
-
hidden =
|
|
773
|
-
}
|
|
774
|
-
|
|
790
|
+
if (opts.forceCollapsed === true) {
|
|
791
|
+
hidden = true;
|
|
792
|
+
} else if (opts.forceCollapsed === false) {
|
|
793
|
+
hidden = false;
|
|
794
|
+
} else {
|
|
795
|
+
try {
|
|
796
|
+
hidden = localStorage.getItem(storageKey) === "1";
|
|
797
|
+
} catch {
|
|
798
|
+
/* ignore */
|
|
799
|
+
}
|
|
775
800
|
}
|
|
776
|
-
apply(hidden);
|
|
801
|
+
apply(hidden, opts.forceCollapsed === true ? false : true);
|
|
777
802
|
const toggle = panel.querySelector("[data-wg-toggle]");
|
|
778
803
|
if (toggle && !toggle.dataset.wgWired) {
|
|
779
804
|
toggle.dataset.wgWired = "1";
|
|
780
805
|
toggle.addEventListener("click", (e) => {
|
|
781
806
|
e.stopPropagation();
|
|
782
|
-
apply(!panel.classList.contains("wg-collapsed"));
|
|
807
|
+
apply(!panel.classList.contains("wg-collapsed"), true);
|
|
783
808
|
});
|
|
784
809
|
}
|
|
810
|
+
const cur = panel.querySelector("#wg-modules .wg-mod-current");
|
|
811
|
+
if (cur && typeof cur.scrollIntoView === "function") {
|
|
812
|
+
try {
|
|
813
|
+
cur.scrollIntoView({ inline: "center", block: "nearest", behavior: "smooth" });
|
|
814
|
+
} catch {
|
|
815
|
+
cur.scrollIntoView(false);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
785
818
|
};
|
|
786
819
|
},
|
|
787
820
|
{ title, favicon: WAYGRAPH_FAVICON, bannerPos, envAutoplay },
|
|
@@ -850,6 +883,7 @@ async function renderBeforeStep(page, info) {
|
|
|
850
883
|
// step's position WITHIN that subset, not the whole chain's index -
|
|
851
884
|
// "in episode 2 it shows 2nd to the last... it should start from the
|
|
852
885
|
// first block" (Dan).
|
|
886
|
+
const modulesClass = info.stepperMode === "full" ? "wg-modules-full" : "wg-modules-carousel";
|
|
853
887
|
const modulesHtml = info.allNames
|
|
854
888
|
.map((name, idx) => {
|
|
855
889
|
const cls = idx < info.moduleIndex ? "wg-mod-done" : idx === info.moduleIndex ? "wg-mod-current" : "wg-mod-upcoming";
|
|
@@ -864,7 +898,7 @@ async function renderBeforeStep(page, info) {
|
|
|
864
898
|
let html =
|
|
865
899
|
"<div id=\\"wg-progress\\"><div id=\\"wg-progress-bar\\" style=\\"width:" + pct + "%\\"></div></div>" +
|
|
866
900
|
episodesHtml +
|
|
867
|
-
"<div id=\\"wg-modules\\">" + modulesHtml + "</div>" +
|
|
901
|
+
"<div id=\\"wg-modules\\" class=\\"" + modulesClass + "\\">" + modulesHtml + "</div>" +
|
|
868
902
|
"<h3>Step " + (info.index + 1) + " / " + info.total + " - " + info.blockName + "</h3>" +
|
|
869
903
|
narrationHtml;
|
|
870
904
|
if (info.keys.length === 0) {
|
|
@@ -897,7 +931,12 @@ async function renderBeforeStep(page, info) {
|
|
|
897
931
|
document.documentElement.appendChild(panel);
|
|
898
932
|
requestAnimationFrame(() => panel.classList.add("wg-in"));
|
|
899
933
|
}
|
|
900
|
-
if (window.__wgWirePanelChrome)
|
|
934
|
+
if (window.__wgWirePanelChrome) {
|
|
935
|
+
window.__wgWirePanelChrome(panel, "wg-panel-hidden", "waygraph demo", {
|
|
936
|
+
stepLabel: (info.index + 1) + " / " + info.total + (info.blockName ? " · " + info.blockName : ""),
|
|
937
|
+
forceCollapsed: info.forceCollapsed === true ? true : info.forceCollapsed === false ? false : undefined,
|
|
938
|
+
});
|
|
939
|
+
}
|
|
901
940
|
// Live, human-readable preview of what a MemKey's raw JSON will
|
|
902
941
|
// actually write - object fields become "Field: value" lines
|
|
903
942
|
// (camelCase split the same way state tags already are); a
|
|
@@ -1040,6 +1079,7 @@ async function renderAfterStep(page, info) {
|
|
|
1040
1079
|
: "Step " + (info.index + 1) + " / " + info.total + " - " + info.blockName + " done";
|
|
1041
1080
|
const buttonLabel = info.isLast ? "Finish" : "Next \\u25B6";
|
|
1042
1081
|
const escA = (s) => String(s).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
1082
|
+
const modulesClass = info.stepperMode === "full" ? "wg-modules-full" : "wg-modules-carousel";
|
|
1043
1083
|
const modulesHtml = info.allNames
|
|
1044
1084
|
.map((name, idx) => {
|
|
1045
1085
|
const cls = idx <= info.moduleIndex ? "wg-mod-done" : "wg-mod-upcoming";
|
|
@@ -1094,7 +1134,7 @@ async function renderAfterStep(page, info) {
|
|
|
1094
1134
|
panel.innerHTML =
|
|
1095
1135
|
"<div id=\\"wg-progress\\"><div id=\\"wg-progress-bar\\" style=\\"width:" + pct + "%\\"></div></div>" +
|
|
1096
1136
|
episodesHtml +
|
|
1097
|
-
"<div id=\\"wg-modules\\">" + modulesHtml + "</div>" +
|
|
1137
|
+
"<div id=\\"wg-modules\\" class=\\"" + modulesClass + "\\">" + modulesHtml + "</div>" +
|
|
1098
1138
|
"<h3>" + heading + "</h3>" +
|
|
1099
1139
|
resultHtml +
|
|
1100
1140
|
gateHtml;
|
|
@@ -1102,7 +1142,12 @@ async function renderAfterStep(page, info) {
|
|
|
1102
1142
|
document.documentElement.appendChild(panel);
|
|
1103
1143
|
requestAnimationFrame(() => panel.classList.add("wg-in"));
|
|
1104
1144
|
}
|
|
1105
|
-
if (window.__wgWirePanelChrome)
|
|
1145
|
+
if (window.__wgWirePanelChrome) {
|
|
1146
|
+
window.__wgWirePanelChrome(panel, "wg-panel-hidden", "waygraph demo", {
|
|
1147
|
+
stepLabel: (info.index + 1) + " / " + info.total + (info.blockName ? " · " + info.blockName : ""),
|
|
1148
|
+
forceCollapsed: info.forceCollapsed === true ? true : info.forceCollapsed === false ? false : undefined,
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1106
1151
|
panel.querySelectorAll(".wg-toggle-btn").forEach((btn) => {
|
|
1107
1152
|
btn.addEventListener("click", () => {
|
|
1108
1153
|
const wantPretty = btn.getAttribute("data-mode") === "pretty";
|
|
@@ -1169,6 +1214,7 @@ async function renderStepError(page, info) {
|
|
|
1169
1214
|
.join("") +
|
|
1170
1215
|
"</div>"
|
|
1171
1216
|
: "";
|
|
1217
|
+
const modulesClass = info.stepperMode === "full" ? "wg-modules-full" : "wg-modules-carousel";
|
|
1172
1218
|
const modulesHtml = info.allNames
|
|
1173
1219
|
.map((name, idx) => {
|
|
1174
1220
|
const cls = idx === info.moduleIndex ? "wg-mod-current" : idx < info.moduleIndex ? "wg-mod-done" : "wg-mod-upcoming";
|
|
@@ -1186,7 +1232,7 @@ async function renderStepError(page, info) {
|
|
|
1186
1232
|
: "";
|
|
1187
1233
|
panel.innerHTML =
|
|
1188
1234
|
episodesHtml +
|
|
1189
|
-
"<div id=\\"wg-modules\\">" + modulesHtml + "</div>" +
|
|
1235
|
+
"<div id=\\"wg-modules\\" class=\\"" + modulesClass + "\\">" + modulesHtml + "</div>" +
|
|
1190
1236
|
"<h3 class=\\"" + (isExpected ? "wg-expected-heading" : "wg-error-heading") + "\\">" + headingText + "</h3>" +
|
|
1191
1237
|
reasonHtml +
|
|
1192
1238
|
"<div class=\\"wg-error-msg\\">" + esc(info.message) + "</div>" +
|
|
@@ -1198,7 +1244,12 @@ async function renderStepError(page, info) {
|
|
|
1198
1244
|
document.documentElement.appendChild(panel);
|
|
1199
1245
|
requestAnimationFrame(() => panel.classList.add("wg-in"));
|
|
1200
1246
|
}
|
|
1201
|
-
if (window.__wgWirePanelChrome)
|
|
1247
|
+
if (window.__wgWirePanelChrome) {
|
|
1248
|
+
window.__wgWirePanelChrome(panel, "wg-panel-hidden", "waygraph demo", {
|
|
1249
|
+
stepLabel: (info.index + 1) + " / " + info.total + (info.blockName ? " · " + info.blockName : ""),
|
|
1250
|
+
forceCollapsed: info.forceCollapsed === true ? true : info.forceCollapsed === false ? false : undefined,
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1202
1253
|
const runBtn = document.getElementById("wg-run");
|
|
1203
1254
|
if (runBtn) runBtn.addEventListener("click", () => window.__wgNext({}));
|
|
1204
1255
|
const retryBtn = document.getElementById("wg-error-retry");
|
|
@@ -1289,7 +1340,7 @@ function extractVerifyHighlights(block, resultTag) {
|
|
|
1289
1340
|
* When autoCollapsePanel is set (QA video / autoplay), tuck the stepper
|
|
1290
1341
|
* away so ring captions + the app fill the frame - Dan: stepper + auto panels.
|
|
1291
1342
|
*/
|
|
1292
|
-
async function markStepRunning(page, opts
|
|
1343
|
+
async function markStepRunning(page, opts) {
|
|
1293
1344
|
await page
|
|
1294
1345
|
.evaluate(({ autoCollapsePanel }) => {
|
|
1295
1346
|
const runBtn = document.getElementById("wg-run");
|
|
@@ -1308,9 +1359,12 @@ async function markStepRunning(page, opts?: { autoCollapsePanel?: boolean }) {
|
|
|
1308
1359
|
panel.classList.add("wg-collapsed");
|
|
1309
1360
|
const toggle = panel.querySelector("[data-wg-toggle]");
|
|
1310
1361
|
if (toggle) toggle.textContent = "Show";
|
|
1362
|
+
const titleEl = panel.querySelector(".wg-chrome-title");
|
|
1363
|
+
const label = panel.dataset.wgStepLabel;
|
|
1364
|
+
if (titleEl && label) titleEl.textContent = label;
|
|
1311
1365
|
}
|
|
1312
1366
|
}
|
|
1313
|
-
}, { autoCollapsePanel: !!opts
|
|
1367
|
+
}, { autoCollapsePanel: !!(opts && opts.autoCollapsePanel) })
|
|
1314
1368
|
.catch(() => {});
|
|
1315
1369
|
}
|
|
1316
1370
|
|
|
@@ -1644,7 +1698,11 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
1644
1698
|
// own added dwell while the rest of the chain keeps the full theatrical
|
|
1645
1699
|
// pace. Playwright's own slowMo is process-wide and untouched by this -
|
|
1646
1700
|
// only OUR added pauses (ring pop, cursor travel, typing delay) shrink.
|
|
1647
|
-
|
|
1701
|
+
// --fast / WAYGRAPH_DEMO_FAST: every step uses fast interaction pacing + shorter gates.
|
|
1702
|
+
// WAYGRAPH_FAST_BLOCKS still names per-block overrides when --fast is off.
|
|
1703
|
+
const demoFast = process.env.WAYGRAPH_DEMO_FAST === "1";
|
|
1704
|
+
const stepperMode = process.env.WAYGRAPH_STEPPER === "full" ? "full" : "carousel";
|
|
1705
|
+
const pacing = { fast: demoFast };
|
|
1648
1706
|
instrumentInteractionHighlighting(page, mem, slowMo, pacing);
|
|
1649
1707
|
// Force the panel checkbox from this process's flags/env at run start.
|
|
1650
1708
|
// installOverlay only seeds localStorage when the key is null (so mid-run
|
|
@@ -1689,7 +1747,11 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
1689
1747
|
// which way the checkbox is set. That's the hybrid Dan asked for: some
|
|
1690
1748
|
// steps auto-advance, some get a manual click, toggled as the demo goes,
|
|
1691
1749
|
// not fixed for the whole run from a single env var.
|
|
1692
|
-
const autoplayMs = process.env.WAYGRAPH_AUTOPLAY_MS
|
|
1750
|
+
const autoplayMs = process.env.WAYGRAPH_AUTOPLAY_MS
|
|
1751
|
+
? Number(process.env.WAYGRAPH_AUTOPLAY_MS)
|
|
1752
|
+
: demoFast
|
|
1753
|
+
? 450
|
|
1754
|
+
: 1800;
|
|
1693
1755
|
const currentAutoplay = () =>
|
|
1694
1756
|
page
|
|
1695
1757
|
.evaluate(() => {
|
|
@@ -1789,7 +1851,12 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
1789
1851
|
if ((clearSession || r.resetSession) && i > 0) {
|
|
1790
1852
|
await resetPageState(context, page, baseURL);
|
|
1791
1853
|
}
|
|
1792
|
-
pacing.fast = fastBlockNames.has(r.block.name);
|
|
1854
|
+
pacing.fast = demoFast || fastBlockNames.has(r.block.name);
|
|
1855
|
+
const isNavBlock = r.block.__waygraphKind === "nav";
|
|
1856
|
+
const autoNow = await currentAutoplay();
|
|
1857
|
+
// Auto-next: tuck stepper on NavBlocks so the page transition fills the frame.
|
|
1858
|
+
// Video recording still collapses every step.
|
|
1859
|
+
const forceCollapsed = !!process.env.WAYGRAPH_VIDEO || (autoNow && isNavBlock);
|
|
1793
1860
|
const requires = r.block.requires ?? [];
|
|
1794
1861
|
const keys = requires.map((k) => {
|
|
1795
1862
|
let value = "<not yet set>";
|
|
@@ -1814,6 +1881,8 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
1814
1881
|
title,
|
|
1815
1882
|
episodeNumber: r.episodeNumber,
|
|
1816
1883
|
episodeTitle: r.episodeTitle,
|
|
1884
|
+
stepperMode,
|
|
1885
|
+
forceCollapsed,
|
|
1817
1886
|
});
|
|
1818
1887
|
const edits = await gate();
|
|
1819
1888
|
for (const k of requires) {
|
|
@@ -1826,7 +1895,7 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
1826
1895
|
}
|
|
1827
1896
|
}
|
|
1828
1897
|
const recordingVideo = !!process.env.WAYGRAPH_VIDEO;
|
|
1829
|
-
const autoCollapsePanel = recordingVideo || (await currentAutoplay());
|
|
1898
|
+
const autoCollapsePanel = recordingVideo || (await currentAutoplay() && isNavBlock) || forceCollapsed;
|
|
1830
1899
|
await markStepRunning(page, { autoCollapsePanel });
|
|
1831
1900
|
// NavBlock click-nav: label the upcoming Locator.click demo cursor as
|
|
1832
1901
|
// "nav: <block>" so pia/demo watchers see cursor+pulse on click nav
|
|
@@ -1876,6 +1945,8 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
1876
1945
|
episodeNumber: r.episodeNumber,
|
|
1877
1946
|
episodeTitle: r.episodeTitle,
|
|
1878
1947
|
expectedFailureReason: r.expectedFailureReason,
|
|
1948
|
+
stepperMode,
|
|
1949
|
+
forceCollapsed: false,
|
|
1879
1950
|
});
|
|
1880
1951
|
const errEdits = await gate();
|
|
1881
1952
|
if (errEdits && errEdits.__wgRetry) {
|
|
@@ -1920,6 +1991,9 @@ async function runStepMode(engine, start, end, context, page, mem, resolved, slo
|
|
|
1920
1991
|
title,
|
|
1921
1992
|
episodeNumber: r.episodeNumber,
|
|
1922
1993
|
episodeTitle: r.episodeTitle,
|
|
1994
|
+
stepperMode,
|
|
1995
|
+
// After a nav under auto-next, stay compact until the next action block expands.
|
|
1996
|
+
forceCollapsed: !!process.env.WAYGRAPH_VIDEO || ((await currentAutoplay()) && isNavBlock),
|
|
1923
1997
|
});
|
|
1924
1998
|
await gate();
|
|
1925
1999
|
}
|
|
@@ -2010,8 +2084,8 @@ async function runChainedFlows(chainFlow, chainFlows, context, mem, page) {
|
|
|
2010
2084
|
}
|
|
2011
2085
|
|
|
2012
2086
|
/** Parses WAYGRAPH_VIDEO_VIEWPORT / --video-viewport: "1920x1080" or "1920,1080". */
|
|
2013
|
-
function parseVideoViewport(raw
|
|
2014
|
-
if (!raw
|
|
2087
|
+
function parseVideoViewport(raw) {
|
|
2088
|
+
if (!raw || !raw.trim()) return null;
|
|
2015
2089
|
const m = raw.trim().match(/^(\d{3,5})[xX,](\d{3,5})$/);
|
|
2016
2090
|
if (!m) return null;
|
|
2017
2091
|
const width = Number(m[1]);
|
|
@@ -2840,6 +2914,12 @@ function parseRunFlags(argv) {
|
|
|
2840
2914
|
else if (a === "--auto-play-video") {
|
|
2841
2915
|
out.autoPlayVideo = true;
|
|
2842
2916
|
}
|
|
2917
|
+
else if (a === "--fast") {
|
|
2918
|
+
out.fast = true;
|
|
2919
|
+
}
|
|
2920
|
+
else if (a === "--full") {
|
|
2921
|
+
out.fullStepper = true;
|
|
2922
|
+
}
|
|
2843
2923
|
else if (a === "--non-headless") {
|
|
2844
2924
|
out.nonHeadless = true;
|
|
2845
2925
|
}
|
|
@@ -2945,6 +3025,10 @@ function applyRunFlags(flags, opts) {
|
|
|
2945
3025
|
if (flags.step === undefined)
|
|
2946
3026
|
flags.step = true;
|
|
2947
3027
|
}
|
|
3028
|
+
if ((flags.fast || flags.fullStepper) && !opts?.allowDemoUi) {
|
|
3029
|
+
console.error("waygraph: --fast / --full are demo-only flags");
|
|
3030
|
+
process.exit(1);
|
|
3031
|
+
}
|
|
2948
3032
|
if (flags.step === true) {
|
|
2949
3033
|
process.env.WAYGRAPH_STEP = "1";
|
|
2950
3034
|
process.env.WAYGRAPH_HEADED = "1";
|
|
@@ -2980,6 +3064,12 @@ function applyRunFlags(flags, opts) {
|
|
|
2980
3064
|
if (flags.data !== undefined) {
|
|
2981
3065
|
process.env.WAYGRAPH_DATA = flags.data;
|
|
2982
3066
|
}
|
|
3067
|
+
if (flags.fast) {
|
|
3068
|
+
process.env.WAYGRAPH_DEMO_FAST = "1";
|
|
3069
|
+
}
|
|
3070
|
+
if (flags.fullStepper) {
|
|
3071
|
+
process.env.WAYGRAPH_STEPPER = "full";
|
|
3072
|
+
}
|
|
2983
3073
|
}
|
|
2984
3074
|
/**
|
|
2985
3075
|
* BASE_URL when neither --base-url nor WAYGRAPH_BASE_URL is set:
|
|
@@ -3135,6 +3225,8 @@ Primary (less is more):
|
|
|
3135
3225
|
waygraph demo [--blocks <flow|file|spec>] Watch with step overlay (QA path)
|
|
3136
3226
|
--data '{...}' Mem seed JSON (or inline flow({...}))
|
|
3137
3227
|
--auto-next Auto-advance steps (alias: --autoplay)
|
|
3228
|
+
--fast Faster transitions + shorter auto-next gates
|
|
3229
|
+
--full Classic wrap-all block chips (default: carousel)
|
|
3138
3230
|
--auto-play-video QA: --auto-next + --video (+ step)
|
|
3139
3231
|
--video-viewport WxH Recording size (default demo: 1920x1080)
|
|
3140
3232
|
--title / --base-url
|
|
@@ -3155,7 +3247,8 @@ Examples:
|
|
|
3155
3247
|
waygraph list # file → export map
|
|
3156
3248
|
waygraph run src/flows/shop.flow.ts --data '{...}'
|
|
3157
3249
|
waygraph run --blocks shopFlow --non-headless --video
|
|
3158
|
-
waygraph demo --blocks src/flows/cart-bulk.flow.ts --auto-next
|
|
3250
|
+
waygraph demo --blocks src/flows/cart-bulk.flow.ts --auto-next --fast
|
|
3251
|
+
waygraph demo src/flows/shop.flow.ts --full
|
|
3159
3252
|
waygraph try auto
|
|
3160
3253
|
waygraph try auto:cli
|
|
3161
3254
|
waygraph auto src/flows/shop.flow.ts --data '{...}' # run by file (same as run)
|
|
@@ -3168,6 +3261,7 @@ Aliases (compat): \`chain <spec>\` -> run --blocks; \`chain auto A B\` -> auto -
|
|
|
3168
3261
|
|
|
3169
3262
|
Project path optional (defaults to cwd). Flags beat WAYGRAPH_* env.
|
|
3170
3263
|
\`run\`/\`demo\`/\`auto\`: Flow export, .flow.ts path, or "a then b" chain (auto also explores).
|
|
3264
|
+
Hide stepper = compact "N / M · block" pill. Auto-next auto-hides on NavBlocks.
|
|
3171
3265
|
`);
|
|
3172
3266
|
process.exit(0);
|
|
3173
3267
|
}
|
|
@@ -3282,13 +3376,13 @@ async function main() {
|
|
|
3282
3376
|
}
|
|
3283
3377
|
case "demo": {
|
|
3284
3378
|
const flags = parseRunFlags(args.slice(1));
|
|
3285
|
-
applyRunFlags(flags, { allowAutoPlayVideo: true });
|
|
3379
|
+
applyRunFlags(flags, { allowAutoPlayVideo: true, allowDemoUi: true });
|
|
3286
3380
|
const spec = resolveSpec(flags);
|
|
3287
3381
|
if (!spec) {
|
|
3288
3382
|
console.error("waygraph demo: missing flow/spec — e.g.\n" +
|
|
3289
3383
|
" waygraph demo src/flows/shop.flow.ts\n" +
|
|
3290
3384
|
" waygraph demo --blocks shopFlow\n" +
|
|
3291
|
-
" Flags: --blocks --data --auto-next --auto-play-video --title --base-url --video");
|
|
3385
|
+
" Flags: --blocks --data --auto-next --fast --full --auto-play-video --title --base-url --video");
|
|
3292
3386
|
process.exit(1);
|
|
3293
3387
|
}
|
|
3294
3388
|
const proj = flags.blocks
|
package/package.json
CHANGED