@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,151 +0,0 @@
1
- /**
2
- * MCP Context JSON Generator
3
- * Generates .vibecheck/context.json for MCP servers
4
- */
5
-
6
- /**
7
- * Generate universal context JSON for MCP
8
- */
9
- function generateContextJson(analysis, projectPath) {
10
- const p = analysis.patterns || {};
11
- const m = analysis.monorepo || {};
12
-
13
- return JSON.stringify({
14
- version: "3.0.0",
15
- generatedAt: new Date().toISOString(),
16
- generator: "vibecheck-context",
17
-
18
- project: {
19
- name: analysis.name,
20
- path: projectPath,
21
- framework: analysis.framework,
22
- language: analysis.language,
23
- architecture: analysis.architecture,
24
- },
25
-
26
- techStack: {
27
- nextjs: analysis.hasNextjs,
28
- react: analysis.hasReact,
29
- typescript: analysis.hasTypescript,
30
- prisma: analysis.hasPrisma,
31
- tailwind: analysis.hasTailwind,
32
- stateManagement: p.stateManagement,
33
- validation: p.validation,
34
- authentication: p.authentication,
35
- dataFetching: p.dataFetching || [],
36
- testing: p.testing || [],
37
- styling: p.styling || [],
38
- },
39
-
40
- structure: {
41
- directories: analysis.directories,
42
- components: analysis.components,
43
- apiRoutes: analysis.apiRoutes,
44
- models: analysis.models,
45
- },
46
-
47
- patterns: {
48
- hooks: p.hooks || [],
49
- stateManagement: p.stateManagement,
50
- validation: p.validation,
51
- authentication: p.authentication,
52
- dataFetching: p.dataFetching || [],
53
- styling: p.styling || [],
54
- testing: p.testing || [],
55
- codeExamples: p.codeExamples || {},
56
- },
57
-
58
- antiPatterns: p.antiPatterns || [],
59
-
60
- types: {
61
- interfaces: analysis.types?.interfaces || [],
62
- types: analysis.types?.types || [],
63
- enums: analysis.types?.enums || [],
64
- },
65
-
66
- environment: {
67
- files: analysis.envVars?.files || [],
68
- variables: analysis.envVars?.variables || [],
69
- },
70
-
71
- scripts: analysis.scripts || [],
72
-
73
- conventions: {
74
- naming: analysis.conventions?.naming || {},
75
- imports: analysis.imports?.importPatterns || [],
76
- },
77
-
78
- monorepo: m.isMonorepo ? {
79
- type: m.type,
80
- tools: m.tools || [],
81
- workspaces: m.workspaces?.map(w => ({
82
- name: w.name,
83
- path: w.path,
84
- description: w.description,
85
- })) || [],
86
- sharedPackages: m.sharedPackages || [],
87
- } : null,
88
-
89
- stats: {
90
- totalFiles: analysis.stats?.totalFiles || 0,
91
- totalLines: analysis.stats?.totalLines || 0,
92
- byExtension: analysis.stats?.byExtension || {},
93
- largestFiles: analysis.stats?.largestFiles || [],
94
- },
95
-
96
- rules: {
97
- critical: [
98
- "Never hardcode secrets - use environment variables",
99
- "No mock data in production code",
100
- `No 'any' types - use proper TypeScript types`,
101
- "Follow existing patterns in the codebase",
102
- "Use existing components before creating new ones",
103
- "API routes must validate all input",
104
- ],
105
- style: [
106
- `File naming: ${analysis.conventions?.naming?.components || "PascalCase"} for components`,
107
- "Use path aliases (@/) for imports",
108
- analysis.hasTailwind ? "Use Tailwind CSS for styling" : null,
109
- p.stateManagement ? `Use ${p.stateManagement} for state management` : null,
110
- p.validation ? `Use ${p.validation} for validation` : null,
111
- ].filter(Boolean),
112
- },
113
-
114
- mcp: {
115
- resources: [
116
- {
117
- uri: `file://${projectPath}/.vibecheck/context.json`,
118
- name: "Project Context",
119
- description: "Full project analysis and context",
120
- mimeType: "application/json",
121
- },
122
- {
123
- uri: `file://${projectPath}/.vibecheck/project-map.json`,
124
- name: "Project Map",
125
- description: "Complete project structure map",
126
- mimeType: "application/json",
127
- },
128
- {
129
- uri: `file://${projectPath}/.vibecheck/memory.json`,
130
- name: "AI Memory",
131
- description: "AI learning memory for this project",
132
- mimeType: "application/json",
133
- },
134
- ],
135
- tools: [
136
- {
137
- name: "vibecheck.context",
138
- description: "Regenerate project context",
139
- },
140
- {
141
- name: "vibecheck.analyze",
142
- description: "Analyze specific file or directory",
143
- },
144
- ],
145
- },
146
- }, null, 2);
147
- }
148
-
149
- module.exports = {
150
- generateContextJson,
151
- };
@@ -1,180 +0,0 @@
1
- /**
2
- * Windsurf Rules Generator
3
- * Generates .windsurf/rules/*.md files for Windsurf Cascade
4
- */
5
-
6
- /**
7
- * Generate Windsurf rules files
8
- */
9
- function generateWindsurfRules(analysis) {
10
- const rules = {};
11
- const p = analysis.patterns || {};
12
- const m = analysis.monorepo || {};
13
-
14
- // Project context
15
- rules["project-context"] = `# Project Context - ${analysis.name}
16
-
17
- ## Overview
18
- - **Framework:** ${analysis.framework || "Unknown"}
19
- - **Language:** ${analysis.language || "JavaScript"}
20
- - **Architecture:** ${analysis.architecture}
21
- ${m.isMonorepo ? `- **Monorepo:** ${m.type} with ${m.workspaces?.length || 0} workspaces` : ""}
22
-
23
- ## Tech Stack
24
- ${analysis.hasNextjs ? "- Next.js" : ""}
25
- ${analysis.hasReact ? "- React" : ""}
26
- ${analysis.hasTypescript ? "- TypeScript" : ""}
27
- ${analysis.hasPrisma ? "- Prisma ORM" : ""}
28
- ${analysis.hasTailwind ? "- Tailwind CSS" : ""}
29
- ${p.stateManagement ? `- ${p.stateManagement}` : ""}
30
- ${p.validation ? `- ${p.validation}` : ""}
31
- ${p.authentication ? `- ${p.authentication}` : ""}
32
-
33
- ## Directory Structure
34
- ${analysis.directories.map(d => `- \`${d}/\``).join("\n")}
35
-
36
- ${m.isMonorepo && m.workspaces?.length > 0 ? `## Workspaces
37
- ${m.workspaces.slice(0, 10).map(w => `- \`${w.path}\` - ${w.name}`).join("\n")}
38
- ` : ""}
39
-
40
- ## Components (${analysis.components.length})
41
- ${analysis.components.slice(0, 25).map(c => `- ${c}`).join("\n") || "None detected"}
42
-
43
- ${p.hooks?.length > 0 ? `## Custom Hooks (${p.hooks.length})
44
- ${p.hooks.slice(0, 15).map(h => `- \`${h}\``).join("\n")}
45
- ` : ""}
46
-
47
- ## API Routes (${analysis.apiRoutes.length})
48
- ${analysis.apiRoutes.slice(0, 15).map(r => `- ${r}`).join("\n") || "None detected"}
49
-
50
- ${analysis.models.length > 0 ? `## Data Models
51
- ${analysis.models.map(m => `- ${m}`).join("\n")}
52
- ` : ""}
53
-
54
- ${analysis.envVars?.variables?.length > 0 ? `## Environment Variables
55
- ${analysis.envVars.variables.slice(0, 15).map(v => `- \`${v}\``).join("\n")}
56
- ` : ""}
57
-
58
- ---
59
- *Context Enhanced by vibecheck AI*
60
- `;
61
-
62
- // Coding standards
63
- rules["coding-standards"] = `# Coding Standards
64
-
65
- ## File Naming
66
- - Components: ${analysis.conventions.naming.components || "PascalCase"} (e.g., \`Button.tsx\`)
67
- - Utilities: camelCase (e.g., \`formatDate.ts\`)
68
- - Types: \`.types.ts\` or \`.d.ts\` suffix
69
-
70
- ## Import Order
71
- 1. React/Next.js imports
72
- 2. Third-party libraries
73
- 3. Internal components (\`@/components/\`)
74
- 4. Internal utilities (\`@/lib/\`, \`@/utils/\`)
75
- 5. Types
76
- 6. Styles
77
-
78
- ## Code Style
79
- ${analysis.hasTypescript ? "- TypeScript with strict mode enabled" : "- JavaScript with JSDoc comments"}
80
- - Functional components with hooks
81
- - Path aliases (\`@/\`) for imports
82
- ${analysis.hasTailwind ? "- Tailwind CSS for styling" : ""}
83
- ${p.stateManagement ? `- ${p.stateManagement} for state management` : ""}
84
- ${p.validation ? `- ${p.validation} for validation` : ""}
85
-
86
- ## Critical Rules
87
-
88
- 1. **No hardcoded secrets** - Use environment variables
89
- 2. **No \`any\` types** - Use proper TypeScript types
90
- 3. **No mock data in production** - Real API endpoints only
91
- 4. **Validate all inputs** - Never trust client data
92
- 5. **Use existing components** - Check before creating new ones
93
- ${p.hooks?.length ? `6. **Use existing hooks** - ${p.hooks.slice(0, 3).join(", ")}...` : ""}
94
-
95
- ${p.antiPatterns?.length > 0 ? `## ⚠️ Avoid These
96
- ${p.antiPatterns.map(ap => `- ${ap.message}: ${ap.suggestion}`).join("\n")}
97
- ` : ""}
98
-
99
- ## When Creating New Files
100
- 1. Check if similar file exists
101
- 2. Place in correct directory
102
- 3. Follow naming conventions
103
- 4. Add proper types
104
- 5. Use existing patterns
105
- `;
106
-
107
- // API patterns
108
- if (analysis.apiRoutes.length > 0 || analysis.hasPrisma) {
109
- rules["api-patterns"] = `# API & Data Patterns
110
-
111
- ${analysis.hasPrisma ? `## Database (Prisma)
112
-
113
- ### Available Models
114
- ${analysis.models.map(m => `- ${m}`).join("\n")}
115
-
116
- ### Usage
117
- \`\`\`typescript
118
- import { prisma } from '@/lib/prisma'
119
-
120
- // Query
121
- const users = await prisma.user.findMany()
122
-
123
- // Create with validation
124
- const user = await prisma.user.create({
125
- data: validatedInput
126
- })
127
- \`\`\`
128
-
129
- ### Rules
130
- - Always import from \`@/lib/prisma\`
131
- - Use transactions for multi-step operations
132
- - Handle errors gracefully
133
- - Never expose raw errors to client
134
- ` : ""}
135
-
136
- ${analysis.apiRoutes.length > 0 ? `## API Routes
137
-
138
- ### Existing Endpoints
139
- ${analysis.apiRoutes.slice(0, 20).map(r => `- \`${r}\``).join("\n")}
140
-
141
- ### API Response Pattern
142
- \`\`\`typescript
143
- // Success
144
- return Response.json({ data, success: true })
145
-
146
- // Error
147
- return Response.json({ error: message }, { status: 400 })
148
- \`\`\`
149
-
150
- ### Validation
151
- ${p.validation ? `Use ${p.validation} for input validation:
152
- \`\`\`typescript
153
- const schema = z.object({ name: z.string() })
154
- const data = schema.parse(await req.json())
155
- \`\`\`` : "Always validate input before processing"}
156
- ` : ""}
157
-
158
- ${p.dataFetching?.length ? `## Data Fetching: ${p.dataFetching.join(", ")}
159
-
160
- ${p.dataFetching.includes("TanStack Query") ? `### TanStack Query
161
- \`\`\`typescript
162
- const { data, isLoading } = useQuery({
163
- queryKey: ['resource'],
164
- queryFn: fetchResource,
165
- })
166
- \`\`\`` : ""}
167
- ${p.dataFetching.includes("SWR") ? `### SWR
168
- \`\`\`typescript
169
- const { data, error } = useSWR('/api/resource', fetcher)
170
- \`\`\`` : ""}
171
- ` : ""}
172
- `;
173
- }
174
-
175
- return rules;
176
- }
177
-
178
- module.exports = {
179
- generateWindsurfRules,
180
- };
@@ -1,302 +0,0 @@
1
- /**
2
- * Git-Aware Context Module
3
- * Extracts commit patterns, branch conventions, and PR templates
4
- */
5
-
6
- const fs = require("fs");
7
- const path = require("path");
8
- const { execSync } = require("child_process");
9
-
10
- /**
11
- * Check if directory is a git repository
12
- */
13
- function isGitRepo(projectPath) {
14
- return fs.existsSync(path.join(projectPath, ".git"));
15
- }
16
-
17
- /**
18
- * Execute git command safely
19
- */
20
- function execGit(command, cwd = process.cwd()) {
21
- try {
22
- return execSync(command, { cwd, encoding: "utf-8" }).trim();
23
- } catch {
24
- return null;
25
- }
26
- }
27
-
28
- /**
29
- * Get recent commits with patterns
30
- */
31
- function getRecentCommits(projectPath, limit = 20) {
32
- if (!isGitRepo(projectPath)) return null;
33
-
34
- const output = execGit(`log --oneline -${limit}`, projectPath);
35
- if (!output) return null;
36
-
37
- const commits = output.split("\n").map(line => {
38
- const [hash, ...messageParts] = line.split(" ");
39
- const message = messageParts.join(" ");
40
-
41
- // Detect patterns
42
- const patterns = {
43
- hasTicket: /(FEAT|FIX|CHORE|DOCS|REFACTOR|TEST|PERF)-\d+/i.test(message),
44
- ticketType: message.match(/(FEAT|FIX|CHORE|DOCS|REFACTOR|TEST|PERF)-\d+/i)?.[1],
45
- isBreaking: /BREAKING CHANGE/i.test(message),
46
- hasScope: /\([^)]+\):/.test(message),
47
- scope: message.match(/\(([^)]+)\):/)?.[1],
48
- isWIP: /wip|work in progress/i.test(message),
49
- isMerge: /^Merge /i.test(message),
50
- };
51
-
52
- return {
53
- hash,
54
- message,
55
- patterns,
56
- };
57
- });
58
-
59
- // Analyze patterns
60
- const analysis = {
61
- totalCommits: commits.length,
62
- withTickets: commits.filter(c => c.patterns.hasTicket).length,
63
- breakingChanges: commits.filter(c => c.patterns.isBreaking).length,
64
- withScopes: commits.filter(c => c.patterns.hasScope).length,
65
- commonScopes: {},
66
- ticketTypes: {},
67
- };
68
-
69
- // Count common patterns
70
- for (const commit of commits) {
71
- if (commit.patterns.scope) {
72
- analysis.commonScopes[commit.patterns.scope] = (analysis.commonScopes[commit.patterns.scope] || 0) + 1;
73
- }
74
- if (commit.patterns.ticketType) {
75
- analysis.ticketTypes[commit.patterns.ticketType] = (analysis.ticketTypes[commit.patterns.ticketType] || 0) + 1;
76
- }
77
- }
78
-
79
- return {
80
- commits,
81
- analysis,
82
- };
83
- }
84
-
85
- /**
86
- * Get branch information and conventions
87
- */
88
- function getBranchInfo(projectPath) {
89
- if (!isGitRepo(projectPath)) return null;
90
-
91
- const currentBranch = execGit("branch --show-current", projectPath);
92
- const allBranches = execGit("branch -a", projectPath);
93
- const defaultBranch = execGit("symbolic-ref refs/remotes/origin/HEAD | sed 's@^.*/@@'", projectPath);
94
-
95
- if (!currentBranch || !allBranches) return null;
96
-
97
- const branches = allBranches.split("\n").map(b => b.replace("*", "").trim());
98
- const localBranches = branches.filter(b => !b.startsWith("remotes/"));
99
- const remoteBranches = branches.filter(b => b.startsWith("remotes/")).map(b => b.replace("remotes/origin/", ""));
100
-
101
- // Analyze naming patterns
102
- const patterns = {
103
- hasFeaturePrefix: localBranches.some(b => /^feature\//.test(b)),
104
- hasBugfixPrefix: localBranches.some(b => /^bugfix\//.test(b) || /^fix\//.test(b)),
105
- hasHotfixPrefix: localBranches.some(b => /^hotfix\//.test(b)),
106
- hasIssueNumber: localBranches.some(b => /\d+$/.test(b)),
107
- usesSlashes: localBranches.some(b => b.includes("/")),
108
- usesKebabCase: localBranches.some(b => /-/.test(b)),
109
- };
110
-
111
- // Common prefixes
112
- const prefixes = {};
113
- for (const branch of localBranches) {
114
- if (branch.includes("/")) {
115
- const prefix = branch.split("/")[0];
116
- prefixes[prefix] = (prefixes[prefix] || 0) + 1;
117
- }
118
- }
119
-
120
- return {
121
- current: currentBranch,
122
- default: defaultBranch,
123
- total: localBranches.length,
124
- local: localBranches,
125
- remote: remoteBranches,
126
- patterns,
127
- commonPrefixes: Object.entries(prefixes)
128
- .sort((a, b) => b[1] - a[1])
129
- .slice(0, 5)
130
- .map(([name, count]) => ({ name, count })),
131
- };
132
- }
133
-
134
- /**
135
- * Get PR template information
136
- */
137
- function getPRTemplate(projectPath) {
138
- const templates = [
139
- ".github/pull_request_template.md",
140
- ".github/PULL_REQUEST_TEMPLATE.md",
141
- "PULL_REQUEST_TEMPLATE.md",
142
- ];
143
-
144
- for (const template of templates) {
145
- const templatePath = path.join(projectPath, template);
146
- if (fs.existsSync(templatePath)) {
147
- try {
148
- const content = fs.readFileSync(templatePath, "utf-8");
149
-
150
- // Analyze template sections
151
- const sections = [];
152
- const lines = content.split("\n");
153
- let currentSection = null;
154
-
155
- for (const line of lines) {
156
- if (line.startsWith("##") || line.startsWith("###")) {
157
- if (currentSection) {
158
- sections.push(currentSection);
159
- }
160
- currentSection = {
161
- title: line.replace(/^#+\s*/, ""),
162
- required: line.includes("Required") || line.includes("MUST"),
163
- content: [],
164
- };
165
- } else if (currentSection && line.trim()) {
166
- currentSection.content.push(line);
167
- }
168
- }
169
-
170
- if (currentSection) {
171
- sections.push(currentSection);
172
- }
173
-
174
- return {
175
- file: template,
176
- sections,
177
- hasRequiredSections: sections.some(s => s.required),
178
- sectionCount: sections.length,
179
- };
180
- } catch {}
181
- }
182
- }
183
-
184
- return null;
185
- }
186
-
187
- /**
188
- * Get git blame information for team patterns
189
- */
190
- function getTeamPatterns(projectPath, fileLimit = 10) {
191
- if (!isGitRepo(projectPath)) return null;
192
-
193
- // Get recent files
194
- const output = execGit("ls-files -z", projectPath);
195
- if (!output) return null;
196
-
197
- const files = output.split("\0")
198
- .filter(f => f && (f.endsWith(".ts") || f.endsWith(".tsx") || f.endsWith(".js")))
199
- .slice(0, fileLimit);
200
-
201
- const authorStats = {};
202
- const patterns = {
203
- commonImports: {},
204
- commentStyles: {},
205
- functionPatterns: {},
206
- };
207
-
208
- for (const file of files) {
209
- const blameOutput = execGit(`blame --line-porcelain "${file}"`, projectPath);
210
- if (!blameOutput) continue;
211
-
212
- const lines = blameOutput.split("\n");
213
- let currentAuthor = null;
214
-
215
- for (const line of lines) {
216
- if (line.startsWith("author ")) {
217
- currentAuthor = line.slice(7);
218
- authorStats[currentAuthor] = (authorStats[currentAuthor] || 0) + 1;
219
- } else if (line.startsWith("\t") && currentAuthor) {
220
- const codeLine = line.slice(1);
221
-
222
- // Track patterns by author
223
- if (!patterns.authorPatterns) patterns.authorPatterns = {};
224
- if (!patterns.authorPatterns[currentAuthor]) {
225
- patterns.authorPatterns[currentAuthor] = {
226
- imports: [],
227
- comments: [],
228
- functions: [],
229
- };
230
- }
231
-
232
- // Import patterns
233
- if (codeLine.includes("import ")) {
234
- const importType = codeLine.includes(" from ") ? "named" : "default";
235
- patterns.authorPatterns[currentAuthor].imports.push(importType);
236
- }
237
-
238
- // Comment patterns
239
- if (codeLine.includes("//")) {
240
- patterns.authorPatterns[currentAuthor].comments.push(codeLine);
241
- }
242
-
243
- // Function patterns
244
- if (codeLine.includes("function ") || codeLine.includes("=>")) {
245
- patterns.authorPatterns[currentAuthor].functions.push(codeLine);
246
- }
247
- }
248
- }
249
- }
250
-
251
- // Analyze top contributors
252
- const topAuthors = Object.entries(authorStats)
253
- .sort((a, b) => b[1] - a[1])
254
- .slice(0, 5)
255
- .map(([name, lines]) => ({ name, lines }));
256
-
257
- return {
258
- topAuthors,
259
- totalAuthors: Object.keys(authorStats).length,
260
- patterns,
261
- };
262
- }
263
-
264
- /**
265
- * Get complete git context
266
- */
267
- function getGitContext(projectPath) {
268
- if (!isGitRepo(projectPath)) {
269
- return {
270
- isRepo: false,
271
- message: "Not a git repository",
272
- };
273
- }
274
-
275
- const commits = getRecentCommits(projectPath);
276
- const branches = getBranchInfo(projectPath);
277
- const prTemplate = getPRTemplate(projectPath);
278
- const teamPatterns = getTeamPatterns(projectPath);
279
-
280
- return {
281
- isRepo: true,
282
- commits,
283
- branches,
284
- prTemplate,
285
- teamPatterns,
286
- conventions: {
287
- commitMessages: commits?.analysis || null,
288
- branchNaming: branches?.patterns || null,
289
- hasPRTemplate: !!prTemplate,
290
- teamSize: teamPatterns?.totalAuthors || 0,
291
- },
292
- };
293
- }
294
-
295
- module.exports = {
296
- isGitRepo,
297
- getGitContext,
298
- getRecentCommits,
299
- getBranchInfo,
300
- getPRTemplate,
301
- getTeamPatterns,
302
- };