@vibecheckai/cli 3.1.2 → 3.1.4
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/README.md +60 -33
- package/bin/registry.js +319 -34
- package/bin/runners/CLI_REFACTOR_SUMMARY.md +229 -0
- package/bin/runners/REPORT_AUDIT.md +64 -0
- package/bin/runners/lib/entitlements-v2.js +97 -28
- package/bin/runners/lib/entitlements.js +3 -6
- package/bin/runners/lib/init-wizard.js +1 -1
- package/bin/runners/lib/report-engine.js +459 -280
- package/bin/runners/lib/report-html.js +1154 -1423
- package/bin/runners/lib/report-output.js +187 -0
- package/bin/runners/lib/report-templates.js +848 -850
- package/bin/runners/lib/scan-output.js +545 -0
- package/bin/runners/lib/server-usage.js +0 -12
- package/bin/runners/lib/ship-output.js +641 -0
- package/bin/runners/lib/status-output.js +253 -0
- package/bin/runners/lib/terminal-ui.js +853 -0
- package/bin/runners/runCheckpoint.js +502 -0
- package/bin/runners/runContracts.js +105 -0
- package/bin/runners/runExport.js +93 -0
- package/bin/runners/runFix.js +31 -24
- package/bin/runners/runInit.js +377 -112
- package/bin/runners/runInstall.js +1 -5
- package/bin/runners/runLabs.js +3 -3
- package/bin/runners/runPolish.js +2452 -0
- package/bin/runners/runProve.js +2 -2
- package/bin/runners/runReport.js +251 -200
- package/bin/runners/runRuntime.js +110 -0
- package/bin/runners/runScan.js +477 -379
- package/bin/runners/runSecurity.js +92 -0
- package/bin/runners/runShip.js +137 -207
- package/bin/runners/runStatus.js +16 -68
- package/bin/runners/utils.js +5 -5
- package/bin/vibecheck.js +25 -11
- package/mcp-server/index.js +150 -18
- package/mcp-server/package.json +2 -2
- package/mcp-server/premium-tools.js +13 -13
- package/mcp-server/tier-auth.js +292 -27
- package/mcp-server/vibecheck-tools.js +9 -9
- package/package.json +1 -1
- package/bin/runners/runClaimVerifier.js +0 -483
- package/bin/runners/runContextCompiler.js +0 -385
- package/bin/runners/runGate.js +0 -17
- package/bin/runners/runInitGha.js +0 -164
- package/bin/runners/runInteractive.js +0 -388
- package/bin/runners/runMdc.js +0 -204
- package/bin/runners/runMissionGenerator.js +0 -282
- package/bin/runners/runTruthpack.js +0 -636
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vibecheck Interactive Mode
|
|
3
|
-
*
|
|
4
|
-
* Beautiful interactive CLI experience with menus, tables, and visual feedback.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const path = require("path");
|
|
8
|
-
const fs = require("fs");
|
|
9
|
-
const readline = require("readline");
|
|
10
|
-
|
|
11
|
-
const {
|
|
12
|
-
c,
|
|
13
|
-
createHeader,
|
|
14
|
-
createTable,
|
|
15
|
-
createProgressBar,
|
|
16
|
-
createScoreCard,
|
|
17
|
-
createMenu,
|
|
18
|
-
createSpinner,
|
|
19
|
-
createVerdictDisplay,
|
|
20
|
-
createBadgeDisplay,
|
|
21
|
-
divider,
|
|
22
|
-
sectionHeader,
|
|
23
|
-
} = require("./lib/cli-ui");
|
|
24
|
-
|
|
25
|
-
// ASCII Art Logo
|
|
26
|
-
const LOGO = `
|
|
27
|
-
${c.cyan}${c.bold}
|
|
28
|
-
██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗
|
|
29
|
-
██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝
|
|
30
|
-
██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝
|
|
31
|
-
╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗
|
|
32
|
-
╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗
|
|
33
|
-
╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝
|
|
34
|
-
${c.reset}
|
|
35
|
-
${c.dim} Proof-of-Working for AI-built apps${c.reset}
|
|
36
|
-
`;
|
|
37
|
-
|
|
38
|
-
const WELCOME_MESSAGE = `
|
|
39
|
-
${c.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${c.reset}
|
|
40
|
-
${c.bold} Welcome to Vibecheck Interactive Mode${c.reset}
|
|
41
|
-
${c.dim} Navigate with numbers. Get ship verdicts, fix issues, verify runtime.${c.reset}
|
|
42
|
-
${c.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${c.reset}
|
|
43
|
-
`;
|
|
44
|
-
|
|
45
|
-
const MAIN_MENU_OPTIONS = [
|
|
46
|
-
{
|
|
47
|
-
key: "ship",
|
|
48
|
-
label: "Ship Check",
|
|
49
|
-
icon: "🚀",
|
|
50
|
-
description: "Get a ship verdict: SHIP | WARN | BLOCK",
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
key: "fix",
|
|
54
|
-
label: "Fix Issues",
|
|
55
|
-
icon: "🔧",
|
|
56
|
-
description: "Run safe mechanical fixes with patch preview",
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
key: "verify",
|
|
60
|
-
label: "Runtime Verify",
|
|
61
|
-
icon: "🔍",
|
|
62
|
-
description: "Playwright-powered runtime proof",
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
key: "report",
|
|
66
|
-
label: "Generate Report",
|
|
67
|
-
icon: "📄",
|
|
68
|
-
description: "Professional client reports (Executive/Technical/Compliance)",
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
key: "badge",
|
|
72
|
-
label: "Ship Badge",
|
|
73
|
-
icon: "🏆",
|
|
74
|
-
description: "Generate beautiful embeddable badge for README",
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
key: "history",
|
|
78
|
-
label: "Score History",
|
|
79
|
-
icon: "📊",
|
|
80
|
-
description: "View score trends and streaks",
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
key: "doctor",
|
|
84
|
-
label: "Doctor",
|
|
85
|
-
icon: "🩺",
|
|
86
|
-
description: "Environment sanity check",
|
|
87
|
-
},
|
|
88
|
-
];
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Clear screen and show logo
|
|
92
|
-
*/
|
|
93
|
-
function showLogo() {
|
|
94
|
-
console.clear();
|
|
95
|
-
console.log(LOGO);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Show welcome screen
|
|
100
|
-
*/
|
|
101
|
-
function showWelcome() {
|
|
102
|
-
showLogo();
|
|
103
|
-
console.log(WELCOME_MESSAGE);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Create input prompt
|
|
108
|
-
*/
|
|
109
|
-
function prompt(question) {
|
|
110
|
-
return new Promise((resolve) => {
|
|
111
|
-
const rl = readline.createInterface({
|
|
112
|
-
input: process.stdin,
|
|
113
|
-
output: process.stdout,
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
rl.question(question, (answer) => {
|
|
117
|
-
rl.close();
|
|
118
|
-
resolve(answer.trim());
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Show main menu
|
|
125
|
-
*/
|
|
126
|
-
async function showMainMenu() {
|
|
127
|
-
console.log("");
|
|
128
|
-
console.log(`${c.bold}${c.cyan}┌─────────────────────────────────────┐${c.reset}`);
|
|
129
|
-
console.log(`${c.bold}${c.cyan}│${c.reset} ${c.bold}MAIN MENU${c.reset} ${c.bold}${c.cyan}│${c.reset}`);
|
|
130
|
-
console.log(`${c.bold}${c.cyan}└─────────────────────────────────────┘${c.reset}`);
|
|
131
|
-
console.log("");
|
|
132
|
-
|
|
133
|
-
MAIN_MENU_OPTIONS.forEach((opt, i) => {
|
|
134
|
-
const num = `${i + 1}`.padStart(2);
|
|
135
|
-
console.log(` ${c.cyan}${num}${c.reset} ${opt.icon} ${c.bold}${opt.label}${c.reset}`);
|
|
136
|
-
console.log(` ${c.dim}${opt.description}${c.reset}`);
|
|
137
|
-
console.log("");
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
console.log(` ${c.dim} 0 Exit${c.reset}`);
|
|
141
|
-
console.log("");
|
|
142
|
-
console.log(divider(50));
|
|
143
|
-
|
|
144
|
-
const choice = await prompt(` ${c.cyan}›${c.reset} Select option: `);
|
|
145
|
-
return parseInt(choice, 10);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Run ship check with beautiful output
|
|
150
|
-
*/
|
|
151
|
-
async function runShipInteractive(projectPath) {
|
|
152
|
-
console.log("");
|
|
153
|
-
console.log(sectionHeader("Ship Check", "🚀"));
|
|
154
|
-
console.log("");
|
|
155
|
-
|
|
156
|
-
const spinner = createSpinner("Analyzing your codebase...", "dots").start();
|
|
157
|
-
|
|
158
|
-
// Simulate analysis steps
|
|
159
|
-
await sleep(800);
|
|
160
|
-
spinner.update("Checking for exposed secrets...");
|
|
161
|
-
await sleep(600);
|
|
162
|
-
spinner.update("Analyzing authentication coverage...");
|
|
163
|
-
await sleep(600);
|
|
164
|
-
spinner.update("Detecting mock/demo code...");
|
|
165
|
-
await sleep(600);
|
|
166
|
-
spinner.update("Verifying route integrity...");
|
|
167
|
-
await sleep(500);
|
|
168
|
-
spinner.success("Analysis complete!");
|
|
169
|
-
|
|
170
|
-
// Run actual ship check
|
|
171
|
-
try {
|
|
172
|
-
const { runShip } = require("./runShip");
|
|
173
|
-
return await runShip(["--path", projectPath]);
|
|
174
|
-
} catch (err) {
|
|
175
|
-
console.error(`${c.red}Error: ${err.message}${c.reset}`);
|
|
176
|
-
return 1;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Show badge generation with stunning display
|
|
182
|
-
*/
|
|
183
|
-
async function runBadgeInteractive(projectPath) {
|
|
184
|
-
console.log("");
|
|
185
|
-
console.log(sectionHeader("Ship Badge Generator", "🏆"));
|
|
186
|
-
console.log("");
|
|
187
|
-
|
|
188
|
-
const spinner = createSpinner("Generating your ship badge...", "star").start();
|
|
189
|
-
await sleep(1500);
|
|
190
|
-
|
|
191
|
-
// Get latest scan results
|
|
192
|
-
const outputDir = path.join(projectPath, ".vibecheck");
|
|
193
|
-
const reportPath = path.join(outputDir, "report.json");
|
|
194
|
-
|
|
195
|
-
let score = 85;
|
|
196
|
-
let verdict = "SHIP";
|
|
197
|
-
|
|
198
|
-
if (fs.existsSync(reportPath)) {
|
|
199
|
-
try {
|
|
200
|
-
const report = JSON.parse(fs.readFileSync(reportPath, "utf8"));
|
|
201
|
-
score = report.score || 85;
|
|
202
|
-
verdict = report.canShip ? "SHIP" : (score >= 50 ? "WARN" : "BLOCK");
|
|
203
|
-
} catch {}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
spinner.success("Badge generated!");
|
|
207
|
-
|
|
208
|
-
const projectName = path.basename(projectPath);
|
|
209
|
-
const projectId = projectName.toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
210
|
-
|
|
211
|
-
// Show the stunning badge
|
|
212
|
-
console.log(createBadgeDisplay(projectId, score, verdict));
|
|
213
|
-
|
|
214
|
-
// Show embed codes
|
|
215
|
-
const badgeUrl = `https://vibecheck.dev/badge/${projectId}.svg`;
|
|
216
|
-
const reportUrl = `https://vibecheck.dev/report/${projectId}`;
|
|
217
|
-
const markdown = `[](${reportUrl})`;
|
|
218
|
-
|
|
219
|
-
console.log("");
|
|
220
|
-
console.log(`${c.bold}${c.cyan}┌─ Embed Codes ─────────────────────────────────────────────────────┐${c.reset}`);
|
|
221
|
-
console.log(`${c.cyan}│${c.reset}`);
|
|
222
|
-
console.log(`${c.cyan}│${c.reset} ${c.dim}Badge URL:${c.reset}`);
|
|
223
|
-
console.log(`${c.cyan}│${c.reset} ${c.green}${badgeUrl}${c.reset}`);
|
|
224
|
-
console.log(`${c.cyan}│${c.reset}`);
|
|
225
|
-
console.log(`${c.cyan}│${c.reset} ${c.dim}Markdown (for README):${c.reset}`);
|
|
226
|
-
console.log(`${c.cyan}│${c.reset} ${c.yellow}${markdown}${c.reset}`);
|
|
227
|
-
console.log(`${c.cyan}│${c.reset}`);
|
|
228
|
-
console.log(`${c.cyan}│${c.reset} ${c.dim}Report URL:${c.reset}`);
|
|
229
|
-
console.log(`${c.cyan}│${c.reset} ${c.blue}${reportUrl}${c.reset}`);
|
|
230
|
-
console.log(`${c.cyan}│${c.reset}`);
|
|
231
|
-
console.log(`${c.bold}${c.cyan}└───────────────────────────────────────────────────────────────────┘${c.reset}`);
|
|
232
|
-
console.log("");
|
|
233
|
-
|
|
234
|
-
// Save badge info
|
|
235
|
-
try {
|
|
236
|
-
if (!fs.existsSync(outputDir)) {
|
|
237
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
238
|
-
}
|
|
239
|
-
fs.writeFileSync(
|
|
240
|
-
path.join(outputDir, "badge.json"),
|
|
241
|
-
JSON.stringify({ projectId, score, verdict, badgeUrl, reportUrl, markdown, generatedAt: new Date().toISOString() }, null, 2)
|
|
242
|
-
);
|
|
243
|
-
} catch {}
|
|
244
|
-
|
|
245
|
-
return 0;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Show score history with trends
|
|
250
|
-
*/
|
|
251
|
-
async function showHistoryInteractive(projectPath) {
|
|
252
|
-
console.log("");
|
|
253
|
-
console.log(sectionHeader("Score History", "📊"));
|
|
254
|
-
console.log("");
|
|
255
|
-
|
|
256
|
-
try {
|
|
257
|
-
const { formatHistoryDisplay } = require("./lib/score-history");
|
|
258
|
-
console.log(formatHistoryDisplay(projectPath));
|
|
259
|
-
} catch {
|
|
260
|
-
console.log(`${c.dim}No history available. Run \`vibecheck ship\` to start tracking.${c.reset}`);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
return 0;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Run doctor with beautiful output
|
|
268
|
-
*/
|
|
269
|
-
async function runDoctorInteractive(projectPath) {
|
|
270
|
-
console.log("");
|
|
271
|
-
console.log(sectionHeader("Environment Doctor", "🩺"));
|
|
272
|
-
console.log("");
|
|
273
|
-
|
|
274
|
-
try {
|
|
275
|
-
const { runDoctor } = require("./runDoctor");
|
|
276
|
-
return await runDoctor(["--path", projectPath]);
|
|
277
|
-
} catch (err) {
|
|
278
|
-
console.error(`${c.red}Error: ${err.message}${c.reset}`);
|
|
279
|
-
return 1;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Run report generator
|
|
285
|
-
*/
|
|
286
|
-
async function runReportInteractive(projectPath) {
|
|
287
|
-
console.log("");
|
|
288
|
-
console.log(sectionHeader("Report Generator", "📄"));
|
|
289
|
-
console.log("");
|
|
290
|
-
|
|
291
|
-
console.log(" Select report type:");
|
|
292
|
-
console.log("");
|
|
293
|
-
console.log(` ${c.cyan}1${c.reset} 📋 ${c.bold}Executive Summary${c.reset}`);
|
|
294
|
-
console.log(` ${c.dim}One-page overview for stakeholders${c.reset}`);
|
|
295
|
-
console.log("");
|
|
296
|
-
console.log(` ${c.cyan}2${c.reset} 🔬 ${c.bold}Technical Report${c.reset}`);
|
|
297
|
-
console.log(` ${c.dim}Detailed findings for developers${c.reset}`);
|
|
298
|
-
console.log("");
|
|
299
|
-
console.log(` ${c.cyan}3${c.reset} 🔒 ${c.bold}Compliance Report${c.reset}`);
|
|
300
|
-
console.log(` ${c.dim}SOC2-adjacent language${c.reset}`);
|
|
301
|
-
console.log("");
|
|
302
|
-
|
|
303
|
-
const choice = await prompt(` ${c.cyan}›${c.reset} Select type: `);
|
|
304
|
-
const types = ["executive", "technical", "compliance"];
|
|
305
|
-
const type = types[parseInt(choice, 10) - 1] || "executive";
|
|
306
|
-
|
|
307
|
-
try {
|
|
308
|
-
const { runReport } = require("./runReport");
|
|
309
|
-
return await runReport(["--type", type, "--path", projectPath]);
|
|
310
|
-
} catch (err) {
|
|
311
|
-
console.error(`${c.red}Error: ${err.message}${c.reset}`);
|
|
312
|
-
return 1;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Sleep utility
|
|
318
|
-
*/
|
|
319
|
-
function sleep(ms) {
|
|
320
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Main interactive loop
|
|
325
|
-
*/
|
|
326
|
-
async function runInteractive(args) {
|
|
327
|
-
const projectPath = path.resolve(args[0] || ".");
|
|
328
|
-
|
|
329
|
-
showWelcome();
|
|
330
|
-
|
|
331
|
-
let running = true;
|
|
332
|
-
|
|
333
|
-
while (running) {
|
|
334
|
-
const choice = await showMainMenu();
|
|
335
|
-
|
|
336
|
-
switch (choice) {
|
|
337
|
-
case 1: // Ship
|
|
338
|
-
await runShipInteractive(projectPath);
|
|
339
|
-
break;
|
|
340
|
-
case 2: // Fix
|
|
341
|
-
console.log("");
|
|
342
|
-
console.log(sectionHeader("Fix Issues", "🔧"));
|
|
343
|
-
const { runFix } = require("./runFix");
|
|
344
|
-
await runFix(["--path", projectPath]);
|
|
345
|
-
break;
|
|
346
|
-
case 3: // Verify
|
|
347
|
-
console.log("");
|
|
348
|
-
console.log(sectionHeader("Runtime Verify", "🔍"));
|
|
349
|
-
console.log(`${c.dim}Provide a URL to verify:${c.reset}`);
|
|
350
|
-
const url = await prompt(` ${c.cyan}URL:${c.reset} `);
|
|
351
|
-
if (url) {
|
|
352
|
-
const { runReality } = require("./runReality");
|
|
353
|
-
await runReality(["--url", url]);
|
|
354
|
-
}
|
|
355
|
-
break;
|
|
356
|
-
case 4: // Report
|
|
357
|
-
await runReportInteractive(projectPath);
|
|
358
|
-
break;
|
|
359
|
-
case 5: // Badge
|
|
360
|
-
await runBadgeInteractive(projectPath);
|
|
361
|
-
break;
|
|
362
|
-
case 6: // History
|
|
363
|
-
await showHistoryInteractive(projectPath);
|
|
364
|
-
break;
|
|
365
|
-
case 7: // Doctor
|
|
366
|
-
await runDoctorInteractive(projectPath);
|
|
367
|
-
break;
|
|
368
|
-
case 0:
|
|
369
|
-
running = false;
|
|
370
|
-
console.log("");
|
|
371
|
-
console.log(`${c.dim} Goodbye! Happy shipping. 🚀${c.reset}`);
|
|
372
|
-
console.log("");
|
|
373
|
-
break;
|
|
374
|
-
default:
|
|
375
|
-
console.log(`${c.yellow} Invalid option. Try again.${c.reset}`);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
if (running && choice !== 0) {
|
|
379
|
-
console.log("");
|
|
380
|
-
await prompt(` ${c.dim}Press Enter to continue...${c.reset}`);
|
|
381
|
-
showLogo();
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
return 0;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
module.exports = { runInteractive };
|
package/bin/runners/runMdc.js
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vibecheck mdc - Generate MDC (Markdown Context) documentation
|
|
3
|
-
*
|
|
4
|
-
* Generates .mdc specification files for AI coding agents.
|
|
5
|
-
* These files help AI understand your codebase architecture.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const path = require("path");
|
|
9
|
-
const fs = require("fs");
|
|
10
|
-
|
|
11
|
-
// ANSI colors
|
|
12
|
-
const c = {
|
|
13
|
-
reset: "\x1b[0m",
|
|
14
|
-
dim: "\x1b[2m",
|
|
15
|
-
bold: "\x1b[1m",
|
|
16
|
-
cyan: "\x1b[36m",
|
|
17
|
-
green: "\x1b[32m",
|
|
18
|
-
yellow: "\x1b[33m",
|
|
19
|
-
red: "\x1b[31m",
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function printHelp() {
|
|
23
|
-
console.log(`
|
|
24
|
-
${c.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${c.reset}
|
|
25
|
-
${c.bold}vibecheck mdc${c.reset} - Generate MDC Specifications
|
|
26
|
-
${c.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${c.reset}
|
|
27
|
-
|
|
28
|
-
${c.green}USAGE${c.reset}
|
|
29
|
-
vibecheck mdc [options]
|
|
30
|
-
|
|
31
|
-
${c.yellow}OPTIONS${c.reset}
|
|
32
|
-
--output, -o <dir> Output directory (default: .specs)
|
|
33
|
-
--categories <list> Categories: architecture,security,data-flow,design-system
|
|
34
|
-
--depth <level> Analysis depth: shallow, medium, deep (default: medium)
|
|
35
|
-
--min-score <n> Minimum importance score 0-100 (default: 70)
|
|
36
|
-
--no-examples Skip code examples
|
|
37
|
-
--json Output JSON instead of MDC files
|
|
38
|
-
|
|
39
|
-
${c.dim}EXAMPLE${c.reset}
|
|
40
|
-
vibecheck mdc --output .cursor/rules --categories architecture,security
|
|
41
|
-
|
|
42
|
-
${c.dim}MDC files help AI coding agents understand your codebase structure.${c.reset}
|
|
43
|
-
`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async function runMdc(args = []) {
|
|
47
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
48
|
-
printHelp();
|
|
49
|
-
return 0;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Parse arguments
|
|
53
|
-
const outputIdx = args.findIndex(a => a === "--output" || a === "-o");
|
|
54
|
-
const outputDir = outputIdx !== -1 ? args[outputIdx + 1] : ".specs";
|
|
55
|
-
|
|
56
|
-
const catIdx = args.findIndex(a => a === "--categories");
|
|
57
|
-
const categories = catIdx !== -1 ? args[catIdx + 1] : null;
|
|
58
|
-
|
|
59
|
-
const depthIdx = args.findIndex(a => a === "--depth");
|
|
60
|
-
const depth = depthIdx !== -1 ? args[depthIdx + 1] : "medium";
|
|
61
|
-
|
|
62
|
-
const minScoreIdx = args.findIndex(a => a === "--min-score");
|
|
63
|
-
const minScore = minScoreIdx !== -1 ? parseInt(args[minScoreIdx + 1]) : 70;
|
|
64
|
-
|
|
65
|
-
const noExamples = args.includes("--no-examples");
|
|
66
|
-
const jsonOutput = args.includes("--json");
|
|
67
|
-
|
|
68
|
-
console.log(`
|
|
69
|
-
${c.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${c.reset}
|
|
70
|
-
${c.bold}📄 VIBECHECK MDC${c.reset} - Generating Specifications
|
|
71
|
-
${c.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${c.reset}
|
|
72
|
-
`);
|
|
73
|
-
|
|
74
|
-
const repoRoot = process.cwd();
|
|
75
|
-
|
|
76
|
-
// Try to use the context module for MDC generation
|
|
77
|
-
try {
|
|
78
|
-
const { runContext } = require("./runContext");
|
|
79
|
-
|
|
80
|
-
// Build args for context command which can generate rules
|
|
81
|
-
const contextArgs = ["--output", outputDir];
|
|
82
|
-
if (categories) {
|
|
83
|
-
contextArgs.push("--categories", categories);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
console.log(`${c.dim}▸ Analyzing codebase...${c.reset}`);
|
|
87
|
-
|
|
88
|
-
// Generate context which includes MDC-compatible output
|
|
89
|
-
const exitCode = await runContext(contextArgs);
|
|
90
|
-
|
|
91
|
-
if (exitCode === 0) {
|
|
92
|
-
console.log(`
|
|
93
|
-
${c.green}✓${c.reset} MDC specifications generated in ${c.cyan}${outputDir}/${c.reset}
|
|
94
|
-
|
|
95
|
-
${c.dim}Generated files can be used with:${c.reset}
|
|
96
|
-
• Cursor (.cursor/rules/)
|
|
97
|
-
• Windsurf (.windsurf/rules/)
|
|
98
|
-
• GitHub Copilot (.github/copilot-instructions.md)
|
|
99
|
-
• Claude (.claude/project-context.md)
|
|
100
|
-
`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return exitCode;
|
|
104
|
-
} catch (e) {
|
|
105
|
-
// Fallback: generate basic MDC from truthpack
|
|
106
|
-
console.log(`${c.dim}▸ Using basic MDC generation...${c.reset}`);
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
const truthpackPath = path.join(repoRoot, ".vibecheck", "truth", "truthpack.json");
|
|
110
|
-
|
|
111
|
-
if (!fs.existsSync(truthpackPath)) {
|
|
112
|
-
console.log(`${c.yellow}⚠${c.reset} No truthpack found. Run ${c.cyan}vibecheck ctx${c.reset} first.`);
|
|
113
|
-
return 1;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const truthpack = JSON.parse(fs.readFileSync(truthpackPath, "utf8"));
|
|
117
|
-
|
|
118
|
-
// Generate basic MDC content
|
|
119
|
-
const mdcContent = generateBasicMDC(truthpack, repoRoot);
|
|
120
|
-
|
|
121
|
-
// Ensure output directory exists
|
|
122
|
-
const fullOutputDir = path.join(repoRoot, outputDir);
|
|
123
|
-
if (!fs.existsSync(fullOutputDir)) {
|
|
124
|
-
fs.mkdirSync(fullOutputDir, { recursive: true });
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Write MDC file
|
|
128
|
-
const mdcPath = path.join(fullOutputDir, "architecture.mdc");
|
|
129
|
-
fs.writeFileSync(mdcPath, mdcContent, "utf8");
|
|
130
|
-
|
|
131
|
-
console.log(`${c.green}✓${c.reset} Generated ${c.cyan}${outputDir}/architecture.mdc${c.reset}`);
|
|
132
|
-
return 0;
|
|
133
|
-
} catch (err) {
|
|
134
|
-
console.error(`${c.red}✗${c.reset} MDC generation failed:`, err.message);
|
|
135
|
-
return 1;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function generateBasicMDC(truthpack, repoRoot) {
|
|
141
|
-
const routes = truthpack.routes?.server || [];
|
|
142
|
-
const env = truthpack.env?.vars || [];
|
|
143
|
-
const auth = truthpack.auth || {};
|
|
144
|
-
|
|
145
|
-
let content = `---
|
|
146
|
-
description: Auto-generated architecture context from vibecheck
|
|
147
|
-
globs: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"]
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
# Project Architecture
|
|
151
|
-
|
|
152
|
-
## API Routes (${routes.length} total)
|
|
153
|
-
|
|
154
|
-
`;
|
|
155
|
-
|
|
156
|
-
// Group routes by method
|
|
157
|
-
const byMethod = {};
|
|
158
|
-
routes.forEach(r => {
|
|
159
|
-
const method = r.method || "GET";
|
|
160
|
-
if (!byMethod[method]) byMethod[method] = [];
|
|
161
|
-
byMethod[method].push(r);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
for (const [method, rs] of Object.entries(byMethod)) {
|
|
165
|
-
content += `### ${method}\n`;
|
|
166
|
-
rs.slice(0, 10).forEach(r => {
|
|
167
|
-
content += `- \`${r.path}\`\n`;
|
|
168
|
-
});
|
|
169
|
-
if (rs.length > 10) {
|
|
170
|
-
content += `- ... and ${rs.length - 10} more\n`;
|
|
171
|
-
}
|
|
172
|
-
content += "\n";
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (env.length > 0) {
|
|
176
|
-
content += `## Environment Variables (${env.length} total)\n\n`;
|
|
177
|
-
env.slice(0, 15).forEach(e => {
|
|
178
|
-
content += `- \`${e.name}\` - ${e.required ? "required" : "optional"}\n`;
|
|
179
|
-
});
|
|
180
|
-
if (env.length > 15) {
|
|
181
|
-
content += `- ... and ${env.length - 15} more\n`;
|
|
182
|
-
}
|
|
183
|
-
content += "\n";
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (auth.nextMiddleware?.length > 0 || auth.fastify?.hooks?.length > 0) {
|
|
187
|
-
content += `## Authentication\n\n`;
|
|
188
|
-
if (auth.nextMiddleware?.length > 0) {
|
|
189
|
-
content += `- Next.js middleware: ${auth.nextMiddleware.length} rules\n`;
|
|
190
|
-
}
|
|
191
|
-
if (auth.fastify?.hooks?.length > 0) {
|
|
192
|
-
content += `- Fastify hooks: ${auth.fastify.hooks.length} hooks\n`;
|
|
193
|
-
}
|
|
194
|
-
content += "\n";
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
content += `---
|
|
198
|
-
*Generated by vibecheck on ${new Date().toISOString().split("T")[0]}*
|
|
199
|
-
`;
|
|
200
|
-
|
|
201
|
-
return content;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
module.exports = { runMdc };
|