@flighthq/tool-capture 0.2.0 → 0.2.1-next.423.3350e53

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/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ // The tool-capture CLI. First (and currently only) command: `observe <url>` — the standalone eyes
3
+ // primitive. Point it at any running page and it drives a deterministic headless render, grabs the
4
+ // present frame (via the getContext intercept — zero page integration), and writes screenshot.png +
5
+ // logs.jsonl + status.json (with the observe diagnostics block). No capture script or discovery needed
6
+ // in the consumer; a repo just adds `"capture:observe": "tool-capture observe"` and points it at a URL.
7
+ import { resolve } from 'node:path';
8
+ import { captureUrl } from './captureEntry.js';
9
+ const USAGE = 'usage: tool-capture observe <url> [--out <dir>] [--wait <ms>] [--frames <n>]';
10
+ function flag(argv, key) {
11
+ const i = argv.indexOf(`--${key}`);
12
+ return i >= 0 && argv[i + 1] !== undefined ? argv[i + 1] : undefined;
13
+ }
14
+ async function main() {
15
+ const argv = process.argv.slice(2);
16
+ if (argv[0] !== 'observe') {
17
+ console.error(USAGE);
18
+ process.exit(2);
19
+ }
20
+ const url = argv[1];
21
+ if (url === undefined || url.startsWith('--')) {
22
+ console.error(`observe requires a <url>\n${USAGE}`);
23
+ process.exit(2);
24
+ }
25
+ const outDir = resolve(flag(argv, 'out') ?? './capture');
26
+ const wait = Number.parseInt(flag(argv, 'wait') ?? '0', 10) || 0;
27
+ const captureFrames = Number.parseInt(flag(argv, 'frames') ?? '1', 10) || 1;
28
+ const diagnostics = await captureUrl(url, { outDir, wait, captureFrames });
29
+ console.log(`captured → ${resolve(outDir, 'screenshot.png')}`);
30
+ console.log(`observe ${JSON.stringify(diagnostics)}`);
31
+ // Exit explicitly — the browser's live handles would otherwise keep the event loop alive after
32
+ // teardown and hang the process (the same trap the capture scripts hit).
33
+ process.exit(0);
34
+ }
35
+ main().catch((err) => {
36
+ console.error(err);
37
+ process.exit(1);
38
+ });
39
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,kGAAkG;AAClG,mGAAmG;AACnG,oGAAoG;AACpG,uGAAuG;AACvG,wGAAwG;AAExG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,KAAK,GAAG,8EAA8E,CAAC;AAE7F,SAAS,IAAI,CAAC,IAAuB,EAAE,GAAW;IAChD,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,OAAO,CAAC,KAAK,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,WAAW,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAE5E,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAAE,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACxD,+FAA+F;IAC/F,yEAAyE;IACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -2,6 +2,7 @@ import type { Browser, BrowserContext } from '@playwright/test';
2
2
  export declare function launchBrowser(options?: {
3
3
  captureFrames?: number;
4
4
  verify?: boolean;
5
+ observe?: boolean;
5
6
  }): Promise<{
6
7
  browser: Browser;
7
8
  context: BrowserContext;
@@ -1 +1 @@
1
- {"version":3,"file":"captureBrowser.d.ts","sourceRoot":"","sources":["../src/captureBrowser.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEhE,wBAAsB,aAAa,CACjC,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACzD,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC,CA+FxD"}
1
+ {"version":3,"file":"captureBrowser.d.ts","sourceRoot":"","sources":["../src/captureBrowser.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEhE,wBAAsB,aAAa,CACjC,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAC5E,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC,CAwLxD"}
@@ -34,9 +34,10 @@ export async function launchBrowser(options = {}) {
34
34
  // with no settle-timing race).
35
35
  const captureFrames = options.captureFrames ?? 0;
36
36
  const verify = options.verify ?? true;
37
+ const observe = options.observe ?? false;
37
38
  await context.addInitScript((args) => {
38
39
  const flags = window;
39
- const { frames, verify } = args;
40
+ const { frames, verify, observe } = args;
40
41
  flags.__flightCapture = true;
41
42
  flags.__flightCaptureVerify = verify;
42
43
  // Inline mulberry32 — the exact algorithm of the SDK's createRandomSource (@flighthq/math). It is
@@ -54,15 +55,40 @@ export async function launchBrowser(options = {}) {
54
55
  if (frames < 1)
55
56
  return;
56
57
  flags.__captureFramesReached = false;
57
- // Force preserveDrawingBuffer so the halted Gl frame survives in the buffer for the screenshot
58
- // (the default clears it once composited, which would shoot blank once the loop stops).
58
+ // Own the GL-context boundary. Forcing preserveDrawingBuffer keeps the halted frame in the buffer
59
+ // for the screenshot (the default clears it once composited, shooting blank once the loop stops).
60
+ // Recording each (canvas, gl) here is what lets the harness grab the present frame back post-hoc
61
+ // with ZERO integration: a scene just renders, and captureEntry reads these contexts' default
62
+ // framebuffers itself (see the intercepted-frame grab) — no client verifier registration needed.
63
+ flags.__ftGlContexts = [];
59
64
  const realGetContext = HTMLCanvasElement.prototype.getContext;
60
65
  HTMLCanvasElement.prototype.getContext = function (type, attrs) {
61
66
  if (type === 'webgl' || type === 'webgl2' || type === 'experimental-webgl') {
62
- return realGetContext.call(this, type, { ...attrs, preserveDrawingBuffer: true });
67
+ const gl = realGetContext.call(this, type, { ...attrs, preserveDrawingBuffer: true });
68
+ if (gl !== null && !flags.__ftGlContexts.some((e) => e.gl === gl)) {
69
+ flags.__ftGlContexts.push({ canvas: this, gl: gl });
70
+ }
71
+ return gl;
63
72
  }
64
73
  return realGetContext.call(this, type, attrs);
65
74
  };
75
+ // A scene whose first frames render blank while it warms up (async mesh/texture upload, an IBL
76
+ // bake, a float render target) needs more than `frames` frames before its first non-blank frame.
77
+ // Freezing hard on frame N would then shoot black. So for a GPU verifier the halt treats `frames`
78
+ // as a minimum: once past it, keep advancing until the verifier publishes a real (non-blank) frame,
79
+ // up to this ceiling. Scenes already non-blank by frame N halt at exactly N (unchanged), so stable
80
+ // baselines are unaffected; only warm-up-slow scenes render the extra frames. A scene that stays
81
+ // blank to the ceiling still stops, and the verifier guard in captureEntry then fails it — no false
82
+ // green, no unbounded loop (captureEntry's own 15s wait is the outer bound either way).
83
+ const warmupCeiling = frames + 600;
84
+ // Observe-only fallback: a page that registers no verify target takes the canvas-grab path with no
85
+ // warmup, so an app-loop-driven scene (whose first tick establishes time and hasn't drawn yet) is
86
+ // frozen blank at frame N. In observe mode, keep advancing such a page until its canvas actually
87
+ // draws — bounded by this much smaller ceiling (app-loop startup is a few frames, and a genuinely
88
+ // blank scene must not burn the GPU-warmup's ~10s here). The extra frames are recorded so the
89
+ // caller can warn that the capture took longer. Gate/baseline mode is untouched (deterministic
90
+ // freeze at frame N), so this changes no committed hash.
91
+ const observeWarmupCeiling = frames + 120;
66
92
  let count = 0;
67
93
  const realRequestAnimationFrame = window.requestAnimationFrame.bind(window);
68
94
  // Expose the un-hijacked rAF so the render verifier can await a genuine presented frame before it
@@ -70,14 +96,73 @@ export async function launchBrowser(options = {}) {
70
96
  // verifier awaiting window.requestAnimationFrame could hang; it uses this stashed one instead.
71
97
  flags.__ftRealRequestAnimationFrame = realRequestAnimationFrame;
72
98
  window.requestAnimationFrame = (callback) => realRequestAnimationFrame((time) => {
73
- if (count >= frames)
74
- return; // halt: scene stops advancing on frame N
99
+ if (flags.__captureFramesReached)
100
+ return; // halted: scene holds its last frame
101
+ if (count >= frames) {
102
+ const targetKind = flags.__ftTarget?.kind;
103
+ const gpuVerifying = verify && (targetKind === 'webgl' || targetKind === 'webgpu');
104
+ let done;
105
+ if (observe) {
106
+ // Eyes mode halts on MEASURED canvas pixels, not the verifier's publish signal — the latter
107
+ // false-negatives for whole corpora (e.g. starling/functional render at >0.9 coverage yet
108
+ // never publish, so a verifier-gated warmup burns all the way to the ceiling). Cheap inline
109
+ // "did anything draw" test: downscale the canvas into a 32×32 2D context and look for any
110
+ // pixel differing from the top-left (background). Inlined rather than a named helper on
111
+ // purpose — a named function in an addInitScript body gets esbuild's __name() wrapper, which
112
+ // is undefined in the injected page (same reason mulberry32 is inlined above). The ceiling
113
+ // stays generous when a GPU target is present (a slow IBL bake / async upload can need dozens
114
+ // of frames before first pixels), tighter otherwise (an app-loop 2D scene draws within a few).
115
+ let drew = false;
116
+ const canvas = document.querySelector('canvas');
117
+ if (canvas !== null && canvas.width > 0 && canvas.height > 0) {
118
+ const off = document.createElement('canvas');
119
+ off.width = 32;
120
+ off.height = 32;
121
+ const ctx = off.getContext('2d');
122
+ if (ctx === null) {
123
+ drew = true; // can't sample — don't block the halt
124
+ }
125
+ else {
126
+ try {
127
+ ctx.drawImage(canvas, 0, 0, 32, 32);
128
+ const data = ctx.getImageData(0, 0, 32, 32).data;
129
+ const r = data[0];
130
+ const g = data[1];
131
+ const b = data[2];
132
+ for (let i = 4; i < data.length; i += 4) {
133
+ if (Math.abs(data[i] - r) > 8 ||
134
+ Math.abs(data[i + 1] - g) > 8 ||
135
+ Math.abs(data[i + 2] - b) > 8) {
136
+ drew = true;
137
+ break;
138
+ }
139
+ }
140
+ }
141
+ catch {
142
+ drew = true; // tainted/unreadable — don't block the halt
143
+ }
144
+ }
145
+ }
146
+ done = drew || count >= (gpuVerifying ? warmupCeiling : observeWarmupCeiling);
147
+ }
148
+ else if (gpuVerifying) {
149
+ const haveRealFrame = (flags.__ftVerification?.fingerprint ?? null) !== null || document.getElementById('ft-error') !== null;
150
+ done = haveRealFrame || count >= warmupCeiling;
151
+ }
152
+ else {
153
+ done = true; // gate/baseline: deterministic freeze at exactly frame N
154
+ }
155
+ if (done) {
156
+ flags.__ftWarmupFrames = count - frames; // extra frames the warmup cost (0 = none)
157
+ flags.__captureFramesReached = true;
158
+ return; // halt: scene stops advancing
159
+ }
160
+ // else: still warming up — fall through to render another frame
161
+ }
75
162
  count++;
76
- if (count >= frames)
77
- flags.__captureFramesReached = true;
78
163
  callback(time);
79
164
  });
80
- }, { frames: captureFrames, verify });
165
+ }, { frames: captureFrames, verify, observe });
81
166
  return { browser, context };
82
167
  }
83
168
  //# sourceMappingURL=captureBrowser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"captureBrowser.js","sourceRoot":"","sources":["../src/captureBrowser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"captureBrowser.js","sourceRoot":"","sources":["../src/captureBrowser.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,uGAAuG;AACvG,EAAE;AACF,uGAAuG;AACvG,sGAAsG;AACtG,oGAAoG;AACpG,oCAAoC;AAIpC,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,UAA2E,EAAE;IAE7E,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAEtD,2FAA2F;IAC3F,2FAA2F;IAC3F,6FAA6F;IAC7F,8FAA8F;IAC9F,mFAAmF;IACnF,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QACpC,IAAI,EAAE,CAAC,wBAAwB,EAAE,kCAAkC,CAAC;KACrE,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAEpF,iGAAiG;IACjG,kGAAkG;IAClG,iGAAiG;IACjG,EAAE;IACF,kGAAkG;IAClG,oGAAoG;IACpG,sGAAsG;IACtG,qGAAqG;IACrG,qGAAqG;IACrG,qGAAqG;IACrG,2DAA2D;IAC3D,EAAE;IACF,iGAAiG;IACjG,kGAAkG;IAClG,qGAAqG;IACrG,+BAA+B;IAC/B,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC;IACtC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;IACzC,MAAM,OAAO,CAAC,aAAa,CACzB,CAAC,IAA2D,EAAE,EAAE;QAC9D,MAAM,KAAK,GAAG,MASb,CAAC;QACF,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;QACzC,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC;QAC7B,KAAK,CAAC,qBAAqB,GAAG,MAAM,CAAC;QAErC,kGAAkG;QAClG,+FAA+F;QAC/F,gGAAgG;QAChG,mGAAmG;QACnG,yEAAyE;QACzE,IAAI,IAAI,GAAG,UAAU,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,GAAG,EAAE;YACjB,IAAI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;YAClD,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAC/C,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,UAAU,CAAC;QAC/C,CAAC,CAAC;QAEF,IAAI,MAAM,GAAG,CAAC;YAAE,OAAO;QACvB,KAAK,CAAC,sBAAsB,GAAG,KAAK,CAAC;QAErC,kGAAkG;QAClG,kGAAkG;QAClG,iGAAiG;QACjG,8FAA8F;QAC9F,iGAAiG;QACjG,KAAK,CAAC,cAAc,GAAG,EAAE,CAAC;QAC1B,MAAM,cAAc,GAAG,iBAAiB,CAAC,SAAS,CAAC,UAIvB,CAAC;QAC7B,iBAAiB,CAAC,SAAS,CAAC,UAAU,GAAG,UAEvC,IAAY,EACZ,KAA+B;YAE/B,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,oBAAoB,EAAE,CAAC;gBAC3E,MAAM,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,KAAK,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC,CAAC;gBACtF,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,cAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;oBACnE,KAAK,CAAC,cAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EAAoD,EAAE,CAAC,CAAC;gBACzG,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAChD,CAAkD,CAAC;QAEnD,+FAA+F;QAC/F,iGAAiG;QACjG,kGAAkG;QAClG,oGAAoG;QACpG,mGAAmG;QACnG,iGAAiG;QACjG,oGAAoG;QACpG,wFAAwF;QACxF,MAAM,aAAa,GAAG,MAAM,GAAG,GAAG,CAAC;QACnC,mGAAmG;QACnG,kGAAkG;QAClG,iGAAiG;QACjG,kGAAkG;QAClG,8FAA8F;QAC9F,+FAA+F;QAC/F,yDAAyD;QACzD,MAAM,oBAAoB,GAAG,MAAM,GAAG,GAAG,CAAC;QAC1C,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,MAAM,yBAAyB,GAAG,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5E,kGAAkG;QAClG,+FAA+F;QAC/F,+FAA+F;QAC/F,KAAK,CAAC,6BAA6B,GAAG,yBAAyB,CAAC;QAChE,MAAM,CAAC,qBAAqB,GAAG,CAAC,QAA8B,EAAU,EAAE,CACxE,yBAAyB,CAAC,CAAC,IAAI,EAAE,EAAE;YACjC,IAAI,KAAK,CAAC,sBAAsB;gBAAE,OAAO,CAAC,qCAAqC;YAC/E,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;gBACpB,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC;gBAC1C,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,UAAU,KAAK,OAAO,IAAI,UAAU,KAAK,QAAQ,CAAC,CAAC;gBACnF,IAAI,IAAa,CAAC;gBAClB,IAAI,OAAO,EAAE,CAAC;oBACZ,4FAA4F;oBAC5F,0FAA0F;oBAC1F,4FAA4F;oBAC5F,0FAA0F;oBAC1F,wFAAwF;oBACxF,6FAA6F;oBAC7F,2FAA2F;oBAC3F,8FAA8F;oBAC9F,+FAA+F;oBAC/F,IAAI,IAAI,GAAG,KAAK,CAAC;oBACjB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;oBAChD,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC7D,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;wBAC7C,GAAG,CAAC,KAAK,GAAG,EAAE,CAAC;wBACf,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;wBAChB,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;wBACjC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;4BACjB,IAAI,GAAG,IAAI,CAAC,CAAC,sCAAsC;wBACrD,CAAC;6BAAM,CAAC;4BACN,IAAI,CAAC;gCACH,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;gCACpC,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;gCACjD,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;gCACnB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;gCACnB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;gCACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;oCACxC,IACE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,GAAG,CAAC;wCAC1B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC,GAAG,CAAC;wCAC9B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC,GAAG,CAAC,EAC9B,CAAC;wCACD,IAAI,GAAG,IAAI,CAAC;wCACZ,MAAM;oCACR,CAAC;gCACH,CAAC;4BACH,CAAC;4BAAC,MAAM,CAAC;gCACP,IAAI,GAAG,IAAI,CAAC,CAAC,4CAA4C;4BAC3D,CAAC;wBACH,CAAC;oBACH,CAAC;oBACD,IAAI,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC;gBAChF,CAAC;qBAAM,IAAI,YAAY,EAAE,CAAC;oBACxB,MAAM,aAAa,GACjB,CAAC,KAAK,CAAC,gBAAgB,EAAE,WAAW,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;oBACzG,IAAI,GAAG,aAAa,IAAI,KAAK,IAAI,aAAa,CAAC;gBACjD,CAAC;qBAAM,CAAC;oBACN,IAAI,GAAG,IAAI,CAAC,CAAC,yDAAyD;gBACxE,CAAC;gBACD,IAAI,IAAI,EAAE,CAAC;oBACT,KAAK,CAAC,gBAAgB,GAAG,KAAK,GAAG,MAAM,CAAC,CAAC,0CAA0C;oBACnF,KAAK,CAAC,sBAAsB,GAAG,IAAI,CAAC;oBACpC,OAAO,CAAC,8BAA8B;gBACxC,CAAC;gBACD,gEAAgE;YAClE,CAAC;YACD,KAAK,EAAE,CAAC;YACR,QAAQ,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;IACP,CAAC,EACD,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,CAC3C,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC"}
@@ -1,8 +1,9 @@
1
1
  export declare const RENDERERS: readonly ["dom", "canvas", "webgl", "webgpu"];
2
- export type Tool = 'examples' | 'functional';
2
+ export type Tool = 'examples' | 'functional' | 'reference';
3
3
  export interface Entry {
4
4
  name: string;
5
5
  renderers: string[];
6
+ route?: (renderer: string) => string;
6
7
  }
7
8
  export declare const BACKEND_UNAVAILABLE: RegExp;
8
9
  export declare function discoverEntries(tool: Tool, root: string): Entry[];
@@ -1 +1 @@
1
- {"version":3,"file":"captureEntries.d.ts","sourceRoot":"","sources":["../src/captureEntries.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,SAAS,+CAAgD,CAAC;AACvE,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG,YAAY,CAAC;AAE7C,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AASD,eAAO,MAAM,mBAAmB,QACgJ,CAAC;AAEjL,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,CAkBjE;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAI1F;AAID,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD"}
1
+ {"version":3,"file":"captureEntries.d.ts","sourceRoot":"","sources":["../src/captureEntries.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,SAAS,+CAAgD,CAAC;AAIvE,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,CAAC;AAE3D,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IAIpB,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CACtC;AASD,eAAO,MAAM,mBAAmB,QACgJ,CAAC;AAEjL,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,CAqBjE;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAI1F;AAID,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD"}
@@ -13,6 +13,10 @@ export const RENDERERS = ['dom', 'canvas', 'webgl', 'webgpu'];
13
13
  // as "unavailable".
14
14
  export const BACKEND_UNAVAILABLE = /WebGPU adapter|WebGPU device|requestAdapter|requestDevice|GPUAdapter|WebGPU is not supported|external Instance reference no longer exists|device (was )?lost|device is lost/i;
15
15
  export function discoverEntries(tool, root) {
16
+ // 'reference' entries come from the external flight-reference harness (the reference runner supplies
17
+ // them with routes), not from a directory walk here.
18
+ if (tool === 'reference')
19
+ return [];
16
20
  // Functional scenes are flat files under functional/scenes/; the shared discovery is the single
17
21
  // source of truth (also used by tools/functional/vite.config.ts).
18
22
  if (tool === 'functional')
@@ -1 +1 @@
1
- {"version":3,"file":"captureEntries.js","sourceRoot":"","sources":["../src/captureEntries.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,uEAAuE;AAEvE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAC;AAQvE,oGAAoG;AACpG,+FAA+F;AAC/F,oGAAoG;AACpG,qGAAqG;AACrG,oGAAoG;AACpG,sGAAsG;AACtG,oBAAoB;AACpB,MAAM,CAAC,MAAM,mBAAmB,GAC9B,8KAA8K,CAAC;AAEjL,MAAM,UAAU,eAAe,CAAC,IAAU,EAAE,IAAY;IACtD,gGAAgG;IAChG,kEAAkE;IAClE,IAAI,IAAI,KAAK,YAAY;QAAE,OAAO,wBAAwB,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE/F,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SAC7C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC;SAC/E,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SAC5C,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;QAChB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAChC,MAAM,eAAe,GAAI,SAA+B,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACpE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAChD,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;IAC9C,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,QAAgB,EAAE,MAAyB;IAC/E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC9F,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC/D,CAAC;AAED,iFAAiF;AACjF,qEAAqE;AACrE,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"captureEntries.js","sourceRoot":"","sources":["../src/captureEntries.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,uEAAuE;AAEvE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAC;AAevE,oGAAoG;AACpG,+FAA+F;AAC/F,oGAAoG;AACpG,qGAAqG;AACrG,oGAAoG;AACpG,sGAAsG;AACtG,oBAAoB;AACpB,MAAM,CAAC,MAAM,mBAAmB,GAC9B,8KAA8K,CAAC;AAEjL,MAAM,UAAU,eAAe,CAAC,IAAU,EAAE,IAAY;IACtD,qGAAqG;IACrG,qDAAqD;IACrD,IAAI,IAAI,KAAK,WAAW;QAAE,OAAO,EAAE,CAAC;IACpC,gGAAgG;IAChG,kEAAkE;IAClE,IAAI,IAAI,KAAK,YAAY;QAAE,OAAO,wBAAwB,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE/F,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SAC7C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC;SAC/E,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SAC5C,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;QAChB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAChC,MAAM,eAAe,GAAI,SAA+B,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACpE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAChD,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;IAC9C,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,QAAgB,EAAE,MAAyB;IAC/E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC9F,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC/D,CAAC;AAED,iFAAiF;AACjF,qEAAqE;AACrE,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC"}
@@ -9,6 +9,36 @@ export interface CaptureStatus {
9
9
  baselineHash: string | null;
10
10
  /** null = no baseline exists yet; false = hash matches baseline; true = hash differs from baseline */
11
11
  changed: boolean | null;
12
+ /**
13
+ * Present only for an observe-mode capture: what the eyes actually saw. Observe never gates or
14
+ * touches baselines — it always emits a screenshot plus this block so a reviewing agent can tell
15
+ * "geometry drew but wrong" (blank:false, coverage>0) from "nothing drew" (blank:true, coverage 0)
16
+ * from "the page crashed" (pageErrorCount>0), instead of dead-ending on "cannot capture".
17
+ */
18
+ observe?: CaptureObserveDiagnostics;
19
+ }
20
+ /** What an observe-mode capture saw: the trustworthiness metadata beside the emitted screenshot. */
21
+ export interface CaptureObserveDiagnostics {
22
+ /** No verified/non-blank frame was produced — the emitted screenshot is a fallback, likely blank/black. */
23
+ blank: boolean;
24
+ /** Render backend: canvas | dom | webgl | webgpu. */
25
+ backend: string;
26
+ /** The functional verify-target kind the page registered, or null when it registered none. */
27
+ verifyTargetKind: string | null;
28
+ /** True when the in-page verifier published a non-blank frame (window.__ftRenderImage). */
29
+ verifyPublished: boolean;
30
+ /** Verifier-reported non-background coverage in 0..1, or null when the page exposed none. */
31
+ coverage: number | null;
32
+ /** Uncaught page exceptions the page threw (a non-zero count means broken code, not a backend limit). */
33
+ pageErrorCount: number;
34
+ /** Console/network error logs (a failed asset, a console.error), excluding page exceptions. */
35
+ errorCount: number;
36
+ /**
37
+ * Extra animation frames the observe warmup rendered past the requested count to coax a first draw out
38
+ * of an app-loop-driven page (see launchBrowser). 0 = drew immediately. A large value that still ended
39
+ * blank means the warmup gave up at its ceiling — the scene never drew, not that it merely started late.
40
+ */
41
+ warmupFrames: number;
12
42
  }
13
43
  export interface CaptureEntryOptions {
14
44
  context: BrowserContext;
@@ -36,6 +66,14 @@ export interface CaptureEntryOptions {
36
66
  * error on every backend.
37
67
  */
38
68
  failOnError?: boolean;
69
+ /**
70
+ * Eyes mode. When true the capture never fails closed: a blank/failed verifier readback that would
71
+ * otherwise throw ("cannot capture") instead emits a best-available screenshot and records a
72
+ * `CaptureObserveDiagnostics` block in status.json. Observe does not gate and does not compare or
73
+ * write baselines — it is for an agent (or human) to SEE a scene, not to pass/fail it. Overrides
74
+ * failOnError/updateBaseline behavior for the run.
75
+ */
76
+ observe?: boolean;
39
77
  /**
40
78
  * Polled before each renderer: when it returns true the run is being interrupted (Ctrl+C), so the
41
79
  * renderer loop stops and a torn-down page is not reported as a failure. See installAbortHandler.
@@ -46,6 +84,12 @@ export interface CaptureEntryOptions {
46
84
  * identifies its entry: `entry.name/renderer` rather than just `renderer`.
47
85
  */
48
86
  displayLabel?: string;
87
+ /**
88
+ * Forces (true) or disables (false) the in-page render-verification wait + surface readback. Defaults
89
+ * to `tool === 'functional'`. An external subject (reference) sets it true once its pages register a
90
+ * functional target, so its WebGL captures read the fingerprinted surface instead of a black canvas.
91
+ */
92
+ verify?: boolean;
49
93
  }
50
94
  export interface ParallelCaptureOptions {
51
95
  context: BrowserContext;
@@ -59,7 +103,9 @@ export interface ParallelCaptureOptions {
59
103
  extraWait?: number;
60
104
  captureFrames?: number;
61
105
  failOnError?: boolean;
106
+ observe?: boolean;
62
107
  isAborted?: () => boolean;
108
+ verify?: boolean;
63
109
  /** Number of Playwright pages to run concurrently. Default: 6. */
64
110
  workerCount?: number;
65
111
  }
@@ -77,7 +123,25 @@ export interface CaptureOutputPaths {
77
123
  finalLogs: string;
78
124
  statusPath: string;
79
125
  }
126
+ export declare function buildCaptureObserveDiagnostics(args: {
127
+ backend: string;
128
+ blank: boolean;
129
+ coverage: number | null;
130
+ logs: readonly unknown[];
131
+ verifyPublished: boolean;
132
+ verifyTargetKind: string | null;
133
+ warmupFrames: number;
134
+ }): CaptureObserveDiagnostics;
80
135
  export declare function captureEntry(opts: CaptureEntryOptions): Promise<'ok' | 'changed' | 'error'>;
81
136
  export declare function captureParallel(opts: ParallelCaptureOptions): Promise<ParallelCaptureResult>;
137
+ export declare function captureUrl(url: string, options: Readonly<CaptureUrlOptions>): Promise<CaptureObserveDiagnostics>;
138
+ export interface CaptureUrlOptions {
139
+ /** Directory to write screenshot.png / logs.jsonl / status.json into (flat, one page). */
140
+ outDir: string;
141
+ /** Extra settle time after the frame halt, in ms. */
142
+ wait?: number;
143
+ /** Frame-halt minimum (see launchBrowser); 1 is the robust default. */
144
+ captureFrames?: number;
145
+ }
82
146
  export declare function getCaptureOutputPaths(outBase: string, tool: Tool, name: string, renderer: string): CaptureOutputPaths;
83
147
  //# sourceMappingURL=captureEntry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"captureEntry.d.ts","sourceRoot":"","sources":["../src/captureEntry.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAQ,MAAM,kBAAkB,CAAC;AAI7D,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAMvD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,sGAAsG;IACtG,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,8FAA8F;IAC9F,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,KAAK,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wGAAwG;AACxG,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAQD,wBAAsB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,CA+PjG;AA2CD,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA8ClG;AAKD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAUrH"}
1
+ {"version":3,"file":"captureEntry.d.ts","sourceRoot":"","sources":["../src/captureEntry.ts"],"names":[],"mappings":"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"}