@vibecheckai/cli 3.3.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/bin/registry.js +389 -269
  2. package/bin/runners/cli-utils.js +2 -33
  3. package/bin/runners/context/generators/cursor.js +49 -2
  4. package/bin/runners/lib/agent-firewall/learning/learning-engine.js +849 -0
  5. package/bin/runners/lib/analyzers.js +599 -142
  6. package/bin/runners/lib/audit-logger.js +532 -0
  7. package/bin/runners/lib/authority/authorities/architecture.js +364 -0
  8. package/bin/runners/lib/authority/authorities/compliance.js +341 -0
  9. package/bin/runners/lib/authority/authorities/human.js +343 -0
  10. package/bin/runners/lib/authority/authorities/quality.js +420 -0
  11. package/bin/runners/lib/authority/authorities/security.js +228 -0
  12. package/bin/runners/lib/authority/index.js +293 -0
  13. package/bin/runners/lib/authority-badge.js +425 -425
  14. package/bin/runners/lib/bundle/bundle-intelligence.js +846 -0
  15. package/bin/runners/lib/cli-charts.js +368 -0
  16. package/bin/runners/lib/cli-config-display.js +405 -0
  17. package/bin/runners/lib/cli-demo.js +275 -0
  18. package/bin/runners/lib/cli-errors.js +438 -0
  19. package/bin/runners/lib/cli-help-formatter.js +439 -0
  20. package/bin/runners/lib/cli-interactive-menu.js +509 -0
  21. package/bin/runners/lib/cli-prompts.js +441 -0
  22. package/bin/runners/lib/cli-scan-cards.js +362 -0
  23. package/bin/runners/lib/compliance-reporter.js +710 -0
  24. package/bin/runners/lib/conductor/index.js +671 -0
  25. package/bin/runners/lib/easy/README.md +123 -0
  26. package/bin/runners/lib/easy/index.js +140 -0
  27. package/bin/runners/lib/easy/interactive-wizard.js +788 -0
  28. package/bin/runners/lib/easy/one-click-firewall.js +564 -0
  29. package/bin/runners/lib/easy/zero-config-reality.js +714 -0
  30. package/bin/runners/lib/engines/accessibility-engine.js +218 -18
  31. package/bin/runners/lib/engines/api-consistency-engine.js +335 -30
  32. package/bin/runners/lib/engines/async-patterns-engine.js +444 -0
  33. package/bin/runners/lib/engines/bundle-size-engine.js +433 -0
  34. package/bin/runners/lib/engines/confidence-scoring.js +276 -0
  35. package/bin/runners/lib/engines/context-detection.js +264 -0
  36. package/bin/runners/lib/engines/cross-file-analysis-engine.js +292 -27
  37. package/bin/runners/lib/engines/database-patterns-engine.js +429 -0
  38. package/bin/runners/lib/engines/duplicate-code-engine.js +354 -0
  39. package/bin/runners/lib/engines/empty-catch-engine.js +127 -17
  40. package/bin/runners/lib/engines/env-variables-engine.js +458 -0
  41. package/bin/runners/lib/engines/error-handling-engine.js +437 -0
  42. package/bin/runners/lib/engines/false-positive-prevention.js +630 -0
  43. package/bin/runners/lib/engines/framework-adapters/index.js +607 -0
  44. package/bin/runners/lib/engines/framework-detection.js +508 -0
  45. package/bin/runners/lib/engines/import-order-engine.js +429 -0
  46. package/bin/runners/lib/engines/mock-data-engine.js +53 -10
  47. package/bin/runners/lib/engines/naming-conventions-engine.js +544 -0
  48. package/bin/runners/lib/engines/noise-reduction-engine.js +452 -0
  49. package/bin/runners/lib/engines/orchestrator.js +334 -0
  50. package/bin/runners/lib/engines/performance-issues-engine.js +176 -36
  51. package/bin/runners/lib/engines/react-patterns-engine.js +457 -0
  52. package/bin/runners/lib/engines/security-vulnerabilities-engine.js +382 -54
  53. package/bin/runners/lib/engines/type-aware-engine.js +263 -39
  54. package/bin/runners/lib/engines/vibecheck-engines/index.js +122 -13
  55. package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +806 -0
  56. package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +373 -73
  57. package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +577 -0
  58. package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +543 -0
  59. package/bin/runners/lib/engines/vibecheck-engines.js +514 -0
  60. package/bin/runners/lib/enhanced-features/index.js +305 -0
  61. package/bin/runners/lib/enhanced-output.js +631 -0
  62. package/bin/runners/lib/enterprise.js +300 -0
  63. package/bin/runners/lib/entitlements-v2.js +161 -478
  64. package/bin/runners/lib/firewall/command-validator.js +351 -0
  65. package/bin/runners/lib/firewall/config.js +341 -0
  66. package/bin/runners/lib/firewall/content-validator.js +519 -0
  67. package/bin/runners/lib/firewall/index.js +101 -0
  68. package/bin/runners/lib/firewall/path-validator.js +256 -0
  69. package/bin/runners/lib/html-proof-report.js +350 -700
  70. package/bin/runners/lib/intelligence/cross-repo-intelligence.js +817 -0
  71. package/bin/runners/lib/mcp-utils.js +425 -0
  72. package/bin/runners/lib/missions/plan.js +46 -6
  73. package/bin/runners/lib/missions/templates.js +232 -0
  74. package/bin/runners/lib/output/index.js +1022 -0
  75. package/bin/runners/lib/policy-engine.js +652 -0
  76. package/bin/runners/lib/polish/autofix/accessibility-fixes.js +333 -0
  77. package/bin/runners/lib/polish/autofix/async-handlers.js +273 -0
  78. package/bin/runners/lib/polish/autofix/dead-code.js +280 -0
  79. package/bin/runners/lib/polish/autofix/imports-optimizer.js +344 -0
  80. package/bin/runners/lib/polish/autofix/index.js +200 -0
  81. package/bin/runners/lib/polish/autofix/remove-consoles.js +209 -0
  82. package/bin/runners/lib/polish/autofix/strengthen-types.js +245 -0
  83. package/bin/runners/lib/polish/backend-checks.js +148 -0
  84. package/bin/runners/lib/polish/documentation-checks.js +111 -0
  85. package/bin/runners/lib/polish/frontend-checks.js +168 -0
  86. package/bin/runners/lib/polish/index.js +71 -0
  87. package/bin/runners/lib/polish/infrastructure-checks.js +131 -0
  88. package/bin/runners/lib/polish/library-detection.js +175 -0
  89. package/bin/runners/lib/polish/performance-checks.js +100 -0
  90. package/bin/runners/lib/polish/security-checks.js +148 -0
  91. package/bin/runners/lib/polish/utils.js +203 -0
  92. package/bin/runners/lib/prompt-builder.js +540 -0
  93. package/bin/runners/lib/proof-certificate.js +634 -0
  94. package/bin/runners/lib/reality/accessibility-audit.js +946 -0
  95. package/bin/runners/lib/reality/api-contract-validator.js +1012 -0
  96. package/bin/runners/lib/reality/chaos-engineering.js +1084 -0
  97. package/bin/runners/lib/reality/performance-tracker.js +1077 -0
  98. package/bin/runners/lib/reality/scenario-generator.js +1404 -0
  99. package/bin/runners/lib/reality/visual-regression.js +852 -0
  100. package/bin/runners/lib/reality-profiler.js +717 -0
  101. package/bin/runners/lib/replay/flight-recorder-viewer.js +1160 -0
  102. package/bin/runners/lib/review/ai-code-review.js +832 -0
  103. package/bin/runners/lib/rules/custom-rule-engine.js +985 -0
  104. package/bin/runners/lib/sbom-generator.js +641 -0
  105. package/bin/runners/lib/scan-output-enhanced.js +512 -0
  106. package/bin/runners/lib/scan-output.js +65 -19
  107. package/bin/runners/lib/security/owasp-scanner.js +939 -0
  108. package/bin/runners/lib/ship-output.js +18 -25
  109. package/bin/runners/lib/terminal-ui.js +113 -1
  110. package/bin/runners/lib/unified-cli-output.js +603 -430
  111. package/bin/runners/lib/upsell.js +90 -338
  112. package/bin/runners/lib/validators/contract-validator.js +283 -0
  113. package/bin/runners/lib/validators/dead-export-detector.js +279 -0
  114. package/bin/runners/lib/validators/dep-audit.js +245 -0
  115. package/bin/runners/lib/validators/env-validator.js +319 -0
  116. package/bin/runners/lib/validators/index.js +120 -0
  117. package/bin/runners/lib/validators/license-checker.js +252 -0
  118. package/bin/runners/lib/validators/route-validator.js +290 -0
  119. package/bin/runners/runAIAgent.js +5 -10
  120. package/bin/runners/runAgent.js +3 -0
  121. package/bin/runners/runApprove.js +1233 -1200
  122. package/bin/runners/runAuth.js +22 -1
  123. package/bin/runners/runAuthority.js +528 -0
  124. package/bin/runners/runCheckpoint.js +4 -24
  125. package/bin/runners/runClassify.js +862 -859
  126. package/bin/runners/runConductor.js +772 -0
  127. package/bin/runners/runContainer.js +366 -0
  128. package/bin/runners/runContext.js +3 -0
  129. package/bin/runners/runDoctor.js +28 -41
  130. package/bin/runners/runEasy.js +410 -0
  131. package/bin/runners/runFirewall.js +3 -0
  132. package/bin/runners/runFirewallHook.js +3 -0
  133. package/bin/runners/runFix.js +76 -66
  134. package/bin/runners/runGuard.js +411 -18
  135. package/bin/runners/runIaC.js +372 -0
  136. package/bin/runners/runInit.js +10 -60
  137. package/bin/runners/runMcp.js +11 -12
  138. package/bin/runners/runPolish.js +240 -64
  139. package/bin/runners/runPromptFirewall.js +5 -12
  140. package/bin/runners/runProve.js +20 -55
  141. package/bin/runners/runReality.js +68 -59
  142. package/bin/runners/runReport.js +31 -5
  143. package/bin/runners/runRuntime.js +5 -8
  144. package/bin/runners/runScan.js +194 -1273
  145. package/bin/runners/runShip.js +695 -47
  146. package/bin/runners/runTruth.js +3 -0
  147. package/bin/runners/runValidate.js +7 -11
  148. package/bin/runners/runVibe.js +791 -0
  149. package/bin/runners/runWatch.js +14 -23
  150. package/bin/vibecheck.js +179 -65
  151. package/mcp-server/index.js +202 -636
  152. package/mcp-server/lib/api-client.cjs +7 -299
  153. package/mcp-server/package.json +1 -1
  154. package/mcp-server/tier-auth.js +175 -574
  155. package/mcp-server/tools-v3.js +800 -505
  156. package/mcp-server/tools.js +495 -0
  157. package/package.json +1 -1
  158. package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +0 -164
  159. package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +0 -291
  160. package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +0 -83
  161. package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +0 -198
  162. package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +0 -275
  163. package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +0 -167
  164. package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +0 -217
  165. package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +0 -140
  166. package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +0 -164
  167. package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +0 -234
  168. package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +0 -217
  169. package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +0 -78
  170. package/mcp-server/index-v1.js +0 -698
@@ -0,0 +1,577 @@
1
+ /**
2
+ * Smart Fix Suggestions Engine
3
+ *
4
+ * AI-powered fix recommendations with confidence scoring.
5
+ * Generates actionable, context-aware fix suggestions for vibecheck findings.
6
+ *
7
+ * Features:
8
+ * - Context-aware fix generation based on surrounding code
9
+ * - Framework-specific fixes (React, Next.js, Express, etc.)
10
+ * - Confidence scoring for each suggestion
11
+ * - Auto-applicable fixes vs manual review required
12
+ * - Code snippets for common patterns
13
+ *
14
+ * @module smart-fix-engine
15
+ */
16
+
17
+ "use strict";
18
+
19
+ const path = require("path");
20
+ const fs = require("fs");
21
+
22
+ // ═══════════════════════════════════════════════════════════════════════════════
23
+ // FIX TEMPLATES - Common fix patterns for different issue types
24
+ // ═══════════════════════════════════════════════════════════════════════════════
25
+
26
+ const FIX_TEMPLATES = {
27
+ // ═══════════════════════════════════════════════════════════════════════════
28
+ // FAKE SUCCESS FIXES
29
+ // ═══════════════════════════════════════════════════════════════════════════
30
+ "fake-success": {
31
+ patterns: [
32
+ {
33
+ match: /return\s*{\s*success:\s*true\s*}/,
34
+ replace: `// TODO: Implement actual logic before returning success
35
+ const result = await performActualOperation();
36
+ if (!result.ok) {
37
+ return { success: false, error: result.error };
38
+ }
39
+ return { success: true, data: result.data };`,
40
+ confidence: 0.85,
41
+ autoApplicable: false,
42
+ message: "Replace hardcoded success with actual operation result",
43
+ },
44
+ ],
45
+ manualSteps: [
46
+ "Identify what operation this function should perform",
47
+ "Implement the actual business logic",
48
+ "Add error handling for failure cases",
49
+ "Return success only after verifying the operation completed",
50
+ ],
51
+ },
52
+
53
+ // ═══════════════════════════════════════════════════════════════════════════
54
+ // EMPTY CATCH FIXES
55
+ // ═══════════════════════════════════════════════════════════════════════════
56
+ "empty-catch": {
57
+ patterns: [
58
+ {
59
+ match: /catch\s*\(\s*(?:e|err|error|_)?\s*\)\s*{\s*}/,
60
+ replace: `catch (error) {
61
+ console.error('Operation failed:', error);
62
+ throw error; // Re-throw to let caller handle
63
+ }`,
64
+ confidence: 0.90,
65
+ autoApplicable: true,
66
+ message: "Add proper error handling - log and rethrow",
67
+ },
68
+ {
69
+ // Catch with only console.log
70
+ match: /catch\s*\(\s*(\w+)\s*\)\s*{\s*console\.log\([^)]+\)\s*;?\s*}/,
71
+ replace: (match, varName) => `catch (${varName}) {
72
+ console.error('Operation failed:', ${varName});
73
+ // Choose one:
74
+ // throw ${varName}; // Re-throw for caller to handle
75
+ // return { success: false, error: ${varName}.message }; // Return error response
76
+ }`,
77
+ confidence: 0.85,
78
+ autoApplicable: false,
79
+ message: "Improve error handling beyond just logging",
80
+ },
81
+ ],
82
+ manualSteps: [
83
+ "Decide how this error should be handled in context",
84
+ "Either: rethrow the error for upstream handling",
85
+ "Or: return an error response to the caller",
86
+ "Or: implement recovery/retry logic if appropriate",
87
+ "Consider adding error reporting to a monitoring service",
88
+ ],
89
+ },
90
+
91
+ // ═══════════════════════════════════════════════════════════════════════════
92
+ // PLACEHOLDER DATA FIXES
93
+ // ═══════════════════════════════════════════════════════════════════════════
94
+ "placeholder-data": {
95
+ patterns: [
96
+ {
97
+ // Placeholder UUID
98
+ match: /["'](?:12345678-1234-1234-1234-123456789012|00000000-0000-0000-0000-000000000000)["']/,
99
+ replace: `crypto.randomUUID() // Generate real UUID`,
100
+ confidence: 0.95,
101
+ autoApplicable: false,
102
+ message: "Replace placeholder UUID with dynamically generated one",
103
+ },
104
+ {
105
+ // Placeholder email
106
+ match: /["'](?:test@test\.com|user@example\.com)["']/i,
107
+ replace: `process.env.USER_EMAIL || throw new Error('USER_EMAIL not set')`,
108
+ confidence: 0.75,
109
+ autoApplicable: false,
110
+ message: "Replace placeholder email with environment variable or actual user data",
111
+ },
112
+ ],
113
+ manualSteps: [
114
+ "Identify where this data should come from (database, user input, env var)",
115
+ "Replace the hardcoded value with dynamic data",
116
+ "Add validation for the data source",
117
+ "Update tests to use proper test fixtures",
118
+ ],
119
+ },
120
+
121
+ // ═══════════════════════════════════════════════════════════════════════════
122
+ // PLACEHOLDER API URL FIXES
123
+ // ═══════════════════════════════════════════════════════════════════════════
124
+ "placeholder-api": {
125
+ patterns: [
126
+ {
127
+ match: /fetch\s*\(\s*["']https?:\/\/(?:example\.com|api\.example|your-api|my-api)/i,
128
+ replace: `fetch(process.env.API_URL + '/endpoint')`,
129
+ confidence: 0.90,
130
+ autoApplicable: false,
131
+ message: "Use environment variable for API URL",
132
+ },
133
+ ],
134
+ manualSteps: [
135
+ "Add API_URL to your .env file with the real endpoint",
136
+ "Update all fetch calls to use the environment variable",
137
+ "Add API_URL to .env.example for documentation",
138
+ "Verify the endpoint exists and is accessible",
139
+ ],
140
+ },
141
+
142
+ // ═══════════════════════════════════════════════════════════════════════════
143
+ // STUB IMPLEMENTATION FIXES
144
+ // ═══════════════════════════════════════════════════════════════════════════
145
+ "stub-implementation": {
146
+ patterns: [
147
+ {
148
+ match: /{\s*throw\s+(?:new\s+Error\()?["'](?:not\s+implemented|TODO|NYI)/i,
149
+ replace: `{
150
+ // TODO: Implement this function
151
+ // 1. Validate inputs
152
+ // 2. Perform the operation
153
+ // 3. Return the result
154
+ throw new Error('Not implemented - remove this after implementing');
155
+ }`,
156
+ confidence: 0.80,
157
+ autoApplicable: false,
158
+ message: "Implement the function logic",
159
+ },
160
+ ],
161
+ manualSteps: [
162
+ "Review the function signature and docstring to understand what it should do",
163
+ "Implement the actual business logic",
164
+ "Add input validation",
165
+ "Add proper error handling",
166
+ "Write tests to verify the implementation",
167
+ "Remove any 'not implemented' throws",
168
+ ],
169
+ },
170
+
171
+ // ═══════════════════════════════════════════════════════════════════════════
172
+ // HARDCODED SECRET FIXES
173
+ // ═══════════════════════════════════════════════════════════════════════════
174
+ "hardcoded-secret": {
175
+ patterns: [
176
+ {
177
+ match: /(?:api[_-]?key|apiKey|API_KEY)\s*[=:]\s*["']([^"']+)["']/i,
178
+ replace: `apiKey: process.env.API_KEY || throw new Error('API_KEY not configured')`,
179
+ confidence: 0.95,
180
+ autoApplicable: false,
181
+ message: "Move secret to environment variable",
182
+ },
183
+ ],
184
+ manualSteps: [
185
+ "Add the secret to your .env file (never commit this)",
186
+ "Add the variable name (without value) to .env.example",
187
+ "Update code to read from process.env",
188
+ "Add validation to ensure the env var is set",
189
+ "Consider using a secrets manager in production",
190
+ "IMPORTANT: If this was committed, rotate the secret immediately",
191
+ ],
192
+ },
193
+
194
+ // ═══════════════════════════════════════════════════════════════════════════
195
+ // ASYNC WITHOUT AWAIT FIXES
196
+ // ═══════════════════════════════════════════════════════════════════════════
197
+ "async-without-await": {
198
+ patterns: [
199
+ {
200
+ match: /async\s+(?:function\s+)?(\w+)\s*\([^)]*\)\s*{/,
201
+ replace: (match, funcName) => `// If this function doesn't need to be async, remove 'async':
202
+ function ${funcName}(`,
203
+ confidence: 0.60,
204
+ autoApplicable: false,
205
+ message: "Either add await calls or remove async keyword",
206
+ },
207
+ ],
208
+ manualSteps: [
209
+ "Check if this function actually needs to be async",
210
+ "If yes: add await for async operations inside",
211
+ "If no: remove the async keyword to avoid confusion",
212
+ "Async functions always return Promises - make sure callers expect this",
213
+ ],
214
+ },
215
+
216
+ // ═══════════════════════════════════════════════════════════════════════════
217
+ // CONSOLE.LOG IN PRODUCTION FIXES
218
+ // ═══════════════════════════════════════════════════════════════════════════
219
+ "console-log": {
220
+ patterns: [
221
+ {
222
+ match: /console\.log\s*\(/,
223
+ replace: `// Use a proper logger instead:
224
+ logger.debug(`,
225
+ confidence: 0.70,
226
+ autoApplicable: false,
227
+ message: "Replace console.log with proper logger",
228
+ },
229
+ ],
230
+ manualSteps: [
231
+ "Set up a proper logging library (pino, winston, etc.)",
232
+ "Replace console.log with logger.debug or logger.info",
233
+ "Configure log levels for different environments",
234
+ "Remove or downgrade debug logs before shipping",
235
+ ],
236
+ },
237
+ };
238
+
239
+ // ═══════════════════════════════════════════════════════════════════════════════
240
+ // FRAMEWORK-SPECIFIC FIXES
241
+ // ═══════════════════════════════════════════════════════════════════════════════
242
+
243
+ const FRAMEWORK_FIXES = {
244
+ nextjs: {
245
+ "api-handler-error": {
246
+ patterns: [
247
+ {
248
+ match: /export\s+(?:default\s+)?(?:async\s+)?function\s+handler/,
249
+ fix: `export default async function handler(req, res) {
250
+ try {
251
+ // Your logic here
252
+ return res.status(200).json({ success: true, data: result });
253
+ } catch (error) {
254
+ console.error('API Error:', error);
255
+ return res.status(500).json({ success: false, error: error.message });
256
+ }
257
+ }`,
258
+ message: "Next.js API handler should have try-catch",
259
+ },
260
+ ],
261
+ },
262
+ },
263
+
264
+ react: {
265
+ "missing-error-boundary": {
266
+ patterns: [
267
+ {
268
+ message: "Wrap components with ErrorBoundary for better error handling",
269
+ fix: `import { ErrorBoundary } from 'react-error-boundary';
270
+
271
+ function ErrorFallback({error}) {
272
+ return <div role="alert">Something went wrong: {error.message}</div>
273
+ }
274
+
275
+ // Wrap your component:
276
+ <ErrorBoundary FallbackComponent={ErrorFallback}>
277
+ <YourComponent />
278
+ </ErrorBoundary>`,
279
+ },
280
+ ],
281
+ },
282
+ },
283
+
284
+ express: {
285
+ "missing-error-middleware": {
286
+ patterns: [
287
+ {
288
+ message: "Add error handling middleware",
289
+ fix: `// Add at the end of your routes:
290
+ app.use((err, req, res, next) => {
291
+ console.error('Server Error:', err);
292
+ res.status(err.status || 500).json({
293
+ success: false,
294
+ error: process.env.NODE_ENV === 'production'
295
+ ? 'Internal server error'
296
+ : err.message
297
+ });
298
+ });`,
299
+ },
300
+ ],
301
+ },
302
+ },
303
+ };
304
+
305
+ // ═══════════════════════════════════════════════════════════════════════════════
306
+ // SMART FIX GENERATOR
307
+ // ═══════════════════════════════════════════════════════════════════════════════
308
+
309
+ /**
310
+ * Generate smart fix suggestions for a finding
311
+ * @param {object} finding - The finding to generate fixes for
312
+ * @param {object} context - Context about the file and project
313
+ * @returns {object} Fix suggestions with confidence
314
+ */
315
+ function generateFixSuggestions(finding, context = {}) {
316
+ const {
317
+ fileContent = "",
318
+ filePath = "",
319
+ framework = null,
320
+ projectType = null,
321
+ } = context;
322
+
323
+ const suggestions = [];
324
+
325
+ // Get template for finding type
326
+ const findingType = normalizeFindingType(finding.type || finding.category);
327
+ const template = FIX_TEMPLATES[findingType];
328
+
329
+ if (template) {
330
+ // Generate pattern-based fixes
331
+ for (const pattern of template.patterns) {
332
+ const match = fileContent.match(pattern.match);
333
+
334
+ if (match) {
335
+ let replacement = pattern.replace;
336
+
337
+ // If replace is a function, call it with match groups
338
+ if (typeof replacement === "function") {
339
+ replacement = replacement(match[0], ...match.slice(1));
340
+ }
341
+
342
+ suggestions.push({
343
+ type: "code-fix",
344
+ confidence: pattern.confidence,
345
+ autoApplicable: pattern.autoApplicable,
346
+ message: pattern.message,
347
+ original: match[0],
348
+ replacement,
349
+ location: {
350
+ file: filePath,
351
+ line: finding.line,
352
+ matchIndex: match.index,
353
+ },
354
+ });
355
+ }
356
+ }
357
+
358
+ // Add manual steps
359
+ if (template.manualSteps) {
360
+ suggestions.push({
361
+ type: "manual-steps",
362
+ confidence: 0.95,
363
+ autoApplicable: false,
364
+ message: "Manual fix steps",
365
+ steps: template.manualSteps,
366
+ });
367
+ }
368
+ }
369
+
370
+ // Add framework-specific fixes
371
+ if (framework && FRAMEWORK_FIXES[framework]) {
372
+ const frameworkFixes = FRAMEWORK_FIXES[framework];
373
+
374
+ for (const [fixType, fixData] of Object.entries(frameworkFixes)) {
375
+ // Check if this fix is relevant
376
+ if (isFixRelevant(finding, fixType)) {
377
+ for (const pattern of fixData.patterns) {
378
+ suggestions.push({
379
+ type: "framework-fix",
380
+ framework,
381
+ confidence: 0.75,
382
+ autoApplicable: false,
383
+ message: pattern.message,
384
+ codeExample: pattern.fix,
385
+ });
386
+ }
387
+ }
388
+ }
389
+ }
390
+
391
+ // Add general best practice suggestions
392
+ suggestions.push(...generateBestPracticeSuggestions(finding, context));
393
+
394
+ // Sort by confidence
395
+ suggestions.sort((a, b) => b.confidence - a.confidence);
396
+
397
+ return {
398
+ finding: finding.id || finding.type,
399
+ fixCount: suggestions.length,
400
+ hasAutoFix: suggestions.some(s => s.autoApplicable),
401
+ suggestions: suggestions.slice(0, 5), // Top 5 suggestions
402
+ priority: calculateFixPriority(finding, suggestions),
403
+ };
404
+ }
405
+
406
+ /**
407
+ * Normalize finding type to match template keys
408
+ */
409
+ function normalizeFindingType(type) {
410
+ const typeMap = {
411
+ "hardcoded-success-object": "fake-success",
412
+ "async-fake-success": "fake-success",
413
+ "api-fake-success": "fake-success",
414
+ "catch-returns-success": "empty-catch",
415
+ "catch-log-only": "empty-catch",
416
+ "catch-todo-comment": "empty-catch",
417
+ "empty-catch": "empty-catch",
418
+ "swallowed-errors": "empty-catch",
419
+ "placeholder-uuid": "placeholder-data",
420
+ "placeholder-email": "placeholder-data",
421
+ "fetch-example-url": "placeholder-api",
422
+ "placeholder-api-url": "placeholder-api",
423
+ "throws-not-implemented": "stub-implementation",
424
+ "comment-only-function": "stub-implementation",
425
+ "placeholder-api-key": "hardcoded-secret",
426
+ "HardcodedSecret": "hardcoded-secret",
427
+ "async-without-await": "async-without-await",
428
+ "ConsoleLog": "console-log",
429
+ };
430
+
431
+ return typeMap[type] || type?.toLowerCase().replace(/_/g, "-");
432
+ }
433
+
434
+ /**
435
+ * Check if a framework fix is relevant for a finding
436
+ */
437
+ function isFixRelevant(finding, fixType) {
438
+ const relevanceMap = {
439
+ "api-handler-error": ["fake-success", "empty-catch", "FakeSuccess"],
440
+ "missing-error-boundary": ["empty-catch", "swallowed-errors"],
441
+ "missing-error-middleware": ["empty-catch", "silent-failure"],
442
+ };
443
+
444
+ const relevantTypes = relevanceMap[fixType] || [];
445
+ return relevantTypes.some(t =>
446
+ finding.type?.includes(t) || finding.category?.includes(t)
447
+ );
448
+ }
449
+
450
+ /**
451
+ * Generate best practice suggestions
452
+ */
453
+ function generateBestPracticeSuggestions(finding, context) {
454
+ const suggestions = [];
455
+
456
+ // Error handling best practices
457
+ if (finding.category?.includes("Error") || finding.type?.includes("catch")) {
458
+ suggestions.push({
459
+ type: "best-practice",
460
+ confidence: 0.80,
461
+ autoApplicable: false,
462
+ message: "Error Handling Best Practices",
463
+ tips: [
464
+ "Always handle or rethrow errors - never swallow them",
465
+ "Use typed error classes for different error types",
466
+ "Log errors with context (user ID, request ID, etc.)",
467
+ "Consider using a centralized error handler",
468
+ "In production, never expose internal error details to users",
469
+ ],
470
+ });
471
+ }
472
+
473
+ // API best practices
474
+ if (finding.type?.includes("api") || finding.category?.includes("API")) {
475
+ suggestions.push({
476
+ type: "best-practice",
477
+ confidence: 0.80,
478
+ autoApplicable: false,
479
+ message: "API Best Practices",
480
+ tips: [
481
+ "Always use environment variables for API URLs",
482
+ "Add timeout and retry logic for external API calls",
483
+ "Validate API responses before using the data",
484
+ "Use TypeScript interfaces for API response types",
485
+ "Add error handling for network failures",
486
+ ],
487
+ });
488
+ }
489
+
490
+ return suggestions;
491
+ }
492
+
493
+ /**
494
+ * Calculate fix priority
495
+ */
496
+ function calculateFixPriority(finding, suggestions) {
497
+ let priority = 0;
498
+
499
+ // Higher priority for blockers
500
+ if (finding.severity === "BLOCK" || finding.severity === "critical") {
501
+ priority += 30;
502
+ } else if (finding.severity === "WARN") {
503
+ priority += 15;
504
+ }
505
+
506
+ // Higher priority for auto-fixable issues
507
+ if (suggestions.some(s => s.autoApplicable)) {
508
+ priority += 20;
509
+ }
510
+
511
+ // Higher priority for high-confidence fixes
512
+ const maxConfidence = Math.max(...suggestions.map(s => s.confidence || 0));
513
+ priority += maxConfidence * 10;
514
+
515
+ // Higher priority for security issues
516
+ if (finding.category?.includes("Security") || finding.type?.includes("secret")) {
517
+ priority += 25;
518
+ }
519
+
520
+ return Math.min(100, priority);
521
+ }
522
+
523
+ /**
524
+ * Generate fix plan for multiple findings
525
+ * @param {Array} findings - Array of findings
526
+ * @param {object} context - Project context
527
+ * @returns {object} Comprehensive fix plan
528
+ */
529
+ function generateFixPlan(findings, context = {}) {
530
+ const fixes = findings.map(f => generateFixSuggestions(f, context));
531
+
532
+ // Sort by priority
533
+ fixes.sort((a, b) => b.priority - a.priority);
534
+
535
+ // Group by fix type
536
+ const autoFixable = fixes.filter(f => f.hasAutoFix);
537
+ const manualRequired = fixes.filter(f => !f.hasAutoFix);
538
+
539
+ // Calculate estimated effort
540
+ const autoFixTime = autoFixable.length * 2; // ~2 min per auto-fix
541
+ const manualFixTime = manualRequired.reduce((sum, f) => {
542
+ const severity = findings.find(finding => finding.id === f.finding)?.severity;
543
+ return sum + (severity === "BLOCK" ? 30 : 15); // 30 min for blockers, 15 for warnings
544
+ }, 0);
545
+
546
+ return {
547
+ summary: {
548
+ totalFindings: findings.length,
549
+ autoFixable: autoFixable.length,
550
+ manualRequired: manualRequired.length,
551
+ estimatedTimeMinutes: autoFixTime + manualFixTime,
552
+ },
553
+ prioritized: fixes,
554
+ autoFixes: autoFixable,
555
+ manualFixes: manualRequired,
556
+ recommendations: [
557
+ autoFixable.length > 0 ?
558
+ `Run 'vibecheck fix --auto' to apply ${autoFixable.length} automatic fixes` : null,
559
+ manualRequired.length > 0 ?
560
+ `${manualRequired.length} issues require manual review and fixes` : null,
561
+ fixes.some(f => f.priority > 50) ?
562
+ "Start with high-priority fixes marked with priority > 50" : null,
563
+ ].filter(Boolean),
564
+ };
565
+ }
566
+
567
+ // ═══════════════════════════════════════════════════════════════════════════════
568
+ // EXPORTS
569
+ // ═══════════════════════════════════════════════════════════════════════════════
570
+
571
+ module.exports = {
572
+ generateFixSuggestions,
573
+ generateFixPlan,
574
+ FIX_TEMPLATES,
575
+ FRAMEWORK_FIXES,
576
+ normalizeFindingType,
577
+ };