@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
@@ -1,12 +1,161 @@
1
1
  /**
2
2
  * API Consistency Engine
3
- * Checks API route consistency, response formats, error handling patterns
3
+ * Enhanced with:
4
+ * - REST convention checking (HTTP methods, response codes)
5
+ * - Response shape consistency
6
+ * - Input validation detection
7
+ * - Error response format standardization
8
+ * - CORS and security header detection
9
+ * - Rate limiting indicators
10
+ * - API versioning patterns
4
11
  */
5
12
 
6
13
  const { getAST } = require("./ast-cache");
7
14
  const traverse = require("@babel/traverse").default;
8
15
  const t = require("@babel/types");
9
16
 
17
+ /**
18
+ * HTTP method best practices
19
+ */
20
+ const HTTP_METHOD_EXPECTATIONS = {
21
+ GET: {
22
+ shouldHaveBody: false,
23
+ typicalStatusCodes: [200, 404],
24
+ description: "Retrieve data",
25
+ },
26
+ POST: {
27
+ shouldHaveBody: true,
28
+ typicalStatusCodes: [201, 400, 409],
29
+ description: "Create resource",
30
+ },
31
+ PUT: {
32
+ shouldHaveBody: true,
33
+ typicalStatusCodes: [200, 204, 404],
34
+ description: "Replace resource",
35
+ },
36
+ PATCH: {
37
+ shouldHaveBody: true,
38
+ typicalStatusCodes: [200, 204, 404],
39
+ description: "Update resource partially",
40
+ },
41
+ DELETE: {
42
+ shouldHaveBody: false,
43
+ typicalStatusCodes: [204, 404],
44
+ description: "Remove resource",
45
+ },
46
+ };
47
+
48
+ /**
49
+ * Common response wrapper patterns
50
+ */
51
+ const RESPONSE_WRAPPER_PATTERNS = [
52
+ { pattern: /\{\s*data\s*:/, name: "data" },
53
+ { pattern: /\{\s*result\s*:/, name: "result" },
54
+ { pattern: /\{\s*payload\s*:/, name: "payload" },
55
+ { pattern: /\{\s*response\s*:/, name: "response" },
56
+ { pattern: /\{\s*body\s*:/, name: "body" },
57
+ { pattern: /\{\s*message\s*:/, name: "message" },
58
+ { pattern: /\{\s*error\s*:/, name: "error" },
59
+ { pattern: /\{\s*success\s*:/, name: "success" },
60
+ ];
61
+
62
+ /**
63
+ * Detect HTTP method from file or code
64
+ */
65
+ function detectHTTPMethod(code, filePath) {
66
+ const methods = new Set();
67
+
68
+ // Next.js App Router pattern: export function GET/POST/etc
69
+ const appRouterMatch = code.match(/export\s+(?:async\s+)?function\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g);
70
+ if (appRouterMatch) {
71
+ appRouterMatch.forEach(m => {
72
+ const method = m.match(/(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/)[1];
73
+ methods.add(method);
74
+ });
75
+ }
76
+
77
+ // Express pattern: app.get/post/etc or router.get/post/etc
78
+ const expressMatch = code.match(/\.(get|post|put|patch|delete|head|options)\s*\(/gi);
79
+ if (expressMatch) {
80
+ expressMatch.forEach(m => {
81
+ const method = m.match(/\.(get|post|put|patch|delete|head|options)/i)[1].toUpperCase();
82
+ methods.add(method);
83
+ });
84
+ }
85
+
86
+ // Next.js Pages Router pattern
87
+ if (/req\.method\s*===?\s*['"](\w+)['"]/g.test(code)) {
88
+ const methodMatch = code.match(/req\.method\s*===?\s*['"](\w+)['"]/g);
89
+ methodMatch?.forEach(m => {
90
+ const method = m.match(/['"](\w+)['"]/)[1].toUpperCase();
91
+ methods.add(method);
92
+ });
93
+ }
94
+
95
+ return methods;
96
+ }
97
+
98
+ /**
99
+ * Check for input validation
100
+ */
101
+ function hasInputValidation(code) {
102
+ const validationPatterns = [
103
+ /\bzod\b/,
104
+ /\byup\b/,
105
+ /\bjoi\b/,
106
+ /\bvalidate\s*\(/i,
107
+ /\bschema\s*\.\s*parse/,
108
+ /\bschema\s*\.\s*safeParse/,
109
+ /\.input\s*\(/, // tRPC input
110
+ /\bz\s*\.\s*object/,
111
+ /\bz\s*\.\s*string/,
112
+ /\bvalidateBody/i,
113
+ /\brequestSchema/i,
114
+ /\bbodySchema/i,
115
+ ];
116
+
117
+ return validationPatterns.some(p => p.test(code));
118
+ }
119
+
120
+ /**
121
+ * Check for authentication
122
+ */
123
+ function hasAuthentication(code) {
124
+ const authPatterns = [
125
+ /getServerSession/,
126
+ /getSession/,
127
+ /auth\s*\(\)/,
128
+ /verifyToken/,
129
+ /authenticate/i,
130
+ /authorization/i,
131
+ /protectedProcedure/,
132
+ /withAuth/i,
133
+ /requireAuth/i,
134
+ /isAuthenticated/i,
135
+ /bearer/i,
136
+ /jwt/i,
137
+ ];
138
+
139
+ return authPatterns.some(p => p.test(code));
140
+ }
141
+
142
+ /**
143
+ * Check for rate limiting
144
+ */
145
+ function hasRateLimiting(code) {
146
+ const rateLimitPatterns = [
147
+ /rateLimit/i,
148
+ /rateLimiter/i,
149
+ /throttle/i,
150
+ /X-RateLimit/i,
151
+ /upstash.*ratelimit/i,
152
+ /@upstash\/ratelimit/,
153
+ /limiter\./i,
154
+ ];
155
+
156
+ return rateLimitPatterns.some(p => p.test(code));
157
+ }
158
+
10
159
  /**
11
160
  * Analyze API consistency issues
12
161
  */
@@ -16,13 +165,23 @@ function analyzeAPIConsistency(code, filePath) {
16
165
  if (!ast) return findings;
17
166
 
18
167
  const lines = code.split("\n");
19
- const isAPIRoute = filePath.includes("/api/") || filePath.includes("/routes/");
168
+ const normalizedPath = filePath.replace(/\\/g, "/");
169
+ const isAPIRoute = normalizedPath.includes("/api/") ||
170
+ normalizedPath.includes("/routes/") ||
171
+ normalizedPath.match(/\/route\.(ts|js)$/);
20
172
 
21
173
  if (!isAPIRoute) return findings;
22
174
 
23
175
  const responseFormats = new Set();
24
176
  const errorHandlingPatterns = new Set();
177
+ const statusCodesUsed = new Set();
178
+ const responseWrappers = new Set();
25
179
  let hasErrorHandler = false;
180
+ let readsRequestBody = false;
181
+ let hasContentTypeCheck = false;
182
+
183
+ // Detect HTTP methods
184
+ const httpMethods = detectHTTPMethod(code, filePath);
26
185
 
27
186
  traverse(ast, {
28
187
  // Check response formats
@@ -32,18 +191,39 @@ function analyzeAPIConsistency(code, filePath) {
32
191
  // Next.js API routes
33
192
  if (t.isMemberExpression(node.callee) &&
34
193
  t.isIdentifier(node.callee.object, { name: "NextResponse" })) {
35
- const method = node.callee.property.name;
194
+ const method = node.callee.property?.name;
36
195
  if (["json", "redirect", "next"].includes(method)) {
37
196
  responseFormats.add(`NextResponse.${method}`);
38
197
  }
198
+
199
+ // Check response wrapper in NextResponse.json()
200
+ if (method === "json" && node.arguments[0]) {
201
+ const arg = node.arguments[0];
202
+ if (t.isObjectExpression(arg)) {
203
+ arg.properties.forEach(prop => {
204
+ if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) {
205
+ responseWrappers.add(prop.key.name);
206
+ }
207
+ });
208
+ }
209
+ }
39
210
  }
40
211
 
41
212
  // Express-style responses
42
213
  if (t.isMemberExpression(node.callee)) {
43
214
  const prop = node.callee.property;
44
- if (t.isIdentifier(prop) &&
45
- ["json", "send", "status", "redirect"].includes(prop.name)) {
46
- responseFormats.add(`res.${prop.name}`);
215
+ if (t.isIdentifier(prop)) {
216
+ if (["json", "send", "status", "redirect"].includes(prop.name)) {
217
+ responseFormats.add(`res.${prop.name}`);
218
+ }
219
+
220
+ // Track status codes
221
+ if (prop.name === "status" && node.arguments[0]) {
222
+ const statusArg = node.arguments[0];
223
+ if (t.isNumericLiteral(statusArg)) {
224
+ statusCodesUsed.add(statusArg.value);
225
+ }
226
+ }
47
227
  }
48
228
  }
49
229
 
@@ -53,6 +233,43 @@ function analyzeAPIConsistency(code, filePath) {
53
233
  hasErrorHandler = true;
54
234
  errorHandlingPatterns.add("promise.catch");
55
235
  }
236
+
237
+ // Request body access
238
+ if (t.isMemberExpression(node.callee)) {
239
+ const obj = node.callee.object;
240
+ const prop = node.callee.property;
241
+
242
+ // req.body, request.json(), etc.
243
+ if ((t.isIdentifier(obj, { name: "req" }) || t.isIdentifier(obj, { name: "request" })) &&
244
+ t.isIdentifier(prop) && ["body", "json"].includes(prop.name)) {
245
+ readsRequestBody = true;
246
+ }
247
+ }
248
+
249
+ // Content-Type check
250
+ if (t.isMemberExpression(node.callee)) {
251
+ const callee = node.callee;
252
+ if (t.isIdentifier(callee.property, { name: "get" }) &&
253
+ node.arguments[0] &&
254
+ t.isStringLiteral(node.arguments[0]) &&
255
+ node.arguments[0].value.toLowerCase() === "content-type") {
256
+ hasContentTypeCheck = true;
257
+ }
258
+ }
259
+ },
260
+
261
+ // Await request.json() also indicates body reading
262
+ AwaitExpression(path) {
263
+ const arg = path.node.argument;
264
+ if (t.isCallExpression(arg) && t.isMemberExpression(arg.callee)) {
265
+ const obj = arg.callee.object;
266
+ const prop = arg.callee.property;
267
+ if (t.isIdentifier(prop, { name: "json" }) ||
268
+ t.isIdentifier(prop, { name: "formData" }) ||
269
+ t.isIdentifier(prop, { name: "text" })) {
270
+ readsRequestBody = true;
271
+ }
272
+ }
56
273
  },
57
274
 
58
275
  // Try-catch blocks
@@ -67,7 +284,6 @@ function analyzeAPIConsistency(code, filePath) {
67
284
  if (t.isBinaryExpression(test) &&
68
285
  (test.operator === "===" || test.operator === "==")) {
69
286
  const left = test.left;
70
- const right = test.right;
71
287
 
72
288
  // Check for error status checks
73
289
  if ((t.isMemberExpression(left) &&
@@ -98,18 +314,59 @@ function analyzeAPIConsistency(code, filePath) {
98
314
  },
99
315
  });
100
316
 
101
- // Check for inconsistent response formats
102
- if (responseFormats.size > 1) {
317
+ // REST convention checks
318
+ for (const method of httpMethods) {
319
+ const expectations = HTTP_METHOD_EXPECTATIONS[method];
320
+ if (!expectations) continue;
321
+
322
+ // Check GET/DELETE with body
323
+ if (!expectations.shouldHaveBody && readsRequestBody) {
324
+ findings.push({
325
+ type: "rest_convention_violation",
326
+ severity: "WARN",
327
+ category: "APIConsistency",
328
+ file: filePath,
329
+ line: 1,
330
+ column: 0,
331
+ title: `${method} request should not have body`,
332
+ message: `REST convention: ${method} requests typically don't have a request body. Consider using query parameters instead.`,
333
+ confidence: "med",
334
+ fixHint: "Use query parameters (searchParams) instead of request body for GET requests",
335
+ });
336
+ }
337
+
338
+ // Check POST/PUT/PATCH without body
339
+ if (expectations.shouldHaveBody && !readsRequestBody && method !== "DELETE") {
340
+ findings.push({
341
+ type: "rest_convention_violation",
342
+ severity: "INFO",
343
+ category: "APIConsistency",
344
+ file: filePath,
345
+ line: 1,
346
+ column: 0,
347
+ title: `${method} request without body`,
348
+ message: `${method} requests typically include a request body. This might be intentional for some endpoints.`,
349
+ confidence: "low",
350
+ });
351
+ }
352
+ }
353
+
354
+ // Check for inconsistent response wrappers
355
+ const dataWrappers = Array.from(responseWrappers).filter(w =>
356
+ ["data", "result", "payload", "response", "body"].includes(w)
357
+ );
358
+ if (dataWrappers.length > 1) {
103
359
  findings.push({
104
- type: "inconsistent_response_format",
360
+ type: "inconsistent_response_wrapper",
105
361
  severity: "WARN",
106
362
  category: "APIConsistency",
107
363
  file: filePath,
108
364
  line: 1,
109
365
  column: 0,
110
- title: "Inconsistent API response formats",
111
- message: `Multiple response formats used: ${Array.from(responseFormats).join(", ")}`,
112
- confidence: "low",
366
+ title: "Inconsistent response wrapper keys",
367
+ message: `Multiple response wrapper keys used: ${dataWrappers.join(", ")}. Standardize on one format.`,
368
+ confidence: "med",
369
+ fixHint: "Use a consistent wrapper like { data: ... } or { result: ... } across all endpoints",
113
370
  });
114
371
  }
115
372
 
@@ -123,34 +380,78 @@ function analyzeAPIConsistency(code, filePath) {
123
380
  line: 1,
124
381
  column: 0,
125
382
  title: "API route missing error handling",
126
- message: "API route should have try-catch or promise error handling",
383
+ message: "API route should have try-catch or promise error handling to prevent unhandled exceptions",
127
384
  confidence: "med",
385
+ fixHint: "Wrap async logic in try-catch and return appropriate error responses",
128
386
  });
129
387
  }
130
388
 
131
- // Check for missing status codes
132
- let hasStatusCode = false;
133
- traverse(ast, {
134
- CallExpression(path) {
135
- const node = path.node;
136
- if (t.isMemberExpression(node.callee) &&
137
- t.isIdentifier(node.callee.property, { name: "status" })) {
138
- hasStatusCode = true;
139
- }
140
- },
141
- });
142
-
143
- if (!hasStatusCode && responseFormats.size > 0) {
389
+ // Check for missing input validation on POST/PUT/PATCH
390
+ const mutationMethods = ["POST", "PUT", "PATCH"];
391
+ const hasMutationMethod = mutationMethods.some(m => httpMethods.has(m));
392
+
393
+ if (hasMutationMethod && readsRequestBody && !hasInputValidation(code)) {
144
394
  findings.push({
145
- type: "missing_status_code",
395
+ type: "missing_input_validation",
146
396
  severity: "WARN",
147
397
  category: "APIConsistency",
148
398
  file: filePath,
149
399
  line: 1,
150
400
  column: 0,
151
- title: "API response missing explicit status code",
152
- message: "API responses should explicitly set HTTP status codes",
401
+ title: "API endpoint missing input validation",
402
+ message: "Mutation endpoints should validate request body. Consider using Zod, Yup, or similar.",
153
403
  confidence: "med",
404
+ fixHint: "Add schema validation: const body = schema.parse(await request.json())",
405
+ });
406
+ }
407
+
408
+ // Check for missing authentication on sensitive endpoints
409
+ const isSensitiveEndpoint = /\/(admin|user|account|settings|billing|payment)/i.test(normalizedPath);
410
+ if (isSensitiveEndpoint && !hasAuthentication(code)) {
411
+ findings.push({
412
+ type: "missing_authentication",
413
+ severity: "WARN",
414
+ category: "APIConsistency",
415
+ file: filePath,
416
+ line: 1,
417
+ column: 0,
418
+ title: "Sensitive endpoint may need authentication",
419
+ message: `Endpoint path suggests sensitive data (${normalizedPath}). Consider adding authentication.`,
420
+ confidence: "low",
421
+ fixHint: "Add authentication check: const session = await getServerSession()",
422
+ });
423
+ }
424
+
425
+ // Check for missing rate limiting on public endpoints
426
+ const isPublicEndpoint = /(public|webhook|auth\/.*login|auth\/.*register)/i.test(normalizedPath);
427
+ if (isPublicEndpoint && !hasRateLimiting(code)) {
428
+ findings.push({
429
+ type: "missing_rate_limiting",
430
+ severity: "INFO",
431
+ category: "APIConsistency",
432
+ file: filePath,
433
+ line: 1,
434
+ column: 0,
435
+ title: "Public endpoint without rate limiting",
436
+ message: "Public endpoints should consider rate limiting to prevent abuse",
437
+ confidence: "low",
438
+ fixHint: "Consider using @upstash/ratelimit or similar rate limiting solution",
439
+ });
440
+ }
441
+
442
+ // Check Content-Type validation for POST/PUT/PATCH
443
+ if (hasMutationMethod && readsRequestBody && !hasContentTypeCheck) {
444
+ // This is a low-priority check - most frameworks handle this
445
+ findings.push({
446
+ type: "missing_content_type_check",
447
+ severity: "INFO",
448
+ category: "APIConsistency",
449
+ file: filePath,
450
+ line: 1,
451
+ column: 0,
452
+ title: "No explicit Content-Type validation",
453
+ message: "Consider validating Content-Type header for request body endpoints",
454
+ confidence: "low",
154
455
  });
155
456
  }
156
457
 
@@ -159,4 +460,8 @@ function analyzeAPIConsistency(code, filePath) {
159
460
 
160
461
  module.exports = {
161
462
  analyzeAPIConsistency,
463
+ detectHTTPMethod,
464
+ hasInputValidation,
465
+ hasAuthentication,
466
+ hasRateLimiting,
162
467
  };