fivocell 4.0.0 → 4.1.1

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 (166) hide show
  1. package/dist/__tests__/behavior-intelligence-bug.test.d.ts +2 -0
  2. package/dist/__tests__/behavior-intelligence-bug.test.d.ts.map +1 -0
  3. package/dist/__tests__/behavior-intelligence-bug.test.js +21 -0
  4. package/dist/__tests__/behavior-intelligence-bug.test.js.map +1 -0
  5. package/dist/__tests__/code-scanner-arrow-return-type.test.d.ts +2 -0
  6. package/dist/__tests__/code-scanner-arrow-return-type.test.d.ts.map +1 -0
  7. package/dist/__tests__/code-scanner-arrow-return-type.test.js +76 -0
  8. package/dist/__tests__/code-scanner-arrow-return-type.test.js.map +1 -0
  9. package/dist/__tests__/code-scanner-blindspot.test.d.ts +2 -0
  10. package/dist/__tests__/code-scanner-blindspot.test.d.ts.map +1 -0
  11. package/dist/__tests__/code-scanner-blindspot.test.js +18 -0
  12. package/dist/__tests__/code-scanner-blindspot.test.js.map +1 -0
  13. package/dist/__tests__/code-scanner-error-recovery.test.d.ts +2 -0
  14. package/dist/__tests__/code-scanner-error-recovery.test.d.ts.map +1 -0
  15. package/dist/__tests__/code-scanner-error-recovery.test.js +21 -0
  16. package/dist/__tests__/code-scanner-error-recovery.test.js.map +1 -0
  17. package/dist/__tests__/code-scanner-n1-detection.test.d.ts +2 -0
  18. package/dist/__tests__/code-scanner-n1-detection.test.d.ts.map +1 -0
  19. package/dist/__tests__/code-scanner-n1-detection.test.js +113 -0
  20. package/dist/__tests__/code-scanner-n1-detection.test.js.map +1 -0
  21. package/dist/__tests__/code-scanner-nesting.test.d.ts +2 -0
  22. package/dist/__tests__/code-scanner-nesting.test.d.ts.map +1 -0
  23. package/dist/__tests__/code-scanner-nesting.test.js +113 -0
  24. package/dist/__tests__/code-scanner-nesting.test.js.map +1 -0
  25. package/dist/__tests__/code-scanner-null-check.test.d.ts +2 -0
  26. package/dist/__tests__/code-scanner-null-check.test.d.ts.map +1 -0
  27. package/dist/__tests__/code-scanner-null-check.test.js +126 -0
  28. package/dist/__tests__/code-scanner-null-check.test.js.map +1 -0
  29. package/dist/__tests__/code-scanner-sql-fix.test.d.ts +2 -0
  30. package/dist/__tests__/code-scanner-sql-fix.test.d.ts.map +1 -0
  31. package/dist/__tests__/code-scanner-sql-fix.test.js +21 -0
  32. package/dist/__tests__/code-scanner-sql-fix.test.js.map +1 -0
  33. package/dist/__tests__/code-scanner-trust-score.test.d.ts +1 -0
  34. package/dist/__tests__/code-scanner-trust-score.test.d.ts.map +1 -0
  35. package/dist/__tests__/code-scanner-trust-score.test.js +39 -0
  36. package/dist/__tests__/code-scanner-trust-score.test.js.map +1 -0
  37. package/dist/__tests__/code-scanner-validation.test.d.ts +2 -0
  38. package/dist/__tests__/code-scanner-validation.test.d.ts.map +1 -0
  39. package/dist/__tests__/code-scanner-validation.test.js +131 -0
  40. package/dist/__tests__/code-scanner-validation.test.js.map +1 -0
  41. package/dist/__tests__/community-store.test.d.ts +2 -0
  42. package/dist/__tests__/community-store.test.d.ts.map +1 -0
  43. package/dist/__tests__/community-store.test.js +231 -0
  44. package/dist/__tests__/community-store.test.js.map +1 -0
  45. package/dist/__tests__/enhanced-blind-spots.test.d.ts +2 -0
  46. package/dist/__tests__/enhanced-blind-spots.test.d.ts.map +1 -0
  47. package/dist/__tests__/enhanced-blind-spots.test.js +347 -0
  48. package/dist/__tests__/enhanced-blind-spots.test.js.map +1 -0
  49. package/dist/__tests__/knowledge-graph-store.test.d.ts +2 -0
  50. package/dist/__tests__/knowledge-graph-store.test.d.ts.map +1 -0
  51. package/dist/__tests__/knowledge-graph-store.test.js +252 -0
  52. package/dist/__tests__/knowledge-graph-store.test.js.map +1 -0
  53. package/dist/__tests__/live-watcher.test.d.ts +2 -0
  54. package/dist/__tests__/live-watcher.test.d.ts.map +1 -0
  55. package/dist/__tests__/live-watcher.test.js +312 -0
  56. package/dist/__tests__/live-watcher.test.js.map +1 -0
  57. package/dist/__tests__/mcp-cell-tools.test.d.ts +2 -0
  58. package/dist/__tests__/mcp-cell-tools.test.d.ts.map +1 -0
  59. package/dist/__tests__/mcp-cell-tools.test.js +176 -0
  60. package/dist/__tests__/mcp-cell-tools.test.js.map +1 -0
  61. package/dist/__tests__/multi-project.test.d.ts +2 -0
  62. package/dist/__tests__/multi-project.test.d.ts.map +1 -0
  63. package/dist/__tests__/multi-project.test.js +145 -0
  64. package/dist/__tests__/multi-project.test.js.map +1 -0
  65. package/dist/__tests__/pc-scanner-paths.test.d.ts +2 -0
  66. package/dist/__tests__/pc-scanner-paths.test.d.ts.map +1 -0
  67. package/dist/__tests__/pc-scanner-paths.test.js +16 -0
  68. package/dist/__tests__/pc-scanner-paths.test.js.map +1 -0
  69. package/dist/__tests__/prompt-builder-realdata.test.d.ts +2 -0
  70. package/dist/__tests__/prompt-builder-realdata.test.d.ts.map +1 -0
  71. package/dist/__tests__/prompt-builder-realdata.test.js +94 -0
  72. package/dist/__tests__/prompt-builder-realdata.test.js.map +1 -0
  73. package/dist/__tests__/prompt-builder-sessions.test.d.ts +2 -0
  74. package/dist/__tests__/prompt-builder-sessions.test.d.ts.map +1 -0
  75. package/dist/__tests__/prompt-builder-sessions.test.js +124 -0
  76. package/dist/__tests__/prompt-builder-sessions.test.js.map +1 -0
  77. package/dist/__tests__/security.test.d.ts +1 -0
  78. package/dist/__tests__/security.test.d.ts.map +1 -0
  79. package/dist/__tests__/security.test.js +161 -0
  80. package/dist/__tests__/security.test.js.map +1 -0
  81. package/dist/__tests__/session-bridge.test.d.ts +2 -0
  82. package/dist/__tests__/session-bridge.test.d.ts.map +1 -0
  83. package/dist/__tests__/session-bridge.test.js +158 -0
  84. package/dist/__tests__/session-bridge.test.js.map +1 -0
  85. package/dist/__tests__/session-memory-tables.test.d.ts +2 -0
  86. package/dist/__tests__/session-memory-tables.test.d.ts.map +1 -0
  87. package/dist/__tests__/session-memory-tables.test.js +169 -0
  88. package/dist/__tests__/session-memory-tables.test.js.map +1 -0
  89. package/dist/__tests__/staleness-detection.test.d.ts +2 -0
  90. package/dist/__tests__/staleness-detection.test.d.ts.map +1 -0
  91. package/dist/__tests__/staleness-detection.test.js +105 -0
  92. package/dist/__tests__/staleness-detection.test.js.map +1 -0
  93. package/dist/__tests__/team-collaboration.test.d.ts +2 -0
  94. package/dist/__tests__/team-collaboration.test.d.ts.map +1 -0
  95. package/dist/__tests__/team-collaboration.test.js +224 -0
  96. package/dist/__tests__/team-collaboration.test.js.map +1 -0
  97. package/dist/__tests__/tool-specific-format.test.d.ts +2 -0
  98. package/dist/__tests__/tool-specific-format.test.d.ts.map +1 -0
  99. package/dist/__tests__/tool-specific-format.test.js +130 -0
  100. package/dist/__tests__/tool-specific-format.test.js.map +1 -0
  101. package/dist/__tests__/usage-intelligence-store.test.d.ts +2 -0
  102. package/dist/__tests__/usage-intelligence-store.test.d.ts.map +1 -0
  103. package/dist/__tests__/usage-intelligence-store.test.js +266 -0
  104. package/dist/__tests__/usage-intelligence-store.test.js.map +1 -0
  105. package/dist/behavior-intelligence.d.ts.map +1 -1
  106. package/dist/behavior-intelligence.js +12 -1
  107. package/dist/behavior-intelligence.js.map +1 -1
  108. package/dist/cli.js +403 -4
  109. package/dist/cli.js.map +1 -1
  110. package/dist/code-scanner.d.ts.map +1 -1
  111. package/dist/code-scanner.js +344 -102
  112. package/dist/code-scanner.js.map +1 -1
  113. package/dist/core/community-store.d.ts +128 -0
  114. package/dist/core/community-store.d.ts.map +1 -0
  115. package/dist/core/community-store.js +329 -0
  116. package/dist/core/community-store.js.map +1 -0
  117. package/dist/core/database.d.ts +0 -3
  118. package/dist/core/database.d.ts.map +1 -1
  119. package/dist/core/database.js +287 -15
  120. package/dist/core/database.js.map +1 -1
  121. package/dist/core/enhanced-blind-spots.d.ts +27 -0
  122. package/dist/core/enhanced-blind-spots.d.ts.map +1 -0
  123. package/dist/core/enhanced-blind-spots.js +710 -0
  124. package/dist/core/enhanced-blind-spots.js.map +1 -0
  125. package/dist/core/knowledge-graph-store.d.ts +69 -0
  126. package/dist/core/knowledge-graph-store.d.ts.map +1 -0
  127. package/dist/core/knowledge-graph-store.js +269 -0
  128. package/dist/core/knowledge-graph-store.js.map +1 -0
  129. package/dist/core/live-watcher.d.ts +52 -0
  130. package/dist/core/live-watcher.d.ts.map +1 -0
  131. package/dist/core/live-watcher.js +369 -0
  132. package/dist/core/live-watcher.js.map +1 -0
  133. package/dist/core/project-registry.d.ts +24 -0
  134. package/dist/core/project-registry.d.ts.map +1 -0
  135. package/dist/core/project-registry.js +70 -0
  136. package/dist/core/project-registry.js.map +1 -0
  137. package/dist/core/prompt-builder.d.ts +49 -0
  138. package/dist/core/prompt-builder.d.ts.map +1 -1
  139. package/dist/core/prompt-builder.js +540 -67
  140. package/dist/core/prompt-builder.js.map +1 -1
  141. package/dist/core/security.d.ts +23 -0
  142. package/dist/core/security.d.ts.map +1 -0
  143. package/dist/core/security.js +117 -0
  144. package/dist/core/security.js.map +1 -0
  145. package/dist/core/session-memory.d.ts +64 -0
  146. package/dist/core/session-memory.d.ts.map +1 -1
  147. package/dist/core/session-memory.js +111 -0
  148. package/dist/core/session-memory.js.map +1 -1
  149. package/dist/core/syntax-engine.d.ts.map +1 -1
  150. package/dist/core/syntax-engine.js +5 -2
  151. package/dist/core/syntax-engine.js.map +1 -1
  152. package/dist/core/usage-intelligence-store.d.ts +126 -0
  153. package/dist/core/usage-intelligence-store.d.ts.map +1 -0
  154. package/dist/core/usage-intelligence-store.js +405 -0
  155. package/dist/core/usage-intelligence-store.js.map +1 -0
  156. package/dist/daemon/server.d.ts.map +1 -1
  157. package/dist/daemon/server.js +936 -17
  158. package/dist/daemon/server.js.map +1 -1
  159. package/dist/knowledge-graph-builder.d.ts.map +1 -1
  160. package/dist/knowledge-graph-builder.js +18 -2
  161. package/dist/knowledge-graph-builder.js.map +1 -1
  162. package/dist/pc-scanner.d.ts +1 -0
  163. package/dist/pc-scanner.d.ts.map +1 -1
  164. package/dist/pc-scanner.js +64 -33
  165. package/dist/pc-scanner.js.map +1 -1
  166. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"code-scanner.d.ts","sourceRoot":"","sources":["../src/code-scanner.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AA+wBD,iBAAS,sBAAsB,IAAI,IAAI,CA4CtC;AA+DD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CA4G9E;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAuB5E;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE,CAgBjF;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAkD3D;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAelE;AAED,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
1
+ {"version":3,"file":"code-scanner.d.ts","sourceRoot":"","sources":["../src/code-scanner.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AA03BD,iBAAS,sBAAsB,IAAI,IAAI,CA4CtC;AAmFD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CAwO9E;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAuB5E;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE,CAgBjF;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAkD3D;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAelE;AAED,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
@@ -41,6 +41,7 @@ exports.formatScanReportCompact = formatScanReportCompact;
41
41
  exports.ensureCodePatternTable = ensureCodePatternTable;
42
42
  const fs = __importStar(require("fs"));
43
43
  const path = __importStar(require("path"));
44
+ const os = __importStar(require("os"));
44
45
  const ts = __importStar(require("typescript"));
45
46
  const database_1 = require("./core/database");
46
47
  const stack_detector_1 = require("./stack-detector");
@@ -238,9 +239,12 @@ function extractCodeStyle(content) {
238
239
  }
239
240
  if (trimmed.includes('`') && (trimmed.includes('${') || trimmed.split('`').length > 2))
240
241
  backtickStrings++;
241
- if (trimmed.endsWith(';'))
242
+ if (/^[}\])]/.test(trimmed) || trimmed.length === 0) {
243
+ // skip — not a statement line
244
+ }
245
+ else if (trimmed.endsWith(';'))
242
246
  semicolons++;
243
- else if (trimmed.length > 0 && /[a-zA-Z0-9"'})\]]/.test(trimmed))
247
+ else if (trimmed.length > 0 && /[a-zA-Z0-9"'`]/.test(trimmed))
244
248
  noSemicolons++;
245
249
  }
246
250
  if (/^\t/.test(line))
@@ -265,10 +269,12 @@ function extractCodeStyle(content) {
265
269
  patterns.push({ type: 'style_template', category: 'style', value: 'template-literals', count: backtickStrings, trustScore: 85 });
266
270
  const codeLines = semicolons + noSemicolons;
267
271
  if (codeLines > 0) {
268
- if (semicolons > noSemicolons * 1.5)
272
+ if (semicolons > noSemicolons)
269
273
  patterns.push({ type: 'style_semicolons', category: 'style', value: 'always', count: semicolons, trustScore: 90 });
270
- else if (noSemicolons > semicolons * 1.5)
274
+ else if (noSemicolons > semicolons)
271
275
  patterns.push({ type: 'style_semicolons', category: 'style', value: 'never', count: noSemicolons, trustScore: 90 });
276
+ else
277
+ patterns.push({ type: 'style_semicolons', category: 'style', value: 'mixed', count: semicolons + noSemicolons, trustScore: 70 });
272
278
  }
273
279
  if (tabs > twoSpaces + fourSpaces)
274
280
  patterns.push({ type: 'style_indent', category: 'style', value: 'tabs', count: tabs, trustScore: 90 });
@@ -395,6 +401,8 @@ function extractASTPatterns(content, filePath) {
395
401
  let zodImports = false;
396
402
  let nestDepth = 0;
397
403
  let maxNestDepth = 0;
404
+ let controlFlowDepth = 0;
405
+ let maxControlFlowDepth = 0;
398
406
  let nPlusOne = 0;
399
407
  let hardcodedSecrets = 0;
400
408
  let missingNullCheck = 0;
@@ -402,6 +410,23 @@ function extractASTPatterns(content, filePath) {
402
410
  const visit = (node, depth) => {
403
411
  nestDepth = Math.max(nestDepth, depth);
404
412
  maxNestDepth = Math.max(maxNestDepth, depth);
413
+ const isControlFlow = ts.isIfStatement(node) ||
414
+ ts.isForStatement(node) ||
415
+ ts.isForInStatement(node) ||
416
+ ts.isForOfStatement(node) ||
417
+ ts.isWhileStatement(node) ||
418
+ ts.isDoStatement(node) ||
419
+ ts.isSwitchStatement(node) ||
420
+ ts.isTryStatement(node) ||
421
+ ts.isConditionalExpression(node);
422
+ if (isControlFlow) {
423
+ controlFlowDepth = depth;
424
+ maxControlFlowDepth = Math.max(maxControlFlowDepth, depth);
425
+ }
426
+ if (isControlFlow) {
427
+ ts.forEachChild(node, (child) => visit(child, depth + 1));
428
+ return;
429
+ }
405
430
  // ── Async without try/catch ──────────────────────────────────────
406
431
  if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node)) {
407
432
  const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
@@ -419,7 +444,10 @@ function extractASTPatterns(content, filePath) {
419
444
  if (!hasTryCatch)
420
445
  asyncNoTryCatch++;
421
446
  // Return type check
422
- if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
447
+ if (ts.isFunctionDeclaration(node) ||
448
+ ts.isMethodDeclaration(node) ||
449
+ ts.isFunctionExpression(node) ||
450
+ ts.isArrowFunction(node)) {
423
451
  const hasReturnType = node.type !== undefined;
424
452
  if (hasReturnType)
425
453
  functionsWithType++;
@@ -462,13 +490,16 @@ function extractASTPatterns(content, filePath) {
462
490
  const callText = expr.getText();
463
491
  if (callText.includes('.find') || callText.includes('.query') || callText.includes('.execute') ||
464
492
  callText.includes('fetch') || callText.includes('prisma.') || callText.includes('db.')) {
465
- // Check if we're inside a loop
466
493
  let parent = node.parent;
467
494
  while (parent) {
468
- const parentText = parent.getText().substring(0, 50);
469
- if (parentText.includes('for (') || parentText.includes('while (') ||
470
- parentText.includes('.map(') || parentText.includes('.forEach(') ||
471
- parentText.includes('for...of')) {
495
+ if (ts.isForStatement(parent) ||
496
+ ts.isForInStatement(parent) ||
497
+ ts.isForOfStatement(parent) ||
498
+ ts.isWhileStatement(parent) ||
499
+ ts.isDoStatement(parent) ||
500
+ (ts.isCallExpression(parent) &&
501
+ ts.isPropertyAccessExpression(parent.expression) &&
502
+ (parent.expression.name.text === 'map' || parent.expression.name.text === 'forEach'))) {
472
503
  nPlusOne++;
473
504
  break;
474
505
  }
@@ -476,21 +507,48 @@ function extractASTPatterns(content, filePath) {
476
507
  }
477
508
  }
478
509
  }
479
- // Missing null check detection — data access after API call
480
- if (ts.isPropertyAccessExpression(expr) && expr.name.text === 'data') {
481
- const callText = expr.expression.getText();
482
- if (callText.includes('fetch') || callText.includes('axios') || callText.includes('request') ||
483
- callText.includes('http.get') || callText.includes('.get(')) {
484
- let parent = node.parent;
510
+ // Missing null check detection — any property access on awaited API call
511
+ if (ts.isPropertyAccessExpression(expr)) {
512
+ let base = expr.expression;
513
+ while (ts.isPropertyAccessExpression(base))
514
+ base = base.expression;
515
+ const baseText = base.getText();
516
+ if (baseText.includes('fetch') ||
517
+ baseText.includes('axios') ||
518
+ baseText.includes('request') ||
519
+ baseText.includes('http.get') ||
520
+ baseText.includes('prisma.') ||
521
+ baseText.includes('db.')) {
522
+ let hasAwait = false;
485
523
  let hasNullCheck = false;
486
- while (parent && !hasNullCheck) {
487
- const pText = parent.getText().substring(0, 100);
488
- if (pText.includes('if (') && (pText.includes('!') || pText.includes('null') || pText.includes('undefined') || pText.includes('?.'))) {
489
- hasNullCheck = true;
524
+ let ancestor = expr.parent;
525
+ while (ancestor && (!hasAwait || !hasNullCheck)) {
526
+ if (ts.isAwaitExpression(ancestor))
527
+ hasAwait = true;
528
+ if (ts.isExpressionStatement(ancestor) || ts.isVariableDeclaration(ancestor))
529
+ break;
530
+ if (ts.isIfStatement(ancestor)) {
531
+ const condText = ancestor.expression.getText();
532
+ if (condText.includes('!') ||
533
+ condText.includes('null') ||
534
+ condText.includes('undefined') ||
535
+ condText.includes('?.')) {
536
+ hasNullCheck = true;
537
+ }
490
538
  }
491
- parent = parent.parent;
539
+ if (ts.isBinaryExpression(ancestor) &&
540
+ (ancestor.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken ||
541
+ ancestor.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken ||
542
+ ancestor.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken ||
543
+ ancestor.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken)) {
544
+ const text = ancestor.getText();
545
+ if (text.includes('null') || text.includes('undefined')) {
546
+ hasNullCheck = true;
547
+ }
548
+ }
549
+ ancestor = ancestor.parent;
492
550
  }
493
- if (!hasNullCheck)
551
+ if (hasAwait && !hasNullCheck)
494
552
  missingNullCheck++;
495
553
  }
496
554
  }
@@ -510,10 +568,29 @@ function extractASTPatterns(content, filePath) {
510
568
  }
511
569
  }
512
570
  // ── Missing input validation in API handlers ────────────────────
513
- if (ts.isFunctionDeclaration(node)) {
514
- const funcNode = node;
515
- const funcName = funcNode.name ? funcNode.name.text : '';
516
- if (funcName.includes('handler') || funcName.includes('route') || funcName.includes('endpoint') || funcName.includes('controller')) {
571
+ const isHandlerLike = ts.isFunctionDeclaration(node) ||
572
+ ts.isFunctionExpression(node) ||
573
+ ts.isArrowFunction(node);
574
+ if (isHandlerLike) {
575
+ let funcName = '';
576
+ let body;
577
+ if (ts.isFunctionDeclaration(node) && node.name) {
578
+ funcName = node.name.text;
579
+ body = node.body;
580
+ }
581
+ else if (ts.isFunctionExpression(node) ||
582
+ ts.isArrowFunction(node)) {
583
+ let p = node.parent;
584
+ while (p) {
585
+ if (ts.isVariableDeclaration(p) && ts.isIdentifier(p.name)) {
586
+ funcName = p.name.text;
587
+ break;
588
+ }
589
+ p = p.parent;
590
+ }
591
+ body = node.body;
592
+ }
593
+ if (funcName.toLowerCase().includes('handler') || funcName.toLowerCase().includes('route') || funcName.toLowerCase().includes('endpoint') || funcName.toLowerCase().includes('controller')) {
517
594
  let hasValidation = false;
518
595
  const checkBody = (n) => {
519
596
  if (ts.isCallExpression(n)) {
@@ -525,8 +602,8 @@ function extractASTPatterns(content, filePath) {
525
602
  }
526
603
  ts.forEachChild(n, checkBody);
527
604
  };
528
- if (funcNode.body)
529
- checkBody(funcNode.body);
605
+ if (body)
606
+ checkBody(body);
530
607
  if (!hasValidation)
531
608
  missingInputValidation++;
532
609
  }
@@ -583,12 +660,12 @@ function extractASTPatterns(content, filePath) {
583
660
  trustScore: 85,
584
661
  });
585
662
  }
586
- if (maxNestDepth > 4) {
663
+ if (maxControlFlowDepth > 4) {
587
664
  patterns.push({
588
665
  type: 'blind_spot_deep_nesting',
589
666
  category: 'blind_spots',
590
- value: `max_nesting:${maxNestDepth}`,
591
- count: maxNestDepth,
667
+ value: `max_nesting:${maxControlFlowDepth}`,
668
+ count: maxControlFlowDepth,
592
669
  trustScore: 80,
593
670
  });
594
671
  }
@@ -716,8 +793,9 @@ function aggregatePatterns(analyses) {
716
793
  const key = `${pattern.type}:${pattern.value}`;
717
794
  const existing = patternMap.get(key);
718
795
  if (existing) {
719
- existing.count += pattern.count;
720
- existing.trustScore = Math.min(95, Math.round((existing.trustScore + pattern.trustScore) / 2));
796
+ const totalCount = existing.count + pattern.count;
797
+ existing.trustScore = Math.min(95, Math.round((existing.trustScore * existing.count + pattern.trustScore * pattern.count) / totalCount));
798
+ existing.count = totalCount;
721
799
  }
722
800
  else {
723
801
  patternMap.set(key, { ...pattern });
@@ -730,7 +808,31 @@ function buildDeveloperProfile(patterns) {
730
808
  const getByType = (type) => patterns.filter(p => p.type === type);
731
809
  const getTopValue = (type) => {
732
810
  const matches = getByType(type);
733
- return matches.length > 0 ? matches[0].value : 'unknown';
811
+ if (matches.length === 0)
812
+ return 'unknown';
813
+ // Sum counts per unique value, then return the value with highest total count
814
+ const sums = new Map();
815
+ for (const m of matches)
816
+ sums.set(m.value, (sums.get(m.value) || 0) + m.count);
817
+ let best = matches[0].value;
818
+ let bestCount = 0;
819
+ for (const [v, c] of sums)
820
+ if (c > bestCount) {
821
+ best = v;
822
+ bestCount = c;
823
+ }
824
+ // For semicolons, normalize: if "always" is at least 35% of (always + never), prefer "always"
825
+ // because the "noSemi" counter is inflated by multi-line statements
826
+ if (type === 'style_semicolons') {
827
+ const always = sums.get('always') || 0;
828
+ const never = sums.get('never') || 0;
829
+ if (always + never > 0 && always / (always + never) >= 0.35)
830
+ return 'always';
831
+ if (never + always > 0 && never / (always + never) >= 0.7)
832
+ return 'never';
833
+ return 'mixed';
834
+ }
835
+ return best;
734
836
  };
735
837
  const namingPatterns = getByType('naming_style');
736
838
  const namingStyle = namingPatterns.length > 0 ? namingPatterns[0].value : 'mixed';
@@ -844,54 +946,68 @@ function buildDeveloperProfile(patterns) {
844
946
  // ─── Database Storage ────────────────────────────────────────────────────────
845
947
  function ensureCodePatternTable() {
846
948
  const db = (0, database_1.getDb)();
847
- db.exec(`
848
- CREATE TABLE IF NOT EXISTS code_patterns (
849
- id INTEGER PRIMARY KEY AUTOINCREMENT,
850
- project TEXT NOT NULL,
851
- file_path TEXT NOT NULL,
852
- pattern_type TEXT NOT NULL,
853
- pattern_value TEXT NOT NULL,
854
- category TEXT NOT NULL,
855
- count INTEGER DEFAULT 1,
856
- trust_score INTEGER DEFAULT 50,
857
- language TEXT,
858
- created_at TEXT DEFAULT (datetime('now'))
859
- );
860
- CREATE INDEX IF NOT EXISTS idx_code_patterns_project ON code_patterns(project);
861
- CREATE INDEX IF NOT EXISTS idx_code_patterns_type ON code_patterns(pattern_type);
862
- CREATE INDEX IF NOT EXISTS idx_code_patterns_category ON code_patterns(category);
863
-
864
- CREATE TABLE IF NOT EXISTS developer_profiles (
865
- id INTEGER PRIMARY KEY AUTOINCREMENT,
866
- project TEXT NOT NULL UNIQUE,
867
- naming_style TEXT,
868
- import_style TEXT,
869
- export_style TEXT,
870
- error_handling TEXT,
871
- function_style TEXT,
872
- async_style TEXT,
873
- comment_style TEXT,
874
- indent_style TEXT,
875
- quote_style TEXT,
876
- semicolon_style TEXT,
877
- architecture_style TEXT,
878
- test_pattern TEXT,
879
- top_patterns TEXT,
880
- strengths TEXT,
881
- improvements TEXT,
882
- files_scanned INTEGER DEFAULT 0,
883
- total_lines INTEGER DEFAULT 0,
884
- languages TEXT,
885
- scanned_at TEXT DEFAULT (datetime('now'))
886
- );
887
- CREATE INDEX IF NOT EXISTS idx_dev_profile_project ON developer_profiles(project);
949
+ db.exec(`
950
+ CREATE TABLE IF NOT EXISTS code_patterns (
951
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
952
+ project TEXT NOT NULL,
953
+ file_path TEXT NOT NULL,
954
+ pattern_type TEXT NOT NULL,
955
+ pattern_value TEXT NOT NULL,
956
+ category TEXT NOT NULL,
957
+ count INTEGER DEFAULT 1,
958
+ trust_score INTEGER DEFAULT 50,
959
+ language TEXT,
960
+ created_at TEXT DEFAULT (datetime('now'))
961
+ );
962
+ CREATE INDEX IF NOT EXISTS idx_code_patterns_project ON code_patterns(project);
963
+ CREATE INDEX IF NOT EXISTS idx_code_patterns_type ON code_patterns(pattern_type);
964
+ CREATE INDEX IF NOT EXISTS idx_code_patterns_category ON code_patterns(category);
965
+
966
+ CREATE TABLE IF NOT EXISTS developer_profiles (
967
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
968
+ project TEXT NOT NULL UNIQUE,
969
+ naming_style TEXT,
970
+ import_style TEXT,
971
+ export_style TEXT,
972
+ error_handling TEXT,
973
+ function_style TEXT,
974
+ async_style TEXT,
975
+ comment_style TEXT,
976
+ indent_style TEXT,
977
+ quote_style TEXT,
978
+ semicolon_style TEXT,
979
+ architecture_style TEXT,
980
+ test_pattern TEXT,
981
+ top_patterns TEXT,
982
+ strengths TEXT,
983
+ improvements TEXT,
984
+ files_scanned INTEGER DEFAULT 0,
985
+ total_lines INTEGER DEFAULT 0,
986
+ languages TEXT,
987
+ scanned_at TEXT DEFAULT (datetime('now'))
988
+ );
989
+ CREATE INDEX IF NOT EXISTS idx_dev_profile_project ON developer_profiles(project);
888
990
  `);
889
991
  }
890
- function saveToDatabase(project, result) {
992
+ function saveToDatabase(project, result, projectPath) {
891
993
  const db = (0, database_1.getDb)();
892
994
  ensureCodePatternTable();
995
+ try {
996
+ const { ProjectRegistry } = require('./core/project-registry');
997
+ const registry = new ProjectRegistry();
998
+ const stack = Object.keys(result.languages || {}).slice(0, 3).join('+') || 'unknown';
999
+ registry.registerProject({
1000
+ name: project,
1001
+ path: projectPath || project,
1002
+ stack,
1003
+ fileCount: result.filesScanned,
1004
+ });
1005
+ }
1006
+ catch (e) {
1007
+ console.warn('[cell] Project registration failed (non-fatal):', e instanceof Error ? e.message : String(e));
1008
+ }
893
1009
  db.prepare('DELETE FROM code_patterns WHERE project = ?').run(project);
894
- const insertPattern = db.prepare('INSERT INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count, confidence, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
1010
+ const insertPattern = db.prepare('INSERT INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count, trust_score, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
895
1011
  const insertMany = db.transaction((patterns) => {
896
1012
  for (const p of patterns) {
897
1013
  insertPattern.run(project, 'scan', p.type, p.value, p.category, p.count, p.trustScore, '');
@@ -899,16 +1015,23 @@ function saveToDatabase(project, result) {
899
1015
  });
900
1016
  insertMany(result.patterns);
901
1017
  db.prepare('DELETE FROM developer_profiles WHERE project = ?').run(project);
902
- db.prepare(`INSERT INTO developer_profiles
903
- (project, naming_style, import_style, export_style, error_handling, function_style,
904
- async_style, comment_style, indent_style, quote_style, semicolon_style,
905
- architecture_style, test_pattern, top_patterns, strengths, improvements,
906
- files_scanned, total_lines, languages, scanned_at)
1018
+ db.prepare(`INSERT INTO developer_profiles
1019
+ (project, naming_style, import_style, export_style, error_handling, function_style,
1020
+ async_style, comment_style, indent_style, quote_style, semicolon_style,
1021
+ architecture_style, test_pattern, top_patterns, strengths, improvements,
1022
+ files_scanned, total_lines, languages, scanned_at)
907
1023
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))`)
908
1024
  .run(project, result.profile.namingStyle, result.profile.importStyle, result.profile.exportStyle, result.profile.errorHandling, result.profile.functionStyle, result.profile.asyncStyle, result.profile.commentStyle, result.profile.indentStyle, result.profile.quoteStyle, result.profile.semicolonStyle, result.profile.architectureStyle, result.profile.testPattern, JSON.stringify(result.profile.topPatterns), JSON.stringify(result.profile.strengths), JSON.stringify(result.profile.improvements), result.filesScanned, result.totalLines, JSON.stringify(result.languages));
909
- db.prepare(`INSERT OR REPLACE INTO scans (project, scanned_at, file_count, line_count, stack, patterns, hubs, issues)
910
- VALUES (?, datetime('now'), ?, ?, ?, ?, ?, ?)`)
911
- .run(project, result.filesScanned, result.totalLines, JSON.stringify(result.languages), JSON.stringify(result.patterns.slice(0, 20)), JSON.stringify({}), JSON.stringify(result.profile.improvements));
1025
+ try {
1026
+ const stmt = db.prepare(`INSERT OR REPLACE INTO scans (project, scanned_at, file_count, line_count, stack, patterns, hubs, issues)
1027
+ VALUES (?, datetime('now'), ?, ?, ?, ?, ?, ?)`);
1028
+ if (stmt) {
1029
+ stmt.run(project, result.filesScanned, result.totalLines, JSON.stringify(result.languages), JSON.stringify(result.patterns.slice(0, 20)), JSON.stringify({}), JSON.stringify(result.profile.improvements));
1030
+ }
1031
+ }
1032
+ catch (e) {
1033
+ console.warn('[cell] scans table insert failed (schema mismatch, non-fatal):', e instanceof Error ? e.message : String(e));
1034
+ }
912
1035
  }
913
1036
  // ─── Public API ──────────────────────────────────────────────────────────────
914
1037
  function scanCodebase(dirPath, projectName) {
@@ -938,11 +1061,71 @@ function scanCodebase(dirPath, projectName) {
938
1061
  patterns,
939
1062
  profile,
940
1063
  };
941
- saveToDatabase(project, result);
1064
+ saveToDatabase(project, result, dirPath);
1065
+ // ─── PHASE 3: Build Knowledge Graphs (file deps + pattern entities) ───
1066
+ try {
1067
+ const { saveFileKnowledgeGraph, saveTechProficiency } = require('./core/knowledge-graph-store');
1068
+ const fileGraph = saveFileKnowledgeGraph(project, dirPath);
1069
+ // Tech proficiency: use languages + architecture style
1070
+ const archTech = profile.architectureStyle || 'unknown';
1071
+ saveTechProficiency(project, {
1072
+ technology: archTech,
1073
+ category: 'architecture',
1074
+ signalsCount: 1,
1075
+ proficiencyScore: 70,
1076
+ lastSeen: new Date().toISOString(),
1077
+ trend: 'stable',
1078
+ });
1079
+ for (const [lang, count] of Object.entries(languages)) {
1080
+ const score = Math.min(100, 40 + Math.log10(count + 1) * 20);
1081
+ saveTechProficiency(project, {
1082
+ technology: lang,
1083
+ category: 'language',
1084
+ signalsCount: count,
1085
+ proficiencyScore: Math.round(score),
1086
+ lastSeen: new Date().toISOString(),
1087
+ trend: 'stable',
1088
+ });
1089
+ }
1090
+ // Save pattern entities + relationships
1091
+ if (result.patterns && result.patterns.length > 0) {
1092
+ const { savePatternEntities, savePatternRelationships } = require('./core/knowledge-graph-store');
1093
+ const entities = result.patterns.slice(0, 200).map((p, i) => ({
1094
+ id: `${p.category || 'pattern'}-${i}`,
1095
+ type: p.category || 'pattern',
1096
+ label: p.value || '',
1097
+ weight: p.trustScore || 1,
1098
+ }));
1099
+ savePatternEntities(project, entities);
1100
+ // Co-occurrence: patterns in same category from same file are related
1101
+ const filePatterns = new Map();
1102
+ for (let i = 0; i < Math.min(200, result.patterns.length); i++) {
1103
+ const p = result.patterns[i];
1104
+ const f = p.file || 'global';
1105
+ const key = `${f}`;
1106
+ const arr = filePatterns.get(key) || [];
1107
+ arr.push(`${p.category || 'pattern'}-${i}`);
1108
+ filePatterns.set(key, arr);
1109
+ }
1110
+ const edges = [];
1111
+ for (const arr of filePatterns.values()) {
1112
+ for (let i = 0; i < arr.length; i++) {
1113
+ for (let j = i + 1; j < arr.length; j++) {
1114
+ edges.push({ from: arr[i], to: arr[j], type: 'co_occurs', weight: 1 });
1115
+ }
1116
+ }
1117
+ }
1118
+ if (edges.length > 0)
1119
+ savePatternRelationships(project, edges);
1120
+ }
1121
+ }
1122
+ catch (e) {
1123
+ console.warn('[cell] Knowledge graph build failed (non-fatal):', e instanceof Error ? e.message : String(e));
1124
+ }
1125
+ const hookResults = [];
942
1126
  // ─── CONNECT: Scanner → Behavioral Tracker ───────────────────────────────
943
1127
  try {
944
1128
  const { logError, logDecision, logContext } = require('./behavioral-tracker');
945
- // Log blind spots as errors
946
1129
  if (profile.improvements.length > 0) {
947
1130
  for (const imp of profile.improvements) {
948
1131
  logError({
@@ -954,7 +1137,6 @@ function scanCodebase(dirPath, projectName) {
954
1137
  });
955
1138
  }
956
1139
  }
957
- // Log architecture decision
958
1140
  logDecision({
959
1141
  project,
960
1142
  file: 'scan-auto',
@@ -962,55 +1144,115 @@ function scanCodebase(dirPath, projectName) {
962
1144
  approach: `Scan detected ${files.length} files, ${result.languages ? Object.keys(result.languages).join(', ') : 'unknown'}`,
963
1145
  worked: true,
964
1146
  });
965
- // Log current context
966
1147
  logContext({
967
1148
  project,
968
1149
  task: `Codebase scan completed — ${files.length} files, ${totalLines.toLocaleString()} lines`,
969
1150
  files: [dirPath],
970
1151
  });
1152
+ hookResults.push({ hook: 'behavioral-tracker', ok: true });
1153
+ }
1154
+ catch (e) {
1155
+ hookResults.push({ hook: 'behavioral-tracker', ok: false, error: String(e) });
1156
+ console.warn('[cell] Hook failed: behavioral-tracker:', e instanceof Error ? e.message : String(e));
971
1157
  }
972
- catch { /* behavioral tracker may not be initialized yet */ }
973
- // ─── CONNECT: Git Intelligence (behavior + journey + user analysis) ──────
1158
+ // ─── CONNECT: Git Intelligence ──────
974
1159
  try {
975
1160
  const { buildDeveloperIntelligence } = require('./developer-intelligence');
976
1161
  const gitIntel = buildDeveloperIntelligence(dirPath);
977
1162
  if (gitIntel) {
978
1163
  console.log(`[cell] Git intelligence: ${gitIntel.topBlindSpots.length} blind spots, ${gitIntel.topMistakes.length} repeat mistakes, score: ${gitIntel.behavioralScore}/100`);
979
1164
  }
1165
+ hookResults.push({ hook: 'developer-intelligence', ok: true });
980
1166
  }
981
- catch { /* git intelligence may not be available */ }
982
- // ─── CONNECT: Style Pull → Generate .cursorrules, CLAUDE.md, etc. ────
1167
+ catch (e) {
1168
+ hookResults.push({ hook: 'developer-intelligence', ok: false, error: String(e) });
1169
+ console.warn('[cell] Hook failed: developer-intelligence:', e instanceof Error ? e.message : String(e));
1170
+ }
1171
+ // ─── CONNECT: Style Pull ────
983
1172
  try {
984
1173
  const { writeStyleFiles, buildStyleSummary } = require('./style-pull');
985
1174
  const summary = buildStyleSummary(dirPath);
986
- const result = writeStyleFiles(dirPath, summary, { force: false });
987
- if (result.written.length > 0) {
988
- console.log(`[cell] Generated: ${result.written.join(', ')}`);
1175
+ const styleResult = writeStyleFiles(dirPath, summary, { force: false });
1176
+ if (styleResult.written.length > 0) {
1177
+ console.log(`[cell] Generated: ${styleResult.written.join(', ')}`);
989
1178
  }
1179
+ hookResults.push({ hook: 'style-pull', ok: true });
1180
+ }
1181
+ catch (e) {
1182
+ hookResults.push({ hook: 'style-pull', ok: false, error: String(e) });
1183
+ console.warn('[cell] Hook failed: style-pull:', e instanceof Error ? e.message : String(e));
990
1184
  }
991
- catch { /* style-pull may not be available */ }
992
- // ─── CONNECT: Stack Detector → Deep project understanding ──────────
1185
+ // ─── CONNECT: Stack Detector ──────────
993
1186
  try {
994
1187
  const dna = (0, stack_detector_1.detectProjectDNA)(dirPath);
995
1188
  const projectName = dna.name || project;
996
1189
  const db = (0, database_1.getDb)();
997
- db.prepare('INSERT OR REPLACE INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count, confidence, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(projectName, 'stack-dna', 'project_dna', JSON.stringify(dna.stack), 'stack_detect', 1, dna.stack.trustScore, dna.stack.languages[0] || '');
998
- db.prepare('INSERT OR REPLACE INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count, confidence, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(projectName, 'arch-dna', 'architecture', JSON.stringify(dna.architecture), 'architecture', 1, dna.architecture.confidence === 'high' ? 90 : 50, '');
1190
+ db.prepare('INSERT OR REPLACE INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count, trust_score, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(projectName, 'stack-dna', 'project_dna', JSON.stringify(dna.stack), 'stack_detect', 1, dna.stack.trustScore, dna.stack.languages[0] || '');
1191
+ db.prepare('INSERT OR REPLACE INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count, trust_score, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(projectName, 'arch-dna', 'architecture', JSON.stringify(dna.architecture), 'architecture', 1, dna.architecture.confidence === 'high' ? 90 : 50, '');
999
1192
  console.log('[cell] Stack: ' + dna.stack.frontend + ' + ' + dna.stack.backend + ', DB: ' + dna.stack.database.join(', ') + ', ORM: ' + dna.stack.orm + ', Test: ' + dna.stack.testing.join(', '));
1000
1193
  console.log('[cell] Arch: ' + dna.architecture.type + ' (' + dna.architecture.confidence + '), Entry: ' + dna.architecture.entryPoints.join(', '));
1194
+ hookResults.push({ hook: 'stack-detector', ok: true });
1001
1195
  }
1002
1196
  catch (e) {
1003
- console.log('[cell] Stack detection failed:', String(e));
1197
+ hookResults.push({ hook: 'stack-detector', ok: false, error: String(e) });
1198
+ console.warn('[cell] Hook failed: stack-detector:', e instanceof Error ? e.message : String(e));
1004
1199
  }
1005
1200
  // ─── CONNECT: Knowledge Graph ────────────────────────────────────
1006
1201
  try {
1007
1202
  const { buildKnowledgeGraph } = require('./knowledge-graph-builder');
1008
1203
  const graph = buildKnowledgeGraph(dirPath);
1009
1204
  console.log(`[cell] Graph: ${graph.nodes.length} nodes, ${graph.mostCoupled.length} most-coupled, Entry: ${graph.entryPoints.join(', ')}`);
1205
+ hookResults.push({ hook: 'knowledge-graph', ok: true });
1206
+ }
1207
+ catch (e) {
1208
+ hookResults.push({ hook: 'knowledge-graph', ok: false, error: String(e) });
1209
+ console.warn('[cell] Hook failed: knowledge-graph:', e instanceof Error ? e.message : String(e));
1210
+ }
1211
+ // ─── CONNECT: Blind Spot Engine ──────────────────────────────
1212
+ try {
1213
+ const { BlindSpotEngine } = require('./core/blind-spot-engine');
1214
+ const engine = new BlindSpotEngine(path.join(os.homedir(), '.fivo', 'cell'));
1215
+ let totalBlindSpots = 0;
1216
+ let totalHit = 0;
1217
+ let totalMissed = 0;
1218
+ let analyzed = 0;
1219
+ for (const analysis of analyses) {
1220
+ try {
1221
+ if (!analysis.filePath || typeof analysis.filePath !== 'string')
1222
+ continue;
1223
+ const content = fs.readFileSync(analysis.filePath, 'utf-8');
1224
+ const spots = engine.analyze(content, analysis.language);
1225
+ analyzed++;
1226
+ // Count unique rule IDs only (not per-detection), cap at 5 per file
1227
+ const seenRuleIds = new Set();
1228
+ let perFileCount = 0;
1229
+ for (const s of spots) {
1230
+ if (seenRuleIds.has(s.id))
1231
+ continue;
1232
+ if (perFileCount >= 5)
1233
+ break;
1234
+ seenRuleIds.add(s.id);
1235
+ perFileCount++;
1236
+ totalBlindSpots++;
1237
+ totalHit += Math.min(100, Math.round(s.hitRate * 100));
1238
+ totalMissed += Math.min(5, Math.round(s.missedRate));
1239
+ }
1240
+ }
1241
+ catch { }
1242
+ }
1243
+ console.log(`[cell] Blind spots: ${totalBlindSpots} issues across ${analyzed}/${analyses.length} files, ${totalMissed} weighted severity`);
1244
+ result.blindSpotStats = { totalBlindSpots, totalHit, totalMissed, files: analyzed };
1245
+ hookResults.push({ hook: 'blind-spot-engine', ok: true });
1010
1246
  }
1011
1247
  catch (e) {
1012
- console.log('[cell] Graph failed:', String(e));
1248
+ hookResults.push({ hook: 'blind-spot-engine', ok: false, error: String(e) });
1249
+ console.warn('[cell] Hook failed: blind-spot-engine:', e instanceof Error ? e.message : String(e));
1250
+ }
1251
+ const failed = hookResults.filter(h => !h.ok);
1252
+ if (failed.length > 0) {
1253
+ console.warn(`[cell] Scan completed with ${failed.length} hook failures: ${failed.map(f => f.hook).join(', ')}`);
1013
1254
  }
1255
+ result.hookResults = hookResults;
1014
1256
  return result;
1015
1257
  }
1016
1258
  function getDeveloperProfile(project) {