@bridge-ds/mcp 0.8.4 → 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/README.md +92 -49
- package/dist/branches.d.ts +85 -10
- package/dist/build-requests.d.ts +96 -0
- package/dist/{chunk-HZWFI7A2.js → chunk-TP33MW7E.js} +3705 -836
- package/dist/{chunk-PMZGEZGX.js → chunk-ZVORAO5H.js} +258 -160
- package/dist/components.d.ts +3 -1
- package/dist/context.d.ts +22 -0
- package/dist/figma-fixes.d.ts +206 -0
- package/dist/figma.d.ts +2 -1
- package/dist/history.d.ts +149 -6
- package/dist/index.js +8 -4
- package/dist/lib.d.ts +15 -2
- package/dist/lib.js +18 -4
- package/dist/ops.d.ts +41 -0
- package/dist/say.d.ts +22 -0
- package/dist/{src-DRJFSLRV.js → src-RUS6SPYZ.js} +75 -20
- package/dist/studio.d.ts +10 -0
- package/dist/suggestions.d.ts +3 -1
- package/package.json +4 -3
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
referenceImagePath,
|
|
12
12
|
selectTokenFiles,
|
|
13
13
|
showFile
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-ZVORAO5H.js";
|
|
15
15
|
|
|
16
16
|
// ../visual/src/run.ts
|
|
17
17
|
import { existsSync as existsSync3 } from "node:fs";
|
|
@@ -317,6 +317,17 @@ async function switchStory(page, storyId2) {
|
|
|
317
317
|
);
|
|
318
318
|
if (!ok) throw new Error("Storybook channel not found");
|
|
319
319
|
}
|
|
320
|
+
async function openMeasurePage(o = {}) {
|
|
321
|
+
const browser = await launch(o);
|
|
322
|
+
try {
|
|
323
|
+
const ctx = await browser.newContext({ viewport: { width: 1200, height: 800 }, deviceScaleFactor: o.scale ?? 1, reducedMotion: "reduce", colorScheme: "light", locale: "en-US", serviceWorkers: "block" });
|
|
324
|
+
const page = await ctx.newPage();
|
|
325
|
+
return { page, close: () => browser.close().catch(() => void 0) };
|
|
326
|
+
} catch (e) {
|
|
327
|
+
await browser.close().catch(() => void 0);
|
|
328
|
+
throw e;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
320
331
|
|
|
321
332
|
// ../visual/src/composite.ts
|
|
322
333
|
import { readFile, writeFile as writeFile2 } from "node:fs/promises";
|
|
@@ -368,6 +379,15 @@ import pixelmatch from "pixelmatch";
|
|
|
368
379
|
import { PNG } from "pngjs";
|
|
369
380
|
var decodePng = (buf) => PNG.sync.read(buf);
|
|
370
381
|
var encodePng = (png) => PNG.sync.write(png, { colorType: 6 });
|
|
382
|
+
function cropPng(src, x, y, width, height) {
|
|
383
|
+
const left = Math.max(0, Math.round(x));
|
|
384
|
+
const top = Math.max(0, Math.round(y));
|
|
385
|
+
const w = Math.max(1, Math.min(src.width - left, Math.round(width)));
|
|
386
|
+
const h = Math.max(1, Math.min(src.height - top, Math.round(height)));
|
|
387
|
+
const out = new PNG({ width: w, height: h });
|
|
388
|
+
PNG.bitblt(src, out, left, top, w, h, 0, 0);
|
|
389
|
+
return out;
|
|
390
|
+
}
|
|
371
391
|
function padTo(src, width, height) {
|
|
372
392
|
if (src.width === width && src.height === height) return src;
|
|
373
393
|
const out = new PNG({ width, height });
|
|
@@ -1208,9 +1228,12 @@ async function captureFigmaReferences(o) {
|
|
|
1208
1228
|
try {
|
|
1209
1229
|
const ctx = await newContext(browser, { width: 1200, height: 800 }, scale);
|
|
1210
1230
|
const page = await newPage(ctx);
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1231
|
+
const openStory = async () => {
|
|
1232
|
+
await page.goto(storyUrl(served.url, FIGMA_REFERENCE_STORY, brand, theme), { waitUntil: "load", timeout: 3e4 });
|
|
1233
|
+
await page.waitForSelector("[data-fidelity-root], [data-fidelity-error]", { state: "attached", timeout: 2e4 });
|
|
1234
|
+
await settle(page, { busy: false });
|
|
1235
|
+
};
|
|
1236
|
+
await openStory();
|
|
1214
1237
|
log(`Capturing ${jobs.length} variants at ${scale}x (${brand} ${theme})`);
|
|
1215
1238
|
for (const j of jobs) {
|
|
1216
1239
|
const variants = manifest.components[j.component].variants;
|
|
@@ -1219,25 +1242,17 @@ async function captureFigmaReferences(o) {
|
|
|
1219
1242
|
skipped++;
|
|
1220
1243
|
continue;
|
|
1221
1244
|
}
|
|
1222
|
-
const
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
resolve2();
|
|
1230
|
-
};
|
|
1231
|
-
const timer = setTimeout(done, 1e4);
|
|
1232
|
-
ch.on("storyRendered", done);
|
|
1233
|
-
ch.emit("updateStoryArgs", { storyId: id, updatedArgs: { plan: plan2 } });
|
|
1234
|
-
}),
|
|
1235
|
-
{ id: FIGMA_REFERENCE_STORY, plan }
|
|
1236
|
-
);
|
|
1245
|
+
const shown = await renderPlan(page, JSON.stringify(j.plan.render));
|
|
1246
|
+
if (shown.broken) {
|
|
1247
|
+
variants[j.key] = { skipped: `the code example threw: ${shown.error ?? "the story did not finish rendering"}` };
|
|
1248
|
+
skipped++;
|
|
1249
|
+
await openStory();
|
|
1250
|
+
continue;
|
|
1251
|
+
}
|
|
1237
1252
|
await settle(page, { network: false, quiet: 2, interval: 40, busy: false });
|
|
1238
1253
|
const error = await page.locator("[data-fidelity-error]").first().textContent({ timeout: 200 }).catch(() => null);
|
|
1239
1254
|
let target = page.locator("[data-fidelity-root] > *").first();
|
|
1240
|
-
if (!error && !await target.count()) {
|
|
1255
|
+
if (!error && (j.plan.render.within || j.plan.render.popup || !await target.count())) {
|
|
1241
1256
|
const marked = page.locator("[data-fidelity-target]").first();
|
|
1242
1257
|
await marked.waitFor({ state: "visible", timeout: 3e3 }).catch(() => void 0);
|
|
1243
1258
|
await settle(page, { network: false, quiet: 2, interval: 40, busy: false });
|
|
@@ -1248,6 +1263,15 @@ async function captureFigmaReferences(o) {
|
|
|
1248
1263
|
skipped++;
|
|
1249
1264
|
continue;
|
|
1250
1265
|
}
|
|
1266
|
+
const transparent = await target.evaluate((el) => {
|
|
1267
|
+
for (let e = el; e; e = e.parentElement) if (getComputedStyle(e).opacity === "0") return true;
|
|
1268
|
+
return false;
|
|
1269
|
+
});
|
|
1270
|
+
if (transparent) {
|
|
1271
|
+
variants[j.key] = { skipped: "the code example rendered invisible (opacity 0)" };
|
|
1272
|
+
skipped++;
|
|
1273
|
+
continue;
|
|
1274
|
+
}
|
|
1251
1275
|
const file = referenceImagePath(j.component, j.key);
|
|
1252
1276
|
const path = join4(o.out, file);
|
|
1253
1277
|
await mkdir4(dirname3(path), { recursive: true });
|
|
@@ -1268,6 +1292,35 @@ async function captureFigmaReferences(o) {
|
|
|
1268
1292
|
log(`${captured} images, ${skipped} variants skipped. ${manifestPath}`);
|
|
1269
1293
|
return { manifest, manifestPath, captured, skipped };
|
|
1270
1294
|
}
|
|
1295
|
+
async function renderPlan(page, plan) {
|
|
1296
|
+
const r = await page.evaluate(
|
|
1297
|
+
({ id, plan: plan2 }) => new Promise((resolve2) => {
|
|
1298
|
+
const ch = window.__STORYBOOK_ADDONS_CHANNEL__;
|
|
1299
|
+
let error;
|
|
1300
|
+
const failed = (p) => {
|
|
1301
|
+
const e = p;
|
|
1302
|
+
error ??= e?.message ?? e?.title ?? e?.description;
|
|
1303
|
+
};
|
|
1304
|
+
const finish = (rendered) => {
|
|
1305
|
+
clearTimeout(timer);
|
|
1306
|
+
ch.off("storyRendered", done);
|
|
1307
|
+
ch.off("storyThrewException", failed);
|
|
1308
|
+
ch.off("storyErrored", failed);
|
|
1309
|
+
resolve2({ rendered, ...error ? { error } : {} });
|
|
1310
|
+
};
|
|
1311
|
+
const done = () => finish(true);
|
|
1312
|
+
document.querySelectorAll("[data-fidelity-target]").forEach((el) => el.removeAttribute("data-fidelity-target"));
|
|
1313
|
+
const timer = setTimeout(() => finish(false), 1e4);
|
|
1314
|
+
ch.on("storyThrewException", failed);
|
|
1315
|
+
ch.on("storyErrored", failed);
|
|
1316
|
+
ch.on("storyRendered", done);
|
|
1317
|
+
ch.emit("updateStoryArgs", { storyId: id, updatedArgs: { plan: plan2 } });
|
|
1318
|
+
}),
|
|
1319
|
+
{ id: FIGMA_REFERENCE_STORY, plan }
|
|
1320
|
+
);
|
|
1321
|
+
const errorScreen = await page.evaluate(() => document.body.classList.contains("sb-show-errordisplay"));
|
|
1322
|
+
return { broken: !r.rendered || !!r.error || errorScreen, ...r.error ? { error: r.error } : {} };
|
|
1323
|
+
}
|
|
1271
1324
|
export {
|
|
1272
1325
|
COMMENT_MARKER,
|
|
1273
1326
|
DEFAULT_ROUTES,
|
|
@@ -1276,11 +1329,13 @@ export {
|
|
|
1276
1329
|
boxesFromDiff,
|
|
1277
1330
|
captureFigmaReferences,
|
|
1278
1331
|
changedTokens,
|
|
1332
|
+
cropPng,
|
|
1279
1333
|
decodePng,
|
|
1280
1334
|
diffPngs,
|
|
1281
1335
|
encodePng,
|
|
1282
1336
|
hasVisualChange,
|
|
1283
1337
|
linkNodeModules,
|
|
1338
|
+
openMeasurePage,
|
|
1284
1339
|
padTo,
|
|
1285
1340
|
planImpact,
|
|
1286
1341
|
rankShots,
|
package/dist/studio.d.ts
CHANGED
|
@@ -114,6 +114,16 @@ export declare function getSettings(ctx: BridgeContext): Promise<{
|
|
|
114
114
|
visualImpact: import("@bridge-ds/core").VisualImpactMode;
|
|
115
115
|
note: string;
|
|
116
116
|
}>;
|
|
117
|
+
/**
|
|
118
|
+
* One count of components everywhere: the component folders (snapshot.json and llms.txt count the same), then what the
|
|
119
|
+
* other numbers are: layout helpers have no Figma component, and in Figma popups and items are sets of their own.
|
|
120
|
+
*/
|
|
121
|
+
export declare function coverageLine(s: {
|
|
122
|
+
inFigma: number;
|
|
123
|
+
drafted: number;
|
|
124
|
+
layout: number;
|
|
125
|
+
total: number;
|
|
126
|
+
}, figmaSets: number): string;
|
|
117
127
|
/** Which components are in Figma (Studio's "In Figma" column), and whether code images exist for the fidelity check. */
|
|
118
128
|
export declare function figmaCoverage(ctx: BridgeContext, a?: {
|
|
119
129
|
component?: string | undefined;
|
package/dist/suggestions.d.ts
CHANGED
|
@@ -9,7 +9,9 @@ export declare const SUGGEST_RIGHTS = "Issues: read and write (Contents: read is
|
|
|
9
9
|
*/
|
|
10
10
|
export declare function changesFor(ctx: BridgeContext, explicit?: ChangesMode | undefined): Promise<ChangesMode>;
|
|
11
11
|
/** What to do next once a suggestion is filed. The wording matches the issue's "How to apply". */
|
|
12
|
-
export declare const appliedNext: (n: number
|
|
12
|
+
export declare const appliedNext: (n: number, ctx?: {
|
|
13
|
+
surface: "mcp" | "cli";
|
|
14
|
+
}) => string;
|
|
13
15
|
/** Why nothing was filed: no GitHub repo, or no token that can write issues. */
|
|
14
16
|
export declare function noSuggestionAccess(ctx: BridgeContext, gh: GitHubClient | null): string;
|
|
15
17
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bridge-ds/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Bridge MCP server: lets Claude (Claude Code, Claude Desktop or any MCP client) read, check and propose changes to a DTCG design system repo through pull requests.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,11 +51,12 @@
|
|
|
51
51
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
52
52
|
"test": "npm run build && vitest run --config vitest.config.ts",
|
|
53
53
|
"start": "node dist/index.js",
|
|
54
|
+
"readme:tools": "BRIDGE_UPDATE_README=1 vitest run --config vitest.config.ts packages/mcp/test/readme.test.ts",
|
|
54
55
|
"build:package": "node ../../scripts/build-packages.mjs mcp"
|
|
55
56
|
},
|
|
56
57
|
"dependencies": {
|
|
57
|
-
"@bridge-ds/core": "^0.
|
|
58
|
-
"@bridge-ds/visual": "^0.3.
|
|
58
|
+
"@bridge-ds/core": "^0.19.0",
|
|
59
|
+
"@bridge-ds/visual": "^0.3.13",
|
|
59
60
|
"@modelcontextprotocol/sdk": "1.31.0",
|
|
60
61
|
"typescript": "5.9.3",
|
|
61
62
|
"zod": "3.25.76"
|