waygraph 0.15.22 → 0.15.24
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/cli/discover.d.ts +40 -0
- package/dist/cli/discover.js +148 -0
- package/dist/cli/flags.d.ts +91 -0
- package/dist/cli/flags.js +442 -0
- package/dist/cli/run-chain.d.ts +8 -0
- package/dist/cli/run-chain.js +67 -0
- package/dist/cli/usage.d.ts +4 -0
- package/dist/cli/usage.js +236 -0
- package/dist/cli/util.d.ts +4 -0
- package/dist/cli/util.js +24 -0
- package/dist/cli.js +45 -8494
- package/dist/commands/agent-dive.d.ts +1 -0
- package/dist/commands/agent-dive.js +52 -0
- package/dist/commands/check.d.ts +4 -0
- package/dist/commands/check.js +192 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +54 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +67 -0
- package/dist/commands/map.d.ts +1 -0
- package/dist/commands/map.js +29 -0
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.js +104 -0
- package/dist/commands/session.d.ts +2 -0
- package/dist/commands/session.js +600 -0
- package/dist/commands/test.d.ts +1 -0
- package/dist/commands/test.js +33 -0
- package/dist/commands/traverse.d.ts +1 -0
- package/dist/commands/traverse.js +177 -0
- package/dist/commands/try.d.ts +1 -0
- package/dist/commands/try.js +298 -0
- package/dist/runner/chain-run.js +102 -0
- package/dist/runner/cursor.js +140 -0
- package/dist/runner/demo-log.js +314 -0
- package/dist/runner/device-stage.js +400 -0
- package/dist/runner/discovery.js +105 -0
- package/dist/runner/index.js +2 -0
- package/dist/runner/interaction-patch.js +353 -0
- package/dist/runner/main.js +397 -0
- package/dist/runner/overlay-css.js +342 -0
- package/dist/runner/overlay-install.js +1301 -0
- package/dist/runner/rings.js +490 -0
- package/dist/runner/seed-mem.js +110 -0
- package/dist/runner/slides.js +272 -0
- package/dist/runner/step-mode.js +776 -0
- package/dist/runner/step-panels.js +723 -0
- package/dist/runner/teardown.js +195 -0
- package/dist/runner/todo-dock.js +142 -0
- package/examples/saucedemo/.waygraph-auto/0ac58118.log +0 -0
- package/examples/saucedemo/.waygraph-auto/309c107f.log +0 -0
- package/examples/saucedemo/.waygraph-auto/3ab7c7bd.log +44 -0
- package/examples/saucedemo/.waygraph-auto/45864828.log +0 -0
- package/examples/saucedemo/.waygraph-auto/95bd8371.log +0 -0
- package/examples/saucedemo/.waygraph-auto/bcb9e31a.log +0 -0
- package/examples/saucedemo/.waygraph-auto/cd3e528c.log +0 -0
- package/examples/saucedemo/.waygraph-auto/dce1535d.log +0 -0
- package/examples/saucedemo/.waygraph-auto/e280bf20.log +0 -0
- package/package.json +5 -2
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// Moved verbatim from the former CHAIN_RUNNER_SCRIPT template string in cli.ts (see src/ARCHITECTURE.md).
|
|
2
|
+
// Runs inside the target project's own waygraph copy - keep it dependency-light and self-contained.
|
|
3
|
+
|
|
4
|
+
export async function moveCursorTo(page, box, ms) {
|
|
5
|
+
const x = box.x + box.width / 2;
|
|
6
|
+
const y = box.y + box.height / 2;
|
|
7
|
+
const travel = Math.max(0, Number(ms) || 0);
|
|
8
|
+
await page
|
|
9
|
+
.evaluate(({ x, y, ms }) => {
|
|
10
|
+
if (window.__wgMoveCursorTo) window.__wgMoveCursorTo(x, y, ms);
|
|
11
|
+
}, { x, y, ms: travel })
|
|
12
|
+
.catch(() => {});
|
|
13
|
+
// CSS transition is async - wait the full travel so the cursor is ON the
|
|
14
|
+
// target before ring/pulse/real click (NavBlock click nav was skipping
|
|
15
|
+
// this and looked like a teleport).
|
|
16
|
+
if (travel > 0) {
|
|
17
|
+
await new Promise((res) => setTimeout(res, travel));
|
|
18
|
+
}
|
|
19
|
+
return { x, y };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
export async function clickPulseAt(page, x, y, tone) {
|
|
24
|
+
await page
|
|
25
|
+
.evaluate(({ x, y, tone }) => {
|
|
26
|
+
if (window.__wgClickPulse) window.__wgClickPulse(x, y, tone || "planned");
|
|
27
|
+
}, { x, y, tone: tone || "planned" })
|
|
28
|
+
.catch(() => {});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Touch swipe trail (mobile/tablet). dir: left|right|up|down.
|
|
34
|
+
* Returns after the trail animation completes.
|
|
35
|
+
* Self-contained when overlay helper is not installed yet (device runs before panel).
|
|
36
|
+
*/
|
|
37
|
+
export async function playSwipeTrail(page, opts) {
|
|
38
|
+
const o = opts || {};
|
|
39
|
+
const waitMs = await page
|
|
40
|
+
.evaluate((payload) => {
|
|
41
|
+
if (typeof window.__wgSwipeTrail === "function") {
|
|
42
|
+
return window.__wgSwipeTrail(payload);
|
|
43
|
+
}
|
|
44
|
+
// Fallback: inject a one-shot trail without full overlay install.
|
|
45
|
+
const dir =
|
|
46
|
+
payload.dir === "right" || payload.dir === "up" || payload.dir === "down"
|
|
47
|
+
? payload.dir
|
|
48
|
+
: "left";
|
|
49
|
+
const ms = Math.max(280, Math.min(1400, Number(payload.ms) || 720));
|
|
50
|
+
const label = payload.label || "swipe";
|
|
51
|
+
let layer = document.getElementById("wg-swipe-layer");
|
|
52
|
+
if (layer) layer.remove();
|
|
53
|
+
layer = document.createElement("div");
|
|
54
|
+
layer.id = "wg-swipe-layer";
|
|
55
|
+
layer.setAttribute("data-wg-ui", "1");
|
|
56
|
+
layer.style.cssText =
|
|
57
|
+
"position:fixed;inset:0;z-index:2147483646;pointer-events:none;overflow:hidden;";
|
|
58
|
+
const finger = document.createElement("div");
|
|
59
|
+
finger.style.cssText =
|
|
60
|
+
"position:absolute;width:28px;height:28px;margin:-14px 0 0 -14px;border-radius:50%;" +
|
|
61
|
+
"background:rgba(15,23,42,.92);border:2px solid #fff;box-shadow:0 4px 16px rgba(0,0,0,.4);";
|
|
62
|
+
const lab = document.createElement("div");
|
|
63
|
+
lab.textContent = label;
|
|
64
|
+
lab.style.cssText =
|
|
65
|
+
"position:absolute;left:50%;top:18%;transform:translateX(-50%);padding:6px 12px;" +
|
|
66
|
+
"border-radius:999px;background:rgba(15,23,42,.88);color:#e0f2fe;" +
|
|
67
|
+
"border:1px solid rgba(56,189,248,.55);font:700 12px/1.2 system-ui,sans-serif;";
|
|
68
|
+
layer.appendChild(lab);
|
|
69
|
+
layer.appendChild(finger);
|
|
70
|
+
document.documentElement.appendChild(layer);
|
|
71
|
+
const vw = window.innerWidth || 390;
|
|
72
|
+
const vh = window.innerHeight || 844;
|
|
73
|
+
const pad = Math.min(vw, vh) * 0.18;
|
|
74
|
+
let x0;
|
|
75
|
+
let y0;
|
|
76
|
+
let x1;
|
|
77
|
+
let y1;
|
|
78
|
+
if (dir === "left") {
|
|
79
|
+
x0 = vw - pad;
|
|
80
|
+
x1 = pad;
|
|
81
|
+
y0 = y1 = vh * 0.52;
|
|
82
|
+
} else if (dir === "right") {
|
|
83
|
+
x0 = pad;
|
|
84
|
+
x1 = vw - pad;
|
|
85
|
+
y0 = y1 = vh * 0.52;
|
|
86
|
+
} else if (dir === "up") {
|
|
87
|
+
x0 = x1 = vw * 0.5;
|
|
88
|
+
y0 = vh - pad;
|
|
89
|
+
y1 = pad;
|
|
90
|
+
} else {
|
|
91
|
+
x0 = x1 = vw * 0.5;
|
|
92
|
+
y0 = pad;
|
|
93
|
+
y1 = vh - pad;
|
|
94
|
+
}
|
|
95
|
+
finger.style.left = x0 + "px";
|
|
96
|
+
finger.style.top = y0 + "px";
|
|
97
|
+
const steps = 12;
|
|
98
|
+
const stepMs = Math.floor(ms / steps);
|
|
99
|
+
for (let i = 1; i <= steps; i++) {
|
|
100
|
+
const t = i / steps;
|
|
101
|
+
const e = t * t * (3 - 2 * t);
|
|
102
|
+
const x = x0 + (x1 - x0) * e;
|
|
103
|
+
const y = y0 + (y1 - y0) * e;
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
finger.style.left = x + "px";
|
|
106
|
+
finger.style.top = y + "px";
|
|
107
|
+
const dot = document.createElement("div");
|
|
108
|
+
dot.style.cssText =
|
|
109
|
+
"position:absolute;width:14px;height:14px;margin:-7px 0 0 -7px;border-radius:50%;" +
|
|
110
|
+
"background:rgba(147,197,253,.55);border:2px solid rgba(255,255,255,.85);left:" +
|
|
111
|
+
x +
|
|
112
|
+
"px;top:" +
|
|
113
|
+
y +
|
|
114
|
+
"px;opacity:" +
|
|
115
|
+
(0.85 - t * 0.55) +
|
|
116
|
+
";transition:opacity .45s ease,transform .45s ease;";
|
|
117
|
+
layer.appendChild(dot);
|
|
118
|
+
requestAnimationFrame(() => {
|
|
119
|
+
dot.style.opacity = "0";
|
|
120
|
+
dot.style.transform = "scale(1.8)";
|
|
121
|
+
});
|
|
122
|
+
if (i === steps) {
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
const el = document.getElementById("wg-swipe-layer");
|
|
125
|
+
if (el) el.remove();
|
|
126
|
+
}, 400);
|
|
127
|
+
}
|
|
128
|
+
}, i * stepMs);
|
|
129
|
+
}
|
|
130
|
+
return ms + 120;
|
|
131
|
+
}, {
|
|
132
|
+
dir: o.dir || "left",
|
|
133
|
+
label: o.label || "swipe",
|
|
134
|
+
hint: o.hint || "",
|
|
135
|
+
ms: o.ms || 720,
|
|
136
|
+
})
|
|
137
|
+
.catch(() => 0);
|
|
138
|
+
const n = Number(waitMs) || 0;
|
|
139
|
+
if (n > 0) await new Promise((r) => setTimeout(r, n));
|
|
140
|
+
}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
// Moved verbatim from the former CHAIN_RUNNER_SCRIPT template string in cli.ts (see src/ARCHITECTURE.md).
|
|
2
|
+
// Runs inside the target project's own waygraph copy - keep it dependency-light and self-contained.
|
|
3
|
+
import { demoPaceIsFast, demoPaceIsSlow, formatDemoPaceBadge, formatDemoPaceLabel, normalizeDemoPace, normalizeHighlightTone } from "../highlights.js";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
export function demoPaceKind(pace) {
|
|
7
|
+
const p = normalizeDemoPace(pace);
|
|
8
|
+
if (typeof p === "number" && p > 20) return "ms";
|
|
9
|
+
if (typeof p === "number") return demoPaceIsSlow(p) ? "num-slow" : demoPaceIsFast(p) ? "fast" : "normal";
|
|
10
|
+
if (p === "blitz" || p === "fast" || p === "slow") return p;
|
|
11
|
+
return "normal";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export function paceSpeakFields(pace, baseAutoplayMs) {
|
|
16
|
+
const p = normalizeDemoPace(pace);
|
|
17
|
+
const base = Number.isFinite(baseAutoplayMs) && baseAutoplayMs > 0 ? baseAutoplayMs : 1800;
|
|
18
|
+
return {
|
|
19
|
+
pace: p,
|
|
20
|
+
paceBadge: formatDemoPaceBadge(p, base),
|
|
21
|
+
paceLabel: formatDemoPaceLabel(p, base),
|
|
22
|
+
paceKind: demoPaceKind(p),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
/** Demo CLI chatter (agents use this to ballpark timing / todo layout). Off for WAYGRAPH_JSON. */
|
|
28
|
+
function demoQuiet() {
|
|
29
|
+
return process.env.WAYGRAPH_JSON === "1";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function demoColorEnabled() {
|
|
33
|
+
// FORCE_COLOR wins (agents/CI often set NO_COLOR=1).
|
|
34
|
+
if (process.env.FORCE_COLOR && process.env.FORCE_COLOR !== "0") return true;
|
|
35
|
+
if (process.env.NO_COLOR === "1" || process.env.NO_COLOR === "true") return false;
|
|
36
|
+
if (process.env.FORCE_COLOR === "0") return false;
|
|
37
|
+
return !!(
|
|
38
|
+
(process.stderr && process.stderr.isTTY) ||
|
|
39
|
+
(process.stdout && process.stdout.isTTY)
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const ESC = String.fromCharCode(27);
|
|
44
|
+
|
|
45
|
+
export const ANSI = {
|
|
46
|
+
reset: ESC + "[0m",
|
|
47
|
+
bold: ESC + "[1m",
|
|
48
|
+
dim: ESC + "[2m",
|
|
49
|
+
purple: ESC + "[38;5;141m",
|
|
50
|
+
blue: ESC + "[38;5;75m",
|
|
51
|
+
yellow: ESC + "[38;5;220m",
|
|
52
|
+
red: ESC + "[38;5;203m",
|
|
53
|
+
green: ESC + "[38;5;114m",
|
|
54
|
+
gray: ESC + "[38;5;246m",
|
|
55
|
+
cyan: ESC + "[38;5;87m",
|
|
56
|
+
magenta: ESC + "[38;5;213m",
|
|
57
|
+
white: ESC + "[37m",
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export function ansiPaint(code, text) {
|
|
61
|
+
if (!demoColorEnabled() || text == null || text === "") return String(text ?? "");
|
|
62
|
+
return code + String(text) + ANSI.reset;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function toneAnsi(tone) {
|
|
66
|
+
const t = normalizeHighlightTone(tone);
|
|
67
|
+
if (t === "info") return ANSI.blue;
|
|
68
|
+
if (t === "warning") return ANSI.yellow;
|
|
69
|
+
if (t === "danger") return ANSI.red;
|
|
70
|
+
if (t === "success") return ANSI.green;
|
|
71
|
+
if (t === "auto") return ANSI.gray;
|
|
72
|
+
return ANSI.purple;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function toneName(tone) {
|
|
76
|
+
const t = normalizeHighlightTone(tone);
|
|
77
|
+
if (t === "info") return "BLUE";
|
|
78
|
+
if (t === "warning") return "YELLOW";
|
|
79
|
+
if (t === "danger") return "RED";
|
|
80
|
+
if (t === "success") return "GREEN";
|
|
81
|
+
if (t === "auto") return "GRAY";
|
|
82
|
+
return "PURPLE";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Optional authored CSS color (#rrggbb) -> truecolor ANSI when TTY. */
|
|
86
|
+
function hexAnsi(hex) {
|
|
87
|
+
if (!hex || typeof hex !== "string") return null;
|
|
88
|
+
const m = String(hex).trim().match(/^#?([0-9a-fA-F]{6})$/);
|
|
89
|
+
if (!m) return null;
|
|
90
|
+
const n = parseInt(m[1], 16);
|
|
91
|
+
const r = (n >> 16) & 255;
|
|
92
|
+
const g = (n >> 8) & 255;
|
|
93
|
+
const b = n & 255;
|
|
94
|
+
return ESC + "[38;2;" + r + ";" + g + ";" + b + "m";
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function demoTs() {
|
|
98
|
+
const d = new Date();
|
|
99
|
+
const p = (n) => String(n).padStart(2, "0");
|
|
100
|
+
const ms = String(d.getMilliseconds()).padStart(3, "0");
|
|
101
|
+
return (
|
|
102
|
+
p(d.getHours()) +
|
|
103
|
+
":" +
|
|
104
|
+
p(d.getMinutes()) +
|
|
105
|
+
":" +
|
|
106
|
+
p(d.getSeconds()) +
|
|
107
|
+
"." +
|
|
108
|
+
ms
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function demoPrefix() {
|
|
113
|
+
return ansiPaint(ANSI.dim, "[" + demoTs() + "]") + " waygraph demo: ";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function demoLog(msg) {
|
|
117
|
+
if (demoQuiet()) return;
|
|
118
|
+
console.log(demoPrefix() + msg);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Fixture catch-all: how it was called + value. */
|
|
122
|
+
export function demoFixture(kind, call, value) {
|
|
123
|
+
if (demoQuiet()) return;
|
|
124
|
+
const head = ansiPaint(ANSI.cyan, "FIXTURE") + " " + ansiPaint(ANSI.bold, kind);
|
|
125
|
+
const callPart = call ? " " + ansiPaint(ANSI.dim, call) : "";
|
|
126
|
+
let val = "";
|
|
127
|
+
if (value !== undefined) {
|
|
128
|
+
if (typeof value === "string") val = value;
|
|
129
|
+
else {
|
|
130
|
+
try {
|
|
131
|
+
val = JSON.stringify(value);
|
|
132
|
+
} catch {
|
|
133
|
+
val = String(value);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (val.length > 220) val = val.slice(0, 217) + "...";
|
|
137
|
+
val = " = " + ansiPaint(ANSI.white, val);
|
|
138
|
+
}
|
|
139
|
+
console.log(demoPrefix() + head + callPart + val);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Highlight trigger line: PURPLE · Cart items - Product landed in cart */
|
|
143
|
+
export function demoHighlight(h, extra) {
|
|
144
|
+
if (demoQuiet()) return;
|
|
145
|
+
const tone = h && h.tone != null ? h.tone : "planned";
|
|
146
|
+
const paint = hexAnsi(h && h.color) || toneAnsi(tone);
|
|
147
|
+
const name = toneName(tone);
|
|
148
|
+
const label = String((h && h.label) || "").trim() || "(no label)";
|
|
149
|
+
const sel = h && h.selector ? String(h.selector) : "";
|
|
150
|
+
const bits = [];
|
|
151
|
+
if (h && h.focus) bits.push("focus");
|
|
152
|
+
if (h && h.zoom != null && Number(h.zoom) > 1) bits.push("zoom=" + h.zoom);
|
|
153
|
+
if (h && h.zoomOut === false) bits.push("zoomOut=false");
|
|
154
|
+
if (h && h.gesture) bits.push("gesture=" + h.gesture);
|
|
155
|
+
if (h && h.weight && h.weight !== "normal") bits.push("weight=" + h.weight);
|
|
156
|
+
if (h && h.size && h.size !== "md") bits.push("size=" + h.size);
|
|
157
|
+
if (h && h.color) bits.push("color=" + h.color);
|
|
158
|
+
if (extra) bits.push(extra);
|
|
159
|
+
const line =
|
|
160
|
+
ansiPaint(paint, name) +
|
|
161
|
+
" · " +
|
|
162
|
+
ansiPaint(paint, label) +
|
|
163
|
+
(sel ? ansiPaint(ANSI.dim, " sel=" + sel) : "") +
|
|
164
|
+
(bits.length ? ansiPaint(ANSI.dim, " [" + bits.join(" ") + "]") : "");
|
|
165
|
+
console.log(demoPrefix() + ansiPaint(ANSI.magenta, "HIGHLIGHT") + " " + line);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function logStubPhaseFixtures(phaseName, phase) {
|
|
169
|
+
if (demoQuiet() || !phase) return;
|
|
170
|
+
const tag = "stub." + phaseName;
|
|
171
|
+
if (phase.title) demoFixture(tag, "ctx.title(...)", JSON.stringify(phase.title));
|
|
172
|
+
if (phase.banner) demoFixture(tag, "ctx.banner(...)", JSON.stringify(phase.banner));
|
|
173
|
+
if (phase.deviceSync && phase.deviceSync !== "keep") {
|
|
174
|
+
demoFixture(
|
|
175
|
+
tag,
|
|
176
|
+
phase.deviceSync === "clear" ? "ctx.clearDevice()" : "ctx.device(...)",
|
|
177
|
+
phase.device
|
|
178
|
+
? {
|
|
179
|
+
preset: phase.device.preset,
|
|
180
|
+
w: phase.device.viewport && phase.device.viewport.width,
|
|
181
|
+
h: phase.device.viewport && phase.device.viewport.height,
|
|
182
|
+
orient: phase.device.orientation,
|
|
183
|
+
touch: !!phase.device.touchMode,
|
|
184
|
+
}
|
|
185
|
+
: phase.deviceSync,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
if (phase.zoom != null) demoFixture(tag, "ctx.zoom(" + phase.zoom + ")", phase.zoom + "x");
|
|
189
|
+
if (phase.zoomOut !== undefined) demoFixture(tag, "ctx.zoomOut(" + !!phase.zoomOut + ")", !!phase.zoomOut);
|
|
190
|
+
if (phase.todoSync && phase.todoSync !== "keep") {
|
|
191
|
+
demoFixture(
|
|
192
|
+
tag,
|
|
193
|
+
phase.todoSync === "clear" ? "ctx.hideTodos() / clear" : "ctx.todos(...)",
|
|
194
|
+
phase.todoDock
|
|
195
|
+
? {
|
|
196
|
+
id: phase.todoDock.id,
|
|
197
|
+
pos: phase.todoDock.pos,
|
|
198
|
+
title: phase.todoDock.title,
|
|
199
|
+
n: (phase.todos && phase.todos.length) || 0,
|
|
200
|
+
}
|
|
201
|
+
: phase.todoSync,
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
const rings = phase.highlights || [];
|
|
205
|
+
for (let i = 0; i < rings.length; i++) {
|
|
206
|
+
const h = rings[i];
|
|
207
|
+
demoFixture(
|
|
208
|
+
tag,
|
|
209
|
+
"ctx.ring/highlights[" + i + "]",
|
|
210
|
+
{
|
|
211
|
+
selector: h.selector,
|
|
212
|
+
label: h.label || h.caption,
|
|
213
|
+
detail: h.detail,
|
|
214
|
+
tone: h.tone || "planned",
|
|
215
|
+
color: h.color,
|
|
216
|
+
focus: !!h.focus,
|
|
217
|
+
zoom: h.zoom,
|
|
218
|
+
zoomOut: h.zoomOut,
|
|
219
|
+
gesture: h.gesture,
|
|
220
|
+
duration: h.duration,
|
|
221
|
+
},
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
if (phase.slides && phase.slides.length) {
|
|
225
|
+
demoFixture(tag, "ctx.slides(...)", { n: phase.slides.length });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function summarizeTodoDock(dock) {
|
|
230
|
+
if (!dock) return "todos=none";
|
|
231
|
+
const id = dock.id || "_default";
|
|
232
|
+
const pos = dock.pos || "left";
|
|
233
|
+
const style = dock.style || "sequential";
|
|
234
|
+
const title = dock.title ? String(dock.title) : "";
|
|
235
|
+
const items = [];
|
|
236
|
+
for (const g of dock.groups || []) {
|
|
237
|
+
for (const t of g.items || []) items.push(t);
|
|
238
|
+
}
|
|
239
|
+
const cur = items.find((t) => t.current);
|
|
240
|
+
const done = items.filter((t) => t.done).length;
|
|
241
|
+
return (
|
|
242
|
+
"todos id=" +
|
|
243
|
+
id +
|
|
244
|
+
" pos=" +
|
|
245
|
+
pos +
|
|
246
|
+
" style=" +
|
|
247
|
+
style +
|
|
248
|
+
(title ? ' title="' + title + '"' : "") +
|
|
249
|
+
" n=" +
|
|
250
|
+
items.length +
|
|
251
|
+
" done=" +
|
|
252
|
+
done +
|
|
253
|
+
(cur && cur.text ? ' current="' + String(cur.text).slice(0, 48) + '"' : "")
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** Full todo dump for agents (every group/item id + flags). */
|
|
258
|
+
export function logTodoDockFull(dock, tag) {
|
|
259
|
+
const prefix = tag ? tag + " " : "";
|
|
260
|
+
if (!dock) {
|
|
261
|
+
demoLog(prefix + "todos=none");
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
demoLog(prefix + summarizeTodoDock(dock));
|
|
265
|
+
const groups = dock.groups || [];
|
|
266
|
+
if (!groups.length) {
|
|
267
|
+
demoLog(prefix + " (no groups)");
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
for (let gi = 0; gi < groups.length; gi++) {
|
|
271
|
+
const g = groups[gi];
|
|
272
|
+
const gLabel =
|
|
273
|
+
"group[" +
|
|
274
|
+
gi +
|
|
275
|
+
"]" +
|
|
276
|
+
(g.id ? " id=" + g.id : "") +
|
|
277
|
+
(g.title ? ' title="' + String(g.title).slice(0, 40) + '"' : "") +
|
|
278
|
+
(g.style ? " style=" + g.style : "");
|
|
279
|
+
demoLog(prefix + " " + gLabel);
|
|
280
|
+
const items = g.items || [];
|
|
281
|
+
for (let ti = 0; ti < items.length; ti++) {
|
|
282
|
+
const t = items[ti];
|
|
283
|
+
const mark = t.done ? "done" : t.current ? "CURRENT" : "pending";
|
|
284
|
+
demoLog(
|
|
285
|
+
prefix +
|
|
286
|
+
" [" +
|
|
287
|
+
ti +
|
|
288
|
+
"] " +
|
|
289
|
+
mark +
|
|
290
|
+
(t.id ? " id=" + t.id : "") +
|
|
291
|
+
' text="' +
|
|
292
|
+
String(t.text || "").slice(0, 80) +
|
|
293
|
+
'"' +
|
|
294
|
+
(t.detail ? ' detail="' + String(t.detail).slice(0, 40) + '"' : ""),
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export function summarizeDevice(d) {
|
|
301
|
+
if (!d) return "device=none";
|
|
302
|
+
const vp = d.viewport || {};
|
|
303
|
+
return (
|
|
304
|
+
"device=" +
|
|
305
|
+
(d.preset || "?") +
|
|
306
|
+
" " +
|
|
307
|
+
(vp.width || "?") +
|
|
308
|
+
"x" +
|
|
309
|
+
(vp.height || "?") +
|
|
310
|
+
" " +
|
|
311
|
+
(d.orientation || "?") +
|
|
312
|
+
(d.touchMode ? " touch" : "")
|
|
313
|
+
);
|
|
314
|
+
}
|