@sightmap/mcp 0.7.1 → 0.9.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/dist/index.js CHANGED
@@ -191,6 +191,22 @@ async function handleUpdateView(input) {
191
191
  if (input.patch.memory_replace) {
192
192
  after.memory = [...input.patch.memory_replace];
193
193
  }
194
+ if (input.patch.name !== void 0) {
195
+ after.name = input.patch.name;
196
+ }
197
+ if (input.patch.route !== void 0) {
198
+ after.route = input.patch.route;
199
+ }
200
+ if (input.patch.components !== void 0) {
201
+ const seen = /* @__PURE__ */ new Set();
202
+ for (const c2 of input.patch.components) {
203
+ if (seen.has(c2.name)) {
204
+ throw new Error(`duplicate component name in patch: ${c2.name}`);
205
+ }
206
+ seen.add(c2.name);
207
+ }
208
+ after.components = input.patch.components;
209
+ }
194
210
  const nextViews = [...views];
195
211
  nextViews[idx] = after;
196
212
  const nextDoc = stripFragmentBrand(parsed);
@@ -210,23 +226,108 @@ function stripFragmentBrand(input) {
210
226
  return out;
211
227
  }
212
228
 
229
+ // src/tools/curate/add.ts
230
+ import { writeFile as writeFile2, readFile as readFile4, readdir as readdir2 } from "fs/promises";
231
+ import { resolve, join as join2 } from "path";
232
+ import {
233
+ format as format2,
234
+ canonicalize as canonicalize2
235
+ } from "@sightmap/sightmap";
236
+ async function handleAddView(input) {
237
+ await ensureNotExists(input.sightmapDir, input.view.name);
238
+ const filename = input.file ?? kebab(input.view.name) + ".yaml";
239
+ const path = join2(input.sightmapDir, filename);
240
+ const doc = {
241
+ version: 1,
242
+ views: [input.view]
243
+ };
244
+ const out = format2(doc);
245
+ const c = canonicalize2(out, { file: path });
246
+ const text = c.kind === "canonical" ? c.text : out;
247
+ await writeFile2(path, text, "utf8");
248
+ return { ok: true, file: path, written: input.view };
249
+ }
250
+ async function ensureNotExists(dir, name) {
251
+ let files;
252
+ try {
253
+ files = await readdir2(dir);
254
+ } catch {
255
+ return;
256
+ }
257
+ for (const f of files) {
258
+ if (!f.endsWith(".yaml")) continue;
259
+ const text = await readFile4(resolve(dir, f), "utf8");
260
+ if (new RegExp(`(^|\\n)\\s*-\\s+name:\\s+${escapeRe(name)}(\\s|$)`).test(text)) {
261
+ throw new Error(`view "${name}" already exists in ${f}`);
262
+ }
263
+ }
264
+ }
265
+ function kebab(s) {
266
+ return s.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
267
+ }
268
+ function escapeRe(s) {
269
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
270
+ }
271
+
272
+ // src/tools/curate/remove.ts
273
+ import { readFile as readFile5, writeFile as writeFile3, unlink, readdir as readdir3 } from "fs/promises";
274
+ import { resolve as resolve2 } from "path";
275
+ import {
276
+ parse as parse4,
277
+ format as format3,
278
+ canonicalize as canonicalize3
279
+ } from "@sightmap/sightmap";
280
+ async function handleDeleteView(input) {
281
+ const entries = await readdir3(input.sightmapDir);
282
+ for (const entry of entries) {
283
+ if (!entry.endsWith(".yaml")) continue;
284
+ const path = resolve2(input.sightmapDir, entry);
285
+ const text = await readFile5(path, "utf8");
286
+ const parsed = parse4(text, { sourceFile: path });
287
+ const views = parsed.views ?? [];
288
+ const idx = views.findIndex((v) => v.name === input.name);
289
+ if (idx < 0) continue;
290
+ const remaining = views.filter((_, i) => i !== idx);
291
+ if (remaining.length === 0) {
292
+ await unlink(path);
293
+ return { ok: true, file: path, fileDeleted: true };
294
+ }
295
+ const nextDoc = stripFragmentBrand2(parsed);
296
+ nextDoc.views = remaining;
297
+ const out = format3(nextDoc);
298
+ const c = canonicalize3(out, { file: path });
299
+ const finalText = c.kind === "canonical" ? c.text : out;
300
+ await writeFile3(path, finalText, "utf8");
301
+ return { ok: true, file: path, fileDeleted: false };
302
+ }
303
+ throw new Error(`view "${input.name}" not found in ${input.sightmapDir}`);
304
+ }
305
+ function stripFragmentBrand2(input) {
306
+ const out = {};
307
+ for (const k of Object.keys(input)) {
308
+ if (k === "__brand" || k === "__sourceFile") continue;
309
+ out[k] = input[k];
310
+ }
311
+ return out;
312
+ }
313
+
213
314
  // src/tools/curate/init.ts
214
- import { mkdir, writeFile as writeFile2, access } from "fs/promises";
215
- import { join as join2 } from "path";
315
+ import { mkdir, writeFile as writeFile4, access } from "fs/promises";
316
+ import { join as join3 } from "path";
216
317
 
217
318
  // src/curate/scaffolder.ts
218
- import { format as format2, canonicalize as canonicalize2 } from "@sightmap/sightmap";
319
+ import { format as format4, canonicalize as canonicalize4 } from "@sightmap/sightmap";
219
320
  function makeStarterSightmap() {
220
- const text = format2({ version: 1 });
221
- const c = canonicalize2(text, { file: "app.yaml" });
321
+ const text = format4({ version: 1 });
322
+ const c = canonicalize4(text, { file: "app.yaml" });
222
323
  return c.kind === "canonical" ? c.text : text;
223
324
  }
224
325
 
225
326
  // src/tools/curate/init.ts
226
327
  async function handleInitProject(input) {
227
328
  const root = input.dir ?? process.cwd();
228
- const sightmapDir = join2(root, ".sightmap");
229
- const appFile = join2(sightmapDir, "app.yaml");
329
+ const sightmapDir = join3(root, ".sightmap");
330
+ const appFile = join3(sightmapDir, "app.yaml");
230
331
  if (input.force !== true) {
231
332
  let exists = false;
232
333
  try {
@@ -241,10 +342,485 @@ async function handleInitProject(input) {
241
342
  }
242
343
  }
243
344
  await mkdir(sightmapDir, { recursive: true });
244
- await writeFile2(appFile, makeStarterSightmap(), "utf8");
345
+ await writeFile4(appFile, makeStarterSightmap(), "utf8");
245
346
  return { ok: true, files: [appFile] };
246
347
  }
247
348
 
349
+ // src/tools/runtime/snapshot.ts
350
+ async function handleRuntimeSnapshot(input, deps = {}) {
351
+ if (input.source.kind === "endpoint") {
352
+ return runEndpoint(input.source);
353
+ }
354
+ if (input.source.kind === "literal") {
355
+ return runLiteral(input.source);
356
+ }
357
+ return runBrowser(input.source, deps);
358
+ }
359
+ async function runEndpoint(source) {
360
+ const res = await fetch(source.url);
361
+ if (res.status === 404) {
362
+ let detail = "";
363
+ try {
364
+ const body = await res.json();
365
+ detail = body.error ?? "";
366
+ } catch {
367
+ }
368
+ throw new Error(
369
+ `no snapshot cached yet at ${source.url}${detail ? `: ${detail}` : ""}`
370
+ );
371
+ }
372
+ if (!res.ok) {
373
+ throw new Error(`snapshot fetch failed: HTTP ${res.status}`);
374
+ }
375
+ const snapshot = await res.json();
376
+ return { ok: true, snapshot, source };
377
+ }
378
+ var REQUIRED_SNAPSHOT_FIELDS = [
379
+ "capturedAt",
380
+ "route",
381
+ "components",
382
+ "markers",
383
+ "unmarkedCandidates"
384
+ ];
385
+ function runLiteral(source) {
386
+ validateSnapshotShape(source.snapshot, "literal");
387
+ return { ok: true, snapshot: source.snapshot, source };
388
+ }
389
+ function validateSnapshotShape(value, label) {
390
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
391
+ throw new Error(
392
+ `${label} snapshot: expected an object with fields { capturedAt, route, components, markers, unmarkedCandidates }; got ${value === null ? "null" : Array.isArray(value) ? "array" : typeof value}`
393
+ );
394
+ }
395
+ const s = value;
396
+ for (const field of REQUIRED_SNAPSHOT_FIELDS) {
397
+ if (!(field in s)) {
398
+ throw new Error(`${label} snapshot: missing required field \`${field}\``);
399
+ }
400
+ }
401
+ if (!Array.isArray(s["components"])) {
402
+ throw new Error(`${label} snapshot: \`components\` must be an array`);
403
+ }
404
+ if (!Array.isArray(s["markers"])) {
405
+ throw new Error(`${label} snapshot: \`markers\` must be an array`);
406
+ }
407
+ if (!Array.isArray(s["unmarkedCandidates"])) {
408
+ throw new Error(`${label} snapshot: \`unmarkedCandidates\` must be an array`);
409
+ }
410
+ }
411
+ async function runBrowser(source, deps) {
412
+ if (deps.upstream === void 0) {
413
+ throw new Error(
414
+ "browser-mode snapshot requires an upstream MCP server (e.g., @playwright/mcp). Run sightmap-mcp without `--curate-only` so the @playwright/mcp passthrough is wired up."
415
+ );
416
+ }
417
+ const upstream = deps.upstream;
418
+ const wantInject = source.inject === true;
419
+ const allowAutoInject = source.inject === void 0;
420
+ const urls = source.routes !== void 0 && source.routes.length > 0 ? source.routes.map((r) => absolutize(r, source.url)) : [source.url];
421
+ const captures = [];
422
+ for (const targetUrl of urls) {
423
+ const captureOpts = {
424
+ forceInject: wantInject,
425
+ autoInject: allowAutoInject
426
+ };
427
+ if (deps.getInjectScript !== void 0) {
428
+ captureOpts.getInjectScript = deps.getInjectScript;
429
+ }
430
+ const cap = await captureOneUrl(upstream, targetUrl, captureOpts);
431
+ validateSnapshotShape(cap, "browser");
432
+ captures.push({ url: targetUrl, snapshot: cap });
433
+ }
434
+ if (source.routes === void 0 || source.routes.length === 0) {
435
+ return { ok: true, snapshot: captures[0].snapshot, source };
436
+ }
437
+ return { ok: true, snapshots: captures, source };
438
+ }
439
+ function absolutize(routeOrUrl, baseUrl) {
440
+ try {
441
+ return new URL(routeOrUrl).toString();
442
+ } catch {
443
+ const base = new URL(baseUrl);
444
+ return new URL(routeOrUrl, base).toString();
445
+ }
446
+ }
447
+ async function captureOneUrl(upstream, url, opts) {
448
+ const navResult = await upstream.callTool("browser_navigate", { url });
449
+ if (navResult.isError === true) {
450
+ throw new Error(
451
+ `browser_navigate to ${url} failed: ${navResult.content[0]?.text ?? "unknown error"}`
452
+ );
453
+ }
454
+ const probe = await evalAndDecode(
455
+ upstream,
456
+ `() => typeof (window.__sightmap__ && window.__sightmap__.snapshot)`
457
+ );
458
+ const hasHook = probe === "function";
459
+ if (!hasHook && (opts.forceInject || opts.autoInject)) {
460
+ if (opts.getInjectScript === void 0) {
461
+ throw new Error(
462
+ "browser-mode snapshot: page has no window.__sightmap__ and no inject script provider was configured. Install @sightmap/react in the target app, or wire `getInjectScript` into the MCP server."
463
+ );
464
+ }
465
+ const script = await opts.getInjectScript();
466
+ const wrapped = `() => { ${script}
467
+ ; return typeof (window.__sightmap__ && window.__sightmap__.snapshot); }`;
468
+ const injectResult = await evalAndDecode(upstream, wrapped);
469
+ if (injectResult !== "function") {
470
+ throw new Error(
471
+ `browser-mode snapshot: inject script did not install window.__sightmap__.snapshot (typeof after inject: ${String(injectResult)}). The target page may not be a React app.`
472
+ );
473
+ }
474
+ } else if (!hasHook && opts.forceInject === false && opts.autoInject === false) {
475
+ throw new Error(
476
+ "browser-mode snapshot: page has no window.__sightmap__.snapshot and `inject: false` was set. Either install @sightmap/react in the app or pass `inject: true`."
477
+ );
478
+ }
479
+ const snap = await evalAndDecode(
480
+ upstream,
481
+ `() => JSON.parse(JSON.stringify(window.__sightmap__.snapshot()))`
482
+ );
483
+ return snap;
484
+ }
485
+ async function evalAndDecode(upstream, fnSource) {
486
+ const r = await upstream.callTool("browser_evaluate", { function: fnSource });
487
+ if (r.isError === true) {
488
+ throw new Error(
489
+ `browser_evaluate failed: ${r.content[0]?.text ?? "unknown error"}`
490
+ );
491
+ }
492
+ const text = r.content.map((b) => b.text).join("\n");
493
+ return decodeEvalText(text);
494
+ }
495
+ function decodeEvalText(text) {
496
+ const afterResult = text.split(/^###\s*Result/im)[1] ?? text;
497
+ const trimmed = afterResult.trim();
498
+ if (trimmed.length === 0) return void 0;
499
+ for (let end = trimmed.length; end > 0; end--) {
500
+ try {
501
+ return JSON.parse(trimmed.slice(0, end));
502
+ } catch {
503
+ }
504
+ }
505
+ return void 0;
506
+ }
507
+
508
+ // src/runtime/inject-script.ts
509
+ import { createRequire } from "module";
510
+ import { readFile as readFile6 } from "fs/promises";
511
+ import { dirname, resolve as resolve3 } from "path";
512
+ var cachedScript;
513
+ async function getInjectScript() {
514
+ if (cachedScript !== void 0) return cachedScript;
515
+ const bippyIife = await loadBippyIife();
516
+ cachedScript = `${bippyIife}
517
+ ${BOOTSTRAP_SRC}`;
518
+ return cachedScript;
519
+ }
520
+ async function loadBippyIife() {
521
+ const require2 = createRequire(import.meta.url);
522
+ const bippyPkgJson = require2.resolve("bippy/package.json");
523
+ const iifePath = resolve3(dirname(bippyPkgJson), "dist/index.iife.js");
524
+ return readFile6(iifePath, "utf8");
525
+ }
526
+ var BOOTSTRAP_SRC = String.raw`
527
+ (function () {
528
+ if (typeof window === "undefined") return;
529
+ if (!window.Bippy || typeof window.Bippy.instrument !== "function") return;
530
+ if (window.__sightmap__ && typeof window.__sightmap__.snapshot === "function") {
531
+ // Already installed (e.g. @sightmap/react is present). Don't double-wire.
532
+ return;
533
+ }
534
+
535
+ var trackedRoots = new Set();
536
+ window.Bippy.instrument({
537
+ onCommitFiberRoot: function (_id, root) {
538
+ trackedRoots.add(root);
539
+ },
540
+ });
541
+
542
+ var FRAMEWORK_NOISE = new Set([
543
+ "Routes", "Route", "RenderedRoute", "Outlet", "BrowserRouter",
544
+ "Router", "RouterProvider", "DataRouterProvider", "RouterProviderImpl",
545
+ "LinkWithRef", "StrictMode", "SightmapProvider", "Fragment", "Anonymous",
546
+ "Suspense", "ErrorBoundary", "Provider", "Consumer",
547
+ "ThemeProvider", "Hydration", "HydrateFallback",
548
+ "RemixErrorBoundary", "HydratedRouter", "DataRoutes",
549
+ "WithHydrateFallbackProps2", "RenderErrorBoundary", "Layout",
550
+ ]);
551
+
552
+ var HOST_PORTAL_TAG = 4;
553
+
554
+ function cssEsc(v) { return String(v).replace(/"/g, '\\"'); }
555
+ function isHumanShapedId(id) {
556
+ if (/[0-9]{6,}/.test(id)) return false;
557
+ if (/^[a-z]+-[a-f0-9]{8,}/i.test(id)) return false;
558
+ if (/:r[0-9a-z]+:/i.test(id)) return false;
559
+ return true;
560
+ }
561
+ function rankSelectors(el) {
562
+ var out = [];
563
+ var dsm = el.getAttribute("data-sightmap");
564
+ if (dsm !== null) {
565
+ out.push({ selector: '[data-sightmap="' + cssEsc(dsm) + '"]', stability: "high", source: "data-sightmap" });
566
+ }
567
+ ["data-testid", "data-cy", "data-test"].forEach(function (attr) {
568
+ var v = el.getAttribute(attr);
569
+ if (v !== null) {
570
+ out.push({ selector: "[" + attr + '="' + cssEsc(v) + '"]', stability: "high", source: attr });
571
+ }
572
+ });
573
+ var role = el.getAttribute("role");
574
+ var aria = el.getAttribute("aria-label");
575
+ if (role && aria) {
576
+ out.push({ selector: '[role="' + cssEsc(role) + '"][aria-label="' + cssEsc(aria) + '"]', stability: "medium", source: "aria" });
577
+ } else if (aria) {
578
+ out.push({ selector: '[aria-label="' + cssEsc(aria) + '"]', stability: "medium", source: "aria-label" });
579
+ }
580
+ var name = el.getAttribute("name");
581
+ if (name !== null && /^(form|input|button|select|textarea|nav)$/i.test(el.tagName)) {
582
+ out.push({ selector: el.tagName.toLowerCase() + '[name="' + cssEsc(name) + '"]', stability: "medium", source: "semantic-name" });
583
+ }
584
+ if (el.id && isHumanShapedId(el.id)) {
585
+ out.push({ selector: "#" + cssEsc(el.id), stability: "high", source: "id" });
586
+ }
587
+ return out;
588
+ }
589
+
590
+ function findHostElementForFiber(fiber) {
591
+ if (!fiber.child) return null;
592
+ var stack = [fiber.child];
593
+ var walks = 0;
594
+ while (stack.length > 0 && walks < 5000) {
595
+ walks++;
596
+ var f = stack.pop();
597
+ if (!f) continue;
598
+ if (f.sibling) stack.push(f.sibling);
599
+ if (f.tag === HOST_PORTAL_TAG) continue;
600
+ var sn = f.stateNode;
601
+ if (sn && typeof sn === "object" && "tagName" in sn && document.contains(sn)) {
602
+ return sn;
603
+ }
604
+ if (f.child) stack.push(f.child);
605
+ }
606
+ return null;
607
+ }
608
+
609
+ function bridgeDomToFiber(el) {
610
+ for (var i = 0, keys = Object.keys(el); i < keys.length; i++) {
611
+ if (keys[i].indexOf("__reactFiber$") === 0) return el[keys[i]] || null;
612
+ }
613
+ return null;
614
+ }
615
+
616
+ function nearestCompositeName(fiber) {
617
+ var f = fiber, walks = 0;
618
+ while (f && walks < 50) {
619
+ if (window.Bippy.isCompositeFiber(f)) {
620
+ var n = window.Bippy.getDisplayName(f);
621
+ if (n) return n;
622
+ }
623
+ f = f.return;
624
+ walks++;
625
+ }
626
+ return undefined;
627
+ }
628
+
629
+ function domDepth(el) {
630
+ var d = 0, cur = el.parentElement;
631
+ while (cur && cur !== document.body) { d++; cur = cur.parentElement; }
632
+ return d;
633
+ }
634
+
635
+ function collectComponents(rootFiber) {
636
+ var out = [];
637
+ var depthByFiber = new Map();
638
+ depthByFiber.set(rootFiber, 0);
639
+ window.Bippy.traverseFiber(rootFiber, function (f) {
640
+ var depth = depthByFiber.get(f) || 0;
641
+ var c = f.child;
642
+ while (c) { depthByFiber.set(c, depth + 1); c = c.sibling; }
643
+ if (!window.Bippy.isCompositeFiber(f)) return false;
644
+ var name = window.Bippy.getDisplayName(f);
645
+ if (!name) return false;
646
+ var childNames = [];
647
+ var cc = f.child;
648
+ while (cc) {
649
+ if (window.Bippy.isCompositeFiber(cc)) {
650
+ var n = window.Bippy.getDisplayName(cc);
651
+ if (n) childNames.push(n);
652
+ }
653
+ cc = cc.sibling;
654
+ }
655
+ out.push({ displayName: name, depth: depth, children: childNames });
656
+ return false;
657
+ });
658
+ return out;
659
+ }
660
+
661
+ function collectMarkers() {
662
+ var out = [];
663
+ if (typeof document === "undefined") return out;
664
+ var els = document.querySelectorAll("[data-sightmap]");
665
+ for (var i = 0; i < els.length; i++) {
666
+ var el = els[i];
667
+ var name = el.getAttribute("data-sightmap") || "";
668
+ var fiber = bridgeDomToFiber(el);
669
+ var nc = nearestCompositeName(fiber);
670
+ var marker = {
671
+ name: name,
672
+ hostTag: el.tagName.toLowerCase(),
673
+ domDepth: domDepth(el),
674
+ candidateSelectors: rankSelectors(el),
675
+ };
676
+ if (nc !== undefined) marker.nearestComponent = nc;
677
+ out.push(marker);
678
+ }
679
+ return out;
680
+ }
681
+
682
+ function collectUnmarkedCandidates(rootFiber) {
683
+ var out = [];
684
+ var seen = new Set();
685
+ window.Bippy.traverseFiber(rootFiber, function (f) {
686
+ if (!window.Bippy.isCompositeFiber(f)) return false;
687
+ var name = window.Bippy.getDisplayName(f);
688
+ if (!name || seen.has(name) || FRAMEWORK_NOISE.has(name)) return false;
689
+ seen.add(name);
690
+ var hostEl = findHostElementForFiber(f);
691
+ if (!hostEl) return false;
692
+ var selectors = rankSelectors(hostEl);
693
+ if (selectors.length === 0) return false;
694
+ out.push({
695
+ displayName: name,
696
+ hostTag: hostEl.tagName.toLowerCase(),
697
+ selectors: selectors,
698
+ domDepth: domDepth(hostEl),
699
+ });
700
+ return false;
701
+ });
702
+ return out;
703
+ }
704
+
705
+ function snapshot() {
706
+ var roots = Array.from(trackedRoots);
707
+ var now = new Date().toISOString();
708
+ var loc = (typeof window !== "undefined" && window.location)
709
+ ? (window.location.pathname + (window.location.search || ""))
710
+ : "?";
711
+ if (roots.length === 0) {
712
+ return { capturedAt: now, route: loc === "?" ? "?" : loc, commits: 0, components: [], markers: [], unmarkedCandidates: [] };
713
+ }
714
+ var root = roots.find(function (r) { return r.current && r.current.child !== null; }) || roots[0];
715
+ if (!root) {
716
+ return { capturedAt: now, route: loc === "?" ? "?" : loc, commits: 0, components: [], markers: [], unmarkedCandidates: [] };
717
+ }
718
+ var rootFiber = root.current;
719
+ return {
720
+ capturedAt: now,
721
+ route: loc,
722
+ commits: roots.length,
723
+ components: collectComponents(rootFiber),
724
+ markers: collectMarkers(),
725
+ unmarkedCandidates: collectUnmarkedCandidates(rootFiber),
726
+ };
727
+ }
728
+
729
+ window.__sightmap__ = { snapshot: snapshot };
730
+ })();
731
+ `;
732
+
733
+ // src/tools/propose/store.ts
734
+ var ProposalStore = class {
735
+ views = [];
736
+ components = [];
737
+ nextId = 1;
738
+ mintId(prefix) {
739
+ return `${prefix}_${this.nextId++}`;
740
+ }
741
+ appendView(p) {
742
+ const v = { id: this.mintId("v"), ...p };
743
+ this.views.push(v);
744
+ return v;
745
+ }
746
+ appendComponent(p) {
747
+ const c = { id: this.mintId("c"), ...p };
748
+ this.components.push(c);
749
+ return c;
750
+ }
751
+ review() {
752
+ return { views: [...this.views], components: [...this.components] };
753
+ }
754
+ commit(input = {}) {
755
+ if (!input.ids) {
756
+ const out = this.review();
757
+ this.views = [];
758
+ this.components = [];
759
+ return out;
760
+ }
761
+ const selected = new Set(input.ids);
762
+ const consumedViews = this.views.filter((v) => selected.has(v.id));
763
+ const consumedComponents = this.components.filter((c) => selected.has(c.id));
764
+ this.views = this.views.filter((v) => !selected.has(v.id));
765
+ this.components = this.components.filter((c) => !selected.has(c.id));
766
+ return { views: consumedViews, components: consumedComponents };
767
+ }
768
+ };
769
+ var proposalStore = new ProposalStore();
770
+
771
+ // src/tools/propose/view.ts
772
+ async function handleProposeView(input) {
773
+ const v = proposalStore.appendView(input);
774
+ return { ok: true, id: v.id };
775
+ }
776
+
777
+ // src/tools/propose/component.ts
778
+ async function handleProposeComponent(input) {
779
+ const c = proposalStore.appendComponent(input);
780
+ return { ok: true, id: c.id };
781
+ }
782
+
783
+ // src/tools/propose/review.ts
784
+ async function handleReviewProposals() {
785
+ return proposalStore.review();
786
+ }
787
+
788
+ // src/tools/propose/commit.ts
789
+ async function handleCommitProposals(input) {
790
+ if (input.dry_run === true) {
791
+ const peek = proposalStore.review();
792
+ const selectedIds = input.ids ? new Set(input.ids) : null;
793
+ const filtered = {
794
+ views: selectedIds ? peek.views.filter((v) => selectedIds.has(v.id)) : peek.views,
795
+ components: selectedIds ? peek.components.filter((c) => selectedIds.has(c.id)) : peek.components
796
+ };
797
+ return { ok: true, committed: filtered, writes: [] };
798
+ }
799
+ const consumed = proposalStore.commit(
800
+ input.ids ? { ids: input.ids } : {}
801
+ );
802
+ const writes = [];
803
+ for (const v of consumed.views) {
804
+ const r = await handleAddView({
805
+ sightmapDir: input.sightmapDir,
806
+ view: {
807
+ name: v.name ?? deriveName(v.route),
808
+ route: v.route,
809
+ components: [],
810
+ ...v.intent !== void 0 ? { intent: v.intent } : {},
811
+ ...v.memory_notes && v.memory_notes.length > 0 ? { memory: v.memory_notes } : {}
812
+ }
813
+ });
814
+ writes.push({ kind: "view", file: r.file });
815
+ }
816
+ return { ok: true, committed: consumed, writes };
817
+ }
818
+ function deriveName(route) {
819
+ const parts = route.replace(/^\/+|\/+$/g, "").split("/").filter((p) => p.length > 0);
820
+ const last = parts[parts.length - 1] ?? "Index";
821
+ return last.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).replace(/\s+/g, "");
822
+ }
823
+
248
824
  // src/prompts/sepTrack.ts
249
825
  var VALID_PHASES = ["draft", "spec", "fixture", "verify"];
250
826
  function buildDraftPhase(args) {
@@ -502,7 +1078,7 @@ var SIGHTMAP_INIT_PROJECT = {
502
1078
  };
503
1079
  var SIGHTMAP_UPDATE_VIEW = {
504
1080
  name: "sightmap_update_view",
505
- description: "Apply a partial patch to a view's agent-authored fields (description, intent, memory). Memory edits use either `memory_append` (default operation) or `memory_replace` \u2014 pass exactly one. Component / route / selector edits are NOT supported here \u2014 those are codegen-owned; edit source and re-run sightmap-react gen instead.",
1081
+ description: "Apply a patch to a view's fields. Accepts both semantic edits (description, intent, memory_append/memory_replace) and structural edits (name, route, components). Memory edits use either `memory_append` (default) or `memory_replace` \u2014 pass exactly one. Components is a full array replacement; use sightmap_add_view/sightmap_delete_view for whole-view lifecycle.",
506
1082
  inputSchema: {
507
1083
  type: "object",
508
1084
  properties: {
@@ -513,7 +1089,22 @@ var SIGHTMAP_UPDATE_VIEW = {
513
1089
  description: { type: "string" },
514
1090
  intent: { type: "string" },
515
1091
  memory_append: { type: "array", items: { type: "string" } },
516
- memory_replace: { type: "array", items: { type: "string" } }
1092
+ memory_replace: { type: "array", items: { type: "string" } },
1093
+ name: { type: "string" },
1094
+ route: { type: "string" },
1095
+ components: {
1096
+ type: "array",
1097
+ items: {
1098
+ type: "object",
1099
+ properties: {
1100
+ name: { type: "string" },
1101
+ selector: { type: "string" },
1102
+ memory: { type: "array", items: { type: "string" } }
1103
+ },
1104
+ required: ["name", "selector"],
1105
+ additionalProperties: true
1106
+ }
1107
+ }
517
1108
  },
518
1109
  additionalProperties: false
519
1110
  }
@@ -522,6 +1113,164 @@ var SIGHTMAP_UPDATE_VIEW = {
522
1113
  additionalProperties: false
523
1114
  }
524
1115
  };
1116
+ var SIGHTMAP_ADD_VIEW = {
1117
+ name: "sightmap_add_view",
1118
+ description: "Create a new view in a new .yaml file. Filename defaults to kebab(view.name) + '.yaml' unless overridden via `file`. Rejects names that collide with an existing view.",
1119
+ inputSchema: {
1120
+ type: "object",
1121
+ properties: {
1122
+ view: {
1123
+ type: "object",
1124
+ properties: {
1125
+ name: { type: "string" },
1126
+ route: { type: "string" },
1127
+ description: { type: "string" },
1128
+ memory: { type: "array", items: { type: "string" } },
1129
+ components: {
1130
+ type: "array",
1131
+ items: {
1132
+ type: "object",
1133
+ properties: {
1134
+ name: { type: "string" },
1135
+ selector: { type: "string" },
1136
+ memory: { type: "array", items: { type: "string" } }
1137
+ },
1138
+ required: ["name", "selector"],
1139
+ additionalProperties: true
1140
+ }
1141
+ }
1142
+ },
1143
+ required: ["name", "route"],
1144
+ additionalProperties: true
1145
+ },
1146
+ file: {
1147
+ type: "string",
1148
+ description: "Optional filename hint (relative to the curate root). Defaults to kebab(view.name) + '.yaml'."
1149
+ }
1150
+ },
1151
+ required: ["view"],
1152
+ additionalProperties: false
1153
+ }
1154
+ };
1155
+ var SIGHTMAP_RUNTIME_SNAPSHOT = {
1156
+ name: "sightmap_runtime_snapshot",
1157
+ description: "Fetch a SightmapSnapshot (fiber-tree introspection from bippy). Three sources:\n - { kind: 'endpoint', url } \u2014 HTTP GET against the @sightmap/react Vite plugin endpoint (zero-config for Vite users).\n - { kind: 'browser', url, routes?, inject? } \u2014 drive the live browser via @playwright/mcp; works on any React app (Webpack, RR 5.x, etc.) and, with `inject: true`, on apps that haven't installed @sightmap/react.\n - { kind: 'literal', snapshot } \u2014 accept a pre-captured snapshot from any source (subtext live-eval-script, devtools console paste, custom Playwright scripts, CI capture). Validates the shape; returns it.",
1158
+ inputSchema: {
1159
+ type: "object",
1160
+ properties: {
1161
+ source: {
1162
+ type: "object",
1163
+ oneOf: [
1164
+ {
1165
+ type: "object",
1166
+ properties: {
1167
+ kind: { type: "string", const: "endpoint" },
1168
+ url: { type: "string", description: "Plugin endpoint URL, e.g. http://localhost:5173/__sightmap__/snapshot.json." }
1169
+ },
1170
+ required: ["kind", "url"],
1171
+ additionalProperties: false
1172
+ },
1173
+ {
1174
+ type: "object",
1175
+ properties: {
1176
+ kind: { type: "string", const: "browser" },
1177
+ url: { type: "string", description: "Target URL to navigate to." },
1178
+ routes: {
1179
+ type: "array",
1180
+ items: { type: "string" },
1181
+ description: "Optional list of routes (absolute or relative to `url`) to capture in sequence."
1182
+ },
1183
+ inject: {
1184
+ type: "boolean",
1185
+ description: "When true, inject bippy + the snapshot bootstrap before navigation so non-@sightmap/react apps work. Omit to auto-inject only when the page lacks window.__sightmap__."
1186
+ }
1187
+ },
1188
+ required: ["kind", "url"],
1189
+ additionalProperties: false
1190
+ },
1191
+ {
1192
+ type: "object",
1193
+ properties: {
1194
+ kind: { type: "string", const: "literal" },
1195
+ snapshot: {
1196
+ description: "A pre-captured SightmapSnapshot object. Must include capturedAt, route, components, markers, unmarkedCandidates."
1197
+ }
1198
+ },
1199
+ required: ["kind", "snapshot"],
1200
+ additionalProperties: false
1201
+ }
1202
+ ]
1203
+ }
1204
+ },
1205
+ required: ["source"],
1206
+ additionalProperties: false
1207
+ }
1208
+ };
1209
+ var SIGHTMAP_PROPOSE_VIEW = {
1210
+ name: "sightmap_propose_view",
1211
+ description: "Stage a proposed view from runtime observation. Does NOT write disk. Use sightmap_commit_proposals to persist.",
1212
+ inputSchema: {
1213
+ type: "object",
1214
+ properties: {
1215
+ route: { type: "string", description: "URL path for the observed view (e.g., '/dashboard')." },
1216
+ name: { type: "string", description: "Optional display name. If omitted, derived from route at commit time." },
1217
+ intent: { type: "string", description: "Optional one-liner describing the view's purpose." },
1218
+ observed: { type: "string", description: "Free-form note about what was observed on this view." },
1219
+ observed_components: { type: "array", items: { type: "string" } },
1220
+ memory_notes: { type: "array", items: { type: "string" } }
1221
+ },
1222
+ required: ["route"],
1223
+ additionalProperties: false
1224
+ }
1225
+ };
1226
+ var SIGHTMAP_PROPOSE_COMPONENT = {
1227
+ name: "sightmap_propose_component",
1228
+ description: "Stage a proposed component observation. Does NOT write disk.",
1229
+ inputSchema: {
1230
+ type: "object",
1231
+ properties: {
1232
+ name: { type: "string", description: "Component name (e.g., 'KpiCard')." },
1233
+ selector_candidate: { type: "string", description: "Best-guess CSS selector for the component." },
1234
+ observed_routes: { type: "array", items: { type: "string" } },
1235
+ notes: { type: "array", items: { type: "string" } }
1236
+ },
1237
+ required: ["name"],
1238
+ additionalProperties: false
1239
+ }
1240
+ };
1241
+ var SIGHTMAP_REVIEW_PROPOSALS = {
1242
+ name: "sightmap_review_proposals",
1243
+ description: "Return the current staged proposals (views + components).",
1244
+ inputSchema: {
1245
+ type: "object",
1246
+ properties: {},
1247
+ additionalProperties: false
1248
+ }
1249
+ };
1250
+ var SIGHTMAP_COMMIT_PROPOSALS = {
1251
+ name: "sightmap_commit_proposals",
1252
+ description: "Promote staged proposals to disk via add_view. Pass dry_run:true to preview without consuming the queue. Pass ids:[...] to commit a selection only.",
1253
+ inputSchema: {
1254
+ type: "object",
1255
+ properties: {
1256
+ ids: { type: "array", items: { type: "string" }, description: "Optional subset of proposal ids to commit. Omit to commit everything." },
1257
+ dry_run: { type: "boolean", description: "If true, preview without consuming the queue and without writing." }
1258
+ },
1259
+ additionalProperties: false
1260
+ }
1261
+ };
1262
+ var SIGHTMAP_DELETE_VIEW = {
1263
+ name: "sightmap_delete_view",
1264
+ description: "Delete a view by name. If the containing .yaml file has only this view, the file is removed; otherwise the view is spliced out and the file rewritten.",
1265
+ inputSchema: {
1266
+ type: "object",
1267
+ properties: {
1268
+ name: { type: "string" }
1269
+ },
1270
+ required: ["name"],
1271
+ additionalProperties: false
1272
+ }
1273
+ };
525
1274
  var SIGHTMAP_CHECK = {
526
1275
  name: "sightmap_check",
527
1276
  description: "Validate the loaded sightmap. level='schema' returns only schema-level diagnostics (parse errors, schema failures, merge collisions). level='quality' (default) also runs lint rules: duplicate routes, route shadowing, selector syntax, unknown source attributions. Returns an array of diagnostics; an empty array means clean.",
@@ -628,8 +1377,15 @@ var SightmapMcpServer = class {
628
1377
  SIGHTMAP_LIST_VIEWS,
629
1378
  SIGHTMAP_GET_VIEW,
630
1379
  SIGHTMAP_CHECK,
1380
+ SIGHTMAP_ADD_VIEW,
631
1381
  SIGHTMAP_UPDATE_VIEW,
632
- SIGHTMAP_INIT_PROJECT
1382
+ SIGHTMAP_DELETE_VIEW,
1383
+ SIGHTMAP_INIT_PROJECT,
1384
+ SIGHTMAP_RUNTIME_SNAPSHOT,
1385
+ SIGHTMAP_PROPOSE_VIEW,
1386
+ SIGHTMAP_PROPOSE_COMPONENT,
1387
+ SIGHTMAP_REVIEW_PROPOSALS,
1388
+ SIGHTMAP_COMMIT_PROPOSALS
633
1389
  ];
634
1390
  }
635
1391
  /** Full async list including upstream-proxied tools, if configured. */
@@ -639,8 +1395,15 @@ var SightmapMcpServer = class {
639
1395
  SIGHTMAP_LIST_VIEWS,
640
1396
  SIGHTMAP_GET_VIEW,
641
1397
  SIGHTMAP_CHECK,
1398
+ SIGHTMAP_ADD_VIEW,
642
1399
  SIGHTMAP_UPDATE_VIEW,
643
- SIGHTMAP_INIT_PROJECT
1400
+ SIGHTMAP_DELETE_VIEW,
1401
+ SIGHTMAP_INIT_PROJECT,
1402
+ SIGHTMAP_RUNTIME_SNAPSHOT,
1403
+ SIGHTMAP_PROPOSE_VIEW,
1404
+ SIGHTMAP_PROPOSE_COMPONENT,
1405
+ SIGHTMAP_REVIEW_PROPOSALS,
1406
+ SIGHTMAP_COMMIT_PROPOSALS
644
1407
  ];
645
1408
  if (this.upstream !== void 0) {
646
1409
  own.push(SIGHTMAP_SNAPSHOT, SIGHTMAP_ACT, SIGHTMAP_NETWORK_REQUESTS);
@@ -678,10 +1441,24 @@ var SightmapMcpServer = class {
678
1441
  return this.callSightmapGetView(args);
679
1442
  case "sightmap_check":
680
1443
  return this.callSightmapCheck(args);
1444
+ case "sightmap_add_view":
1445
+ return this.callSightmapAddView(args);
681
1446
  case "sightmap_update_view":
682
1447
  return this.callSightmapUpdateView(args);
1448
+ case "sightmap_delete_view":
1449
+ return this.callSightmapDeleteView(args);
683
1450
  case "sightmap_init_project":
684
1451
  return this.callSightmapInitProject(args);
1452
+ case "sightmap_runtime_snapshot":
1453
+ return this.callSightmapRuntimeSnapshot(args);
1454
+ case "sightmap_propose_view":
1455
+ return this.callSightmapProposeView(args);
1456
+ case "sightmap_propose_component":
1457
+ return this.callSightmapProposeComponent(args);
1458
+ case "sightmap_review_proposals":
1459
+ return this.callSightmapReviewProposals();
1460
+ case "sightmap_commit_proposals":
1461
+ return this.callSightmapCommitProposals(args);
685
1462
  case "sightmap_snapshot":
686
1463
  return this.callSightmapSnapshot();
687
1464
  case "sightmap_act":
@@ -924,6 +1701,196 @@ var SightmapMcpServer = class {
924
1701
  return errorResult(err instanceof Error ? err.message : String(err));
925
1702
  }
926
1703
  }
1704
+ async callSightmapRuntimeSnapshot(args) {
1705
+ const source = args["source"];
1706
+ if (source === null || typeof source !== "object" || Array.isArray(source)) {
1707
+ return errorResult(
1708
+ "sightmap_runtime_snapshot: required argument `source` (object) is missing."
1709
+ );
1710
+ }
1711
+ const s = source;
1712
+ const kind = s["kind"];
1713
+ if (kind !== "endpoint" && kind !== "browser" && kind !== "literal") {
1714
+ return errorResult(
1715
+ "sightmap_runtime_snapshot: `source.kind` must be 'endpoint', 'browser', or 'literal'."
1716
+ );
1717
+ }
1718
+ let input;
1719
+ if (kind === "endpoint") {
1720
+ if (typeof s["url"] !== "string" || s["url"].length === 0) {
1721
+ return errorResult(
1722
+ "sightmap_runtime_snapshot: endpoint mode requires `source.url` (string)."
1723
+ );
1724
+ }
1725
+ input = { source: { kind: "endpoint", url: s["url"] } };
1726
+ } else if (kind === "browser") {
1727
+ if (typeof s["url"] !== "string" || s["url"].length === 0) {
1728
+ return errorResult(
1729
+ "sightmap_runtime_snapshot: browser mode requires `source.url` (string)."
1730
+ );
1731
+ }
1732
+ const browserSrc = {
1733
+ kind: "browser",
1734
+ url: s["url"]
1735
+ };
1736
+ if (Array.isArray(s["routes"])) {
1737
+ browserSrc.routes = s["routes"].filter(
1738
+ (r) => typeof r === "string"
1739
+ );
1740
+ }
1741
+ if (typeof s["inject"] === "boolean") {
1742
+ browserSrc.inject = s["inject"];
1743
+ }
1744
+ input = { source: browserSrc };
1745
+ } else {
1746
+ if (!("snapshot" in s)) {
1747
+ return errorResult(
1748
+ "sightmap_runtime_snapshot: literal mode requires `source.snapshot`."
1749
+ );
1750
+ }
1751
+ input = { source: { kind: "literal", snapshot: s["snapshot"] } };
1752
+ }
1753
+ try {
1754
+ const deps = {
1755
+ getInjectScript
1756
+ };
1757
+ if (this.upstream !== void 0) deps.upstream = this.upstream;
1758
+ const result = await handleRuntimeSnapshot(input, deps);
1759
+ return {
1760
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1761
+ };
1762
+ } catch (err) {
1763
+ return errorResult(err instanceof Error ? err.message : String(err));
1764
+ }
1765
+ }
1766
+ async callSightmapProposeView(args) {
1767
+ if (typeof args["route"] !== "string" || args["route"].length === 0) {
1768
+ return errorResult(
1769
+ "sightmap_propose_view: required argument `route` (string) is missing or empty."
1770
+ );
1771
+ }
1772
+ const input = { route: args["route"] };
1773
+ if (typeof args["name"] === "string") input.name = args["name"];
1774
+ if (typeof args["intent"] === "string") input.intent = args["intent"];
1775
+ if (typeof args["observed"] === "string") input.observed = args["observed"];
1776
+ if (Array.isArray(args["observed_components"])) {
1777
+ input.observed_components = args["observed_components"].filter(
1778
+ (s) => typeof s === "string"
1779
+ );
1780
+ }
1781
+ if (Array.isArray(args["memory_notes"])) {
1782
+ input.memory_notes = args["memory_notes"].filter(
1783
+ (s) => typeof s === "string"
1784
+ );
1785
+ }
1786
+ try {
1787
+ const result = await handleProposeView(input);
1788
+ return {
1789
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1790
+ };
1791
+ } catch (err) {
1792
+ return errorResult(err instanceof Error ? err.message : String(err));
1793
+ }
1794
+ }
1795
+ async callSightmapProposeComponent(args) {
1796
+ if (typeof args["name"] !== "string" || args["name"].length === 0) {
1797
+ return errorResult(
1798
+ "sightmap_propose_component: required argument `name` (string) is missing or empty."
1799
+ );
1800
+ }
1801
+ const input = { name: args["name"] };
1802
+ if (typeof args["selector_candidate"] === "string") {
1803
+ input.selector_candidate = args["selector_candidate"];
1804
+ }
1805
+ if (Array.isArray(args["observed_routes"])) {
1806
+ input.observed_routes = args["observed_routes"].filter(
1807
+ (s) => typeof s === "string"
1808
+ );
1809
+ }
1810
+ if (Array.isArray(args["notes"])) {
1811
+ input.notes = args["notes"].filter(
1812
+ (s) => typeof s === "string"
1813
+ );
1814
+ }
1815
+ try {
1816
+ const result = await handleProposeComponent(input);
1817
+ return {
1818
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1819
+ };
1820
+ } catch (err) {
1821
+ return errorResult(err instanceof Error ? err.message : String(err));
1822
+ }
1823
+ }
1824
+ async callSightmapReviewProposals() {
1825
+ try {
1826
+ const result = await handleReviewProposals();
1827
+ return {
1828
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1829
+ };
1830
+ } catch (err) {
1831
+ return errorResult(err instanceof Error ? err.message : String(err));
1832
+ }
1833
+ }
1834
+ async callSightmapCommitProposals(args) {
1835
+ if (this.curateRoot === void 0) {
1836
+ return errorResult(
1837
+ "sightmap_commit_proposals: no writable sightmap dir configured (pass --curate-root or --sightmap-dir)."
1838
+ );
1839
+ }
1840
+ const input = { sightmapDir: this.curateRoot };
1841
+ if (Array.isArray(args["ids"])) {
1842
+ input.ids = args["ids"].filter(
1843
+ (s) => typeof s === "string"
1844
+ );
1845
+ }
1846
+ if (args["dry_run"] === true) input.dry_run = true;
1847
+ try {
1848
+ const result = await handleCommitProposals(input);
1849
+ return {
1850
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1851
+ };
1852
+ } catch (err) {
1853
+ return errorResult(err instanceof Error ? err.message : String(err));
1854
+ }
1855
+ }
1856
+ async callSightmapAddView(args) {
1857
+ if (this.curateRoot === void 0) {
1858
+ return errorResult(
1859
+ "sightmap_add_view: no writable sightmap dir configured (pass --curate-root or --sightmap-dir)."
1860
+ );
1861
+ }
1862
+ if (args["view"] === null || typeof args["view"] !== "object" || Array.isArray(args["view"])) {
1863
+ return errorResult(
1864
+ "sightmap_add_view: required argument `view` (object) is missing."
1865
+ );
1866
+ }
1867
+ const view = args["view"];
1868
+ if (typeof view["name"] !== "string" || view["name"].length === 0) {
1869
+ return errorResult(
1870
+ "sightmap_add_view: `view.name` (string) is required."
1871
+ );
1872
+ }
1873
+ if (typeof view["route"] !== "string" || view["route"].length === 0) {
1874
+ return errorResult(
1875
+ "sightmap_add_view: `view.route` (string) is required."
1876
+ );
1877
+ }
1878
+ const input = {
1879
+ sightmapDir: this.curateRoot,
1880
+ view
1881
+ };
1882
+ if (typeof args["file"] === "string" && args["file"].length > 0) {
1883
+ input.file = args["file"];
1884
+ }
1885
+ try {
1886
+ const result = await handleAddView(input);
1887
+ return {
1888
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1889
+ };
1890
+ } catch (err) {
1891
+ return errorResult(err instanceof Error ? err.message : String(err));
1892
+ }
1893
+ }
927
1894
  async callSightmapUpdateView(args) {
928
1895
  if (this.curateRoot === void 0) {
929
1896
  return errorResult(
@@ -953,6 +1920,29 @@ var SightmapMcpServer = class {
953
1920
  return errorResult(err instanceof Error ? err.message : String(err));
954
1921
  }
955
1922
  }
1923
+ async callSightmapDeleteView(args) {
1924
+ if (this.curateRoot === void 0) {
1925
+ return errorResult(
1926
+ "sightmap_delete_view: no writable sightmap dir configured (pass --curate-root or --sightmap-dir)."
1927
+ );
1928
+ }
1929
+ if (typeof args["name"] !== "string" || args["name"].length === 0) {
1930
+ return errorResult(
1931
+ "sightmap_delete_view: required argument `name` (string) is missing or empty."
1932
+ );
1933
+ }
1934
+ try {
1935
+ const result = await handleDeleteView({
1936
+ sightmapDir: this.curateRoot,
1937
+ name: args["name"]
1938
+ });
1939
+ return {
1940
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1941
+ };
1942
+ } catch (err) {
1943
+ return errorResult(err instanceof Error ? err.message : String(err));
1944
+ }
1945
+ }
956
1946
  async callSightmapCheck(args) {
957
1947
  const input = {};
958
1948
  if (args["level"] === "schema" || args["level"] === "quality") {