@gemini-designer/mcp-server 0.1.2 → 0.1.29
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/components/catalog.d.ts.map +1 -1
- package/dist/components/catalog.js +10 -4
- package/dist/components/catalog.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +11 -6
- package/dist/config/index.js.map +1 -1
- package/dist/context/builder.d.ts.map +1 -1
- package/dist/context/builder.js.map +1 -1
- package/dist/context/filter.d.ts.map +1 -1
- package/dist/context/filter.js +5 -1
- package/dist/context/filter.js.map +1 -1
- package/dist/context/grounding.d.ts.map +1 -1
- package/dist/context/grounding.js +7 -3
- package/dist/context/grounding.js.map +1 -1
- package/dist/context/guards.d.ts.map +1 -1
- package/dist/context/guards.js +53 -0
- package/dist/context/guards.js.map +1 -1
- package/dist/context/repo-hints.js.map +1 -1
- package/dist/context/styling-detector.d.ts +24 -0
- package/dist/context/styling-detector.d.ts.map +1 -0
- package/dist/context/styling-detector.js +337 -0
- package/dist/context/styling-detector.js.map +1 -0
- package/dist/design/principles.js.map +1 -1
- package/dist/generation/gemini-client.d.ts.map +1 -1
- package/dist/generation/gemini-client.js.map +1 -1
- package/dist/generation/litellm-client.d.ts.map +1 -1
- package/dist/generation/litellm-client.js +14 -7
- package/dist/generation/litellm-client.js.map +1 -1
- package/dist/generation/remote-client.d.ts +10 -5
- package/dist/generation/remote-client.d.ts.map +1 -1
- package/dist/generation/remote-client.js +13 -2
- package/dist/generation/remote-client.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/output/file-writer.d.ts.map +1 -1
- package/dist/output/file-writer.js +4 -4
- package/dist/output/file-writer.js.map +1 -1
- package/dist/output/formatter.d.ts.map +1 -1
- package/dist/output/formatter.js +5 -2
- package/dist/output/formatter.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -1
- package/dist/server.js.map +1 -1
- package/dist/stack/detect.d.ts.map +1 -1
- package/dist/stack/detect.js +42 -9
- package/dist/stack/detect.js.map +1 -1
- package/dist/tokens/sync.d.ts.map +1 -1
- package/dist/tokens/sync.js +22 -5
- package/dist/tokens/sync.js.map +1 -1
- package/dist/tools/analyze-screenshot-ui.d.ts.map +1 -1
- package/dist/tools/analyze-screenshot-ui.js +5 -5
- package/dist/tools/analyze-screenshot-ui.js.map +1 -1
- package/dist/tools/analyze-tokens.d.ts.map +1 -1
- package/dist/tools/analyze-tokens.js +3 -1
- package/dist/tools/analyze-tokens.js.map +1 -1
- package/dist/tools/catalog-components.d.ts.map +1 -1
- package/dist/tools/catalog-components.js +1 -4
- package/dist/tools/catalog-components.js.map +1 -1
- package/dist/tools/create-ui.d.ts +3 -0
- package/dist/tools/create-ui.d.ts.map +1 -1
- package/dist/tools/create-ui.js +203 -75
- package/dist/tools/create-ui.js.map +1 -1
- package/dist/tools/detect-ui-stack.js.map +1 -1
- package/dist/tools/generate-component-variants.d.ts.map +1 -1
- package/dist/tools/generate-component-variants.js +15 -4
- package/dist/tools/generate-component-variants.js.map +1 -1
- package/dist/tools/generate-vibes.d.ts.map +1 -1
- package/dist/tools/generate-vibes.js +7 -3
- package/dist/tools/generate-vibes.js.map +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/modify-ui.d.ts.map +1 -1
- package/dist/tools/modify-ui.js +7 -2
- package/dist/tools/modify-ui.js.map +1 -1
- package/dist/tools/scaffold-project.d.ts.map +1 -1
- package/dist/tools/scaffold-project.js +3 -1
- package/dist/tools/scaffold-project.js.map +1 -1
- package/dist/tools/snippet-ui.d.ts +3 -1
- package/dist/tools/snippet-ui.d.ts.map +1 -1
- package/dist/tools/snippet-ui.js +219 -88
- package/dist/tools/snippet-ui.js.map +1 -1
- package/dist/tools/sync-design-tokens.d.ts.map +1 -1
- package/dist/tools/sync-design-tokens.js +26 -11
- package/dist/tools/sync-design-tokens.js.map +1 -1
- package/dist/utils/walk.d.ts.map +1 -1
- package/dist/utils/walk.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/package.json +55 -55
- package/src/__tests__/builder.test.ts +19 -19
- package/src/__tests__/config.test.ts +63 -31
- package/src/__tests__/filter.test.ts +98 -92
- package/src/__tests__/remote-client.test.ts +179 -0
- package/src/components/catalog.ts +170 -166
- package/src/config/index.ts +185 -177
- package/src/context/builder.ts +157 -157
- package/src/context/filter.ts +110 -104
- package/src/context/grounding.ts +143 -129
- package/src/context/guards.ts +97 -38
- package/src/context/repo-hints.ts +24 -24
- package/src/context/styling-detector.ts +460 -0
- package/src/design/principles.ts +14 -14
- package/src/generation/gemini-client.ts +53 -56
- package/src/generation/litellm-client.ts +102 -86
- package/src/generation/remote-client.ts +100 -77
- package/src/index.ts +16 -16
- package/src/output/file-writer.ts +123 -123
- package/src/output/formatter.ts +139 -132
- package/src/server.ts +12 -11
- package/src/stack/detect.ts +226 -175
- package/src/tokens/sync.ts +189 -155
- package/src/tools/analyze-screenshot-ui.ts +89 -88
- package/src/tools/analyze-tokens.ts +80 -78
- package/src/tools/catalog-components.ts +68 -68
- package/src/tools/create-ui.ts +295 -142
- package/src/tools/detect-ui-stack.ts +36 -36
- package/src/tools/generate-component-variants.ts +155 -135
- package/src/tools/generate-vibes.ts +121 -117
- package/src/tools/index.ts +14 -14
- package/src/tools/modify-ui.ts +170 -165
- package/src/tools/scaffold-project.ts +68 -66
- package/src/tools/snippet-ui.ts +323 -172
- package/src/tools/sync-design-tokens.ts +217 -195
- package/src/utils/walk.ts +47 -45
- package/src/version.ts +6 -0
- package/tsconfig.json +23 -33
- package/vitest.config.ts +10 -10
- package/.prettierrc +0 -9
- package/eslint.config.js +0 -37
|
@@ -14,11 +14,11 @@ import { sanitizeContent } from '../context/filter.js';
|
|
|
14
14
|
import { generateWithGemini } from '../generation/gemini-client.js';
|
|
15
15
|
|
|
16
16
|
const inputSchema = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
paths: z.array(z.string()).describe('Paths to CSS, SCSS, or design token files to analyze'),
|
|
18
|
+
format: z
|
|
19
|
+
.enum(['json', 'css-vars', 'tailwind', 'summary'])
|
|
20
|
+
.default('json')
|
|
21
|
+
.describe('Output format for the extracted tokens'),
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
const SYSTEM_PROMPT = `You are a design system analyst. Your task is to extract and structure design tokens from CSS/SCSS files.
|
|
@@ -42,82 +42,84 @@ Output rules:
|
|
|
42
42
|
When naming tokens, prefer semantic names (primary, surface, text, border) rather than raw hex values.`;
|
|
43
43
|
|
|
44
44
|
export function registerAnalyzeTokens(server: McpServer, config: Config): void {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
45
|
+
server.registerTool(
|
|
46
|
+
'analyze_tokens',
|
|
47
|
+
{
|
|
48
|
+
title: 'Analyze Design Tokens',
|
|
49
|
+
description:
|
|
50
|
+
'Extract and structure design tokens from existing CSS/SCSS files. Use before create_ui to understand existing design systems.',
|
|
51
|
+
inputSchema,
|
|
52
|
+
},
|
|
53
|
+
async (args) => {
|
|
54
|
+
const paths = args.paths as string[];
|
|
55
|
+
const format = (args.format as 'json' | 'css-vars' | 'tailwind' | 'summary') || 'json';
|
|
56
|
+
|
|
57
|
+
// Read all specified files (with safety checks)
|
|
58
|
+
const fileContents: string[] = [];
|
|
59
|
+
const errors: string[] = [];
|
|
60
|
+
|
|
61
|
+
for (const filePath of paths) {
|
|
62
|
+
try {
|
|
63
|
+
const safePath = assertReadablePath(filePath, config);
|
|
64
|
+
const raw = fs.readFileSync(safePath, 'utf-8');
|
|
65
|
+
const content = sanitizeContent(raw);
|
|
66
|
+
fileContents.push(`/* File: ${filePath} */\n${content}`);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
const message = error instanceof Error ? error.message : 'Could not read';
|
|
69
|
+
errors.push(`${filePath}: ${message}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (fileContents.length === 0) {
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: 'text' as const,
|
|
78
|
+
text: `Error: Could not read any files.\n${errors.join('\n')}`,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
isError: true,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (errors.length > 0 && config.debug) {
|
|
86
|
+
console.error('[analyze_tokens] Warnings:\n' + errors.join('\n'));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const combinedContent = fileContents.join('\n\n');
|
|
90
|
+
|
|
91
|
+
const userPrompt = `Analyze these CSS/SCSS files and extract design tokens.
|
|
92
92
|
Format: ${format}
|
|
93
93
|
|
|
94
94
|
FILES:
|
|
95
95
|
${combinedContent}`;
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
97
|
+
try {
|
|
98
|
+
const response = await generateWithGemini(config, SYSTEM_PROMPT, userPrompt, {
|
|
99
|
+
toolName: 'analyze_tokens',
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// IMPORTANT: Return raw model output ONLY (no wrappers) so JSON / CSS output stays valid.
|
|
103
|
+
return {
|
|
104
|
+
content: [
|
|
105
|
+
{
|
|
106
|
+
type: 'text' as const,
|
|
107
|
+
text: response.trim(),
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
} catch (error) {
|
|
112
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
113
|
+
return {
|
|
114
|
+
content: [
|
|
115
|
+
{
|
|
116
|
+
type: 'text' as const,
|
|
117
|
+
text: `Error analyzing tokens: ${message}`,
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
isError: true,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
);
|
|
123
125
|
}
|
|
@@ -18,82 +18,82 @@ import { walkFiles, toPosixPath } from '../utils/walk.js';
|
|
|
18
18
|
import { buildComponentCatalog } from '../components/catalog.js';
|
|
19
19
|
|
|
20
20
|
const inputSchema = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
extensions
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
.max(50_000)
|
|
34
|
-
.default(2000)
|
|
35
|
-
.describe('Safety limit to avoid scanning huge repos.'),
|
|
21
|
+
roots: z.array(z.string()).optional().describe('Directories to scan (defaults to ["src"]).'),
|
|
22
|
+
extensions: z
|
|
23
|
+
.array(z.string())
|
|
24
|
+
.optional()
|
|
25
|
+
.describe('File extensions to include (defaults to [".tsx", ".jsx"]).'),
|
|
26
|
+
maxFiles: z
|
|
27
|
+
.number()
|
|
28
|
+
.int()
|
|
29
|
+
.min(1)
|
|
30
|
+
.max(50_000)
|
|
31
|
+
.default(2000)
|
|
32
|
+
.describe('Safety limit to avoid scanning huge repos.'),
|
|
36
33
|
};
|
|
37
34
|
|
|
38
35
|
export function registerCatalogComponents(server: McpServer, config: Config): void {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
36
|
+
server.registerTool(
|
|
37
|
+
'catalog_components',
|
|
38
|
+
{
|
|
39
|
+
title: 'Catalog Components',
|
|
40
|
+
description: 'Scan the repo and return a JSON catalog of exported components (no LLM).',
|
|
41
|
+
inputSchema,
|
|
42
|
+
},
|
|
43
|
+
async (args) => {
|
|
44
|
+
const roots = (args.roots as string[] | undefined) || ['src'];
|
|
45
|
+
const extensions = (args.extensions as string[] | undefined) || ['.tsx', '.jsx'];
|
|
46
|
+
const maxFiles = (args.maxFiles as number | undefined) || 2000;
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
48
|
+
const safeRoots: string[] = [];
|
|
49
|
+
for (const r of roots) {
|
|
50
|
+
try {
|
|
51
|
+
safeRoots.push(assertReadableDir(r, config));
|
|
52
|
+
} catch (error) {
|
|
53
|
+
const message = error instanceof Error ? error.message : 'Invalid root';
|
|
54
|
+
return {
|
|
55
|
+
content: [{ type: 'text' as const, text: `Error: ${message}` }],
|
|
56
|
+
isError: true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
const allFiles: string[] = [];
|
|
62
|
+
for (const r of safeRoots) {
|
|
63
|
+
const found = walkFiles(r, { includeExtensions: extensions, maxFiles });
|
|
64
|
+
allFiles.push(...found);
|
|
65
|
+
}
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
// Use cwd as catalog root so paths are stable for agents
|
|
68
|
+
const root = path.resolve(process.cwd());
|
|
72
69
|
|
|
73
|
-
|
|
70
|
+
const catalog = await buildComponentCatalog(
|
|
71
|
+
root,
|
|
72
|
+
allFiles.map((f) => path.resolve(f))
|
|
73
|
+
);
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
// Ensure POSIX paths
|
|
76
|
+
catalog.components = catalog.components.map((c) => ({ ...c, file: toPosixPath(c.file) }));
|
|
77
|
+
catalog.root = toPosixPath(catalog.root);
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
// Small summary
|
|
80
|
+
const summary = {
|
|
81
|
+
totalFiles: catalog.filesScanned,
|
|
82
|
+
totalComponents: catalog.components.length,
|
|
83
|
+
byExportType: {
|
|
84
|
+
named: catalog.components.filter((c) => c.exportType === 'named').length,
|
|
85
|
+
default: catalog.components.filter((c) => c.exportType === 'default').length,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
89
|
+
return {
|
|
90
|
+
content: [
|
|
91
|
+
{
|
|
92
|
+
type: 'text' as const,
|
|
93
|
+
text: JSON.stringify({ ...catalog, summary }, null, 2),
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
99
|
}
|