@sightmap/mcp 0.7.1 → 0.8.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/cli.js +590 -19
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +583 -12
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -49,7 +49,7 @@ var init_loadMerged = __esm({
|
|
|
49
49
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
50
50
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
51
51
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
52
|
-
import { resolve, dirname } from "path";
|
|
52
|
+
import { resolve as resolve3, dirname } from "path";
|
|
53
53
|
import { readFileSync, realpathSync } from "fs";
|
|
54
54
|
import { fileURLToPath } from "url";
|
|
55
55
|
|
|
@@ -246,6 +246,22 @@ async function handleUpdateView(input) {
|
|
|
246
246
|
if (input.patch.memory_replace) {
|
|
247
247
|
after.memory = [...input.patch.memory_replace];
|
|
248
248
|
}
|
|
249
|
+
if (input.patch.name !== void 0) {
|
|
250
|
+
after.name = input.patch.name;
|
|
251
|
+
}
|
|
252
|
+
if (input.patch.route !== void 0) {
|
|
253
|
+
after.route = input.patch.route;
|
|
254
|
+
}
|
|
255
|
+
if (input.patch.components !== void 0) {
|
|
256
|
+
const seen = /* @__PURE__ */ new Set();
|
|
257
|
+
for (const c2 of input.patch.components) {
|
|
258
|
+
if (seen.has(c2.name)) {
|
|
259
|
+
throw new Error(`duplicate component name in patch: ${c2.name}`);
|
|
260
|
+
}
|
|
261
|
+
seen.add(c2.name);
|
|
262
|
+
}
|
|
263
|
+
after.components = input.patch.components;
|
|
264
|
+
}
|
|
249
265
|
const nextViews = [...views];
|
|
250
266
|
nextViews[idx] = after;
|
|
251
267
|
const nextDoc = stripFragmentBrand(parsed);
|
|
@@ -265,23 +281,108 @@ function stripFragmentBrand(input) {
|
|
|
265
281
|
return out;
|
|
266
282
|
}
|
|
267
283
|
|
|
284
|
+
// src/tools/curate/add.ts
|
|
285
|
+
import { writeFile as writeFile2, readFile as readFile4, readdir as readdir2 } from "fs/promises";
|
|
286
|
+
import { resolve, join as join2 } from "path";
|
|
287
|
+
import {
|
|
288
|
+
format as format2,
|
|
289
|
+
canonicalize as canonicalize2
|
|
290
|
+
} from "@sightmap/sightmap";
|
|
291
|
+
async function handleAddView(input) {
|
|
292
|
+
await ensureNotExists(input.sightmapDir, input.view.name);
|
|
293
|
+
const filename = input.file ?? kebab(input.view.name) + ".yaml";
|
|
294
|
+
const path = join2(input.sightmapDir, filename);
|
|
295
|
+
const doc = {
|
|
296
|
+
version: 1,
|
|
297
|
+
views: [input.view]
|
|
298
|
+
};
|
|
299
|
+
const out = format2(doc);
|
|
300
|
+
const c = canonicalize2(out, { file: path });
|
|
301
|
+
const text = c.kind === "canonical" ? c.text : out;
|
|
302
|
+
await writeFile2(path, text, "utf8");
|
|
303
|
+
return { ok: true, file: path, written: input.view };
|
|
304
|
+
}
|
|
305
|
+
async function ensureNotExists(dir, name) {
|
|
306
|
+
let files;
|
|
307
|
+
try {
|
|
308
|
+
files = await readdir2(dir);
|
|
309
|
+
} catch {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
for (const f of files) {
|
|
313
|
+
if (!f.endsWith(".yaml")) continue;
|
|
314
|
+
const text = await readFile4(resolve(dir, f), "utf8");
|
|
315
|
+
if (new RegExp(`(^|\\n)\\s*-\\s+name:\\s+${escapeRe(name)}(\\s|$)`).test(text)) {
|
|
316
|
+
throw new Error(`view "${name}" already exists in ${f}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function kebab(s) {
|
|
321
|
+
return s.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
|
|
322
|
+
}
|
|
323
|
+
function escapeRe(s) {
|
|
324
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// src/tools/curate/remove.ts
|
|
328
|
+
import { readFile as readFile5, writeFile as writeFile3, unlink, readdir as readdir3 } from "fs/promises";
|
|
329
|
+
import { resolve as resolve2 } from "path";
|
|
330
|
+
import {
|
|
331
|
+
parse as parse4,
|
|
332
|
+
format as format3,
|
|
333
|
+
canonicalize as canonicalize3
|
|
334
|
+
} from "@sightmap/sightmap";
|
|
335
|
+
async function handleDeleteView(input) {
|
|
336
|
+
const entries = await readdir3(input.sightmapDir);
|
|
337
|
+
for (const entry of entries) {
|
|
338
|
+
if (!entry.endsWith(".yaml")) continue;
|
|
339
|
+
const path = resolve2(input.sightmapDir, entry);
|
|
340
|
+
const text = await readFile5(path, "utf8");
|
|
341
|
+
const parsed = parse4(text, { sourceFile: path });
|
|
342
|
+
const views = parsed.views ?? [];
|
|
343
|
+
const idx = views.findIndex((v) => v.name === input.name);
|
|
344
|
+
if (idx < 0) continue;
|
|
345
|
+
const remaining = views.filter((_, i) => i !== idx);
|
|
346
|
+
if (remaining.length === 0) {
|
|
347
|
+
await unlink(path);
|
|
348
|
+
return { ok: true, file: path, fileDeleted: true };
|
|
349
|
+
}
|
|
350
|
+
const nextDoc = stripFragmentBrand2(parsed);
|
|
351
|
+
nextDoc.views = remaining;
|
|
352
|
+
const out = format3(nextDoc);
|
|
353
|
+
const c = canonicalize3(out, { file: path });
|
|
354
|
+
const finalText = c.kind === "canonical" ? c.text : out;
|
|
355
|
+
await writeFile3(path, finalText, "utf8");
|
|
356
|
+
return { ok: true, file: path, fileDeleted: false };
|
|
357
|
+
}
|
|
358
|
+
throw new Error(`view "${input.name}" not found in ${input.sightmapDir}`);
|
|
359
|
+
}
|
|
360
|
+
function stripFragmentBrand2(input) {
|
|
361
|
+
const out = {};
|
|
362
|
+
for (const k of Object.keys(input)) {
|
|
363
|
+
if (k === "__brand" || k === "__sourceFile") continue;
|
|
364
|
+
out[k] = input[k];
|
|
365
|
+
}
|
|
366
|
+
return out;
|
|
367
|
+
}
|
|
368
|
+
|
|
268
369
|
// src/tools/curate/init.ts
|
|
269
|
-
import { mkdir, writeFile as
|
|
270
|
-
import { join as
|
|
370
|
+
import { mkdir, writeFile as writeFile4, access } from "fs/promises";
|
|
371
|
+
import { join as join3 } from "path";
|
|
271
372
|
|
|
272
373
|
// src/curate/scaffolder.ts
|
|
273
|
-
import { format as
|
|
374
|
+
import { format as format4, canonicalize as canonicalize4 } from "@sightmap/sightmap";
|
|
274
375
|
function makeStarterSightmap() {
|
|
275
|
-
const text =
|
|
276
|
-
const c =
|
|
376
|
+
const text = format4({ version: 1 });
|
|
377
|
+
const c = canonicalize4(text, { file: "app.yaml" });
|
|
277
378
|
return c.kind === "canonical" ? c.text : text;
|
|
278
379
|
}
|
|
279
380
|
|
|
280
381
|
// src/tools/curate/init.ts
|
|
281
382
|
async function handleInitProject(input) {
|
|
282
383
|
const root = input.dir ?? process.cwd();
|
|
283
|
-
const sightmapDir =
|
|
284
|
-
const appFile =
|
|
384
|
+
const sightmapDir = join3(root, ".sightmap");
|
|
385
|
+
const appFile = join3(sightmapDir, "app.yaml");
|
|
285
386
|
if (input.force !== true) {
|
|
286
387
|
let exists = false;
|
|
287
388
|
try {
|
|
@@ -296,10 +397,127 @@ async function handleInitProject(input) {
|
|
|
296
397
|
}
|
|
297
398
|
}
|
|
298
399
|
await mkdir(sightmapDir, { recursive: true });
|
|
299
|
-
await
|
|
400
|
+
await writeFile4(appFile, makeStarterSightmap(), "utf8");
|
|
300
401
|
return { ok: true, files: [appFile] };
|
|
301
402
|
}
|
|
302
403
|
|
|
404
|
+
// src/tools/runtime/snapshot.ts
|
|
405
|
+
async function handleRuntimeSnapshot(input) {
|
|
406
|
+
if (input.source.kind === "endpoint") {
|
|
407
|
+
const res = await fetch(input.source.url);
|
|
408
|
+
if (res.status === 404) {
|
|
409
|
+
let detail = "";
|
|
410
|
+
try {
|
|
411
|
+
const body = await res.json();
|
|
412
|
+
detail = body.error ?? "";
|
|
413
|
+
} catch {
|
|
414
|
+
}
|
|
415
|
+
throw new Error(
|
|
416
|
+
`no snapshot cached yet at ${input.source.url}${detail ? `: ${detail}` : ""}`
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
if (!res.ok) {
|
|
420
|
+
throw new Error(`snapshot fetch failed: HTTP ${res.status}`);
|
|
421
|
+
}
|
|
422
|
+
const snapshot = await res.json();
|
|
423
|
+
return { ok: true, snapshot, source: input.source };
|
|
424
|
+
}
|
|
425
|
+
throw new Error(
|
|
426
|
+
"browser-driven snapshot capture is not implemented in 1.0-rc; use { kind: 'endpoint' } with the Vite plugin endpoint instead"
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// src/tools/propose/store.ts
|
|
431
|
+
var ProposalStore = class {
|
|
432
|
+
views = [];
|
|
433
|
+
components = [];
|
|
434
|
+
nextId = 1;
|
|
435
|
+
mintId(prefix) {
|
|
436
|
+
return `${prefix}_${this.nextId++}`;
|
|
437
|
+
}
|
|
438
|
+
appendView(p) {
|
|
439
|
+
const v = { id: this.mintId("v"), ...p };
|
|
440
|
+
this.views.push(v);
|
|
441
|
+
return v;
|
|
442
|
+
}
|
|
443
|
+
appendComponent(p) {
|
|
444
|
+
const c = { id: this.mintId("c"), ...p };
|
|
445
|
+
this.components.push(c);
|
|
446
|
+
return c;
|
|
447
|
+
}
|
|
448
|
+
review() {
|
|
449
|
+
return { views: [...this.views], components: [...this.components] };
|
|
450
|
+
}
|
|
451
|
+
commit(input = {}) {
|
|
452
|
+
if (!input.ids) {
|
|
453
|
+
const out = this.review();
|
|
454
|
+
this.views = [];
|
|
455
|
+
this.components = [];
|
|
456
|
+
return out;
|
|
457
|
+
}
|
|
458
|
+
const selected = new Set(input.ids);
|
|
459
|
+
const consumedViews = this.views.filter((v) => selected.has(v.id));
|
|
460
|
+
const consumedComponents = this.components.filter((c) => selected.has(c.id));
|
|
461
|
+
this.views = this.views.filter((v) => !selected.has(v.id));
|
|
462
|
+
this.components = this.components.filter((c) => !selected.has(c.id));
|
|
463
|
+
return { views: consumedViews, components: consumedComponents };
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
var proposalStore = new ProposalStore();
|
|
467
|
+
|
|
468
|
+
// src/tools/propose/view.ts
|
|
469
|
+
async function handleProposeView(input) {
|
|
470
|
+
const v = proposalStore.appendView(input);
|
|
471
|
+
return { ok: true, id: v.id };
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// src/tools/propose/component.ts
|
|
475
|
+
async function handleProposeComponent(input) {
|
|
476
|
+
const c = proposalStore.appendComponent(input);
|
|
477
|
+
return { ok: true, id: c.id };
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// src/tools/propose/review.ts
|
|
481
|
+
async function handleReviewProposals() {
|
|
482
|
+
return proposalStore.review();
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// src/tools/propose/commit.ts
|
|
486
|
+
async function handleCommitProposals(input) {
|
|
487
|
+
if (input.dry_run === true) {
|
|
488
|
+
const peek = proposalStore.review();
|
|
489
|
+
const selectedIds = input.ids ? new Set(input.ids) : null;
|
|
490
|
+
const filtered = {
|
|
491
|
+
views: selectedIds ? peek.views.filter((v) => selectedIds.has(v.id)) : peek.views,
|
|
492
|
+
components: selectedIds ? peek.components.filter((c) => selectedIds.has(c.id)) : peek.components
|
|
493
|
+
};
|
|
494
|
+
return { ok: true, committed: filtered, writes: [] };
|
|
495
|
+
}
|
|
496
|
+
const consumed = proposalStore.commit(
|
|
497
|
+
input.ids ? { ids: input.ids } : {}
|
|
498
|
+
);
|
|
499
|
+
const writes = [];
|
|
500
|
+
for (const v of consumed.views) {
|
|
501
|
+
const r = await handleAddView({
|
|
502
|
+
sightmapDir: input.sightmapDir,
|
|
503
|
+
view: {
|
|
504
|
+
name: v.name ?? deriveName(v.route),
|
|
505
|
+
route: v.route,
|
|
506
|
+
components: [],
|
|
507
|
+
...v.intent !== void 0 ? { intent: v.intent } : {},
|
|
508
|
+
...v.memory_notes && v.memory_notes.length > 0 ? { memory: v.memory_notes } : {}
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
writes.push({ kind: "view", file: r.file });
|
|
512
|
+
}
|
|
513
|
+
return { ok: true, committed: consumed, writes };
|
|
514
|
+
}
|
|
515
|
+
function deriveName(route) {
|
|
516
|
+
const parts = route.replace(/^\/+|\/+$/g, "").split("/").filter((p) => p.length > 0);
|
|
517
|
+
const last = parts[parts.length - 1] ?? "Index";
|
|
518
|
+
return last.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).replace(/\s+/g, "");
|
|
519
|
+
}
|
|
520
|
+
|
|
303
521
|
// src/prompts/sepTrack.ts
|
|
304
522
|
var VALID_PHASES = ["draft", "spec", "fixture", "verify"];
|
|
305
523
|
function buildDraftPhase(args) {
|
|
@@ -557,7 +775,7 @@ var SIGHTMAP_INIT_PROJECT = {
|
|
|
557
775
|
};
|
|
558
776
|
var SIGHTMAP_UPDATE_VIEW = {
|
|
559
777
|
name: "sightmap_update_view",
|
|
560
|
-
description: "Apply a
|
|
778
|
+
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.",
|
|
561
779
|
inputSchema: {
|
|
562
780
|
type: "object",
|
|
563
781
|
properties: {
|
|
@@ -568,7 +786,22 @@ var SIGHTMAP_UPDATE_VIEW = {
|
|
|
568
786
|
description: { type: "string" },
|
|
569
787
|
intent: { type: "string" },
|
|
570
788
|
memory_append: { type: "array", items: { type: "string" } },
|
|
571
|
-
memory_replace: { type: "array", items: { type: "string" } }
|
|
789
|
+
memory_replace: { type: "array", items: { type: "string" } },
|
|
790
|
+
name: { type: "string" },
|
|
791
|
+
route: { type: "string" },
|
|
792
|
+
components: {
|
|
793
|
+
type: "array",
|
|
794
|
+
items: {
|
|
795
|
+
type: "object",
|
|
796
|
+
properties: {
|
|
797
|
+
name: { type: "string" },
|
|
798
|
+
selector: { type: "string" },
|
|
799
|
+
memory: { type: "array", items: { type: "string" } }
|
|
800
|
+
},
|
|
801
|
+
required: ["name", "selector"],
|
|
802
|
+
additionalProperties: true
|
|
803
|
+
}
|
|
804
|
+
}
|
|
572
805
|
},
|
|
573
806
|
additionalProperties: false
|
|
574
807
|
}
|
|
@@ -577,6 +810,131 @@ var SIGHTMAP_UPDATE_VIEW = {
|
|
|
577
810
|
additionalProperties: false
|
|
578
811
|
}
|
|
579
812
|
};
|
|
813
|
+
var SIGHTMAP_ADD_VIEW = {
|
|
814
|
+
name: "sightmap_add_view",
|
|
815
|
+
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.",
|
|
816
|
+
inputSchema: {
|
|
817
|
+
type: "object",
|
|
818
|
+
properties: {
|
|
819
|
+
view: {
|
|
820
|
+
type: "object",
|
|
821
|
+
properties: {
|
|
822
|
+
name: { type: "string" },
|
|
823
|
+
route: { type: "string" },
|
|
824
|
+
description: { type: "string" },
|
|
825
|
+
memory: { type: "array", items: { type: "string" } },
|
|
826
|
+
components: {
|
|
827
|
+
type: "array",
|
|
828
|
+
items: {
|
|
829
|
+
type: "object",
|
|
830
|
+
properties: {
|
|
831
|
+
name: { type: "string" },
|
|
832
|
+
selector: { type: "string" },
|
|
833
|
+
memory: { type: "array", items: { type: "string" } }
|
|
834
|
+
},
|
|
835
|
+
required: ["name", "selector"],
|
|
836
|
+
additionalProperties: true
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
},
|
|
840
|
+
required: ["name", "route"],
|
|
841
|
+
additionalProperties: true
|
|
842
|
+
},
|
|
843
|
+
file: {
|
|
844
|
+
type: "string",
|
|
845
|
+
description: "Optional filename hint (relative to the curate root). Defaults to kebab(view.name) + '.yaml'."
|
|
846
|
+
}
|
|
847
|
+
},
|
|
848
|
+
required: ["view"],
|
|
849
|
+
additionalProperties: false
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
var SIGHTMAP_RUNTIME_SNAPSHOT = {
|
|
853
|
+
name: "sightmap_runtime_snapshot",
|
|
854
|
+
description: "Fetch the live SightmapSnapshot from a running Vite dev server's /__sightmap__/snapshot.json endpoint. Pass { source: { kind: 'endpoint', url: 'http://localhost:5173/__sightmap__/snapshot.json' } }. The browser-driven (kind: 'browser') mode is reserved for future Playwright bridge support.",
|
|
855
|
+
inputSchema: {
|
|
856
|
+
type: "object",
|
|
857
|
+
properties: {
|
|
858
|
+
source: {
|
|
859
|
+
type: "object",
|
|
860
|
+
properties: {
|
|
861
|
+
kind: { type: "string", enum: ["endpoint", "browser"] },
|
|
862
|
+
url: { type: "string" },
|
|
863
|
+
routes: { type: "array", items: { type: "string" } }
|
|
864
|
+
},
|
|
865
|
+
required: ["kind", "url"],
|
|
866
|
+
additionalProperties: false
|
|
867
|
+
}
|
|
868
|
+
},
|
|
869
|
+
required: ["source"],
|
|
870
|
+
additionalProperties: false
|
|
871
|
+
}
|
|
872
|
+
};
|
|
873
|
+
var SIGHTMAP_PROPOSE_VIEW = {
|
|
874
|
+
name: "sightmap_propose_view",
|
|
875
|
+
description: "Stage a proposed view from runtime observation. Does NOT write disk. Use sightmap_commit_proposals to persist.",
|
|
876
|
+
inputSchema: {
|
|
877
|
+
type: "object",
|
|
878
|
+
properties: {
|
|
879
|
+
route: { type: "string", description: "URL path for the observed view (e.g., '/dashboard')." },
|
|
880
|
+
name: { type: "string", description: "Optional display name. If omitted, derived from route at commit time." },
|
|
881
|
+
intent: { type: "string", description: "Optional one-liner describing the view's purpose." },
|
|
882
|
+
observed: { type: "string", description: "Free-form note about what was observed on this view." },
|
|
883
|
+
observed_components: { type: "array", items: { type: "string" } },
|
|
884
|
+
memory_notes: { type: "array", items: { type: "string" } }
|
|
885
|
+
},
|
|
886
|
+
required: ["route"],
|
|
887
|
+
additionalProperties: false
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
var SIGHTMAP_PROPOSE_COMPONENT = {
|
|
891
|
+
name: "sightmap_propose_component",
|
|
892
|
+
description: "Stage a proposed component observation. Does NOT write disk.",
|
|
893
|
+
inputSchema: {
|
|
894
|
+
type: "object",
|
|
895
|
+
properties: {
|
|
896
|
+
name: { type: "string", description: "Component name (e.g., 'KpiCard')." },
|
|
897
|
+
selector_candidate: { type: "string", description: "Best-guess CSS selector for the component." },
|
|
898
|
+
observed_routes: { type: "array", items: { type: "string" } },
|
|
899
|
+
notes: { type: "array", items: { type: "string" } }
|
|
900
|
+
},
|
|
901
|
+
required: ["name"],
|
|
902
|
+
additionalProperties: false
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
var SIGHTMAP_REVIEW_PROPOSALS = {
|
|
906
|
+
name: "sightmap_review_proposals",
|
|
907
|
+
description: "Return the current staged proposals (views + components).",
|
|
908
|
+
inputSchema: {
|
|
909
|
+
type: "object",
|
|
910
|
+
properties: {},
|
|
911
|
+
additionalProperties: false
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
var SIGHTMAP_COMMIT_PROPOSALS = {
|
|
915
|
+
name: "sightmap_commit_proposals",
|
|
916
|
+
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.",
|
|
917
|
+
inputSchema: {
|
|
918
|
+
type: "object",
|
|
919
|
+
properties: {
|
|
920
|
+
ids: { type: "array", items: { type: "string" }, description: "Optional subset of proposal ids to commit. Omit to commit everything." },
|
|
921
|
+
dry_run: { type: "boolean", description: "If true, preview without consuming the queue and without writing." }
|
|
922
|
+
},
|
|
923
|
+
additionalProperties: false
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
var SIGHTMAP_DELETE_VIEW = {
|
|
927
|
+
name: "sightmap_delete_view",
|
|
928
|
+
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.",
|
|
929
|
+
inputSchema: {
|
|
930
|
+
type: "object",
|
|
931
|
+
properties: {
|
|
932
|
+
name: { type: "string" }
|
|
933
|
+
},
|
|
934
|
+
required: ["name"],
|
|
935
|
+
additionalProperties: false
|
|
936
|
+
}
|
|
937
|
+
};
|
|
580
938
|
var SIGHTMAP_CHECK = {
|
|
581
939
|
name: "sightmap_check",
|
|
582
940
|
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.",
|
|
@@ -683,8 +1041,15 @@ var SightmapMcpServer = class {
|
|
|
683
1041
|
SIGHTMAP_LIST_VIEWS,
|
|
684
1042
|
SIGHTMAP_GET_VIEW,
|
|
685
1043
|
SIGHTMAP_CHECK,
|
|
1044
|
+
SIGHTMAP_ADD_VIEW,
|
|
686
1045
|
SIGHTMAP_UPDATE_VIEW,
|
|
687
|
-
|
|
1046
|
+
SIGHTMAP_DELETE_VIEW,
|
|
1047
|
+
SIGHTMAP_INIT_PROJECT,
|
|
1048
|
+
SIGHTMAP_RUNTIME_SNAPSHOT,
|
|
1049
|
+
SIGHTMAP_PROPOSE_VIEW,
|
|
1050
|
+
SIGHTMAP_PROPOSE_COMPONENT,
|
|
1051
|
+
SIGHTMAP_REVIEW_PROPOSALS,
|
|
1052
|
+
SIGHTMAP_COMMIT_PROPOSALS
|
|
688
1053
|
];
|
|
689
1054
|
}
|
|
690
1055
|
/** Full async list including upstream-proxied tools, if configured. */
|
|
@@ -694,8 +1059,15 @@ var SightmapMcpServer = class {
|
|
|
694
1059
|
SIGHTMAP_LIST_VIEWS,
|
|
695
1060
|
SIGHTMAP_GET_VIEW,
|
|
696
1061
|
SIGHTMAP_CHECK,
|
|
1062
|
+
SIGHTMAP_ADD_VIEW,
|
|
697
1063
|
SIGHTMAP_UPDATE_VIEW,
|
|
698
|
-
|
|
1064
|
+
SIGHTMAP_DELETE_VIEW,
|
|
1065
|
+
SIGHTMAP_INIT_PROJECT,
|
|
1066
|
+
SIGHTMAP_RUNTIME_SNAPSHOT,
|
|
1067
|
+
SIGHTMAP_PROPOSE_VIEW,
|
|
1068
|
+
SIGHTMAP_PROPOSE_COMPONENT,
|
|
1069
|
+
SIGHTMAP_REVIEW_PROPOSALS,
|
|
1070
|
+
SIGHTMAP_COMMIT_PROPOSALS
|
|
699
1071
|
];
|
|
700
1072
|
if (this.upstream !== void 0) {
|
|
701
1073
|
own.push(SIGHTMAP_SNAPSHOT, SIGHTMAP_ACT, SIGHTMAP_NETWORK_REQUESTS);
|
|
@@ -733,10 +1105,24 @@ var SightmapMcpServer = class {
|
|
|
733
1105
|
return this.callSightmapGetView(args);
|
|
734
1106
|
case "sightmap_check":
|
|
735
1107
|
return this.callSightmapCheck(args);
|
|
1108
|
+
case "sightmap_add_view":
|
|
1109
|
+
return this.callSightmapAddView(args);
|
|
736
1110
|
case "sightmap_update_view":
|
|
737
1111
|
return this.callSightmapUpdateView(args);
|
|
1112
|
+
case "sightmap_delete_view":
|
|
1113
|
+
return this.callSightmapDeleteView(args);
|
|
738
1114
|
case "sightmap_init_project":
|
|
739
1115
|
return this.callSightmapInitProject(args);
|
|
1116
|
+
case "sightmap_runtime_snapshot":
|
|
1117
|
+
return this.callSightmapRuntimeSnapshot(args);
|
|
1118
|
+
case "sightmap_propose_view":
|
|
1119
|
+
return this.callSightmapProposeView(args);
|
|
1120
|
+
case "sightmap_propose_component":
|
|
1121
|
+
return this.callSightmapProposeComponent(args);
|
|
1122
|
+
case "sightmap_review_proposals":
|
|
1123
|
+
return this.callSightmapReviewProposals();
|
|
1124
|
+
case "sightmap_commit_proposals":
|
|
1125
|
+
return this.callSightmapCommitProposals(args);
|
|
740
1126
|
case "sightmap_snapshot":
|
|
741
1127
|
return this.callSightmapSnapshot();
|
|
742
1128
|
case "sightmap_act":
|
|
@@ -979,6 +1365,168 @@ var SightmapMcpServer = class {
|
|
|
979
1365
|
return errorResult(err instanceof Error ? err.message : String(err));
|
|
980
1366
|
}
|
|
981
1367
|
}
|
|
1368
|
+
async callSightmapRuntimeSnapshot(args) {
|
|
1369
|
+
const source = args["source"];
|
|
1370
|
+
if (source === null || typeof source !== "object" || Array.isArray(source)) {
|
|
1371
|
+
return errorResult(
|
|
1372
|
+
"sightmap_runtime_snapshot: required argument `source` (object) is missing."
|
|
1373
|
+
);
|
|
1374
|
+
}
|
|
1375
|
+
const s = source;
|
|
1376
|
+
if (s["kind"] !== "endpoint" && s["kind"] !== "browser") {
|
|
1377
|
+
return errorResult(
|
|
1378
|
+
"sightmap_runtime_snapshot: `source.kind` must be 'endpoint' or 'browser'."
|
|
1379
|
+
);
|
|
1380
|
+
}
|
|
1381
|
+
if (typeof s["url"] !== "string" || s["url"].length === 0) {
|
|
1382
|
+
return errorResult(
|
|
1383
|
+
"sightmap_runtime_snapshot: `source.url` (string) is required."
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
const input = s["kind"] === "endpoint" ? { source: { kind: "endpoint", url: s["url"] } } : {
|
|
1387
|
+
source: {
|
|
1388
|
+
kind: "browser",
|
|
1389
|
+
url: s["url"],
|
|
1390
|
+
...Array.isArray(s["routes"]) ? { routes: s["routes"].filter((r) => typeof r === "string") } : {}
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
try {
|
|
1394
|
+
const result = await handleRuntimeSnapshot(input);
|
|
1395
|
+
return {
|
|
1396
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1397
|
+
};
|
|
1398
|
+
} catch (err) {
|
|
1399
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
async callSightmapProposeView(args) {
|
|
1403
|
+
if (typeof args["route"] !== "string" || args["route"].length === 0) {
|
|
1404
|
+
return errorResult(
|
|
1405
|
+
"sightmap_propose_view: required argument `route` (string) is missing or empty."
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
1408
|
+
const input = { route: args["route"] };
|
|
1409
|
+
if (typeof args["name"] === "string") input.name = args["name"];
|
|
1410
|
+
if (typeof args["intent"] === "string") input.intent = args["intent"];
|
|
1411
|
+
if (typeof args["observed"] === "string") input.observed = args["observed"];
|
|
1412
|
+
if (Array.isArray(args["observed_components"])) {
|
|
1413
|
+
input.observed_components = args["observed_components"].filter(
|
|
1414
|
+
(s) => typeof s === "string"
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
if (Array.isArray(args["memory_notes"])) {
|
|
1418
|
+
input.memory_notes = args["memory_notes"].filter(
|
|
1419
|
+
(s) => typeof s === "string"
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
try {
|
|
1423
|
+
const result = await handleProposeView(input);
|
|
1424
|
+
return {
|
|
1425
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1426
|
+
};
|
|
1427
|
+
} catch (err) {
|
|
1428
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
async callSightmapProposeComponent(args) {
|
|
1432
|
+
if (typeof args["name"] !== "string" || args["name"].length === 0) {
|
|
1433
|
+
return errorResult(
|
|
1434
|
+
"sightmap_propose_component: required argument `name` (string) is missing or empty."
|
|
1435
|
+
);
|
|
1436
|
+
}
|
|
1437
|
+
const input = { name: args["name"] };
|
|
1438
|
+
if (typeof args["selector_candidate"] === "string") {
|
|
1439
|
+
input.selector_candidate = args["selector_candidate"];
|
|
1440
|
+
}
|
|
1441
|
+
if (Array.isArray(args["observed_routes"])) {
|
|
1442
|
+
input.observed_routes = args["observed_routes"].filter(
|
|
1443
|
+
(s) => typeof s === "string"
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1446
|
+
if (Array.isArray(args["notes"])) {
|
|
1447
|
+
input.notes = args["notes"].filter(
|
|
1448
|
+
(s) => typeof s === "string"
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
try {
|
|
1452
|
+
const result = await handleProposeComponent(input);
|
|
1453
|
+
return {
|
|
1454
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1455
|
+
};
|
|
1456
|
+
} catch (err) {
|
|
1457
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
async callSightmapReviewProposals() {
|
|
1461
|
+
try {
|
|
1462
|
+
const result = await handleReviewProposals();
|
|
1463
|
+
return {
|
|
1464
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1465
|
+
};
|
|
1466
|
+
} catch (err) {
|
|
1467
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
async callSightmapCommitProposals(args) {
|
|
1471
|
+
if (this.curateRoot === void 0) {
|
|
1472
|
+
return errorResult(
|
|
1473
|
+
"sightmap_commit_proposals: no writable sightmap dir configured (pass --curate-root or --sightmap-dir)."
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1476
|
+
const input = { sightmapDir: this.curateRoot };
|
|
1477
|
+
if (Array.isArray(args["ids"])) {
|
|
1478
|
+
input.ids = args["ids"].filter(
|
|
1479
|
+
(s) => typeof s === "string"
|
|
1480
|
+
);
|
|
1481
|
+
}
|
|
1482
|
+
if (args["dry_run"] === true) input.dry_run = true;
|
|
1483
|
+
try {
|
|
1484
|
+
const result = await handleCommitProposals(input);
|
|
1485
|
+
return {
|
|
1486
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1487
|
+
};
|
|
1488
|
+
} catch (err) {
|
|
1489
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
async callSightmapAddView(args) {
|
|
1493
|
+
if (this.curateRoot === void 0) {
|
|
1494
|
+
return errorResult(
|
|
1495
|
+
"sightmap_add_view: no writable sightmap dir configured (pass --curate-root or --sightmap-dir)."
|
|
1496
|
+
);
|
|
1497
|
+
}
|
|
1498
|
+
if (args["view"] === null || typeof args["view"] !== "object" || Array.isArray(args["view"])) {
|
|
1499
|
+
return errorResult(
|
|
1500
|
+
"sightmap_add_view: required argument `view` (object) is missing."
|
|
1501
|
+
);
|
|
1502
|
+
}
|
|
1503
|
+
const view = args["view"];
|
|
1504
|
+
if (typeof view["name"] !== "string" || view["name"].length === 0) {
|
|
1505
|
+
return errorResult(
|
|
1506
|
+
"sightmap_add_view: `view.name` (string) is required."
|
|
1507
|
+
);
|
|
1508
|
+
}
|
|
1509
|
+
if (typeof view["route"] !== "string" || view["route"].length === 0) {
|
|
1510
|
+
return errorResult(
|
|
1511
|
+
"sightmap_add_view: `view.route` (string) is required."
|
|
1512
|
+
);
|
|
1513
|
+
}
|
|
1514
|
+
const input = {
|
|
1515
|
+
sightmapDir: this.curateRoot,
|
|
1516
|
+
view
|
|
1517
|
+
};
|
|
1518
|
+
if (typeof args["file"] === "string" && args["file"].length > 0) {
|
|
1519
|
+
input.file = args["file"];
|
|
1520
|
+
}
|
|
1521
|
+
try {
|
|
1522
|
+
const result = await handleAddView(input);
|
|
1523
|
+
return {
|
|
1524
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1525
|
+
};
|
|
1526
|
+
} catch (err) {
|
|
1527
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
982
1530
|
async callSightmapUpdateView(args) {
|
|
983
1531
|
if (this.curateRoot === void 0) {
|
|
984
1532
|
return errorResult(
|
|
@@ -1008,6 +1556,29 @@ var SightmapMcpServer = class {
|
|
|
1008
1556
|
return errorResult(err instanceof Error ? err.message : String(err));
|
|
1009
1557
|
}
|
|
1010
1558
|
}
|
|
1559
|
+
async callSightmapDeleteView(args) {
|
|
1560
|
+
if (this.curateRoot === void 0) {
|
|
1561
|
+
return errorResult(
|
|
1562
|
+
"sightmap_delete_view: no writable sightmap dir configured (pass --curate-root or --sightmap-dir)."
|
|
1563
|
+
);
|
|
1564
|
+
}
|
|
1565
|
+
if (typeof args["name"] !== "string" || args["name"].length === 0) {
|
|
1566
|
+
return errorResult(
|
|
1567
|
+
"sightmap_delete_view: required argument `name` (string) is missing or empty."
|
|
1568
|
+
);
|
|
1569
|
+
}
|
|
1570
|
+
try {
|
|
1571
|
+
const result = await handleDeleteView({
|
|
1572
|
+
sightmapDir: this.curateRoot,
|
|
1573
|
+
name: args["name"]
|
|
1574
|
+
});
|
|
1575
|
+
return {
|
|
1576
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1577
|
+
};
|
|
1578
|
+
} catch (err) {
|
|
1579
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1011
1582
|
async callSightmapCheck(args) {
|
|
1012
1583
|
const input = {};
|
|
1013
1584
|
if (args["level"] === "schema" || args["level"] === "quality") {
|
|
@@ -1166,13 +1737,13 @@ var KNOWN_INCOMPATIBLE_RANGES = [
|
|
|
1166
1737
|
{ pluginLt: "0.2.0", mcpGte: "0.5.0" }
|
|
1167
1738
|
];
|
|
1168
1739
|
var KNOWN_GOOD_MCP_MAJOR_MINOR = ["0.3", "0.4"];
|
|
1169
|
-
function
|
|
1740
|
+
function parse5(v) {
|
|
1170
1741
|
const [a, b, c] = v.split(".").map((s) => parseInt(s, 10));
|
|
1171
1742
|
return [a ?? 0, b ?? 0, c ?? 0];
|
|
1172
1743
|
}
|
|
1173
1744
|
function lt(a, b) {
|
|
1174
|
-
const [a0, a1, a2] =
|
|
1175
|
-
const [b0, b1, b2] =
|
|
1745
|
+
const [a0, a1, a2] = parse5(a);
|
|
1746
|
+
const [b0, b1, b2] = parse5(b);
|
|
1176
1747
|
if (a0 !== b0) return a0 < b0;
|
|
1177
1748
|
if (a1 !== b1) return a1 < b1;
|
|
1178
1749
|
return a2 < b2;
|
|
@@ -1193,7 +1764,7 @@ function evaluateCompat(input) {
|
|
|
1193
1764
|
|
|
1194
1765
|
// src/cli.ts
|
|
1195
1766
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
1196
|
-
var pkgJson = JSON.parse(readFileSync(
|
|
1767
|
+
var pkgJson = JSON.parse(readFileSync(resolve3(__dirname, "../package.json"), "utf8"));
|
|
1197
1768
|
function parseArgv(argv) {
|
|
1198
1769
|
const collectedDirs = [];
|
|
1199
1770
|
let explicitCurateRoot;
|
|
@@ -1236,7 +1807,7 @@ function parseArgv(argv) {
|
|
|
1236
1807
|
i++;
|
|
1237
1808
|
}
|
|
1238
1809
|
out.sightmapDirs = collectedDirs.length > 0 ? collectedDirs : [".sightmap"];
|
|
1239
|
-
out.curateRoot = explicitCurateRoot !== void 0 ?
|
|
1810
|
+
out.curateRoot = explicitCurateRoot !== void 0 ? resolve3(explicitCurateRoot) : resolve3(out.sightmapDirs[0]);
|
|
1240
1811
|
return out;
|
|
1241
1812
|
}
|
|
1242
1813
|
function printHelp() {
|
|
@@ -1274,7 +1845,7 @@ Pin matching versions in your .mcp.json.`
|
|
|
1274
1845
|
console.error(`[sightmap-mcp] Untested plugin/MCP pair: plugin v${process.env.SIGHTMAP_PLUGIN_VERSION} \u2194 MCP v${pkgJson.version}. Proceeding.`);
|
|
1275
1846
|
}
|
|
1276
1847
|
const { mergeSightmaps: mergeSightmaps2 } = await Promise.resolve().then(() => (init_loadMerged(), loadMerged_exports));
|
|
1277
|
-
const sightmap = await mergeSightmaps2(args.sightmapDirs.map((d) =>
|
|
1848
|
+
const sightmap = await mergeSightmaps2(args.sightmapDirs.map((d) => resolve3(d)));
|
|
1278
1849
|
if (sightmap.diagnostics.some((d) => d.severity === "error")) {
|
|
1279
1850
|
process.stderr.write(
|
|
1280
1851
|
`sightmap-mcp: ${sightmap.diagnostics.length} diagnostic(s) loading sightmap; continuing
|