codeslick-cli 1.2.0 → 1.2.2

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 (103) hide show
  1. package/README.md +18 -19
  2. package/dist/packages/cli/src/reporters/cli-reporter.js +7 -7
  3. package/dist/packages/cli/src/reporters/cli-reporter.js.map +1 -1
  4. package/dist/src/lib/analyzers/go/security-checks/ai-generated-code.d.ts +5 -2
  5. package/dist/src/lib/analyzers/go/security-checks/ai-generated-code.d.ts.map +1 -1
  6. package/dist/src/lib/analyzers/go/security-checks/ai-generated-code.js +61 -5
  7. package/dist/src/lib/analyzers/go/security-checks/ai-generated-code.js.map +1 -1
  8. package/dist/src/lib/analyzers/go/security-checks/credentials-crypto.d.ts +6 -4
  9. package/dist/src/lib/analyzers/go/security-checks/credentials-crypto.d.ts.map +1 -1
  10. package/dist/src/lib/analyzers/go/security-checks/credentials-crypto.js +97 -4
  11. package/dist/src/lib/analyzers/go/security-checks/credentials-crypto.js.map +1 -1
  12. package/dist/src/lib/analyzers/go/security-checks/enhanced-supply-chain.d.ts +21 -0
  13. package/dist/src/lib/analyzers/go/security-checks/enhanced-supply-chain.d.ts.map +1 -0
  14. package/dist/src/lib/analyzers/go/security-checks/enhanced-supply-chain.js +114 -0
  15. package/dist/src/lib/analyzers/go/security-checks/enhanced-supply-chain.js.map +1 -0
  16. package/dist/src/lib/analyzers/go/security-checks/injection-attacks.d.ts +1 -0
  17. package/dist/src/lib/analyzers/go/security-checks/injection-attacks.d.ts.map +1 -1
  18. package/dist/src/lib/analyzers/go/security-checks/injection-attacks.js +48 -0
  19. package/dist/src/lib/analyzers/go/security-checks/injection-attacks.js.map +1 -1
  20. package/dist/src/lib/analyzers/go-analyzer.d.ts.map +1 -1
  21. package/dist/src/lib/analyzers/go-analyzer.js +3 -0
  22. package/dist/src/lib/analyzers/go-analyzer.js.map +1 -1
  23. package/dist/src/lib/analyzers/helpers/ai-code-detection-utils.d.ts +226 -2
  24. package/dist/src/lib/analyzers/helpers/ai-code-detection-utils.d.ts.map +1 -1
  25. package/dist/src/lib/analyzers/helpers/ai-code-detection-utils.js +1108 -23
  26. package/dist/src/lib/analyzers/helpers/ai-code-detection-utils.js.map +1 -1
  27. package/dist/src/lib/analyzers/helpers/variable-tracker.d.ts.map +1 -1
  28. package/dist/src/lib/analyzers/helpers/variable-tracker.js +6 -4
  29. package/dist/src/lib/analyzers/helpers/variable-tracker.js.map +1 -1
  30. package/dist/src/lib/analyzers/java/security-checks/ai-generated-code.d.ts +2 -0
  31. package/dist/src/lib/analyzers/java/security-checks/ai-generated-code.d.ts.map +1 -1
  32. package/dist/src/lib/analyzers/java/security-checks/ai-generated-code.js +76 -12
  33. package/dist/src/lib/analyzers/java/security-checks/ai-generated-code.js.map +1 -1
  34. package/dist/src/lib/analyzers/java/security-checks/enhanced-supply-chain.d.ts +2 -0
  35. package/dist/src/lib/analyzers/java/security-checks/enhanced-supply-chain.d.ts.map +1 -1
  36. package/dist/src/lib/analyzers/java/security-checks/enhanced-supply-chain.js +99 -6
  37. package/dist/src/lib/analyzers/java/security-checks/enhanced-supply-chain.js.map +1 -1
  38. package/dist/src/lib/analyzers/java/security-checks/injection-attacks.d.ts +1 -0
  39. package/dist/src/lib/analyzers/java/security-checks/injection-attacks.d.ts.map +1 -1
  40. package/dist/src/lib/analyzers/java/security-checks/injection-attacks.js +41 -3
  41. package/dist/src/lib/analyzers/java/security-checks/injection-attacks.js.map +1 -1
  42. package/dist/src/lib/analyzers/javascript/security-checks/ai-generated-code.d.ts +3 -2
  43. package/dist/src/lib/analyzers/javascript/security-checks/ai-generated-code.d.ts.map +1 -1
  44. package/dist/src/lib/analyzers/javascript/security-checks/ai-generated-code.js +82 -11
  45. package/dist/src/lib/analyzers/javascript/security-checks/ai-generated-code.js.map +1 -1
  46. package/dist/src/lib/analyzers/javascript/security-checks/enhanced-supply-chain.d.ts +3 -0
  47. package/dist/src/lib/analyzers/javascript/security-checks/enhanced-supply-chain.d.ts.map +1 -1
  48. package/dist/src/lib/analyzers/javascript/security-checks/enhanced-supply-chain.js +75 -0
  49. package/dist/src/lib/analyzers/javascript/security-checks/enhanced-supply-chain.js.map +1 -1
  50. package/dist/src/lib/analyzers/javascript-analyzer.d.ts.map +1 -1
  51. package/dist/src/lib/analyzers/javascript-analyzer.js +9 -2
  52. package/dist/src/lib/analyzers/javascript-analyzer.js.map +1 -1
  53. package/dist/src/lib/analyzers/python/security-checks/ai-generated-code.d.ts +3 -2
  54. package/dist/src/lib/analyzers/python/security-checks/ai-generated-code.d.ts.map +1 -1
  55. package/dist/src/lib/analyzers/python/security-checks/ai-generated-code.js +113 -10
  56. package/dist/src/lib/analyzers/python/security-checks/ai-generated-code.js.map +1 -1
  57. package/dist/src/lib/analyzers/python/security-checks/credentials-crypto.d.ts +2 -0
  58. package/dist/src/lib/analyzers/python/security-checks/credentials-crypto.d.ts.map +1 -1
  59. package/dist/src/lib/analyzers/python/security-checks/credentials-crypto.js +48 -0
  60. package/dist/src/lib/analyzers/python/security-checks/credentials-crypto.js.map +1 -1
  61. package/dist/src/lib/analyzers/python/security-checks/enhanced-supply-chain.d.ts +3 -0
  62. package/dist/src/lib/analyzers/python/security-checks/enhanced-supply-chain.d.ts.map +1 -1
  63. package/dist/src/lib/analyzers/python/security-checks/enhanced-supply-chain.js +84 -0
  64. package/dist/src/lib/analyzers/python/security-checks/enhanced-supply-chain.js.map +1 -1
  65. package/dist/src/lib/analyzers/python/security-checks/injection-attacks.d.ts +4 -2
  66. package/dist/src/lib/analyzers/python/security-checks/injection-attacks.d.ts.map +1 -1
  67. package/dist/src/lib/analyzers/python/security-checks/injection-attacks.js +43 -3
  68. package/dist/src/lib/analyzers/python/security-checks/injection-attacks.js.map +1 -1
  69. package/dist/src/lib/analyzers/python-analyzer.d.ts.map +1 -1
  70. package/dist/src/lib/analyzers/python-analyzer.js +19 -3
  71. package/dist/src/lib/analyzers/python-analyzer.js.map +1 -1
  72. package/dist/src/lib/analyzers/secrets/patterns/api-keys/aws.js +1 -1
  73. package/dist/src/lib/analyzers/secrets/patterns/api-keys/aws.js.map +1 -1
  74. package/dist/src/lib/analyzers/secrets/patterns/api-keys/communication.js +2 -2
  75. package/dist/src/lib/analyzers/secrets/patterns/api-keys/communication.js.map +1 -1
  76. package/dist/src/lib/analyzers/secrets/patterns/api-keys/github.js +3 -3
  77. package/dist/src/lib/analyzers/secrets/patterns/api-keys/github.js.map +1 -1
  78. package/dist/src/lib/analyzers/typescript/security-checks/ai-generated-code.d.ts.map +1 -1
  79. package/dist/src/lib/analyzers/typescript/security-checks/ai-generated-code.js +8 -1
  80. package/dist/src/lib/analyzers/typescript/security-checks/ai-generated-code.js.map +1 -1
  81. package/dist/src/lib/analyzers/typescript/security-checks/enhanced-supply-chain.d.ts +2 -0
  82. package/dist/src/lib/analyzers/typescript/security-checks/enhanced-supply-chain.d.ts.map +1 -1
  83. package/dist/src/lib/analyzers/typescript/security-checks/enhanced-supply-chain.js +49 -0
  84. package/dist/src/lib/analyzers/typescript/security-checks/enhanced-supply-chain.js.map +1 -1
  85. package/dist/src/lib/analyzers/typescript/security-checks/injection-attacks.d.ts +13 -11
  86. package/dist/src/lib/analyzers/typescript/security-checks/injection-attacks.d.ts.map +1 -1
  87. package/dist/src/lib/analyzers/typescript/security-checks/injection-attacks.js +79 -22
  88. package/dist/src/lib/analyzers/typescript/security-checks/injection-attacks.js.map +1 -1
  89. package/dist/src/lib/analyzers/typescript/security-checks/type-safety.d.ts +24 -0
  90. package/dist/src/lib/analyzers/typescript/security-checks/type-safety.d.ts.map +1 -0
  91. package/dist/src/lib/analyzers/typescript/security-checks/type-safety.js +181 -0
  92. package/dist/src/lib/analyzers/typescript/security-checks/type-safety.js.map +1 -0
  93. package/dist/src/lib/analyzers/typescript-analyzer.d.ts.map +1 -1
  94. package/dist/src/lib/analyzers/typescript-analyzer.js +3 -0
  95. package/dist/src/lib/analyzers/typescript-analyzer.js.map +1 -1
  96. package/dist/src/lib/security/compliance-mapping.d.ts.map +1 -1
  97. package/dist/src/lib/security/compliance-mapping.js +19 -0
  98. package/dist/src/lib/security/compliance-mapping.js.map +1 -1
  99. package/dist/src/lib/security/severity-scoring.d.ts.map +1 -1
  100. package/dist/src/lib/security/severity-scoring.js +7 -0
  101. package/dist/src/lib/security/severity-scoring.js.map +1 -1
  102. package/package.json +1 -1
  103. package/src/reporters/cli-reporter.ts +7 -7
@@ -21,21 +21,87 @@ exports.detectRedundantNullChecks = detectRedundantNullChecks;
21
21
  exports.detectUnnecessaryAsync = detectUnnecessaryAsync;
22
22
  exports.detectGenericVariableOveruse = detectGenericVariableOveruse;
23
23
  exports.detectInconsistentStringConcatenation = detectInconsistentStringConcatenation;
24
+ exports.detectVerboseDocstrings = detectVerboseDocstrings;
25
+ exports.detectDefensiveNullChecks = detectDefensiveNullChecks;
26
+ exports.detectExcessiveTryCatch = detectExcessiveTryCatch;
27
+ exports.detectHelperFunctionProliferation = detectHelperFunctionProliferation;
28
+ exports.detectOverlyDescriptiveNames = detectOverlyDescriptiveNames;
29
+ exports.detectPrematureOptimizationComments = detectPrematureOptimizationComments;
30
+ exports.detectDetailedTodoMarkers = detectDetailedTodoMarkers;
31
+ exports.detectTypeAnnotationOveruse = detectTypeAnnotationOveruse;
32
+ exports.detectBoilerplateComments = detectBoilerplateComments;
33
+ exports.detectPlaceholderTodos = detectPlaceholderTodos;
34
+ exports.detectGenericFunctionNames = detectGenericFunctionNames;
35
+ exports.detectPlaceholderConstants = detectPlaceholderConstants;
36
+ exports.detectUnusualImportOrdering = detectUnusualImportOrdering;
37
+ exports.detectCopilotMarkers = detectCopilotMarkers;
38
+ exports.detectExcessiveTypeAssertions = detectExcessiveTypeAssertions;
39
+ exports.detectDetailedExplanatoryComments = detectDetailedExplanatoryComments;
40
+ exports.detectCustomErrorClasses = detectCustomErrorClasses;
41
+ exports.detectExtensiveInputValidation = detectExtensiveInputValidation;
42
+ exports.detectDescriptiveHelperFunctions = detectDescriptiveHelperFunctions;
43
+ exports.detectStructuredReturnObjects = detectStructuredReturnObjects;
44
+ exports.detectAICommandMarkers = detectAICommandMarkers;
45
+ exports.detectDiffStyleComments = detectDiffStyleComments;
46
+ exports.detectTabCompletionArtifacts = detectTabCompletionArtifacts;
47
+ exports.detectContextWindowLeakage = detectContextWindowLeakage;
48
+ exports.detectOverGenericExports = detectOverGenericExports;
49
+ exports.detectUnusedImportCleanup = detectUnusedImportCleanup;
50
+ exports.detectPlaceholderErrorMessages = detectPlaceholderErrorMessages;
51
+ exports.detectInlineDocumentationOverload = detectInlineDocumentationOverload;
52
+ exports.detectZeroEdgeCases = detectZeroEdgeCases;
53
+ exports.detectUniformIndentation = detectUniformIndentation;
54
+ exports.detectTextbookVariableNames = detectTextbookVariableNames;
55
+ exports.detectNoCommentsWithPerfectStructure = detectNoCommentsWithPerfectStructure;
56
+ exports.detectExcessiveParameterValidation = detectExcessiveParameterValidation;
24
57
  exports.calculateAICodeConfidence = calculateAICodeConfidence;
25
58
  exports.isTestFile = isTestFile;
26
59
  exports.removeCommentsAndStrings = removeCommentsAndStrings;
27
60
  /**
28
- * Heuristic weights (sum = 1.0)
61
+ * Heuristic weights (sum = 1.0) - Now 13 heuristics
29
62
  */
30
63
  const HEURISTIC_WEIGHTS = {
31
- overEngineeredErrors: 0.15,
32
- unnecessaryWrappers: 0.12,
33
- verboseComments: 0.10,
34
- mixedNaming: 0.13,
35
- redundantNullChecks: 0.15,
36
- unnecessaryAsync: 0.12,
37
- genericVariables: 0.10,
38
- inconsistentStrings: 0.13,
64
+ // Original 8 heuristics (slightly reduced weights)
65
+ overEngineeredErrors: 0.10,
66
+ unnecessaryWrappers: 0.08,
67
+ verboseComments: 0.07,
68
+ mixedNaming: 0.09,
69
+ redundantNullChecks: 0.10,
70
+ unnecessaryAsync: 0.08,
71
+ genericVariables: 0.07,
72
+ inconsistentStrings: 0.09,
73
+ // "Perfect code" heuristics (5 new patterns - 32% total)
74
+ zeroEdgeCases: 0.08,
75
+ uniformIndentation: 0.07,
76
+ textbookVariableNames: 0.07,
77
+ noCommentsWithPerfectStructure: 0.05,
78
+ excessiveParameterValidation: 0.05,
79
+ };
80
+ /**
81
+ * LLM fingerprint weights for GPT-4 (sum = 1.0)
82
+ */
83
+ const GPT4_FINGERPRINT_WEIGHTS = {
84
+ verboseDocstrings: 0.15,
85
+ defensiveNullChecks: 0.12,
86
+ excessiveTryCatch: 0.15,
87
+ helperFunctionProliferation: 0.13,
88
+ overlyDescriptiveNames: 0.10,
89
+ prematureOptimizationComments: 0.10,
90
+ detailedTodoMarkers: 0.10,
91
+ typeAnnotationOveruse: 0.15,
92
+ };
93
+ /**
94
+ * LLM fingerprint weights for Cursor (sum = 1.0)
95
+ */
96
+ const CURSOR_FINGERPRINT_WEIGHTS = {
97
+ aiCommandMarkers: 0.15,
98
+ diffStyleComments: 0.12,
99
+ tabCompletionArtifacts: 0.15,
100
+ contextWindowLeakage: 0.10,
101
+ overGenericExports: 0.10,
102
+ unusedImportCleanup: 0.13,
103
+ placeholderErrorMessages: 0.13,
104
+ inlineDocumentationOverload: 0.12,
39
105
  };
40
106
  /**
41
107
  * 1. Detect over-engineered error handling
@@ -290,41 +356,1060 @@ function detectInconsistentStringConcatenation(lines) {
290
356
  return totalFunctions > 0 ? Math.min(inconsistentFunctions / totalFunctions, 1.0) : 0;
291
357
  }
292
358
  /**
293
- * Calculate confidence score from hallucination count and heuristic scores
359
+ * ====================
360
+ * LLM FINGERPRINT DETECTORS (Week 2)
361
+ * ====================
362
+ */
363
+ /**
364
+ * GPT-4 Fingerprint #1: Verbose docstrings
365
+ * Pattern: JSDoc/docstring with >5 lines and @param/@returns for trivial functions
366
+ */
367
+ function detectVerboseDocstrings(lines) {
368
+ let verboseDocCount = 0;
369
+ let totalDocs = 0;
370
+ let inDocstring = false;
371
+ let docstringLines = 0;
372
+ let docstringStart = -1;
373
+ let docstringType = ''; // '/**' or '"""'
374
+ for (let i = 0; i < lines.length; i++) {
375
+ const trimmed = lines[i].trim();
376
+ // If already in docstring, check for end first
377
+ if (inDocstring) {
378
+ docstringLines++;
379
+ // Detect docstring end
380
+ const isJSDocEnd = docstringType === '/**' && trimmed.endsWith('*/');
381
+ const isPythonDocEnd = docstringType === '"""' && trimmed.endsWith('"""') && i > docstringStart;
382
+ if (isJSDocEnd || isPythonDocEnd) {
383
+ inDocstring = false;
384
+ // Check if next line is a trivial function
385
+ let nextFunctionLine = i + 1;
386
+ while (nextFunctionLine < lines.length && lines[nextFunctionLine].trim() === '') {
387
+ nextFunctionLine++;
388
+ }
389
+ if (nextFunctionLine < lines.length) {
390
+ const functionDecl = lines[nextFunctionLine].trim();
391
+ // Check if trivial function (one-liner or simple return on next line)
392
+ const isJSOneLiner = functionDecl.match(/^function\s+\w+\s*\([^)]*\)\s*{\s*return/);
393
+ const isPythonOneLiner = functionDecl.match(/^def\s+\w+\([^)]*\):\s*return/);
394
+ // Check if it's a function declaration followed by a simple return statement
395
+ let isSimpleReturn = false;
396
+ if (functionDecl.match(/^function\s+\w+\s*\([^)]*\)\s*{/) && nextFunctionLine + 1 < lines.length) {
397
+ const nextLine = lines[nextFunctionLine + 1].trim();
398
+ isSimpleReturn = nextLine.startsWith('return ');
399
+ }
400
+ const isTrivialFunction = isJSOneLiner || isPythonOneLiner || isSimpleReturn;
401
+ // Verbose = >5 lines of docs for trivial function
402
+ if (docstringLines > 5 && isTrivialFunction) {
403
+ verboseDocCount++;
404
+ }
405
+ }
406
+ }
407
+ }
408
+ else {
409
+ // Not in docstring, check for start (/** or """)
410
+ if (trimmed.startsWith('/**')) {
411
+ inDocstring = true;
412
+ docstringStart = i;
413
+ docstringLines = 0;
414
+ docstringType = '/**';
415
+ totalDocs++;
416
+ }
417
+ else if (trimmed.startsWith('"""') || trimmed === '"""') {
418
+ inDocstring = true;
419
+ docstringStart = i;
420
+ docstringLines = 0;
421
+ docstringType = '"""';
422
+ totalDocs++;
423
+ }
424
+ }
425
+ }
426
+ return totalDocs > 0 ? Math.min(verboseDocCount / totalDocs, 1.0) : 0;
427
+ }
428
+ /**
429
+ * GPT-4 Fingerprint #2: Defensive null checks
430
+ * Pattern: 3+ consecutive null checks on different variables
431
+ */
432
+ function detectDefensiveNullChecks(lines) {
433
+ let defensiveBlocks = 0;
434
+ for (let i = 0; i < lines.length - 2; i++) {
435
+ const window = lines.slice(i, i + 3).join('\n');
436
+ // Count null checks (JavaScript/TypeScript/Java and Python)
437
+ const jsNullChecks = (window.match(/if\s*\([^)]*\s*(===|!==|==|!=)\s*(null|undefined)\s*\)/g) || []).length;
438
+ // Count typeof checks (typeof x === 'string', typeof x !== 'number', etc.)
439
+ const typeofChecks = (window.match(/if\s*\([^)]*typeof\s+[\w.]+\s*(===|!==|==|!=)\s*['"][a-z]+['"]\s*\)/g) || []).length;
440
+ // Python: if user is None, if user.name is None, etc.
441
+ const pythonNullChecks = (window.match(/if\s+[\w.]+\s+is\s+(None|null)/gi) || []).length;
442
+ const totalChecks = jsNullChecks + typeofChecks + pythonNullChecks;
443
+ if (totalChecks >= 3) {
444
+ defensiveBlocks++;
445
+ }
446
+ }
447
+ return Math.min(defensiveBlocks / 5, 1.0); // Normalize (5 = very defensive)
448
+ }
449
+ /**
450
+ * GPT-4 Fingerprint #3: Excessive try-catch
451
+ * Pattern: >50% of functions wrapped in try-catch, even for simple operations
452
+ */
453
+ function detectExcessiveTryCatch(lines) {
454
+ let functionsWithTryCatch = 0;
455
+ let totalFunctions = 0;
456
+ let inFunction = false;
457
+ let functionStart = -1;
458
+ for (let i = 0; i < lines.length; i++) {
459
+ const line = lines[i].trim();
460
+ // Detect function start
461
+ const isFunctionStart = line.match(/^function\s+\w+\s*\(/) ||
462
+ line.match(/^def\s+\w+\s*\(/) ||
463
+ line.match(/^(public|private|protected)?\s*(static)?\s+\w+\s+\w+\s*\(/);
464
+ if (isFunctionStart) {
465
+ inFunction = true;
466
+ functionStart = i;
467
+ totalFunctions++;
468
+ }
469
+ // Detect function end
470
+ if (inFunction && line.match(/^}/)) {
471
+ const functionBody = lines.slice(functionStart, i + 1).join('\n');
472
+ // Check if function contains try-catch
473
+ const hasTryCatch = functionBody.match(/\btry\s*{/) !== null;
474
+ if (hasTryCatch) {
475
+ functionsWithTryCatch++;
476
+ }
477
+ inFunction = false;
478
+ }
479
+ }
480
+ const tryCatchRatio = totalFunctions > 0 ? functionsWithTryCatch / totalFunctions : 0;
481
+ // GPT-4 fingerprint: ≥50% of functions have try-catch (excessive)
482
+ // Flag if 50% or more functions have try-catch
483
+ if (tryCatchRatio < 0.5)
484
+ return 0;
485
+ return Math.min(tryCatchRatio * 2 - 0.9, 1.0); // Maps 50% → 0.1, 75% → 0.6, 100% → 1.0
486
+ }
487
+ /**
488
+ * GPT-4 Fingerprint #4: Helper function proliferation
489
+ * Pattern: >30% of functions are single-line helpers used only once
490
+ */
491
+ function detectHelperFunctionProliferation(lines) {
492
+ const functionNames = new Map(); // name -> line count
493
+ const functionUsage = new Map(); // name -> usage count
494
+ let inFunction = false;
495
+ let currentFunctionName = '';
496
+ let functionStart = -1;
497
+ // Phase 1: Identify functions and count their body lines
498
+ for (let i = 0; i < lines.length; i++) {
499
+ const trimmed = lines[i].trim();
500
+ // Detect function declaration
501
+ const funcMatch = trimmed.match(/^function\s+(\w+)\s*\(/) ||
502
+ trimmed.match(/^def\s+(\w+)\s*\(/) ||
503
+ trimmed.match(/^(?:public|private|protected)?\s*(?:static)?\s+\w+\s+(\w+)\s*\(/);
504
+ if (funcMatch) {
505
+ inFunction = true;
506
+ currentFunctionName = funcMatch[1];
507
+ functionStart = i;
508
+ // Check if it's a one-liner (declaration and closing brace on same line)
509
+ if (trimmed.includes('}') && trimmed.endsWith('}')) {
510
+ const lineCount = 1; // One-liner function
511
+ functionNames.set(currentFunctionName, lineCount);
512
+ functionUsage.set(currentFunctionName, 0); // Initialize usage count
513
+ inFunction = false;
514
+ continue;
515
+ }
516
+ // Check if it's a Python one-liner (def foo(): return bar)
517
+ if (trimmed.match(/^def\s+\w+\([^)]*\):\s*return/)) {
518
+ const lineCount = 1; // Python one-liner
519
+ functionNames.set(currentFunctionName, lineCount);
520
+ functionUsage.set(currentFunctionName, 0); // Initialize usage count
521
+ inFunction = false;
522
+ continue;
523
+ }
524
+ }
525
+ // Detect function end (closing brace)
526
+ if (inFunction && (trimmed === '}' || trimmed.startsWith('}'))) {
527
+ const lineCount = i - functionStart;
528
+ functionNames.set(currentFunctionName, lineCount);
529
+ functionUsage.set(currentFunctionName, 0); // Initialize usage count
530
+ inFunction = false;
531
+ }
532
+ }
533
+ // Phase 2: Count function usage
534
+ const code = lines.join('\n');
535
+ functionNames.forEach((_, name) => {
536
+ const usagePattern = new RegExp(`\\b${name}\\s*\\(`, 'g');
537
+ const matches = code.match(usagePattern) || [];
538
+ functionUsage.set(name, matches.length - 1); // -1 to exclude declaration
539
+ });
540
+ // Phase 3: Count single-line helpers used ≤1 time
541
+ let helperCount = 0;
542
+ functionNames.forEach((lineCount, name) => {
543
+ const usageCount = functionUsage.get(name) || 0;
544
+ // Only flag truly trivial one-liners (lineCount == 1) with low usage
545
+ if (lineCount == 1 && usageCount <= 1) {
546
+ helperCount++;
547
+ }
548
+ });
549
+ const helperRatio = functionNames.size > 0 ? helperCount / functionNames.size : 0;
550
+ // GPT-4 fingerprint: >30% are single-use helpers
551
+ return helperRatio > 0.3 ? 1.0 : helperRatio / 0.3;
552
+ }
553
+ /**
554
+ * GPT-4 Fingerprint #5: Overly descriptive variable names
555
+ * Pattern: >3 variables with names >25 characters
556
+ */
557
+ function detectOverlyDescriptiveNames(lines) {
558
+ const longVariableNames = new Set();
559
+ lines.forEach(line => {
560
+ // Match variable declarations
561
+ const varPattern = /(?:const|let|var|val)\s+(\w{26,})\s*=/g;
562
+ const matches = Array.from(line.matchAll(varPattern));
563
+ matches.forEach(match => {
564
+ longVariableNames.add(match[1]);
565
+ });
566
+ });
567
+ return Math.min(longVariableNames.size / 3, 1.0); // Normalize (3+ = verbose)
568
+ }
569
+ /**
570
+ * GPT-4 Fingerprint #6: Premature optimization comments
571
+ * Pattern: Comments mentioning "performance", "optimization", "O(n)" before implementation
572
+ */
573
+ function detectPrematureOptimizationComments(lines) {
574
+ let optimizationComments = 0;
575
+ lines.forEach(line => {
576
+ const trimmed = line.trim();
577
+ const isComment = trimmed.startsWith('//') || trimmed.startsWith('#');
578
+ if (isComment) {
579
+ const hasOptimizationKeywords = /\b(performance|optimization|optimize|O\(\w+\)|time complexity|space complexity)\b/i.test(trimmed);
580
+ if (hasOptimizationKeywords) {
581
+ optimizationComments++;
582
+ }
583
+ }
584
+ });
585
+ return Math.min(optimizationComments / 3, 1.0); // Normalize (3+ = premature)
586
+ }
587
+ /**
588
+ * GPT-4 Fingerprint #7: Detailed TODO markers
589
+ * Pattern: TODO comments with >10 words (GPT-4 over-explains)
590
+ */
591
+ function detectDetailedTodoMarkers(lines) {
592
+ let detailedTodoCount = 0;
593
+ let totalTodos = 0;
594
+ lines.forEach(line => {
595
+ const trimmed = line.trim();
596
+ const isTodo = /TODO|FIXME|XXX/i.test(trimmed);
597
+ if (isTodo) {
598
+ totalTodos++;
599
+ // Extract TODO text
600
+ const todoText = trimmed.replace(/^(\/\/|#)\s*/, '');
601
+ const wordCount = todoText.split(/\s+/).length;
602
+ if (wordCount > 10) {
603
+ detailedTodoCount++;
604
+ }
605
+ }
606
+ });
607
+ return totalTodos > 0 ? Math.min(detailedTodoCount / totalTodos, 1.0) : 0;
608
+ }
609
+ /**
610
+ * GPT-4 Fingerprint #8: Type annotation overuse
611
+ * Pattern: Type hints on >70% of variables in Python/TypeScript (unnecessary)
612
+ */
613
+ function detectTypeAnnotationOveruse(lines) {
614
+ let annotatedVariables = 0;
615
+ let totalVariables = 0;
616
+ lines.forEach(line => {
617
+ const trimmed = line.trim();
618
+ // Python type hints: var: str = "value"
619
+ const pythonTypeHint = trimmed.match(/^(\w+)\s*:\s*\w+\s*=/);
620
+ if (pythonTypeHint) {
621
+ annotatedVariables++;
622
+ totalVariables++;
623
+ }
624
+ // Python variable without type hint: var = "value"
625
+ const pythonVar = trimmed.match(/^(\w+)\s*=\s*[^=]/);
626
+ if (pythonVar && !pythonTypeHint) {
627
+ totalVariables++;
628
+ }
629
+ // TypeScript/JavaScript type annotations
630
+ const tsAnnotated = line.match(/(?:const|let|var)\s+\w+\s*:\s*\w+/g) || [];
631
+ annotatedVariables += tsAnnotated.length;
632
+ const tsVars = line.match(/(?:const|let|var)\s+\w+/g) || [];
633
+ totalVariables += tsVars.length;
634
+ });
635
+ const annotationRatio = totalVariables > 0 ? annotatedVariables / totalVariables : 0;
636
+ // GPT-4 fingerprint: >70% annotated (excessive for dynamic languages)
637
+ return annotationRatio > 0.7 ? 1.0 : annotationRatio / 0.7;
638
+ }
639
+ /**
640
+ * ====================
641
+ * GITHUB COPILOT FINGERPRINT DETECTORS (Week 2)
642
+ * ====================
643
+ */
644
+ /**
645
+ * GitHub Copilot Fingerprint #1: Boilerplate comments
646
+ * Pattern: Comments like "// your code here", "// TODO: implement this"
647
+ */
648
+ function detectBoilerplateComments(lines) {
649
+ let boilerplateCount = 0;
650
+ const boilerplatePatterns = [
651
+ /\/\/\s*(your code here|add your code|implementation here|code goes here)/i,
652
+ /#\s*(your code here|add your code|implementation here|code goes here)/i,
653
+ ];
654
+ lines.forEach(line => {
655
+ const trimmed = line.trim();
656
+ if (boilerplatePatterns.some(pattern => pattern.test(trimmed))) {
657
+ boilerplateCount++;
658
+ }
659
+ });
660
+ return Math.min(boilerplateCount / 3, 1.0); // 3+ = high score
661
+ }
662
+ /**
663
+ * GitHub Copilot Fingerprint #2: Placeholder TODOs
664
+ * Pattern: Generic TODOs like "TODO: implement", "TODO: add error handling"
665
+ */
666
+ function detectPlaceholderTodos(lines) {
667
+ let placeholderTodoCount = 0;
668
+ const placeholderPatterns = [
669
+ /TODO:\s*(implement|add|fix|update|handle|check)/i,
670
+ /FIXME:\s*(implement|add|fix|update|handle|check)/i,
671
+ ];
672
+ lines.forEach(line => {
673
+ const trimmed = line.trim();
674
+ if (placeholderPatterns.some(pattern => pattern.test(trimmed))) {
675
+ placeholderTodoCount++;
676
+ }
677
+ });
678
+ return Math.min(placeholderTodoCount / 5, 1.0); // 5+ = high score
679
+ }
680
+ /**
681
+ * GitHub Copilot Fingerprint #3: Generic function names
682
+ * Pattern: handleClick, doSomething, processData, etc.
683
+ */
684
+ function detectGenericFunctionNames(lines) {
685
+ const genericNames = [
686
+ 'handleClick', 'handleSubmit', 'handleChange', 'handleEvent',
687
+ 'doSomething', 'doStuff', 'processData', 'processInput',
688
+ 'getData', 'setData', 'updateData', 'fetchData',
689
+ 'myFunction', 'testFunction', 'exampleFunction',
690
+ ];
691
+ let genericFunctionCount = 0;
692
+ let totalFunctions = 0;
693
+ lines.forEach(line => {
694
+ const trimmed = line.trim();
695
+ // Detect function declarations
696
+ const funcMatch = trimmed.match(/function\s+(\w+)\s*\(/) ||
697
+ trimmed.match(/def\s+(\w+)\s*\(/) ||
698
+ trimmed.match(/const\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>/);
699
+ if (funcMatch) {
700
+ totalFunctions++;
701
+ const functionName = funcMatch[1];
702
+ if (genericNames.includes(functionName)) {
703
+ genericFunctionCount++;
704
+ }
705
+ }
706
+ });
707
+ return totalFunctions > 0 ? Math.min(genericFunctionCount / totalFunctions, 1.0) : 0;
708
+ }
709
+ /**
710
+ * GitHub Copilot Fingerprint #4: Placeholder constants
711
+ * Pattern: PLACEHOLDER, YOUR_API_KEY, CHANGE_ME, etc.
712
+ */
713
+ function detectPlaceholderConstants(lines) {
714
+ const placeholderPatterns = [
715
+ /\b(PLACEHOLDER|YOUR_API_KEY|YOUR_SECRET|CHANGE_ME|REPLACE_ME|API_KEY_HERE|TOKEN_HERE)\b/,
716
+ /\b(TODO_REPLACE|FIX_ME|UPDATE_THIS|CHANGEME)\b/,
717
+ ];
718
+ let placeholderCount = 0;
719
+ lines.forEach(line => {
720
+ const trimmed = line.trim();
721
+ if (placeholderPatterns.some(pattern => pattern.test(trimmed))) {
722
+ placeholderCount++;
723
+ }
724
+ });
725
+ return Math.min(placeholderCount / 2, 1.0); // 2+ = high score
726
+ }
727
+ /**
728
+ * GitHub Copilot Fingerprint #5: Unusual import ordering
729
+ * Pattern: Copilot often puts imports in alphabetical order, which is uncommon
730
+ */
731
+ function detectUnusualImportOrdering(lines) {
732
+ const imports = [];
733
+ lines.forEach(line => {
734
+ const trimmed = line.trim();
735
+ if (trimmed.startsWith('import ') || trimmed.startsWith('from ')) {
736
+ imports.push(trimmed);
737
+ }
738
+ });
739
+ if (imports.length < 3)
740
+ return 0;
741
+ // Check if imports are in strict alphabetical order
742
+ const sortedImports = [...imports].sort();
743
+ const isAlphabetical = imports.every((imp, i) => imp === sortedImports[i]);
744
+ return isAlphabetical ? 0.7 : 0; // Alphabetical imports = 70% score
745
+ }
746
+ /**
747
+ * GitHub Copilot Fingerprint #6: Copilot suggestion markers
748
+ * Pattern: Comments mentioning "Copilot", "AI-generated", "auto-generated"
749
+ */
750
+ function detectCopilotMarkers(lines) {
751
+ const markerPatterns = [
752
+ /\b(copilot|github copilot|ai.generated|auto.generated|generated by ai)\b/i,
753
+ /\b(ai suggestion|suggested by copilot)\b/i,
754
+ ];
755
+ let markerCount = 0;
756
+ lines.forEach(line => {
757
+ const trimmed = line.trim();
758
+ if (markerPatterns.some(pattern => pattern.test(trimmed))) {
759
+ markerCount++;
760
+ }
761
+ });
762
+ return markerCount > 0 ? 1.0 : 0; // Any marker = 100% score
763
+ }
764
+ /**
765
+ * GitHub Copilot Fingerprint #7: Excessive type assertions
766
+ * Pattern: Overuse of `as any`, `!` (non-null assertion) in TypeScript
767
+ */
768
+ function detectExcessiveTypeAssertions(lines) {
769
+ let typeAssertionCount = 0;
770
+ let totalLines = 0;
771
+ lines.forEach(line => {
772
+ const trimmed = line.trim();
773
+ if (trimmed.length > 0 && !trimmed.startsWith('//') && !trimmed.startsWith('#')) {
774
+ totalLines++;
775
+ // Count `as any`, `as unknown`, `!.` (non-null assertion)
776
+ const asAnyCount = (trimmed.match(/\s+as\s+any\b/g) || []).length;
777
+ const asUnknownCount = (trimmed.match(/\s+as\s+unknown\b/g) || []).length;
778
+ const nonNullCount = (trimmed.match(/!\./g) || []).length;
779
+ typeAssertionCount += asAnyCount + asUnknownCount + nonNullCount;
780
+ }
781
+ });
782
+ const assertionRatio = totalLines > 0 ? typeAssertionCount / totalLines : 0;
783
+ // >10% of lines have type assertions = excessive
784
+ return assertionRatio > 0.1 ? 1.0 : assertionRatio * 10;
785
+ }
786
+ /**
787
+ * ====================
788
+ * CLAUDE CODE FINGERPRINT DETECTORS (Week 2)
789
+ * ====================
790
+ */
791
+ /**
792
+ * Claude Code Fingerprint #1: Detailed explanatory comments
793
+ * Pattern: Multi-line comments explaining "why" not just "what" (Claude's style)
794
+ */
795
+ function detectDetailedExplanatoryComments(lines) {
796
+ let detailedCommentBlocks = 0;
797
+ let inCommentBlock = false;
798
+ let commentLines = 0;
799
+ lines.forEach(line => {
800
+ const trimmed = line.trim();
801
+ // Multi-line comment start
802
+ if (trimmed.startsWith('/*') || trimmed.startsWith('/**')) {
803
+ inCommentBlock = true;
804
+ commentLines = 0;
805
+ }
806
+ if (inCommentBlock) {
807
+ commentLines++;
808
+ // Check for explanatory keywords (why, because, note, important)
809
+ if (/\b(why|because|note that|important|rationale|reason)\b/i.test(trimmed)) {
810
+ detailedCommentBlocks++;
811
+ inCommentBlock = false; // Count once per block
812
+ }
813
+ if (trimmed.endsWith('*/')) {
814
+ inCommentBlock = false;
815
+ }
816
+ }
817
+ // Single-line explanatory comments
818
+ if (trimmed.startsWith('//') && /\b(why|because|note that|important|rationale)\b/i.test(trimmed)) {
819
+ detailedCommentBlocks++;
820
+ }
821
+ });
822
+ return Math.min(detailedCommentBlocks / 5, 1.0); // 5+ explanatory comments = Claude style
823
+ }
824
+ /**
825
+ * Claude Code Fingerprint #2: Custom error classes
826
+ * Pattern: Creating custom error classes instead of using built-in errors
827
+ */
828
+ function detectCustomErrorClasses(lines) {
829
+ let customErrorCount = 0;
830
+ const customErrorPatterns = [
831
+ /class\s+\w+Error\s+extends\s+Error/, // JavaScript/TypeScript
832
+ /class\s+\w+Exception\s*\([^)]*\):/, // Python custom exception
833
+ /public\s+class\s+\w+Exception\s+extends\s+Exception/, // Java
834
+ ];
835
+ lines.forEach(line => {
836
+ const trimmed = line.trim();
837
+ if (customErrorPatterns.some(pattern => pattern.test(trimmed))) {
838
+ customErrorCount++;
839
+ }
840
+ });
841
+ return Math.min(customErrorCount / 2, 1.0); // 2+ custom error classes = Claude style
842
+ }
843
+ /**
844
+ * Claude Code Fingerprint #3: Extensive input validation
845
+ * Pattern: Multiple validation checks at function entry (Claude is thorough)
846
+ */
847
+ function detectExtensiveInputValidation(lines) {
848
+ let functionsWithExtensiveValidation = 0;
849
+ let totalFunctions = 0;
850
+ let inFunction = false;
851
+ let validationChecks = 0;
852
+ let linesIntoFunction = 0;
853
+ lines.forEach(line => {
854
+ const trimmed = line.trim();
855
+ // Detect function start
856
+ const isFunctionStart = trimmed.match(/^function\s+\w+\s*\(/) ||
857
+ trimmed.match(/^def\s+\w+\s*\(/) ||
858
+ trimmed.match(/^(public|private|protected)?\s*(static)?\s+\w+\s+\w+\s*\(/);
859
+ if (isFunctionStart) {
860
+ inFunction = true;
861
+ validationChecks = 0;
862
+ linesIntoFunction = 0;
863
+ totalFunctions++;
864
+ }
865
+ if (inFunction) {
866
+ linesIntoFunction++;
867
+ // Count validation patterns in first 10 lines of function
868
+ if (linesIntoFunction <= 10) {
869
+ if (/if\s*\([^)]*(!|===|!==|<|>|typeof|instanceof)\s*\)/.test(trimmed)) {
870
+ validationChecks++;
871
+ }
872
+ if (/throw new \w+Error/.test(trimmed)) {
873
+ validationChecks++;
874
+ }
875
+ }
876
+ // Function end
877
+ if (trimmed === '}' || trimmed.startsWith('}')) {
878
+ if (validationChecks >= 3) {
879
+ functionsWithExtensiveValidation++;
880
+ }
881
+ inFunction = false;
882
+ }
883
+ }
884
+ });
885
+ return totalFunctions > 0 ? Math.min(functionsWithExtensiveValidation / totalFunctions, 1.0) : 0;
886
+ }
887
+ /**
888
+ * Claude Code Fingerprint #4: Descriptive helper functions
889
+ * Pattern: Helper functions with very clear, descriptive names (Claude's clarity)
890
+ */
891
+ function detectDescriptiveHelperFunctions(lines) {
892
+ let descriptiveHelperCount = 0;
893
+ let totalFunctions = 0;
894
+ // Claude-style descriptive prefixes
895
+ const descriptivePrefixes = [
896
+ 'validate', 'ensure', 'verify', 'check', 'sanitize',
897
+ 'normalize', 'transform', 'convert', 'extract', 'parse',
898
+ 'calculate', 'compute', 'determine', 'resolve',
899
+ ];
900
+ lines.forEach(line => {
901
+ const trimmed = line.trim();
902
+ // Detect function declarations
903
+ const funcMatch = trimmed.match(/^function\s+(\w+)\s*\(/) ||
904
+ trimmed.match(/^def\s+(\w+)\s*\(/) ||
905
+ trimmed.match(/^const\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>/);
906
+ if (funcMatch) {
907
+ totalFunctions++;
908
+ const functionName = funcMatch[1];
909
+ // Check if name starts with descriptive prefix
910
+ if (descriptivePrefixes.some(prefix => functionName.toLowerCase().startsWith(prefix))) {
911
+ descriptiveHelperCount++;
912
+ }
913
+ }
914
+ });
915
+ return totalFunctions > 0 ? Math.min(descriptiveHelperCount / totalFunctions, 1.0) : 0;
916
+ }
917
+ /**
918
+ * Claude Code Fingerprint #5: Structured return objects
919
+ * Pattern: Returning objects with { success, data, error } structure
920
+ */
921
+ function detectStructuredReturnObjects(lines) {
922
+ let structuredReturnCount = 0;
923
+ const structuredReturnPatterns = [
924
+ /return\s*{\s*success\s*:/,
925
+ /return\s*{\s*data\s*:/,
926
+ /return\s*{\s*error\s*:/,
927
+ /return\s*{\s*ok\s*:/,
928
+ /return\s*{\s*result\s*:/,
929
+ /\{\s*success\s*,\s*data\s*,\s*error\s*\}/,
930
+ ];
931
+ lines.forEach(line => {
932
+ const trimmed = line.trim();
933
+ if (structuredReturnPatterns.some(pattern => pattern.test(trimmed))) {
934
+ structuredReturnCount++;
935
+ }
936
+ });
937
+ return Math.min(structuredReturnCount / 3, 1.0); // 3+ structured returns = Claude style
938
+ }
939
+ // =======================================================================================
940
+ // CURSOR BEHAVIORAL FINGERPRINTS (8 patterns)
941
+ // =======================================================================================
942
+ /**
943
+ * Cursor Fingerprint #1: AI command markers
944
+ * Pattern: Comments with AI/Cursor directives
945
+ */
946
+ function detectAICommandMarkers(lines) {
947
+ let markerCount = 0;
948
+ const aiCommandPatterns = [
949
+ /\/\/\s*AI:/i,
950
+ /\/\/\s*Cursor:/i,
951
+ /#\s*AI:/i,
952
+ /#\s*Cursor:/i,
953
+ /@cursor/i,
954
+ /\/\*\s*@cursor/i,
955
+ /\/\/\s*@ai\s/i,
956
+ ];
957
+ lines.forEach(line => {
958
+ const trimmed = line.trim();
959
+ if (aiCommandPatterns.some(pattern => pattern.test(trimmed))) {
960
+ markerCount++;
961
+ }
962
+ });
963
+ return Math.min(markerCount / 2, 1.0); // 2+ AI command markers = Cursor usage
964
+ }
965
+ /**
966
+ * Cursor Fingerprint #2: Diff-style comments
967
+ * Pattern: Comments indicating code generation/addition
968
+ */
969
+ function detectDiffStyleComments(lines) {
970
+ let diffCommentCount = 0;
971
+ const diffStylePatterns = [
972
+ /\/\/\s*Added by Cursor/i,
973
+ /\/\/\s*Generated block/i,
974
+ /\/\/\s*Cursor suggestion/i,
975
+ /#\s*Added by Cursor/i,
976
+ /#\s*Generated by AI/i,
977
+ /\/\/\s*AI-assisted code/i,
978
+ /\/\*\s*Generated code\s*\*\//i,
979
+ ];
980
+ lines.forEach(line => {
981
+ const trimmed = line.trim();
982
+ if (diffStylePatterns.some(pattern => pattern.test(trimmed))) {
983
+ diffCommentCount++;
984
+ }
985
+ });
986
+ return Math.min(diffCommentCount / 2, 1.0); // 2+ diff-style comments
987
+ }
988
+ /**
989
+ * Cursor Fingerprint #3: Tab completion artifacts
990
+ * Pattern: Incomplete suggestions, placeholder text left in code
294
991
  */
295
- function calculateAICodeConfidence(hallucinationCount, heuristicScores) {
296
- // Calculate weighted heuristic score
297
- const heuristicScore = heuristicScores.overEngineeredErrors * HEURISTIC_WEIGHTS.overEngineeredErrors +
992
+ function detectTabCompletionArtifacts(lines) {
993
+ let artifactCount = 0;
994
+ const artifactPatterns = [
995
+ /\.\.\.\s*$/, // Trailing ellipsis
996
+ /\/\/\s*\.\.\./, // Comment with ellipsis
997
+ /#\s*\.\.\./, // Python comment with ellipsis
998
+ /\bTODO:\s*$/i, // Empty TODO
999
+ /\/\/\s*TODO\s*$/i, // Empty TODO comment
1000
+ /\?\?\?/, // Question marks placeholder
1001
+ /<<<<<<</, // Merge conflict markers (Cursor artifacts)
1002
+ />>>>>>>/,
1003
+ ];
1004
+ lines.forEach(line => {
1005
+ const trimmed = line.trim();
1006
+ if (artifactPatterns.some(pattern => pattern.test(trimmed))) {
1007
+ artifactCount++;
1008
+ }
1009
+ });
1010
+ return Math.min(artifactCount / 3, 1.0); // 3+ artifacts
1011
+ }
1012
+ /**
1013
+ * Cursor Fingerprint #4: Context window leakage
1014
+ * Pattern: Comments referencing files/context not in codebase
1015
+ */
1016
+ function detectContextWindowLeakage(lines) {
1017
+ let leakageCount = 0;
1018
+ const leakagePatterns = [
1019
+ /\/\/\s*From:\s*[a-zA-Z0-9_\-]+\.(js|ts|py|java|go)/i, // "From: otherfile.js"
1020
+ /\/\/\s*See:\s*[a-zA-Z0-9_\-]+\.(js|ts|py|java|go)/i, // "See: utils.ts"
1021
+ /\/\/\s*Similar to\s+[a-zA-Z0-9_\-]+/i, // "Similar to OtherClass"
1022
+ /#\s*Based on\s+[a-zA-Z0-9_\-]+/i, // "Based on module_name"
1023
+ /\/\/\s*Imported from\s+/i,
1024
+ ];
1025
+ lines.forEach(line => {
1026
+ const trimmed = line.trim();
1027
+ if (leakagePatterns.some(pattern => pattern.test(trimmed))) {
1028
+ leakageCount++;
1029
+ }
1030
+ });
1031
+ return Math.min(leakageCount / 2, 1.0); // 2+ context leakage comments
1032
+ }
1033
+ /**
1034
+ * Cursor Fingerprint #5: Over-generic exports
1035
+ * Pattern: Export statements with placeholder/generic patterns
1036
+ */
1037
+ function detectOverGenericExports(lines) {
1038
+ let genericExportCount = 0;
1039
+ const genericExportPatterns = [
1040
+ /export\s*\{\s*everything\s*\}/i,
1041
+ /export\s+\*\s+as\s+utils\s+from/i,
1042
+ /export\s+\*\s+as\s+helpers\s+from/i,
1043
+ /export\s+\*\s+as\s+components\s+from/i,
1044
+ /export\s+default\s+\{\}/, // Empty default export
1045
+ ];
1046
+ lines.forEach(line => {
1047
+ const trimmed = line.trim();
1048
+ if (genericExportPatterns.some(pattern => pattern.test(trimmed))) {
1049
+ genericExportCount++;
1050
+ }
1051
+ });
1052
+ return Math.min(genericExportCount / 2, 1.0); // 2+ generic exports
1053
+ }
1054
+ /**
1055
+ * Cursor Fingerprint #6: Unused import cleanup
1056
+ * Pattern: Perfect alphabetical imports with no actual usage
1057
+ */
1058
+ function detectUnusedImportCleanup(lines) {
1059
+ const imports = [];
1060
+ let alphabeticalCount = 0;
1061
+ lines.forEach(line => {
1062
+ const trimmed = line.trim();
1063
+ // Detect import statements
1064
+ const importMatch = trimmed.match(/^import\s+.*\s+from\s+['"]([^'"]+)['"]/) ||
1065
+ trimmed.match(/^from\s+([^\s]+)\s+import/);
1066
+ if (importMatch) {
1067
+ imports.push(trimmed);
1068
+ }
1069
+ });
1070
+ // Check if imports are perfectly alphabetical (Cursor cleanup signature)
1071
+ if (imports.length >= 5) {
1072
+ const sorted = [...imports].sort();
1073
+ alphabeticalCount = imports.every((imp, i) => imp === sorted[i]) ? 1 : 0;
1074
+ }
1075
+ return alphabeticalCount;
1076
+ }
1077
+ /**
1078
+ * Cursor Fingerprint #7: Placeholder error messages
1079
+ * Pattern: Generic error messages from AI suggestions
1080
+ */
1081
+ function detectPlaceholderErrorMessages(lines) {
1082
+ let placeholderErrorCount = 0;
1083
+ const placeholderErrorPatterns = [
1084
+ /(throw new Error|raise Exception)\s*\(\s*['"]An error occurred['"]\s*\)/i,
1085
+ /(throw new Error|raise Exception)\s*\(\s*['"]Something went wrong['"]\s*\)/i,
1086
+ /(throw new Error|raise Exception)\s*\(\s*['"]Error['"]\s*\)/i,
1087
+ /(throw new Error|raise Exception)\s*\(\s*['"]Invalid input['"]\s*\)/i,
1088
+ /(throw new Error|raise Exception)\s*\(\s*['"]Failed['"]\s*\)/i,
1089
+ /console\.error\s*\(\s*['"]Error:['"]/i,
1090
+ /logger\.error\s*\(\s*['"]An error/i,
1091
+ ];
1092
+ lines.forEach(line => {
1093
+ const trimmed = line.trim();
1094
+ if (placeholderErrorPatterns.some(pattern => pattern.test(trimmed))) {
1095
+ placeholderErrorCount++;
1096
+ }
1097
+ });
1098
+ return Math.min(placeholderErrorCount / 3, 1.0); // 3+ placeholder errors
1099
+ }
1100
+ /**
1101
+ * Cursor Fingerprint #8: Inline documentation overload
1102
+ * Pattern: JSDoc/docstrings on every single line (Cursor over-generates docs)
1103
+ */
1104
+ function detectInlineDocumentationOverload(lines) {
1105
+ let docLineCount = 0;
1106
+ let codeLineCount = 0;
1107
+ lines.forEach(line => {
1108
+ const trimmed = line.trim();
1109
+ // Skip empty lines
1110
+ if (trimmed.length === 0)
1111
+ return;
1112
+ // Count documentation lines
1113
+ if (trimmed.startsWith('/**') ||
1114
+ trimmed.startsWith('*') ||
1115
+ trimmed.startsWith('*/') ||
1116
+ trimmed.startsWith('///') ||
1117
+ trimmed.startsWith('///')) {
1118
+ docLineCount++;
1119
+ }
1120
+ else if (trimmed.startsWith('//') || trimmed.startsWith('#')) {
1121
+ // Count inline comments
1122
+ docLineCount++;
1123
+ }
1124
+ else {
1125
+ codeLineCount++;
1126
+ }
1127
+ });
1128
+ // Cursor signature: >60% of lines are documentation/comments
1129
+ const docRatio = codeLineCount > 0 ? docLineCount / (docLineCount + codeLineCount) : 0;
1130
+ return docRatio > 0.6 ? 1.0 : docRatio / 0.6;
1131
+ }
1132
+ // =======================================================================================
1133
+ // "PERFECT CODE" HEURISTICS (5 patterns) - AI code is "too perfect"
1134
+ // =======================================================================================
1135
+ /**
1136
+ * Perfect Code #1: Zero edge cases
1137
+ * Pattern: Functions with no error handling or boundary checks (AI assumes happy path)
1138
+ */
1139
+ function detectZeroEdgeCases(lines) {
1140
+ let functionCount = 0;
1141
+ let functionsWithErrorHandling = 0;
1142
+ let inFunction = false;
1143
+ let currentFunctionHasErrorHandling = false;
1144
+ lines.forEach(line => {
1145
+ const trimmed = line.trim();
1146
+ // Detect function start
1147
+ if (trimmed.match(/^function\s+\w+\s*\(/) ||
1148
+ trimmed.match(/^(async\s+)?function\s*\(/) ||
1149
+ trimmed.match(/^def\s+\w+\s*\(/) ||
1150
+ trimmed.match(/^(public|private|protected)?\s*(static\s+)?\w+\s+\w+\s*\(/)) {
1151
+ if (inFunction && !currentFunctionHasErrorHandling) {
1152
+ // Previous function had no error handling
1153
+ }
1154
+ else if (inFunction) {
1155
+ functionsWithErrorHandling++;
1156
+ }
1157
+ inFunction = true;
1158
+ currentFunctionHasErrorHandling = false;
1159
+ functionCount++;
1160
+ }
1161
+ // Detect error handling patterns
1162
+ if (inFunction) {
1163
+ if (trimmed.includes('try') ||
1164
+ trimmed.includes('catch') ||
1165
+ trimmed.includes('except') ||
1166
+ trimmed.includes('if (!') ||
1167
+ trimmed.includes('if (!') ||
1168
+ trimmed.includes('if (') && (trimmed.includes('null') || trimmed.includes('undefined')) ||
1169
+ trimmed.includes('throw') ||
1170
+ trimmed.includes('raise') ||
1171
+ trimmed.includes('assert')) {
1172
+ currentFunctionHasErrorHandling = true;
1173
+ }
1174
+ }
1175
+ // Detect function end
1176
+ if (trimmed === '}' && inFunction) {
1177
+ if (currentFunctionHasErrorHandling) {
1178
+ functionsWithErrorHandling++;
1179
+ }
1180
+ inFunction = false;
1181
+ currentFunctionHasErrorHandling = false;
1182
+ }
1183
+ });
1184
+ // AI code: >60% of functions have NO error handling (assumes happy path)
1185
+ const noErrorHandlingRatio = functionCount > 0 ? 1 - (functionsWithErrorHandling / functionCount) : 0;
1186
+ return noErrorHandlingRatio > 0.6 ? 1.0 : noErrorHandlingRatio / 0.6;
1187
+ }
1188
+ /**
1189
+ * Perfect Code #2: Uniform indentation
1190
+ * Pattern: Perfectly aligned code (humans are messy, AI is perfect)
1191
+ */
1192
+ function detectUniformIndentation(lines) {
1193
+ const indentationLevels = [];
1194
+ lines.forEach(line => {
1195
+ if (line.trim().length === 0)
1196
+ return; // Skip empty lines
1197
+ // Count leading spaces
1198
+ const leadingSpaces = line.match(/^(\s*)/)?.[1].length || 0;
1199
+ if (leadingSpaces > 0) {
1200
+ indentationLevels.push(leadingSpaces);
1201
+ }
1202
+ });
1203
+ if (indentationLevels.length < 10)
1204
+ return 0; // Not enough data
1205
+ // Check if all indentation is perfectly consistent (multiples of 2 or 4)
1206
+ const allMultiplesOf2 = indentationLevels.every(level => level % 2 === 0);
1207
+ const allMultiplesOf4 = indentationLevels.every(level => level % 4 === 0);
1208
+ // Check for perfect uniformity (no variation)
1209
+ const uniqueLevels = new Set(indentationLevels);
1210
+ const uniformityRatio = 1 - (uniqueLevels.size / indentationLevels.length);
1211
+ // AI signature: Perfect multiples + high uniformity
1212
+ if ((allMultiplesOf2 || allMultiplesOf4) && uniformityRatio > 0.8) {
1213
+ return 1.0;
1214
+ }
1215
+ else if ((allMultiplesOf2 || allMultiplesOf4) && uniformityRatio > 0.6) {
1216
+ return 0.5;
1217
+ }
1218
+ return 0;
1219
+ }
1220
+ /**
1221
+ * Perfect Code #3: Textbook variable names
1222
+ * Pattern: Generic tutorial-style names (firstName, lastName, emailAddress)
1223
+ */
1224
+ function detectTextbookVariableNames(lines) {
1225
+ let textbookNameCount = 0;
1226
+ const textbookNames = [
1227
+ 'firstName', 'first_name', 'lastname', 'last_name',
1228
+ 'emailAddress', 'email_address', 'phoneNumber', 'phone_number',
1229
+ 'userName', 'user_name', 'password', 'confirmPassword',
1230
+ 'startDate', 'endDate', 'createdAt', 'updatedAt',
1231
+ 'userId', 'user_id', 'customerId', 'customer_id',
1232
+ ];
1233
+ lines.forEach(line => {
1234
+ textbookNames.forEach(name => {
1235
+ if (line.includes(name)) {
1236
+ textbookNameCount++;
1237
+ }
1238
+ });
1239
+ });
1240
+ // AI uses textbook names from tutorials
1241
+ return Math.min(textbookNameCount / 5, 1.0); // 5+ textbook names = AI
1242
+ }
1243
+ /**
1244
+ * Perfect Code #4: No comments + perfect structure
1245
+ * Pattern: Production code is messy; AI generates clean, structured code with zero comments
1246
+ */
1247
+ function detectNoCommentsWithPerfectStructure(lines) {
1248
+ let commentCount = 0;
1249
+ let structuralComplexity = 0;
1250
+ lines.forEach(line => {
1251
+ const trimmed = line.trim();
1252
+ // Count comments
1253
+ if (trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('/*')) {
1254
+ commentCount++;
1255
+ }
1256
+ // Count structural elements
1257
+ if (trimmed.includes('function') ||
1258
+ trimmed.includes('def ') ||
1259
+ trimmed.includes('class ') ||
1260
+ trimmed.includes('if (') ||
1261
+ trimmed.includes('for (') ||
1262
+ trimmed.includes('while (')) {
1263
+ structuralComplexity++;
1264
+ }
1265
+ });
1266
+ // AI signature: >10 structural elements with <2 comments
1267
+ if (structuralComplexity > 10 && commentCount < 2) {
1268
+ return 1.0;
1269
+ }
1270
+ else if (structuralComplexity > 5 && commentCount === 0) {
1271
+ return 0.5;
1272
+ }
1273
+ return 0;
1274
+ }
1275
+ /**
1276
+ * Perfect Code #5: Excessive parameter validation
1277
+ * Pattern: AI validates every parameter, even in private functions
1278
+ */
1279
+ function detectExcessiveParameterValidation(lines) {
1280
+ let functionCount = 0;
1281
+ let functionsWithParamValidation = 0;
1282
+ let inFunction = false;
1283
+ let currentFunctionHasValidation = false;
1284
+ let linesIntoFunction = 0;
1285
+ lines.forEach(line => {
1286
+ const trimmed = line.trim();
1287
+ // Detect function start
1288
+ if (trimmed.match(/^function\s+\w+\s*\(/) ||
1289
+ trimmed.match(/^def\s+\w+\s*\(/) ||
1290
+ trimmed.match(/^(public|private|protected)?\s*\w+\s+\w+\s*\(/)) {
1291
+ if (inFunction && currentFunctionHasValidation) {
1292
+ functionsWithParamValidation++;
1293
+ }
1294
+ inFunction = true;
1295
+ currentFunctionHasValidation = false;
1296
+ linesIntoFunction = 0;
1297
+ functionCount++;
1298
+ }
1299
+ // Check for parameter validation in first 5 lines of function
1300
+ if (inFunction && linesIntoFunction < 5) {
1301
+ if (trimmed.includes('if (!') ||
1302
+ trimmed.includes('if (typeof') ||
1303
+ trimmed.includes('if (') && (trimmed.includes('=== null') || trimmed.includes('=== undefined')) ||
1304
+ trimmed.includes('throw') && trimmed.includes('Invalid') ||
1305
+ trimmed.includes('raise') && (trimmed.includes('ValueError') || trimmed.includes('TypeError'))) {
1306
+ currentFunctionHasValidation = true;
1307
+ }
1308
+ linesIntoFunction++;
1309
+ }
1310
+ // Detect function end
1311
+ if (trimmed === '}' && inFunction) {
1312
+ if (currentFunctionHasValidation) {
1313
+ functionsWithParamValidation++;
1314
+ }
1315
+ inFunction = false;
1316
+ currentFunctionHasValidation = false;
1317
+ }
1318
+ });
1319
+ // AI validates >70% of functions (even private ones)
1320
+ const validationRatio = functionCount > 0 ? functionsWithParamValidation / functionCount : 0;
1321
+ return validationRatio > 0.7 ? 1.0 : validationRatio / 0.7;
1322
+ }
1323
+ /**
1324
+ * Calculate confidence score from hallucination count, heuristics, and LLM fingerprints
1325
+ *
1326
+ * Scoring weights:
1327
+ * - Hallucination patterns: 60% (strongest signal - causes runtime errors)
1328
+ * - Code smell heuristics: 25% (structural patterns)
1329
+ * - LLM fingerprints: 15% (behavioral patterns)
1330
+ */
1331
+ function calculateAICodeConfidence(hallucinationCount, heuristicScores, llmFingerprintScores) {
1332
+ // Calculate weighted heuristic score (13 heuristics total)
1333
+ const heuristicScore =
1334
+ // Original 8 heuristics
1335
+ heuristicScores.overEngineeredErrors * HEURISTIC_WEIGHTS.overEngineeredErrors +
298
1336
  heuristicScores.unnecessaryWrappers * HEURISTIC_WEIGHTS.unnecessaryWrappers +
299
1337
  heuristicScores.verboseComments * HEURISTIC_WEIGHTS.verboseComments +
300
1338
  heuristicScores.mixedNaming * HEURISTIC_WEIGHTS.mixedNaming +
301
1339
  heuristicScores.redundantNullChecks * HEURISTIC_WEIGHTS.redundantNullChecks +
302
1340
  heuristicScores.unnecessaryAsync * HEURISTIC_WEIGHTS.unnecessaryAsync +
303
1341
  heuristicScores.genericVariables * HEURISTIC_WEIGHTS.genericVariables +
304
- heuristicScores.inconsistentStrings * HEURISTIC_WEIGHTS.inconsistentStrings;
305
- // HIGH confidence: 2+ hallucinations OR 1 hallucination + strong heuristics
306
- if (hallucinationCount >= 2 || (hallucinationCount >= 1 && heuristicScore >= 0.5)) {
1342
+ heuristicScores.inconsistentStrings * HEURISTIC_WEIGHTS.inconsistentStrings +
1343
+ // Perfect code heuristics (5 new)
1344
+ heuristicScores.zeroEdgeCases * HEURISTIC_WEIGHTS.zeroEdgeCases +
1345
+ heuristicScores.uniformIndentation * HEURISTIC_WEIGHTS.uniformIndentation +
1346
+ heuristicScores.textbookVariableNames * HEURISTIC_WEIGHTS.textbookVariableNames +
1347
+ heuristicScores.noCommentsWithPerfectStructure * HEURISTIC_WEIGHTS.noCommentsWithPerfectStructure +
1348
+ heuristicScores.excessiveParameterValidation * HEURISTIC_WEIGHTS.excessiveParameterValidation;
1349
+ // Calculate weighted LLM fingerprint scores (all 4 LLM tools)
1350
+ let llmFingerprintScore = 0;
1351
+ if (llmFingerprintScores) {
1352
+ // GPT-4 fingerprints
1353
+ const gpt4Score = (llmFingerprintScores.verboseDocstrings || 0) * GPT4_FINGERPRINT_WEIGHTS.verboseDocstrings +
1354
+ (llmFingerprintScores.defensiveNullChecks || 0) * GPT4_FINGERPRINT_WEIGHTS.defensiveNullChecks +
1355
+ (llmFingerprintScores.excessiveTryCatch || 0) * GPT4_FINGERPRINT_WEIGHTS.excessiveTryCatch +
1356
+ (llmFingerprintScores.helperFunctionProliferation || 0) * GPT4_FINGERPRINT_WEIGHTS.helperFunctionProliferation +
1357
+ (llmFingerprintScores.overlyDescriptiveNames || 0) * GPT4_FINGERPRINT_WEIGHTS.overlyDescriptiveNames +
1358
+ (llmFingerprintScores.prematureOptimizationComments || 0) * GPT4_FINGERPRINT_WEIGHTS.prematureOptimizationComments +
1359
+ (llmFingerprintScores.detailedTodoMarkers || 0) * GPT4_FINGERPRINT_WEIGHTS.detailedTodoMarkers +
1360
+ (llmFingerprintScores.typeAnnotationOveruse || 0) * GPT4_FINGERPRINT_WEIGHTS.typeAnnotationOveruse;
1361
+ // GitHub Copilot fingerprints (equal weight to GPT-4)
1362
+ const copilotScore = (llmFingerprintScores.boilerplateComments || 0) * 0.15 +
1363
+ (llmFingerprintScores.placeholderTodos || 0) * 0.14 +
1364
+ (llmFingerprintScores.genericFunctionNames || 0) * 0.15 +
1365
+ (llmFingerprintScores.placeholderConstants || 0) * 0.14 +
1366
+ (llmFingerprintScores.unusualImportOrdering || 0) * 0.14 +
1367
+ (llmFingerprintScores.copilotMarkers || 0) * 0.14 +
1368
+ (llmFingerprintScores.excessiveTypeAssertions || 0) * 0.14;
1369
+ // Claude Code fingerprints (equal weight to GPT-4)
1370
+ const claudeScore = (llmFingerprintScores.detailedExplanatoryComments || 0) * 0.20 +
1371
+ (llmFingerprintScores.customErrorClasses || 0) * 0.20 +
1372
+ (llmFingerprintScores.extensiveInputValidation || 0) * 0.20 +
1373
+ (llmFingerprintScores.descriptiveHelperFunctions || 0) * 0.20 +
1374
+ (llmFingerprintScores.structuredReturnObjects || 0) * 0.20;
1375
+ // Cursor fingerprints
1376
+ const cursorScore = (llmFingerprintScores.aiCommandMarkers || 0) * CURSOR_FINGERPRINT_WEIGHTS.aiCommandMarkers +
1377
+ (llmFingerprintScores.diffStyleComments || 0) * CURSOR_FINGERPRINT_WEIGHTS.diffStyleComments +
1378
+ (llmFingerprintScores.tabCompletionArtifacts || 0) * CURSOR_FINGERPRINT_WEIGHTS.tabCompletionArtifacts +
1379
+ (llmFingerprintScores.contextWindowLeakage || 0) * CURSOR_FINGERPRINT_WEIGHTS.contextWindowLeakage +
1380
+ (llmFingerprintScores.overGenericExports || 0) * CURSOR_FINGERPRINT_WEIGHTS.overGenericExports +
1381
+ (llmFingerprintScores.unusedImportCleanup || 0) * CURSOR_FINGERPRINT_WEIGHTS.unusedImportCleanup +
1382
+ (llmFingerprintScores.placeholderErrorMessages || 0) * CURSOR_FINGERPRINT_WEIGHTS.placeholderErrorMessages +
1383
+ (llmFingerprintScores.inlineDocumentationOverload || 0) * CURSOR_FINGERPRINT_WEIGHTS.inlineDocumentationOverload;
1384
+ // Average all LLM tool scores (equal weight per tool)
1385
+ llmFingerprintScore = (gpt4Score + copilotScore + claudeScore + cursorScore) / 4;
1386
+ }
1387
+ // Combined weighted score (hallucinations 60%, heuristics 25%, LLM fingerprints 15%)
1388
+ const hallucinationWeight = hallucinationCount > 0 ? Math.min(hallucinationCount / 3, 1.0) : 0;
1389
+ const combinedScore = (hallucinationWeight * 0.6) + (heuristicScore * 0.25) + (llmFingerprintScore * 0.15);
1390
+ // HIGH confidence: 2+ hallucinations OR combined score >= 0.6
1391
+ if (hallucinationCount >= 2 || combinedScore >= 0.6) {
307
1392
  return {
308
1393
  hallucinationPatterns: hallucinationCount,
309
- heuristicScore,
1394
+ heuristicScore: combinedScore,
310
1395
  confidence: 'HIGH',
311
1396
  severity: 'CRITICAL',
312
1397
  };
313
1398
  }
314
- // MEDIUM confidence: 1 hallucination OR strong heuristics
315
- if (hallucinationCount === 1 || heuristicScore >= 0.4) {
1399
+ // MEDIUM confidence: 1 hallucination OR combined score >= 0.4
1400
+ if (hallucinationCount === 1 || combinedScore >= 0.4) {
316
1401
  return {
317
1402
  hallucinationPatterns: hallucinationCount,
318
- heuristicScore,
1403
+ heuristicScore: combinedScore,
319
1404
  confidence: 'MEDIUM',
320
1405
  severity: 'HIGH',
321
1406
  };
322
1407
  }
323
- // LOW confidence: Weak heuristics only
324
- if (heuristicScore >= 0.25) {
1408
+ // LOW confidence: Weak signals (combined score >= 0.25)
1409
+ if (combinedScore >= 0.25) {
325
1410
  return {
326
1411
  hallucinationPatterns: 0,
327
- heuristicScore,
1412
+ heuristicScore: combinedScore,
328
1413
  confidence: 'LOW',
329
1414
  severity: 'MEDIUM',
330
1415
  };