vibetachyon 1.5.6 → 1.5.8
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/mcp-server.js +229 -63
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -177,51 +177,148 @@ async function startMcpServer() {
|
|
|
177
177
|
version: "1.5.0"
|
|
178
178
|
});
|
|
179
179
|
/**
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
* You
|
|
183
|
-
*
|
|
184
|
-
*
|
|
180
|
+
* VIBETACHYON FRONTEND PERSONA — Senior Frontend Designer
|
|
181
|
+
*
|
|
182
|
+
* You are a Senior Frontend Designer with 10 years of experience building SaaS products.
|
|
183
|
+
* You have strong opinions and you enforce them. You do NOT generate generic code.
|
|
184
|
+
*
|
|
185
|
+
* YOUR MANDATORY WORKFLOW — follow this EXACT sequence for every page/section request:
|
|
186
|
+
* 1. vibe_project_dna — read the project first, always
|
|
187
|
+
* 2. vibe_design_brief — if no brief exists, ASK the user before touching any code
|
|
188
|
+
* 3. vibe_read_design_brief — read active brief before each new section
|
|
189
|
+
* 4. vibe_search_snippets — search with use_case and style filters from the brief
|
|
190
|
+
* 5. Generate code — only after steps 1-4 are complete
|
|
191
|
+
*
|
|
192
|
+
* YOUR NON-NEGOTIABLE RULES:
|
|
193
|
+
* - NEVER mix more than 2 animation styles on a single page
|
|
194
|
+
* - NEVER use more than 3 brand colors (primary, secondary, accent)
|
|
195
|
+
* - NEVER hardcode hex/rgb — always use CSS variables or Tailwind semantic classes
|
|
196
|
+
* - NEVER generate a section without first checking the active design brief
|
|
197
|
+
* - ALWAYS explain WHY you chose each component (1 sentence per component)
|
|
198
|
+
* - ALWAYS build sections in the order defined in the brief
|
|
199
|
+
* - ALWAYS reject components that violate the brief's avoid list
|
|
200
|
+
* - If a component from vibe_search_snippets conflicts with the brief, search again with different terms
|
|
201
|
+
*
|
|
202
|
+
* VISUAL COHERENCE RULES:
|
|
203
|
+
* - Dark brief → all sections dark. No random light cards in a dark page.
|
|
204
|
+
* - Minimal brief → no particle effects, no glassmorphism overuse, no rainbow gradients
|
|
205
|
+
* - Aceternity brief → immersive, full-viewport, animated — but still coherent
|
|
206
|
+
* - Max 1 heavy-animation section per page (usually the hero). Rest = subtle or static.
|
|
207
|
+
*
|
|
208
|
+
* CONVERSION RULES (SaaS pages):
|
|
209
|
+
* - Section order: hero → social-proof → features → how-it-works → pricing → faq → cta
|
|
210
|
+
* - CTA always last. Never bury it in the middle.
|
|
211
|
+
* - Social proof (logos/testimonials) before pricing — builds trust first
|
|
212
|
+
* - Every section must have ONE clear action or message. Not two.
|
|
185
213
|
*/
|
|
186
214
|
// Tool: Searching Snippets
|
|
187
|
-
server.tool("vibe_search_snippets", "Search for UI components in the VibeCodes repository
|
|
188
|
-
query: zod_1.z.string().describe("Search query for the UI component (e.g. '
|
|
215
|
+
server.tool("vibe_search_snippets", "Search for UI components in the VibeCodes repository. Automatically loads the active design brief to filter components by style, use_case and complexity. Always call vibe_project_dna and vibe_design_brief before this tool.", {
|
|
216
|
+
query: zod_1.z.string().describe("Search query for the UI component (e.g. 'hero section dark', 'animated button')"),
|
|
189
217
|
limit: zod_1.z.number().optional().describe("Max number of results to return (default: 5)"),
|
|
190
|
-
projectDir: zod_1.z.string().optional().describe("Absolute path to the user's project root.
|
|
191
|
-
|
|
218
|
+
projectDir: zod_1.z.string().optional().describe("Absolute path to the user's project root."),
|
|
219
|
+
useCaseFilter: zod_1.z.string().optional().describe("Filter by use case: 'hero', 'cta', 'feature-section', 'navigation', 'footer', 'pricing', 'social-proof', 'background-effect', 'text-effect', 'modal', 'form'"),
|
|
220
|
+
styleFilter: zod_1.z.array(zod_1.z.string()).optional().describe("Filter by style tags: 'dark', 'light', 'animated', 'glassmorphism', 'gradient', 'minimal', 'modern'"),
|
|
221
|
+
complexityFilter: zod_1.z.enum(['simple', 'medium', 'complex']).optional().describe("Filter by code complexity")
|
|
222
|
+
}, async ({ query, limit = 5, projectDir, useCaseFilter, styleFilter, complexityFilter }) => {
|
|
192
223
|
await checkSanity();
|
|
193
|
-
console.error(`[VibeTachyon] Searching
|
|
224
|
+
console.error(`[VibeTachyon] Searching DB for: ${query}`);
|
|
225
|
+
const rawRoot = projectDir || process.cwd();
|
|
226
|
+
const root = await findProjectRoot(rawRoot);
|
|
227
|
+
// Auto-load design brief to enrich filters
|
|
228
|
+
let brief = null;
|
|
229
|
+
let briefWarning = '';
|
|
194
230
|
try {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
.
|
|
231
|
+
const sessionPath = path_1.default.join(root, '.vibetachyon', 'design-session.json');
|
|
232
|
+
if (await fs_extra_1.default.pathExists(sessionPath)) {
|
|
233
|
+
brief = await fs_extra_1.default.readJson(sessionPath);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
briefWarning = `\n⚠️ [VibeTachyon] No design brief found. Call vibe_design_brief first for better results.\n`;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
catch { /* brief is optional */ }
|
|
240
|
+
// Merge explicit filters with brief-derived filters
|
|
241
|
+
let resolvedStyleFilter = styleFilter;
|
|
242
|
+
let resolvedUseCaseFilter = useCaseFilter;
|
|
243
|
+
let resolvedComplexity = complexityFilter;
|
|
244
|
+
if (brief && !styleFilter) {
|
|
245
|
+
const tone = brief.rules?.visualTone;
|
|
246
|
+
const animLevel = brief.rules?.animationLevel || brief.styleProfile?.animationLevel;
|
|
247
|
+
const derivedTags = [];
|
|
248
|
+
if (tone === 'dark')
|
|
249
|
+
derivedTags.push('dark');
|
|
250
|
+
if (tone === 'light')
|
|
251
|
+
derivedTags.push('light');
|
|
252
|
+
if (animLevel === 'heavy')
|
|
253
|
+
derivedTags.push('animated');
|
|
254
|
+
if (brief.referenceStyle === 'aceternity')
|
|
255
|
+
derivedTags.push('animated', 'dark');
|
|
256
|
+
if (brief.referenceStyle === 'notion' || brief.referenceStyle === 'stripe')
|
|
257
|
+
derivedTags.push('minimal');
|
|
258
|
+
if (derivedTags.length > 0)
|
|
259
|
+
resolvedStyleFilter = derivedTags;
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
const rpcParams = {
|
|
198
263
|
search_query: query,
|
|
199
264
|
max_limit: limit
|
|
200
|
-
}
|
|
265
|
+
};
|
|
266
|
+
if (resolvedUseCaseFilter)
|
|
267
|
+
rpcParams.filter_use_case = resolvedUseCaseFilter;
|
|
268
|
+
if (resolvedStyleFilter && resolvedStyleFilter.length > 0)
|
|
269
|
+
rpcParams.filter_style_tags = resolvedStyleFilter;
|
|
270
|
+
if (resolvedComplexity)
|
|
271
|
+
rpcParams.filter_complexity = resolvedComplexity;
|
|
272
|
+
const { data: allResults, error } = await supabase
|
|
273
|
+
.rpc('search_vibecodes_mcp', rpcParams);
|
|
201
274
|
if (error) {
|
|
202
275
|
console.error("[VibeTachyon] Supabase RPC Error:", error);
|
|
203
276
|
throw error;
|
|
204
277
|
}
|
|
205
|
-
|
|
278
|
+
// If filtered search returns nothing, fallback to unfiltered
|
|
279
|
+
let results = allResults;
|
|
280
|
+
let fallbackNote = '';
|
|
281
|
+
if ((!results || results.length === 0) && (resolvedStyleFilter || resolvedUseCaseFilter)) {
|
|
282
|
+
console.error(`[VibeTachyon] No filtered results, falling back to unfiltered search`);
|
|
283
|
+
const { data: fallback } = await supabase.rpc('search_vibecodes_mcp', {
|
|
284
|
+
search_query: query,
|
|
285
|
+
max_limit: limit
|
|
286
|
+
});
|
|
287
|
+
results = fallback;
|
|
288
|
+
fallbackNote = `\n⚠️ No components matched the style filters. Showing best semantic matches instead — review fit with design brief.\n`;
|
|
289
|
+
}
|
|
290
|
+
if (!results || results.length === 0) {
|
|
206
291
|
return {
|
|
207
|
-
content: [{ type: "text", text: `No VibeCodes components found for "${query}". Try different
|
|
292
|
+
content: [{ type: "text", text: `No VibeCodes components found for "${query}". Try different search terms.` }]
|
|
208
293
|
};
|
|
209
294
|
}
|
|
210
|
-
|
|
211
|
-
|
|
295
|
+
// Coherence check — flag components that might break brief rules
|
|
296
|
+
const briefAvoid = brief?.rules?.mustAvoid || [];
|
|
297
|
+
const formattedResults = results.map((item) => {
|
|
298
|
+
const srcInfo = item.source_table === 'Aceternity UI' ? '[⭐ ACETERNITY]'
|
|
299
|
+
: item.source_table === 'Magic UI' ? '[✨ MAGIC UI]'
|
|
300
|
+
: item.source_table === '21st.dev' ? '[🌐 21ST.DEV]'
|
|
301
|
+
: `[📦 ${item.source_table?.toUpperCase() || 'VIBECODES'}]`;
|
|
302
|
+
const styleLine = item.style_tags?.length
|
|
303
|
+
? `Style: ${item.style_tags.join(', ')}`
|
|
304
|
+
: '';
|
|
305
|
+
const useCaseLine = item.use_case?.length
|
|
306
|
+
? `Use case: ${item.use_case.join(', ')}`
|
|
307
|
+
: '';
|
|
308
|
+
const complexityLine = item.complexity ? `Complexity: ${item.complexity}` : '';
|
|
309
|
+
// Coherence warning
|
|
310
|
+
const codeStr = (item.code || '').toLowerCase();
|
|
311
|
+
const violations = briefAvoid.filter((rule) => {
|
|
312
|
+
const ruleKey = rule.toLowerCase();
|
|
313
|
+
return codeStr.includes(ruleKey) || (item.title || '').toLowerCase().includes(ruleKey);
|
|
314
|
+
});
|
|
315
|
+
const coherenceNote = violations.length > 0
|
|
316
|
+
? `\n🚨 BRIEF CONFLICT: This component may contain "${violations.join(', ')}" which is in the avoid list. Review before using.\n`
|
|
317
|
+
: '';
|
|
212
318
|
const minifiedCode = minifySnippet(item.code);
|
|
213
|
-
return `### ${item.title} ${srcInfo}\n${item.description || ''}\n
|
|
319
|
+
return `### ${item.title} ${srcInfo}\n${[styleLine, useCaseLine, complexityLine].filter(Boolean).join(' | ')}\n${item.description || ''}${coherenceNote}\n\`\`\`tsx\n${minifiedCode}\n\`\`\``;
|
|
214
320
|
}).join('\n\n---\n\n');
|
|
215
|
-
//
|
|
216
|
-
const rawRoot = projectDir || process.cwd();
|
|
217
|
-
const root = await findProjectRoot(rawRoot);
|
|
218
|
-
const standardDeps = { "framer-motion": "11.0.0", "lucide-react": "0.400.0" };
|
|
219
|
-
const audit = await auditPeerDeps(root, standardDeps);
|
|
220
|
-
let auditPrefix = "";
|
|
221
|
-
if (audit.warnings.length > 0) {
|
|
222
|
-
auditPrefix = `### ⚠️ [VIBESHIELD: VERSION WARNING]\n${audit.warnings.join('\n')}\n\n`;
|
|
223
|
-
}
|
|
224
|
-
// --- ZERO FRICTION "ACCEPT-ALL" GUARDRAILS ---
|
|
321
|
+
// Framework guardrails
|
|
225
322
|
let frameworkContext = "";
|
|
226
323
|
try {
|
|
227
324
|
const pkgPath = path_1.default.join(root, 'package.json');
|
|
@@ -230,51 +327,120 @@ async function startMcpServer() {
|
|
|
230
327
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
231
328
|
const isVite = !!deps['vite'];
|
|
232
329
|
const isNext = !!deps['next'];
|
|
233
|
-
frameworkContext += `\n\n
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
frameworkContext += `🚨 FATAL VITE ERROR PREVENTION:\n- DO NOT use Next.js '<Image>' or 'next/link'.\n- DO NOT use '"use client"'.\n- You MUST implicitly translate the components above into standard '<img>' and '<a>' tags BEFORE writing the final code.\n`;
|
|
239
|
-
frameworkContext += `- Tell the user to run this command if animations are used: \`npm install framer-motion lucide-react clsx tailwind-merge\`\n`;
|
|
240
|
-
}
|
|
241
|
-
else if (isNext) {
|
|
242
|
-
frameworkContext += `🚨 NEXT.JS OPTIMIZATION:\n- Use Server Components by default.\n- If the component uses hooks (useState) or onClick, you MUST prepend '"use client";' at the very top of the generated file.\n`;
|
|
243
|
-
frameworkContext += `- Ensure image domains are whitelisted (tell them to update next.config.ts if an external src is used).\n`;
|
|
244
|
-
}
|
|
245
|
-
frameworkContext += `=======================================================\n`;
|
|
330
|
+
frameworkContext += `\n[FRAMEWORK: ${isNext ? 'Next.js' : isVite ? 'Vite/React' : 'React'}]\n`;
|
|
331
|
+
if (isVite)
|
|
332
|
+
frameworkContext += `- Remove "use client", replace next/image with <img>, replace next/link with <a>\n`;
|
|
333
|
+
if (isNext)
|
|
334
|
+
frameworkContext += `- Add "use client" if component uses hooks or event handlers\n`;
|
|
246
335
|
}
|
|
247
336
|
}
|
|
248
|
-
catch
|
|
249
|
-
|
|
250
|
-
}
|
|
337
|
+
catch { /* silent */ }
|
|
338
|
+
// Peer dep audit
|
|
339
|
+
const standardDeps = { "framer-motion": "11.0.0", "lucide-react": "0.400.0" };
|
|
340
|
+
const audit = await auditPeerDeps(root, standardDeps);
|
|
341
|
+
const auditPrefix = audit.warnings.length > 0
|
|
342
|
+
? `⚠️ [VIBESHIELD]\n${audit.warnings.join('\n')}\n\n`
|
|
343
|
+
: '';
|
|
344
|
+
const briefSummary = brief
|
|
345
|
+
? `[Active Brief: ${brief.referenceStyle} | ${brief.rules?.visualTone} | max ${brief.rules?.maxAnimationTypes} animations]\n`
|
|
346
|
+
: '';
|
|
251
347
|
return {
|
|
252
|
-
content: [{
|
|
348
|
+
content: [{
|
|
349
|
+
type: "text",
|
|
350
|
+
text: `${auditPrefix}${briefWarning}${fallbackNote}${briefSummary}` +
|
|
351
|
+
`🧠 VibeTachyon found ${results.length} components for "${query}"` +
|
|
352
|
+
(resolvedStyleFilter ? ` [style: ${resolvedStyleFilter.join(', ')}]` : '') +
|
|
353
|
+
(resolvedUseCaseFilter ? ` [use: ${resolvedUseCaseFilter}]` : '') +
|
|
354
|
+
`:\n\n${formattedResults}\n\n${frameworkContext}` +
|
|
355
|
+
`\nINSTRUCTION FOR AI: Cross-check each component against the active design brief before using. Reject any that violate the brief rules.`
|
|
356
|
+
}]
|
|
253
357
|
};
|
|
254
358
|
}
|
|
255
359
|
catch (error) {
|
|
256
|
-
console.error("[VibeTachyon]
|
|
360
|
+
console.error("[VibeTachyon] Search Error:", error);
|
|
257
361
|
return {
|
|
258
|
-
content: [{ type: "text", text: `Error searching VibeCodes repository: ${error}` }]
|
|
362
|
+
content: [{ type: "text", text: `Error searching VibeCodes repository: ${error instanceof Error ? error.message : String(error)}` }]
|
|
259
363
|
};
|
|
260
364
|
}
|
|
261
365
|
});
|
|
262
|
-
//
|
|
263
|
-
server.tool("vibe_get_architecture", "
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
366
|
+
// Tool: Frontend Persona — Senior Designer Rules
|
|
367
|
+
server.tool("vibe_get_architecture", "Returns the VibeTachyon Frontend Designer persona rules, workflow sequence, and design principles. Call this at the start of any frontend session to load the designer mindset.", {
|
|
368
|
+
context: zod_1.z.string().optional().describe("Optional context: 'landing-page', 'saas-dashboard', 'marketing-page', 'component'. Defaults to 'landing-page'.")
|
|
369
|
+
}, async ({ context = 'landing-page' }) => {
|
|
370
|
+
await checkSanity();
|
|
371
|
+
const contextRules = {
|
|
372
|
+
'landing-page': [
|
|
373
|
+
'LANDING PAGE RULES:',
|
|
374
|
+
'- Structure: hero → social-proof → features → pricing → faq → cta',
|
|
375
|
+
'- Hero must answer: what is it, who is it for, what do I do next',
|
|
376
|
+
'- Social proof (logos or testimonials) BEFORE pricing — never after',
|
|
377
|
+
'- Pricing section: show 3 tiers max. Highlight the middle one.',
|
|
378
|
+
'- One CTA per section. Not two.',
|
|
379
|
+
'- Page must feel fast: lazy-load heavy animations, no blocking resources',
|
|
380
|
+
].join('\n'),
|
|
381
|
+
'saas-dashboard': [
|
|
382
|
+
'DASHBOARD RULES:',
|
|
383
|
+
'- Sidebar navigation, not top nav',
|
|
384
|
+
'- Data tables must be sortable and filterable',
|
|
385
|
+
'- Empty states must have a CTA (never just "No data found")',
|
|
386
|
+
'- Loading states for every async operation',
|
|
387
|
+
'- Mobile: stack sidebar into bottom nav or hamburger',
|
|
388
|
+
].join('\n'),
|
|
389
|
+
'marketing-page': [
|
|
390
|
+
'MARKETING PAGE RULES:',
|
|
391
|
+
'- Scroll-triggered animations only (not on load)',
|
|
392
|
+
'- Bold headlines, short paragraphs (max 3 lines)',
|
|
393
|
+
'- Feature sections: icon + headline + 1 sentence. Nothing more.',
|
|
394
|
+
'- Video > images > illustrations > icons (in order of impact)',
|
|
395
|
+
].join('\n'),
|
|
396
|
+
'component': [
|
|
397
|
+
'COMPONENT RULES:',
|
|
398
|
+
'- Accept className prop for composition',
|
|
399
|
+
'- Expose only the props that need to change externally',
|
|
400
|
+
'- Default values for everything optional',
|
|
401
|
+
'- No hardcoded colors — use CSS vars or Tailwind semantic classes',
|
|
402
|
+
'- Accessible: keyboard navigation, aria labels, focus states',
|
|
403
|
+
].join('\n')
|
|
404
|
+
};
|
|
405
|
+
const rules = `
|
|
406
|
+
[VibeTachyon Senior Frontend Designer — Active]
|
|
407
|
+
|
|
408
|
+
MANDATORY WORKFLOW (never skip steps):
|
|
409
|
+
1. vibe_project_dna → understand the project
|
|
410
|
+
2. vibe_design_brief → define goal, style, sections (ASK if missing)
|
|
411
|
+
3. vibe_read_design_brief → check brief before each section
|
|
412
|
+
4. vibe_search_snippets → search with style + use_case filters
|
|
413
|
+
5. Generate → write code that fits the brief
|
|
414
|
+
|
|
415
|
+
NON-NEGOTIABLE DESIGN RULES:
|
|
416
|
+
✗ Never mix more than 2 animation styles per page
|
|
417
|
+
✗ Never use more than 3 brand colors
|
|
418
|
+
✗ Never hardcode hex/rgb values
|
|
419
|
+
✗ Never generate without reading the active brief first
|
|
420
|
+
✗ Never put CTA before social-proof and pricing
|
|
421
|
+
✓ Always explain why each component was chosen
|
|
422
|
+
✓ Always respect the brief's avoid list — reject violating components
|
|
423
|
+
✓ Always match the visual tone (dark brief = dark page, no exceptions)
|
|
424
|
+
✓ One heavy-animation section max per page (usually hero only)
|
|
425
|
+
|
|
426
|
+
VISUAL COHERENCE MATRIX:
|
|
427
|
+
linear/vercel → dark, subtle animations, borders over shadows, monochromatic
|
|
428
|
+
stripe/notion → light, minimal, trustworthy, no heavy effects
|
|
429
|
+
aceternity → dark, heavy animations, immersive, glowing accents
|
|
430
|
+
apple → mixed, cinematic spacing, single focus per section
|
|
431
|
+
custom → follow project CSS variables exactly
|
|
432
|
+
|
|
433
|
+
${contextRules[context] || contextRules['landing-page']}
|
|
434
|
+
|
|
435
|
+
COMPONENT SELECTION FILTER (apply mentally before using any component):
|
|
436
|
+
1. Does it match the brief's visual tone? (dark/light/mixed)
|
|
437
|
+
2. Does it respect the animation limit?
|
|
438
|
+
3. Does it avoid the items in the brief's avoid list?
|
|
439
|
+
4. Does it fit the section's use_case?
|
|
440
|
+
If any answer is NO → reject and search again.
|
|
441
|
+
`;
|
|
271
442
|
return {
|
|
272
|
-
content: [
|
|
273
|
-
{
|
|
274
|
-
type: "text",
|
|
275
|
-
text: rules
|
|
276
|
-
}
|
|
277
|
-
]
|
|
443
|
+
content: [{ type: "text", text: rules }]
|
|
278
444
|
};
|
|
279
445
|
});
|
|
280
446
|
// Tool: Scan Local Architecture
|