@bridge-ds/mcp 0.8.5 → 0.10.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 +110 -0
- package/README.md +93 -50
- package/dist/branches.d.ts +87 -10
- package/dist/build-requests.d.ts +96 -0
- package/dist/{chunk-PMZGEZGX.js → chunk-BZEPCY42.js} +108 -8
- package/dist/{chunk-S5JR43L7.js → chunk-E5V42VCS.js} +3934 -801
- package/dist/components.d.ts +3 -1
- package/dist/context.d.ts +22 -0
- package/dist/figma-fixes.d.ts +234 -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 +34 -4
- package/dist/lib.js +22 -4
- package/dist/ops.d.ts +42 -0
- package/dist/say.d.ts +22 -0
- package/dist/server.d.ts +28 -1
- package/dist/{src-DRJFSLRV.js → src-ATD4DJF3.js} +75 -20
- package/dist/studio.d.ts +11 -0
- package/dist/suggestions.d.ts +21 -2
- package/package.json +5 -4
|
@@ -171,7 +171,7 @@ function resolveBranchPreviews(apps, ctx, sources = {}) {
|
|
|
171
171
|
}
|
|
172
172
|
return out;
|
|
173
173
|
}
|
|
174
|
-
var previewsSettled = (previews) => previews.every((p) =>
|
|
174
|
+
var previewsSettled = (previews) => previews.every((p) => p.state === "failed" || !!p.url && p.state === "ready");
|
|
175
175
|
|
|
176
176
|
// ../core/src/teams.ts
|
|
177
177
|
var LOGIN = /^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$/;
|
|
@@ -578,6 +578,12 @@ var CONFIG_FILE = "bridge.config.json";
|
|
|
578
578
|
var CHANGES_MODES = ["suggest", "direct"];
|
|
579
579
|
var DEFAULT_CHANGES_MODE = "suggest";
|
|
580
580
|
var DEFAULT_OVERRIDE = { allowed: [], requireReason: true, minReasonLength: 20 };
|
|
581
|
+
var TEAM_NAME_MAX = 60;
|
|
582
|
+
function teamName(value) {
|
|
583
|
+
if (typeof value !== "string") return void 0;
|
|
584
|
+
const v = value.trim().replace(/\s+/g, " ");
|
|
585
|
+
return v && v.length <= TEAM_NAME_MAX ? v : void 0;
|
|
586
|
+
}
|
|
581
587
|
var DEFAULT_TOKEN_PATHS = {
|
|
582
588
|
root: "tokens",
|
|
583
589
|
primitives: "primitives",
|
|
@@ -683,6 +689,7 @@ function defineConfig(input) {
|
|
|
683
689
|
const g = input.governance ?? {};
|
|
684
690
|
const contrastFile = contrastPath ?? [root === "." ? "" : root, paths.contrastChecks].filter(Boolean).join("/");
|
|
685
691
|
return {
|
|
692
|
+
...teamName(input.name) ? { name: teamName(input.name) } : {},
|
|
686
693
|
repo: parseRepoInput(input.repo, input.branch),
|
|
687
694
|
tokens: { ...paths, include: input.tokens?.include ?? ["**/*.tokens.json"], exclude: input.tokens?.exclude ?? [], tiers, layers, ...t.usage ? { usage: trimSlashes(t.usage) } : {} },
|
|
688
695
|
axes,
|
|
@@ -715,12 +722,14 @@ function defineConfig(input) {
|
|
|
715
722
|
}
|
|
716
723
|
} : {},
|
|
717
724
|
...g.rights ? { rights: normalizeRights(g.rights) } : {},
|
|
718
|
-
...g.soloOwnerCanApproveBoth === true ? { soloOwnerCanApproveBoth: true } : {}
|
|
725
|
+
...g.soloOwnerCanApproveBoth === true ? { soloOwnerCanApproveBoth: true } : {},
|
|
726
|
+
...g.leadsPublishTier1 === false ? { leadsPublishTier1: false } : {}
|
|
719
727
|
},
|
|
720
728
|
products: input.products?.length ? input.products.map((p) => ({ ...p })) : DEFAULT_PRODUCTS.map((p) => ({ ...p })),
|
|
721
729
|
changes: input.changes === "direct" ? "direct" : DEFAULT_CHANGES_MODE,
|
|
722
730
|
...input.storybook?.url ? { storybook: { url: input.storybook.url.trim().replace(/\/+$/, "") } } : {},
|
|
723
731
|
...input.library?.public === true ? { library: { public: true } } : {},
|
|
732
|
+
...input.demo?.viewer?.trim() ? { demo: { viewer: input.demo.viewer.trim(), ...input.demo.role?.trim() ? { role: input.demo.role.trim() } : {} } } : {},
|
|
724
733
|
...input.audit ? { audit: { ...input.audit } } : {},
|
|
725
734
|
...input.visualImpact ? { visualImpact: { mode: input.visualImpact.mode === "on-demand" ? "on-demand" : "auto" } } : {},
|
|
726
735
|
...input.integrations ? { integrations: { ...input.integrations } } : {},
|
|
@@ -842,9 +851,11 @@ function loadConfig(source) {
|
|
|
842
851
|
}
|
|
843
852
|
problems.push(...rightsProblems(gov.rights));
|
|
844
853
|
if (gov.soloOwnerCanApproveBoth !== void 0 && typeof gov.soloOwnerCanApproveBoth !== "boolean") problems.push('"governance.soloOwnerCanApproveBoth" must be true or false');
|
|
854
|
+
if (gov.leadsPublishTier1 !== void 0 && typeof gov.leadsPublishTier1 !== "boolean") problems.push('"governance.leadsPublishTier1" must be true or false');
|
|
845
855
|
}
|
|
846
856
|
}
|
|
847
857
|
problems.push(...visualImpactProblems(d.visualImpact));
|
|
858
|
+
if (d.name !== void 0 && teamName(d.name) === void 0) problems.push(`"name" must be the team's name, 1 to ${TEAM_NAME_MAX} characters`);
|
|
848
859
|
if (d.changes !== void 0 && !CHANGES_MODES.includes(d.changes)) problems.push(`"changes" must be "suggest" or "direct" (got ${JSON.stringify(d.changes)})`);
|
|
849
860
|
const sb = d.storybook;
|
|
850
861
|
if (sb !== void 0) {
|
|
@@ -860,6 +871,14 @@ function loadConfig(source) {
|
|
|
860
871
|
for (const k of Object.keys(lib)) if (k !== "public") problems.push(`"library.${k}" is not a known key`);
|
|
861
872
|
}
|
|
862
873
|
}
|
|
874
|
+
const demo = d.demo;
|
|
875
|
+
if (demo !== void 0) {
|
|
876
|
+
if (!isObj(demo) || !isStr(demo.viewer) || !demo.viewer.trim()) problems.push('"demo" must be { "viewer" }, for example { "viewer": "Dana", "role": "DS lead" }');
|
|
877
|
+
else {
|
|
878
|
+
if (demo.role !== void 0 && !isStr(demo.role)) problems.push('"demo.role" must be a string, for example "DS lead"');
|
|
879
|
+
for (const k of Object.keys(demo)) if (k !== "viewer" && k !== "role") problems.push(`"demo.${k}" is not a known key`);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
863
882
|
problems.push(...productProblems(d.products));
|
|
864
883
|
const audit = d.audit;
|
|
865
884
|
if (audit !== void 0) {
|
|
@@ -897,6 +916,7 @@ function toConfigJson(config, schema = "./packages/core/bridge.config.schema.jso
|
|
|
897
916
|
return {
|
|
898
917
|
$schema: schema,
|
|
899
918
|
version: 1,
|
|
919
|
+
...config.name ? { name: config.name } : {},
|
|
900
920
|
...config.repo ? { repo: config.repo } : {},
|
|
901
921
|
tokens: { root: config.tokens.root, include: config.tokens.include, ...config.tokens.exclude.length ? { exclude: config.tokens.exclude } : {}, tiers: config.tokens.tiers, layers: config.tokens.layers.map((l) => l.optional ? l : { files: l.files }), ...config.tokens.usage ? { usage: config.tokens.usage } : {} },
|
|
902
922
|
modes: Object.fromEntries(Object.entries(config.axes).map(([k, a]) => [k, a.parity ? a : { values: a.values, default: a.default }])),
|
|
@@ -912,6 +932,7 @@ function toConfigJson(config, schema = "./packages/core/bridge.config.schema.jso
|
|
|
912
932
|
changes: changesMode(config),
|
|
913
933
|
...config.storybook ? { storybook: config.storybook } : {},
|
|
914
934
|
...config.library ? { library: config.library } : {},
|
|
935
|
+
...config.demo ? { demo: config.demo } : {},
|
|
915
936
|
...config.products && !sameProducts(config.products, DEFAULT_PRODUCTS) ? { products: config.products } : {}
|
|
916
937
|
};
|
|
917
938
|
}
|
|
@@ -1525,6 +1546,11 @@ var RISK_LABELS = {
|
|
|
1525
1546
|
2: "Tier 2: medium risk, design review then design + tech approval",
|
|
1526
1547
|
3: "Tier 3: token change, needs design + tech approval"
|
|
1527
1548
|
};
|
|
1549
|
+
function figmaPushTierLabel(tier, changes) {
|
|
1550
|
+
const waits = changes.some((c) => c.kind === "renamed" || c.kind === "removed");
|
|
1551
|
+
return `Tier ${tier}: token change. From Figma: design-approved, ${waits ? "waits for a developer OK (a token renamed or removed can break product code)" : "ships once the checks pass"}`;
|
|
1552
|
+
}
|
|
1553
|
+
var figmaPushNextLine = (changes) => changes.some((c) => c.kind === "renamed" || c.kind === "removed") ? "Pushed from Figma, so design-approved. A developer OKs the rename or removal before it merges." : "Pushed from Figma, so design-approved. Bridge merges it once the automatic checks pass; Undo is in History in Bridge Studio.";
|
|
1528
1554
|
var BUMP_RANK = { patch: 0, minor: 1, major: 2 };
|
|
1529
1555
|
var LOW = [/\.md$/, /^docs\//, /\.stories\.tsx?$/, /\.docs\.json$/, /\.test\.tsx?$/, /^\.changeset\//];
|
|
1530
1556
|
var isSummary = (c) => "kind" in c;
|
|
@@ -1703,14 +1729,15 @@ _${deltas.length - limit} more pair(s) not shown._` : "";
|
|
|
1703
1729
|
}
|
|
1704
1730
|
function composeProposalBody(args) {
|
|
1705
1731
|
const t = args.tier.tier;
|
|
1706
|
-
const
|
|
1732
|
+
const figma = Boolean(args.fromFigma);
|
|
1733
|
+
const box = (n) => `- ${n === t ? "[x]" : "[ ]"} ${figma && n === t ? figmaPushTierLabel(n, args.changes) : RISK_LABELS[n]}`;
|
|
1707
1734
|
const impactList = args.impact.entries.slice(0, 15).map((e) => `- \`${e.path}\`: ${swatch(e.before)} -> ${swatch(e.after)} (${e.modes.length} mode${e.modes.length > 1 ? "s" : ""})`);
|
|
1708
1735
|
return [
|
|
1709
1736
|
"## What changed and why",
|
|
1710
1737
|
"",
|
|
1711
1738
|
args.summary.trim(),
|
|
1712
1739
|
"",
|
|
1713
|
-
`Proposed through ${args.tool ?? "Bridge MCP"}${args.author ? ` by ${args.author}` : ""}. Agent-authored: a human design owner and tech owner review and merge.`,
|
|
1740
|
+
figma ? `Pushed from Figma through ${args.tool ?? "the Bridge Figma plugin"}${args.author ? ` by ${args.author}` : ""}. ${figmaPushNextLine(args.changes)}` : `Proposed through ${args.tool ?? "Bridge MCP"}${args.author ? ` by ${args.author}` : ""}. Agent-authored: a human design owner and tech owner review and merge.`,
|
|
1714
1741
|
"",
|
|
1715
1742
|
"## Risk tier",
|
|
1716
1743
|
"",
|
|
@@ -1740,8 +1767,8 @@ function composeProposalBody(args) {
|
|
|
1740
1767
|
"",
|
|
1741
1768
|
"## Authored by",
|
|
1742
1769
|
"",
|
|
1743
|
-
|
|
1744
|
-
"
|
|
1770
|
+
`- [${figma ? "x" : " "}] Human`,
|
|
1771
|
+
`- [${figma ? " " : "x"}] AI agent (Claude), reviewed by a human before merge`,
|
|
1745
1772
|
"",
|
|
1746
1773
|
"## Design review checklist",
|
|
1747
1774
|
"",
|
|
@@ -1755,6 +1782,36 @@ function composeProposalBody(args) {
|
|
|
1755
1782
|
// ../core/src/component-spec.ts
|
|
1756
1783
|
var COMPONENT_SPECS_VERSION = 1;
|
|
1757
1784
|
var DEFAULT_COMPONENT_SPECS_FILE = "packages/react/component-specs.json";
|
|
1785
|
+
var SPEC_FIELDS = [
|
|
1786
|
+
"fill",
|
|
1787
|
+
"stroke",
|
|
1788
|
+
"strokeWeight",
|
|
1789
|
+
"strokeTopWeight",
|
|
1790
|
+
"strokeRightWeight",
|
|
1791
|
+
"strokeBottomWeight",
|
|
1792
|
+
"strokeLeftWeight",
|
|
1793
|
+
"cornerRadius",
|
|
1794
|
+
"paddingTop",
|
|
1795
|
+
"paddingRight",
|
|
1796
|
+
"paddingBottom",
|
|
1797
|
+
"paddingLeft",
|
|
1798
|
+
"itemSpacing",
|
|
1799
|
+
"counterAxisSpacing",
|
|
1800
|
+
"width",
|
|
1801
|
+
"height",
|
|
1802
|
+
"minWidth",
|
|
1803
|
+
"minHeight",
|
|
1804
|
+
"opacity",
|
|
1805
|
+
"shadow",
|
|
1806
|
+
"textFill",
|
|
1807
|
+
"fontFamily",
|
|
1808
|
+
"fontSize",
|
|
1809
|
+
"fontWeight",
|
|
1810
|
+
"lineHeight",
|
|
1811
|
+
"letterSpacing",
|
|
1812
|
+
"textDecoration"
|
|
1813
|
+
];
|
|
1814
|
+
var COLOR_FIELDS = /* @__PURE__ */ new Set(["fill", "stroke", "textFill"]);
|
|
1758
1815
|
function coverageSummary(file) {
|
|
1759
1816
|
const list2 = file.coverage ?? file.components.map((c) => ({ name: c.name, status: "generated" }));
|
|
1760
1817
|
const generated = list2.filter((c) => c.status === "generated").length;
|
|
@@ -1762,6 +1819,18 @@ function coverageSummary(file) {
|
|
|
1762
1819
|
const layout = list2.filter((c) => c.status === "layout").length;
|
|
1763
1820
|
return { generated, drafted, inFigma: generated + drafted, visual: list2.length - layout, layout, total: list2.length, missing: list2.filter((c) => c.status === "unsupported") };
|
|
1764
1821
|
}
|
|
1822
|
+
function specHash(text) {
|
|
1823
|
+
let h = 2166136261;
|
|
1824
|
+
for (let i = 0; i < text.length; i++) {
|
|
1825
|
+
h ^= text.charCodeAt(i);
|
|
1826
|
+
h = Math.imul(h, 16777619);
|
|
1827
|
+
}
|
|
1828
|
+
return (h >>> 0).toString(16).padStart(8, "0");
|
|
1829
|
+
}
|
|
1830
|
+
function hashSpec(spec) {
|
|
1831
|
+
const { hash: _ignored, example: _example, ...rest } = spec;
|
|
1832
|
+
return specHash(JSON.stringify(rest));
|
|
1833
|
+
}
|
|
1765
1834
|
var variantKeyOf = (props) => Object.keys(props).sort().map((k) => `${k}=${props[k]}`).join(", ") || "Default";
|
|
1766
1835
|
function parseComponentSpecs(text) {
|
|
1767
1836
|
let data;
|
|
@@ -1805,7 +1874,7 @@ var STATE_PSEUDO = {
|
|
|
1805
1874
|
var iconName = (component) => component.replace(/^Icon\//, "");
|
|
1806
1875
|
var exportName = (name) => name.replace(/[^A-Za-z0-9]+/g, "");
|
|
1807
1876
|
function planReference(spec, variant, file) {
|
|
1808
|
-
if (spec.view === "popup") return
|
|
1877
|
+
if (spec.view === "popup") return planPopup(spec, variant);
|
|
1809
1878
|
const props = { ...spec.fixed ?? {} };
|
|
1810
1879
|
let pseudo;
|
|
1811
1880
|
for (const axis of spec.axes) {
|
|
@@ -1834,6 +1903,7 @@ function planReference(spec, variant, file) {
|
|
|
1834
1903
|
if (part.swap && swapTo) {
|
|
1835
1904
|
const slot = file?.slots?.find((s) => s.name === swapTo);
|
|
1836
1905
|
if (!slot) return { reason: `${swapTo} is not in the specs` };
|
|
1906
|
+
if (slot.kind === "media") return { reason: `Figma shows a media placeholder (${swapTo}); code shows the image it is given, nothing to compare` };
|
|
1837
1907
|
if (slot.kind !== "text" || !slot.text) return { reason: `Figma shows a placeholder (${swapTo}) that code has no example of` };
|
|
1838
1908
|
return slot.text.default;
|
|
1839
1909
|
}
|
|
@@ -1885,10 +1955,13 @@ function planReference(spec, variant, file) {
|
|
|
1885
1955
|
}
|
|
1886
1956
|
const example = spec.example;
|
|
1887
1957
|
const exampleChildren = example?.children?.length ? example.children : void 0;
|
|
1958
|
+
const component = exportName(example?.c ?? (spec.name.includes("/") ? spec.component ?? spec.name : spec.name));
|
|
1959
|
+
const parent = spec.component ? exportName(spec.component) : void 0;
|
|
1888
1960
|
return {
|
|
1889
1961
|
ok: true,
|
|
1890
1962
|
render: {
|
|
1891
|
-
component
|
|
1963
|
+
component,
|
|
1964
|
+
...parent && parent !== component ? { within: parent } : {},
|
|
1892
1965
|
props: { ...example?.p ?? {}, ...props },
|
|
1893
1966
|
...exampleChildren ? { children: exampleChildren } : {},
|
|
1894
1967
|
...text !== void 0 && !exampleChildren ? { text } : {},
|
|
@@ -1899,6 +1972,28 @@ function planReference(spec, variant, file) {
|
|
|
1899
1972
|
}
|
|
1900
1973
|
};
|
|
1901
1974
|
}
|
|
1975
|
+
function planPopup(spec, variant) {
|
|
1976
|
+
const root = spec.parts.find((p) => !p.parent);
|
|
1977
|
+
const own = {};
|
|
1978
|
+
for (const axis of spec.axes) {
|
|
1979
|
+
const value = variant.props[axis.name];
|
|
1980
|
+
if (!axis.prop || value === void 0) return { ok: false, reason: `${axis.name} has no matching option in code` };
|
|
1981
|
+
own[axis.prop] = value === "true" ? true : value === "false" ? false : value;
|
|
1982
|
+
}
|
|
1983
|
+
const className = /\.module\.css \.([\w-]+)/.exec(root?.source ?? "")?.[1];
|
|
1984
|
+
const component = spec.component ? exportName(spec.component) : void 0;
|
|
1985
|
+
const example = spec.example;
|
|
1986
|
+
if (!component || !example) return { ok: false, reason: "drawn open from no code example: nothing to open in code" };
|
|
1987
|
+
if (!className) return { ok: false, reason: "the popup has no class to find it by in code" };
|
|
1988
|
+
const popup = { className };
|
|
1989
|
+
if (exportName(example.c) === component) {
|
|
1990
|
+
return { ok: true, render: { component, props: { ...example.p ?? {}, ...own, defaultOpen: true }, ...example.children?.length ? { children: example.children } : {}, popup } };
|
|
1991
|
+
}
|
|
1992
|
+
return {
|
|
1993
|
+
ok: true,
|
|
1994
|
+
render: { component, props: { defaultOpen: true }, children: [{ c: `${component}Trigger`, children: ["Open"] }, { ...example, p: { ...example.p ?? {}, ...own } }], popup }
|
|
1995
|
+
};
|
|
1996
|
+
}
|
|
1902
1997
|
function referenceImagePath(component, key) {
|
|
1903
1998
|
const slug = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
1904
1999
|
const file = key.split(",").map((kv) => slug(kv)).filter(Boolean).join("__");
|
|
@@ -2053,6 +2148,7 @@ export {
|
|
|
2053
2148
|
CONFIG_FILE,
|
|
2054
2149
|
DEFAULT_OVERRIDE,
|
|
2055
2150
|
DEFAULT_TOKEN_PATHS,
|
|
2151
|
+
DEFAULT_GOVERNANCE,
|
|
2056
2152
|
loadConfig,
|
|
2057
2153
|
tokensPath,
|
|
2058
2154
|
protectedBranchesOf,
|
|
@@ -2067,6 +2163,7 @@ export {
|
|
|
2067
2163
|
parseContrastChecks,
|
|
2068
2164
|
threeWayDiff,
|
|
2069
2165
|
RISK_LABELS,
|
|
2166
|
+
isGuardrail,
|
|
2070
2167
|
classifyRisk,
|
|
2071
2168
|
aliasOf,
|
|
2072
2169
|
globToRegExp,
|
|
@@ -2088,7 +2185,10 @@ export {
|
|
|
2088
2185
|
ProtectedBranchError,
|
|
2089
2186
|
assertSafeBranch,
|
|
2090
2187
|
DEFAULT_COMPONENT_SPECS_FILE,
|
|
2188
|
+
SPEC_FIELDS,
|
|
2189
|
+
COLOR_FIELDS,
|
|
2091
2190
|
coverageSummary,
|
|
2191
|
+
hashSpec,
|
|
2092
2192
|
variantKeyOf,
|
|
2093
2193
|
parseComponentSpecs,
|
|
2094
2194
|
figmaCell,
|