@gemini-designer/mcp-server 0.1.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/.prettierrc +9 -0
- package/dist/components/catalog.d.ts +24 -0
- package/dist/components/catalog.d.ts.map +1 -0
- package/dist/components/catalog.js +186 -0
- package/dist/components/catalog.js.map +1 -0
- package/dist/config/index.d.ts +60 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +199 -0
- package/dist/config/index.js.map +1 -0
- package/dist/context/builder.d.ts +32 -0
- package/dist/context/builder.d.ts.map +1 -0
- package/dist/context/builder.js +194 -0
- package/dist/context/builder.js.map +1 -0
- package/dist/context/filter.d.ts +28 -0
- package/dist/context/filter.d.ts.map +1 -0
- package/dist/context/filter.js +136 -0
- package/dist/context/filter.js.map +1 -0
- package/dist/context/grounding.d.ts +27 -0
- package/dist/context/grounding.d.ts.map +1 -0
- package/dist/context/grounding.js +162 -0
- package/dist/context/grounding.js.map +1 -0
- package/dist/context/guards.d.ts +31 -0
- package/dist/context/guards.d.ts.map +1 -0
- package/dist/context/guards.js +76 -0
- package/dist/context/guards.js.map +1 -0
- package/dist/context/repo-hints.d.ts +12 -0
- package/dist/context/repo-hints.d.ts.map +1 -0
- package/dist/context/repo-hints.js +40 -0
- package/dist/context/repo-hints.js.map +1 -0
- package/dist/generation/gemini-client.d.ts +27 -0
- package/dist/generation/gemini-client.d.ts.map +1 -0
- package/dist/generation/gemini-client.js +64 -0
- package/dist/generation/gemini-client.js.map +1 -0
- package/dist/generation/litellm-client.d.ts +16 -0
- package/dist/generation/litellm-client.d.ts.map +1 -0
- package/dist/generation/litellm-client.js +98 -0
- package/dist/generation/litellm-client.js.map +1 -0
- package/dist/generation/remote-client.d.ts +20 -0
- package/dist/generation/remote-client.d.ts.map +1 -0
- package/dist/generation/remote-client.js +69 -0
- package/dist/generation/remote-client.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/output/file-writer.d.ts +39 -0
- package/dist/output/file-writer.d.ts.map +1 -0
- package/dist/output/file-writer.js +153 -0
- package/dist/output/file-writer.js.map +1 -0
- package/dist/output/formatter.d.ts +26 -0
- package/dist/output/formatter.d.ts.map +1 -0
- package/dist/output/formatter.js +156 -0
- package/dist/output/formatter.js.map +1 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +22 -0
- package/dist/server.js.map +1 -0
- package/dist/stack/detect.d.ts +49 -0
- package/dist/stack/detect.d.ts.map +1 -0
- package/dist/stack/detect.js +157 -0
- package/dist/stack/detect.js.map +1 -0
- package/dist/tokens/sync.d.ts +32 -0
- package/dist/tokens/sync.d.ts.map +1 -0
- package/dist/tokens/sync.js +188 -0
- package/dist/tokens/sync.js.map +1 -0
- package/dist/tools/analyze-screenshot-ui.d.ts +18 -0
- package/dist/tools/analyze-screenshot-ui.d.ts.map +1 -0
- package/dist/tools/analyze-screenshot-ui.js +133 -0
- package/dist/tools/analyze-screenshot-ui.js.map +1 -0
- package/dist/tools/analyze-tokens.d.ts +10 -0
- package/dist/tools/analyze-tokens.d.ts.map +1 -0
- package/dist/tools/analyze-tokens.js +107 -0
- package/dist/tools/analyze-tokens.js.map +1 -0
- package/dist/tools/catalog-components.d.ts +14 -0
- package/dist/tools/catalog-components.d.ts.map +1 -0
- package/dist/tools/catalog-components.js +85 -0
- package/dist/tools/catalog-components.js.map +1 -0
- package/dist/tools/create-ui.d.ts +10 -0
- package/dist/tools/create-ui.d.ts.map +1 -0
- package/dist/tools/create-ui.js +167 -0
- package/dist/tools/create-ui.js.map +1 -0
- package/dist/tools/detect-ui-stack.d.ts +15 -0
- package/dist/tools/detect-ui-stack.d.ts.map +1 -0
- package/dist/tools/detect-ui-stack.js +52 -0
- package/dist/tools/detect-ui-stack.js.map +1 -0
- package/dist/tools/generate-component-variants.d.ts +15 -0
- package/dist/tools/generate-component-variants.d.ts.map +1 -0
- package/dist/tools/generate-component-variants.js +199 -0
- package/dist/tools/generate-component-variants.js.map +1 -0
- package/dist/tools/generate-vibes.d.ts +10 -0
- package/dist/tools/generate-vibes.d.ts.map +1 -0
- package/dist/tools/generate-vibes.js +145 -0
- package/dist/tools/generate-vibes.js.map +1 -0
- package/dist/tools/index.d.ts +12 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +36 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/modify-ui.d.ts +11 -0
- package/dist/tools/modify-ui.d.ts.map +1 -0
- package/dist/tools/modify-ui.js +207 -0
- package/dist/tools/modify-ui.js.map +1 -0
- package/dist/tools/scaffold-project.d.ts +10 -0
- package/dist/tools/scaffold-project.d.ts.map +1 -0
- package/dist/tools/scaffold-project.js +122 -0
- package/dist/tools/scaffold-project.js.map +1 -0
- package/dist/tools/snippet-ui.d.ts +11 -0
- package/dist/tools/snippet-ui.d.ts.map +1 -0
- package/dist/tools/snippet-ui.js +194 -0
- package/dist/tools/snippet-ui.js.map +1 -0
- package/dist/tools/sync-design-tokens.d.ts +14 -0
- package/dist/tools/sync-design-tokens.d.ts.map +1 -0
- package/dist/tools/sync-design-tokens.js +233 -0
- package/dist/tools/sync-design-tokens.js.map +1 -0
- package/dist/utils/walk.d.ts +15 -0
- package/dist/utils/walk.d.ts.map +1 -0
- package/dist/utils/walk.js +63 -0
- package/dist/utils/walk.js.map +1 -0
- package/eslint.config.js +37 -0
- package/package.json +56 -0
- package/src/__tests__/builder.test.ts +31 -0
- package/src/__tests__/config.test.ts +52 -0
- package/src/__tests__/filter.test.ts +109 -0
- package/src/components/catalog.ts +214 -0
- package/src/config/index.ts +237 -0
- package/src/context/builder.ts +233 -0
- package/src/context/filter.ts +164 -0
- package/src/context/grounding.ts +191 -0
- package/src/context/guards.ts +94 -0
- package/src/context/repo-hints.ts +43 -0
- package/src/generation/gemini-client.ts +94 -0
- package/src/generation/litellm-client.ts +121 -0
- package/src/generation/remote-client.ts +103 -0
- package/src/index.ts +36 -0
- package/src/output/file-writer.ts +181 -0
- package/src/output/formatter.ts +186 -0
- package/src/server.ts +28 -0
- package/src/stack/detect.ts +204 -0
- package/src/tokens/sync.ts +212 -0
- package/src/tools/analyze-screenshot-ui.ts +150 -0
- package/src/tools/analyze-tokens.ts +123 -0
- package/src/tools/catalog-components.ts +99 -0
- package/src/tools/create-ui.ts +194 -0
- package/src/tools/detect-ui-stack.ts +64 -0
- package/src/tools/generate-component-variants.ts +218 -0
- package/src/tools/generate-vibes.ts +177 -0
- package/src/tools/index.ts +42 -0
- package/src/tools/modify-ui.ts +230 -0
- package/src/tools/scaffold-project.ts +138 -0
- package/src/tools/snippet-ui.ts +222 -0
- package/src/tools/sync-design-tokens.ts +256 -0
- package/src/utils/walk.ts +75 -0
- package/tsconfig.json +34 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Sync Utilities
|
|
3
|
+
*
|
|
4
|
+
* Normalizes tokens into a small internal representation and can output:
|
|
5
|
+
* - CSS custom properties
|
|
6
|
+
* - Tailwind theme extension
|
|
7
|
+
* - Tokens Studio JSON
|
|
8
|
+
* - Style Dictionary JSON
|
|
9
|
+
*/
|
|
10
|
+
import * as path from 'node:path';
|
|
11
|
+
function isColorValue(v) {
|
|
12
|
+
const s = v.trim().toLowerCase();
|
|
13
|
+
return (/^#([0-9a-f]{3,8})$/.test(s) ||
|
|
14
|
+
/^rgb\(/.test(s) ||
|
|
15
|
+
/^rgba\(/.test(s) ||
|
|
16
|
+
/^hsl\(/.test(s) ||
|
|
17
|
+
/^hsla\(/.test(s) ||
|
|
18
|
+
/^oklch\(/.test(s) ||
|
|
19
|
+
/^oklab\(/.test(s));
|
|
20
|
+
}
|
|
21
|
+
function isDimensionValue(v) {
|
|
22
|
+
const s = v.trim().toLowerCase();
|
|
23
|
+
return /^-?\d+(\.\d+)?(px|rem|em|vh|vw|%|ch|ex)$/.test(s);
|
|
24
|
+
}
|
|
25
|
+
function isDurationValue(v) {
|
|
26
|
+
const s = v.trim().toLowerCase();
|
|
27
|
+
return /^\d+(\.\d+)?(ms|s)$/.test(s);
|
|
28
|
+
}
|
|
29
|
+
function inferTokenType(name, value) {
|
|
30
|
+
const n = name.toLowerCase();
|
|
31
|
+
const v = value.trim();
|
|
32
|
+
if (isColorValue(v) || n.includes('color') || n.includes('bg') || n.includes('foreground') || n.includes('surface'))
|
|
33
|
+
return 'color';
|
|
34
|
+
if (isDurationValue(v) || n.includes('duration') || n.includes('transition'))
|
|
35
|
+
return 'duration';
|
|
36
|
+
if (n.includes('easing') || n.includes('ease'))
|
|
37
|
+
return 'easing';
|
|
38
|
+
if (n.includes('shadow') || v.includes('rgba') && v.includes('px'))
|
|
39
|
+
return 'shadow';
|
|
40
|
+
if (n.includes('font') && n.includes('family'))
|
|
41
|
+
return 'fontFamily';
|
|
42
|
+
if (n.includes('weight'))
|
|
43
|
+
return 'fontWeight';
|
|
44
|
+
if (isDimensionValue(v) || n.includes('space') || n.includes('radius') || n.includes('size') || n.includes('gap'))
|
|
45
|
+
return 'dimension';
|
|
46
|
+
if (/^-?\d+(\.\d+)?$/.test(v))
|
|
47
|
+
return 'number';
|
|
48
|
+
return 'string';
|
|
49
|
+
}
|
|
50
|
+
function normalizeCssVarNameToTokenName(cssVar) {
|
|
51
|
+
// '--color-primary' -> 'color.primary'
|
|
52
|
+
// '--radius-md' -> 'radius.md'
|
|
53
|
+
let n = cssVar.trim();
|
|
54
|
+
if (n.startsWith('--'))
|
|
55
|
+
n = n.slice(2);
|
|
56
|
+
n = n.replace(/\s+/g, '-');
|
|
57
|
+
// Convert separators to dots for nesting
|
|
58
|
+
return n
|
|
59
|
+
.replace(/__/g, '.')
|
|
60
|
+
.replace(/--/g, '.')
|
|
61
|
+
.replace(/-/g, '.')
|
|
62
|
+
.replace(/\.+/g, '.')
|
|
63
|
+
.replace(/^\./, '')
|
|
64
|
+
.replace(/\.$/, '');
|
|
65
|
+
}
|
|
66
|
+
export function parseCssVars(content, sourceFile) {
|
|
67
|
+
const warnings = [];
|
|
68
|
+
const tokens = [];
|
|
69
|
+
// Very simple parse: extract any --var: value; pairs
|
|
70
|
+
const re = /(--[A-Za-z0-9_-]+)\s*:\s*([^;\n\r]+)\s*;/g;
|
|
71
|
+
let match;
|
|
72
|
+
const seen = new Set();
|
|
73
|
+
while ((match = re.exec(content))) {
|
|
74
|
+
const originalName = match[1];
|
|
75
|
+
const value = match[2].trim();
|
|
76
|
+
const name = normalizeCssVarNameToTokenName(originalName);
|
|
77
|
+
if (!name)
|
|
78
|
+
continue;
|
|
79
|
+
if (seen.has(name))
|
|
80
|
+
continue;
|
|
81
|
+
seen.add(name);
|
|
82
|
+
tokens.push({
|
|
83
|
+
name,
|
|
84
|
+
value,
|
|
85
|
+
type: inferTokenType(name, value),
|
|
86
|
+
source: {
|
|
87
|
+
file: sourceFile ? path.basename(sourceFile) : undefined,
|
|
88
|
+
originalName,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (tokens.length === 0) {
|
|
93
|
+
warnings.push('No CSS custom properties found (expected patterns like --token-name: value;)');
|
|
94
|
+
}
|
|
95
|
+
return { tokens, warnings };
|
|
96
|
+
}
|
|
97
|
+
function setNested(obj, pathParts, value) {
|
|
98
|
+
// Protect against prototype pollution
|
|
99
|
+
const dangerousKeys = new Set(['__proto__', 'constructor', 'prototype']);
|
|
100
|
+
let cur = obj;
|
|
101
|
+
for (let i = 0; i < pathParts.length; i++) {
|
|
102
|
+
const key = pathParts[i];
|
|
103
|
+
// Block dangerous keys
|
|
104
|
+
if (dangerousKeys.has(key)) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (i === pathParts.length - 1) {
|
|
108
|
+
cur[key] = value;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (!Object.hasOwn(cur, key) || typeof cur[key] !== 'object' || cur[key] === null) {
|
|
112
|
+
cur[key] = Object.create(null);
|
|
113
|
+
}
|
|
114
|
+
cur = cur[key];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export function tokensToCssVars(tokens, options) {
|
|
118
|
+
const selector = options?.selector || ':root';
|
|
119
|
+
const lines = [`${selector} {`];
|
|
120
|
+
for (const t of tokens) {
|
|
121
|
+
const cssName = `--${t.name.replace(/\./g, '-')}`;
|
|
122
|
+
lines.push(` ${cssName}: ${t.value};`);
|
|
123
|
+
}
|
|
124
|
+
lines.push('}');
|
|
125
|
+
return lines.join('\n');
|
|
126
|
+
}
|
|
127
|
+
export function tokensToTailwindTheme(tokens) {
|
|
128
|
+
const extend = { colors: {}, spacing: {}, borderRadius: {}, boxShadow: {}, fontFamily: {}, fontWeight: {}, transitionDuration: {} };
|
|
129
|
+
for (const t of tokens) {
|
|
130
|
+
const parts = t.name.split('.').filter(Boolean);
|
|
131
|
+
if (parts.length === 0)
|
|
132
|
+
continue;
|
|
133
|
+
const root = parts[0];
|
|
134
|
+
const rest = parts.slice(1);
|
|
135
|
+
if (t.type === 'color' && (root === 'color' || root === 'colors')) {
|
|
136
|
+
setNested(extend.colors, rest.length ? rest : ['DEFAULT'], t.value);
|
|
137
|
+
}
|
|
138
|
+
else if (t.type === 'dimension' && (root === 'space' || root === 'spacing')) {
|
|
139
|
+
setNested(extend.spacing, rest.length ? rest : ['DEFAULT'], t.value);
|
|
140
|
+
}
|
|
141
|
+
else if (t.type === 'dimension' && (root === 'radius' || root === 'radii' || root === 'borderRadius')) {
|
|
142
|
+
setNested(extend.borderRadius, rest.length ? rest : ['DEFAULT'], t.value);
|
|
143
|
+
}
|
|
144
|
+
else if (t.type === 'shadow' && (root === 'shadow' || root === 'shadows')) {
|
|
145
|
+
setNested(extend.boxShadow, rest.length ? rest : ['DEFAULT'], t.value);
|
|
146
|
+
}
|
|
147
|
+
else if (t.type === 'fontFamily') {
|
|
148
|
+
setNested(extend.fontFamily, rest.length ? rest : ['sans'], t.value);
|
|
149
|
+
}
|
|
150
|
+
else if (t.type === 'fontWeight') {
|
|
151
|
+
setNested(extend.fontWeight, rest.length ? rest : ['normal'], t.value);
|
|
152
|
+
}
|
|
153
|
+
else if (t.type === 'duration') {
|
|
154
|
+
setNested(extend.transitionDuration, rest.length ? rest : ['DEFAULT'], t.value);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Prune empty sections
|
|
158
|
+
for (const k of Object.keys(extend)) {
|
|
159
|
+
if (extend[k] && typeof extend[k] === 'object' && Object.keys(extend[k]).length === 0) {
|
|
160
|
+
delete extend[k];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return `/** Auto-generated by sync_design_tokens */\nexport default {\n theme: {\n extend: ${JSON.stringify(extend, null, 2)}\n }\n}`;
|
|
164
|
+
}
|
|
165
|
+
export function tokensToTokensStudio(tokens) {
|
|
166
|
+
// Tokens Studio expects {"token": {"value": ..., "type": ...}}
|
|
167
|
+
const out = {};
|
|
168
|
+
for (const t of tokens) {
|
|
169
|
+
const parts = t.name.split('.').filter(Boolean);
|
|
170
|
+
if (parts.length === 0)
|
|
171
|
+
continue;
|
|
172
|
+
setNested(out, parts, { value: t.value, type: t.type, description: t.description });
|
|
173
|
+
}
|
|
174
|
+
return JSON.stringify(out, null, 2);
|
|
175
|
+
}
|
|
176
|
+
export function tokensToStyleDictionary(tokens) {
|
|
177
|
+
// Style Dictionary commonly uses nested objects with { value, type }
|
|
178
|
+
// We'll output a format compatible with SD v3+ token JSON.
|
|
179
|
+
const out = {};
|
|
180
|
+
for (const t of tokens) {
|
|
181
|
+
const parts = t.name.split('.').filter(Boolean);
|
|
182
|
+
if (parts.length === 0)
|
|
183
|
+
continue;
|
|
184
|
+
setNested(out, parts, { value: t.value, type: t.type });
|
|
185
|
+
}
|
|
186
|
+
return JSON.stringify(out, null, 2);
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/tokens/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAoBlC,SAAS,YAAY,CAAC,CAAS;IAC3B,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACjC,OAAO,CACH,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5B,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAChB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAChB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QACjB,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QAClB,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CACrB,CAAC;AACN,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAS;IAC/B,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACjC,OAAO,0CAA0C,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,eAAe,CAAC,CAAS;IAC9B,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACjC,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,cAAc,CAAC,IAAY,EAAE,KAAa;IAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAC7B,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IACvB,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,OAAO,CAAC;IACpI,IAAI,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,UAAU,CAAC;IAChG,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,QAAQ,CAAC;IAChE,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IACpF,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,YAAY,CAAC;IACpE,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,YAAY,CAAC;IAC9C,IAAI,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IACtI,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC/C,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED,SAAS,8BAA8B,CAAC,MAAc;IAClD,uCAAuC;IACvC,+BAA+B;IAC/B,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,yCAAyC;IACzC,OAAO,CAAC;SACH,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;SAClB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;SAClB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,UAAmB;IAC7D,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAY,EAAE,CAAC;IAE3B,qDAAqD;IACrD,MAAM,EAAE,GAAG,2CAA2C,CAAC;IACvD,IAAI,KAA6B,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAChC,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,8BAA8B,CAAC,YAAY,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAC7B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEf,MAAM,CAAC,IAAI,CAAC;YACR,IAAI;YACJ,KAAK;YACL,IAAI,EAAE,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC;YACjC,MAAM,EAAE;gBACJ,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS;gBACxD,YAAY;aACf;SACJ,CAAC,CAAC;IACP,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,QAAQ,CAAC,IAAI,CAAC,8EAA8E,CAAC,CAAC;IAClG,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,SAAS,CAAC,GAA4B,EAAE,SAAmB,EAAE,KAAc;IAChF,sCAAsC;IACtC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC;IAEzE,IAAI,GAAG,GAA4B,GAAG,CAAC;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAEzB,uBAAuB;QACvB,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO;QACX,CAAC;QAED,IAAI,CAAC,KAAK,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACjB,OAAO;QACX,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;YAChF,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAA4B,CAAC;QAC9D,CAAC;QACD,GAAG,GAAG,GAAG,CAAC,GAAG,CAA4B,CAAC;IAC9C,CAAC;AACL,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAe,EAAE,OAA+B;IAC5E,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,OAAO,CAAC;IAC9C,MAAM,KAAK,GAAG,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACrB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAAe;IACjD,MAAM,MAAM,GAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,kBAAkB,EAAE,EAAE,EAAE,CAAC;IAEzI,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACjC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAE5B,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,QAAQ,CAAC,EAAE,CAAC;YAChE,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QACxE,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;YAC5E,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QACzE,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,cAAc,CAAC,EAAE,CAAC;YACtG,SAAS,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QAC9E,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;YAC1E,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3E,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACjC,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QACzE,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACjC,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3E,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC/B,SAAS,CAAC,MAAM,CAAC,kBAAkB,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QACpF,CAAC;IACL,CAAC;IAED,uBAAuB;IACvB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpF,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;IACL,CAAC;IAED,OAAO,0FAA0F,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC;AAC/I,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAe;IAChD,+DAA+D;IAC/D,MAAM,GAAG,GAAQ,EAAE,CAAC;IACpB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACjC,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,MAAe;IACnD,qEAAqE;IACrE,2DAA2D;IAC3D,MAAM,GAAG,GAAQ,EAAE,CAAC;IACpB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACjC,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* analyze_screenshot_ui Tool
|
|
3
|
+
*
|
|
4
|
+
* Multimodal screenshot analysis:
|
|
5
|
+
* - layout breakdown
|
|
6
|
+
* - component suggestions
|
|
7
|
+
* - token guesses
|
|
8
|
+
* - accessibility notes
|
|
9
|
+
*
|
|
10
|
+
* This tool can run in:
|
|
11
|
+
* - local gemini mode (Gemini SDK multimodal)
|
|
12
|
+
* - remote mode (gateway supports userParts)
|
|
13
|
+
* - local litellm mode (OpenAI-compatible image_url content)
|
|
14
|
+
*/
|
|
15
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
16
|
+
import { Config } from '../config/index.js';
|
|
17
|
+
export declare function registerAnalyzeScreenshotUI(server: McpServer, config: Config): void;
|
|
18
|
+
//# sourceMappingURL=analyze-screenshot-ui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-screenshot-ui.d.ts","sourceRoot":"","sources":["../../src/tools/analyze-screenshot-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAkD5C,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAgFnF"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* analyze_screenshot_ui Tool
|
|
3
|
+
*
|
|
4
|
+
* Multimodal screenshot analysis:
|
|
5
|
+
* - layout breakdown
|
|
6
|
+
* - component suggestions
|
|
7
|
+
* - token guesses
|
|
8
|
+
* - accessibility notes
|
|
9
|
+
*
|
|
10
|
+
* This tool can run in:
|
|
11
|
+
* - local gemini mode (Gemini SDK multimodal)
|
|
12
|
+
* - remote mode (gateway supports userParts)
|
|
13
|
+
* - local litellm mode (OpenAI-compatible image_url content)
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import * as fs from 'node:fs';
|
|
17
|
+
import * as path from 'node:path';
|
|
18
|
+
import { assertReadablePath } from '../context/guards.js';
|
|
19
|
+
import { sanitizeContent } from '../context/filter.js';
|
|
20
|
+
import { buildContext } from '../context/builder.js';
|
|
21
|
+
import { generateWithGemini } from '../generation/gemini-client.js';
|
|
22
|
+
const inputSchema = {
|
|
23
|
+
imagePath: z.string().optional().describe('Path to an image file (png/jpg/webp).'),
|
|
24
|
+
imageBase64: z.string().optional().describe('Base64 image data (if not using imagePath).'),
|
|
25
|
+
mimeType: z.string().optional().describe('Image mime type, e.g. image/png. Required when using imageBase64.'),
|
|
26
|
+
instruction: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('What to extract from the screenshot. Defaults to a full UI breakdown.'),
|
|
30
|
+
outputFormat: z.enum(['json', 'markdown']).default('json').describe('Response format.'),
|
|
31
|
+
framework: z
|
|
32
|
+
.enum(['react', 'nextjs', 'vue', 'svelte', 'vanilla'])
|
|
33
|
+
.optional()
|
|
34
|
+
.describe('Target framework hint.'),
|
|
35
|
+
context: z.array(z.string()).optional().describe('Related design/token files for grounding.'),
|
|
36
|
+
};
|
|
37
|
+
const SYSTEM_PROMPT = `You are a senior UI engineer and design system expert.
|
|
38
|
+
|
|
39
|
+
You will analyze a UI screenshot and return a structured breakdown suitable for code generation.
|
|
40
|
+
|
|
41
|
+
Output requirements:
|
|
42
|
+
- If outputFormat=json: output ONE valid JSON object only. No prose. No markdown. No code fences.
|
|
43
|
+
- If outputFormat=markdown: output concise markdown with headings and bullet points.
|
|
44
|
+
|
|
45
|
+
When outputFormat=json, include:
|
|
46
|
+
{
|
|
47
|
+
"layout": {"type": "page|modal|panel|component", "grid": "...", "sections": [...]},
|
|
48
|
+
"components": [{"name": "...", "role": "...", "suggestedImplementation": "..."}],
|
|
49
|
+
"tokensGuess": {"colors": [...], "typography": [...], "spacing": [...], "radii": [...], "shadows": [...]},
|
|
50
|
+
"a11y": {"landmarks": [...], "labels": [...], "keyboard": [...], "contrastRisks": [...]},
|
|
51
|
+
"notes": [...]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
Be practical: prefer reusable primitives (Button, Input, Card, Table) and suggest variants/states.
|
|
55
|
+
Do not invent backend logic.`;
|
|
56
|
+
function mimeFromPath(p) {
|
|
57
|
+
const ext = path.extname(p).toLowerCase();
|
|
58
|
+
if (ext === '.png')
|
|
59
|
+
return 'image/png';
|
|
60
|
+
if (ext === '.jpg' || ext === '.jpeg')
|
|
61
|
+
return 'image/jpeg';
|
|
62
|
+
if (ext === '.webp')
|
|
63
|
+
return 'image/webp';
|
|
64
|
+
return 'application/octet-stream';
|
|
65
|
+
}
|
|
66
|
+
export function registerAnalyzeScreenshotUI(server, config) {
|
|
67
|
+
server.registerTool('analyze_screenshot_ui', {
|
|
68
|
+
title: 'Analyze UI Screenshot',
|
|
69
|
+
description: 'Analyze a UI screenshot (layout/components/tokens/a11y). Supports multimodal prompts in local or remote mode.',
|
|
70
|
+
inputSchema,
|
|
71
|
+
}, async (args) => {
|
|
72
|
+
const imagePath = args.imagePath;
|
|
73
|
+
const imageBase64 = args.imageBase64;
|
|
74
|
+
const mimeType = args.mimeType;
|
|
75
|
+
const instruction = args.instruction || '';
|
|
76
|
+
const outputFormat = args.outputFormat || 'json';
|
|
77
|
+
const framework = args.framework || config.defaultFramework;
|
|
78
|
+
const contextPaths = args.context;
|
|
79
|
+
if (!imagePath && !imageBase64) {
|
|
80
|
+
return {
|
|
81
|
+
content: [{ type: 'text', text: 'Error: Provide imagePath or imageBase64.' }],
|
|
82
|
+
isError: true,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
let data;
|
|
86
|
+
let mime;
|
|
87
|
+
try {
|
|
88
|
+
if (imagePath) {
|
|
89
|
+
const safe = assertReadablePath(imagePath, config);
|
|
90
|
+
const buf = fs.readFileSync(safe);
|
|
91
|
+
data = buf.toString('base64');
|
|
92
|
+
mime = mimeFromPath(safe);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
data = imageBase64;
|
|
96
|
+
mime = mimeType || 'application/octet-stream';
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
const message = error instanceof Error ? error.message : 'Could not read image';
|
|
101
|
+
return { content: [{ type: 'text', text: `Error: ${message}` }], isError: true };
|
|
102
|
+
}
|
|
103
|
+
let contextContent = '';
|
|
104
|
+
if (contextPaths && contextPaths.length > 0) {
|
|
105
|
+
contextContent = await buildContext(contextPaths, config);
|
|
106
|
+
contextContent = sanitizeContent(contextContent);
|
|
107
|
+
}
|
|
108
|
+
const userText = `Analyze this screenshot.
|
|
109
|
+
|
|
110
|
+
outputFormat: ${outputFormat}
|
|
111
|
+
frameworkHint: ${framework}
|
|
112
|
+
instruction: ${instruction || '(full breakdown)'}
|
|
113
|
+
|
|
114
|
+
${contextContent ? `RELATED FILES (sanitized):\n${contextContent}` : ''}
|
|
115
|
+
|
|
116
|
+
Return in the requested format.`;
|
|
117
|
+
try {
|
|
118
|
+
const resp = await generateWithGemini(config, SYSTEM_PROMPT, [
|
|
119
|
+
{ text: userText },
|
|
120
|
+
{ inlineData: { mimeType: mime, data } },
|
|
121
|
+
], { toolName: 'analyze_screenshot_ui' });
|
|
122
|
+
return { content: [{ type: 'text', text: resp.trim() }] };
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
126
|
+
return {
|
|
127
|
+
content: [{ type: 'text', text: `Error analyzing screenshot: ${message}` }],
|
|
128
|
+
isError: true,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=analyze-screenshot-ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-screenshot-ui.js","sourceRoot":"","sources":["../../src/tools/analyze-screenshot-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEpE,MAAM,WAAW,GAAG;IAChB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;IAClF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;IAC1F,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;IAC7G,WAAW,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,uEAAuE,CAAC;IACtF,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IACvF,SAAS,EAAE,CAAC;SACP,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;SACrD,QAAQ,EAAE;SACV,QAAQ,CAAC,wBAAwB,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;CAChG,CAAC;AAEF,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;6BAkBO,CAAC;AAE9B,SAAS,YAAY,CAAC,CAAS;IAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1C,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,WAAW,CAAC;IACvC,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,OAAO;QAAE,OAAO,YAAY,CAAC;IAC3D,IAAI,GAAG,KAAK,OAAO;QAAE,OAAO,YAAY,CAAC;IACzC,OAAO,0BAA0B,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,MAAiB,EAAE,MAAc;IACzE,MAAM,CAAC,YAAY,CACf,uBAAuB,EACvB;QACI,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EACP,+GAA+G;QACnH,WAAW;KACd,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACX,MAAM,SAAS,GAAG,IAAI,CAAC,SAA+B,CAAC;QACvD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAiC,CAAC;QAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAA8B,CAAC;QACrD,MAAM,WAAW,GAAI,IAAI,CAAC,WAAkC,IAAI,EAAE,CAAC;QACnE,MAAM,YAAY,GAAI,IAAI,CAAC,YAAoC,IAAI,MAAM,CAAC;QAC1E,MAAM,SAAS,GAAI,IAAI,CAAC,SAAoD,IAAI,MAAM,CAAC,gBAAgB,CAAC;QACxG,MAAM,YAAY,GAAG,IAAI,CAAC,OAA+B,CAAC;QAE1D,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,CAAC;YAC7B,OAAO;gBACH,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,0CAA0C,EAAE,CAAC;gBACtF,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;QAED,IAAI,IAAY,CAAC;QACjB,IAAI,IAAY,CAAC;QAEjB,IAAI,CAAC;YACD,IAAI,SAAS,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,kBAAkB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;gBACnD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;gBAClC,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBAC9B,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YAC9B,CAAC;iBAAM,CAAC;gBACJ,IAAI,GAAG,WAAqB,CAAC;gBAC7B,IAAI,GAAG,QAAQ,IAAI,0BAA0B,CAAC;YAClD,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC;YAChF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC9F,CAAC;QAED,IAAI,cAAc,GAAG,EAAE,CAAC;QACxB,IAAI,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1C,cAAc,GAAG,MAAM,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;YAC1D,cAAc,GAAG,eAAe,CAAC,cAAc,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,QAAQ,GAAG;;gBAEb,YAAY;iBACX,SAAS;eACX,WAAW,IAAI,kBAAkB;;EAE9C,cAAc,CAAC,CAAC,CAAC,+BAA+B,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE;;gCAEvC,CAAC;QAErB,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,kBAAkB,CACjC,MAAM,EACN,aAAa,EACb;gBACI,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAClB,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;aAC3C,EACD,EAAE,QAAQ,EAAE,uBAAuB,EAAE,CACxC,CAAC;YAEF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QACvE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,OAAO;gBACH,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,+BAA+B,OAAO,EAAE,EAAE,CAAC;gBACpF,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;IACL,CAAC,CACJ,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* analyze_tokens Tool
|
|
3
|
+
*
|
|
4
|
+
* Extracts and understands existing design systems.
|
|
5
|
+
* Returns structured design tokens from CSS/SCSS files.
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
import { Config } from '../config/index.js';
|
|
9
|
+
export declare function registerAnalyzeTokens(server: McpServer, config: Config): void;
|
|
10
|
+
//# sourceMappingURL=analyze-tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-tokens.d.ts","sourceRoot":"","sources":["../../src/tools/analyze-tokens.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAiC5C,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA+E7E"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* analyze_tokens Tool
|
|
3
|
+
*
|
|
4
|
+
* Extracts and understands existing design systems.
|
|
5
|
+
* Returns structured design tokens from CSS/SCSS files.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import * as fs from 'node:fs';
|
|
9
|
+
import { assertReadablePath } from '../context/guards.js';
|
|
10
|
+
import { sanitizeContent } from '../context/filter.js';
|
|
11
|
+
import { generateWithGemini } from '../generation/gemini-client.js';
|
|
12
|
+
const inputSchema = {
|
|
13
|
+
paths: z.array(z.string()).describe('Paths to CSS, SCSS, or design token files to analyze'),
|
|
14
|
+
format: z
|
|
15
|
+
.enum(['json', 'css-vars', 'tailwind', 'summary'])
|
|
16
|
+
.default('json')
|
|
17
|
+
.describe('Output format for the extracted tokens'),
|
|
18
|
+
};
|
|
19
|
+
const SYSTEM_PROMPT = `You are a design system analyst. Your task is to extract and structure design tokens from CSS/SCSS files.
|
|
20
|
+
|
|
21
|
+
Analyze the provided files and extract:
|
|
22
|
+
1. Colors - with semantic names and usage hints
|
|
23
|
+
2. Typography - font families, sizes, weights, line heights
|
|
24
|
+
3. Spacing - margin/padding values, identify a scale (e.g. 4px base)
|
|
25
|
+
4. Breakpoints - media query values
|
|
26
|
+
5. Shadows - box-shadow values
|
|
27
|
+
6. Border radii - radius values
|
|
28
|
+
7. Transitions - duration and easing values
|
|
29
|
+
8. Z-index - layering values
|
|
30
|
+
|
|
31
|
+
Output rules:
|
|
32
|
+
- If format=json: output ONE valid JSON object only. No prose. No markdown. No code fences.
|
|
33
|
+
- If format=css-vars: output ONLY CSS custom properties (no markdown).
|
|
34
|
+
- If format=tailwind: output ONLY a tailwind theme extension (JS object or full tailwind.config.js), no markdown.
|
|
35
|
+
- If format=summary: output concise bullet points.
|
|
36
|
+
|
|
37
|
+
When naming tokens, prefer semantic names (primary, surface, text, border) rather than raw hex values.`;
|
|
38
|
+
export function registerAnalyzeTokens(server, config) {
|
|
39
|
+
server.registerTool('analyze_tokens', {
|
|
40
|
+
title: 'Analyze Design Tokens',
|
|
41
|
+
description: 'Extract and structure design tokens from existing CSS/SCSS files. Use before create_ui to understand existing design systems.',
|
|
42
|
+
inputSchema,
|
|
43
|
+
}, async (args) => {
|
|
44
|
+
const paths = args.paths;
|
|
45
|
+
const format = args.format || 'json';
|
|
46
|
+
// Read all specified files (with safety checks)
|
|
47
|
+
const fileContents = [];
|
|
48
|
+
const errors = [];
|
|
49
|
+
for (const filePath of paths) {
|
|
50
|
+
try {
|
|
51
|
+
const safePath = assertReadablePath(filePath, config);
|
|
52
|
+
const raw = fs.readFileSync(safePath, 'utf-8');
|
|
53
|
+
const content = sanitizeContent(raw);
|
|
54
|
+
fileContents.push(`/* File: ${filePath} */\n${content}`);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
const message = error instanceof Error ? error.message : 'Could not read';
|
|
58
|
+
errors.push(`${filePath}: ${message}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (fileContents.length === 0) {
|
|
62
|
+
return {
|
|
63
|
+
content: [
|
|
64
|
+
{
|
|
65
|
+
type: 'text',
|
|
66
|
+
text: `Error: Could not read any files.\n${errors.join('\n')}`,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
isError: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (errors.length > 0 && config.debug) {
|
|
73
|
+
console.error('[analyze_tokens] Warnings:\n' + errors.join('\n'));
|
|
74
|
+
}
|
|
75
|
+
const combinedContent = fileContents.join('\n\n');
|
|
76
|
+
const userPrompt = `Analyze these CSS/SCSS files and extract design tokens.
|
|
77
|
+
Format: ${format}
|
|
78
|
+
|
|
79
|
+
FILES:
|
|
80
|
+
${combinedContent}`;
|
|
81
|
+
try {
|
|
82
|
+
const response = await generateWithGemini(config, SYSTEM_PROMPT, userPrompt, { toolName: 'analyze_tokens' });
|
|
83
|
+
// IMPORTANT: Return raw model output ONLY (no wrappers) so JSON / CSS output stays valid.
|
|
84
|
+
return {
|
|
85
|
+
content: [
|
|
86
|
+
{
|
|
87
|
+
type: 'text',
|
|
88
|
+
text: response.trim(),
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
95
|
+
return {
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: 'text',
|
|
99
|
+
text: `Error analyzing tokens: ${message}`,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
isError: true,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=analyze-tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-tokens.js","sourceRoot":"","sources":["../../src/tools/analyze-tokens.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* catalog_components Tool
|
|
3
|
+
*
|
|
4
|
+
* Builds a machine-readable catalog of exported components in the codebase.
|
|
5
|
+
*
|
|
6
|
+
* Why this matters:
|
|
7
|
+
* - Lets create_ui/snippet_ui/modify_ui match existing patterns
|
|
8
|
+
* - Enables component-library detection & reuse instead of regenerating duplicates
|
|
9
|
+
* - Grounding data for agents (props, file paths, exports)
|
|
10
|
+
*/
|
|
11
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
12
|
+
import { Config } from '../config/index.js';
|
|
13
|
+
export declare function registerCatalogComponents(server: McpServer, config: Config): void;
|
|
14
|
+
//# sourceMappingURL=catalog-components.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-components.d.ts","sourceRoot":"","sources":["../../src/tools/catalog-components.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAuB5C,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA6DjF"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* catalog_components Tool
|
|
3
|
+
*
|
|
4
|
+
* Builds a machine-readable catalog of exported components in the codebase.
|
|
5
|
+
*
|
|
6
|
+
* Why this matters:
|
|
7
|
+
* - Lets create_ui/snippet_ui/modify_ui match existing patterns
|
|
8
|
+
* - Enables component-library detection & reuse instead of regenerating duplicates
|
|
9
|
+
* - Grounding data for agents (props, file paths, exports)
|
|
10
|
+
*/
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import { assertReadableDir } from '../context/guards.js';
|
|
14
|
+
import { walkFiles, toPosixPath } from '../utils/walk.js';
|
|
15
|
+
import { buildComponentCatalog } from '../components/catalog.js';
|
|
16
|
+
const inputSchema = {
|
|
17
|
+
roots: z
|
|
18
|
+
.array(z.string())
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('Directories to scan (defaults to ["src"]).'),
|
|
21
|
+
extensions: z
|
|
22
|
+
.array(z.string())
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('File extensions to include (defaults to [".tsx", ".jsx"]).'),
|
|
25
|
+
maxFiles: z
|
|
26
|
+
.number()
|
|
27
|
+
.int()
|
|
28
|
+
.min(1)
|
|
29
|
+
.max(50_000)
|
|
30
|
+
.default(2000)
|
|
31
|
+
.describe('Safety limit to avoid scanning huge repos.'),
|
|
32
|
+
};
|
|
33
|
+
export function registerCatalogComponents(server, config) {
|
|
34
|
+
server.registerTool('catalog_components', {
|
|
35
|
+
title: 'Catalog Components',
|
|
36
|
+
description: 'Scan the repo and return a JSON catalog of exported components (no LLM).',
|
|
37
|
+
inputSchema,
|
|
38
|
+
}, async (args) => {
|
|
39
|
+
const roots = args.roots || ['src'];
|
|
40
|
+
const extensions = args.extensions || ['.tsx', '.jsx'];
|
|
41
|
+
const maxFiles = args.maxFiles || 2000;
|
|
42
|
+
const safeRoots = [];
|
|
43
|
+
for (const r of roots) {
|
|
44
|
+
try {
|
|
45
|
+
safeRoots.push(assertReadableDir(r, config));
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
const message = error instanceof Error ? error.message : 'Invalid root';
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: 'text', text: `Error: ${message}` }],
|
|
51
|
+
isError: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const allFiles = [];
|
|
56
|
+
for (const r of safeRoots) {
|
|
57
|
+
const found = walkFiles(r, { includeExtensions: extensions, maxFiles });
|
|
58
|
+
allFiles.push(...found);
|
|
59
|
+
}
|
|
60
|
+
// Use cwd as catalog root so paths are stable for agents
|
|
61
|
+
const root = path.resolve(process.cwd());
|
|
62
|
+
const catalog = await buildComponentCatalog(root, allFiles.map((f) => path.resolve(f)));
|
|
63
|
+
// Ensure POSIX paths
|
|
64
|
+
catalog.components = catalog.components.map((c) => ({ ...c, file: toPosixPath(c.file) }));
|
|
65
|
+
catalog.root = toPosixPath(catalog.root);
|
|
66
|
+
// Small summary
|
|
67
|
+
const summary = {
|
|
68
|
+
totalFiles: catalog.filesScanned,
|
|
69
|
+
totalComponents: catalog.components.length,
|
|
70
|
+
byExportType: {
|
|
71
|
+
named: catalog.components.filter((c) => c.exportType === 'named').length,
|
|
72
|
+
default: catalog.components.filter((c) => c.exportType === 'default').length,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: 'text',
|
|
79
|
+
text: JSON.stringify({ ...catalog, summary }, null, 2),
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=catalog-components.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-components.js","sourceRoot":"","sources":["../../src/tools/catalog-components.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* create_ui Tool
|
|
3
|
+
*
|
|
4
|
+
* Scaffolds new UI components or views.
|
|
5
|
+
* Generates complete, responsive, accessible frontend code.
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
import { Config } from '../config/index.js';
|
|
9
|
+
export declare function registerCreateUI(server: McpServer, config: Config): void;
|
|
10
|
+
//# sourceMappingURL=create-ui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-ui.d.ts","sourceRoot":"","sources":["../../src/tools/create-ui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAsF5C,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,QAkGjE"}
|