@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,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* create_ui Tool
|
|
3
|
+
*
|
|
4
|
+
* Scaffolds new UI components or views.
|
|
5
|
+
* Generates complete, responsive, accessible frontend code.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { buildContext } from '../context/builder.js';
|
|
9
|
+
import { assertWritablePath } from '../context/guards.js';
|
|
10
|
+
import { generateWithGemini } from '../generation/gemini-client.js';
|
|
11
|
+
import { writeFile } from '../output/file-writer.js';
|
|
12
|
+
import { formatCode } from '../output/formatter.js';
|
|
13
|
+
import { buildRepoHints } from '../context/repo-hints.js';
|
|
14
|
+
const inputSchema = {
|
|
15
|
+
description: z.string().describe('Description of the UI to create (component or view)'),
|
|
16
|
+
framework: z.enum(['react', 'vue', 'svelte', 'html']).default('react'),
|
|
17
|
+
vibe: z.string().optional().describe('Design tokens/vibe from generate_vibes'),
|
|
18
|
+
contextFiles: z.array(z.string()).optional().describe('Paths to relevant UI files for context'),
|
|
19
|
+
targetPath: z.string().describe('Target file path to generate (e.g. src/components/Button.tsx)'),
|
|
20
|
+
includeStyles: z.boolean().default(true).describe('Include styling in the generated code'),
|
|
21
|
+
writeToFile: z.boolean().default(false).describe('Write the generated code to targetPath'),
|
|
22
|
+
backup: z.boolean().default(true).describe('Create .bak backup if overwriting an existing file'),
|
|
23
|
+
format: z.boolean().default(true).describe('Format the code with Prettier before returning/writing'),
|
|
24
|
+
};
|
|
25
|
+
const SYSTEM_PROMPT = `You are a senior frontend engineer and UI designer.
|
|
26
|
+
|
|
27
|
+
Your task: generate a COMPLETE, production-ready UI implementation.
|
|
28
|
+
|
|
29
|
+
Hard rules (must follow):
|
|
30
|
+
- Output ONLY the final code. No explanations. No markdown. No code fences.
|
|
31
|
+
- Use the specified framework and keep the code idiomatic for that ecosystem.
|
|
32
|
+
- Do NOT introduce new dependencies unless the user explicitly asked to.
|
|
33
|
+
- Accessibility: meet WCAG AA as a default.
|
|
34
|
+
- Semantic HTML, proper labels, aria-* where appropriate
|
|
35
|
+
- Keyboard navigation for all interactive elements
|
|
36
|
+
- Visible focus states (use :focus-visible patterns if relevant)
|
|
37
|
+
- Responsive by default (mobile-first).
|
|
38
|
+
- If design tokens / vibe are provided, use them (prefer CSS variables) and do not hard-code random colors.
|
|
39
|
+
- Keep logic minimal and UI-focused; avoid fake backend calls.
|
|
40
|
+
|
|
41
|
+
Quality bar:
|
|
42
|
+
- TypeScript types where applicable
|
|
43
|
+
- No unused imports/vars
|
|
44
|
+
- Clean component structure and clear naming`;
|
|
45
|
+
function buildUserPrompt(args) {
|
|
46
|
+
return `Create UI code.
|
|
47
|
+
|
|
48
|
+
${args.repoHints || ''}
|
|
49
|
+
|
|
50
|
+
Framework: ${args.framework}
|
|
51
|
+
Target file: ${args.targetPath}
|
|
52
|
+
|
|
53
|
+
Description:
|
|
54
|
+
${args.description}
|
|
55
|
+
|
|
56
|
+
Design direction / tokens (if provided):
|
|
57
|
+
${args.vibe || '(none)'}
|
|
58
|
+
|
|
59
|
+
Project UI context (if provided):
|
|
60
|
+
${args.context || '(none)'}
|
|
61
|
+
|
|
62
|
+
Styling:
|
|
63
|
+
- includeStyles = ${args.includeStyles}
|
|
64
|
+
- If Tailwind classes appear in context, prefer Tailwind.
|
|
65
|
+
- Otherwise use simple CSS variables + className patterns, minimal inline styles.
|
|
66
|
+
|
|
67
|
+
Return ONLY the code for the target file.`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Extract code from a model response that might contain fences.
|
|
71
|
+
* (We still tell the model not to use fences, but this makes the tool resilient.)
|
|
72
|
+
*/
|
|
73
|
+
function extractCode(response) {
|
|
74
|
+
const codeBlockMatch = response.match(/```[a-zA-Z]*\n([\s\S]*?)```/);
|
|
75
|
+
if (codeBlockMatch) {
|
|
76
|
+
return codeBlockMatch[1].trim();
|
|
77
|
+
}
|
|
78
|
+
return response.trim();
|
|
79
|
+
}
|
|
80
|
+
export function registerCreateUI(server, config) {
|
|
81
|
+
server.registerTool('create_ui', {
|
|
82
|
+
title: 'Create UI Component/View',
|
|
83
|
+
description: 'Generate a complete UI component or view from description and design vibe',
|
|
84
|
+
inputSchema,
|
|
85
|
+
}, async (args) => {
|
|
86
|
+
try {
|
|
87
|
+
const description = args.description;
|
|
88
|
+
const framework = args.framework || config.defaultFramework;
|
|
89
|
+
const vibe = args.vibe;
|
|
90
|
+
const contextFiles = args.contextFiles || [];
|
|
91
|
+
const targetPath = args.targetPath;
|
|
92
|
+
const includeStyles = args.includeStyles;
|
|
93
|
+
const writeToFile = args.writeToFile;
|
|
94
|
+
const backup = args.backup;
|
|
95
|
+
const format = args.format;
|
|
96
|
+
// Build context from files (token-optimized)
|
|
97
|
+
let context = '';
|
|
98
|
+
if (contextFiles.length > 0) {
|
|
99
|
+
context = await buildContext(contextFiles, config);
|
|
100
|
+
}
|
|
101
|
+
const userPrompt = buildUserPrompt({
|
|
102
|
+
description,
|
|
103
|
+
framework,
|
|
104
|
+
vibe,
|
|
105
|
+
context,
|
|
106
|
+
targetPath,
|
|
107
|
+
includeStyles,
|
|
108
|
+
repoHints: buildRepoHints(config),
|
|
109
|
+
});
|
|
110
|
+
if (config.debug) {
|
|
111
|
+
console.error(`[create_ui] Generating UI for: ${description}`);
|
|
112
|
+
console.error(`[create_ui] Framework: ${framework}`);
|
|
113
|
+
console.error(`[create_ui] Context files: ${contextFiles.length}`);
|
|
114
|
+
}
|
|
115
|
+
// Generate code with Gemini
|
|
116
|
+
const response = await generateWithGemini(config, SYSTEM_PROMPT, userPrompt, { toolName: 'create_ui' });
|
|
117
|
+
let code = extractCode(response);
|
|
118
|
+
// Format if requested
|
|
119
|
+
if (format) {
|
|
120
|
+
try {
|
|
121
|
+
code = await formatCode(code, { filePath: targetPath });
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// ignore formatting errors
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Write to file if requested
|
|
128
|
+
if (writeToFile) {
|
|
129
|
+
const safePath = assertWritablePath(targetPath, config);
|
|
130
|
+
const result = await writeFile(safePath, code, { backup, format });
|
|
131
|
+
if (!result.success) {
|
|
132
|
+
return {
|
|
133
|
+
content: [
|
|
134
|
+
{
|
|
135
|
+
type: 'text',
|
|
136
|
+
text: `Error writing file: ${result.error || 'Unknown error'}`,
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
isError: true,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const msg = [
|
|
143
|
+
`✅ UI written successfully.`,
|
|
144
|
+
`File: ${result.filePath}`,
|
|
145
|
+
result.backupPath ? `Backup: ${result.backupPath}` : undefined,
|
|
146
|
+
]
|
|
147
|
+
.filter(Boolean)
|
|
148
|
+
.join('\n');
|
|
149
|
+
return {
|
|
150
|
+
content: [{ type: 'text', text: msg }],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
// Return code only (no wrappers) for best compatibility with agents
|
|
154
|
+
return {
|
|
155
|
+
content: [{ type: 'text', text: code }],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
160
|
+
return {
|
|
161
|
+
content: [{ type: 'text', text: `Error: ${message}` }],
|
|
162
|
+
isError: true,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=create-ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-ui.js","sourceRoot":"","sources":["../../src/tools/create-ui.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* detect_ui_stack Tool
|
|
3
|
+
*
|
|
4
|
+
* Deterministically inspects the workspace to detect the UI stack:
|
|
5
|
+
* framework, styling approach, component libraries, storybook, etc.
|
|
6
|
+
*
|
|
7
|
+
* This tool is intentionally non-LLM to:
|
|
8
|
+
* - reduce token usage
|
|
9
|
+
* - increase reliability
|
|
10
|
+
* - enable downstream tools to condition prompts/outputs on real repo constraints
|
|
11
|
+
*/
|
|
12
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
13
|
+
import { Config } from '../config/index.js';
|
|
14
|
+
export declare function registerDetectUIStack(server: McpServer, config: Config): void;
|
|
15
|
+
//# sourceMappingURL=detect-ui-stack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-ui-stack.d.ts","sourceRoot":"","sources":["../../src/tools/detect-ui-stack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAY5C,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAoC7E"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* detect_ui_stack Tool
|
|
3
|
+
*
|
|
4
|
+
* Deterministically inspects the workspace to detect the UI stack:
|
|
5
|
+
* framework, styling approach, component libraries, storybook, etc.
|
|
6
|
+
*
|
|
7
|
+
* This tool is intentionally non-LLM to:
|
|
8
|
+
* - reduce token usage
|
|
9
|
+
* - increase reliability
|
|
10
|
+
* - enable downstream tools to condition prompts/outputs on real repo constraints
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import { assertReadableDir } from '../context/guards.js';
|
|
15
|
+
import { detectUiStack } from '../stack/detect.js';
|
|
16
|
+
const inputSchema = {
|
|
17
|
+
root: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('Project root directory (defaults to current working directory)')
|
|
21
|
+
.default(process.cwd()),
|
|
22
|
+
};
|
|
23
|
+
export function registerDetectUIStack(server, config) {
|
|
24
|
+
server.registerTool('detect_ui_stack', {
|
|
25
|
+
title: 'Detect UI Stack',
|
|
26
|
+
description: 'Detect framework/styling/component libraries from the repo (no LLM). Useful to ground other tools.',
|
|
27
|
+
inputSchema,
|
|
28
|
+
}, async (args) => {
|
|
29
|
+
const root = args.root || process.cwd();
|
|
30
|
+
let safeRoot;
|
|
31
|
+
try {
|
|
32
|
+
safeRoot = assertReadableDir(root, config);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
const message = error instanceof Error ? error.message : 'Invalid root directory';
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: 'text', text: `Error: ${message}` }],
|
|
38
|
+
isError: true,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const result = detectUiStack(safeRoot);
|
|
42
|
+
// Normalize paths for agent readability
|
|
43
|
+
const normalized = {
|
|
44
|
+
...result,
|
|
45
|
+
root: path.resolve(result.root),
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
content: [{ type: 'text', text: JSON.stringify(normalized, null, 2) }],
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=detect-ui-stack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-ui-stack.js","sourceRoot":"","sources":["../../src/tools/detect-ui-stack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,WAAW,GAAG;IAChB,IAAI,EAAE,CAAC;SACF,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,gEAAgE,CAAC;SAC1E,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;CAC9B,CAAC;AAEF,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,MAAc;IACnE,MAAM,CAAC,YAAY,CACf,iBAAiB,EACjB;QACI,KAAK,EAAE,iBAAiB;QACxB,WAAW,EACP,oGAAoG;QACxG,WAAW;KACd,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACX,MAAM,IAAI,GAAI,IAAI,CAAC,IAAe,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAEpD,IAAI,QAAgB,CAAC;QACrB,IAAI,CAAC;YACD,QAAQ,GAAG,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC;YAClF,OAAO;gBACH,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;gBAC/D,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;QAED,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QAEvC,wCAAwC;QACxC,MAAM,UAAU,GAAG;YACf,GAAG,MAAM;YACT,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;SAClC,CAAC;QAEF,OAAO;YACH,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAClF,CAAC;IACN,CAAC,CACJ,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate_component_variants Tool
|
|
3
|
+
*
|
|
4
|
+
* Given an existing component, generate variants (sizes, intents, states) and
|
|
5
|
+
* optional Storybook stories.
|
|
6
|
+
*
|
|
7
|
+
* Output contract:
|
|
8
|
+
* - When applyChanges=false: outputs ONE JSON object only:
|
|
9
|
+
* {"files": [{"path": string, "content": string}]}
|
|
10
|
+
* - When applyChanges=true: writes files and returns a short summary string.
|
|
11
|
+
*/
|
|
12
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
13
|
+
import { Config } from '../config/index.js';
|
|
14
|
+
export declare function registerGenerateComponentVariants(server: McpServer, config: Config): void;
|
|
15
|
+
//# sourceMappingURL=generate-component-variants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-component-variants.d.ts","sourceRoot":"","sources":["../../src/tools/generate-component-variants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AA8D5C,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA2IzF"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate_component_variants Tool
|
|
3
|
+
*
|
|
4
|
+
* Given an existing component, generate variants (sizes, intents, states) and
|
|
5
|
+
* optional Storybook stories.
|
|
6
|
+
*
|
|
7
|
+
* Output contract:
|
|
8
|
+
* - When applyChanges=false: outputs ONE JSON object only:
|
|
9
|
+
* {"files": [{"path": string, "content": string}]}
|
|
10
|
+
* - When applyChanges=true: writes files and returns a short summary string.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import * as fs from 'node:fs';
|
|
14
|
+
import * as path from 'node:path';
|
|
15
|
+
import { buildContext } from '../context/builder.js';
|
|
16
|
+
import { assertReadablePath, assertWritablePath } from '../context/guards.js';
|
|
17
|
+
import { buildRepoGrounding } from '../context/grounding.js';
|
|
18
|
+
import { generateWithGemini } from '../generation/gemini-client.js';
|
|
19
|
+
import { writeFile } from '../output/file-writer.js';
|
|
20
|
+
const inputSchema = {
|
|
21
|
+
componentFile: z.string().describe('Path to an existing component file (e.g., src/components/Button.tsx).'),
|
|
22
|
+
variants: z
|
|
23
|
+
.object({
|
|
24
|
+
sizes: z.array(z.string()).optional(),
|
|
25
|
+
intents: z.array(z.string()).optional(),
|
|
26
|
+
states: z.array(z.string()).optional(),
|
|
27
|
+
themes: z.array(z.string()).optional(),
|
|
28
|
+
custom: z.array(z.string()).optional().describe('Any additional variant requirements.'),
|
|
29
|
+
})
|
|
30
|
+
.optional()
|
|
31
|
+
.describe('Variant dimensions to generate.'),
|
|
32
|
+
instruction: z.string().optional().describe('Extra guidance about behavior, styling, or API.'),
|
|
33
|
+
storybook: z.boolean().default(true).describe('Generate a Storybook stories file if true.'),
|
|
34
|
+
storyFile: z.string().optional().describe('Optional path for the stories file (defaults next to component).'),
|
|
35
|
+
context: z.array(z.string()).optional().describe('Related files (tokens, theme, utilities).'),
|
|
36
|
+
applyChanges: z.boolean().default(false).describe('If true, write files to disk.'),
|
|
37
|
+
backup: z.boolean().default(true).describe('Create .bak backups before overwriting existing files.'),
|
|
38
|
+
};
|
|
39
|
+
const SYSTEM_PROMPT = `You are a senior frontend engineer specializing in reusable component APIs.
|
|
40
|
+
|
|
41
|
+
Your task:
|
|
42
|
+
- Update an existing component to support the requested variants.
|
|
43
|
+
- Preserve existing behavior and imports unless required.
|
|
44
|
+
- Keep code style consistent with the file.
|
|
45
|
+
- Ensure accessibility: keyboard/focus, aria-labels, disabled states.
|
|
46
|
+
|
|
47
|
+
Repo alignment (CRITICAL):
|
|
48
|
+
- Prefer reusing existing utilities/components already present in the repo.
|
|
49
|
+
- You will receive an auto-detected stack summary + component catalog; do not invent duplicates.
|
|
50
|
+
|
|
51
|
+
Output contract (CRITICAL):
|
|
52
|
+
- If storybook=true, output JSON with an array of files: {"files": [{"path": string, "content": string}]}
|
|
53
|
+
- If storybook=false, output JSON with exactly one file (the component file).
|
|
54
|
+
- Output MUST be ONE valid JSON object only. No prose. No markdown. No code fences.
|
|
55
|
+
|
|
56
|
+
API guidance:
|
|
57
|
+
- Prefer adding/expanding a typed prop such as "size" | "variant" | "intent" and mapping to classes.
|
|
58
|
+
- Avoid breaking changes: keep default props aligned to existing visuals.
|
|
59
|
+
- Do not introduce new dependencies unless explicitly requested.`;
|
|
60
|
+
function cleanJson(response) {
|
|
61
|
+
let out = response.trim();
|
|
62
|
+
const fenced = out.match(/```(?:json)?\n([\s\S]*?)```/);
|
|
63
|
+
if (fenced)
|
|
64
|
+
out = fenced[1].trim();
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
function defaultStoryPath(componentFile) {
|
|
68
|
+
const dir = path.dirname(componentFile);
|
|
69
|
+
const base = path.basename(componentFile).replace(/\.(tsx|jsx|ts|js)$/, '');
|
|
70
|
+
return path.join(dir, `${base}.stories.tsx`);
|
|
71
|
+
}
|
|
72
|
+
export function registerGenerateComponentVariants(server, config) {
|
|
73
|
+
server.registerTool('generate_component_variants', {
|
|
74
|
+
title: 'Generate Component Variants',
|
|
75
|
+
description: 'Enhance an existing component with variants (sizes/intents/states) and optionally generate Storybook stories.',
|
|
76
|
+
inputSchema,
|
|
77
|
+
}, async (args) => {
|
|
78
|
+
const componentFile = args.componentFile;
|
|
79
|
+
const variants = args.variants || {};
|
|
80
|
+
const instruction = args.instruction || '';
|
|
81
|
+
const storybook = args.storybook !== false;
|
|
82
|
+
const storyFile = args.storyFile || defaultStoryPath(componentFile);
|
|
83
|
+
const contextPaths = args.context;
|
|
84
|
+
const applyChanges = args.applyChanges === true;
|
|
85
|
+
const backup = args.backup !== false;
|
|
86
|
+
let safeComponent;
|
|
87
|
+
try {
|
|
88
|
+
safeComponent = assertReadablePath(componentFile, config);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
const message = error instanceof Error ? error.message : 'Invalid componentFile';
|
|
92
|
+
return { content: [{ type: 'text', text: `Error: ${message}` }], isError: true };
|
|
93
|
+
}
|
|
94
|
+
let componentContent;
|
|
95
|
+
try {
|
|
96
|
+
componentContent = fs.readFileSync(safeComponent, 'utf-8');
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return {
|
|
100
|
+
content: [{ type: 'text', text: `Error: Could not read ${componentFile}` }],
|
|
101
|
+
isError: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
let contextContent = '';
|
|
105
|
+
if (contextPaths && contextPaths.length > 0) {
|
|
106
|
+
contextContent = await buildContext(contextPaths, config);
|
|
107
|
+
}
|
|
108
|
+
// Deterministic repo grounding (stack + reusable components)
|
|
109
|
+
const grounding = await buildRepoGrounding(config, {
|
|
110
|
+
focusFileAbs: safeComponent,
|
|
111
|
+
instruction,
|
|
112
|
+
});
|
|
113
|
+
const userPrompt = `Enhance the component to support variants.
|
|
114
|
+
|
|
115
|
+
${grounding}
|
|
116
|
+
|
|
117
|
+
COMPONENT FILE PATH:
|
|
118
|
+
${componentFile}
|
|
119
|
+
|
|
120
|
+
VARIANTS (JSON):
|
|
121
|
+
${JSON.stringify(variants, null, 2)}
|
|
122
|
+
|
|
123
|
+
STORYBOOK:
|
|
124
|
+
${storybook}
|
|
125
|
+
|
|
126
|
+
STORY FILE PATH (if storybook=true):
|
|
127
|
+
${storyFile}
|
|
128
|
+
|
|
129
|
+
EXTRA INSTRUCTION:
|
|
130
|
+
${instruction || '(none)'}
|
|
131
|
+
|
|
132
|
+
CURRENT COMPONENT FILE CONTENT:
|
|
133
|
+
${componentContent}
|
|
134
|
+
|
|
135
|
+
${contextContent ? `RELATED FILES FOR CONTEXT:\n${contextContent}` : ''}
|
|
136
|
+
|
|
137
|
+
Remember: Output JSON only: {"files": [{"path": string, "content": string}]}`;
|
|
138
|
+
try {
|
|
139
|
+
const resp = await generateWithGemini(config, SYSTEM_PROMPT, userPrompt, {
|
|
140
|
+
toolName: 'generate_component_variants',
|
|
141
|
+
});
|
|
142
|
+
const cleaned = cleanJson(resp);
|
|
143
|
+
const parsed = JSON.parse(cleaned);
|
|
144
|
+
if (!parsed || !Array.isArray(parsed.files) || parsed.files.length === 0) {
|
|
145
|
+
return {
|
|
146
|
+
content: [
|
|
147
|
+
{
|
|
148
|
+
type: 'text',
|
|
149
|
+
text: 'Error: Model output did not match expected JSON format: {"files": [...]}',
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
isError: true,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (!applyChanges) {
|
|
156
|
+
return { content: [{ type: 'text', text: JSON.stringify(parsed, null, 2) }] };
|
|
157
|
+
}
|
|
158
|
+
const writes = [];
|
|
159
|
+
for (const f of parsed.files) {
|
|
160
|
+
const target = f.path;
|
|
161
|
+
const content = f.content;
|
|
162
|
+
let safeOut;
|
|
163
|
+
try {
|
|
164
|
+
safeOut = assertWritablePath(target, config);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
const message = error instanceof Error ? error.message : 'Invalid output path';
|
|
168
|
+
return { content: [{ type: 'text', text: `Error: ${message}` }], isError: true };
|
|
169
|
+
}
|
|
170
|
+
const result = await writeFile(safeOut, content, { format: true, backup });
|
|
171
|
+
if (!result.success) {
|
|
172
|
+
return {
|
|
173
|
+
content: [
|
|
174
|
+
{
|
|
175
|
+
type: 'text',
|
|
176
|
+
text: `Error: Failed writing ${target}: ${result.error || 'Unknown error'}`,
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
isError: true,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
writes.push({ file: result.filePath, backup: result.backupPath });
|
|
183
|
+
}
|
|
184
|
+
const summary = [
|
|
185
|
+
'✅ Generated component variants and wrote files:',
|
|
186
|
+
...writes.map((w) => `- ${w.file}${w.backup ? ` (backup: ${w.backup})` : ''}`),
|
|
187
|
+
].join('\n');
|
|
188
|
+
return { content: [{ type: 'text', text: summary }] };
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
192
|
+
return {
|
|
193
|
+
content: [{ type: 'text', text: `Error generating variants: ${message}` }],
|
|
194
|
+
isError: true,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=generate-component-variants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-component-variants.js","sourceRoot":"","sources":["../../src/tools/generate-component-variants.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate_vibes Tool
|
|
3
|
+
*
|
|
4
|
+
* Generates design direction options (vibes) before creating UI.
|
|
5
|
+
* Returns color palettes, typography, spacing, and sample CSS variables.
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
import { Config } from '../config/index.js';
|
|
9
|
+
export declare function registerGenerateVibes(server: McpServer, config: Config): void;
|
|
10
|
+
//# sourceMappingURL=generate-vibes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-vibes.d.ts","sourceRoot":"","sources":["../../src/tools/generate-vibes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAwE5C,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA+D7E"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate_vibes Tool
|
|
3
|
+
*
|
|
4
|
+
* Generates design direction options (vibes) before creating UI.
|
|
5
|
+
* Returns color palettes, typography, spacing, and sample CSS variables.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { buildContext } from '../context/builder.js';
|
|
9
|
+
import { generateWithGemini } from '../generation/gemini-client.js';
|
|
10
|
+
const inputSchema = {
|
|
11
|
+
projectContext: z
|
|
12
|
+
.string()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe('Brief description of the project (e.g., "Modern SaaS dashboard for analytics")'),
|
|
15
|
+
existingTokens: z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe('Path to existing design tokens or CSS file to analyze (optional)'),
|
|
19
|
+
vibeCount: z
|
|
20
|
+
.number()
|
|
21
|
+
.min(1)
|
|
22
|
+
.max(5)
|
|
23
|
+
.default(3)
|
|
24
|
+
.describe('Number of vibe options to generate (1-5)'),
|
|
25
|
+
preferences: z
|
|
26
|
+
.object({
|
|
27
|
+
colorTemp: z.enum(['warm', 'cool', 'neutral']).optional(),
|
|
28
|
+
density: z.enum(['compact', 'comfortable', 'spacious']).optional(),
|
|
29
|
+
style: z.enum(['minimal', 'playful', 'corporate', 'brutalist', 'glassmorphism']).optional(),
|
|
30
|
+
})
|
|
31
|
+
.optional()
|
|
32
|
+
.describe('Optional style preferences to guide generation'),
|
|
33
|
+
};
|
|
34
|
+
const SYSTEM_PROMPT = `You are an expert UI/UX designer specializing in modern web design systems.
|
|
35
|
+
|
|
36
|
+
Your task is to generate design "vibes"—cohesive design directions that include colors, typography, and spacing.
|
|
37
|
+
|
|
38
|
+
Requirements:
|
|
39
|
+
- Return ONE valid JSON object with a "vibes" array (no markdown, no code fences, no extra commentary).
|
|
40
|
+
- Use semantic color roles (primary, secondary, accent, background, surface, text, textMuted, border, danger, success).
|
|
41
|
+
- Prefer accessible color combinations (aim for WCAG AA contrast for text on background/surface).
|
|
42
|
+
- Provide a sensible type scale and spacing scale (consistent multiplier).
|
|
43
|
+
- Provide a ready-to-paste CSS variable block (light theme). If you can, include a dark theme block too.
|
|
44
|
+
|
|
45
|
+
Output structure:
|
|
46
|
+
{
|
|
47
|
+
"vibes": [
|
|
48
|
+
{
|
|
49
|
+
"name": "Vibe Name",
|
|
50
|
+
"description": "Brief aesthetic description",
|
|
51
|
+
"colors": {
|
|
52
|
+
"primary": "#hex",
|
|
53
|
+
"secondary": "#hex",
|
|
54
|
+
"accent": "#hex",
|
|
55
|
+
"background": "#hex",
|
|
56
|
+
"surface": "#hex",
|
|
57
|
+
"text": "#hex",
|
|
58
|
+
"textMuted": "#hex",
|
|
59
|
+
"border": "#hex",
|
|
60
|
+
"danger": "#hex",
|
|
61
|
+
"success": "#hex"
|
|
62
|
+
},
|
|
63
|
+
"typography": {
|
|
64
|
+
"fontFamily": "font stack",
|
|
65
|
+
"headingFamily": "font stack or same",
|
|
66
|
+
"scale": [12, 14, 16, 18, 20, 24, 30, 36, 48, 60]
|
|
67
|
+
},
|
|
68
|
+
"spacing": {
|
|
69
|
+
"unit": 4,
|
|
70
|
+
"scale": [0, 4, 8, 12, 16, 24, 32, 48, 64, 96]
|
|
71
|
+
},
|
|
72
|
+
"cssVariables": "/* light */\\n:root { --color-primary: #...; }\\n\\n/* dark */\\n[data-theme='dark'] { --color-primary: #...; }"
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}`;
|
|
76
|
+
export function registerGenerateVibes(server, config) {
|
|
77
|
+
server.registerTool('generate_vibes', {
|
|
78
|
+
title: 'Generate Design Vibes',
|
|
79
|
+
description: 'Generate design direction options (vibes) with color palettes, typography, and spacing. Call this before create_ui to establish design consistency.',
|
|
80
|
+
inputSchema,
|
|
81
|
+
}, async (args) => {
|
|
82
|
+
const projectContext = args.projectContext;
|
|
83
|
+
const vibeCount = args.vibeCount;
|
|
84
|
+
const preferences = args.preferences;
|
|
85
|
+
const existingTokensPath = args.existingTokens;
|
|
86
|
+
let existingTokensContext = '';
|
|
87
|
+
if (existingTokensPath) {
|
|
88
|
+
// Use the same context pipeline (path allowlist + sensitive file filtering + truncation)
|
|
89
|
+
existingTokensContext = await buildContext([existingTokensPath], config);
|
|
90
|
+
}
|
|
91
|
+
let userPrompt = buildPrompt({
|
|
92
|
+
projectContext,
|
|
93
|
+
vibeCount,
|
|
94
|
+
preferences,
|
|
95
|
+
});
|
|
96
|
+
if (existingTokensContext) {
|
|
97
|
+
userPrompt += `\n\nExisting design tokens / styles to respect:\n${existingTokensContext}`;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const response = await generateWithGemini(config, SYSTEM_PROMPT, userPrompt, { toolName: 'generate_vibes' });
|
|
101
|
+
return {
|
|
102
|
+
content: [
|
|
103
|
+
{
|
|
104
|
+
type: 'text',
|
|
105
|
+
text: response.trim(),
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
112
|
+
return {
|
|
113
|
+
content: [
|
|
114
|
+
{
|
|
115
|
+
type: 'text',
|
|
116
|
+
text: `Error generating vibes: ${message}`,
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
isError: true,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function buildPrompt(input) {
|
|
125
|
+
const vibeCount = input.vibeCount ?? 3;
|
|
126
|
+
let prompt = `Generate ${vibeCount} distinct design vibes`;
|
|
127
|
+
if (input.projectContext) {
|
|
128
|
+
prompt += ` for this project: "${input.projectContext}"`;
|
|
129
|
+
}
|
|
130
|
+
if (input.preferences) {
|
|
131
|
+
const prefs = [];
|
|
132
|
+
if (input.preferences.colorTemp)
|
|
133
|
+
prefs.push(`${input.preferences.colorTemp} color temperature`);
|
|
134
|
+
if (input.preferences.density)
|
|
135
|
+
prefs.push(`${input.preferences.density} spacing density`);
|
|
136
|
+
if (input.preferences.style)
|
|
137
|
+
prefs.push(`${input.preferences.style} style`);
|
|
138
|
+
if (prefs.length > 0) {
|
|
139
|
+
prompt += `. Preferences: ${prefs.join(', ')}`;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
prompt += '. Return valid JSON only.';
|
|
143
|
+
return prompt;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=generate-vibes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-vibes.js","sourceRoot":"","sources":["../../src/tools/generate-vibes.ts"],"names":[],"mappings":"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"}
|