@cimplify/cli 0.15.2 → 0.16.0

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.
Files changed (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -2
  3. package/dist/add-SXC6RUPQ.mjs +140 -0
  4. package/dist/{add-KRIIKAS4.mjs → add-XQVQLD3F.mjs} +4 -4
  5. package/dist/ai-NQH5L4I6.mjs +17 -0
  6. package/dist/{assets-CWB72PZG.mjs → assets-FZGVOQXH.mjs} +12 -7
  7. package/dist/{auth-step-up-Z6KOTTV7.mjs → auth-step-up-67LCPDNL.mjs} +5 -5
  8. package/dist/build-J4ZUIOPX.mjs +625 -0
  9. package/dist/{cancel-ZHVVILOU.mjs → cancel-VGJHZJ4J.mjs} +4 -4
  10. package/dist/capture-RAJ2B3BH.mjs +69 -0
  11. package/dist/chunk-25ZPFHLF.mjs +51 -0
  12. package/dist/chunk-47ZXSY47.mjs +52 -0
  13. package/dist/{chunk-NK6VC264.mjs → chunk-54J3XR4T.mjs} +2 -2
  14. package/dist/chunk-5HP2INMY.mjs +10631 -0
  15. package/dist/chunk-7JR6JCFF.mjs +32 -0
  16. package/dist/chunk-7PQL7E7K.mjs +68 -0
  17. package/dist/chunk-AKACUJ3W.mjs +81 -0
  18. package/dist/chunk-BYNE553A.mjs +2945 -0
  19. package/dist/{chunk-NYXA6X56.mjs → chunk-CLQYPTJ2.mjs} +31 -11
  20. package/dist/chunk-CNZAOVSK.mjs +104 -0
  21. package/dist/chunk-CPBESPWK.mjs +5576 -0
  22. package/dist/{chunk-GRR5U2M5.mjs → chunk-DYWUPHV3.mjs} +11 -7
  23. package/dist/chunk-EAV2P4N3.mjs +1941 -0
  24. package/dist/{chunk-KN2YSKXZ.mjs → chunk-EDZSOL5O.mjs} +14 -6
  25. package/dist/chunk-EGQIPYUN.mjs +696 -0
  26. package/dist/{chunk-DMLQBAGC.mjs → chunk-EOO4UOQD.mjs} +1 -1
  27. package/dist/chunk-EYEMPIMP.mjs +74 -0
  28. package/dist/chunk-G2ZEFSQJ.mjs +46 -0
  29. package/dist/{chunk-TH4XENKH.mjs → chunk-I4HNHPEM.mjs} +1 -1
  30. package/dist/chunk-JEVSFNPT.mjs +363 -0
  31. package/dist/chunk-JKECUAAV.mjs +2169 -0
  32. package/dist/chunk-KMHORI4Y.mjs +638 -0
  33. package/dist/chunk-KNPYBZ6B.mjs +502 -0
  34. package/dist/{chunk-3QUK5BPY.mjs → chunk-KOD4GBQ5.mjs} +8 -1
  35. package/dist/chunk-KQNZKV6E.mjs +535 -0
  36. package/dist/{chunk-MXYUAJEW.mjs → chunk-LLRUOIMU.mjs} +5 -2
  37. package/dist/{chunk-F2UI225N.mjs → chunk-LNMITJ4Z.mjs} +6 -6
  38. package/dist/chunk-MEM3MDV4.mjs +6463 -0
  39. package/dist/chunk-NY4YT7O6.mjs +84 -0
  40. package/dist/{chunk-A6WHBSXZ.mjs → chunk-Q6CF4C3E.mjs} +15 -13
  41. package/dist/chunk-RP66A52P.mjs +86 -0
  42. package/dist/{chunk-I2UP7YTG.mjs → chunk-SAXGWS2K.mjs} +1 -1
  43. package/dist/chunk-SCKQ4XSD.mjs +41 -0
  44. package/dist/chunk-SF44L2OD.mjs +1152 -0
  45. package/dist/chunk-SGT5IJVW.mjs +28 -0
  46. package/dist/{chunk-WEAB6HHQ.mjs → chunk-SS4JTMIV.mjs} +8 -8
  47. package/dist/chunk-T4MW3PD4.mjs +1456 -0
  48. package/dist/chunk-THATLMEX.mjs +1227 -0
  49. package/dist/{chunk-MLE4MVYC.mjs → chunk-TT4YI33G.mjs} +2 -2
  50. package/dist/chunk-TYV2SVFN.mjs +101 -0
  51. package/dist/chunk-VHK7WBO3.mjs +189 -0
  52. package/dist/chunk-VSA44UKR.mjs +391 -0
  53. package/dist/chunk-XL54SQJ3.mjs +42 -0
  54. package/dist/{chunk-5KYR6WJB.mjs → chunk-XQAHREKO.mjs} +17 -1
  55. package/dist/chunk-ZUCDXRFI.mjs +2011 -0
  56. package/dist/create-4S2EAUR3.mjs +10 -0
  57. package/dist/credits-NJOAOPPW.mjs +33 -0
  58. package/dist/{deploy-JE6TUYCL.mjs → deploy-26Y4UGZZ.mjs} +14 -14
  59. package/dist/dev-MOYURRWQ.mjs +401 -0
  60. package/dist/dev-WL43Q7VD.mjs +8 -0
  61. package/dist/dispatcher.mjs +131 -30
  62. package/dist/{doctor-HFB4IBYK.mjs → doctor-E6ETD2GJ.mjs} +12 -19
  63. package/dist/{domains-BZKGIDF4.mjs → domains-LOTQMVOR.mjs} +6 -6
  64. package/dist/engine-runtime-fetch-CIE7S7PB.mjs +10 -0
  65. package/dist/{env-FZNXKLGL.mjs → env-3PDFC5XF.mjs} +7 -7
  66. package/dist/env-MOTYOPM5.mjs +19 -0
  67. package/dist/explain-K5QEVWCD.mjs +251 -0
  68. package/dist/{inspect-X3M7WSTL.mjs → inspect-Q3E2DHYY.mjs} +3 -3
  69. package/dist/inspect-SJ4WBAXO.mjs +86 -0
  70. package/dist/introspect-7F34YN5V.mjs +9 -0
  71. package/dist/kernel-DEGWMHFL.mjs +662 -0
  72. package/dist/kernel-plugin.js +6862 -0
  73. package/dist/keys-W5SN3DPK.mjs +71 -0
  74. package/dist/lines-XGJYTQ7P.mjs +56 -0
  75. package/dist/{link-4NM2QMI5.mjs → link-NKUAVNM2.mjs} +6 -5
  76. package/dist/{lint-DDZ7HUQN.mjs → lint-G4YPQSSO.mjs} +2 -2
  77. package/dist/{list-2MFOQKKQ.mjs → list-TDR7K2JB.mjs} +3 -3
  78. package/dist/lock-EJPW2LM3.mjs +57 -0
  79. package/dist/{login-RLMDEWAL.mjs → login-AYLU7JU7.mjs} +10 -8
  80. package/dist/{logout-Z57X6HPE.mjs → logout-3M6VMHLH.mjs} +2 -2
  81. package/dist/{logs-36BLYJHJ.mjs → logs-4EL5SOXN.mjs} +5 -5
  82. package/dist/logs-4QQGG2XY.mjs +44 -0
  83. package/dist/mcp-4R2R6E5M.mjs +1077 -0
  84. package/dist/{mock-EVER34IX.mjs → mock-AK24GSP2.mjs} +2 -2
  85. package/dist/outdated-JEKCVLTG.mjs +58 -0
  86. package/dist/port-SBZ7X3EH.mjs +2408 -0
  87. package/dist/{projects-4XRNHJAH.mjs → projects-7JKTC5WJ.mjs} +9 -7
  88. package/dist/publish-QQCX47HK.mjs +20 -0
  89. package/dist/remix-NLLYD3BI.mjs +125 -0
  90. package/dist/repo-Z4G4EW3N.mjs +9 -0
  91. package/dist/report-M7F4ZYP7.mjs +2 -0
  92. package/dist/rollback-2WQ2CW7T.mjs +43 -0
  93. package/dist/{rollback-WCRWXSE3.mjs → rollback-ZGU32HGT.mjs} +6 -6
  94. package/dist/scene-HXARHUM7.mjs +324 -0
  95. package/dist/{status-VA326DWD.mjs → status-C3ZSLZ7Q.mjs} +5 -5
  96. package/dist/status-WEQOC25K.mjs +18 -0
  97. package/dist/test-ZPBWV4VX.mjs +233 -0
  98. package/dist/testers-A3LMXOJJ.mjs +49 -0
  99. package/dist/{unlink-H3BO3DOQ.mjs → unlink-4G4FE4RJ.mjs} +2 -2
  100. package/dist/{update-YYOTN7MG.mjs → update-GHKKM5FS.mjs} +4 -4
  101. package/dist/{whoami-CQPPARRS.mjs → whoami-3QQN6G2A.mjs} +3 -3
  102. package/dist/workshop-CD74D2LK.mjs +1703 -0
  103. package/package.json +11 -7
  104. package/templates/storefront-auto/app/products/[slug]/page.tsx +1 -1
  105. package/templates/storefront-auto/package.json +1 -1
  106. package/templates/storefront-bakery/package.json +1 -1
  107. package/templates/storefront-fashion/app/products/[slug]/page.tsx +1 -1
  108. package/templates/storefront-fashion/package.json +1 -1
  109. package/templates/storefront-grocery/package.json +1 -1
  110. package/templates/storefront-pharmacy/app/products/[slug]/page.tsx +1 -1
  111. package/templates/storefront-pharmacy/package.json +1 -1
  112. package/templates/storefront-restaurant/package.json +1 -1
  113. package/templates/storefront-retail/app/products/[slug]/page.tsx +1 -1
  114. package/templates/storefront-retail/package.json +1 -1
  115. package/templates/storefront-services/package.json +1 -1
  116. package/dist/chunk-ARIDYKLO.mjs +0 -6463
  117. package/dist/dev-V7JSUVOI.mjs +0 -8
  118. package/dist/explain-O5AC73EE.mjs +0 -251
  119. package/dist/introspect-2NGESQZE.mjs +0 -8
  120. package/dist/repo-X3KZ5R64.mjs +0 -9
@@ -0,0 +1,502 @@
1
+ #!/usr/bin/env node
2
+ import { locateChromium, startDevServer, HARDWARE_GPU_ARGS, BROWSER_ARGS, probeScript, SILENT_PARAM, EMPTY_READINESS } from './chunk-BYNE553A.mjs';
3
+ import { inspectSnapshot } from './chunk-THATLMEX.mjs';
4
+ import { inflateSync, deflateSync } from 'zlib';
5
+ import { promises } from 'fs';
6
+ import path from 'path';
7
+ import vm from 'vm';
8
+ import ts from 'typescript';
9
+
10
+ var GOLDEN = { mean: 1.5, outliers: 5e-3 };
11
+ var OUTLIER_DELTA = 24;
12
+ var SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
13
+ var CHANNELS = { 0: 1, 2: 3, 4: 2, 6: 4 };
14
+ var CRC_TABLE = (() => {
15
+ const table = new Uint32Array(256);
16
+ for (let n = 0; n < 256; n++) {
17
+ let c = n;
18
+ for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
19
+ table[n] = c >>> 0;
20
+ }
21
+ return table;
22
+ })();
23
+ function crc32(bytes) {
24
+ let c = 4294967295;
25
+ for (let i = 0; i < bytes.length; i++) c = CRC_TABLE[(c ^ bytes[i]) & 255] ^ c >>> 8;
26
+ return (c ^ 4294967295) >>> 0;
27
+ }
28
+ function paeth(a, b, c) {
29
+ const p = a + b - c;
30
+ const pa = Math.abs(p - a);
31
+ const pb = Math.abs(p - b);
32
+ const pc = Math.abs(p - c);
33
+ return pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
34
+ }
35
+ function decodePng(data) {
36
+ const bytes = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
37
+ if (bytes.length < SIGNATURE.length || !bytes.subarray(0, SIGNATURE.length).equals(SIGNATURE)) throw new Error("not a PNG file");
38
+ let at = SIGNATURE.length;
39
+ let width = 0;
40
+ let height = 0;
41
+ let depth = 0;
42
+ let type = 0;
43
+ let interlace = 0;
44
+ const idat = [];
45
+ while (at + 8 <= bytes.length) {
46
+ const length = bytes.readUInt32BE(at);
47
+ const kind = bytes.toString("latin1", at + 4, at + 8);
48
+ const body = bytes.subarray(at + 8, at + 8 + length);
49
+ if (kind === "IHDR") {
50
+ width = body.readUInt32BE(0);
51
+ height = body.readUInt32BE(4);
52
+ depth = body[8];
53
+ type = body[9];
54
+ interlace = body[12];
55
+ } else if (kind === "IDAT") idat.push(body);
56
+ else if (kind === "IEND") break;
57
+ at += 12 + length;
58
+ }
59
+ const channels = CHANNELS[type];
60
+ if (depth !== 8 || channels === void 0 || interlace !== 0) throw new Error(`unsupported PNG (bit depth ${depth}, colour type ${type}, interlace ${interlace})`);
61
+ const raw = inflateSync(Buffer.concat(idat));
62
+ const stride = width * channels;
63
+ const rows = new Uint8Array(height * stride);
64
+ for (let y = 0; y < height; y++) {
65
+ const filter = raw[y * (stride + 1)];
66
+ const line = raw.subarray(y * (stride + 1) + 1, (y + 1) * (stride + 1));
67
+ for (let x = 0; x < stride; x++) {
68
+ const left = x >= channels ? rows[y * stride + x - channels] : 0;
69
+ const up = y > 0 ? rows[(y - 1) * stride + x] : 0;
70
+ const corner = x >= channels && y > 0 ? rows[(y - 1) * stride + x - channels] : 0;
71
+ const value = line[x];
72
+ const predicted = filter === 1 ? left : filter === 2 ? up : filter === 3 ? left + up >> 1 : filter === 4 ? paeth(left, up, corner) : 0;
73
+ rows[y * stride + x] = value + predicted & 255;
74
+ }
75
+ }
76
+ const pixels = new Uint8Array(width * height * 4);
77
+ for (let i = 0; i < width * height; i++) {
78
+ const s = i * channels;
79
+ const d = i * 4;
80
+ if (channels >= 3) {
81
+ pixels[d] = rows[s];
82
+ pixels[d + 1] = rows[s + 1];
83
+ pixels[d + 2] = rows[s + 2];
84
+ pixels[d + 3] = channels === 4 ? rows[s + 3] : 255;
85
+ } else {
86
+ pixels[d] = pixels[d + 1] = pixels[d + 2] = rows[s];
87
+ pixels[d + 3] = channels === 2 ? rows[s + 1] : 255;
88
+ }
89
+ }
90
+ return { width, height, pixels };
91
+ }
92
+ function chunk(kind, body) {
93
+ const head = Buffer.alloc(8);
94
+ head.writeUInt32BE(body.length, 0);
95
+ head.write(kind, 4, "latin1");
96
+ const tail = Buffer.alloc(4);
97
+ tail.writeUInt32BE(crc32(Buffer.concat([head.subarray(4), body])), 0);
98
+ return Buffer.concat([head, body, tail]);
99
+ }
100
+ function encodePng(image) {
101
+ const header = Buffer.alloc(13);
102
+ header.writeUInt32BE(image.width, 0);
103
+ header.writeUInt32BE(image.height, 4);
104
+ header[8] = 8;
105
+ header[9] = 6;
106
+ const stride = image.width * 4;
107
+ const raw = Buffer.alloc((stride + 1) * image.height);
108
+ for (let y = 0; y < image.height; y++) Buffer.from(image.pixels.buffer, image.pixels.byteOffset + y * stride, stride).copy(raw, y * (stride + 1) + 1);
109
+ return Buffer.concat([SIGNATURE, chunk("IHDR", header), chunk("IDAT", deflateSync(raw)), chunk("IEND", new Uint8Array(0))]);
110
+ }
111
+ var DIM = 0.25;
112
+ function compareImages(actual, expected, tolerance = GOLDEN) {
113
+ if (actual.width !== expected.width || actual.height !== expected.height) return { mean: Number.POSITIVE_INFINITY, outliers: 1, passed: false, size_matches: false, diff: null };
114
+ const texels = actual.width * actual.height;
115
+ const diff = new Uint8Array(texels * 4);
116
+ let total = 0;
117
+ let outliers = 0;
118
+ for (let i = 0; i < texels; i++) {
119
+ const at = i * 4;
120
+ let worst = 0;
121
+ for (let c = 0; c < 3; c++) {
122
+ const delta = Math.abs(actual.pixels[at + c] - expected.pixels[at + c]);
123
+ total += delta;
124
+ if (delta > worst) worst = delta;
125
+ }
126
+ const outlier = worst > OUTLIER_DELTA;
127
+ if (outlier) outliers++;
128
+ const grey = Math.round((expected.pixels[at] + expected.pixels[at + 1] + expected.pixels[at + 2]) / 3 * DIM);
129
+ diff[at] = outlier ? 255 : grey;
130
+ diff[at + 1] = outlier ? 0 : grey;
131
+ diff[at + 2] = outlier ? 255 : grey;
132
+ diff[at + 3] = 255;
133
+ }
134
+ const mean = total / (texels * 3);
135
+ const fraction = outliers / texels;
136
+ return { mean, outliers: fraction, passed: mean <= tolerance.mean && fraction <= tolerance.outliers, size_matches: true, diff: { width: actual.width, height: actual.height, pixels: diff } };
137
+ }
138
+ var SCRIPT_SCHEMA = "cimplify.input/1";
139
+ var DEFAULT_DRAG_FRAMES = 12;
140
+ var DEFAULT_HOLD_FRAMES = 1;
141
+ function isRecord(value) {
142
+ return typeof value === "object" && value !== null && !Array.isArray(value);
143
+ }
144
+ function frames(value, where) {
145
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) throw new Error(`${where} must be a whole number of frames, 0 or more`);
146
+ return value;
147
+ }
148
+ function isPoint(value) {
149
+ return Array.isArray(value) && value.length === 2 && value.every((v) => typeof v === "number" && Number.isFinite(v));
150
+ }
151
+ function point(value, where) {
152
+ if (isPoint(value)) return [value[0], value[1]];
153
+ throw new Error(`${where} must be [x, y] in points`);
154
+ }
155
+ function target(value, where) {
156
+ if (isPoint(value)) return [value[0], value[1]];
157
+ if (isRecord(value)) {
158
+ if (typeof value.node === "number" && Number.isInteger(value.node)) return { node: value.node };
159
+ if (typeof value.name === "string" && value.name.length > 0) return { name: value.name };
160
+ if (typeof value.text === "string" && value.text.length > 0) return { text: value.text };
161
+ }
162
+ throw new Error(`${where} must be [x, y] in points, { node: id }, { name: "variable" } or { text: "shown text" }`);
163
+ }
164
+ function step(value, index) {
165
+ const where = `steps[${index}]`;
166
+ if (!isRecord(value)) throw new Error(`${where} must be an object`);
167
+ const keys = Object.keys(value);
168
+ if ("wait" in value) return { wait: frames(value.wait, `${where}.wait`) };
169
+ if ("wait_ms" in value) {
170
+ if (typeof value.wait_ms !== "number" || value.wait_ms < 0) throw new Error(`${where}.wait_ms must be 0 or more milliseconds`);
171
+ return { wait_ms: value.wait_ms };
172
+ }
173
+ if ("tap" in value) return { tap: target(value.tap, `${where}.tap`), hold: value.hold === void 0 ? DEFAULT_HOLD_FRAMES : frames(value.hold, `${where}.hold`) };
174
+ if ("drag" in value) {
175
+ const drag = value.drag;
176
+ if (!isRecord(drag)) throw new Error(`${where}.drag must be { from, to, frames?, path? }`);
177
+ const from = target(drag.from, `${where}.drag.from`);
178
+ const to = target(drag.to, `${where}.drag.to`);
179
+ if (drag.path !== void 0) {
180
+ if (!Array.isArray(drag.path) || drag.path.length === 0) throw new Error(`${where}.drag.path must be a non-empty array of [x, y] points, one per frame`);
181
+ const path2 = drag.path.map((p, i) => point(p, `${where}.drag.path[${i}]`));
182
+ if (drag.frames !== void 0 && drag.frames !== path2.length) throw new Error(`${where}.drag.frames must equal the path length (${path2.length})`);
183
+ return { drag: { from, to, frames: path2.length, path: path2 } };
184
+ }
185
+ return { drag: { from, to, frames: drag.frames === void 0 ? DEFAULT_DRAG_FRAMES : Math.max(1, frames(drag.frames, `${where}.drag.frames`)) } };
186
+ }
187
+ if ("key" in value) {
188
+ if (typeof value.key !== "string" || value.key.length === 0) throw new Error(`${where}.key must be a key name such as "Space" or "ArrowLeft"`);
189
+ return { key: value.key, hold: value.hold === void 0 ? DEFAULT_HOLD_FRAMES : frames(value.hold, `${where}.hold`) };
190
+ }
191
+ if ("down" in value) return { down: point(value.down, `${where}.down`) };
192
+ if ("move" in value) return { move: point(value.move, `${where}.move`) };
193
+ if ("up" in value) {
194
+ if (value.up !== true) throw new Error(`${where}.up must be true`);
195
+ return { up: true };
196
+ }
197
+ if ("key_down" in value || "key_up" in value) {
198
+ const down = "key_down" in value;
199
+ const key = down ? value.key_down : value.key_up;
200
+ if (typeof key !== "string" || key.length === 0) throw new Error(`${where}.${down ? "key_down" : "key_up"} must be a key name such as "Space" or "KeyW"`);
201
+ return down ? { key_down: key } : { key_up: key };
202
+ }
203
+ if ("text" in value) {
204
+ if (typeof value.text !== "string") throw new Error(`${where}.text must be the text to type`);
205
+ return { text: value.text };
206
+ }
207
+ if ("type" in value) {
208
+ if (typeof value.type !== "string") throw new Error(`${where}.type must be the text to type`);
209
+ return { type: value.type };
210
+ }
211
+ if ("capture" in value) {
212
+ if (typeof value.capture !== "string" || !/^[a-z0-9][a-z0-9_-]*$/.test(value.capture)) throw new Error(`${where}.capture must be a name of lowercase letters, digits, - and _`);
213
+ return { capture: value.capture };
214
+ }
215
+ throw new Error(`${where} has no known action (${keys.join(", ")}); use wait, wait_ms, tap, drag, key, type, capture, down, move, up, key_down, key_up or text`);
216
+ }
217
+ function parseScript(value) {
218
+ const body = Array.isArray(value) ? { steps: value } : value;
219
+ if (!isRecord(body)) throw new Error("an input script is an array of steps or { steps: [...] }");
220
+ if (!Array.isArray(body.steps)) throw new Error("an input script needs a steps array");
221
+ const devices = body.devices ?? body.device;
222
+ const list = devices === void 0 ? null : Array.isArray(devices) ? devices : [devices];
223
+ if (list !== null && !list.every((d) => typeof d === "string")) throw new Error("devices must be device names");
224
+ if (body.seed !== void 0 && (typeof body.seed !== "number" || !Number.isInteger(body.seed))) throw new Error("seed must be an integer");
225
+ if (body.scene !== void 0 && typeof body.scene !== "string") throw new Error("scene must be a scene name");
226
+ if (body.max_stalls !== void 0 && (typeof body.max_stalls !== "number" || !Number.isInteger(body.max_stalls) || body.max_stalls < 0)) {
227
+ throw new Error("max_stalls must be a whole number of frames, 0 or more");
228
+ }
229
+ return {
230
+ devices: list,
231
+ seed: body.seed ?? null,
232
+ scene: body.scene ?? null,
233
+ steps: body.steps.map(step),
234
+ max_stalls: body.max_stalls ?? null
235
+ };
236
+ }
237
+ function evaluateModule(source, file) {
238
+ const js = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 }, fileName: file }).outputText;
239
+ const module = { exports: {} };
240
+ const context = vm.createContext({ module, exports: module.exports });
241
+ vm.runInContext(js, context, { filename: file, timeout: 1e3 });
242
+ const exported = module.exports;
243
+ return "default" in exported ? exported.default : exported;
244
+ }
245
+ async function loadScript(file) {
246
+ const text = await promises.readFile(file, "utf8");
247
+ const ext = path.extname(file);
248
+ try {
249
+ const value = ext === ".json" ? JSON.parse(text) : evaluateModule(text, file);
250
+ return parseScript(value);
251
+ } catch (error) {
252
+ throw new Error(`${file}: ${error.message}`);
253
+ }
254
+ }
255
+
256
+ // src/interactives/inspect/session.ts
257
+ var FRAME_MS = 1e3 / 60;
258
+ var DEFAULT_SEED = 1;
259
+ var DEFAULT_EPOCH_MS = Date.UTC(2026, 0, 1);
260
+ var DEFAULT_FRAMES = 60;
261
+ var BACKENDS = ["swiftshader", "hardware"];
262
+ var READY_TIMEOUT_MS = 6e4;
263
+ var POLL_MS = 100;
264
+ var LOCAL_HOST = "127.0.0.1";
265
+ var ANY_PORT = 0;
266
+ var MAX_NODES = 4096;
267
+ var ERRORS_SELECTOR = "#errors";
268
+ async function playStep(step2, driver) {
269
+ const mouse = driver.mouse;
270
+ const keyboard = driver.keyboard;
271
+ if ("wait" in step2) await driver.step(step2.wait);
272
+ else if ("wait_ms" in step2) await driver.step(Math.round(step2.wait_ms / FRAME_MS));
273
+ else if ("tap" in step2) {
274
+ const [x, y] = await driver.resolve(step2.tap);
275
+ await mouse.move(x, y);
276
+ await mouse.down();
277
+ await driver.step(step2.hold ?? DEFAULT_HOLD_FRAMES);
278
+ await mouse.up();
279
+ await driver.step(1);
280
+ } else if ("drag" in step2) {
281
+ const from = await driver.resolve(step2.drag.from);
282
+ const to = await driver.resolve(step2.drag.to);
283
+ const path2 = step2.drag.path;
284
+ const frames2 = path2?.length ?? step2.drag.frames ?? DEFAULT_DRAG_FRAMES;
285
+ await mouse.move(from[0], from[1]);
286
+ await mouse.down();
287
+ await driver.step(1);
288
+ for (let i = 1; i <= frames2; i++) {
289
+ if (path2 !== void 0) await mouse.move(path2[i - 1][0], path2[i - 1][1]);
290
+ else await mouse.move(from[0] + (to[0] - from[0]) * i / frames2, from[1] + (to[1] - from[1]) * i / frames2);
291
+ await driver.step(1);
292
+ }
293
+ await mouse.up();
294
+ await driver.step(1);
295
+ } else if ("key" in step2) {
296
+ await keyboard.down(step2.key);
297
+ await driver.step(step2.hold ?? DEFAULT_HOLD_FRAMES);
298
+ await keyboard.up(step2.key);
299
+ await driver.step(1);
300
+ } else if ("type" in step2) {
301
+ await keyboard.type(step2.type);
302
+ await driver.step(1);
303
+ } else if ("down" in step2) {
304
+ await mouse.move(step2.down[0], step2.down[1]);
305
+ await mouse.down();
306
+ } else if ("move" in step2) await mouse.move(step2.move[0], step2.move[1]);
307
+ else if ("up" in step2) await mouse.up();
308
+ else if ("key_down" in step2) await keyboard.down(step2.key_down);
309
+ else if ("key_up" in step2) await keyboard.up(step2.key_up);
310
+ else if ("text" in step2) await keyboard.type(step2.text);
311
+ else await driver.capture(step2.capture);
312
+ }
313
+ var SessionError = class extends Error {
314
+ };
315
+ var CaptureSession = class _CaptureSession {
316
+ constructor(options, server, browser, context, page) {
317
+ this.options = options;
318
+ this.server = server;
319
+ this.browser = browser;
320
+ this.context = context;
321
+ this.page = page;
322
+ }
323
+ options;
324
+ server;
325
+ browser;
326
+ context;
327
+ page;
328
+ guest = null;
329
+ frame = 0;
330
+ cssSafeArea = false;
331
+ static async open(setup, options) {
332
+ const chromium = locateChromium([setup.toolchain.base, setup.toolchain.sdkDir]);
333
+ if (typeof chromium === "string") throw new SessionError(chromium);
334
+ const server = await startDevServer({ root: setup.root, host: LOCAL_HOST, port: ANY_PORT, watch: false, build: setup.build, packagesRoot: setup.toolchain.base });
335
+ let browser = null;
336
+ try {
337
+ browser = await chromium.launch({ headless: true, args: options.backend === "hardware" ? HARDWARE_GPU_ARGS : BROWSER_ARGS });
338
+ const device = options.device;
339
+ const context = await browser.newContext({ viewport: { width: device.width, height: device.height }, deviceScaleFactor: device.scale, hasTouch: device.touch });
340
+ await context.addInitScript({
341
+ content: probeScript({ seed: options.seed, epoch: DEFAULT_EPOCH_MS, frame_ms: FRAME_MS, insets: device.insets, bare: true, scene: options.scene, max_nodes: MAX_NODES })
342
+ });
343
+ const page = await context.newPage();
344
+ const session = new _CaptureSession(options, server, browser, context, page);
345
+ await session.overrideSafeArea();
346
+ await page.goto(`${server.url}/?${SILENT_PARAM}`);
347
+ await session.waitReady();
348
+ return session;
349
+ } catch (error) {
350
+ await browser?.close();
351
+ await server.close();
352
+ throw error;
353
+ }
354
+ }
355
+ async overrideSafeArea() {
356
+ const insets = this.options.device.insets;
357
+ try {
358
+ const cdp = await this.context.newCDPSession(this.page);
359
+ await cdp.send("Emulation.setSafeAreaInsetsOverride", {
360
+ insets: { top: insets.top, topMax: insets.top, right: insets.right, rightMax: insets.right, bottom: insets.bottom, bottomMax: insets.bottom, left: insets.left, leftMax: insets.left }
361
+ });
362
+ this.cssSafeArea = true;
363
+ } catch {
364
+ this.cssSafeArea = false;
365
+ }
366
+ }
367
+ async pageErrors() {
368
+ return (await this.page.locator(ERRORS_SELECTOR).textContent() ?? "").trim();
369
+ }
370
+ async waitReady() {
371
+ const deadline = Date.now() + READY_TIMEOUT_MS;
372
+ while (Date.now() < deadline) {
373
+ for (const frame of this.page.frames()) {
374
+ const state = await frame.evaluate(() => {
375
+ const probe = globalThis.__cimplify_probe;
376
+ if (probe === void 0 || !probe.guest) return { ready: false, refused: null };
377
+ return { ready: probe.ready(), refused: probe.refused() };
378
+ }, void 0).catch(() => ({ ready: false, refused: null }));
379
+ if (state.refused !== null) throw new SessionError(state.refused);
380
+ if (state.ready) {
381
+ this.guest = frame;
382
+ return;
383
+ }
384
+ }
385
+ const errors = await this.pageErrors();
386
+ if (errors.length > 0) throw new SessionError(`the game failed to start: ${errors}`);
387
+ await new Promise((resolve) => setTimeout(resolve, POLL_MS));
388
+ }
389
+ throw new SessionError(`the game did not start its engine within ${READY_TIMEOUT_MS / 1e3} s`);
390
+ }
391
+ get frameHandle() {
392
+ if (this.guest === null) throw new SessionError("the game frame is not ready");
393
+ return this.guest;
394
+ }
395
+ async step(frames2) {
396
+ if (frames2 <= 0) return;
397
+ const frame = this.frameHandle;
398
+ try {
399
+ this.frame = await frame.evaluate((n) => globalThis.__cimplify_probe.step(n), frames2);
400
+ } catch (error) {
401
+ const refused = await frame.evaluate(() => globalThis.__cimplify_probe.refused(), void 0).catch(() => null);
402
+ if (refused !== null) throw new SessionError(refused);
403
+ throw error;
404
+ }
405
+ }
406
+ async advanceTo(frame) {
407
+ await this.step(frame - this.frame);
408
+ }
409
+ async loopSamples() {
410
+ return this.frameHandle.evaluate(() => {
411
+ const probe = globalThis.__cimplify_loop_probe;
412
+ return probe?.samples?.() ?? {};
413
+ }, void 0).catch(() => ({}));
414
+ }
415
+ async readiness() {
416
+ return this.frameHandle.evaluate(() => {
417
+ const probe = globalThis.__cimplify_readiness_probe;
418
+ return probe?.report?.() ?? null;
419
+ }, void 0).then((report) => report ?? EMPTY_READINESS).catch(() => EMPTY_READINESS);
420
+ }
421
+ async snapshot() {
422
+ return this.frameHandle.evaluate(() => globalThis.__cimplify_probe.snapshot(), void 0);
423
+ }
424
+ driver() {
425
+ const frame = this.frameHandle;
426
+ return {
427
+ open: () => frame.evaluate(() => globalThis.__cimplify_probe.shadowOpen(), void 0),
428
+ apply: (patch) => frame.evaluate((p) => globalThis.__cimplify_probe.shadowApply(p), patch),
429
+ frame: (dt, full) => frame.evaluate(([d, f]) => globalThis.__cimplify_probe.shadowFrame(d, f), [dt, full]),
430
+ close: () => frame.evaluate(() => globalThis.__cimplify_probe.shadowClose(), void 0)
431
+ };
432
+ }
433
+ async screenshot() {
434
+ await this.page.mainFrame().evaluate(
435
+ () => new Promise((resolve) => {
436
+ const scope = globalThis;
437
+ scope.requestAnimationFrame(() => scope.requestAnimationFrame(() => resolve()));
438
+ }),
439
+ void 0
440
+ );
441
+ return this.page.screenshot({ type: "png" });
442
+ }
443
+ async inspect(png) {
444
+ const screenshot = png === null ? null : decodePng(png);
445
+ return inspectSnapshot(await this.snapshot(), this.driver(), this.options.device, screenshot);
446
+ }
447
+ async resolve(target2) {
448
+ if (Array.isArray(target2)) return target2;
449
+ const { report } = await this.inspect(null);
450
+ const visible = report.nodes.filter((n) => n.visible && n.rect !== null);
451
+ const t = target2;
452
+ const match = t.node !== void 0 ? visible.find((n) => n.id === t.node) : t.name !== void 0 ? visible.find((n) => n.name === t.name) : visible.find((n) => n.text === t.text) ?? visible.find((n) => n.text !== null && t.text !== void 0 && n.text.includes(t.text));
453
+ if (match === void 0 || match.rect === null) throw new SessionError(`no visible node matches ${JSON.stringify(target2)} at frame ${this.frame}`);
454
+ return [match.rect.x + match.rect.width / 2, match.rect.y + match.rect.height / 2];
455
+ }
456
+ async perform(step2, onCapture) {
457
+ await playStep(step2, { mouse: this.page.mouse, keyboard: this.page.keyboard, step: (frames2) => this.step(frames2), resolve: (target2) => this.resolve(target2), capture: onCapture });
458
+ }
459
+ async run(script, onCapture) {
460
+ for (const step2 of script.steps) await this.perform(step2, onCapture);
461
+ }
462
+ async close() {
463
+ await this.page.close().catch(() => {
464
+ });
465
+ await this.context.close().catch(() => {
466
+ });
467
+ await this.browser.close().catch(() => {
468
+ });
469
+ await this.server.close();
470
+ }
471
+ };
472
+
473
+ // src/interactives/inspect/devices.ts
474
+ var NO_INSETS = { top: 0, right: 0, bottom: 0, left: 0 };
475
+ var DEVICES = {
476
+ "phone-portrait": { name: "phone-portrait", width: 390, height: 844, scale: 3, insets: { top: 47, right: 0, bottom: 34, left: 0 }, touch: true },
477
+ "phone-landscape": { name: "phone-landscape", width: 844, height: 390, scale: 3, insets: { top: 0, right: 47, bottom: 21, left: 47 }, touch: true },
478
+ "phone-small": { name: "phone-small", width: 375, height: 667, scale: 2, insets: { top: 20, right: 0, bottom: 0, left: 0 }, touch: true },
479
+ tablet: { name: "tablet", width: 820, height: 1180, scale: 2, insets: { top: 24, right: 0, bottom: 20, left: 0 }, touch: true },
480
+ "tablet-landscape": { name: "tablet-landscape", width: 1180, height: 820, scale: 2, insets: { top: 24, right: 0, bottom: 20, left: 0 }, touch: true }
481
+ };
482
+ var DEFAULT_DEVICE = "phone-portrait";
483
+ var CHECK_DEVICES = ["phone-portrait", "phone-landscape", "tablet"];
484
+ var CUSTOM = /^(\d{2,5})x(\d{2,5})(?:@(\d(?:\.\d+)?))?$/;
485
+ function parseDevice(spec) {
486
+ const known = DEVICES[spec];
487
+ if (known !== void 0) return known;
488
+ const match = CUSTOM.exec(spec);
489
+ if (match === null) return `unknown device "${spec}"; use one of ${Object.keys(DEVICES).join(", ")} or WIDTHxHEIGHT[@SCALE]`;
490
+ const scale = match[3] === void 0 ? 1 : Number(match[3]);
491
+ return { name: spec, width: Number(match[1]), height: Number(match[2]), scale, insets: NO_INSETS, touch: false };
492
+ }
493
+ function withInsets(device, insets) {
494
+ return { ...device, insets };
495
+ }
496
+ function parseInsets(spec) {
497
+ const parts = spec.split(",").map((p) => Number(p.trim()));
498
+ if (parts.length !== 4 || parts.some((p) => !Number.isFinite(p) || p < 0)) return `--safe takes four non-negative numbers, top,right,bottom,left; got "${spec}"`;
499
+ return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[3] };
500
+ }
501
+
502
+ export { BACKENDS, CHECK_DEVICES, CaptureSession, DEFAULT_DEVICE, DEFAULT_DRAG_FRAMES, DEFAULT_EPOCH_MS, DEFAULT_FRAMES, DEFAULT_HOLD_FRAMES, DEFAULT_SEED, DEVICES, FRAME_MS, GOLDEN, SCRIPT_SCHEMA, SessionError, compareImages, decodePng, encodePng, loadScript, parseDevice, parseInsets, withInsets };
@@ -65,12 +65,14 @@ var CliError = class extends Error {
65
65
  code;
66
66
  exitCode;
67
67
  remediation;
68
+ details;
68
69
  constructor(code, message, options = {}) {
69
70
  super(message);
70
71
  this.name = "CliError";
71
72
  this.code = code;
72
73
  this.exitCode = options.exitCode ?? EXIT_CODE_FOR[code];
73
74
  this.remediation = options.remediation;
75
+ this.details = options.details;
74
76
  }
75
77
  };
76
78
  function isCliError(err) {
@@ -88,6 +90,7 @@ var CYAN_OPEN = "\x1B[36m";
88
90
  var PREFIX_STEP = "\u25B8";
89
91
  var PREFIX_SUCCESS = "\u2713";
90
92
  var PREFIX_FAILURE = "\u2717";
93
+ var PREFIX_WARN = "!";
91
94
  var OUTPUT_MODE = {
92
95
  HUMAN: "human",
93
96
  JSON: "json"
@@ -150,6 +153,10 @@ function failure(message) {
150
153
  if (isJsonMode()) return;
151
154
  console.error(`${red(PREFIX_FAILURE)} ${message}`);
152
155
  }
156
+ function warn(message) {
157
+ if (isJsonMode()) return;
158
+ console.error(`${yellow(PREFIX_WARN)} ${message}`);
159
+ }
153
160
  function info(message) {
154
161
  if (isJsonMode()) return;
155
162
  console.log(message);
@@ -163,4 +170,4 @@ function result(data) {
163
170
  `);
164
171
  }
165
172
 
166
- export { CLI_ERROR_CODE, CliError, EXIT_CODE, OUTPUT_MODE, bold, configureOutput, dim, failure, green, info, isAutoYes, isCliError, isInteractive, isJsonMode, red, result, step, success, yellow };
173
+ export { CLI_ERROR_CODE, CliError, EXIT_CODE, OUTPUT_MODE, bold, configureOutput, dim, failure, green, info, isAutoYes, isCliError, isInteractive, isJsonMode, red, result, step, success, warn, yellow };