vibetachyon 1.7.0 → 1.8.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/dist/mcp-server.js +149 -1
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -31,12 +31,40 @@ const supabase = (0, supabase_js_1.createClient)(supabaseUrl, supabaseKey, supab
|
|
|
31
31
|
const LOCAL_CACHE_DIR = path_1.default.join(process.env.HOME || process.env.USERPROFILE || '', '.vibetachyon', 'cache');
|
|
32
32
|
const CALL_LIMIT_PER_SESSION = 150; // Sanity Trap to prevent agent infinite loops
|
|
33
33
|
let sessionCallCount = 0;
|
|
34
|
+
// --- Session Stats Tracker ---
|
|
35
|
+
const SESSION_START = Date.now();
|
|
36
|
+
const sessionStats = {
|
|
37
|
+
componentsLoaded: 0,
|
|
38
|
+
tsErrorsFixed: 0,
|
|
39
|
+
depsInstalled: 0,
|
|
40
|
+
missionsStarted: 0,
|
|
41
|
+
missionsCompleted: 0,
|
|
42
|
+
sectionsBuilt: 0,
|
|
43
|
+
};
|
|
34
44
|
async function checkSanity() {
|
|
35
45
|
sessionCallCount++;
|
|
36
46
|
if (sessionCallCount > CALL_LIMIT_PER_SESSION) {
|
|
37
47
|
throw new Error(`[VIBETACHYON SANITY TRAP] Execution blocked. Agent exceeded ${CALL_LIMIT_PER_SESSION} tool calls in a single session. This prevents infinite loops or excessive API usage. Please restart the CLI if this was intentional.`);
|
|
38
48
|
}
|
|
39
49
|
}
|
|
50
|
+
// --- Changelog (per version) ---
|
|
51
|
+
const CHANGELOG = {
|
|
52
|
+
'1.8.0': [
|
|
53
|
+
'vibe_session_recap — resumo completo da sessão',
|
|
54
|
+
'Update check automático no startup com changelog',
|
|
55
|
+
'vibe_clone_design — clone de design system por URL',
|
|
56
|
+
],
|
|
57
|
+
'1.7.0': [
|
|
58
|
+
'vibe_launchpad — MISSION BRIEFING automático antes de qualquer código',
|
|
59
|
+
'Mandatory workflow reforçado nas descrições de tools',
|
|
60
|
+
'Detecção automática de stack, cores e brief existente',
|
|
61
|
+
],
|
|
62
|
+
'1.6.0': [
|
|
63
|
+
'Animmaster Engine com 42 componentes premium',
|
|
64
|
+
'Missions, Tasks, Squads e Personas',
|
|
65
|
+
'Visual QA, Self-heal TypeScript, Ephemeral Previews',
|
|
66
|
+
],
|
|
67
|
+
};
|
|
40
68
|
async function getLocalCache(key) {
|
|
41
69
|
const cachePath = path_1.default.join(LOCAL_CACHE_DIR, `${key}.json`);
|
|
42
70
|
if (await fs_extra_1.default.pathExists(cachePath)) {
|
|
@@ -169,12 +197,38 @@ async function validateTokenAtStartup() {
|
|
|
169
197
|
// Network error — allow graceful degradation (offline mode)
|
|
170
198
|
console.error('[VibeTachyon] Aviso: Não foi possível verificar o token (modo offline). Continuando...');
|
|
171
199
|
}
|
|
200
|
+
// --- Update Check ---
|
|
201
|
+
try {
|
|
202
|
+
const CURRENT_VERSION = '1.8.0'; // keep in sync with package.json
|
|
203
|
+
const npmRes = await fetch('https://registry.npmjs.org/vibetachyon/latest', {
|
|
204
|
+
signal: AbortSignal.timeout(4000)
|
|
205
|
+
});
|
|
206
|
+
const npmData = await npmRes.json();
|
|
207
|
+
const latest = npmData.version;
|
|
208
|
+
if (latest && latest !== CURRENT_VERSION) {
|
|
209
|
+
const sep = '═'.repeat(46);
|
|
210
|
+
const changes = CHANGELOG[latest] || ['Melhorias e correções'];
|
|
211
|
+
const lines = [
|
|
212
|
+
`╔${sep}╗`,
|
|
213
|
+
`║ 🆕 VibeTachyon ${latest} disponível!${' '.repeat(Math.max(0, 46 - 18 - latest.length - 1))}║`,
|
|
214
|
+
`╠${sep}╣`,
|
|
215
|
+
...changes.map(c => `║ ✦ ${c.slice(0, 42).padEnd(42)} ║`),
|
|
216
|
+
`╠${sep}╣`,
|
|
217
|
+
`║ Execute: npm i -g vibetachyon@latest${' '.repeat(8)}║`,
|
|
218
|
+
`╚${sep}╝`,
|
|
219
|
+
];
|
|
220
|
+
console.error(lines.join('\n'));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// Silently ignore update check failures
|
|
225
|
+
}
|
|
172
226
|
}
|
|
173
227
|
async function startMcpServer() {
|
|
174
228
|
await validateTokenAtStartup();
|
|
175
229
|
const server = new mcp_js_1.McpServer({
|
|
176
230
|
name: "VibeTachyon MCP — Animmaster Engine",
|
|
177
|
-
version: "1.
|
|
231
|
+
version: "1.8.0"
|
|
178
232
|
});
|
|
179
233
|
/**
|
|
180
234
|
* VIBETACHYON FRONTEND PERSONA — Senior Frontend Designer (Animmaster Engine)
|
|
@@ -548,6 +602,7 @@ async function startMcpServer() {
|
|
|
548
602
|
name: zod_1.z.string().describe("Animmaster component name (e.g. 'parallax', 'cursor', 'marquee', 'splittype', 'preloader', 'ripple')")
|
|
549
603
|
}, async ({ name }) => {
|
|
550
604
|
await checkSanity();
|
|
605
|
+
sessionStats.componentsLoaded++;
|
|
551
606
|
try {
|
|
552
607
|
const { data, error } = await supabase
|
|
553
608
|
.from('animmaster_components')
|
|
@@ -2068,6 +2123,7 @@ export default function VibePreviewPage() {
|
|
|
2068
2123
|
projectDir: zod_1.z.string().optional().describe("Absolute path to the project root")
|
|
2069
2124
|
}, async ({ title, goal, tasks = [], projectDir }) => {
|
|
2070
2125
|
await checkSanity();
|
|
2126
|
+
sessionStats.missionsStarted++;
|
|
2071
2127
|
const cwd = projectDir || process.cwd();
|
|
2072
2128
|
await ensureVtfDir(cwd, 'missions', 'tasks');
|
|
2073
2129
|
const missionId = `mission_${shortId()}`;
|
|
@@ -2164,6 +2220,7 @@ export default function VibePreviewPage() {
|
|
|
2164
2220
|
projectDir: zod_1.z.string().optional().describe("Absolute path to the project root")
|
|
2165
2221
|
}, async ({ missionId, summary, decisions = [], lessons = [], nextSteps = [], projectDir }) => {
|
|
2166
2222
|
await checkSanity();
|
|
2223
|
+
sessionStats.missionsCompleted++;
|
|
2167
2224
|
const cwd = projectDir || process.cwd();
|
|
2168
2225
|
await ensureVtfDir(cwd, 'missions', 'debriefs');
|
|
2169
2226
|
const missionsDir = vtfPath(cwd, 'missions');
|
|
@@ -4386,6 +4443,7 @@ ${consequences.length > 0 ? consequences.map(c => `- ${c}`).join('\n') : '- (non
|
|
|
4386
4443
|
section.completedAt = new Date().toISOString();
|
|
4387
4444
|
await fs_extra_1.default.writeJson(statePath, state, { spaces: 2 });
|
|
4388
4445
|
}
|
|
4446
|
+
sessionStats.sectionsBuilt++;
|
|
4389
4447
|
const done = state.sections?.filter((s) => s.status === 'done') || [];
|
|
4390
4448
|
const planned = state.sections?.filter((s) => s.status === 'planned') || [];
|
|
4391
4449
|
const next = planned[0];
|
|
@@ -4402,6 +4460,96 @@ ${consequences.length > 0 ? consequences.map(c => `- ${c}`).join('\n') : '- (non
|
|
|
4402
4460
|
}]
|
|
4403
4461
|
};
|
|
4404
4462
|
});
|
|
4463
|
+
// ── Tool: Session Recap ───────────────────────────────────────────────────
|
|
4464
|
+
server.tool("vibe_session_recap", "Show a complete summary of everything accomplished in this session — duration, components loaded, errors fixed, sections built, missions completed. Call this at the end of any work session to review progress.", {
|
|
4465
|
+
projectDir: zod_1.z.string().optional().describe("Absolute path to the project root. If omitted, uses current working directory.")
|
|
4466
|
+
}, async ({ projectDir }) => {
|
|
4467
|
+
await checkSanity();
|
|
4468
|
+
const cwd = projectDir || process.cwd();
|
|
4469
|
+
const root = await findProjectRoot(cwd);
|
|
4470
|
+
// Duration
|
|
4471
|
+
const elapsedMs = Date.now() - SESSION_START;
|
|
4472
|
+
const minutes = Math.floor(elapsedMs / 60000);
|
|
4473
|
+
const seconds = Math.floor((elapsedMs % 60000) / 1000);
|
|
4474
|
+
const duration = minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
|
|
4475
|
+
// Count git-changed files
|
|
4476
|
+
let filesChanged = 0;
|
|
4477
|
+
try {
|
|
4478
|
+
const { stdout } = await execPromise('git status --porcelain 2>/dev/null | wc -l', { cwd: root });
|
|
4479
|
+
filesChanged = parseInt(stdout.trim()) || 0;
|
|
4480
|
+
}
|
|
4481
|
+
catch { /* not a git repo */ }
|
|
4482
|
+
// Count tasks completed in .vibetachyon
|
|
4483
|
+
let tasksCompleted = 0;
|
|
4484
|
+
let missionsActive = 0;
|
|
4485
|
+
const tasksDir = path_1.default.join(root, '.vibetachyon', 'tasks');
|
|
4486
|
+
const missionsDir = path_1.default.join(root, '.vibetachyon', 'missions');
|
|
4487
|
+
try {
|
|
4488
|
+
if (await fs_extra_1.default.pathExists(tasksDir)) {
|
|
4489
|
+
const taskFiles = await fs_extra_1.default.readdir(tasksDir);
|
|
4490
|
+
for (const f of taskFiles) {
|
|
4491
|
+
if (!f.endsWith('.json'))
|
|
4492
|
+
continue;
|
|
4493
|
+
const t = await fs_extra_1.default.readJson(path_1.default.join(tasksDir, f));
|
|
4494
|
+
if (t.status === 'done')
|
|
4495
|
+
tasksCompleted++;
|
|
4496
|
+
}
|
|
4497
|
+
}
|
|
4498
|
+
if (await fs_extra_1.default.pathExists(missionsDir)) {
|
|
4499
|
+
const missionFiles = await fs_extra_1.default.readdir(missionsDir);
|
|
4500
|
+
for (const f of missionFiles) {
|
|
4501
|
+
if (!f.endsWith('.json'))
|
|
4502
|
+
continue;
|
|
4503
|
+
const m = await fs_extra_1.default.readJson(path_1.default.join(missionsDir, f));
|
|
4504
|
+
if (m.status === 'active')
|
|
4505
|
+
missionsActive++;
|
|
4506
|
+
if (m.status === 'completed')
|
|
4507
|
+
sessionStats.missionsCompleted++;
|
|
4508
|
+
}
|
|
4509
|
+
}
|
|
4510
|
+
}
|
|
4511
|
+
catch { /* ignore */ }
|
|
4512
|
+
const sep = '═'.repeat(48);
|
|
4513
|
+
const row = (label, value) => {
|
|
4514
|
+
const line = ` ${label}: ${value}`;
|
|
4515
|
+
return `║${line.padEnd(49)}║`;
|
|
4516
|
+
};
|
|
4517
|
+
// Score — simple quality heuristic
|
|
4518
|
+
const score = Math.min(100, 20 + // base
|
|
4519
|
+
(sessionStats.componentsLoaded > 0 ? 20 : 0) +
|
|
4520
|
+
(sessionStats.sectionsBuilt > 0 ? 20 : 0) +
|
|
4521
|
+
(tasksCompleted > 0 ? 20 : 0) +
|
|
4522
|
+
(sessionStats.tsErrorsFixed > 0 ? 10 : 0) +
|
|
4523
|
+
(filesChanged > 0 ? 10 : 0));
|
|
4524
|
+
const grade = score >= 90 ? 'S' : score >= 75 ? 'A' : score >= 60 ? 'B' : score >= 40 ? 'C' : 'D';
|
|
4525
|
+
const gradeEmoji = grade === 'S' ? '🏆' : grade === 'A' ? '🥇' : grade === 'B' ? '🥈' : '🥉';
|
|
4526
|
+
const lines = [
|
|
4527
|
+
`╔${sep}╗`,
|
|
4528
|
+
`║ ${gradeEmoji} VIBETACHYON SESSION RECAP${' '.repeat(20)}║`,
|
|
4529
|
+
`╠${sep}╣`,
|
|
4530
|
+
row('⏱ Duração', duration),
|
|
4531
|
+
row('📄 Arquivos alterados', filesChanged),
|
|
4532
|
+
row('🧩 Componentes carregados', sessionStats.componentsLoaded),
|
|
4533
|
+
row('🏗️ Seções construídas', sessionStats.sectionsBuilt),
|
|
4534
|
+
row('✅ Tasks concluídas', tasksCompleted),
|
|
4535
|
+
row('🎯 Missões ativas', missionsActive),
|
|
4536
|
+
row('🔧 Erros TS corrigidos', sessionStats.tsErrorsFixed),
|
|
4537
|
+
row('📦 Deps instaladas', sessionStats.depsInstalled),
|
|
4538
|
+
row('🔁 Tools chamados', sessionCallCount),
|
|
4539
|
+
`╠${sep}╣`,
|
|
4540
|
+
`║ NOTA DA SESSÃO: ${grade} (${score}/100)${' '.repeat(Math.max(0, 48 - 20 - grade.length - String(score).length))}║`,
|
|
4541
|
+
`╚${sep}╝`,
|
|
4542
|
+
];
|
|
4543
|
+
if (score < 60) {
|
|
4544
|
+
lines.push('');
|
|
4545
|
+
lines.push('💡 Dica: use vibe_launchpad antes de começar e vibe_section_done após cada seção.');
|
|
4546
|
+
}
|
|
4547
|
+
else if (score >= 90) {
|
|
4548
|
+
lines.push('');
|
|
4549
|
+
lines.push('🔥 Sessão excepcional. Considera fazer commit com vibe_git_smart_commit.');
|
|
4550
|
+
}
|
|
4551
|
+
return { content: [{ type: "text", text: lines.join('\n') }] };
|
|
4552
|
+
});
|
|
4405
4553
|
// Connect via stdio
|
|
4406
4554
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
4407
4555
|
await server.connect(transport);
|