@triscope/mcp 0.4.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.
- package/LICENSE +21 -0
- package/README.md +31 -0
- package/bin/triscope-mcp-supervised.mjs +114 -0
- package/bin/triscope-mcp.mjs +11 -0
- package/dist/browser.mjs +348 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/logger.mjs +51 -0
- package/dist/logger.mjs.map +1 -0
- package/dist/refs.mjs +396 -0
- package/dist/refs.mjs.map +1 -0
- package/dist/server.mjs +3125 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +49 -0
- package/src/browser.ts +461 -0
- package/src/logger.ts +94 -0
- package/src/optimize.ts +142 -0
- package/src/refs.ts +468 -0
- package/src/server.ts +2678 -0
- package/src/targets.ts +163 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.ts","../src/browser.ts","../src/logger.ts","../src/optimize.ts","../src/refs.ts","../src/targets.ts"],"sourcesContent":["// Triscope MCP server.\n//\n// Exposes tools that talk to a running triscope dev server (default\n// http://localhost:5173) and the on-disk telemetry sink it writes:\n// - list_elements : GET /__manifest\n// - read_telemetry : read /tmp/<project>-state.json, optional jq-style path\n// - set_knob : POST /__knob (harness polls and applies live)\n// - capture_views : drives a fresh headed Chromium via CDP, calls\n// window.__TRISCOPE__.captureViews(), writes per-camera\n// PNGs to /tmp/<project>-capture-<element>/<camera>.png\n// - run_smoke : spawns `triscope smoke <element>` and returns pass/fail\n//\n// Configuration env vars:\n// TRISCOPE_URL (default http://localhost:5173)\n// TRISCOPE_PROJECT (default: derived from process.cwd()/package.json#name)\n// TRISCOPE_DEBUG_PORT (default 9230)\n// CHROME_BIN (default 'chromium')\n\nimport { spawn } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { PNG } from 'pngjs';\nimport { z } from 'zod';\nimport { createBrowserPool } from './browser.js';\nimport { createLogger } from './logger.js';\nimport { coordinateDescent, knobMatches } from './optimize.js';\nimport {\n composeFilmstrip,\n diffReference,\n diffReferenceMotion,\n motionMagnitudeFromFrames,\n refsMotionPaths,\n refsPath,\n setReference,\n setReferenceMotion,\n} from './refs.js';\nimport { evaluateTargets } from './targets.js';\n\nconst wait = (ms) => new Promise((r) => setTimeout(r, ms));\n\nexport function readProjectName(cwd) {\n if (process.env.TRISCOPE_PROJECT) return process.env.TRISCOPE_PROJECT;\n try {\n const p = join(cwd, 'package.json');\n if (!existsSync(p)) return 'triscope-project';\n const pkg = JSON.parse(readFileSync(p, 'utf8'));\n return String(pkg.name ?? 'triscope-project').replace(/[^A-Za-z0-9._-]/g, '-');\n } catch {\n return 'triscope-project';\n }\n}\n\nconst DEV_URL = (process.env.TRISCOPE_URL ?? 'http://localhost:5173').replace(/\\/$/, '');\nconst PROJECT = readProjectName(process.cwd());\nconst STATE_PATH = join(tmpdir(), `${PROJECT}-state.json`);\n// Inline image payload safety cap. MCP stdio JSON-RPC has practical message\n// size limits and ours exceeded them at 12 cameras × 1280×720 PNG base64 →\n// the server process got OOM-killed mid-response. Override with\n// TRISCOPE_INLINE_PAYLOAD_BUDGET (bytes) if you really need bigger.\nconst INLINE_PAYLOAD_BUDGET = Number(process.env.TRISCOPE_INLINE_PAYLOAD_BUDGET ?? 1024 * 1024);\n\n// ---- Resilience: ring buffer of recent errors + process-level handlers --\n// A single rogue async exception used to crash the entire MCP server (the\n// process died, Claude Code didn't auto-restart it, and subsequent calls\n// timed out with cryptic \"Connection closed\"). Now we log and continue so\n// individual tool failures stay isolated from the server lifecycle.\nconst SERVER_START_TIME = Date.now();\nconst RECENT_ERRORS_CAP = 16;\nconst recentErrors: string[] = [];\nconst logger = createLogger(PROJECT);\nconst browserPool = createBrowserPool({ logger });\nconst shutdown = () => browserPool.dispose();\nprocess.on('exit', shutdown);\nprocess.on('SIGINT', () => {\n shutdown();\n process.exit(130);\n});\nprocess.on('SIGTERM', () => {\n shutdown();\n process.exit(143);\n});\nexport function recordError(source: string, err: unknown) {\n const detail = (err as any)?.stack ?? (err as any)?.message ?? String(err);\n const msg = `[${new Date().toISOString()}] ${source}: ${detail}`;\n logger.error(source, String((err as any)?.message ?? err), { stack: (err as any)?.stack });\n recentErrors.push(msg);\n if (recentErrors.length > RECENT_ERRORS_CAP) recentErrors.shift();\n}\nprocess.on('uncaughtException', (err) => recordError('uncaughtException', err));\nprocess.on('unhandledRejection', (err) => recordError('unhandledRejection', err));\n\nexport function applyPath(data, path) {\n if (!path) return data;\n const segs = path.replace(/^\\./, '').split('.').filter(Boolean);\n let cur = data;\n for (const s of segs) {\n if (cur == null) return undefined;\n cur = cur[s];\n }\n return cur;\n}\n\nasync function fetchManifest(devUrl: string = DEV_URL): Promise<any> {\n try {\n const r = await fetch(`${devUrl}/__manifest`);\n if (!r.ok) return null;\n const m = await r.json();\n // Shape: { elements: { [name]: { element, labUrl, cameras, knobs } } }\n return m && typeof m === 'object' ? m : null;\n } catch {\n return null;\n }\n}\n\n// Short-TTL manifest cache so a batch of set_knob calls (e.g. auto_tune's\n// inner loop) doesn't fire one GET /__manifest per knob just to look up specs.\n// Keyed by devUrl so cross-project calls don't read each other's manifest.\nconst _manifestCache = new Map<string, { value: any; at: number }>();\nasync function fetchManifestCached(devUrl: string = DEV_URL, ttlMs = 1000): Promise<any> {\n const now = Date.now();\n const hit = _manifestCache.get(devUrl);\n if (hit && now - hit.at < ttlMs) return hit.value;\n const value = await fetchManifest(devUrl);\n _manifestCache.set(devUrl, { value, at: now });\n return value;\n}\n\n/**\n * Resolve the dev-server origin for a per-call request. Precedence: explicit\n * `devUrl` → the origin of `labUrl` → the boot DEV_URL. Lets the\n * dev-server-bound tools (read_telemetry/set_knob/list_elements/get_scene/\n * auto_tune/multi_tune) target a lab/project other than the one the MCP booted\n * against, mirroring the per-call `labUrl` the browser tools already accept.\n */\nexport function resolveDevUrl({ devUrl, labUrl }: { devUrl?: string; labUrl?: string }): string {\n if (devUrl) return devUrl.replace(/\\/$/, '');\n if (labUrl) {\n try {\n return new URL(labUrl).origin;\n } catch {\n /* not an absolute URL — fall through to default */\n }\n }\n return DEV_URL;\n}\n\n/**\n * Fetch the LAST telemetry the harness posted, live over HTTP from the dev\n * server (GET /__state), regardless of which /tmp file it was written to. The\n * harness stamps `postedAt` so the caller can tell how stale the snapshot is\n * (the lab tab may be backgrounded/closed). Returns null on any failure.\n */\nasync function fetchState(devUrl: string): Promise<{ data: any; staleMs: number | null } | null> {\n try {\n const r = await fetch(`${devUrl}/__state`, { signal: AbortSignal.timeout(2000) });\n if (!r.ok) return null;\n const data = (await r.json()) as any;\n // GET /__state returns the literal `{}` (HTTP 200) when no lab tab has posted\n // yet (telemetry.ts). Treat an empty object as \"no telemetry\" → null, so the\n // caller falls through to the disk read / the actionable \"open a lab page\"\n // error instead of silently returning undefined for every path.\n if (!data || typeof data !== 'object' || Object.keys(data).length === 0) return null;\n const staleMs = typeof data.postedAt === 'number' ? Date.now() - data.postedAt : null;\n return { data, staleMs };\n } catch {\n return null;\n }\n}\n\nconst STALE_MS = Number(process.env.TRISCOPE_STALE_MS ?? 1500);\n\n/**\n * Server-local mirror of @triscope/core's `clampKnob` (kept here to preserve\n * the node-only MCP / browser-only core boundary — the same reason\n * probeStatsFromPng mirrors the harness's sampleGpuProbes rather than importing\n * it). The harness clamp is authoritative; clamping here too means out-of-range\n * values are corrected *before* they persist in /__knob and the agent gets\n * immediate `{requested, final}` feedback instead of having to read telemetry.\n */\nexport function clampKnobValue(\n spec: any,\n value: number | string | boolean,\n): { clamped: boolean; final: number | string | boolean } {\n if (!spec || typeof spec !== 'object') return { clamped: false, final: value };\n switch (spec.type) {\n case 'number': {\n const n = Number(value);\n if (!Number.isFinite(n)) return { clamped: true, final: spec.default };\n let next = n;\n if (typeof spec.step === 'number' && spec.step > 0) {\n next = spec.min + Math.round((next - spec.min) / spec.step) * spec.step;\n }\n next = Math.min(spec.max, Math.max(spec.min, next));\n return { clamped: Math.abs(next - n) >= 1e-9, final: next };\n }\n case 'int': {\n const n = Number(value);\n if (!Number.isFinite(n)) return { clamped: true, final: spec.default };\n const next = Math.min(spec.max, Math.max(spec.min, Math.round(n)));\n return { clamped: next !== n, final: next };\n }\n case 'color':\n return /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(String(value))\n ? { clamped: false, final: value }\n : { clamped: true, final: spec.default };\n case 'boolean':\n return { clamped: typeof value !== 'boolean', final: Boolean(value) };\n default:\n return { clamped: false, final: value }; // trigger / unknown → passthrough\n }\n}\n\n/** Build {element: {knobKey: spec}} from the live manifest's knob arrays. */\nexport function knobSpecMapFromManifest(manifest: any): Record<string, Record<string, any>> {\n const out: Record<string, Record<string, any>> = {};\n for (const [el, entry] of Object.entries((manifest?.elements ?? {}) as Record<string, any>)) {\n const byKey: Record<string, any> = {};\n for (const k of entry?.knobs ?? []) {\n if (!k?.name) continue;\n // Index by the advertised name (the display key `element.knob` in a\n // namespaced scene) AND by the element-local key, so set_knob's clamp\n // feedback resolves whether the caller passes `cube.spin` or `spin`.\n byKey[k.name] = k;\n const local = el && k.name.startsWith(`${el}.`) ? k.name.slice(el.length + 1) : k.name;\n if (!(local in byKey)) byKey[local] = k;\n }\n out[el] = byKey;\n }\n return out;\n}\n\nexport function readProjectLabMap(cwd) {\n try {\n const p = join(cwd, 'package.json');\n if (!existsSync(p)) return {};\n const pkg = JSON.parse(readFileSync(p, 'utf8'));\n const m = pkg?.triscope?.labs;\n return m && typeof m === 'object' ? m : {};\n } catch {\n return {};\n }\n}\n\nconst PROJECT_LABS = readProjectLabMap(process.cwd());\n\nexport function absolutize(maybePath, base: string = DEV_URL) {\n if (!maybePath) return null;\n if (/^https?:\\/\\//.test(maybePath)) return maybePath;\n return `${base}${maybePath.startsWith('/') ? '' : '/'}${maybePath}`;\n}\n\nasync function resolveLabUrl({\n element,\n labUrl,\n devUrl,\n}: {\n element?: string;\n labUrl?: string;\n devUrl?: string;\n}): Promise<string> {\n // 1. Explicit arg wins.\n if (labUrl) return absolutize(labUrl);\n const base = resolveDevUrl({ devUrl });\n if (!element) return base;\n // 2. Live manifest from a running lab (on the target dev server).\n const manifest = await fetchManifest(base);\n const entry = manifest?.elements?.[element];\n if (entry?.labUrl) return absolutize(entry.labUrl, base);\n // 3. Per-project escape hatch in package.json#triscope.labs.\n if (PROJECT_LABS[element]) return absolutize(PROJECT_LABS[element], base);\n // 4. Convention fallback.\n return `${base}/labs/${element}.html`;\n}\n\nasync function listElements({ devUrl, labUrl }: { devUrl?: string; labUrl?: string } = {}) {\n const m = await fetchManifest(resolveDevUrl({ devUrl, labUrl }));\n if (!m || !m.elements || Object.keys(m.elements).length === 0) {\n return {\n manifest: null,\n note: 'Dev server is up but no manifest has been posted yet. Load a lab page first.',\n };\n }\n return { manifest: m };\n}\n\nasync function readTelemetry(\n path?: string,\n { devUrl, labUrl }: { devUrl?: string; labUrl?: string } = {},\n) {\n const url = resolveDevUrl({ devUrl, labUrl });\n // Live-first: GET ${url}/__state fetches the dev server's OWN state file over\n // HTTP — works for any project/port without the MCP knowing the /tmp path\n // (the original \"No telemetry at /tmp/...-state.json\" cross-project failure).\n // Fall back to the local file only for the default dev server (a non-default\n // project's state-file path is unknown to this process).\n let data: any = null;\n let source: 'live' | 'disk' | null = null;\n let staleMs: number | null = null;\n const live = await fetchState(url);\n if (live) {\n data = live.data;\n source = 'live';\n staleMs = live.staleMs;\n } else if (url === DEV_URL && existsSync(STATE_PATH)) {\n data = safeReadState();\n source = 'disk';\n staleMs = typeof data?.postedAt === 'number' ? Date.now() - data.postedAt : null;\n }\n if (data == null) {\n throw new Error(\n `No telemetry from ${url}/__state (and no local file). Is the dev server running with a lab page open?`,\n );\n }\n const sliced = applyPath(data, path);\n // Back-compat: a `path` query returns the BARE sliced value (what every\n // existing consumer + the E2E expect). For the FULL snapshot (no path) we\n // annotate freshness via non-colliding `__source`/`__staleMs` keys so a stale\n // tab (backgrounded/closed) is detectable without changing the value shape.\n if (path == null && sliced && typeof sliced === 'object' && !Array.isArray(sliced)) {\n return {\n ...sliced,\n __source: source,\n ...(staleMs != null ? { __staleMs: staleMs } : {}),\n ...(staleMs != null && staleMs > STALE_MS\n ? { __warning: `telemetry is ${staleMs}ms old — the lab tab may be backgrounded or closed` }\n : {}),\n };\n }\n return sliced;\n}\n\nasync function setKnob(payload) {\n // `payload` is either a single {element,key,value} or {updates:[...]}.\n // The /__knob endpoint accepts arrays natively (telemetry.ts line 94).\n const batched = Array.isArray(payload?.updates);\n const updates: Array<{ element: string; key: string; value: unknown }> = batched\n ? payload.updates\n : [payload];\n const url = resolveDevUrl({ devUrl: payload?.devUrl, labUrl: payload?.labUrl });\n\n // Best-effort clamp against the live manifest's knob specs so out-of-range\n // values are corrected before they persist + the agent learns what applied.\n const specs = knobSpecMapFromManifest(await fetchManifestCached(url));\n const clampedReports: Array<{\n element: string;\n key: string;\n requested: unknown;\n final: unknown;\n }> = [];\n const outgoing = updates.map((u) => {\n const spec = specs[u.element]?.[u.key];\n if (!spec) return u;\n const c = clampKnobValue(spec, u.value as number | string | boolean);\n if (c.clamped) {\n clampedReports.push({ element: u.element, key: u.key, requested: u.value, final: c.final });\n }\n return { ...u, value: c.final };\n });\n\n const body = JSON.stringify(batched ? outgoing : outgoing[0]);\n const r = await fetch(`${url}/__knob`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body,\n });\n if (!r.ok) throw new Error(`__knob returned ${r.status}`);\n return {\n ok: true,\n count: outgoing.length,\n ...(clampedReports.length ? { clamped: clampedReports } : {}),\n };\n}\n\n/**\n * Trim + annotate the telemetry snapshot embedded in a capture response:\n * - flag that `perf.fps` is sampled right after the navigate, so it can read\n * low while WebGPU warms (use read_telemetry for steady-state) — otherwise\n * the capture's fps looks catastrophic vs reality;\n * - drop the per-probe `samples` arrays (the payload bulk — a busy scene's full\n * motion history burns context for nothing; keep the stats + a count).\n * Never throws — a capture must not fail over telemetry cosmetics.\n */\nfunction trimCaptureTelemetry(sample: any): any {\n if (!sample || typeof sample !== 'object') return sample;\n try {\n if (sample.perf && typeof sample.perf === 'object') {\n sample.perf = {\n ...sample.perf,\n note: 'capture-time fps — reads low right after a navigate while WebGPU warms; use read_telemetry for steady-state',\n };\n }\n for (const el of Object.values(sample.elements ?? {}) as any[]) {\n for (const probe of Object.values(el?.motion ?? {}) as any[]) {\n if (probe && Array.isArray(probe.samples)) {\n probe.sampleCount = probe.samples.length;\n delete probe.samples;\n }\n }\n }\n } catch {\n /* leave the snapshot as-is */\n }\n return sample;\n}\n\nasync function captureViews({\n element,\n labUrl,\n inline = true,\n fresh = false,\n}: {\n element?: string;\n labUrl?: string;\n inline?: boolean;\n fresh?: boolean;\n}) {\n // Persistent Chromium: first call cold-starts (~3s), subsequent calls\n // reuse the same browser/page and just navigate if the URL changed.\n const target = await resolveLabUrl({ element, labUrl });\n const outDir = join(tmpdir(), `${PROJECT}-capture-${element ?? 'scene'}`);\n mkdirSync(outDir, { recursive: true });\n\n const t0 = Date.now();\n const timings: Record<string, number> = {};\n const tNavStart = Date.now();\n const { call } = await browserPool.getPage(target, { reload: fresh });\n timings.navigate = Date.now() - tNavStart;\n const tRenderStart = Date.now();\n const result = await call('Runtime.evaluate', {\n expression: 'window.__TRISCOPE__.captureViews()',\n awaitPromise: true,\n returnByValue: true,\n });\n timings.render = Date.now() - tRenderStart;\n const views = result.result.result.value;\n if (!views || typeof views !== 'object') {\n // By the time we get here browserPool.getPage has already proven the\n // harness mounted, so an empty result means the Element declared zero\n // cameras OR captureViews itself errored without returning.\n throw new Error(\n `captureViews returned no images for element=\"${element ?? '(scene)'}\" at ${target}. ` +\n `Most likely the Element declares no cameras — check the manifest: ` +\n `mcp__triscope__list_elements.`,\n );\n }\n const written = {};\n const base64ByCam = {};\n const tWriteStart = Date.now();\n for (const [cam, dataUrl] of Object.entries(views)) {\n if (typeof dataUrl !== 'string') continue;\n const b64 = dataUrl.replace(/^data:image\\/png;base64,/, '');\n const path = join(outDir, `${cam}.png`);\n writeFileSync(path, Buffer.from(b64, 'base64'));\n written[cam] = path;\n base64ByCam[cam] = b64;\n }\n timings.writePngs = Date.now() - tWriteStart;\n const tTelStart = Date.now();\n const telemetry = await call('Runtime.evaluate', {\n expression: 'JSON.stringify(window.__TRISCOPE__.sampleTelemetry())',\n returnByValue: true,\n });\n const sample = trimCaptureTelemetry(JSON.parse(telemetry.result.result.value));\n timings.telemetry = Date.now() - tTelStart;\n\n // captureViews() populates window.__TRISCOPE__.lastGpuProbes as a side\n // effect (per-camera luminance/p5/p95/dynamicRange). Surface it in the\n // tool response so consumers don't have to do a second CDP eval.\n // If the harness didn't populate it (lab page that doesn't use\n // @triscope/core runLab — e.g. water3d's scene lab which has a custom\n // capture path), we decode the captured PNGs server-side with pngjs\n // and compute the same scalars. Slower (~5 ms per camera) but means\n // GPU probes are available for any captured PNG.\n const tProbeStart = Date.now();\n let gpuProbes: Record<string, any> | null = null;\n let gpuProbesSource: 'harness' | 'server-fallback' | 'unavailable' = 'unavailable';\n try {\n const probesResp = await call('Runtime.evaluate', {\n expression: 'JSON.stringify(window.__TRISCOPE__.lastGpuProbes ?? null)',\n returnByValue: true,\n });\n const fromHarness = JSON.parse(probesResp.result.result.value);\n if (fromHarness && Object.keys(fromHarness).length > 0) {\n gpuProbes = fromHarness;\n gpuProbesSource = 'harness';\n }\n } catch {\n /* old core — fall through to server-side */\n }\n if (!gpuProbes) {\n gpuProbes = {};\n for (const [cam, b64] of Object.entries(base64ByCam) as [string, string][]) {\n try {\n gpuProbes[cam] = probeStatsFromPng(Buffer.from(b64, 'base64'));\n } catch {\n /* skip cameras whose PNGs fail to decode */\n }\n }\n if (Object.keys(gpuProbes).length === 0) gpuProbes = null;\n else gpuProbesSource = 'server-fallback';\n }\n timings.probes = Date.now() - tProbeStart;\n\n // Cameras the GPU drew black (luminance < threshold) — set by the harness\n // probe or the server-side fallback. Surfaced top-level so the agent sees a\n // dead pane immediately instead of inspecting per-camera gpuProbes.\n const blackFrames = gpuProbes\n ? Object.entries(gpuProbes)\n .filter(([, s]) => (s as any)?.blackFrame)\n .map(([cam]) => cam)\n : [];\n // Cameras that rendered a (near-)UNIFORM frame — dynamicRange ≈ 1 means p95≈p5,\n // i.e. nothing but the flat clear-color is in view (the element drifted out of\n // frame / wasn't drawn). blackFrames misses this when the clear-color sits\n // above the black threshold (the \"empty but not black\" case), so it reads as a\n // false OK. Excludes genuinely black panes (already in blackFrames).\n const flatFrames = gpuProbes\n ? Object.entries(gpuProbes)\n .filter(([, s]) => {\n const p = s as any;\n return p && !p.blackFrame && typeof p.dynamicRange === 'number' && p.dynamicRange <= 1.05;\n })\n .map(([cam]) => cam)\n : [];\n\n return {\n element: element ?? null,\n dir: outDir,\n files: written,\n cameraOrder: Object.keys(written),\n telemetry: sample,\n gpuProbes,\n gpuProbesSource,\n blackFrames,\n flatFrames,\n inline,\n captureMs: Date.now() - t0,\n timings,\n _base64ByCam: base64ByCam,\n };\n}\n\n/** Server-side fallback: same math the harness does, but starting from a\n * decoded PNG buffer instead of a 2D canvas. Stride-samples to ~2300 px\n * so the cost is bounded (~5 ms per 1280×720 PNG). */\n// Mean Rec.709 luminance below which a pane counts as a black render. Matches\n// @triscope/core's BLACK_FRAME_LUMINANCE (mirrored across the node boundary).\nconst BLACK_FRAME_LUMINANCE = 0.004;\n\nexport function probeStatsFromPng(pngBuf: Buffer): {\n luminance: number;\n p5: number;\n p95: number;\n dynamicRange: number;\n samples: number;\n blackFrame?: boolean;\n} {\n const img = PNG.sync.read(pngBuf);\n const stride = Math.max(1, Math.floor(Math.sqrt((img.width * img.height) / 2304)));\n const lums: number[] = [];\n let sum = 0;\n for (let y = 0; y < img.height; y += stride) {\n for (let x = 0; x < img.width; x += stride) {\n const i = (y * img.width + x) * 4;\n const r = img.data[i] / 255;\n const g = img.data[i + 1] / 255;\n const b = img.data[i + 2] / 255;\n const lum = 0.2126 * r + 0.7152 * g + 0.0722 * b;\n lums.push(lum);\n sum += lum;\n }\n }\n lums.sort((a, b) => a - b);\n const n = lums.length;\n const p5 = lums[Math.floor(n * 0.05)];\n const p95 = lums[Math.floor(n * 0.95)];\n const luminance = +(sum / n).toFixed(4);\n return {\n luminance,\n p5: +p5.toFixed(4),\n p95: +p95.toFixed(4),\n dynamicRange: +(p95 / Math.max(p5, 1 / 255)).toFixed(2),\n samples: n,\n ...(luminance < BLACK_FRAME_LUMINANCE ? { blackFrame: true } : {}),\n };\n}\n\nasync function captureMotionFramesRaw({\n element,\n camera,\n frames,\n dt,\n mode,\n labUrl,\n}: any): Promise<string[]> {\n // Like captureMotion but for ONE camera, returns the raw base64 PNG frames.\n // Used internally by set_reference_motion + diff_reference_motion.\n const target = await resolveLabUrl({ element, labUrl });\n const { call } = await browserPool.getPage(target);\n const result = await call('Runtime.evaluate', {\n expression: `window.__TRISCOPE__.captureMotionFrames(${JSON.stringify(camera)}, ${JSON.stringify({ frames, dt, mode })})`,\n awaitPromise: true,\n returnByValue: true,\n });\n const frames_ = result.result.result.value;\n if (!Array.isArray(frames_) || frames_.length === 0) {\n throw new Error(`captureMotionFrames returned empty for camera \"${camera}\"`);\n }\n return frames_.map((du) => du.replace(/^data:image\\/png;base64,/, ''));\n}\n\nasync function captureMotion({\n element,\n camera,\n frames = 6,\n dt = 0.25,\n mode = 'time',\n labUrl,\n fresh = false,\n}: any) {\n // Multi-frame capture per camera through the persistent browser pool.\n // Returns per-camera filmstrip base64 + motionMagnitude scalar + telemetry.\n const target = await resolveLabUrl({ element, labUrl });\n const outDir = join(tmpdir(), `${PROJECT}-motion-${element ?? 'scene'}`);\n mkdirSync(outDir, { recursive: true });\n const t0 = Date.now();\n const { call } = await browserPool.getPage(target, { reload: fresh });\n\n // Pick the camera set: explicit single name or all cameras for the element.\n let cameraOrder: string[];\n if (camera) {\n cameraOrder = [camera];\n } else {\n const camsProbe = await call('Runtime.evaluate', {\n expression: 'Object.keys(window.__TRISCOPE__.cameras)',\n returnByValue: true,\n });\n cameraOrder = camsProbe.result.result.value ?? [];\n }\n if (!Array.isArray(cameraOrder) || cameraOrder.length === 0) {\n throw new Error('no cameras available — is the harness mounted?');\n }\n\n const filmstripPaths = {};\n const filmstripBase64 = {};\n const magnitudeByCam = {};\n for (const camName of cameraOrder) {\n const result = await call('Runtime.evaluate', {\n expression: `window.__TRISCOPE__.captureMotionFrames(${JSON.stringify(camName)}, ${JSON.stringify({ frames, dt, mode })})`,\n awaitPromise: true,\n returnByValue: true,\n });\n const dataUrls = result.result.result.value;\n if (!Array.isArray(dataUrls) || dataUrls.length === 0) {\n throw new Error(`captureMotionFrames returned empty for camera \"${camName}\"`);\n }\n const strip = composeFilmstrip(dataUrls);\n const stripPath = join(outDir, `${camName}.filmstrip.png`);\n writeFileSync(stripPath, strip);\n filmstripPaths[camName] = stripPath;\n filmstripBase64[camName] = strip.toString('base64');\n magnitudeByCam[camName] = motionMagnitudeFromFrames(dataUrls);\n }\n\n const telemetry = await call('Runtime.evaluate', {\n expression: 'JSON.stringify(window.__TRISCOPE__.sampleTelemetry())',\n returnByValue: true,\n });\n const sample = trimCaptureTelemetry(JSON.parse(telemetry.result.result.value));\n\n return {\n element: element ?? null,\n frames,\n dt,\n mode,\n dir: outDir,\n filmstrips: filmstripPaths,\n cameraOrder,\n motionMagnitude: magnitudeByCam,\n captureMs: Date.now() - t0,\n telemetry: sample,\n _filmstripBase64: filmstripBase64,\n };\n}\n\n/**\n * auto_tune (1D): golden-section search over one knob, minimising\n * (1 - SSIM) between the captured target_camera view and the stored\n * reference for that (element, camera). Each iteration: set_knob → wait\n * for the harness to apply (knobPollMs + telemetry tick + margin) →\n * captureViews → diff_reference. Returns the best knob value found,\n * the final SSIM, the iteration history, and total ms.\n *\n * Why golden-section: derivative-free, deterministic, converges\n * exponentially (range × 1/φ per iter ≈ 0.618). 12 iterations narrow a\n * range to ~0.7% — plenty for shader tuning. Robust to noise because we\n * use SSIM (perceptual) rather than meanAbsDiff (pixel-level).\n */\n/**\n * Snapshot / restore via git tags.\n *\n * A snapshot freezes a moment in the iteration loop: the git commit you\n * were on + the knob values applied at that moment. Restoring checks out\n * that commit and re-posts the knobs, so a careful tuning state can be\n * recovered after a risky shader rewrite. Tags live under\n * `triscope/snapshot/<name>` so they don't pollute the user's namespace.\n *\n * Guard rails:\n * - snapshot refuses on a dirty working tree — the commit you'd point\n * at wouldn't actually contain your in-progress edits, so the\n * restore would silently revert them.\n * - restore refuses on a dirty WT too, for the same reason in reverse.\n * - PNG refs are intentionally not bundled into the snapshot for the\n * MVP — they live next to the project as before (refs/<el>/<cam>.png)\n * and are recovered with the git checkout. Keeping the JSON small.\n */\nconst SNAPSHOT_TAG_PREFIX = 'triscope/snapshot/';\n\n// Windows portability: npm/git/code are .cmd scripts on Win32. child_process\n// .spawn refuses to invoke them without `shell: true`. On Linux/macOS the\n// real binaries are on PATH and shell isn't needed. We set the flag\n// conditionally everywhere we spawn one of those tools.\nconst NEED_SHELL = process.platform === 'win32';\n\n// For tools that forward an agent-supplied argument to the `triscope` CLI we\n// spawn the binary WITHOUT a shell (explicit .cmd on Windows) so there's no\n// shell to inject into, and we reject any argument that would smuggle a flag.\nconst TRISCOPE_BIN = process.platform === 'win32' ? 'triscope.cmd' : 'triscope';\nfunction rejectFlagArg(value: unknown, label: string): asserts value is string {\n if (typeof value !== 'string' || value.length === 0 || value.startsWith('-')) {\n throw new Error(\n `unsafe ${label}: ${JSON.stringify(value)} (must be a non-empty value not starting with '-')`,\n );\n }\n}\n\nfunction git(\n args: string[],\n cwd: string = process.cwd(),\n): Promise<{ code: number; stdout: string; stderr: string }> {\n return new Promise((resolve, reject) => {\n const child = spawn('git', args, { cwd, stdio: ['ignore', 'pipe', 'pipe'], shell: NEED_SHELL });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (d) => (stdout += d));\n child.stderr.on('data', (d) => (stderr += d));\n child.on('error', reject);\n child.on('exit', (code) =>\n resolve({ code: code ?? 1, stdout: stdout.trim(), stderr: stderr.trim() }),\n );\n });\n}\n\nasync function assertCleanWt(cwd: string, action: string): Promise<void> {\n const status = await git(['status', '--porcelain'], cwd);\n if (status.stdout.length > 0) {\n throw new Error(\n `${action} refuses to run with a dirty working tree. Commit, stash, or revert your in-progress edits first.\\nDirty paths:\\n${status.stdout.split('\\n').slice(0, 10).join('\\n')}`,\n );\n }\n}\n\n/**\n * Wait until the harness telemetry confirms a knob took the requested value,\n * polling the on-disk state every 50 ms. Replaces fixed sleeps in the tuning\n * loops: a knob usually lands in ~100-600 ms (knob poll + telemetry tick), so\n * this returns as soon as it's applied instead of always sleeping the worst\n * case. Returns false on timeout (caller does a short settle fallback).\n */\nasync function waitForKnobApplied(\n key: string,\n value: number | string | boolean,\n timeoutMs = 2500,\n element?: string,\n devUrl?: string,\n): Promise<boolean> {\n // Telemetry exposes knobs by DISPLAY key. In a namespaced scene the caller may\n // pass the element-local key (`spin`) while telemetry holds `cube.spin`, so\n // also probe the namespaced form — otherwise this never confirms and the\n // tuning loop burns the full timeout every iteration.\n const ns = element ? `${element}.${key}` : null;\n // For the default dev server poll the local file (fast); for a non-default\n // devUrl the file path is unknown here, so poll its /__state over HTTP — else\n // cross-project tuning never confirms and burns the full timeout each round.\n const url = resolveDevUrl({ devUrl });\n const useHttp = url !== DEV_URL;\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n let st: any = null;\n if (useHttp) {\n st = (await fetchState(url))?.data ?? null;\n } else if (existsSync(STATE_PATH)) {\n st = JSON.parse(readFileSync(STATE_PATH, 'utf8'));\n }\n const applied = st?.knobs?.[key] ?? (ns ? st?.knobs?.[ns] : undefined);\n if (applied !== undefined && knobMatches(value, applied)) return true;\n } catch {\n /* state file mid-write / transient fetch — retry */\n }\n await wait(50);\n }\n return false;\n}\n\nasync function fetchPersistedKnobs(): Promise<Record<string, Record<string, unknown>>> {\n try {\n const r = await fetch(`${DEV_URL}/__knob/current`);\n if (!r.ok) return {};\n return (await r.json()) as Record<string, Record<string, unknown>>;\n } catch {\n return {};\n }\n}\n\nasync function snapshot({ name, message }: { name: string; message?: string }) {\n if (!/^[A-Za-z0-9._-]+$/.test(name)) {\n throw new Error(`snapshot name must be [A-Za-z0-9._-]+ (got \"${name}\")`);\n }\n const cwd = process.cwd();\n await assertCleanWt(cwd, 'snapshot');\n const head = await git(['rev-parse', 'HEAD'], cwd);\n if (head.code !== 0) throw new Error(`git rev-parse failed: ${head.stderr}`);\n const knobs = await fetchPersistedKnobs();\n const payload = {\n name,\n createdAt: new Date().toISOString(),\n commit: head.stdout,\n message: message ?? '',\n knobs, // { [element]: { [knobKey]: value, ... } }\n };\n const tagName = `${SNAPSHOT_TAG_PREFIX}${name}`;\n // Annotated tag stores the JSON payload as the tag message — no extra\n // working-tree files, no rebase noise, easy to list+read with `git tag`.\n const tagBody = `triscope snapshot v1\\n\\n${JSON.stringify(payload, null, 2)}`;\n const tag = await git(['tag', '-a', tagName, '-m', tagBody, payload.commit], cwd);\n if (tag.code !== 0) {\n if (tag.stderr.includes('already exists')) {\n throw new Error(\n `snapshot \"${name}\" already exists. Pick a different name or delete the existing tag: git tag -d ${tagName}`,\n );\n }\n throw new Error(`git tag failed: ${tag.stderr}`);\n }\n return {\n ok: true,\n tag: tagName,\n ...payload,\n hint: 'Restore later with mcp__triscope__restore name=' + name,\n };\n}\n\nasync function listSnapshots() {\n const cwd = process.cwd();\n const list = await git(\n [\n 'tag',\n '--list',\n `${SNAPSHOT_TAG_PREFIX}*`,\n '--format=%(refname:short)|%(creatordate:iso)|%(subject)',\n ],\n cwd,\n );\n if (list.code !== 0) throw new Error(`git tag --list failed: ${list.stderr}`);\n const snapshots: Array<{ name: string; tag: string; created: string; subject: string }> = [];\n for (const line of list.stdout.split('\\n').filter(Boolean)) {\n const [tag, created, ...subj] = line.split('|');\n snapshots.push({\n name: tag.replace(SNAPSHOT_TAG_PREFIX, ''),\n tag,\n created,\n subject: subj.join('|'),\n });\n }\n return { count: snapshots.length, snapshots };\n}\n\nasync function restore({ name }: { name: string }) {\n if (!/^[A-Za-z0-9._-]+$/.test(name)) throw new Error(`invalid snapshot name`);\n const cwd = process.cwd();\n await assertCleanWt(cwd, 'restore');\n const tagName = `${SNAPSHOT_TAG_PREFIX}${name}`;\n const show = await git(['cat-file', '-p', tagName], cwd);\n if (show.code !== 0) throw new Error(`snapshot \"${name}\" not found (tag ${tagName})`);\n // Annotated tag object body: header lines, blank line, then the message\n // we wrote in snapshot(). Find the JSON block.\n const bodyMatch = show.stdout.match(/\\n\\n([\\s\\S]*)/);\n const body = bodyMatch?.[1] ?? '';\n const jsonStart = body.indexOf('{');\n if (jsonStart < 0) throw new Error(`snapshot ${name} has no JSON payload`);\n let payload: any;\n try {\n payload = JSON.parse(body.slice(jsonStart));\n } catch {\n throw new Error(`snapshot ${name} payload is not valid JSON`);\n }\n // Checkout the commit the snapshot pointed at (detached HEAD — safe,\n // user can create a branch from there if they want to keep working).\n const checkout = await git(['checkout', payload.commit], cwd);\n if (checkout.code !== 0)\n throw new Error(`git checkout ${payload.commit} failed: ${checkout.stderr}`);\n // Re-post knobs. The harness will pick them up via its 100ms poll once\n // it next mounts (or immediately if already mounted on the same commit).\n const updates: Array<{ element: string; key: string; value: unknown }> = [];\n for (const [elName, kv] of Object.entries(payload.knobs ?? {})) {\n for (const [k, v] of Object.entries(kv as Record<string, unknown>)) {\n updates.push({ element: elName, key: k, value: v });\n }\n }\n if (updates.length > 0) {\n try {\n await setKnob({ updates });\n } catch {\n /* dev server may be down — knobs will re-hydrate on next runLab */\n }\n }\n return {\n ok: true,\n tag: tagName,\n restoredCommit: payload.commit,\n knobUpdates: updates.length,\n payload,\n };\n}\n\nasync function autoTune({\n element,\n knob,\n range,\n target_camera,\n max_iterations = 12,\n labUrl,\n}: {\n element: string;\n knob: string;\n range: [number, number];\n target_camera: string;\n max_iterations?: number;\n labUrl?: string;\n}) {\n const refPath = refsPath(process.cwd(), element, target_camera);\n if (!existsSync(refPath)) {\n throw new Error(\n `auto_tune needs a reference image at ${refPath}. Call set_reference ` +\n `with element=${element}, camera=${target_camera} first (or paste a PNG path/base64).`,\n );\n }\n const target = await resolveLabUrl({ element, labUrl });\n // Derive the knob origin from the RESOLVED page, not the raw labUrl arg, so\n // an element whose manifest advertises an absolute cross-origin labUrl still\n // tunes the page we capture (capture + knob origins must agree).\n const devUrl = resolveDevUrl({ labUrl: target });\n const { call } = await browserPool.getPage(target);\n\n const phi = (1 + Math.sqrt(5)) / 2;\n const invPhi = 1 / phi;\n let [a, b] = range;\n if (!(b > a))\n throw new Error(`auto_tune range must be [min, max] with max > min, got [${a}, ${b}]`);\n\n const cache = new Map<string, number>(); // memoize SSIM by knob value\n const history: Array<{ iter: number; knob: number; ssim: number; ms: number }> = [];\n const t0 = Date.now();\n\n async function evalAt(x: number): Promise<number> {\n const key = x.toFixed(6);\n if (cache.has(key)) return cache.get(key)!;\n const iterStart = Date.now();\n // 1. Post knob via the harness's /__knob endpoint (same origin as capture).\n await setKnob({ element, key: knob, value: x, devUrl });\n // 2. Wait (event-driven) for the harness to confirm it applied — returns as\n // soon as telemetry reflects the value instead of always sleeping 800ms.\n const applied = await waitForKnobApplied(knob, x, 2500, element, devUrl);\n if (!applied) await wait(300); // settle fallback if telemetry didn't confirm\n // 3. Capture target camera in-tab.\n const cap = await call('Runtime.evaluate', {\n expression: 'window.__TRISCOPE__.captureViews()',\n awaitPromise: true,\n returnByValue: true,\n });\n const views = cap.result.result.value ?? {};\n const b64 = String(views[target_camera] ?? '').replace(/^data:image\\/png;base64,/, '');\n if (!b64)\n throw new Error(`auto_tune: captureViews returned no PNG for camera \"${target_camera}\"`);\n // 4. Diff against reference; we minimise (1 - SSIM).\n const diff = diffReference({\n cwd: process.cwd(),\n element,\n camera: target_camera,\n currentBase64: b64,\n });\n const score = diff.ssim;\n cache.set(key, score);\n history.push({ iter: history.length, knob: x, ssim: score, ms: Date.now() - iterStart });\n return score;\n }\n\n // Initial bracket.\n let c = b - (b - a) * invPhi;\n let d = a + (b - a) * invPhi;\n let fc = await evalAt(c);\n let fd = await evalAt(d);\n\n for (let i = 0; i < max_iterations - 2; i++) {\n // Maximise SSIM ⇔ minimise (1 - SSIM): keep the side with higher SSIM.\n if (fc > fd) {\n b = d;\n d = c;\n fd = fc;\n c = b - (b - a) * invPhi;\n fc = await evalAt(c);\n } else {\n a = c;\n c = d;\n fc = fd;\n d = a + (b - a) * invPhi;\n fd = await evalAt(d);\n }\n // Early stop when the bracket is below 1% of the original range.\n if (Math.abs(b - a) < (range[1] - range[0]) * 0.01) break;\n }\n\n const best = [...cache.entries()]\n .map(([k, v]) => ({ knob: Number(k), ssim: v }))\n .sort((x, y) => y.ssim - x.ssim)[0];\n\n // Leave the knob at the best value so the user sees the converged state.\n // Must target the same origin as the tuned page (D5: omitting devUrl would\n // commit `best` to the boot DEV_URL, leaving the actual lab at the last\n // evaluated value and falsely reporting \"left at best\").\n await setKnob({ element, key: knob, value: best.knob, devUrl });\n\n return {\n element,\n knob,\n target_camera,\n bestKnobValue: best.knob,\n bestSsim: best.ssim,\n iterations: history.length,\n history,\n totalMs: Date.now() - t0,\n hint: 'SSIM 1.0 = identical to reference, 0.9+ = visually close, <0.7 = clearly different. The knob has been left at bestKnobValue in the live lab.',\n };\n}\n\n/**\n * multi_tune: coordinate-descent over 2-N knobs against a reference (SSIM),\n * reusing the event-driven evalAt loop. Greedy but robust for the smooth,\n * weakly-coupled knobs shader tuning involves. Hard-capped on total evaluations\n * so worst-case wall time stays bounded.\n */\nasync function multiTune({\n element,\n knobs,\n target_camera,\n max_cycles = 2,\n per_knob_iters = 8,\n compute_interactions = false,\n max_evaluations,\n labUrl,\n}: {\n element: string;\n knobs: Array<{ key: string; range: [number, number]; start?: number }>;\n target_camera: string;\n max_cycles?: number;\n per_knob_iters?: number;\n compute_interactions?: boolean;\n max_evaluations?: number;\n labUrl?: string;\n}) {\n const cwd = process.cwd();\n const refPath = refsPath(cwd, element, target_camera);\n if (!existsSync(refPath)) {\n throw new Error(\n `multi_tune needs a reference image at ${refPath}. Call set_reference (element=${element}, camera=${target_camera}) first.`,\n );\n }\n const target = await resolveLabUrl({ element, labUrl });\n // Knob origin derived from the resolved page (see autoTune) — capture + knob\n // must agree even for an absolute cross-origin manifest labUrl.\n const devUrl = resolveDevUrl({ labUrl: target });\n const { call } = await browserPool.getPage(target);\n const t0 = Date.now();\n const cache = new Map<string, number>();\n\n const evalAt = async (values: Record<string, number>): Promise<number> => {\n const ck = JSON.stringify(values);\n const hit = cache.get(ck);\n if (hit !== undefined) return hit;\n const updates = Object.entries(values).map(([key, value]) => ({ element, key, value }));\n await setKnob({ updates, devUrl });\n const last = updates[updates.length - 1];\n const ok = await waitForKnobApplied(last.key, last.value, 2500, element, devUrl);\n if (!ok) await wait(300);\n const cap = await call('Runtime.evaluate', {\n expression: 'window.__TRISCOPE__.captureViews()',\n awaitPromise: true,\n returnByValue: true,\n });\n const views = cap.result.result.value ?? {};\n const b64 = String(views[target_camera] ?? '').replace(/^data:image\\/png;base64,/, '');\n if (!b64) throw new Error(`multi_tune: captureViews returned no PNG for \"${target_camera}\"`);\n const diff = diffReference({ cwd, element, camera: target_camera, currentBase64: b64 });\n cache.set(ck, diff.ssim);\n return diff.ssim;\n };\n\n const specs = knobs.map((kn) => ({\n key: kn.key,\n min: kn.range[0],\n max: kn.range[1],\n start: kn.start ?? (kn.range[0] + kn.range[1]) / 2,\n }));\n const hardCap = max_evaluations ?? Math.min(specs.length * per_knob_iters * max_cycles + 4, 64);\n const result = await coordinateDescent({\n knobs: specs,\n evalAt,\n maxCycles: max_cycles,\n perKnobIters: per_knob_iters,\n maxEvaluations: hardCap,\n });\n\n // Optional pairwise interaction matrix (2nd-order mixed difference at the\n // optimum). Off by default — it adds ~3 evals per knob pair.\n let interactions: Array<{ a: string; b: string; interaction: number }> | undefined;\n if (compute_interactions && specs.length >= 2) {\n interactions = [];\n const base = await evalAt({ ...result.best });\n for (let i = 0; i < specs.length; i++) {\n for (let j = i + 1; j < specs.length; j++) {\n const A = specs[i];\n const B = specs[j];\n const dA = (A.max - A.min) * 0.05;\n const dB = (B.max - B.min) * 0.05;\n const clamp = (v: number, s: typeof A) => Math.min(s.max, Math.max(s.min, v));\n const fa = await evalAt({ ...result.best, [A.key]: clamp(result.best[A.key] + dA, A) });\n const fb = await evalAt({ ...result.best, [B.key]: clamp(result.best[B.key] + dB, B) });\n const fab = await evalAt({\n ...result.best,\n [A.key]: clamp(result.best[A.key] + dA, A),\n [B.key]: clamp(result.best[B.key] + dB, B),\n });\n interactions.push({ a: A.key, b: B.key, interaction: +(fab - fa - fb + base).toFixed(4) });\n }\n }\n }\n\n // Leave the lab at the converged values (same origin as the tuned page — D5).\n await setKnob({\n updates: Object.entries(result.best).map(([key, value]) => ({ element, key, value })),\n devUrl,\n });\n\n return {\n element,\n target_camera,\n best: result.best,\n bestSsim: +result.bestScore.toFixed(4),\n cycles: result.cycles,\n evaluations: result.evaluations,\n totalMs: Date.now() - t0,\n interactions,\n hint: 'SSIM 1.0 = identical, 0.9+ = close. Knobs left at best values in the live lab. interaction>0 = the two knobs reinforce, <0 = they fight (only present when compute_interactions=true).',\n };\n}\n\n/**\n * check_targets: load .claude/element-targets.json and evaluate the per-camera\n * convergence constraints against the current capture — a machine-readable\n * \"definition of done\". SSIM/meanAbsDiff constraints need a stored reference\n * (else they're skipped, not failed); luminance/dynamicRange come from the GPU\n * probe and are always evaluable.\n */\nasync function checkTargets({ element, labUrl }: { element: string; labUrl?: string }) {\n const cwd = process.cwd();\n const file = join(cwd, '.claude', 'element-targets.json');\n if (!existsSync(file)) {\n return { checked: 0, allPassed: true, note: `no targets file at ${file}` };\n }\n let all: any;\n try {\n all = JSON.parse(readFileSync(file, 'utf8'));\n } catch (e: any) {\n throw new Error(`invalid ${file}: ${e?.message ?? e}`);\n }\n const targetsByCamera = all?.[element];\n if (!targetsByCamera || typeof targetsByCamera !== 'object') {\n return { checked: 0, allPassed: true, note: `no targets for element \"${element}\" in ${file}` };\n }\n const cap = await captureViews({ element, labUrl, inline: true });\n const capturedByCamera: Record<string, any> = {};\n for (const [camera, probe] of Object.entries((cap.gpuProbes ?? {}) as Record<string, any>)) {\n capturedByCamera[camera] = { luminance: probe.luminance, dynamicRange: probe.dynamicRange };\n }\n // For cameras with an ssim/meanAbsDiff constraint AND a stored reference, diff.\n for (const camera of Object.keys(targetsByCamera)) {\n const c = targetsByCamera[camera] ?? {};\n const wantsRefMetric = c.ssim !== undefined || c.meanAbsDiff !== undefined;\n if (wantsRefMetric && existsSync(refsPath(cwd, element, camera))) {\n const b64 = cap._base64ByCam?.[camera];\n if (b64) {\n const d = diffReference({ cwd, element, camera, currentBase64: b64 });\n capturedByCamera[camera] = {\n ...(capturedByCamera[camera] ?? {}),\n ssim: d.ssim,\n meanAbsDiff: d.meanAbsDiff,\n };\n }\n }\n }\n const report = evaluateTargets(targetsByCamera, capturedByCamera);\n return {\n element,\n file,\n ...report,\n hint: report.allPassed\n ? 'All evaluated constraints pass — this view meets its target.'\n : 'Some constraints fail (see results[].pass=false). Skipped constraints need a set_reference to evaluate.',\n };\n}\n\nasync function inspect({ element, camera }: { element: string; camera?: string }) {\n // Resolve the lab URL the same way capture_views does, then append the\n // ?inspect=<el>&camera=<name> query so the harness boots in solo view.\n const baseUrl = await resolveLabUrl({ element });\n const sep = baseUrl.includes('?') ? '&' : '?';\n const inspectUrl = `${baseUrl}${sep}inspect=${encodeURIComponent(element)}${camera ? `&camera=${encodeURIComponent(camera)}` : ''}`;\n const t0 = Date.now();\n await browserPool.getPage(inspectUrl);\n return {\n element,\n camera: camera ?? null,\n url: inspectUrl,\n navMs: Date.now() - t0,\n hint: 'Right-drag to orbit, scroll to zoom, left-click to pick a mesh. Read .selection from telemetry after the user clicks.',\n };\n}\n\nasync function addElement({\n name,\n element,\n labUrl,\n}: {\n name: string;\n element?: string;\n labUrl?: string;\n}) {\n if (typeof name !== 'string' || name.length === 0) {\n throw new Error('add_element requires a non-empty `name`');\n }\n // `element`/`labUrl` only locate the running scene page (any mounted element\n // resolves to it); `name` is the registry element to mount.\n const target = await resolveLabUrl({ element, labUrl });\n const { call } = await browserPool.getPage(target);\n const res = await call('Runtime.evaluate', {\n expression: `JSON.stringify((function(){var t=window.__TRISCOPE__;if(!t||!t.addElement)return{ok:false,error:'addElement unavailable — rebuild the lab against newer @triscope/core'};var ok=t.addElement(${JSON.stringify(name)});return{ok:ok,name:${JSON.stringify(name)},mounted:t.mountedElements?t.mountedElements():[],available:t.availableElements?t.availableElements():[]};})())`,\n returnByValue: true,\n });\n return JSON.parse(res.result.result.value);\n}\n\nasync function removeElement({\n name,\n element,\n labUrl,\n}: {\n name: string;\n element?: string;\n labUrl?: string;\n}) {\n if (typeof name !== 'string' || name.length === 0) {\n throw new Error('remove_element requires a non-empty `name`');\n }\n const target = await resolveLabUrl({ element, labUrl });\n const { call } = await browserPool.getPage(target);\n const res = await call('Runtime.evaluate', {\n expression: `JSON.stringify((function(){var t=window.__TRISCOPE__;if(!t||!t.removeElement)return{ok:false,error:'removeElement unavailable — rebuild the lab against newer @triscope/core'};var ok=t.removeElement(${JSON.stringify(name)});return{ok:ok,name:${JSON.stringify(name)},mounted:t.mountedElements?t.mountedElements():[],available:t.availableElements?t.availableElements():[]};})())`,\n returnByValue: true,\n });\n return JSON.parse(res.result.result.value);\n}\n\nasync function inspectScene({\n element,\n maxNodes,\n labUrl,\n fresh = false,\n}: {\n element?: string;\n maxNodes?: number;\n labUrl?: string;\n fresh?: boolean;\n}) {\n const target = await resolveLabUrl({ element, labUrl });\n const { call } = await browserPool.getPage(target, { reload: fresh });\n const n = Number.isFinite(maxNodes) ? maxNodes : 500;\n const res = await call('Runtime.evaluate', {\n expression: `JSON.stringify(window.__TRISCOPE__ && window.__TRISCOPE__.queryScene ? window.__TRISCOPE__.queryScene(${n}) : { error: 'queryScene unavailable — the lab is on an older @triscope/core; rebuild it' })`,\n returnByValue: true,\n });\n return JSON.parse(res.result.result.value);\n}\n\nasync function readUniform({\n element,\n path,\n labUrl,\n}: {\n element?: string;\n path: string;\n labUrl?: string;\n}) {\n const target = await resolveLabUrl({ element, labUrl });\n const { call } = await browserPool.getPage(target);\n const res = await call('Runtime.evaluate', {\n expression: `JSON.stringify(window.__TRISCOPE__ && window.__TRISCOPE__.readUniform ? window.__TRISCOPE__.readUniform(${JSON.stringify(path)}) : { kind: 'not-found', error: 'readUniform unavailable — rebuild the lab against newer @triscope/core' })`,\n returnByValue: true,\n });\n return JSON.parse(res.result.result.value);\n}\n\nasync function setUniform({\n element,\n path,\n value,\n labUrl,\n}: {\n element?: string;\n path: string;\n value: unknown;\n labUrl?: string;\n}) {\n const target = await resolveLabUrl({ element, labUrl });\n const { call } = await browserPool.getPage(target);\n const res = await call('Runtime.evaluate', {\n expression: `JSON.stringify(window.__TRISCOPE__ && window.__TRISCOPE__.setUniform ? window.__TRISCOPE__.setUniform(${JSON.stringify(path)}, ${JSON.stringify(value)}) : { ok: false, kind: 'not-found', error: 'setUniform unavailable — rebuild the lab against newer @triscope/core' })`,\n returnByValue: true,\n });\n return JSON.parse(res.result.result.value);\n}\n\nasync function setSceneParam({\n cameras,\n knobs,\n elements,\n}: {\n cameras?: Record<string, { position?: number[]; target?: number[]; fov?: number }>;\n knobs?: Record<string, unknown>;\n elements?: Record<string, { enabled?: boolean }>;\n}) {\n const delta: Record<string, unknown> = {};\n if (cameras && Object.keys(cameras).length) delta.cameras = cameras;\n if (knobs && Object.keys(knobs).length) delta.knobs = knobs;\n if (elements && Object.keys(elements).length) delta.elements = elements;\n if (!delta.cameras && !delta.knobs && !delta.elements) {\n throw new Error('set_scene_param needs `cameras`, `knobs`, and/or `elements`');\n }\n const r = await fetch(`${DEV_URL}/__scene`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(delta),\n });\n if (!r.ok) throw new Error(`/__scene returned ${r.status}`);\n return {\n ok: true,\n applied: delta,\n note: 'Applied by the harness within ~100 ms (no reload) and persisted via /__scene so it survives a reload. Read back with get_scene or read_telemetry .cameras.',\n };\n}\n\nasync function getScene({ devUrl, labUrl }: { devUrl?: string; labUrl?: string } = {}) {\n const url = resolveDevUrl({ devUrl, labUrl });\n let sceneSpec: unknown = {};\n let live: unknown = {};\n try {\n const r = await fetch(`${url}/__scene/current`);\n if (r.ok) sceneSpec = await r.json();\n } catch {\n /* dev server down */\n }\n // Live scene state from the dev server's telemetry over HTTP (works for any\n // project/port; falls back to the local file only for the default dev server).\n const state = await fetchState(url);\n const st = state?.data ?? (url === DEV_URL && existsSync(STATE_PATH) ? safeReadState() : null);\n if (st) live = { cameras: st.cameras, knobs: st.knobs, elements: st.sceneElements };\n return { sceneSpec, live };\n}\n\nfunction safeReadState(): any {\n try {\n return JSON.parse(readFileSync(STATE_PATH, 'utf8'));\n } catch {\n return null;\n }\n}\n\nasync function openSelection({ editor }: { editor?: string }) {\n // Read the current selection from the telemetry snapshot. The selection\n // is written by the inspect-mode click handler in the browser, then\n // surfaced into /tmp/<project>-state.json on the next telemetry tick.\n if (!existsSync(STATE_PATH)) {\n throw new Error(`No telemetry at ${STATE_PATH} — is the dev server running with a lab open?`);\n }\n const state: any = JSON.parse(readFileSync(STATE_PATH, 'utf8'));\n const sel = state?.selection;\n if (!sel?.source?.file) {\n throw new Error(\n 'No mesh selected yet. Open the lab in inspect mode and left-click something first.',\n );\n }\n // Convert vite-served URL to a filesystem path: strip protocol+host so\n // `code --goto` resolves it relative to cwd (the project the dev server\n // is serving). Falls through if `file` is already a path.\n const rawFile = String(sel.source.file);\n const fsPath = rawFile\n .replace(/^https?:\\/\\/[^/]+\\//, '') // strip http://host:port/\n .replace(/^file:\\/\\//, '') // strip file://\n .replace(/[?#].*$/, ''); // strip query/hash\n const absPath = fsPath.startsWith('/') ? fsPath : join(process.cwd(), fsPath);\n const line = Number(sel.source.line ?? 1);\n const col = Number(sel.source.col ?? 1);\n // Editor resolution: explicit arg → $EDITOR → `code --goto`. We assume\n // `code` is on PATH for VS Code / Cursor / VSCodium users; others can\n // export $EDITOR (e.g. EDITOR=\"zed --goto\") to override.\n const cmd = editor ?? process.env.EDITOR ?? 'code';\n // `code --goto file:line:col` is the standard VSCode invocation.\n const usesGoto = /code\\b/.test(cmd);\n const args = usesGoto ? ['--goto', `${absPath}:${line}:${col}`] : [`${absPath}:${line}:${col}`];\n return await new Promise<{\n ok: boolean;\n cmd: string;\n args: string[];\n file: string;\n line: number;\n col: number;\n stderr?: string;\n }>((resolve, reject) => {\n const child = spawn(cmd, args, {\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: true,\n shell: NEED_SHELL,\n });\n let stderr = '';\n child.stderr.on('data', (d) => (stderr += d));\n child.on('error', (err) => reject(new Error(`failed to spawn ${cmd}: ${err.message}`)));\n // Editor commands usually fork-and-detach; don't wait for exit, just\n // confirm we spawned without immediate error.\n setTimeout(() => {\n try {\n child.unref();\n } catch {}\n resolve({ ok: true, cmd, args, file: absPath, line, col, stderr: stderr || undefined });\n }, 200);\n });\n}\n\nasync function runSmoke({ element }) {\n return new Promise((resolve, reject) => {\n const args = ['smoke'];\n if (element) args.push(element);\n const child = spawn('triscope', args, { stdio: ['ignore', 'pipe', 'pipe'], shell: NEED_SHELL });\n let out = '';\n let err = '';\n child.stdout.on('data', (d) => (out += d));\n child.stderr.on('data', (d) => (err += d));\n child.on('error', reject);\n child.on('exit', (code) => resolve({ exitCode: code ?? 0, stdout: out, stderr: err }));\n });\n}\n\nasync function importElement({ source, name }: { source: string; name?: string }) {\n rejectFlagArg(source, 'source');\n if (name !== undefined) rejectFlagArg(name, 'name');\n return new Promise((resolve, reject) => {\n const args = ['import', source];\n if (name) args.push('--name', name);\n const child = spawn(TRISCOPE_BIN, args, { stdio: ['ignore', 'pipe', 'pipe'], shell: false });\n let out = '';\n let err = '';\n child.stdout.on('data', (d) => (out += d));\n child.stderr.on('data', (d) => (err += d));\n child.on('error', reject);\n child.on('exit', (code) => resolve({ exitCode: code ?? 0, stdout: out, stderr: err }));\n });\n}\n\nasync function scaffoldFromGltf({ file, name }: { file: string; name?: string }) {\n rejectFlagArg(file, 'file');\n if (name !== undefined) rejectFlagArg(name, 'name');\n return new Promise((resolve, reject) => {\n const args = ['new-gltf', file];\n if (name) args.push('--name', name);\n const child = spawn(TRISCOPE_BIN, args, { stdio: ['ignore', 'pipe', 'pipe'], shell: false });\n let out = '';\n let err = '';\n child.stdout.on('data', (d) => (out += d));\n child.stderr.on('data', (d) => (err += d));\n child.on('error', reject);\n child.on('exit', (code) => resolve({ exitCode: code ?? 0, stdout: out, stderr: err }));\n });\n}\n\nconst tools = [\n {\n name: 'list_elements',\n description:\n 'List elements registered with the running triscope dev server. Cameras + current knob values appear per element ONLY after a browser has mounted that lab (the harness POSTs the full manifest on mount); a cold call returns just the seeded `{element, labUrl}` from package.json#triscope.labs. Pass devUrl/labUrl to target a different dev server than the one the MCP booted against.',\n inputSchema: {\n type: 'object',\n properties: {\n devUrl: {\n type: 'string',\n description: 'Target dev-server origin (default: the boot one).',\n },\n labUrl: { type: 'string', description: 'A lab URL; its origin is used as devUrl.' },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'read_telemetry',\n description:\n 'Read the latest telemetry snapshot (live over GET /__state, falling back to the on-disk file — so it now works cross-project). Optional jq-style \"path\" (e.g. \".elements.ship.triangles\", \".perf.fps\") returns that slice VERBATIM. The FULL snapshot (no path) is annotated with `__source` (\"live\"/\"disk\") + `__staleMs` + a `__warning` when old (the lab tab may be backgrounded/closed). Use for hidden numeric state where screenshots lie. Pass devUrl/labUrl to read a different dev server/project.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Dot-separated jq-style path into the snapshot.' },\n devUrl: {\n type: 'string',\n description: 'Target dev-server origin (default: the boot one).',\n },\n labUrl: { type: 'string', description: 'A lab URL; its origin is used as devUrl.' },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'set_knob',\n description:\n 'Live-update one or many knobs in a single round trip. Either pass {element,key,value} for a single update OR {updates:[{element,key,value},...]} to batch. Use absolute values, never deltas. Changes take effect in the running browser within ~100 ms. Out-of-range / wrong-type values are clamped to the knob spec before they apply; when that happens the response includes clamped:[{element,key,requested,final}] so you know what actually took effect. Pass devUrl/labUrl to target a different dev server.',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string', description: 'Element name (single-update form).' },\n key: { type: 'string', description: 'Knob key (single-update form).' },\n value: { description: 'Absolute value (number, \"#aabbcc\" color, boolean).' },\n updates: {\n type: 'array',\n description: 'Batch form: array of {element,key,value} entries applied atomically.',\n items: {\n type: 'object',\n properties: {\n element: { type: 'string' },\n key: { type: 'string' },\n value: {},\n },\n required: ['element', 'key', 'value'],\n },\n },\n devUrl: {\n type: 'string',\n description: 'Target dev-server origin (default: the boot one).',\n },\n labUrl: { type: 'string', description: 'A lab URL; its origin is used as devUrl.' },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'capture_views',\n description:\n 'Spawn Chromium against a lab page (resolved via Element.labUrl in the manifest, package.json#triscope.labs, or /labs/<element>.html as fallback) and render every named camera. Writes PNGs to /tmp/<project>-capture-<element>/<camera>.png AND returns each image inline as MCP image content blocks (so the model sees them directly without a Read call). Set inline=false to return paths only (smaller payload). The response includes blackFrames:[camera,...] (panes the GPU drew black — luminance below threshold, a render failure) AND flatFrames:[camera,...] (panes with dynamicRange≈1, i.e. only the flat clear-color is in view — the element drifted out of frame or was not drawn; blackFrames misses this when the clear-color is above the black threshold).',\n inputSchema: {\n type: 'object',\n properties: {\n element: {\n type: 'string',\n description: 'Element name. URL is resolved via manifest/config.',\n },\n labUrl: {\n type: 'string',\n description: 'Override the lab URL entirely (highest precedence).',\n },\n inline: {\n type: 'boolean',\n description:\n 'Return images as inline content blocks. Default false — safer for many-camera elements where the inline base64 payload can blow the MCP stdio message budget. Set true only when you specifically want inline.',\n default: false,\n },\n fresh: {\n type: 'boolean',\n description:\n 'Force a full page reload before capturing, so a source edit the pooled page would otherwise miss (e.g. a *.lab.ts change) is picked up. Costs a reload (~1-3s) and drops transient set_uniform writes. Default false.',\n default: false,\n },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'set_reference',\n description:\n 'Save a reference image for an (element, camera) pair under <project>/refs/<element>/<camera>.png. Accepts EITHER a `path` to a file on disk (e.g. a chat-attachment path) OR `base64` inline PNG data. Use this when the user pastes a reference image they want the AI to converge toward.',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string', description: 'Element name.' },\n camera: { type: 'string', description: 'Camera name (must match Element.cameras key).' },\n path: {\n type: 'string',\n description: 'Filesystem path to a PNG/JPEG (one of path or base64 required).',\n },\n base64: {\n type: 'string',\n description: 'Base64-encoded PNG (with or without data: prefix).',\n },\n },\n required: ['element', 'camera'],\n additionalProperties: false,\n },\n },\n {\n name: 'diff_reference',\n description:\n 'Capture the current view at (element, camera), diff it against the stored reference, and return: numeric meanAbsDiff (0-255) + ssim (1=identical); an 8×8 per-tile SSIM grid + the worstTile {row,col,ssim} so you know WHERE they differ; the side-by-side composite (left=ref, right=current); and a black→blue→yellow→red difference heatmap (hot = divergent region) as a second image. Requires a prior set_reference for the same (element, camera).',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string', description: 'Element name.' },\n camera: { type: 'string', description: 'Camera name.' },\n labUrl: {\n type: 'string',\n description: 'Override the lab URL (otherwise resolved like capture_views).',\n },\n fresh: {\n type: 'boolean',\n description:\n 'Force a full reload before capturing (pick up source edits). Default false.',\n },\n },\n required: ['element', 'camera'],\n additionalProperties: false,\n },\n },\n {\n name: 'set_reference_motion',\n description:\n 'Capture the CURRENT motion sequence at (element, camera) and save it as the animated reference. Writes <project>/refs/<element>/<camera>.motion.png (filmstrip) + <camera>.motion.json (frames/dt/mode metadata). Use to lock in a known-good animation before risky shader/uniform edits, then diff_reference_motion confirms regressions visually + numerically.',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string' },\n camera: { type: 'string' },\n frames: { type: 'number', description: 'Default 6.' },\n dt: { type: 'number', description: 'Seconds between frames. Default 0.25.' },\n mode: { type: 'string', enum: ['time', 'real'], description: 'Default \"time\".' },\n labUrl: { type: 'string' },\n },\n required: ['element', 'camera'],\n additionalProperties: false,\n },\n },\n {\n name: 'diff_reference_motion',\n description:\n 'Capture current motion at (element, camera), diff against the saved animated reference. Returns a vertically-stacked composite (reference filmstrip on top, current on bottom) inline AND a scalar motionDiff (0=identical animation, >5=visible drift, >30=clearly different). Requires a prior set_reference_motion for the same (element, camera).',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string' },\n camera: { type: 'string' },\n frames: { type: 'number' },\n dt: { type: 'number' },\n mode: { type: 'string', enum: ['time', 'real'] },\n labUrl: { type: 'string' },\n },\n required: ['element', 'camera'],\n additionalProperties: false,\n },\n },\n {\n name: 'capture_motion',\n description:\n 'Capture N frames per camera spaced by dt seconds, compose each into an inline filmstrip image (frames tiled left-to-right), and return a numeric motionMagnitude per camera (0-255 scale; <1 = static, >5 = visible motion, >20 = vigorous). Use this WHEN THE ELEMENT HAS ANIMATION (shader-driven motion, sail billow, particle systems, oscillation) — a single capture_views frame cannot reveal whether motion is happening. For complementary numeric verification of hidden animated state, read_telemetry .elements.<name>.motion (if the Element declared motionProbes).',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string' },\n camera: {\n type: 'string',\n description: 'Single camera. Omit to capture all cameras (one filmstrip each).',\n },\n frames: { type: 'number', description: 'Frames per filmstrip. Default 6.' },\n dt: { type: 'number', description: 'Seconds between captured frames. Default 0.25.' },\n mode: {\n type: 'string',\n enum: ['time', 'real'],\n description:\n '\"time\" (default) is deterministic (steps time.value, fast). \"real\" runs wall-clock (slower; needed for CPU-integrated state).',\n },\n labUrl: {\n type: 'string',\n description: 'Override the lab URL (otherwise resolved like capture_views).',\n },\n inline: {\n type: 'boolean',\n description: 'Include filmstrips as inline images. Default true.',\n },\n fresh: {\n type: 'boolean',\n description:\n 'Force a full reload before capturing (pick up source edits). Default false.',\n },\n },\n required: ['element'],\n additionalProperties: false,\n },\n },\n {\n name: 'health',\n description:\n 'Server health snapshot. Returns uptime, dev-server reachability, browser-pool state, pid, recent errors (last 16). Call this when other tools misbehave: a \"Connection closed\" error from a capture tool followed by a healthy health() call means the MCP server is alive but the browser pool needs to recover; a failed health() means the server itself is sick.',\n inputSchema: { type: 'object', properties: {}, additionalProperties: false },\n },\n {\n name: 'run_smoke',\n description:\n 'Run the headed-Chromium smoke harness against a lab page. Returns exit code, stdout, stderr. Use as a CI gate after a batch of knob changes.',\n inputSchema: {\n type: 'object',\n properties: {\n element: {\n type: 'string',\n description: 'Element lab to test (defaults to the scene lab).',\n },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'import_element',\n description:\n 'Install a published element package (naming convention `triscope-element-<name>`, or `github:user/repo`) into the current project and wire its lab page + vite input + package.json#triscope.labs. Runs `triscope import`; returns exit code + output. After it succeeds, capture_views/inspect_scene the new element by name.',\n inputSchema: {\n type: 'object',\n properties: {\n source: { type: 'string', description: 'npm package or github:user/repo[#ref].' },\n name: { type: 'string', description: 'Override the local element/lab name.' },\n },\n required: ['source'],\n additionalProperties: false,\n },\n },\n {\n name: 'scaffold_from_gltf',\n description:\n 'Generate a wired triscope Element from a glTF/GLB asset path: auto-detects bounds + animation clips, copies the asset to /public, and writes src/elements/<name>.ts (GLTFLoader + AnimationMixer + fitted cameras + scale knob + dispose). Runs `triscope new-gltf`; returns exit code + output. Saves ~40-100 lines of loader/dispose boilerplate when bringing in a model.',\n inputSchema: {\n type: 'object',\n properties: {\n file: { type: 'string', description: 'Path to a .glb or .gltf file.' },\n name: {\n type: 'string',\n description: 'Override the element name (default: file basename).',\n },\n },\n required: ['file'],\n additionalProperties: false,\n },\n },\n {\n name: 'inspect_scene',\n description:\n 'Snapshot the live scene graph: every mesh/light/group with triangleCount, worldPosition, materialKind + materialColor, uniformNames, and the file:line `source` where it was added. Answers \"what is in this scene / which object is X / where is its code\" in ONE call instead of many capture_views probes. Returns `nodes` (sorted by triangle count, capped at maxNodes — default 120; `truncated`+`total` flag the rest, raise maxNodes to see it) PLUS a separate `lights` array — every light with type/intensity/color/position, ALWAYS included regardless of the cap (a named light is then read/writable via read_uniform/set_uniform \"name.intensity\").',\n inputSchema: {\n type: 'object',\n properties: {\n element: {\n type: 'string',\n description:\n 'Element/lab to introspect (resolved like capture_views). Omit for the scene lab.',\n },\n maxNodes: { type: 'number', description: 'Cap on returned nodes. Default 500.' },\n labUrl: { type: 'string', description: 'Override the lab URL.' },\n fresh: {\n type: 'boolean',\n description: 'Force a full reload first (pick up source edits). Default false.',\n },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'read_uniform',\n description:\n 'Read ANY live material uniform / material property / object property by \"objectName|uuid.key\" path — even values never declared as knobs (e.g. \"ship.metalness\", \"sun.intensity\", a shader uniform \"ocean.uChoppiness\"). Use inspect_scene first to discover object names + uniformNames. Returns {kind, value} (colors as #hex, vectors as arrays); kind=\"not-found\" if the path doesn\\'t resolve.',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string', description: 'Element/lab (resolved like capture_views).' },\n path: { type: 'string', description: '\"<objectName|uuid>.<key>\" — split on the last dot.' },\n labUrl: { type: 'string' },\n },\n required: ['path'],\n additionalProperties: false,\n },\n },\n {\n name: 'set_uniform',\n description:\n 'Write ANY live material uniform / material property / object property by \"objectName|uuid.key\" path WITHOUT a source edit or reload — for probing a shader parameter that isn\\'t a declared knob. Colors accept \"#rrggbb\" or a number; vectors accept [x,y,z]. TRANSIENT: not persisted across reloads (use set_knob for values you want to keep). Returns {ok, previous, current}.',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string' },\n path: { type: 'string', description: '\"<objectName|uuid>.<key>\".' },\n value: { description: 'Number, \"#hex\" / numeric color, boolean, or [x,y,z] vector.' },\n labUrl: { type: 'string' },\n },\n required: ['path', 'value'],\n additionalProperties: false,\n },\n },\n {\n name: 'inspect',\n description:\n 'Open the lab for an element in interactive inspect mode (solo full-canvas camera + OrbitControls + click-to-pick). Navigates the running browser via CDP to ?inspect=<element>&camera=<name>. Use when the user asks to \"inspect\" or \"open\" an element so they can rotate and click parts of it; subsequent clicks populate .selection in telemetry with source file:line.',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string', description: 'Element to inspect (must match the manifest).' },\n camera: {\n type: 'string',\n description: \"Starting camera (defaults to the element's first declared camera).\",\n },\n },\n required: ['element'],\n additionalProperties: false,\n },\n },\n {\n name: 'open_selection',\n description:\n 'Open the file:line of the currently selected mesh (from inspect mode) in the user\\'s editor. Reads .selection.source from the telemetry snapshot and spawns $EDITOR (or `code --goto` by default). Use after the user clicks a mesh and says \"open this\" / \"show me the code\".',\n inputSchema: {\n type: 'object',\n properties: {\n editor: {\n type: 'string',\n description: 'Override the editor command. Default: $EDITOR or `code`.',\n },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'snapshot',\n description:\n \"Freeze the current tuning state as a git tag (triscope/snapshot/<name>). Stores the HEAD commit + every persisted knob value across all elements, as JSON inside the tag's annotated message — no working-tree files written, no rebase noise. Refuses on a dirty working tree (would silently lose the in-progress edits on restore).\",\n inputSchema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Snapshot name. Must match [A-Za-z0-9._-]+.' },\n message: {\n type: 'string',\n description: 'Optional human note for `git show triscope/snapshot/<name>`.',\n },\n },\n required: ['name'],\n additionalProperties: false,\n },\n },\n {\n name: 'restore',\n description:\n 'Restore a snapshot: git checkout the recorded commit and re-post every knob value via /__knob. Refuses on a dirty working tree. Leaves HEAD detached — branch from there if you want to keep iterating.',\n inputSchema: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n description: 'Snapshot name (matches `mcp__triscope__list_snapshots`).',\n },\n },\n required: ['name'],\n additionalProperties: false,\n },\n },\n {\n name: 'list_snapshots',\n description:\n 'List every triscope snapshot tag in this repo (name, creation date, message subject). Use to find which one to restore.',\n inputSchema: { type: 'object', properties: {}, additionalProperties: false },\n },\n {\n name: 'auto_tune',\n description:\n 'Find the knob value that maximises SSIM (perceptual similarity) between the captured view and a stored reference image, using derivative-free golden-section search. Requires a prior set_reference for (element, target_camera). Iterations: post_knob → wait → captureViews → diff_reference. Use to converge a single shader parameter on a reference photo without manual bisection.',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string', description: 'Element whose knob to tune.' },\n knob: {\n type: 'string',\n description: 'Knob key (must exist on Element.knobs and be type=number).',\n },\n range: {\n type: 'array',\n description:\n \"Inclusive [min, max] search bracket. Should cover the knob's declared min/max.\",\n items: { type: 'number' },\n minItems: 2,\n maxItems: 2,\n },\n target_camera: {\n type: 'string',\n description:\n 'Camera the SSIM is computed on. Must have a stored reference (set_reference first).',\n },\n max_iterations: {\n type: 'number',\n description:\n 'Cap on knob evaluations. Default 12 (golden section converges to ~0.7% of range).',\n },\n labUrl: {\n type: 'string',\n description: 'Override the lab URL (otherwise resolved like capture_views).',\n },\n },\n required: ['element', 'knob', 'range', 'target_camera'],\n additionalProperties: false,\n },\n },\n {\n name: 'multi_tune',\n description:\n 'Converge 2-N coupled knobs on a reference image at once via coordinate descent (golden-section per knob, repeated cycles) maximising SSIM. Use when several knobs jointly shape the look (e.g. choppiness + foamThreshold + exposure) — beats chaining single-knob auto_tune. Requires a prior set_reference for (element, target_camera). Hard-capped on total captures so wall time stays bounded; best with <=4 knobs. Leaves the lab at the converged values.',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string' },\n knobs: {\n type: 'array',\n minItems: 1,\n description:\n 'Knobs to co-tune: [{key, range:[min,max], start?}]. Keep to <=4 for reasonable wall time.',\n items: {\n type: 'object',\n properties: {\n key: { type: 'string' },\n range: { type: 'array', items: { type: 'number' }, minItems: 2, maxItems: 2 },\n start: { type: 'number' },\n },\n required: ['key', 'range'],\n additionalProperties: false,\n },\n },\n target_camera: {\n type: 'string',\n description: 'Camera the SSIM is computed on (needs a stored reference).',\n },\n max_cycles: { type: 'number', description: 'Passes over all knobs. Default 2.' },\n per_knob_iters: {\n type: 'number',\n description: 'Golden-section evals per knob per cycle. Default 8.',\n },\n compute_interactions: {\n type: 'boolean',\n description:\n 'Also return a pairwise knob-interaction matrix (extra evals). Default false.',\n },\n max_evaluations: {\n type: 'number',\n description: 'Hard cap on total captures. Default min(knobs*iters*cycles+4, 64).',\n },\n labUrl: { type: 'string' },\n },\n required: ['element', 'knobs', 'target_camera'],\n additionalProperties: false,\n },\n },\n {\n name: 'check_targets',\n description:\n 'Evaluate per-camera convergence constraints from .claude/element-targets.json against the current capture — a machine-readable \"is this view done?\". Constraints per camera: ssim (min), meanAbsDiff (max), luminance {min,max}, dynamicRange {min,max}. ssim/meanAbsDiff need a stored reference (skipped, not failed, when absent); luminance/dynamicRange come from the GPU probe. Returns per-constraint pass/fail + allPassed. No targets file → no-op pass.',\n inputSchema: {\n type: 'object',\n properties: {\n element: { type: 'string' },\n labUrl: { type: 'string' },\n },\n required: ['element'],\n additionalProperties: false,\n },\n },\n {\n name: 'set_scene_param',\n description:\n 'Live-mutate the scene WITHOUT a code edit or reload (Scene Description Layer): repoint cameras (position/target/fov), override knobs, and show/hide composed elements (enabled true/false — the \"solo a track\" model). Applied by the harness within ~100 ms and persisted so it survives a reload. NOTE: `elements` toggles visibility of elements already composed into the scene; instantiating a brand-new element type still needs a code edit.',\n inputSchema: {\n type: 'object',\n properties: {\n cameras: {\n type: 'object',\n description: 'Map of cameraName → {position:[x,y,z], target:[x,y,z], fov} (any subset).',\n additionalProperties: {\n type: 'object',\n properties: {\n position: { type: 'array', items: { type: 'number' }, minItems: 3, maxItems: 3 },\n target: { type: 'array', items: { type: 'number' }, minItems: 3, maxItems: 3 },\n fov: { type: 'number' },\n },\n additionalProperties: false,\n },\n },\n knobs: {\n type: 'object',\n description:\n 'Map of knobKey → value (same effect as set_knob; here for one-call scene edits).',\n },\n elements: {\n type: 'object',\n description:\n 'Map of elementName → {enabled:boolean} to show/hide a composed element live.',\n additionalProperties: {\n type: 'object',\n properties: { enabled: { type: 'boolean' } },\n additionalProperties: false,\n },\n },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'get_scene',\n description:\n 'Return the current scene: `sceneSpec` (the persisted SDL overrides from set_scene_param) and `live` (the camera positions/targets/fov + knob values from telemetry). Use to see what a viewpoint currently is before repointing it. Pass devUrl/labUrl to target a different dev server.',\n inputSchema: {\n type: 'object',\n properties: {\n devUrl: {\n type: 'string',\n description: 'Target dev-server origin (default: the boot one).',\n },\n labUrl: { type: 'string', description: 'A lab URL; its origin is used as devUrl.' },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'add_element',\n description:\n 'Instantiate a registered element into a runSceneLab scene LIVE (no reload): mounts it, adds its namespaced `<element>.<camera>` cameras + `<element>.<knob>` knobs, and rebuilds the grid. Returns {ok, mounted, available}. Only works on a multi-element scene booted with runSceneLab — on a single-element runLab page it returns {ok:false}. Use `available` from a prior add/remove (or list_elements) to see mountable names.',\n inputSchema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Registered element name to mount.' },\n element: {\n type: 'string',\n description: 'Any element in the scene, used only to locate the lab page.',\n },\n labUrl: { type: 'string', description: 'Explicit lab URL (alternative to element).' },\n },\n required: ['name'],\n additionalProperties: false,\n },\n },\n {\n name: 'remove_element',\n description:\n 'Dispose a mounted element from a runSceneLab scene LIVE (no reload): drops its cameras/knobs/telemetry and rebuilds the grid. The element stays in the registry and can be re-added with add_element. Returns {ok, mounted, available}.',\n inputSchema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Mounted element name to dispose.' },\n element: {\n type: 'string',\n description: 'Any element in the scene, used only to locate the lab page.',\n },\n labUrl: { type: 'string', description: 'Explicit lab URL (alternative to element).' },\n },\n required: ['name'],\n additionalProperties: false,\n },\n },\n];\n\nexport function jsonResult(value) {\n let text: string;\n if (value === undefined) text = 'undefined';\n else if (typeof value === 'string') text = value;\n else text = JSON.stringify(value, null, 2);\n return {\n content: [{ type: 'text', text }],\n };\n}\n\nexport async function startServer() {\n const server = new Server(\n // Reported to every MCP client in the `initialize` handshake — keep in sync\n // with packages/mcp/package.json version on each release.\n { name: 'triscope-mcp', version: '0.4.0' },\n { capabilities: { tools: {} } },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));\n\n server.setRequestHandler(CallToolRequestSchema, async (req) => {\n const { name, arguments: args = {} } = req.params;\n // One info log per tool entry; on the way out either 'succeeded' or\n // 'failed' so a hung/dropped call leaves a half-pair in the log (no\n // succeeded/failed entry → the response never returned, e.g. the\n // process was OOM-killed during JSON encoding).\n const toolStart = Date.now();\n logger.info(`tool:${name}`, 'invoked', { args });\n const finish = (outcome: 'succeeded' | 'failed', extra?: Record<string, unknown>) =>\n logger.info(`tool:${name}`, outcome, { ms: Date.now() - toolStart, ...(extra ?? {}) });\n try {\n const result = await (async () => {\n switch (name) {\n case 'list_elements':\n return jsonResult(\n await listElements({\n devUrl: args.devUrl as string | undefined,\n labUrl: args.labUrl as string | undefined,\n }),\n );\n case 'read_telemetry':\n return jsonResult(\n await readTelemetry(args.path as string | undefined, {\n devUrl: args.devUrl as string | undefined,\n labUrl: args.labUrl as string | undefined,\n }),\n );\n case 'set_knob': {\n const value = z.union([z.number(), z.string(), z.boolean()]);\n const update = z.object({ element: z.string(), key: z.string(), value });\n const schema = z.union([z.object({ updates: z.array(update).min(1) }), update]);\n const parsed = schema.parse(args);\n const loc = z\n .object({ devUrl: z.string().optional(), labUrl: z.string().optional() })\n .parse(args);\n return jsonResult(await setKnob({ ...parsed, ...loc }));\n }\n case 'capture_views': {\n const res = await captureViews({\n element: args.element as string | undefined,\n labUrl: args.labUrl as string | undefined,\n inline: (args.inline ?? false) as boolean,\n fresh: (args.fresh ?? false) as boolean,\n });\n const { _base64ByCam, ...summary } = res;\n // Cap inline payload: 12-camera scenes can produce ~20 MB of base64\n // in a single JSON-RPC message over stdio, which OOM-kills the\n // server process (no catch, no log — Claude Code then auto-respawns\n // us and tools are temporarily unavailable). Auto-downgrade to\n // file paths when over budget and surface a warning so the model\n // knows to Read the files instead.\n let inlineBytes = 0;\n for (const b64 of Object.values(_base64ByCam) as string[]) inlineBytes += b64.length;\n const inlineCapped = res.inline && inlineBytes > INLINE_PAYLOAD_BUDGET;\n const finalInline = res.inline && !inlineCapped;\n const summaryWithWarn = inlineCapped\n ? {\n ...summary,\n inline: false,\n inlineCapped: true,\n inlineWarning: `inline payload would have been ${(inlineBytes / 1048576).toFixed(1)} MB (limit ${(INLINE_PAYLOAD_BUDGET / 1048576).toFixed(0)} MB) — files are on disk, Read them by path.`,\n }\n : summary;\n const text = JSON.stringify(summaryWithWarn, null, 2);\n if (!finalInline) return { content: [{ type: 'text', text }] };\n const content: any[] = [{ type: 'text', text }];\n for (const cam of res.cameraOrder) {\n const data = _base64ByCam[cam];\n if (!data) continue;\n content.push({ type: 'image', data, mimeType: 'image/png' });\n }\n return { content };\n }\n case 'set_reference': {\n const parsed = z\n .object({\n element: z.string(),\n camera: z.string(),\n path: z.string().optional(),\n base64: z.string().optional(),\n })\n .parse(args);\n const result = setReference({ cwd: process.cwd(), ...parsed } as any);\n return jsonResult(result);\n }\n case 'diff_reference': {\n const parsed = z\n .object({\n element: z.string(),\n camera: z.string(),\n labUrl: z.string().optional(),\n fresh: z.boolean().optional(),\n })\n .parse(args);\n const refExists = existsSync(refsPath(process.cwd(), parsed.element, parsed.camera));\n if (!refExists) {\n return {\n isError: true,\n content: [\n {\n type: 'text',\n text: `no reference at ${refsPath(process.cwd(), parsed.element, parsed.camera)}. Call set_reference first.`,\n },\n ],\n };\n }\n const cap = await captureViews({\n element: parsed.element,\n labUrl: parsed.labUrl,\n inline: true,\n fresh: parsed.fresh ?? false,\n });\n const currentBase64 = cap._base64ByCam?.[parsed.camera];\n if (!currentBase64) {\n return {\n isError: true,\n content: [\n {\n type: 'text',\n text: `camera \"${parsed.camera}\" not found on element \"${parsed.element}\". Available: ${cap.cameraOrder.join(', ')}`,\n },\n ],\n };\n }\n const diff = diffReference({\n cwd: process.cwd(),\n element: parsed.element,\n camera: parsed.camera,\n currentBase64,\n });\n // Two images: the side-by-side composite (always) and the\n // difference heatmap (when it fits the inline budget). The heatmap\n // is what makes the worstTile/tileGrid spatially legible.\n const compositeBytes = diff.compositeBase64.length;\n const heatmapBytes = diff.heatmapBase64?.length ?? 0;\n const heatmapFits = compositeBytes + heatmapBytes <= INLINE_PAYLOAD_BUDGET;\n const content: any[] = [\n {\n type: 'text',\n text: JSON.stringify(\n {\n camera: diff.camera,\n refPath: diff.refPath,\n meanAbsDiff: diff.meanAbsDiff,\n ssim: diff.ssim,\n worstTile: diff.worstTile,\n tileStats: diff.tileStats,\n tileGrid: diff.tileGrid,\n heatmapIncluded: heatmapFits,\n hint: 'meanAbsDiff: 0 = identical, ~30 = visibly close, >80 = clearly different. ssim: 1.0 = identical, 0.9+ = visually close, <0.7 = clearly different (prefer SSIM, robust to AA noise). tileGrid is an 8×8 SSIM map (row 0 = top); worstTile points at the most divergent region. The second image is a black→blue→yellow→red difference heatmap — hot = where the frames differ.',\n },\n null,\n 2,\n ),\n },\n { type: 'image', data: diff.compositeBase64, mimeType: 'image/png' },\n ];\n if (heatmapFits && diff.heatmapBase64) {\n content.push({ type: 'image', data: diff.heatmapBase64, mimeType: 'image/png' });\n }\n return { content };\n }\n case 'set_reference_motion': {\n const parsed = z\n .object({\n element: z.string(),\n camera: z.string(),\n frames: z.number().int().min(2).max(32).optional(),\n dt: z.number().positive().max(5).optional(),\n mode: z.enum(['time', 'real']).optional(),\n labUrl: z.string().optional(),\n })\n .parse(args);\n const opts = {\n frames: parsed.frames ?? 6,\n dt: parsed.dt ?? 0.25,\n mode: parsed.mode ?? 'time',\n };\n const frameB64s = await captureMotionFramesRaw({ ...parsed, ...opts });\n const r = setReferenceMotion({\n cwd: process.cwd(),\n element: parsed.element,\n camera: parsed.camera,\n frameBase64s: frameB64s,\n meta: opts,\n });\n return jsonResult(r);\n }\n case 'diff_reference_motion': {\n const parsed = z\n .object({\n element: z.string(),\n camera: z.string(),\n frames: z.number().int().min(2).max(32).optional(),\n dt: z.number().positive().max(5).optional(),\n mode: z.enum(['time', 'real']).optional(),\n labUrl: z.string().optional(),\n })\n .parse(args);\n const { filmstrip, meta } = refsMotionPaths(\n process.cwd(),\n parsed.element,\n parsed.camera,\n );\n if (!existsSync(filmstrip)) {\n return {\n isError: true,\n content: [\n {\n type: 'text',\n text: `no motion reference at ${filmstrip}. Call set_reference_motion first.`,\n },\n ],\n };\n }\n // Inherit frame/dt/mode from saved metadata so the comparison is fair.\n let savedMeta: any = {};\n try {\n savedMeta = existsSync(meta) ? JSON.parse(readFileSync(meta, 'utf8')) : {};\n } catch {}\n const opts = {\n frames: parsed.frames ?? savedMeta.frames ?? 6,\n dt: parsed.dt ?? savedMeta.dt ?? 0.25,\n mode: parsed.mode ?? savedMeta.mode ?? 'time',\n };\n const frameB64s = await captureMotionFramesRaw({ ...parsed, ...opts });\n const diff = diffReferenceMotion({\n cwd: process.cwd(),\n element: parsed.element,\n camera: parsed.camera,\n currentFrames: frameB64s,\n });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n camera: parsed.camera,\n refFilmstripPath: diff.refFilmstripPath,\n refMeta: diff.refMeta,\n motionDiff: diff.motionDiff,\n hint: '0 = identical animation, >5 = visible drift, >30 = clearly different',\n },\n null,\n 2,\n ),\n },\n { type: 'image', data: diff.compositeBase64, mimeType: 'image/png' },\n ],\n };\n }\n case 'capture_motion': {\n const parsed = z\n .object({\n element: z.string(),\n camera: z.string().optional(),\n frames: z.number().int().min(2).max(32).optional(),\n dt: z.number().positive().max(5).optional(),\n mode: z.enum(['time', 'real']).optional(),\n labUrl: z.string().optional(),\n inline: z.boolean().optional(),\n fresh: z.boolean().optional(),\n })\n .parse(args);\n const res = await captureMotion(parsed);\n const { _filmstripBase64, ...summary } = res;\n // Same inline budget guard as capture_views — filmstrips can be\n // even bigger (N frames per camera) so easier to blow the cap.\n let filmstripBytes = 0;\n for (const b64 of Object.values(_filmstripBase64) as string[])\n filmstripBytes += b64.length;\n const userWantsInline = parsed.inline !== false;\n const filmstripCapped = userWantsInline && filmstripBytes > INLINE_PAYLOAD_BUDGET;\n const finalInline = userWantsInline && !filmstripCapped;\n const text = JSON.stringify(\n {\n ...summary,\n ...(filmstripCapped\n ? {\n inlineCapped: true,\n inlineWarning: `filmstrip payload would have been ${(filmstripBytes / 1048576).toFixed(1)} MB (limit ${(INLINE_PAYLOAD_BUDGET / 1048576).toFixed(0)} MB) — files are on disk, Read them by path.`,\n }\n : {}),\n hint: '<1 = static, >5 = visible motion, >20 = vigorous (in motionMagnitude)',\n },\n null,\n 2,\n );\n if (!finalInline) return { content: [{ type: 'text', text }] };\n const content: any[] = [{ type: 'text', text }];\n for (const cam of res.cameraOrder) {\n const data = _filmstripBase64[cam];\n if (data) content.push({ type: 'image', data, mimeType: 'image/png' });\n }\n return { content };\n }\n case 'health': {\n let devServerOk = false;\n let manifestElements = [];\n try {\n const r = await fetch(`${DEV_URL}/__manifest`, { signal: AbortSignal.timeout(2000) });\n if (r.ok) {\n const m: any = await r.json();\n devServerOk = true;\n manifestElements = Object.keys(m?.elements ?? {});\n }\n } catch {}\n const mem = process.memoryUsage();\n return jsonResult({\n uptimeSec: Math.round((Date.now() - SERVER_START_TIME) / 1000),\n pid: process.pid,\n nodeVersion: process.version,\n project: PROJECT,\n devServer: { url: DEV_URL, reachable: devServerOk, manifestElements },\n memoryMB: {\n rss: +(mem.rss / 1048576).toFixed(1),\n heapUsed: +(mem.heapUsed / 1048576).toFixed(1),\n external: +(mem.external / 1048576).toFixed(1),\n },\n logPath: logger.logPath,\n recentErrors,\n });\n }\n case 'run_smoke':\n return jsonResult(await runSmoke({ element: args.element }));\n case 'import_element': {\n const parsed = z\n .object({ source: z.string(), name: z.string().optional() })\n .parse(args);\n return jsonResult(\n await importElement({ source: parsed.source as string, name: parsed.name }),\n );\n }\n case 'scaffold_from_gltf': {\n const parsed = z.object({ file: z.string(), name: z.string().optional() }).parse(args);\n return jsonResult(\n await scaffoldFromGltf({ file: parsed.file as string, name: parsed.name }),\n );\n }\n case 'read_uniform': {\n const parsed = z\n .object({\n element: z.string().optional(),\n path: z.string(),\n labUrl: z.string().optional(),\n })\n .parse(args);\n return jsonResult(\n await readUniform({\n element: parsed.element,\n path: parsed.path as string,\n labUrl: parsed.labUrl,\n }),\n );\n }\n case 'set_uniform': {\n const parsed = z\n .object({\n element: z.string().optional(),\n path: z.string(),\n value: z.union([z.number(), z.string(), z.boolean(), z.array(z.number())]),\n labUrl: z.string().optional(),\n })\n .parse(args);\n return jsonResult(\n await setUniform({\n element: parsed.element,\n path: parsed.path as string,\n value: parsed.value,\n labUrl: parsed.labUrl,\n }),\n );\n }\n case 'inspect_scene': {\n const parsed = z\n .object({\n element: z.string().optional(),\n maxNodes: z.number().int().min(1).max(5000).optional(),\n labUrl: z.string().optional(),\n fresh: z.boolean().optional(),\n })\n .parse(args);\n return jsonResult(await inspectScene(parsed));\n }\n case 'inspect': {\n const parsed = z\n .object({\n element: z.string(),\n camera: z.string().optional(),\n })\n .parse(args);\n return jsonResult(await inspect({ element: parsed.element, camera: parsed.camera }));\n }\n case 'open_selection': {\n const parsed = z\n .object({\n editor: z.string().optional(),\n })\n .parse(args);\n return jsonResult(await openSelection(parsed));\n }\n case 'snapshot': {\n const parsed = z\n .object({\n name: z.string(),\n message: z.string().optional(),\n })\n .parse(args);\n return jsonResult(await snapshot({ name: parsed.name, message: parsed.message }));\n }\n case 'restore': {\n const parsed = z.object({ name: z.string() }).parse(args);\n return jsonResult(await restore({ name: parsed.name }));\n }\n case 'list_snapshots':\n return jsonResult(await listSnapshots());\n case 'auto_tune': {\n const parsed = z\n .object({\n element: z.string(),\n knob: z.string(),\n range: z.tuple([z.number(), z.number()]),\n target_camera: z.string(),\n max_iterations: z.number().int().min(2).max(50).optional(),\n labUrl: z.string().optional(),\n })\n .parse(args);\n return jsonResult(\n await autoTune({\n element: parsed.element,\n knob: parsed.knob,\n range: [parsed.range[0], parsed.range[1]],\n target_camera: parsed.target_camera,\n max_iterations: parsed.max_iterations,\n labUrl: parsed.labUrl,\n }),\n );\n }\n case 'multi_tune': {\n const parsed = z\n .object({\n element: z.string(),\n knobs: z\n .array(\n z.object({\n key: z.string(),\n range: z.tuple([z.number(), z.number()]),\n start: z.number().optional(),\n }),\n )\n .min(1),\n target_camera: z.string(),\n max_cycles: z.number().int().min(1).max(6).optional(),\n per_knob_iters: z.number().int().min(2).max(20).optional(),\n compute_interactions: z.boolean().optional(),\n max_evaluations: z.number().int().min(2).max(300).optional(),\n labUrl: z.string().optional(),\n })\n .parse(args);\n return jsonResult(\n await multiTune({\n element: parsed.element as string,\n knobs: (\n parsed.knobs as Array<{ key: string; range: [number, number]; start?: number }>\n ).map((k) => ({\n key: k.key,\n range: [k.range[0], k.range[1]] as [number, number],\n start: k.start,\n })),\n target_camera: parsed.target_camera as string,\n max_cycles: parsed.max_cycles,\n per_knob_iters: parsed.per_knob_iters,\n compute_interactions: parsed.compute_interactions,\n max_evaluations: parsed.max_evaluations,\n labUrl: parsed.labUrl,\n }),\n );\n }\n case 'check_targets': {\n const parsed = z\n .object({ element: z.string(), labUrl: z.string().optional() })\n .parse(args);\n return jsonResult(\n await checkTargets({ element: parsed.element as string, labUrl: parsed.labUrl }),\n );\n }\n case 'set_scene_param': {\n const parsed = z\n .object({\n cameras: z\n .record(\n z.object({\n position: z.array(z.number()).optional(),\n target: z.array(z.number()).optional(),\n fov: z.number().optional(),\n }),\n )\n .optional(),\n knobs: z.record(z.union([z.number(), z.string(), z.boolean()])).optional(),\n elements: z.record(z.object({ enabled: z.boolean().optional() })).optional(),\n })\n .parse(args);\n return jsonResult(await setSceneParam(parsed));\n }\n case 'get_scene':\n return jsonResult(\n await getScene({\n devUrl: args.devUrl as string | undefined,\n labUrl: args.labUrl as string | undefined,\n }),\n );\n case 'add_element': {\n const parsed = z\n .object({\n name: z.string(),\n element: z.string().optional(),\n labUrl: z.string().optional(),\n })\n .parse(args);\n return jsonResult(\n await addElement({\n name: parsed.name,\n element: parsed.element,\n labUrl: parsed.labUrl,\n }),\n );\n }\n case 'remove_element': {\n const parsed = z\n .object({\n name: z.string(),\n element: z.string().optional(),\n labUrl: z.string().optional(),\n })\n .parse(args);\n return jsonResult(\n await removeElement({\n name: parsed.name,\n element: parsed.element,\n labUrl: parsed.labUrl,\n }),\n );\n }\n default:\n return { isError: true, content: [{ type: 'text', text: `Unknown tool: ${name}` }] };\n }\n })();\n finish('succeeded');\n return result;\n } catch (err: any) {\n finish('failed');\n recordError(`tool:${name}`, err);\n return {\n isError: true,\n content: [{ type: 'text', text: `${name} failed: ${err?.message ?? String(err)}` }],\n };\n }\n });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n // eslint-disable-next-line no-console\n console.error(`[triscope-mcp] connected. dev server: ${DEV_URL}, project: ${PROJECT}`);\n}\n","// Persistent Chromium pool. The MCP server keeps one Chromium child +\n// one CDP websocket alive across capture_views / diff_reference calls so\n// subsequent captures skip the 3-5 s cold start. First call lazy-spawns;\n// later calls navigate the existing page if the URL changed, otherwise reuse.\n//\n// One pool per MCP process. Disposed on process exit (kill -9 also clears\n// the user-data-dir via the OS, since /tmp is volatile).\n\nimport type { ChildProcessWithoutNullStreams } from 'node:child_process';\nimport { spawn } from 'node:child_process';\nimport { existsSync, readdirSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Logger } from './logger.js';\n\nconst wait = (ms) => new Promise((r) => setTimeout(r, ms));\n\nconst DEFAULT_CHROME_ARGS = [\n '--enable-unsafe-webgpu',\n '--ignore-gpu-blocklist',\n // Suppress the first-run wizard and the default-browser banner: both\n // can block the new window from rendering or trigger a different code\n // path that ignores --remote-debugging-port until dismissed. Both have\n // been seen to leave Chromium \"running\" but with no CDP endpoint open,\n // which manifests as a \"DevTools endpoint did not become ready\" error.\n '--no-first-run',\n '--no-default-browser-check',\n];\n\nexport function parseExtraChromeArgs(): string[] {\n const raw = process.env.TRISCOPE_CHROME_ARGS ?? '';\n if (!raw.trim()) return [];\n // Keep this intentionally simple: env-configured args are whitespace split.\n // Flags containing spaces should be wrapped in a tiny launcher script and\n // provided via CHROME_BIN instead.\n return raw.trim().split(/\\s+/).filter(Boolean);\n}\n\nexport function tailLines(text: string, maxLines = 24): string {\n const lines = text.trim().split(/\\r?\\n/).filter(Boolean);\n return lines.slice(-maxLines).join('\\n');\n}\n\nasync function readDevtoolsPages(port: number): Promise<any[] | null> {\n try {\n const pages = await fetch(`http://127.0.0.1:${port}/json`, {\n signal: AbortSignal.timeout(1000),\n }).then((r) => r.json());\n return Array.isArray(pages) && pages.length > 0 ? pages : null;\n } catch {\n return null;\n }\n}\n\nexport function cdpClient(ws) {\n const pending = new Map();\n let nextId = 0;\n ws.onmessage = (event) => {\n const msg = JSON.parse(event.data);\n if (msg.id && pending.has(msg.id)) {\n pending.get(msg.id)(msg);\n pending.delete(msg.id);\n }\n };\n // When the socket closes or errors mid-call, every pending request would\n // otherwise sit until its 20s timeout, blocking the next tool call for up to\n // 20s × N. Drain them immediately with a synthetic error so the failing tool\n // call rejects fast (and health() can report a sick pool).\n const drain = (reason: string) => {\n for (const cb of pending.values()) cb({ error: { message: reason } });\n pending.clear();\n };\n ws.onclose = (event) =>\n drain(`CDP WebSocket closed (code ${event?.code ?? '?'}) before the response arrived`);\n ws.onerror = (event) =>\n drain(`CDP WebSocket error (${event?.message ?? 'unknown'}) before the response arrived`);\n const call = (method, params = {}) =>\n new Promise((resolve, reject) => {\n const id = ++nextId;\n ws.send(JSON.stringify({ id, method, params }));\n const t = setTimeout(() => {\n pending.delete(id);\n reject(new Error(`CDP timeout for ${method}`));\n }, 20000);\n pending.set(id, (msg) => {\n clearTimeout(t);\n if (msg.error) reject(new Error(`${method}: ${msg.error.message}`));\n else resolve(msg);\n });\n });\n return call;\n}\n\n/**\n * Locate a Chromium-family browser on disk. Resolution order matches\n * puppeteer/playwright so users who already set one of these for their\n * existing tooling don't have to duplicate config:\n * 1. explicit arg\n * 2. CHROME_BIN\n * 3. PUPPETEER_EXECUTABLE_PATH\n * 4. OS-typical defaults (Windows: Program Files\\Google\\Chrome; macOS:\n * /Applications/Google Chrome.app; Linux: PATH-relative `chromium`)\n */\n\nexport function inferGraphicalEnv(): NodeJS.ProcessEnv {\n if (process.platform !== 'linux') return process.env;\n\n const env: NodeJS.ProcessEnv = { ...process.env };\n const uid = typeof process.getuid === 'function' ? process.getuid() : undefined;\n const runtimeDir = env.XDG_RUNTIME_DIR || (uid !== undefined ? `/run/user/${uid}` : undefined);\n\n if (runtimeDir && existsSync(runtimeDir)) {\n env.XDG_RUNTIME_DIR = runtimeDir;\n if (!env.WAYLAND_DISPLAY) {\n try {\n const waylandSocket = readdirSync(runtimeDir).find((name) => /^wayland-\\d+$/.test(name));\n if (waylandSocket) env.WAYLAND_DISPLAY = waylandSocket;\n } catch {\n /* best-effort */\n }\n }\n }\n\n if (!env.DISPLAY && existsSync('/tmp/.X11-unix/X0')) env.DISPLAY = ':0';\n return env;\n}\n\nexport function defaultChromeBinary(): string {\n if (process.platform === 'win32') {\n // Windows users normally install Chrome under Program Files. We don't\n // touch the filesystem to verify — Chrome's own startup will surface\n // an ENOENT clearly enough — but we pick the typical 64-bit path so\n // most installs Just Work without setting CHROME_BIN.\n return 'C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe';\n }\n if (process.platform === 'darwin') {\n return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';\n }\n return 'chromium';\n}\n\nexport function createBrowserPool({\n chromeBin = process.env.CHROME_BIN ??\n process.env.PUPPETEER_EXECUTABLE_PATH ??\n defaultChromeBinary(),\n port = Number(process.env.TRISCOPE_DEBUG_PORT ?? 9230),\n logger = undefined as Logger | undefined,\n} = {}) {\n let chrome: ChildProcessWithoutNullStreams | null = null;\n let chromeExit: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n let chromeStderr = '';\n let ws = null;\n let call = null;\n let currentUrl = null;\n // URL last confirmed to have rendered ≥1 real frame. Lets getPage skip the\n // warm-frame wait for an already-warm page (so e.g. auto_tune's capture loop\n // isn't slowed); reset whenever we navigate or force a reload.\n let lastWarmUrl: string | null = null;\n\n async function connectToPage(initialUrl: string, pages: any[]) {\n const page =\n pages.find((p) => p.url === initialUrl || p.url?.startsWith(initialUrl)) ?? pages[0];\n ws = new WebSocket(page.webSocketDebuggerUrl);\n await new Promise((res, rej) => {\n ws.onopen = res;\n ws.onerror = (e) => rej(new Error(`ws error: ${e?.message ?? 'unknown'}`));\n });\n call = cdpClient(ws);\n await call('Runtime.enable');\n await call('Page.enable');\n currentUrl = page.url ?? initialUrl;\n if (currentUrl !== initialUrl) await navigateIfNeeded(initialUrl);\n }\n\n function chromeLaunchArgs(profile: string, initialUrl: string): string[] {\n return [\n ...DEFAULT_CHROME_ARGS,\n ...parseExtraChromeArgs(),\n `--user-data-dir=${profile}`,\n `--remote-debugging-port=${port}`,\n '--window-size=1600,900',\n initialUrl,\n ];\n }\n\n async function ensureBrowser(initialUrl: string) {\n if (chrome && !chrome.killed && ws && ws.readyState === 1) return;\n\n // First attach to an already-running browser on the configured port. This\n // is the reliable path in sandboxed agents where opening a headed GUI may\n // require a user-approved launcher outside the MCP process.\n const existingPages = await readDevtoolsPages(port);\n if (existingPages) {\n logger?.info('browser', 'attaching to existing DevTools endpoint', {\n port,\n pages: existingPages.length,\n });\n await connectToPage(initialUrl, existingPages);\n return;\n }\n\n // Profile dir: pid + monotonic timestamp + random suffix → unique per\n // spawn so two concurrent MCP servers (or one that respawned after a\n // crash, leaving SingletonLock pointing at a dead PID) can never share\n // the same dir. Chromium's singleton check is path-based — same dir =\n // forwards URL to the \"running\" instance and exits without binding\n // --remote-debugging-port, which is the silent-fail mode that's hard\n // to diagnose.\n const profile = join(\n tmpdir(),\n `triscope-mcp-profile-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n );\n const args = chromeLaunchArgs(profile, initialUrl);\n chromeExit = null;\n chromeStderr = '';\n const browserEnv = inferGraphicalEnv();\n logger?.info('browser', 'spawning chromium', {\n chromeBin,\n port,\n profile,\n args,\n env: {\n DISPLAY: browserEnv.DISPLAY,\n WAYLAND_DISPLAY: browserEnv.WAYLAND_DISPLAY,\n XDG_RUNTIME_DIR: browserEnv.XDG_RUNTIME_DIR,\n },\n });\n chrome = spawn(chromeBin, args, { stdio: ['ignore', 'ignore', 'pipe'], env: browserEnv });\n chrome.stderr.on('data', (d) => {\n chromeStderr += String(d);\n if (chromeStderr.length > 12000) chromeStderr = chromeStderr.slice(-12000);\n });\n chrome.on('exit', (code, signal) => {\n chromeExit = { code, signal };\n logger?.warn('browser', 'chromium exited', { code, signal, stderr: tailLines(chromeStderr) });\n });\n chrome.on('error', (err) => {\n chromeExit = { code: 1, signal: null };\n chromeStderr += `\\nspawn error: ${(err as any)?.message ?? String(err)}`;\n logger?.error('browser', 'chromium spawn error', {\n message: (err as any)?.message ?? String(err),\n });\n });\n\n let pages: any[] | null = null;\n const start = Date.now();\n while (Date.now() - start < 10000) {\n pages = await readDevtoolsPages(port);\n if (pages) break;\n if (chromeExit) break;\n await wait(250);\n }\n if (!pages) {\n const stderr = tailLines(chromeStderr);\n const exit = chromeExit ? ` chromiumExit=${JSON.stringify(chromeExit)}` : '';\n // Silent-exit pattern: chromiumExit is null (process didn't die) but\n // port stayed closed. Almost always: sandboxed Chromium can't bind\n // network ports, or the singleton check forwarded the URL to a\n // (non-debuggable) sibling instance.\n const silentExit = !chromeExit && !pages;\n const hint = silentExit\n ? 'Chromium process is alive but DevTools never opened — usually the host sandbox is blocking the bind on TRISCOPE_DEBUG_PORT, or another Chromium instance is reusing the same profile dir. Workarounds: (1) pre-launch Chrome yourself with --remote-debugging-port=' +\n port +\n ' --enable-unsafe-webgpu — the MCP server auto-attaches to an existing endpoint when present; (2) set TRISCOPE_DEBUG_PORT to a port the sandbox permits.'\n : 'If this runs under Codex/Claude and headed launch still fails, pre-launch Chrome with --remote-debugging-port=' +\n port +\n ' or set TRISCOPE_CHROME_ARGS=--headless=new for non-interactive capture.';\n throw new Error(\n `DevTools endpoint did not become ready on 127.0.0.1:${port}.${exit}${stderr ? `\\nstderr:\\n${stderr}` : ''}\\n${hint}`,\n );\n }\n await connectToPage(initialUrl, pages);\n }\n\n function harnessNotMountedError(url: string) {\n return new Error(\n `window.__TRISCOPE__ did not mount within 10s on ${url}. ` +\n `Common causes: ` +\n `(1) the page never loaded — confirm the dev server is up and the URL is right (open it in a real browser tab); ` +\n `(2) WebGPU init failed — Linux Chrome needs --enable-unsafe-webgpu and either xvfb or a real display; ` +\n `(3) runLab() threw before mounting — check the #boot overlay text or the page console; ` +\n `(4) the lab page doesn't call runLab() at all — verify its entry script imports @triscope/core.`,\n );\n }\n\n // When the harness never mounts, check whether runLab() recorded a precise\n // mount failure (bad element / mount() threw) and surface THAT instead of the\n // generic timeout — turns \"not mounted within 10s\" into \"element X failed to\n // mount: <real error at line N>\".\n async function mountErrorOrTimeout(url: string): Promise<Error> {\n try {\n const r = await call('Runtime.evaluate', {\n expression: 'JSON.stringify(window.__TRISCOPE_MOUNT_ERROR__ ?? null)',\n returnByValue: true,\n });\n const me = JSON.parse(r.result.result.value);\n if (me?.message) {\n const probs = me.problems?.length\n ? `\\nContract problems:\\n - ${me.problems.join('\\n - ')}`\n : '';\n return new Error(`element \"${me.element ?? '?'}\" failed to mount: ${me.message}${probs}`);\n }\n } catch {\n /* fall through to the generic message */\n }\n return harnessNotMountedError(url);\n }\n\n async function navigateIfNeeded(url) {\n if (url === currentUrl) return;\n await call('Page.navigate', { url });\n lastWarmUrl = null; // new document → not warm until a frame renders\n // Wait for the harness to remount on the new page.\n const start = Date.now();\n while (Date.now() - start < 10000) {\n try {\n const probe = await call('Runtime.evaluate', {\n expression:\n '!!window.__TRISCOPE__ && (Object.keys(window.__TRISCOPE__.cameras || {}).length > 0 || typeof window.__TRISCOPE__.availableElements === \"function\")',\n returnByValue: true,\n });\n if (probe.result.result.value) {\n currentUrl = url;\n return;\n }\n } catch {}\n await wait(200);\n }\n throw await mountErrorOrTimeout(url);\n }\n\n async function waitForHarness() {\n for (let i = 0; i < 40; i++) {\n try {\n const probe = await call('Runtime.evaluate', {\n expression:\n '!!window.__TRISCOPE__ && (Object.keys(window.__TRISCOPE__.cameras || {}).length > 0 || typeof window.__TRISCOPE__.availableElements === \"function\")',\n returnByValue: true,\n });\n if (probe.result.result.value) return;\n } catch {\n // Transient \"execution context destroyed\" while a reload tears down the\n // old document — retry (mirrors navigateIfNeeded). Without this a probe\n // landing mid-teardown throws raw out of a fresh:true call.\n }\n await wait(250);\n }\n throw await mountErrorOrTimeout(currentUrl ?? '(initial page)');\n }\n\n // Wait for the harness to render a REAL frame before a capture. The mount\n // probe (waitForHarness/navigateIfNeeded) only proves window.__TRISCOPE__\n // exists — not that anything was drawn. Capturing in that gap yields a black\n // pre-render frame (observed: diff_reference came back black right after a\n // fresh navigate while a warmed capture_views rendered fine). Polls the\n // harness's monotonic framesRendered() (true on the first RAF), falling back\n // to fps>0 for older labs. Skips entirely when the page is already warm.\n async function waitForWarmFrame() {\n if (currentUrl && currentUrl === lastWarmUrl) return;\n for (let i = 0; i < 20; i++) {\n try {\n const probe = await call('Runtime.evaluate', {\n expression:\n '(function(){var t=window.__TRISCOPE__;if(!t)return 0;if(typeof t.framesRendered===\"function\")return t.framesRendered();try{return (t.sampleTelemetry&&t.sampleTelemetry().perf&&t.sampleTelemetry().perf.fps>0)?2:0;}catch(e){return 0;}})()',\n returnByValue: true,\n });\n if ((probe.result.result.value ?? 0) >= 2) {\n lastWarmUrl = currentUrl;\n return;\n }\n } catch {\n /* transient eval failure — retry */\n }\n await wait(100);\n }\n // Timed out without a confirmed frame — proceed anyway; per-camera\n // blackFrames detection in capture_views is the backstop. Cache as \"warm\"\n // so a perpetually-slow page doesn't re-block every capture.\n lastWarmUrl = currentUrl;\n }\n\n async function isAlive() {\n if (!chrome || chrome.killed || !ws || ws.readyState !== 1) return false;\n // Even with WS open, the page may be hung. Probe with a fast no-op\n // CDP call and short timeout so a stalled Chromium is detected here\n // rather than at the much heavier Page.navigate that follows.\n try {\n await Promise.race([\n call('Runtime.evaluate', { expression: '1', returnByValue: true }),\n new Promise((_, rej) => setTimeout(() => rej(new Error('alive probe timeout')), 1500)),\n ]);\n return true;\n } catch {\n return false;\n }\n }\n\n function disposeQuiet() {\n try {\n ws?.close();\n } catch {}\n try {\n if (chrome && !chrome.killed) chrome.kill();\n } catch {}\n ws = null;\n chrome = null;\n call = null;\n currentUrl = null;\n lastWarmUrl = null;\n chromeExit = null;\n chromeStderr = '';\n }\n\n return {\n /** Lazy-spawn Chromium (first call) or reuse it (subsequent). Always\n * guarantees the page is sitting on `url` with the harness mounted.\n * Self-heals: if the previous Chromium died externally (manual kill,\n * crash) the next call disposes the stale state and respawns. */\n async getPage(url, opts: { reload?: boolean } = {}) {\n const reload = opts?.reload === true;\n if (chrome && !(await isAlive())) {\n disposeQuiet();\n }\n if (!chrome) {\n await ensureBrowser(url);\n await waitForHarness();\n lastWarmUrl = null;\n } else if (reload && url === currentUrl) {\n // Force a fresh load of the SAME url to pick up source edits the pool's\n // cached page would otherwise miss (e.g. a *.lab.ts edit that doesn't\n // match the dev plugin's forceReloadOn regex).\n //\n // Page.reload resolves on *initiation*, not load — the old execution\n // context stays scriptable briefly, so waitForHarness/waitForWarmFrame\n // would otherwise confirm the STALE page (its __TRISCOPE__ + monotonic\n // framesRendered both still satisfy the probes) and we'd capture the\n // pre-edit content. Invalidate the old global first so the probes only\n // pass once the NEW document has mounted a fresh harness.\n try {\n await call('Runtime.evaluate', {\n expression: 'try { window.__TRISCOPE__ = undefined; } catch (e) {}',\n returnByValue: true,\n });\n } catch {\n /* old context already gone — fine */\n }\n lastWarmUrl = null;\n await call('Page.reload', { ignoreCache: true });\n await waitForHarness();\n } else {\n await navigateIfNeeded(url); // navigates only when url changed\n }\n await waitForWarmFrame();\n return { call };\n },\n /** Synchronous teardown. Safe to call multiple times. */\n dispose() {\n disposeQuiet();\n },\n };\n}\n","/**\n * Structured logger for the MCP server.\n *\n * Two output sinks:\n * - console.error (the existing convention — readable when run under\n * Claude Code, doesn't pollute stdout which is the MCP transport)\n * - /tmp/<project>-mcp.log with naive 1 MB rotation (rename to .1 then\n * truncate), so a long-running server keeps a persistent error trail\n * without leaking disk.\n *\n * Each entry is one JSON line:\n * {\"ts\":\"2026-05-17T15:00:00.000Z\",\"level\":\"error\",\"scope\":\"capture\",\n * \"msg\":\"…\",\"meta\":{…}}\n *\n * Designed for grep / jq, not for fancy log libraries.\n */\nimport { appendFileSync, existsSync, renameSync, statSync, unlinkSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\nexport type LogLevel = 'info' | 'warn' | 'error' | 'debug';\n\nexport interface LogEntry {\n ts: string;\n level: LogLevel;\n scope: string;\n msg: string;\n meta?: Record<string, unknown>;\n}\n\nexport interface Logger {\n info(scope: string, msg: string, meta?: Record<string, unknown>): void;\n warn(scope: string, msg: string, meta?: Record<string, unknown>): void;\n error(scope: string, msg: string, meta?: Record<string, unknown>): void;\n debug(scope: string, msg: string, meta?: Record<string, unknown>): void;\n readonly logPath: string;\n}\n\nconst MAX_LOG_BYTES = 1024 * 1024; // 1 MB\n\nexport function createLogger(project: string): Logger {\n const logPath = join(tmpdir(), `${project}-mcp.log`);\n\n function rotateIfNeeded(): void {\n try {\n if (!existsSync(logPath)) return;\n const size = statSync(logPath).size;\n if (size < MAX_LOG_BYTES) return;\n const rolled = `${logPath}.1`;\n if (existsSync(rolled)) {\n try {\n unlinkSync(rolled);\n } catch {\n /* best-effort */\n }\n }\n renameSync(logPath, rolled);\n } catch {\n /* never let logging crash the server */\n }\n }\n\n function write(entry: LogEntry): void {\n // console (stderr — stdout is taken by MCP stdio transport)\n const tag = `[triscope-mcp:${entry.level}:${entry.scope}]`;\n if (entry.level === 'error' || entry.level === 'warn') {\n // eslint-disable-next-line no-console\n console.error(tag, entry.msg, entry.meta ?? '');\n } else if (process.env.TRISCOPE_MCP_DEBUG) {\n // eslint-disable-next-line no-console\n console.error(tag, entry.msg, entry.meta ?? '');\n }\n // file\n try {\n rotateIfNeeded();\n appendFileSync(logPath, JSON.stringify(entry) + '\\n');\n } catch {\n /* swallow */\n }\n }\n\n function make(level: LogLevel) {\n return (scope: string, msg: string, meta?: Record<string, unknown>) =>\n write({ ts: new Date().toISOString(), level, scope, msg, meta });\n }\n\n return {\n info: make('info'),\n warn: make('warn'),\n error: make('error'),\n debug: make('debug'),\n logPath,\n };\n}\n","// Derivative-free optimization for knob tuning. Pure (the objective is an\n// injected async fn), so the search logic is unit-tested without a browser;\n// the server wires `evalAt` to set_knob → wait → capture → SSIM.\n\nexport interface GoldenResult {\n x: number;\n fx: number;\n history: Array<{ x: number; fx: number }>;\n}\n\nconst PHI = (1 + Math.sqrt(5)) / 2;\nconst INV_PHI = 1 / PHI;\n\n/** Golden-section search for the MAXIMUM of a unimodal `f` over [a, b]. */\nexport async function goldenSectionMax(\n f: (x: number) => Promise<number>,\n a: number,\n b: number,\n maxIter = 12,\n tol = 1e-4,\n): Promise<GoldenResult> {\n const history: Array<{ x: number; fx: number }> = [];\n const cache = new Map<string, number>();\n let budget = maxIter;\n const evalAt = async (x: number): Promise<number> => {\n const k = x.toFixed(6);\n const hit = cache.get(k);\n if (hit !== undefined) return hit;\n if (budget <= 0) return Number.NEGATIVE_INFINITY;\n budget--;\n const fx = await f(x);\n cache.set(k, fx);\n history.push({ x, fx });\n return fx;\n };\n let lo = a;\n let hi = b;\n let c = hi - (hi - lo) * INV_PHI;\n let d = lo + (hi - lo) * INV_PHI;\n let fc = await evalAt(c);\n let fd = await evalAt(d);\n while (budget > 0 && Math.abs(hi - lo) > tol * (b - a)) {\n if (fc > fd) {\n hi = d;\n d = c;\n fd = fc;\n c = hi - (hi - lo) * INV_PHI;\n fc = await evalAt(c);\n } else {\n lo = c;\n c = d;\n fc = fd;\n d = lo + (hi - lo) * INV_PHI;\n fd = await evalAt(d);\n }\n }\n let best = history[0] ?? { x: (a + b) / 2, fx: Number.NEGATIVE_INFINITY };\n for (const h of history) if (h.fx > best.fx) best = h;\n return { x: best.x, fx: best.fx, history };\n}\n\nexport interface KnobSpec {\n key: string;\n min: number;\n max: number;\n start: number;\n}\n\nexport interface DescentOptions {\n knobs: KnobSpec[];\n evalAt: (values: Record<string, number>) => Promise<number>;\n maxCycles?: number;\n perKnobIters?: number;\n /** Hard cap on total objective evaluations — bounds worst-case wall time. */\n maxEvaluations?: number;\n /** Stop early when a full cycle improves the score by less than this. */\n tol?: number;\n}\n\nexport interface DescentResult {\n best: Record<string, number>;\n bestScore: number;\n cycles: number;\n evaluations: number;\n history: Array<{ cycle: number; knob: string; value: number; score: number }>;\n}\n\n/**\n * Coordinate descent: optimize one knob at a time via golden-section, repeat\n * over all knobs until the per-cycle gain plateaus, `maxCycles` is hit, or the\n * hard `maxEvaluations` cap is reached. Greedy but robust for the smooth,\n * weakly-coupled knobs shader tuning involves; far cheaper than a grid.\n */\nexport async function coordinateDescent(opts: DescentOptions): Promise<DescentResult> {\n const { knobs, evalAt } = opts;\n const maxCycles = opts.maxCycles ?? 3;\n const perKnobIters = opts.perKnobIters ?? 12;\n const maxEvaluations = opts.maxEvaluations ?? Number.POSITIVE_INFINITY;\n const tol = opts.tol ?? 1e-3;\n\n const current: Record<string, number> = {};\n for (const k of knobs) current[k.key] = k.start;\n const history: DescentResult['history'] = [];\n let evaluations = 0;\n let bestScore = await evalAt({ ...current });\n evaluations++;\n let cycles = 0;\n\n for (let cycle = 0; cycle < maxCycles; cycle++) {\n cycles = cycle + 1;\n const cycleStart = bestScore;\n for (const k of knobs) {\n if (evaluations >= maxEvaluations)\n return { best: current, bestScore, cycles, evaluations, history };\n const f = async (x: number): Promise<number> => {\n if (evaluations >= maxEvaluations) return Number.NEGATIVE_INFINITY;\n evaluations++;\n const score = await evalAt({ ...current, [k.key]: x });\n history.push({ cycle, knob: k.key, value: x, score });\n return score;\n };\n const r = await goldenSectionMax(f, k.min, k.max, perKnobIters);\n if (r.fx >= bestScore) {\n current[k.key] = r.x;\n bestScore = r.fx;\n }\n }\n if (bestScore - cycleStart < tol) break; // plateaued\n }\n return { best: current, bestScore, cycles, evaluations, history };\n}\n\n/** True when an applied knob value matches the requested one (color-insensitive). */\nexport function knobMatches(requested: unknown, applied: unknown, tol = 1e-4): boolean {\n if (typeof requested === 'number' && typeof applied === 'number') {\n return Math.abs(requested - applied) <= tol;\n }\n if (typeof requested === 'string' && typeof applied === 'string') {\n return requested.toLowerCase() === applied.toLowerCase();\n }\n return requested === applied;\n}\n","// Reference photo primitives: save a reference PNG per (element, camera),\n// then compose a side-by-side diff against the current view + a scalar\n// mean-absolute-difference. Designed so the user can paste an image in chat\n// and have Claude pipe it straight into set_reference without an intermediate\n// file system dance — both `path` and `base64` inputs are accepted.\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { PNG } from 'pngjs';\n\nconst stripPrefix = (s) => s.replace(/^data:image\\/png;base64,/, '');\n\nfunction refsRoot(cwd) {\n return resolve(cwd, 'refs');\n}\n\nexport function refsPath(cwd, element, camera) {\n // Sanitize the camera name to a single path segment so any name the\n // element declares can become a filename safely.\n const safeCam = String(camera).replace(/[^A-Za-z0-9._-]/g, '_');\n return join(refsRoot(cwd), element, `${safeCam}.png`);\n}\n\nexport function refsMotionPaths(cwd, element, camera) {\n const safeCam = String(camera).replace(/[^A-Za-z0-9._-]/g, '_');\n const base = join(refsRoot(cwd), element);\n return {\n filmstrip: join(base, `${safeCam}.motion.png`),\n meta: join(base, `${safeCam}.motion.json`),\n };\n}\n\nexport function setReference({\n cwd,\n element,\n camera,\n path,\n base64,\n}: {\n cwd: string;\n element: string;\n camera: string;\n path?: string;\n base64?: string;\n}) {\n if (!element || !camera) throw new Error('element and camera are required');\n let bytes: Buffer;\n if (path) {\n if (!existsSync(path)) throw new Error(`reference file not found: ${path}`);\n bytes = readFileSync(path);\n } else if (base64) {\n bytes = Buffer.from(stripPrefix(base64), 'base64');\n } else {\n throw new Error('provide either path or base64');\n }\n const dest = refsPath(cwd, element, camera);\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, bytes);\n return { path: dest, bytes: bytes.length };\n}\n\nexport function decodePng(buffer) {\n return PNG.sync.read(buffer);\n}\n\nexport function nearestNeighborResize(src, targetW, targetH) {\n if (src.width === targetW && src.height === targetH) return src;\n const dst = new PNG({ width: targetW, height: targetH });\n for (let y = 0; y < targetH; y++) {\n const sy = Math.min(src.height - 1, Math.floor((y * src.height) / targetH));\n for (let x = 0; x < targetW; x++) {\n const sx = Math.min(src.width - 1, Math.floor((x * src.width) / targetW));\n const si = (sy * src.width + sx) * 4;\n const di = (y * targetW + x) * 4;\n dst.data[di] = src.data[si];\n dst.data[di + 1] = src.data[si + 1];\n dst.data[di + 2] = src.data[si + 2];\n dst.data[di + 3] = 255;\n }\n }\n return dst;\n}\n\nexport function composeSideBySide(left, right) {\n // Match heights to the smaller of the two so we don't grow the payload,\n // then concatenate horizontally with a 4-px black separator.\n const h = Math.min(left.height, right.height);\n const sep = 4;\n const lw = Math.round((left.width * h) / left.height);\n const rw = Math.round((right.width * h) / right.height);\n const w = lw + sep + rw;\n const L = nearestNeighborResize(left, lw, h);\n const R = nearestNeighborResize(right, rw, h);\n const out = new PNG({ width: w, height: h });\n // Fill background black (default is zeros — alpha would be 0; force 255).\n for (let i = 0; i < out.data.length; i += 4) out.data[i + 3] = 255;\n for (let y = 0; y < h; y++) {\n const orow = y * w * 4;\n const lrow = y * lw * 4;\n const rrow = y * rw * 4;\n L.data.copy(out.data, orow, lrow, lrow + lw * 4);\n R.data.copy(out.data, orow + (lw + sep) * 4, rrow, rrow + rw * 4);\n }\n return out;\n}\n\nexport function meanAbsDiff(a, b) {\n // Resize to a common 256x256 grid to keep the metric cheap and\n // resolution-independent.\n const W = 256;\n const H = 256;\n const A = nearestNeighborResize(a, W, H);\n const B = nearestNeighborResize(b, W, H);\n let sum = 0;\n const pixels = W * H * 3;\n for (let i = 0; i < W * H; i++) {\n const j = i * 4;\n sum += Math.abs(A.data[j] - B.data[j]);\n sum += Math.abs(A.data[j + 1] - B.data[j + 1]);\n sum += Math.abs(A.data[j + 2] - B.data[j + 2]);\n }\n return +(sum / pixels).toFixed(2);\n}\n\n/**\n * Mean Structural Similarity Index (SSIM) — perceptual metric that's\n * robust to mild brightness/contrast shifts and sensitive to structural\n * change. Returns a value in [-1, 1] where 1 = identical, 0 = no\n * correlation, negative = inverse. Most natural-image diffs land in\n * [0.5, 1.0]; below ~0.9 starts to look visibly different.\n *\n * We compute it over Rec.709 luminance on a 256×256 downsample (same as\n * meanAbsDiff for comparability), with non-overlapping 8×8 windows. The\n * three terms are luminance, contrast, and structure with the standard\n * stability constants K1=0.01, K2=0.03 against dynamic range L=255.\n *\n * This is the metric auto_tune optimizes against — meanAbsDiff is too\n * noisy for an optimizer (chases pixel-level glitter), SSIM tracks the\n * actual structure of what the human sees.\n */\nexport function ssim(a, b): number {\n const W = 256;\n const H = 256;\n const A = nearestNeighborResize(a, W, H);\n const B = nearestNeighborResize(b, W, H);\n const lumA = new Float32Array(W * H);\n const lumB = new Float32Array(W * H);\n for (let i = 0; i < W * H; i++) {\n const j = i * 4;\n lumA[i] = 0.2126 * A.data[j] + 0.7152 * A.data[j + 1] + 0.0722 * A.data[j + 2];\n lumB[i] = 0.2126 * B.data[j] + 0.7152 * B.data[j + 1] + 0.0722 * B.data[j + 2];\n }\n const L = 255;\n const C1 = (0.01 * L) ** 2;\n const C2 = (0.03 * L) ** 2;\n const WIN = 8;\n let total = 0;\n let count = 0;\n for (let wy = 0; wy < H; wy += WIN) {\n for (let wx = 0; wx < W; wx += WIN) {\n let muA = 0,\n muB = 0;\n for (let dy = 0; dy < WIN; dy++)\n for (let dx = 0; dx < WIN; dx++) {\n const i = (wy + dy) * W + (wx + dx);\n muA += lumA[i];\n muB += lumB[i];\n }\n muA /= WIN * WIN;\n muB /= WIN * WIN;\n let varA = 0,\n varB = 0,\n covAB = 0;\n for (let dy = 0; dy < WIN; dy++)\n for (let dx = 0; dx < WIN; dx++) {\n const i = (wy + dy) * W + (wx + dx);\n const da = lumA[i] - muA;\n const db = lumB[i] - muB;\n varA += da * da;\n varB += db * db;\n covAB += da * db;\n }\n varA /= WIN * WIN - 1;\n varB /= WIN * WIN - 1;\n covAB /= WIN * WIN - 1;\n const num = (2 * muA * muB + C1) * (2 * covAB + C2);\n const den = (muA * muA + muB * muB + C1) * (varA + varB + C2);\n total += num / den;\n count += 1;\n }\n }\n return +(total / count).toFixed(4);\n}\n\nexport interface TileGrid {\n /** SSIM per tile, grid[row][col], in [-1, 1] (1 = identical region). */\n grid: number[][];\n /** The single most-divergent tile — tells the agent WHERE frames differ. */\n worst: { row: number; col: number; ssim: number };\n min: number;\n max: number;\n mean: number;\n gridSize: number;\n}\n\n/**\n * Per-tile SSIM map. The scalar `ssim()` averages away the spatial detail it\n * computes per window; this surfaces a coarse `gridSize × gridSize` map (default\n * 8×8 over the 256×256 downsample, i.e. 32-px tiles) plus the worst tile, so an\n * agent can localize \"bow specular clipped, top-right\" instead of re-reading the\n * composite image. Same luminance + windowed-SSIM math as `ssim()`.\n */\nexport function ssimTileGrid(a, b, gridSize = 8): TileGrid {\n const W = 256;\n const H = 256;\n const A = nearestNeighborResize(a, W, H);\n const B = nearestNeighborResize(b, W, H);\n const lumA = new Float32Array(W * H);\n const lumB = new Float32Array(W * H);\n for (let i = 0; i < W * H; i++) {\n const j = i * 4;\n lumA[i] = 0.2126 * A.data[j] + 0.7152 * A.data[j + 1] + 0.0722 * A.data[j + 2];\n lumB[i] = 0.2126 * B.data[j] + 0.7152 * B.data[j + 1] + 0.0722 * B.data[j + 2];\n }\n const L = 255;\n const C1 = (0.01 * L) ** 2;\n const C2 = (0.03 * L) ** 2;\n const tile = Math.floor(W / gridSize);\n const grid: number[][] = [];\n let worst = { row: 0, col: 0, ssim: Number.POSITIVE_INFINITY };\n let min = Number.POSITIVE_INFINITY;\n let max = Number.NEGATIVE_INFINITY;\n let sum = 0;\n let count = 0;\n for (let r = 0; r < gridSize; r++) {\n const rowArr: number[] = [];\n for (let c = 0; c < gridSize; c++) {\n const x0 = c * tile;\n const y0 = r * tile;\n const n = tile * tile;\n let muA = 0;\n let muB = 0;\n for (let dy = 0; dy < tile; dy++)\n for (let dx = 0; dx < tile; dx++) {\n const i = (y0 + dy) * W + (x0 + dx);\n muA += lumA[i];\n muB += lumB[i];\n }\n muA /= n;\n muB /= n;\n let vA = 0;\n let vB = 0;\n let cov = 0;\n for (let dy = 0; dy < tile; dy++)\n for (let dx = 0; dx < tile; dx++) {\n const i = (y0 + dy) * W + (x0 + dx);\n const da = lumA[i] - muA;\n const db = lumB[i] - muB;\n vA += da * da;\n vB += db * db;\n cov += da * db;\n }\n vA /= n - 1;\n vB /= n - 1;\n cov /= n - 1;\n const s =\n ((2 * muA * muB + C1) * (2 * cov + C2)) / ((muA * muA + muB * muB + C1) * (vA + vB + C2));\n const sr = +s.toFixed(4);\n rowArr.push(sr);\n sum += sr;\n count += 1;\n if (sr < min) min = sr;\n if (sr > max) max = sr;\n if (sr < worst.ssim) worst = { row: r, col: c, ssim: sr };\n }\n grid.push(rowArr);\n }\n return {\n grid,\n worst,\n min: +min.toFixed(4),\n max: +max.toFixed(4),\n mean: +(sum / count).toFixed(4),\n gridSize,\n };\n}\n\nfunction heatColor(t: number): [number, number, number] {\n const x = Math.max(0, Math.min(1, t));\n // black → blue → yellow → red\n const stops: Array<[number, [number, number, number]]> = [\n [0, [0, 0, 0]],\n [0.33, [0, 0, 255]],\n [0.66, [255, 255, 0]],\n [1, [255, 0, 0]],\n ];\n for (let i = 1; i < stops.length; i++) {\n if (x <= stops[i][0]) {\n const [t0, c0] = stops[i - 1];\n const [t1, c1] = stops[i];\n const f = (x - t0) / (t1 - t0 || 1);\n return [\n Math.round(c0[0] + f * (c1[0] - c0[0])),\n Math.round(c0[1] + f * (c1[1] - c0[1])),\n Math.round(c0[2] + f * (c1[2] - c0[2])),\n ];\n }\n }\n return [255, 0, 0];\n}\n\n/**\n * Per-pixel difference heatmap (black=identical → blue → yellow → red=max\n * difference) on the 256×256 downsample. Returns a PNG Buffer the diff tool\n * ships as a second image block so the agent SEES where the frames diverge.\n */\nexport function composeDiffHeatmap(a, b, size = 256): Buffer {\n const A = nearestNeighborResize(a, size, size);\n const B = nearestNeighborResize(b, size, size);\n const out = new PNG({ width: size, height: size });\n for (let p = 0; p < size * size; p++) {\n const j = p * 4;\n const d =\n (Math.abs(A.data[j] - B.data[j]) +\n Math.abs(A.data[j + 1] - B.data[j + 1]) +\n Math.abs(A.data[j + 2] - B.data[j + 2])) /\n (3 * 255);\n const [r, g, bl] = heatColor(d);\n out.data[j] = r;\n out.data[j + 1] = g;\n out.data[j + 2] = bl;\n out.data[j + 3] = 255;\n }\n return PNG.sync.write(out);\n}\n\nexport function composeFilmstrip(frameBase64s: string[], opts: { sep?: number } = {}): Buffer {\n // Tile N frames horizontally with a 2-px black separator. Each frame is\n // resized to match the smallest source height (so payload stays bounded\n // even if frames are e.g. 1600x900 each). Returns a PNG Buffer.\n if (!Array.isArray(frameBase64s) || frameBase64s.length === 0) {\n throw new Error('composeFilmstrip: no frames');\n }\n const sep = opts.sep ?? 2;\n const frames = frameBase64s.map((b) => decodePng(Buffer.from(stripPrefix(b), 'base64')));\n const h = Math.min(...frames.map((f) => f.height));\n const resized = frames.map((f) =>\n nearestNeighborResize(f, Math.round((f.width * h) / f.height), h),\n );\n const totalW = resized.reduce((acc, f, i) => acc + f.width + (i > 0 ? sep : 0), 0);\n const out = new PNG({ width: totalW, height: h });\n for (let i = 0; i < out.data.length; i += 4) out.data[i + 3] = 255;\n let x = 0;\n for (let f = 0; f < resized.length; f++) {\n const img = resized[f];\n for (let y = 0; y < h; y++) {\n const srcRow = y * img.width * 4;\n const dstRow = (y * totalW + x) * 4;\n img.data.copy(out.data, dstRow, srcRow, srcRow + img.width * 4);\n }\n x += img.width + sep;\n }\n return PNG.sync.write(out);\n}\n\nexport function motionMagnitudeFromFrames(frameBase64s) {\n // Mean over consecutive-frame pairs of meanAbsDiff. 256x256 downscale.\n // 0 = no motion; >5 = visible; >20 = vigorous.\n if (!Array.isArray(frameBase64s) || frameBase64s.length < 2) return 0;\n const decoded = frameBase64s.map((b) => decodePng(Buffer.from(stripPrefix(b), 'base64')));\n let total = 0;\n for (let i = 1; i < decoded.length; i++) {\n total += meanAbsDiff(decoded[i - 1], decoded[i]);\n }\n return +(total / (decoded.length - 1)).toFixed(2);\n}\n\nexport function setReferenceMotion({ cwd, element, camera, frameBase64s, meta }) {\n if (!Array.isArray(frameBase64s) || frameBase64s.length < 2) {\n throw new Error('setReferenceMotion: need at least 2 frames');\n }\n const filmstrip = composeFilmstrip(frameBase64s);\n const { filmstrip: fpath, meta: mpath } = refsMotionPaths(cwd, element, camera);\n mkdirSync(dirname(fpath), { recursive: true });\n writeFileSync(fpath, filmstrip);\n writeFileSync(\n mpath,\n JSON.stringify(\n {\n frames: frameBase64s.length,\n ...meta,\n savedAt: new Date().toISOString(),\n },\n null,\n 2,\n ),\n );\n return { filmstripPath: fpath, metaPath: mpath, frames: frameBase64s.length };\n}\n\nexport function diffReferenceMotion({ cwd, element, camera, currentFrames }) {\n const { filmstrip: fpath, meta: mpath } = refsMotionPaths(cwd, element, camera);\n if (!existsSync(fpath)) {\n throw new Error(`no motion reference at ${fpath} — call set_reference_motion first`);\n }\n if (!Array.isArray(currentFrames) || currentFrames.length === 0) {\n throw new Error('currentFrames must be a non-empty array of base64 PNGs');\n }\n const refFilmstrip = decodePng(readFileSync(fpath));\n const curFilmstrip = decodePng(composeFilmstrip(currentFrames));\n // Stack vertically: reference on top, current on bottom, 4-px separator.\n const h = Math.min(refFilmstrip.height, curFilmstrip.height);\n const lw = Math.round((refFilmstrip.width * h) / refFilmstrip.height);\n const rw = Math.round((curFilmstrip.width * h) / curFilmstrip.height);\n const w = Math.max(lw, rw);\n const sep = 4;\n const composite = new PNG({ width: w, height: h * 2 + sep });\n for (let i = 0; i < composite.data.length; i += 4) composite.data[i + 3] = 255;\n const refResized = nearestNeighborResize(refFilmstrip, w, h);\n const curResized = nearestNeighborResize(curFilmstrip, w, h);\n for (let y = 0; y < h; y++) {\n refResized.data.copy(composite.data, y * w * 4, y * w * 4, (y + 1) * w * 4);\n curResized.data.copy(composite.data, (y + h + sep) * w * 4, y * w * 4, (y + 1) * w * 4);\n }\n // Per-frame mean abs diff if we have a saved frame count to align with.\n let meta = null;\n try {\n meta = existsSync(mpath) ? JSON.parse(readFileSync(mpath, 'utf8')) : null;\n } catch {\n /* tolerate corrupt meta */\n }\n const motionDiff = meanAbsDiff(refFilmstrip, curFilmstrip);\n return {\n refFilmstripPath: fpath,\n refMeta: meta,\n motionDiff,\n compositeBase64: PNG.sync.write(composite).toString('base64'),\n };\n}\n\nexport function diffReference({ cwd, element, camera, currentBase64 }) {\n const refPath = refsPath(cwd, element, camera);\n if (!existsSync(refPath)) {\n throw new Error(`no reference at ${refPath} — call set_reference first`);\n }\n if (!currentBase64) throw new Error('currentBase64 is required');\n const refPng = decodePng(readFileSync(refPath));\n const curPng = decodePng(Buffer.from(stripPrefix(currentBase64), 'base64'));\n const composite = composeSideBySide(refPng, curPng);\n const compositeBuf = PNG.sync.write(composite);\n const meanAbs = meanAbsDiff(refPng, curPng);\n const ssimScore = ssim(refPng, curPng);\n const tiles = ssimTileGrid(refPng, curPng);\n const heatmap = composeDiffHeatmap(refPng, curPng);\n return {\n camera,\n refPath,\n meanAbsDiff: meanAbs, // 0 = identical, 255 = max difference\n ssim: ssimScore, // 1 = identical, lower = more different\n // Spatial localization: 8×8 SSIM map + the single worst tile, so the agent\n // knows WHERE the divergence is without re-reading the composite image.\n tileGrid: tiles.grid,\n worstTile: tiles.worst,\n tileStats: { min: tiles.min, max: tiles.max, mean: tiles.mean },\n compositeBase64: compositeBuf.toString('base64'),\n heatmapBase64: heatmap.toString('base64'),\n };\n}\n","// Declarative \"definition of done\": evaluate per-camera convergence constraints\n// from .claude/element-targets.json against captured stats, so an agent gets a\n// machine-readable pass/fail instead of eyeballing screenshots. Pure + tested.\n\nexport interface Constraints {\n /** Minimum SSIM vs the stored reference (needs a reference; else skipped). */\n ssim?: number;\n /** Maximum meanAbsDiff vs the stored reference (needs a reference; else skipped). */\n meanAbsDiff?: number;\n /** Allowed mean-luminance band (from the GPU probe — always available). */\n luminance?: { min?: number; max?: number };\n /** Allowed dynamic-range band (from the GPU probe). */\n dynamicRange?: { min?: number; max?: number };\n}\n\nexport interface CapturedStats {\n ssim?: number;\n meanAbsDiff?: number;\n luminance?: number;\n dynamicRange?: number;\n}\n\nexport interface TargetResult {\n camera: string;\n constraint: string;\n op: '>=' | '<=' | 'range' | 'present';\n expected: unknown;\n actual: unknown;\n pass: boolean;\n skipped?: boolean;\n reason?: string;\n}\n\nexport interface TargetReport {\n checked: number;\n passed: number;\n allPassed: boolean;\n results: TargetResult[];\n}\n\nexport function evaluateTargets(\n targetsByCamera: Record<string, Constraints>,\n capturedByCamera: Record<string, CapturedStats>,\n): TargetReport {\n const results: TargetResult[] = [];\n\n for (const [camera, c] of Object.entries(targetsByCamera ?? {})) {\n const cap = capturedByCamera?.[camera];\n if (!cap) {\n results.push({\n camera,\n constraint: 'capture',\n op: 'present',\n expected: 'captured view',\n actual: undefined,\n pass: false,\n skipped: true,\n reason: 'camera not captured',\n });\n continue;\n }\n if (typeof c.ssim === 'number') {\n if (typeof cap.ssim === 'number') {\n results.push({\n camera,\n constraint: 'ssim',\n op: '>=',\n expected: c.ssim,\n actual: cap.ssim,\n pass: cap.ssim >= c.ssim,\n });\n } else {\n results.push({\n camera,\n constraint: 'ssim',\n op: '>=',\n expected: c.ssim,\n actual: undefined,\n pass: true,\n skipped: true,\n reason: 'no reference image — set_reference to enable',\n });\n }\n }\n if (typeof c.meanAbsDiff === 'number') {\n if (typeof cap.meanAbsDiff === 'number') {\n results.push({\n camera,\n constraint: 'meanAbsDiff',\n op: '<=',\n expected: c.meanAbsDiff,\n actual: cap.meanAbsDiff,\n pass: cap.meanAbsDiff <= c.meanAbsDiff,\n });\n } else {\n results.push({\n camera,\n constraint: 'meanAbsDiff',\n op: '<=',\n expected: c.meanAbsDiff,\n actual: undefined,\n pass: true,\n skipped: true,\n reason: 'no reference image — set_reference to enable',\n });\n }\n }\n pushBand(results, camera, 'luminance', c.luminance, cap.luminance);\n pushBand(results, camera, 'dynamicRange', c.dynamicRange, cap.dynamicRange);\n }\n\n const evaluated = results.filter((r) => !r.skipped);\n const passed = evaluated.filter((r) => r.pass).length;\n return {\n checked: evaluated.length,\n passed,\n allPassed: evaluated.every((r) => r.pass),\n results,\n };\n}\n\nfunction pushBand(\n out: TargetResult[],\n camera: string,\n constraint: string,\n band: { min?: number; max?: number } | undefined,\n actual: number | undefined,\n): void {\n if (!band) return;\n if (typeof actual !== 'number') {\n out.push({\n camera,\n constraint,\n op: 'range',\n expected: band,\n actual: undefined,\n pass: true,\n skipped: true,\n reason: 'probe unavailable',\n });\n return;\n }\n if (typeof band.min === 'number') {\n out.push({\n camera,\n constraint: `${constraint}.min`,\n op: '>=',\n expected: band.min,\n actual,\n pass: actual >= band.min,\n });\n }\n if (typeof band.max === 'number') {\n out.push({\n camera,\n constraint: `${constraint}.max`,\n op: '<=',\n expected: band.max,\n actual,\n pass: actual <= band.max,\n });\n }\n}\n"],"mappings":"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","names":["spawn","existsSync","mkdirSync","readFileSync","writeFileSync","tmpdir","join","PNG","resolve","logger","existsSync","tmpdir","join","existsSync","join","wait","join","existsSync","readFileSync","tmpdir","mkdirSync","writeFileSync","PNG","resolve","spawn","result"]}
|