@buoy-design/cli 0.6.1 → 0.7.1
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/commands/check.d.ts +6 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +19 -9
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/mcp.d.ts +10 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +71 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/show.d.ts.map +1 -1
- package/dist/commands/show.js +13 -12
- package/dist/commands/show.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/file-check.d.ts +20 -0
- package/dist/mcp/file-check.d.ts.map +1 -0
- package/dist/mcp/file-check.js +195 -0
- package/dist/mcp/file-check.js.map +1 -0
- package/dist/mcp/hook.d.ts +16 -0
- package/dist/mcp/hook.d.ts.map +1 -0
- package/dist/mcp/hook.js +42 -0
- package/dist/mcp/hook.js.map +1 -0
- package/dist/mcp/install.d.ts +14 -0
- package/dist/mcp/install.d.ts.map +1 -0
- package/dist/mcp/install.js +67 -0
- package/dist/mcp/install.js.map +1 -0
- package/dist/mcp/project.d.ts +49 -0
- package/dist/mcp/project.d.ts.map +1 -0
- package/dist/mcp/project.js +110 -0
- package/dist/mcp/project.js.map +1 -0
- package/dist/mcp/server.d.ts +13 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +98 -0
- package/dist/mcp/server.js.map +1 -0
- package/package.json +5 -3
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line-level drift check for a handful of files.
|
|
3
|
+
*
|
|
4
|
+
* The repo-wide DriftAnalysisService reasons about components; it does not
|
|
5
|
+
* look at literal values inside plain CSS, and it reports a component's line,
|
|
6
|
+
* not the value's. Agents need "line 12: #fff -> var(--color-white)", so this
|
|
7
|
+
* runs the same value-level extractors the PR reviewer uses, per file, and
|
|
8
|
+
* looks each value up in the repo's tokens.
|
|
9
|
+
*/
|
|
10
|
+
import { readFile } from "node:fs/promises";
|
|
11
|
+
import { isAbsolute, join, relative } from "node:path";
|
|
12
|
+
import { extractBorderWidthSignals, extractColorSignals, extractDurationSignals, extractEasingSignals, extractFontFamilySignals, extractFontSizeSignals, extractFontWeightSignals, extractLetterSpacingSignals, extractLineHeightSignals, extractOpacitySignals, extractRadiusSignals, extractShadowSignals, extractSpacingSignals, extractTransitionShorthandSignals, extractZIndexSignals, } from "@buoy-design/scanners";
|
|
13
|
+
import { findTokensByValue } from "./project.js";
|
|
14
|
+
const COLOR_PART = /^(#[0-9a-f]{3,8}|rgba?\(|hsla?\(|oklch\(|oklab\(|color\()/i;
|
|
15
|
+
/** Split a shorthand value on spaces, keeping function calls like rgb(...) intact. */
|
|
16
|
+
export function splitCssValue(value) {
|
|
17
|
+
const parts = [];
|
|
18
|
+
let current = "";
|
|
19
|
+
let depth = 0;
|
|
20
|
+
for (const ch of value) {
|
|
21
|
+
if (ch === "(")
|
|
22
|
+
depth++;
|
|
23
|
+
if (ch === ")")
|
|
24
|
+
depth--;
|
|
25
|
+
if (ch === " " && depth === 0) {
|
|
26
|
+
if (current)
|
|
27
|
+
parts.push(current);
|
|
28
|
+
current = "";
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
current += ch;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (current)
|
|
35
|
+
parts.push(current);
|
|
36
|
+
return parts;
|
|
37
|
+
}
|
|
38
|
+
// Same routing as the cloud scanner container (containers/scanner/src/index.js).
|
|
39
|
+
const CSS_PROPERTY_EXTRACTORS = {
|
|
40
|
+
color: "color", "background-color": "color", "border-color": "color", "outline-color": "color",
|
|
41
|
+
"text-decoration-color": "color", fill: "color", stroke: "color", "caret-color": "color", "accent-color": "color",
|
|
42
|
+
padding: "spacing", "padding-top": "spacing", "padding-right": "spacing", "padding-bottom": "spacing", "padding-left": "spacing",
|
|
43
|
+
"padding-inline": "spacing", "padding-block": "spacing",
|
|
44
|
+
margin: "spacing", "margin-top": "spacing", "margin-right": "spacing", "margin-bottom": "spacing", "margin-left": "spacing",
|
|
45
|
+
"margin-inline": "spacing", "margin-block": "spacing",
|
|
46
|
+
gap: "spacing", "row-gap": "spacing", "column-gap": "spacing",
|
|
47
|
+
top: "spacing", right: "spacing", bottom: "spacing", left: "spacing", inset: "spacing",
|
|
48
|
+
"font-size": "fontSize", "font-family": "fontFamily", "font-weight": "fontWeight",
|
|
49
|
+
"line-height": "lineHeight", "letter-spacing": "letterSpacing",
|
|
50
|
+
"border-radius": "radius", "border-top-left-radius": "radius", "border-top-right-radius": "radius",
|
|
51
|
+
"border-bottom-left-radius": "radius", "border-bottom-right-radius": "radius",
|
|
52
|
+
"box-shadow": "shadow", "text-shadow": "shadow",
|
|
53
|
+
"z-index": "zIndex", opacity: "opacity",
|
|
54
|
+
"transition-duration": "duration", "animation-duration": "duration",
|
|
55
|
+
"transition-timing-function": "easing", "animation-timing-function": "easing",
|
|
56
|
+
transition: "transitionShorthand",
|
|
57
|
+
"border-width": "borderWidth", "border-top-width": "borderWidth", "border-right-width": "borderWidth",
|
|
58
|
+
"border-bottom-width": "borderWidth", "border-left-width": "borderWidth",
|
|
59
|
+
background: "colorShorthand", border: "colorShorthand", "border-top": "colorShorthand",
|
|
60
|
+
"border-right": "colorShorthand", "border-bottom": "colorShorthand", "border-left": "colorShorthand", outline: "colorShorthand",
|
|
61
|
+
};
|
|
62
|
+
const JSX_PROPERTY_EXTRACTORS = Object.fromEntries(Object.entries(CSS_PROPERTY_EXTRACTORS).map(([prop, extractor]) => [
|
|
63
|
+
prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase()),
|
|
64
|
+
extractor,
|
|
65
|
+
]));
|
|
66
|
+
// Signal type -> token category to search for a replacement.
|
|
67
|
+
const SIGNAL_CATEGORY = {
|
|
68
|
+
"color-value": "color",
|
|
69
|
+
"spacing-value": "spacing",
|
|
70
|
+
"radius-value": "border",
|
|
71
|
+
"shadow-value": "shadow",
|
|
72
|
+
"border-width": "border",
|
|
73
|
+
"font-size": "typography",
|
|
74
|
+
"font-family": "typography",
|
|
75
|
+
"font-weight": "typography",
|
|
76
|
+
"line-height": "typography",
|
|
77
|
+
"letter-spacing": "typography",
|
|
78
|
+
"z-index": "zIndex",
|
|
79
|
+
"motion-duration": "motion",
|
|
80
|
+
"motion-easing": "motion",
|
|
81
|
+
"opacity-value": undefined,
|
|
82
|
+
};
|
|
83
|
+
const CSS_PROP = /([a-z-]+)\s*:\s*([^;{}]+)/g;
|
|
84
|
+
const JSX_PROP = /(\w+)\s*:\s*(?:'([^']*)'|"([^"]*)"|(\d+\.?\d*)(?=[,}\s]))/g;
|
|
85
|
+
function route(extractor, value, path, line, property, ctx) {
|
|
86
|
+
switch (extractor) {
|
|
87
|
+
case "color": return extractColorSignals(value, path, line, property, ctx);
|
|
88
|
+
case "spacing": return extractSpacingSignals(value, path, line, property, ctx);
|
|
89
|
+
case "fontSize": return extractFontSizeSignals(value, path, line, ctx);
|
|
90
|
+
case "fontFamily": return extractFontFamilySignals(value, path, line, ctx);
|
|
91
|
+
case "fontWeight": return extractFontWeightSignals(value, path, line, ctx);
|
|
92
|
+
case "lineHeight": return extractLineHeightSignals(value, path, line, ctx);
|
|
93
|
+
case "letterSpacing": return extractLetterSpacingSignals(value, path, line, ctx);
|
|
94
|
+
case "radius": return extractRadiusSignals(value, path, line, property, ctx);
|
|
95
|
+
case "shadow": return extractShadowSignals(value, path, line, property, ctx);
|
|
96
|
+
case "zIndex": return extractZIndexSignals(value, path, line, ctx);
|
|
97
|
+
case "opacity": return extractOpacitySignals(value, path, line, ctx);
|
|
98
|
+
case "duration": return extractDurationSignals(value, path, line, property, ctx);
|
|
99
|
+
case "easing": return extractEasingSignals(value, path, line, property, ctx);
|
|
100
|
+
case "borderWidth": return extractBorderWidthSignals(value, path, line, property, ctx);
|
|
101
|
+
case "transitionShorthand": return extractTransitionShorthandSignals(value, path, line, ctx);
|
|
102
|
+
case "colorShorthand":
|
|
103
|
+
// background / border shorthands: only the colour part is a token candidate.
|
|
104
|
+
return splitCssValue(value)
|
|
105
|
+
.filter((part) => COLOR_PART.test(part))
|
|
106
|
+
.flatMap((part) => extractColorSignals(part, path, line, `${property}-color`, ctx));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** Value-level signals for one file's content. Pure; `path` is only used for locations. */
|
|
110
|
+
export function extractFileSignals(content, path) {
|
|
111
|
+
const isCss = /\.(css|scss)$/.test(path);
|
|
112
|
+
const isJsx = /\.(tsx|jsx)$/.test(path);
|
|
113
|
+
if (!isCss && !isJsx)
|
|
114
|
+
return [];
|
|
115
|
+
const ctx = {
|
|
116
|
+
fileType: isCss ? "css" : "tsx",
|
|
117
|
+
framework: isJsx ? "react" : "css",
|
|
118
|
+
scope: "global",
|
|
119
|
+
isTokenized: false,
|
|
120
|
+
};
|
|
121
|
+
const signals = [];
|
|
122
|
+
const lines = content.split("\n");
|
|
123
|
+
for (let i = 0; i < lines.length; i++) {
|
|
124
|
+
const line = lines[i] ?? "";
|
|
125
|
+
// Already tokenised: var(--x), theme.x, tokens.x, $scss-var
|
|
126
|
+
if (line.includes("var(--") || line.includes("theme.") || line.includes("tokens.") || line.includes("$"))
|
|
127
|
+
continue;
|
|
128
|
+
const pattern = isCss ? CSS_PROP : JSX_PROP;
|
|
129
|
+
const table = isCss ? CSS_PROPERTY_EXTRACTORS : JSX_PROPERTY_EXTRACTORS;
|
|
130
|
+
pattern.lastIndex = 0;
|
|
131
|
+
let m;
|
|
132
|
+
while ((m = pattern.exec(line)) !== null) {
|
|
133
|
+
const property = (m[1] ?? "").trim();
|
|
134
|
+
const extractor = table[property];
|
|
135
|
+
if (!extractor)
|
|
136
|
+
continue;
|
|
137
|
+
let value = isCss ? (m[2] ?? "").trim() : (m[2] ?? m[3] ?? m[4]);
|
|
138
|
+
if (value === undefined || value === "")
|
|
139
|
+
continue;
|
|
140
|
+
// Bare numbers in JSX style objects are pixels.
|
|
141
|
+
if (isJsx && m[4] !== undefined)
|
|
142
|
+
value = `${value}px`;
|
|
143
|
+
signals.push(...route(extractor, value, path, i + 1, property, ctx));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return signals;
|
|
147
|
+
}
|
|
148
|
+
function tokenRef(token) {
|
|
149
|
+
return token.name.startsWith("--") ? `var(${token.name})` : token.name;
|
|
150
|
+
}
|
|
151
|
+
/** Turn raw signals into issues, attaching the token that has the same value when one exists. */
|
|
152
|
+
export function issuesFromSignals(signals, tokens) {
|
|
153
|
+
const seen = new Set();
|
|
154
|
+
const issues = [];
|
|
155
|
+
for (const s of signals) {
|
|
156
|
+
const current = String(s.value);
|
|
157
|
+
const key = `${s.location.path}:${s.location.line}:${s.type}:${current}`;
|
|
158
|
+
if (seen.has(key))
|
|
159
|
+
continue;
|
|
160
|
+
seen.add(key);
|
|
161
|
+
const category = SIGNAL_CATEGORY[s.type];
|
|
162
|
+
const matches = findTokensByValue(tokens, current, category);
|
|
163
|
+
const first = matches[0];
|
|
164
|
+
const label = s.type.replace(/-value$/, "").replace(/-/g, " ");
|
|
165
|
+
issues.push({
|
|
166
|
+
file: s.location.path,
|
|
167
|
+
line: s.location.line,
|
|
168
|
+
type: `hardcoded-${s.type.replace(/-value$/, "")}`,
|
|
169
|
+
severity: first ? "warning" : "info",
|
|
170
|
+
message: first
|
|
171
|
+
? `Hardcoded ${label} ${current} has a token: ${first.name}`
|
|
172
|
+
: `Hardcoded ${label} ${current} (no matching token)`,
|
|
173
|
+
current,
|
|
174
|
+
...(first ? { suggested: tokenRef(first), tokenSuggestions: matches.map(tokenRef) } : {}),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return issues;
|
|
178
|
+
}
|
|
179
|
+
export async function checkFiles(files, projectRoot, tokens) {
|
|
180
|
+
const issues = [];
|
|
181
|
+
for (const file of files) {
|
|
182
|
+
const abs = isAbsolute(file) ? file : join(projectRoot, file);
|
|
183
|
+
const rel = relative(projectRoot, abs) || file;
|
|
184
|
+
let content;
|
|
185
|
+
try {
|
|
186
|
+
content = await readFile(abs, "utf8");
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
continue; // deleted or unreadable: nothing to check
|
|
190
|
+
}
|
|
191
|
+
issues.push(...issuesFromSignals(extractFileSignals(content, rel), tokens));
|
|
192
|
+
}
|
|
193
|
+
return issues;
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=file-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-check.js","sourceRoot":"","sources":["../../src/mcp/file-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code PostToolUse hook: after the agent edits a file, check that
|
|
3
|
+
* file for drift and hand the issues back as feedback (exit code 2). Other
|
|
4
|
+
* agents can call `buoy mcp hook --file <path>` the same way.
|
|
5
|
+
*/
|
|
6
|
+
import { type DriftCheck } from "./project.js";
|
|
7
|
+
/** Pull the edited path out of a Claude Code hook payload. */
|
|
8
|
+
export declare function filePathFromHookPayload(raw: string): string | null;
|
|
9
|
+
export declare function isStyleFile(path: string): boolean;
|
|
10
|
+
export declare function formatHookFeedback(file: string, check: DriftCheck): string;
|
|
11
|
+
export interface HookResult {
|
|
12
|
+
exitCode: 0 | 2;
|
|
13
|
+
message: string | null;
|
|
14
|
+
}
|
|
15
|
+
export declare function runHook(cwd: string, file: string | null): Promise<HookResult>;
|
|
16
|
+
//# sourceMappingURL=hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/mcp/hook.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAA2B,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAIxE,8DAA8D;AAC9D,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOlE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAU1E;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAMnF"}
|
package/dist/mcp/hook.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code PostToolUse hook: after the agent edits a file, check that
|
|
3
|
+
* file for drift and hand the issues back as feedback (exit code 2). Other
|
|
4
|
+
* agents can call `buoy mcp hook --file <path>` the same way.
|
|
5
|
+
*/
|
|
6
|
+
import { checkDrift, loadProject } from "./project.js";
|
|
7
|
+
const STYLE_FILE = /\.(tsx|jsx|vue|svelte|css|scss|html)$/;
|
|
8
|
+
/** Pull the edited path out of a Claude Code hook payload. */
|
|
9
|
+
export function filePathFromHookPayload(raw) {
|
|
10
|
+
try {
|
|
11
|
+
const payload = JSON.parse(raw);
|
|
12
|
+
return payload.tool_input?.file_path ?? payload.tool_input?.path ?? payload.tool_response?.filePath ?? null;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function isStyleFile(path) {
|
|
19
|
+
return STYLE_FILE.test(path);
|
|
20
|
+
}
|
|
21
|
+
export function formatHookFeedback(file, check) {
|
|
22
|
+
const lines = [`Buoy: ${check.summary.total} design drift issue${check.summary.total === 1 ? "" : "s"} in ${file}`];
|
|
23
|
+
for (const issue of check.issues.slice(0, 15)) {
|
|
24
|
+
const where = issue.line ? `:${issue.line}` : "";
|
|
25
|
+
const fix = issue.suggested ? ` -> use ${issue.suggested}` : issue.tokenSuggestions?.[0] ? ` -> ${issue.tokenSuggestions[0]}` : "";
|
|
26
|
+
lines.push(`- ${issue.file}${where} ${issue.message}${fix}`);
|
|
27
|
+
}
|
|
28
|
+
if (check.issues.length > 15)
|
|
29
|
+
lines.push(`- ... and ${check.issues.length - 15} more`);
|
|
30
|
+
lines.push("Replace the literal values with the tokens above, then continue.");
|
|
31
|
+
return lines.join("\n");
|
|
32
|
+
}
|
|
33
|
+
export async function runHook(cwd, file) {
|
|
34
|
+
if (!file || !isStyleFile(file))
|
|
35
|
+
return { exitCode: 0, message: null };
|
|
36
|
+
const project = await loadProject(cwd);
|
|
37
|
+
const check = await checkDrift(project, [file]);
|
|
38
|
+
if (check.summary.total === 0)
|
|
39
|
+
return { exitCode: 0, message: null };
|
|
40
|
+
return { exitCode: 2, message: formatHookFeedback(file, check) };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../../src/mcp/hook.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAmB,MAAM,cAAc,CAAC;AAExE,MAAM,UAAU,GAAG,uCAAuC,CAAC;AAE3D,8DAA8D;AAC9D,MAAM,UAAU,uBAAuB,CAAC,GAAW;IACjD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkG,CAAC;QACjI,OAAO,OAAO,CAAC,UAAU,EAAE,SAAS,IAAI,OAAO,CAAC,UAAU,EAAE,IAAI,IAAI,OAAO,CAAC,aAAa,EAAE,QAAQ,IAAI,IAAI,CAAC;IAC9G,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,KAAiB;IAChE,MAAM,KAAK,GAAG,CAAC,SAAS,KAAK,CAAC,OAAO,CAAC,KAAK,sBAAsB,KAAK,CAAC,OAAO,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,EAAE,CAAC,CAAC;IACpH,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnI,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,GAAG,KAAK,IAAI,KAAK,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,aAAa,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;IACvF,KAAK,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;IAC/E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAOD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAW,EAAE,IAAmB;IAC5D,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACvE,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAChD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACrE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,kBAAkB,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type McpClient = "claude" | "cursor" | "codex" | "windsurf";
|
|
2
|
+
export declare const MCP_CLIENTS: McpClient[];
|
|
3
|
+
/** Merge Buoy into an `mcpServers` map without touching other servers. */
|
|
4
|
+
export declare function mergeMcpServers(existing: Record<string, unknown>): Record<string, unknown>;
|
|
5
|
+
/** Add the PostToolUse hook to Claude Code settings unless it is already there. */
|
|
6
|
+
export declare function mergeClaudeHook(existing: Record<string, unknown>): Record<string, unknown>;
|
|
7
|
+
export interface InstallResult {
|
|
8
|
+
client: McpClient;
|
|
9
|
+
files: string[];
|
|
10
|
+
}
|
|
11
|
+
export declare function installClient(client: McpClient, cwd: string, options?: {
|
|
12
|
+
hook?: boolean;
|
|
13
|
+
}): InstallResult;
|
|
14
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/mcp/install.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AACnE,eAAO,MAAM,WAAW,EAAE,SAAS,EAA8C,CAAC;AAuBlF,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAG1F;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQ1F;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,aAAa,CAwB7G"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write the client-side config that connects an agent to `buoy mcp serve`.
|
|
3
|
+
* Every target is a JSON file in the project; existing entries are kept.
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
export const MCP_CLIENTS = ["claude", "cursor", "codex", "windsurf"];
|
|
8
|
+
const SERVER_ENTRY = { command: "npx", args: ["-y", "@buoy-design/cli", "mcp", "serve"] };
|
|
9
|
+
const HOOK_ENTRY = {
|
|
10
|
+
matcher: "Edit|Write|MultiEdit",
|
|
11
|
+
hooks: [{ type: "command", command: "npx -y @buoy-design/cli mcp hook", timeout: 120 }],
|
|
12
|
+
};
|
|
13
|
+
function readJson(path) {
|
|
14
|
+
if (!existsSync(path))
|
|
15
|
+
return {};
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
throw new Error(`${path} is not valid JSON; fix or remove it and retry`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function writeJson(path, value) {
|
|
24
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
25
|
+
writeFileSync(path, JSON.stringify(value, null, 2) + "\n");
|
|
26
|
+
}
|
|
27
|
+
/** Merge Buoy into an `mcpServers` map without touching other servers. */
|
|
28
|
+
export function mergeMcpServers(existing) {
|
|
29
|
+
const servers = (existing.mcpServers && typeof existing.mcpServers === "object" ? existing.mcpServers : {});
|
|
30
|
+
return { ...existing, mcpServers: { ...servers, buoy: SERVER_ENTRY } };
|
|
31
|
+
}
|
|
32
|
+
/** Add the PostToolUse hook to Claude Code settings unless it is already there. */
|
|
33
|
+
export function mergeClaudeHook(existing) {
|
|
34
|
+
const hooks = (existing.hooks && typeof existing.hooks === "object" ? existing.hooks : {});
|
|
35
|
+
const post = Array.isArray(hooks.PostToolUse) ? hooks.PostToolUse : [];
|
|
36
|
+
const present = post.some((entry) => JSON.stringify(entry).includes("mcp hook"));
|
|
37
|
+
return {
|
|
38
|
+
...existing,
|
|
39
|
+
hooks: { ...hooks, PostToolUse: present ? post : [...post, HOOK_ENTRY] },
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export function installClient(client, cwd, options = {}) {
|
|
43
|
+
const files = [];
|
|
44
|
+
const upsert = (relative, merge) => {
|
|
45
|
+
const path = join(cwd, relative);
|
|
46
|
+
writeJson(path, merge(readJson(path)));
|
|
47
|
+
files.push(relative);
|
|
48
|
+
};
|
|
49
|
+
switch (client) {
|
|
50
|
+
case "claude":
|
|
51
|
+
upsert(".mcp.json", mergeMcpServers);
|
|
52
|
+
if (options.hook !== false)
|
|
53
|
+
upsert(".claude/settings.json", mergeClaudeHook);
|
|
54
|
+
break;
|
|
55
|
+
case "cursor":
|
|
56
|
+
upsert(".cursor/mcp.json", mergeMcpServers);
|
|
57
|
+
break;
|
|
58
|
+
case "windsurf":
|
|
59
|
+
upsert(".windsurf/mcp.json", mergeMcpServers);
|
|
60
|
+
break;
|
|
61
|
+
case "codex":
|
|
62
|
+
upsert(".codex/mcp.json", mergeMcpServers);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
return { client, files };
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/mcp/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { BuoyConfig } from "../config/schema.js";
|
|
2
|
+
import type { DesignToken, DriftSignal } from "@buoy-design/core";
|
|
3
|
+
export interface ProjectContext {
|
|
4
|
+
config: BuoyConfig;
|
|
5
|
+
projectRoot: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function loadProject(cwd: string): Promise<ProjectContext>;
|
|
8
|
+
export interface TokenSummary {
|
|
9
|
+
name: string;
|
|
10
|
+
category: DesignToken["category"];
|
|
11
|
+
value: string;
|
|
12
|
+
source?: string;
|
|
13
|
+
deprecated?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function formatTokenValue(token: DesignToken): string;
|
|
16
|
+
export declare function summarizeToken(token: DesignToken): TokenSummary;
|
|
17
|
+
/** Normalise a CSS-ish value so `#FFF`, `#ffffff` and ` 8px ` compare equal. */
|
|
18
|
+
export declare function normalizeValue(value: string): string;
|
|
19
|
+
export declare function findTokensByValue(tokens: DesignToken[], value: string, category?: string): TokenSummary[];
|
|
20
|
+
export declare function scanTokens(project: ProjectContext): Promise<DesignToken[]>;
|
|
21
|
+
export interface DriftIssue {
|
|
22
|
+
file: string;
|
|
23
|
+
line?: number;
|
|
24
|
+
type: string;
|
|
25
|
+
severity: string;
|
|
26
|
+
message: string;
|
|
27
|
+
current?: unknown;
|
|
28
|
+
suggested?: string;
|
|
29
|
+
tokenSuggestions?: string[];
|
|
30
|
+
}
|
|
31
|
+
export declare function toIssue(drift: DriftSignal): DriftIssue;
|
|
32
|
+
export interface DriftCheck {
|
|
33
|
+
issues: DriftIssue[];
|
|
34
|
+
summary: {
|
|
35
|
+
total: number;
|
|
36
|
+
critical: number;
|
|
37
|
+
warning: number;
|
|
38
|
+
info: number;
|
|
39
|
+
fixable: number;
|
|
40
|
+
};
|
|
41
|
+
tokenCount: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* With `files`: line-level literal values in those files, each matched to a
|
|
45
|
+
* token (fast, what an agent needs right after an edit). Without: the full
|
|
46
|
+
* repo analysis, which also covers components, unused tokens and contrast.
|
|
47
|
+
*/
|
|
48
|
+
export declare function checkDrift(project: ProjectContext, files?: string[], tokens?: DesignToken[]): Promise<DriftCheck>;
|
|
49
|
+
//# sourceMappingURL=project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/mcp/project.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAOtD,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAElE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAQtE;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAW3D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,CAS/D;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAMzG;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAIhF;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,CActD;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7F,UAAU,EAAE,MAAM,CAAC;CACpB;AAgBD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAUvH"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project snapshot for the MCP server and the agent hook.
|
|
3
|
+
*
|
|
4
|
+
* Both need the same thing: this repo's tokens, and drift for some files.
|
|
5
|
+
* Everything here reuses the CLI's scan pipeline; nothing is re-detected.
|
|
6
|
+
*/
|
|
7
|
+
import { dirname } from "node:path";
|
|
8
|
+
import { loadConfig, getConfigPath } from "../config/loader.js";
|
|
9
|
+
import { buildAutoConfig } from "../config/auto-detect.js";
|
|
10
|
+
import { ScanOrchestrator } from "../scan/orchestrator.js";
|
|
11
|
+
import { DriftAnalysisService } from "../services/drift-analysis.js";
|
|
12
|
+
import { filterScannableFiles } from "../commands/check.js";
|
|
13
|
+
import { checkFiles } from "./file-check.js";
|
|
14
|
+
export async function loadProject(cwd) {
|
|
15
|
+
const configPath = getConfigPath(cwd);
|
|
16
|
+
if (configPath) {
|
|
17
|
+
const loaded = await loadConfig(cwd);
|
|
18
|
+
return { config: loaded.config, projectRoot: loaded.configPath ? dirname(loaded.configPath) : cwd };
|
|
19
|
+
}
|
|
20
|
+
const auto = await buildAutoConfig(cwd);
|
|
21
|
+
return { config: auto.config, projectRoot: cwd };
|
|
22
|
+
}
|
|
23
|
+
export function formatTokenValue(token) {
|
|
24
|
+
const v = token.value;
|
|
25
|
+
switch (v.type) {
|
|
26
|
+
case "color": return v.hex;
|
|
27
|
+
case "spacing": return `${v.value}${v.unit}`;
|
|
28
|
+
case "typography": return `${v.fontFamily} ${v.fontSize}`;
|
|
29
|
+
case "shadow": return `${v.x}px ${v.y}px ${v.blur}px ${v.spread}px ${v.color}`;
|
|
30
|
+
case "border": return `${v.width}px ${v.style} ${v.color}`;
|
|
31
|
+
case "raw": return String(v.value);
|
|
32
|
+
default: return "(complex)";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function summarizeToken(token) {
|
|
36
|
+
const source = "path" in token.source ? token.source.path : undefined;
|
|
37
|
+
return {
|
|
38
|
+
name: token.name,
|
|
39
|
+
category: token.category,
|
|
40
|
+
value: formatTokenValue(token),
|
|
41
|
+
...(source ? { source } : {}),
|
|
42
|
+
...(token.metadata?.deprecated ? { deprecated: true } : {}),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Normalise a CSS-ish value so `#FFF`, `#ffffff` and ` 8px ` compare equal. */
|
|
46
|
+
export function normalizeValue(value) {
|
|
47
|
+
let v = value.trim().toLowerCase().replace(/\s+/g, " ");
|
|
48
|
+
const shortHex = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/.exec(v);
|
|
49
|
+
if (shortHex)
|
|
50
|
+
v = `#${shortHex[1]}${shortHex[1]}${shortHex[2]}${shortHex[2]}${shortHex[3]}${shortHex[3]}`;
|
|
51
|
+
v = v.replace(/(\d)\.0+(px|rem|em|%)?$/, "$1$2").replace(/^0(px|rem|em)$/, "0");
|
|
52
|
+
return v;
|
|
53
|
+
}
|
|
54
|
+
export function findTokensByValue(tokens, value, category) {
|
|
55
|
+
const wanted = normalizeValue(value);
|
|
56
|
+
return tokens
|
|
57
|
+
.filter((t) => !category || t.category === category)
|
|
58
|
+
.filter((t) => normalizeValue(formatTokenValue(t)) === wanted)
|
|
59
|
+
.map(summarizeToken);
|
|
60
|
+
}
|
|
61
|
+
export async function scanTokens(project) {
|
|
62
|
+
const orchestrator = new ScanOrchestrator(project.config, project.projectRoot);
|
|
63
|
+
const result = await orchestrator.scan();
|
|
64
|
+
return result.tokens;
|
|
65
|
+
}
|
|
66
|
+
export function toIssue(drift) {
|
|
67
|
+
const location = drift.source.location || "";
|
|
68
|
+
const [file, lineStr] = location.split(":");
|
|
69
|
+
const suggestions = drift.details?.suggestions;
|
|
70
|
+
return {
|
|
71
|
+
file: file || drift.source.entityName,
|
|
72
|
+
...(lineStr ? { line: parseInt(lineStr, 10) } : {}),
|
|
73
|
+
type: drift.type,
|
|
74
|
+
severity: drift.severity,
|
|
75
|
+
message: drift.message,
|
|
76
|
+
...(drift.details?.actual !== undefined ? { current: drift.details.actual } : {}),
|
|
77
|
+
...(suggestions?.[0] ? { suggested: suggestions[0] } : typeof drift.details?.expected === "string" ? { suggested: drift.details.expected } : {}),
|
|
78
|
+
...(drift.details?.tokenSuggestions?.length ? { tokenSuggestions: drift.details.tokenSuggestions } : {}),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function summarize(issues, tokenCount) {
|
|
82
|
+
return {
|
|
83
|
+
issues,
|
|
84
|
+
summary: {
|
|
85
|
+
total: issues.length,
|
|
86
|
+
critical: issues.filter((i) => i.severity === "critical").length,
|
|
87
|
+
warning: issues.filter((i) => i.severity === "warning").length,
|
|
88
|
+
info: issues.filter((i) => i.severity === "info").length,
|
|
89
|
+
fixable: issues.filter((i) => i.suggested || i.tokenSuggestions).length,
|
|
90
|
+
},
|
|
91
|
+
tokenCount,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* With `files`: line-level literal values in those files, each matched to a
|
|
96
|
+
* token (fast, what an agent needs right after an edit). Without: the full
|
|
97
|
+
* repo analysis, which also covers components, unused tokens and contrast.
|
|
98
|
+
*/
|
|
99
|
+
export async function checkDrift(project, files, tokens) {
|
|
100
|
+
if (files && files.length > 0) {
|
|
101
|
+
const scannable = filterScannableFiles(files);
|
|
102
|
+
const known = tokens ?? (await scanTokens(project));
|
|
103
|
+
const issues = scannable.length ? await checkFiles(scannable, project.projectRoot, known) : [];
|
|
104
|
+
return summarize(issues, known.length);
|
|
105
|
+
}
|
|
106
|
+
const service = new DriftAnalysisService(project.config, project.projectRoot);
|
|
107
|
+
const result = await service.analyze({ includeIgnored: false });
|
|
108
|
+
return summarize(result.drifts.map(toIssue), result.tokenCount);
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/mcp/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `buoy mcp serve`: a stdio MCP server that gives coding agents this repo's
|
|
3
|
+
* design tokens and drift checks, so hardcoded values are caught while the
|
|
4
|
+
* agent writes instead of on the PR.
|
|
5
|
+
*/
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
export interface BuoyMcpOptions {
|
|
8
|
+
cwd: string;
|
|
9
|
+
version: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function createBuoyMcpServer(options: BuoyMcpOptions): McpServer;
|
|
12
|
+
export declare function serveStdio(options: BuoyMcpOptions): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiBpE,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,CA4GtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvE"}
|