@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.
Files changed (47) hide show
  1. package/README.md +60 -33
  2. package/bin/registry.js +319 -34
  3. package/bin/runners/CLI_REFACTOR_SUMMARY.md +229 -0
  4. package/bin/runners/REPORT_AUDIT.md +64 -0
  5. package/bin/runners/lib/entitlements-v2.js +97 -28
  6. package/bin/runners/lib/entitlements.js +3 -6
  7. package/bin/runners/lib/init-wizard.js +1 -1
  8. package/bin/runners/lib/report-engine.js +459 -280
  9. package/bin/runners/lib/report-html.js +1154 -1423
  10. package/bin/runners/lib/report-output.js +187 -0
  11. package/bin/runners/lib/report-templates.js +848 -850
  12. package/bin/runners/lib/scan-output.js +545 -0
  13. package/bin/runners/lib/server-usage.js +0 -12
  14. package/bin/runners/lib/ship-output.js +641 -0
  15. package/bin/runners/lib/status-output.js +253 -0
  16. package/bin/runners/lib/terminal-ui.js +853 -0
  17. package/bin/runners/runCheckpoint.js +502 -0
  18. package/bin/runners/runContracts.js +105 -0
  19. package/bin/runners/runExport.js +93 -0
  20. package/bin/runners/runFix.js +31 -24
  21. package/bin/runners/runInit.js +377 -112
  22. package/bin/runners/runInstall.js +1 -5
  23. package/bin/runners/runLabs.js +3 -3
  24. package/bin/runners/runPolish.js +2452 -0
  25. package/bin/runners/runProve.js +2 -2
  26. package/bin/runners/runReport.js +251 -200
  27. package/bin/runners/runRuntime.js +110 -0
  28. package/bin/runners/runScan.js +477 -379
  29. package/bin/runners/runSecurity.js +92 -0
  30. package/bin/runners/runShip.js +137 -207
  31. package/bin/runners/runStatus.js +16 -68
  32. package/bin/runners/utils.js +5 -5
  33. package/bin/vibecheck.js +25 -11
  34. package/mcp-server/index.js +150 -18
  35. package/mcp-server/package.json +2 -2
  36. package/mcp-server/premium-tools.js +13 -13
  37. package/mcp-server/tier-auth.js +292 -27
  38. package/mcp-server/vibecheck-tools.js +9 -9
  39. package/package.json +1 -1
  40. package/bin/runners/runClaimVerifier.js +0 -483
  41. package/bin/runners/runContextCompiler.js +0 -385
  42. package/bin/runners/runGate.js +0 -17
  43. package/bin/runners/runInitGha.js +0 -164
  44. package/bin/runners/runInteractive.js +0 -388
  45. package/bin/runners/runMdc.js +0 -204
  46. package/bin/runners/runMissionGenerator.js +0 -282
  47. 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 = `[![Vibecheck](${badgeUrl})](${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 };
@@ -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 };