@vibecheckai/cli 3.0.2 → 3.0.3

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 (68) hide show
  1. package/package.json +9 -1
  2. package/bin/cli-hygiene.js +0 -241
  3. package/bin/guardrail.js +0 -834
  4. package/bin/runners/cli-utils.js +0 -1070
  5. package/bin/runners/context/ai-task-decomposer.js +0 -337
  6. package/bin/runners/context/analyzer.js +0 -462
  7. package/bin/runners/context/api-contracts.js +0 -427
  8. package/bin/runners/context/context-diff.js +0 -342
  9. package/bin/runners/context/context-pruner.js +0 -291
  10. package/bin/runners/context/dependency-graph.js +0 -414
  11. package/bin/runners/context/generators/claude.js +0 -107
  12. package/bin/runners/context/generators/codex.js +0 -108
  13. package/bin/runners/context/generators/copilot.js +0 -119
  14. package/bin/runners/context/generators/cursor.js +0 -514
  15. package/bin/runners/context/generators/mcp.js +0 -151
  16. package/bin/runners/context/generators/windsurf.js +0 -180
  17. package/bin/runners/context/git-context.js +0 -302
  18. package/bin/runners/context/index.js +0 -1042
  19. package/bin/runners/context/insights.js +0 -173
  20. package/bin/runners/context/mcp-server/generate-rules.js +0 -337
  21. package/bin/runners/context/mcp-server/index.js +0 -1176
  22. package/bin/runners/context/mcp-server/package.json +0 -24
  23. package/bin/runners/context/memory.js +0 -200
  24. package/bin/runners/context/monorepo.js +0 -215
  25. package/bin/runners/context/multi-repo-federation.js +0 -404
  26. package/bin/runners/context/patterns.js +0 -253
  27. package/bin/runners/context/proof-context.js +0 -972
  28. package/bin/runners/context/security-scanner.js +0 -303
  29. package/bin/runners/context/semantic-search.js +0 -350
  30. package/bin/runners/context/shared.js +0 -264
  31. package/bin/runners/context/team-conventions.js +0 -310
  32. package/bin/runners/lib/ai-bridge.js +0 -416
  33. package/bin/runners/lib/analysis-core.js +0 -271
  34. package/bin/runners/lib/analyzers.js +0 -541
  35. package/bin/runners/lib/audit-bridge.js +0 -391
  36. package/bin/runners/lib/auth-truth.js +0 -193
  37. package/bin/runners/lib/auth.js +0 -215
  38. package/bin/runners/lib/backup.js +0 -62
  39. package/bin/runners/lib/billing.js +0 -107
  40. package/bin/runners/lib/claims.js +0 -118
  41. package/bin/runners/lib/cli-ui.js +0 -540
  42. package/bin/runners/lib/compliance-bridge-new.js +0 -0
  43. package/bin/runners/lib/compliance-bridge.js +0 -165
  44. package/bin/runners/lib/contracts/auth-contract.js +0 -194
  45. package/bin/runners/lib/contracts/env-contract.js +0 -178
  46. package/bin/runners/lib/contracts/external-contract.js +0 -198
  47. package/bin/runners/lib/contracts/guard.js +0 -168
  48. package/bin/runners/lib/contracts/index.js +0 -89
  49. package/bin/runners/lib/contracts/plan-validator.js +0 -311
  50. package/bin/runners/lib/contracts/route-contract.js +0 -192
  51. package/bin/runners/lib/detect.js +0 -89
  52. package/bin/runners/lib/doctor/autofix.js +0 -254
  53. package/bin/runners/lib/doctor/index.js +0 -37
  54. package/bin/runners/lib/doctor/modules/dependencies.js +0 -325
  55. package/bin/runners/lib/doctor/modules/index.js +0 -46
  56. package/bin/runners/lib/doctor/modules/network.js +0 -250
  57. package/bin/runners/lib/doctor/modules/project.js +0 -312
  58. package/bin/runners/lib/doctor/modules/runtime.js +0 -224
  59. package/bin/runners/lib/doctor/modules/security.js +0 -348
  60. package/bin/runners/lib/doctor/modules/system.js +0 -213
  61. package/bin/runners/lib/doctor/modules/vibecheck.js +0 -394
  62. package/bin/runners/lib/doctor/reporter.js +0 -262
  63. package/bin/runners/lib/doctor/service.js +0 -262
  64. package/bin/runners/lib/doctor/types.js +0 -113
  65. package/bin/runners/lib/doctor/ui.js +0 -263
  66. package/bin/runners/lib/doctor-enhanced.js +0 -233
  67. package/bin/runners/lib/doctor-v2.js +0 -608
  68. package/bin/runners/lib/enforcement.js +0 -72
@@ -1,414 +0,0 @@
1
- /**
2
- * Dependency Graph Visualization Module
3
- * Generates visual maps of component/module relationships
4
- */
5
-
6
- const fs = require("fs");
7
- const path = require("path");
8
-
9
- /**
10
- * Find files recursively (local helper)
11
- */
12
- function findFiles(dir, extensions, maxDepth = 5, currentDepth = 0) {
13
- if (currentDepth >= maxDepth || !fs.existsSync(dir)) return [];
14
-
15
- const files = [];
16
- try {
17
- const entries = fs.readdirSync(dir, { withFileTypes: true });
18
- for (const entry of entries) {
19
- const fullPath = path.join(dir, entry.name);
20
- if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
21
- files.push(...findFiles(fullPath, extensions, maxDepth, currentDepth + 1));
22
- } else if (entry.isFile() && extensions.some(ext => entry.name.endsWith(ext))) {
23
- files.push(fullPath);
24
- }
25
- }
26
- } catch {}
27
- return files;
28
- }
29
-
30
- /**
31
- * Extract imports from a file
32
- */
33
- function extractImports(filePath) {
34
- const imports = [];
35
- try {
36
- const content = fs.readFileSync(filePath, "utf-8");
37
- const relativePath = path.relative(process.cwd(), filePath).replace(/\\/g, "/");
38
-
39
- // Match import statements
40
- const importMatches = content.match(/import\s+.*?\s+from\s+['"]([^'"]+)['"]/g) || [];
41
-
42
- for (const match of importMatches) {
43
- const source = match.match(/from\s+['"]([^'"]+)['"]/)?.[1];
44
- if (source) {
45
- imports.push({
46
- from: relativePath,
47
- to: source,
48
- type: source.startsWith(".") ? "internal" : "external",
49
- });
50
- }
51
- }
52
- } catch {}
53
- return imports;
54
- }
55
-
56
- /**
57
- * Build dependency graph
58
- */
59
- function buildDependencyGraph(projectPath) {
60
- const graph = {
61
- nodes: new Map(),
62
- edges: [],
63
- stats: {
64
- totalFiles: 0,
65
- internalImports: 0,
66
- externalImports: 0,
67
- circularDeps: 0,
68
- },
69
- };
70
-
71
- const srcFiles = findFiles(projectPath, [".ts", ".tsx", ".js", ".jsx"], 5);
72
- graph.stats.totalFiles = srcFiles.length;
73
-
74
- // Extract all imports
75
- const allImports = [];
76
- for (const file of srcFiles) {
77
- const imports = extractImports(file);
78
- allImports.push(...imports);
79
- }
80
-
81
- // Build nodes
82
- for (const file of srcFiles) {
83
- const relativePath = path.relative(projectPath, file).replace(/\\/g, "/");
84
- const ext = path.extname(relativePath);
85
- const baseName = path.basename(relativePath, ext);
86
- const dir = path.dirname(relativePath);
87
-
88
- // Determine node type
89
- let type = "file";
90
- if (relativePath.includes("/components/") && /^[A-Z]/.test(baseName)) {
91
- type = "component";
92
- } else if (relativePath.includes("/hooks/") || baseName.startsWith("use")) {
93
- type = "hook";
94
- } else if (relativePath.includes("/api/") || relativePath.includes("/routes/")) {
95
- type = "api";
96
- } else if (relativePath.includes("/lib/") || relativePath.includes("/utils/")) {
97
- type = "utility";
98
- } else if (ext === ".json") {
99
- type = "config";
100
- }
101
-
102
- graph.nodes.set(relativePath, {
103
- id: relativePath,
104
- label: baseName,
105
- path: relativePath,
106
- type,
107
- imports: [],
108
- importedBy: [],
109
- });
110
- }
111
-
112
- // Build edges
113
- for (const imp of allImports) {
114
- if (imp.type === "internal") {
115
- // Resolve relative import
116
- const fromDir = path.dirname(imp.from);
117
- const toPath = path.resolve(fromDir, imp.to);
118
- const relativeToPath = path.relative(projectPath, toPath).replace(/\\/g, "/");
119
-
120
- // Try different file extensions
121
- let resolvedPath = relativeToPath;
122
- if (!graph.nodes.has(relativeToPath)) {
123
- for (const ext of [".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.js"]) {
124
- const withExt = relativeToPath + (relativeToPath.endsWith("/") ? ext.slice(1) : ext);
125
- if (graph.nodes.has(withExt)) {
126
- resolvedPath = withExt;
127
- break;
128
- }
129
- }
130
- }
131
-
132
- if (graph.nodes.has(resolvedPath)) {
133
- graph.edges.push({
134
- from: imp.from,
135
- to: resolvedPath,
136
- type: "internal",
137
- });
138
-
139
- // Update node references
140
- const fromNode = graph.nodes.get(imp.from);
141
- const toNode = graph.nodes.get(resolvedPath);
142
- if (fromNode) fromNode.imports.push(resolvedPath);
143
- if (toNode) toNode.importedBy.push(imp.from);
144
-
145
- graph.stats.internalImports++;
146
- }
147
- } else {
148
- graph.stats.externalImports++;
149
- }
150
- }
151
-
152
- // Detect circular dependencies
153
- const visited = new Set();
154
- const recursionStack = new Set();
155
-
156
- function detectCycle(node, path = []) {
157
- if (recursionStack.has(node)) {
158
- const cycleStart = path.indexOf(node);
159
- if (cycleStart > -1) {
160
- graph.stats.circularDeps++;
161
- return path.slice(cycleStart);
162
- }
163
- }
164
-
165
- if (visited.has(node)) return null;
166
-
167
- visited.add(node);
168
- recursionStack.add(node);
169
-
170
- const nodeData = graph.nodes.get(node);
171
- if (nodeData) {
172
- for (const importPath of nodeData.imports) {
173
- const cycle = detectCycle(importPath, [...path, node]);
174
- if (cycle) return cycle;
175
- }
176
- }
177
-
178
- recursionStack.delete(node);
179
- return null;
180
- }
181
-
182
- for (const nodeId of graph.nodes.keys()) {
183
- if (!visited.has(nodeId)) {
184
- detectCycle(nodeId);
185
- }
186
- }
187
-
188
- return graph;
189
- }
190
-
191
- /**
192
- * Generate Mermaid diagram from graph
193
- */
194
- function generateMermaidDiagram(graph, options = {}) {
195
- const { maxNodes = 50, includeExternal = false } = options;
196
-
197
- let diagram = "graph TD\n";
198
- diagram += " %% Generated by vibecheck Context v3.0\n\n";
199
-
200
- // Add nodes with styling
201
- const nodes = Array.from(graph.nodes.values()).slice(0, maxNodes);
202
- const nodeStyles = {
203
- component: "fill:#e1f5fe",
204
- hook: "fill:#f3e5f5",
205
- api: "fill:#ffebee",
206
- utility: "fill:#e8f5e9",
207
- config: "fill:#fff3e0",
208
- file: "fill:#f5f5f5",
209
- };
210
-
211
- for (const node of nodes) {
212
- const style = nodeStyles[node.type] || nodeStyles.file;
213
- diagram += ` ${node.id.replace(/[\/\.:]/g, "_")}["${node.label}"]:::${node.type}\n`;
214
- }
215
-
216
- // Add styles
217
- diagram += "\n classDef component fill:#e1f5fe,stroke:#0288d1\n";
218
- diagram += " classDef hook fill:#f3e5f5,stroke:#7b1fa2\n";
219
- diagram += " classDef api fill:#ffebee,stroke:#d32f2f\n";
220
- diagram += " classDef utility fill:#e8f5e9,stroke:#388e3c\n";
221
- diagram += " classDef config fill:#fff3e0,stroke:#f57c00\n";
222
- diagram += " classDef file fill:#f5f5f5,stroke:#616161\n\n";
223
-
224
- // Add edges
225
- const internalEdges = graph.edges.filter(e => e.type === "internal");
226
- const edgeCount = Math.min(internalEdges.length, 100);
227
-
228
- for (let i = 0; i < edgeCount; i++) {
229
- const edge = internalEdges[i];
230
- const fromId = edge.from.replace(/[\/\.:]/g, "_");
231
- const toId = edge.to.replace(/[\/\.:]/g, "_");
232
- diagram += ` ${fromId} --> ${toId}\n`;
233
- }
234
-
235
- // Add node classes
236
- for (const node of nodes) {
237
- diagram += ` class ${node.id.replace(/[\/\.:]/g, "_")} ${node.type}\n`;
238
- }
239
-
240
- return diagram;
241
- }
242
-
243
- /**
244
- * Generate DOT graph for Graphviz
245
- */
246
- function generateDotGraph(graph, options = {}) {
247
- const { maxNodes = 50 } = options;
248
-
249
- let dot = "digraph DependencyGraph {\n";
250
- dot += " // Generated by vibecheck Context v3.0\n";
251
- dot += " rankdir=LR;\n";
252
- dot += " node [shape=box, style=filled];\n\n";
253
-
254
- const nodes = Array.from(graph.nodes.values()).slice(0, maxNodes);
255
- const colors = {
256
- component: "#e1f5fe",
257
- hook: "#f3e5f5",
258
- api: "#ffebee",
259
- utility: "#e8f5e9",
260
- config: "#fff3e0",
261
- file: "#f5f5f5",
262
- };
263
-
264
- // Add nodes
265
- for (const node of nodes) {
266
- const color = colors[node.type] || colors.file;
267
- dot += ` "${node.id}" [label="${node.label}", fillcolor="${color}"];\n`;
268
- }
269
-
270
- // Add edges
271
- const internalEdges = graph.edges.filter(e => e.type === "internal");
272
- const edgeCount = Math.min(internalEdges.length, 100);
273
-
274
- for (let i = 0; i < edgeCount; i++) {
275
- const edge = internalEdges[i];
276
- dot += ` "${edge.from}" -> "${edge.to}";\n`;
277
- }
278
-
279
- dot += "}\n";
280
- return dot;
281
- }
282
-
283
- /**
284
- * Generate HTML visualization with D3.js
285
- */
286
- function generateHtmlVisualization(graph, options = {}) {
287
- const { maxNodes = 100 } = options;
288
-
289
- const nodes = Array.from(graph.nodes.values()).slice(0, maxNodes);
290
- const edges = graph.edges.filter(e => e.type === "internal").slice(0, 200);
291
-
292
- const html = `<!DOCTYPE html>
293
- <html>
294
- <head>
295
- <title>Dependency Graph - ${path.basename(process.cwd())}</title>
296
- <script src="https://d3js.org/d3.v7.min.js"></script>
297
- <style>
298
- body { font-family: Arial, sans-serif; margin: 20px; }
299
- .node { cursor: pointer; }
300
- .node circle { stroke: #333; stroke-width: 2px; }
301
- .node text { font-size: 12px; pointer-events: none; }
302
- .link { stroke: #999; stroke-opacity: 0.6; }
303
- .component { fill: #e1f5fe; }
304
- .hook { fill: #f3e5f5; }
305
- .api { fill: #ffebee; }
306
- .utility { fill: #e8f5e9; }
307
- .config { fill: #fff3e0; }
308
- .file { fill: #f5f5f5; }
309
- .stats { background: #f5f5f5; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
310
- </style>
311
- </head>
312
- <body>
313
- <h1>Dependency Graph Visualization</h1>
314
- <div class="stats">
315
- <strong>Stats:</strong>
316
- Files: ${graph.stats.totalFiles} |
317
- Internal Imports: ${graph.stats.internalImports} |
318
- External Imports: ${graph.stats.externalImports} |
319
- Circular Dependencies: ${graph.stats.circularDeps}
320
- </div>
321
- <svg width="1200" height="800"></svg>
322
-
323
- <script>
324
- const data = {
325
- nodes: ${JSON.stringify(nodes.map(n => ({
326
- id: n.id,
327
- label: n.label,
328
- type: n.type,
329
- imports: n.imports.length,
330
- importedBy: n.importedBy.length
331
- })))},
332
- links: ${JSON.stringify(edges.map(e => ({
333
- source: e.from,
334
- target: e.to
335
- })))}
336
- };
337
-
338
- const svg = d3.select("svg");
339
- const width = +svg.attr("width");
340
- const height = +svg.attr("height");
341
-
342
- const simulation = d3.forceSimulation(data.nodes)
343
- .force("link", d3.forceLink(data.links).id(d => d.id).distance(100))
344
- .force("charge", d3.forceManyBody().strength(-300))
345
- .force("center", d3.forceCenter(width / 2, height / 2));
346
-
347
- const link = svg.append("g")
348
- .selectAll("line")
349
- .data(data.links)
350
- .enter().append("line")
351
- .attr("class", "link");
352
-
353
- const node = svg.append("g")
354
- .selectAll("g")
355
- .data(data.nodes)
356
- .enter().append("g")
357
- .attr("class", "node")
358
- .call(d3.drag()
359
- .on("start", dragstarted)
360
- .on("drag", dragged)
361
- .on("end", dragended));
362
-
363
- node.append("circle")
364
- .attr("r", d => Math.max(10, Math.min(30, d.imports + d.importedBy)))
365
- .attr("class", d => d.type);
366
-
367
- node.append("text")
368
- .text(d => d.label)
369
- .attr("x", 0)
370
- .attr("y", 0);
371
-
372
- node.on("click", function(event, d) {
373
- alert(\`File: \${d.id}\\nType: \${d.type}\\nImports: \${d.imports}\\nImported by: \${d.importedBy}\`);
374
- });
375
-
376
- simulation.on("tick", () => {
377
- link
378
- .attr("x1", d => d.source.x)
379
- .attr("y1", d => d.source.y)
380
- .attr("x2", d => d.target.x)
381
- .attr("y2", d => d.target.y);
382
-
383
- node.attr("transform", d => \`translate(\${d.x},\${d.y})\`);
384
- });
385
-
386
- function dragstarted(event, d) {
387
- if (!event.active) simulation.alphaTarget(0.3).restart();
388
- d.fx = d.x;
389
- d.fy = d.y;
390
- }
391
-
392
- function dragged(event, d) {
393
- d.fx = event.x;
394
- d.fy = event.y;
395
- }
396
-
397
- function dragended(event, d) {
398
- if (!event.active) simulation.alphaTarget(0);
399
- d.fx = null;
400
- d.fy = null;
401
- }
402
- </script>
403
- </body>
404
- </html>`;
405
-
406
- return html;
407
- }
408
-
409
- module.exports = {
410
- buildDependencyGraph,
411
- generateMermaidDiagram,
412
- generateDotGraph,
413
- generateHtmlVisualization,
414
- };
@@ -1,107 +0,0 @@
1
- /**
2
- * Claude Desktop Config Generator
3
- * Generates .claude/mcp-config.json and .claude/project-context.md
4
- */
5
-
6
- /**
7
- * Generate Claude Desktop MCP config and instructions
8
- */
9
- function generateClaudeConfig(analysis, projectPath) {
10
- const p = analysis.patterns || {};
11
- const m = analysis.monorepo || {};
12
-
13
- const config = {
14
- mcpServers: {
15
- vibecheck: {
16
- command: "npx",
17
- args: ["-y", "@vibecheck/mcp-server"],
18
- env: {
19
- VIBECHECK_PROJECT_PATH: projectPath,
20
- },
21
- },
22
- },
23
- };
24
-
25
- const instructions = `# Claude Desktop - Project Context
26
-
27
- ## Project: ${analysis.name}
28
-
29
- ### Quick Reference
30
-
31
- | Property | Value |
32
- |----------|-------|
33
- | Framework | ${analysis.framework || "Unknown"} |
34
- | Language | ${analysis.language || "JavaScript"} |
35
- | Architecture | ${analysis.architecture} |
36
- ${m.isMonorepo ? `| Monorepo | ${m.type} (${m.workspaces?.length || 0} workspaces) |` : ""}
37
-
38
- ### Tech Stack
39
-
40
- ${analysis.hasNextjs ? "- **Next.js** - React framework" : ""}
41
- ${analysis.hasReact ? "- **React** - UI library" : ""}
42
- ${analysis.hasTypescript ? "- **TypeScript** - Type safety" : ""}
43
- ${analysis.hasPrisma ? "- **Prisma** - Database ORM" : ""}
44
- ${analysis.hasTailwind ? "- **Tailwind CSS** - Styling" : ""}
45
- ${p.stateManagement ? `- **${p.stateManagement}** - State management` : ""}
46
- ${p.validation ? `- **${p.validation}** - Validation` : ""}
47
- ${p.authentication ? `- **${p.authentication}** - Authentication` : ""}
48
-
49
- ### Key Directories
50
-
51
- ${analysis.directories.map(d => `- \`${d}/\``).join("\n")}
52
-
53
- ${m.isMonorepo && m.workspaces?.length > 0 ? `### Workspaces
54
-
55
- ${m.workspaces.slice(0, 10).map(w => `- \`${w.path}\` → ${w.name}`).join("\n")}
56
- ` : ""}
57
-
58
- ### Available Commands
59
-
60
- ${analysis.scripts?.slice(0, 10).map(s => `- \`npm run ${s.name}\``).join("\n") || "See package.json"}
61
-
62
- ### Data Models
63
-
64
- ${analysis.models?.slice(0, 15).map(m => `- ${m}`).join("\n") || "None detected"}
65
-
66
- ### Custom Hooks
67
-
68
- ${p.hooks?.slice(0, 10).map(h => `- \`${h}\``).join("\n") || "None detected"}
69
-
70
- ### Components
71
-
72
- ${analysis.components?.slice(0, 20).map(c => `- ${c}`).join("\n") || "None detected"}
73
-
74
- ### Environment Variables
75
-
76
- ${analysis.envVars?.variables?.slice(0, 15).map(v => `- \`${v}\``).join("\n") || "Check .env.example"}
77
-
78
- ### API Routes
79
-
80
- ${analysis.apiRoutes?.slice(0, 15).map(r => `- ${r}`).join("\n") || "None detected"}
81
-
82
- ### Rules for AI
83
-
84
- 1. **Follow existing patterns** - Match the codebase style
85
- 2. **Use TypeScript strictly** - No \`any\` types
86
- 3. **Use existing components** - Check list above first
87
- 4. **Use existing hooks** - Don't recreate what exists
88
- 5. **Validate inputs** - Use ${p.validation || "zod"} for validation
89
- 6. **No hardcoded secrets** - Use environment variables
90
- 7. **No mock data** - Use real API endpoints
91
-
92
- ${p.antiPatterns?.length > 0 ? `### ⚠️ Avoid These Patterns
93
-
94
- ${p.antiPatterns.map(ap => `- ${ap.message}`).join("\n")}
95
- ` : ""}
96
-
97
- ---
98
-
99
- *Context Enhanced by vibecheck AI*
100
- `;
101
-
102
- return { config, instructions };
103
- }
104
-
105
- module.exports = {
106
- generateClaudeConfig,
107
- };
@@ -1,108 +0,0 @@
1
- /**
2
- * Codex / ChatGPT Instructions Generator
3
- * Generates .codex-instructions.md for OpenAI tools
4
- */
5
-
6
- /**
7
- * Generate OpenAI Codex / ChatGPT instructions
8
- */
9
- function generateCodexConfig(analysis, projectPath) {
10
- const p = analysis.patterns || {};
11
- const m = analysis.monorepo || {};
12
-
13
- return `# OpenAI Codex / ChatGPT Project Instructions
14
-
15
- ## Project: ${analysis.name}
16
-
17
- ### Overview
18
-
19
- - **Framework:** ${analysis.framework || "Unknown"}
20
- - **Language:** ${analysis.language || "JavaScript"}
21
- - **Architecture:** ${analysis.architecture}
22
- ${m.isMonorepo ? `- **Monorepo:** ${m.type} with ${m.workspaces?.length || 0} workspaces` : ""}
23
-
24
- ### Tech Stack
25
-
26
- ${analysis.hasNextjs ? "- Next.js" : ""}
27
- ${analysis.hasReact ? "- React" : ""}
28
- ${analysis.hasTypescript ? "- TypeScript (strict mode)" : ""}
29
- ${analysis.hasPrisma ? "- Prisma ORM" : ""}
30
- ${analysis.hasTailwind ? "- Tailwind CSS" : ""}
31
- ${p.stateManagement ? `- State: ${p.stateManagement}` : ""}
32
- ${p.validation ? `- Validation: ${p.validation}` : ""}
33
- ${p.authentication ? `- Auth: ${p.authentication}` : ""}
34
- ${p.dataFetching?.length ? `- Data Fetching: ${p.dataFetching.join(", ")}` : ""}
35
- ${p.testing?.length ? `- Testing: ${p.testing.join(", ")}` : ""}
36
-
37
- ### Key Directories
38
-
39
- ${analysis.directories.map(d => `- \`${d}/\``).join("\n")}
40
-
41
- ${m.isMonorepo && m.workspaces?.length > 0 ? `### Workspaces
42
-
43
- ${m.workspaces.slice(0, 10).map(w => `- \`${w.path}\` - ${w.name}`).join("\n")}
44
- ` : ""}
45
-
46
- ### Components (${analysis.components?.length || 0})
47
-
48
- ${analysis.components?.slice(0, 20).map(c => `- ${c}`).join("\n") || "None detected"}
49
-
50
- ### Data Models (${analysis.models?.length || 0})
51
-
52
- ${analysis.models?.slice(0, 15).map(m => `- ${m}`).join("\n") || "None detected"}
53
-
54
- ### Custom Hooks
55
-
56
- ${p.hooks?.slice(0, 10).map(h => `- ${h}`).join("\n") || "None detected"}
57
-
58
- ### API Routes
59
-
60
- ${analysis.apiRoutes?.slice(0, 15).map(r => `- ${r}`).join("\n") || "None detected"}
61
-
62
- ### Environment Variables
63
-
64
- ${analysis.envVars?.variables?.slice(0, 15).map(v => `- ${v}`).join("\n") || "Check .env.example"}
65
-
66
- ### NPM Scripts
67
-
68
- ${analysis.scripts?.slice(0, 8).map(s => `- \`npm run ${s.name}\` - ${s.command}`).join("\n") || "See package.json"}
69
-
70
- ### Coding Rules
71
-
72
- 1. Follow existing patterns in the codebase
73
- 2. Use TypeScript with strict types - no \`any\`
74
- 3. Use existing components before creating new ones
75
- 4. Use existing hooks before creating new ones
76
- 5. Validate all API inputs with ${p.validation || "zod"}
77
- 6. Use path aliases (@/) for imports
78
- 7. Follow the established file naming conventions
79
- ${analysis.hasTailwind ? "8. Use Tailwind CSS for styling" : ""}
80
-
81
- ### Anti-Patterns to Avoid
82
-
83
- ${p.antiPatterns?.map(ap => `- ❌ ${ap.message}`).join("\n") || "- No console.log in production\n- No hardcoded secrets\n- No mock data in production"}
84
-
85
- ### File Naming Conventions
86
-
87
- - Components: ${analysis.conventions?.naming?.components || "PascalCase"} (e.g., \`Button.tsx\`)
88
- - Utilities: camelCase (e.g., \`formatDate.ts\`)
89
- - Types: \`.types.ts\` or \`.d.ts\`
90
-
91
- ### Import Order
92
-
93
- 1. React/framework imports
94
- 2. Third-party libraries
95
- 3. Internal components (\`@/components/\`)
96
- 4. Internal utilities (\`@/lib/\`)
97
- 5. Types
98
- 6. Styles
99
-
100
- ---
101
-
102
- *Generated by vibecheck AI - https://vibecheckai.dev*
103
- `;
104
- }
105
-
106
- module.exports = {
107
- generateCodexConfig,
108
- };