fivocell 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) 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 +302 -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 +132 -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 +368 -1
  109. package/dist/cli.js.map +1 -1
  110. package/dist/code-scanner.d.ts.map +1 -1
  111. package/dist/code-scanner.js +301 -97
  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 +591 -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 +482 -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/usage-intelligence-store.d.ts +126 -0
  150. package/dist/core/usage-intelligence-store.d.ts.map +1 -0
  151. package/dist/core/usage-intelligence-store.js +405 -0
  152. package/dist/core/usage-intelligence-store.js.map +1 -0
  153. package/dist/daemon/server.d.ts.map +1 -1
  154. package/dist/daemon/server.js +936 -17
  155. package/dist/daemon/server.js.map +1 -1
  156. package/dist/knowledge-graph-builder.d.ts.map +1 -1
  157. package/dist/knowledge-graph-builder.js +18 -2
  158. package/dist/knowledge-graph-builder.js.map +1 -1
  159. package/dist/pc-scanner.d.ts +1 -0
  160. package/dist/pc-scanner.d.ts.map +1 -1
  161. package/dist/pc-scanner.js +58 -30
  162. package/dist/pc-scanner.js.map +1 -1
  163. package/package.json +1 -1
@@ -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");
@@ -395,6 +396,8 @@ function extractASTPatterns(content, filePath) {
395
396
  let zodImports = false;
396
397
  let nestDepth = 0;
397
398
  let maxNestDepth = 0;
399
+ let controlFlowDepth = 0;
400
+ let maxControlFlowDepth = 0;
398
401
  let nPlusOne = 0;
399
402
  let hardcodedSecrets = 0;
400
403
  let missingNullCheck = 0;
@@ -402,6 +405,23 @@ function extractASTPatterns(content, filePath) {
402
405
  const visit = (node, depth) => {
403
406
  nestDepth = Math.max(nestDepth, depth);
404
407
  maxNestDepth = Math.max(maxNestDepth, depth);
408
+ const isControlFlow = ts.isIfStatement(node) ||
409
+ ts.isForStatement(node) ||
410
+ ts.isForInStatement(node) ||
411
+ ts.isForOfStatement(node) ||
412
+ ts.isWhileStatement(node) ||
413
+ ts.isDoStatement(node) ||
414
+ ts.isSwitchStatement(node) ||
415
+ ts.isTryStatement(node) ||
416
+ ts.isConditionalExpression(node);
417
+ if (isControlFlow) {
418
+ controlFlowDepth = depth;
419
+ maxControlFlowDepth = Math.max(maxControlFlowDepth, depth);
420
+ }
421
+ if (isControlFlow) {
422
+ ts.forEachChild(node, (child) => visit(child, depth + 1));
423
+ return;
424
+ }
405
425
  // ── Async without try/catch ──────────────────────────────────────
406
426
  if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node)) {
407
427
  const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
@@ -419,7 +439,10 @@ function extractASTPatterns(content, filePath) {
419
439
  if (!hasTryCatch)
420
440
  asyncNoTryCatch++;
421
441
  // Return type check
422
- if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
442
+ if (ts.isFunctionDeclaration(node) ||
443
+ ts.isMethodDeclaration(node) ||
444
+ ts.isFunctionExpression(node) ||
445
+ ts.isArrowFunction(node)) {
423
446
  const hasReturnType = node.type !== undefined;
424
447
  if (hasReturnType)
425
448
  functionsWithType++;
@@ -462,13 +485,16 @@ function extractASTPatterns(content, filePath) {
462
485
  const callText = expr.getText();
463
486
  if (callText.includes('.find') || callText.includes('.query') || callText.includes('.execute') ||
464
487
  callText.includes('fetch') || callText.includes('prisma.') || callText.includes('db.')) {
465
- // Check if we're inside a loop
466
488
  let parent = node.parent;
467
489
  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')) {
490
+ if (ts.isForStatement(parent) ||
491
+ ts.isForInStatement(parent) ||
492
+ ts.isForOfStatement(parent) ||
493
+ ts.isWhileStatement(parent) ||
494
+ ts.isDoStatement(parent) ||
495
+ (ts.isCallExpression(parent) &&
496
+ ts.isPropertyAccessExpression(parent.expression) &&
497
+ (parent.expression.name.text === 'map' || parent.expression.name.text === 'forEach'))) {
472
498
  nPlusOne++;
473
499
  break;
474
500
  }
@@ -476,21 +502,48 @@ function extractASTPatterns(content, filePath) {
476
502
  }
477
503
  }
478
504
  }
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;
505
+ // Missing null check detection — any property access on awaited API call
506
+ if (ts.isPropertyAccessExpression(expr)) {
507
+ let base = expr.expression;
508
+ while (ts.isPropertyAccessExpression(base))
509
+ base = base.expression;
510
+ const baseText = base.getText();
511
+ if (baseText.includes('fetch') ||
512
+ baseText.includes('axios') ||
513
+ baseText.includes('request') ||
514
+ baseText.includes('http.get') ||
515
+ baseText.includes('prisma.') ||
516
+ baseText.includes('db.')) {
517
+ let hasAwait = false;
485
518
  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;
519
+ let ancestor = expr.parent;
520
+ while (ancestor && (!hasAwait || !hasNullCheck)) {
521
+ if (ts.isAwaitExpression(ancestor))
522
+ hasAwait = true;
523
+ if (ts.isExpressionStatement(ancestor) || ts.isVariableDeclaration(ancestor))
524
+ break;
525
+ if (ts.isIfStatement(ancestor)) {
526
+ const condText = ancestor.expression.getText();
527
+ if (condText.includes('!') ||
528
+ condText.includes('null') ||
529
+ condText.includes('undefined') ||
530
+ condText.includes('?.')) {
531
+ hasNullCheck = true;
532
+ }
490
533
  }
491
- parent = parent.parent;
534
+ if (ts.isBinaryExpression(ancestor) &&
535
+ (ancestor.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken ||
536
+ ancestor.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken ||
537
+ ancestor.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken ||
538
+ ancestor.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken)) {
539
+ const text = ancestor.getText();
540
+ if (text.includes('null') || text.includes('undefined')) {
541
+ hasNullCheck = true;
542
+ }
543
+ }
544
+ ancestor = ancestor.parent;
492
545
  }
493
- if (!hasNullCheck)
546
+ if (hasAwait && !hasNullCheck)
494
547
  missingNullCheck++;
495
548
  }
496
549
  }
@@ -510,10 +563,29 @@ function extractASTPatterns(content, filePath) {
510
563
  }
511
564
  }
512
565
  // ── 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')) {
566
+ const isHandlerLike = ts.isFunctionDeclaration(node) ||
567
+ ts.isFunctionExpression(node) ||
568
+ ts.isArrowFunction(node);
569
+ if (isHandlerLike) {
570
+ let funcName = '';
571
+ let body;
572
+ if (ts.isFunctionDeclaration(node) && node.name) {
573
+ funcName = node.name.text;
574
+ body = node.body;
575
+ }
576
+ else if (ts.isFunctionExpression(node) ||
577
+ ts.isArrowFunction(node)) {
578
+ let p = node.parent;
579
+ while (p) {
580
+ if (ts.isVariableDeclaration(p) && ts.isIdentifier(p.name)) {
581
+ funcName = p.name.text;
582
+ break;
583
+ }
584
+ p = p.parent;
585
+ }
586
+ body = node.body;
587
+ }
588
+ if (funcName.toLowerCase().includes('handler') || funcName.toLowerCase().includes('route') || funcName.toLowerCase().includes('endpoint') || funcName.toLowerCase().includes('controller')) {
517
589
  let hasValidation = false;
518
590
  const checkBody = (n) => {
519
591
  if (ts.isCallExpression(n)) {
@@ -525,8 +597,8 @@ function extractASTPatterns(content, filePath) {
525
597
  }
526
598
  ts.forEachChild(n, checkBody);
527
599
  };
528
- if (funcNode.body)
529
- checkBody(funcNode.body);
600
+ if (body)
601
+ checkBody(body);
530
602
  if (!hasValidation)
531
603
  missingInputValidation++;
532
604
  }
@@ -583,12 +655,12 @@ function extractASTPatterns(content, filePath) {
583
655
  trustScore: 85,
584
656
  });
585
657
  }
586
- if (maxNestDepth > 4) {
658
+ if (maxControlFlowDepth > 4) {
587
659
  patterns.push({
588
660
  type: 'blind_spot_deep_nesting',
589
661
  category: 'blind_spots',
590
- value: `max_nesting:${maxNestDepth}`,
591
- count: maxNestDepth,
662
+ value: `max_nesting:${maxControlFlowDepth}`,
663
+ count: maxControlFlowDepth,
592
664
  trustScore: 80,
593
665
  });
594
666
  }
@@ -716,8 +788,9 @@ function aggregatePatterns(analyses) {
716
788
  const key = `${pattern.type}:${pattern.value}`;
717
789
  const existing = patternMap.get(key);
718
790
  if (existing) {
719
- existing.count += pattern.count;
720
- existing.trustScore = Math.min(95, Math.round((existing.trustScore + pattern.trustScore) / 2));
791
+ const totalCount = existing.count + pattern.count;
792
+ existing.trustScore = Math.min(95, Math.round((existing.trustScore * existing.count + pattern.trustScore * pattern.count) / totalCount));
793
+ existing.count = totalCount;
721
794
  }
722
795
  else {
723
796
  patternMap.set(key, { ...pattern });
@@ -844,54 +917,68 @@ function buildDeveloperProfile(patterns) {
844
917
  // ─── Database Storage ────────────────────────────────────────────────────────
845
918
  function ensureCodePatternTable() {
846
919
  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);
920
+ db.exec(`
921
+ CREATE TABLE IF NOT EXISTS code_patterns (
922
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
923
+ project TEXT NOT NULL,
924
+ file_path TEXT NOT NULL,
925
+ pattern_type TEXT NOT NULL,
926
+ pattern_value TEXT NOT NULL,
927
+ category TEXT NOT NULL,
928
+ count INTEGER DEFAULT 1,
929
+ trust_score INTEGER DEFAULT 50,
930
+ language TEXT,
931
+ created_at TEXT DEFAULT (datetime('now'))
932
+ );
933
+ CREATE INDEX IF NOT EXISTS idx_code_patterns_project ON code_patterns(project);
934
+ CREATE INDEX IF NOT EXISTS idx_code_patterns_type ON code_patterns(pattern_type);
935
+ CREATE INDEX IF NOT EXISTS idx_code_patterns_category ON code_patterns(category);
936
+
937
+ CREATE TABLE IF NOT EXISTS developer_profiles (
938
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
939
+ project TEXT NOT NULL UNIQUE,
940
+ naming_style TEXT,
941
+ import_style TEXT,
942
+ export_style TEXT,
943
+ error_handling TEXT,
944
+ function_style TEXT,
945
+ async_style TEXT,
946
+ comment_style TEXT,
947
+ indent_style TEXT,
948
+ quote_style TEXT,
949
+ semicolon_style TEXT,
950
+ architecture_style TEXT,
951
+ test_pattern TEXT,
952
+ top_patterns TEXT,
953
+ strengths TEXT,
954
+ improvements TEXT,
955
+ files_scanned INTEGER DEFAULT 0,
956
+ total_lines INTEGER DEFAULT 0,
957
+ languages TEXT,
958
+ scanned_at TEXT DEFAULT (datetime('now'))
959
+ );
960
+ CREATE INDEX IF NOT EXISTS idx_dev_profile_project ON developer_profiles(project);
888
961
  `);
889
962
  }
890
- function saveToDatabase(project, result) {
963
+ function saveToDatabase(project, result, projectPath) {
891
964
  const db = (0, database_1.getDb)();
892
965
  ensureCodePatternTable();
966
+ try {
967
+ const { ProjectRegistry } = require('./core/project-registry');
968
+ const registry = new ProjectRegistry();
969
+ const stack = Object.keys(result.languages || {}).slice(0, 3).join('+') || 'unknown';
970
+ registry.registerProject({
971
+ name: project,
972
+ path: projectPath || project,
973
+ stack,
974
+ fileCount: result.filesScanned,
975
+ });
976
+ }
977
+ catch (e) {
978
+ console.warn('[cell] Project registration failed (non-fatal):', e instanceof Error ? e.message : String(e));
979
+ }
893
980
  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 (?, ?, ?, ?, ?, ?, ?, ?)');
981
+ const insertPattern = db.prepare('INSERT INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count, trust_score, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
895
982
  const insertMany = db.transaction((patterns) => {
896
983
  for (const p of patterns) {
897
984
  insertPattern.run(project, 'scan', p.type, p.value, p.category, p.count, p.trustScore, '');
@@ -899,16 +986,23 @@ function saveToDatabase(project, result) {
899
986
  });
900
987
  insertMany(result.patterns);
901
988
  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)
989
+ db.prepare(`INSERT INTO developer_profiles
990
+ (project, naming_style, import_style, export_style, error_handling, function_style,
991
+ async_style, comment_style, indent_style, quote_style, semicolon_style,
992
+ architecture_style, test_pattern, top_patterns, strengths, improvements,
993
+ files_scanned, total_lines, languages, scanned_at)
907
994
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))`)
908
995
  .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));
996
+ try {
997
+ const stmt = db.prepare(`INSERT OR REPLACE INTO scans (project, scanned_at, file_count, line_count, stack, patterns, hubs, issues)
998
+ VALUES (?, datetime('now'), ?, ?, ?, ?, ?, ?)`);
999
+ if (stmt) {
1000
+ 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));
1001
+ }
1002
+ }
1003
+ catch (e) {
1004
+ console.warn('[cell] scans table insert failed (schema mismatch, non-fatal):', e instanceof Error ? e.message : String(e));
1005
+ }
912
1006
  }
913
1007
  // ─── Public API ──────────────────────────────────────────────────────────────
914
1008
  function scanCodebase(dirPath, projectName) {
@@ -938,11 +1032,71 @@ function scanCodebase(dirPath, projectName) {
938
1032
  patterns,
939
1033
  profile,
940
1034
  };
941
- saveToDatabase(project, result);
1035
+ saveToDatabase(project, result, dirPath);
1036
+ // ─── PHASE 3: Build Knowledge Graphs (file deps + pattern entities) ───
1037
+ try {
1038
+ const { saveFileKnowledgeGraph, saveTechProficiency } = require('./core/knowledge-graph-store');
1039
+ const fileGraph = saveFileKnowledgeGraph(project, dirPath);
1040
+ // Tech proficiency: use languages + architecture style
1041
+ const archTech = profile.architectureStyle || 'unknown';
1042
+ saveTechProficiency(project, {
1043
+ technology: archTech,
1044
+ category: 'architecture',
1045
+ signalsCount: 1,
1046
+ proficiencyScore: 70,
1047
+ lastSeen: new Date().toISOString(),
1048
+ trend: 'stable',
1049
+ });
1050
+ for (const [lang, count] of Object.entries(languages)) {
1051
+ const score = Math.min(100, 40 + Math.log10(count + 1) * 20);
1052
+ saveTechProficiency(project, {
1053
+ technology: lang,
1054
+ category: 'language',
1055
+ signalsCount: count,
1056
+ proficiencyScore: Math.round(score),
1057
+ lastSeen: new Date().toISOString(),
1058
+ trend: 'stable',
1059
+ });
1060
+ }
1061
+ // Save pattern entities + relationships
1062
+ if (result.patterns && result.patterns.length > 0) {
1063
+ const { savePatternEntities, savePatternRelationships } = require('./core/knowledge-graph-store');
1064
+ const entities = result.patterns.slice(0, 200).map((p, i) => ({
1065
+ id: `${p.category || 'pattern'}-${i}`,
1066
+ type: p.category || 'pattern',
1067
+ label: p.value || '',
1068
+ weight: p.trustScore || 1,
1069
+ }));
1070
+ savePatternEntities(project, entities);
1071
+ // Co-occurrence: patterns in same category from same file are related
1072
+ const filePatterns = new Map();
1073
+ for (let i = 0; i < Math.min(200, result.patterns.length); i++) {
1074
+ const p = result.patterns[i];
1075
+ const f = p.file || 'global';
1076
+ const key = `${f}`;
1077
+ const arr = filePatterns.get(key) || [];
1078
+ arr.push(`${p.category || 'pattern'}-${i}`);
1079
+ filePatterns.set(key, arr);
1080
+ }
1081
+ const edges = [];
1082
+ for (const arr of filePatterns.values()) {
1083
+ for (let i = 0; i < arr.length; i++) {
1084
+ for (let j = i + 1; j < arr.length; j++) {
1085
+ edges.push({ from: arr[i], to: arr[j], type: 'co_occurs', weight: 1 });
1086
+ }
1087
+ }
1088
+ }
1089
+ if (edges.length > 0)
1090
+ savePatternRelationships(project, edges);
1091
+ }
1092
+ }
1093
+ catch (e) {
1094
+ console.warn('[cell] Knowledge graph build failed (non-fatal):', e instanceof Error ? e.message : String(e));
1095
+ }
1096
+ const hookResults = [];
942
1097
  // ─── CONNECT: Scanner → Behavioral Tracker ───────────────────────────────
943
1098
  try {
944
1099
  const { logError, logDecision, logContext } = require('./behavioral-tracker');
945
- // Log blind spots as errors
946
1100
  if (profile.improvements.length > 0) {
947
1101
  for (const imp of profile.improvements) {
948
1102
  logError({
@@ -954,7 +1108,6 @@ function scanCodebase(dirPath, projectName) {
954
1108
  });
955
1109
  }
956
1110
  }
957
- // Log architecture decision
958
1111
  logDecision({
959
1112
  project,
960
1113
  file: 'scan-auto',
@@ -962,55 +1115,106 @@ function scanCodebase(dirPath, projectName) {
962
1115
  approach: `Scan detected ${files.length} files, ${result.languages ? Object.keys(result.languages).join(', ') : 'unknown'}`,
963
1116
  worked: true,
964
1117
  });
965
- // Log current context
966
1118
  logContext({
967
1119
  project,
968
1120
  task: `Codebase scan completed — ${files.length} files, ${totalLines.toLocaleString()} lines`,
969
1121
  files: [dirPath],
970
1122
  });
1123
+ hookResults.push({ hook: 'behavioral-tracker', ok: true });
971
1124
  }
972
- catch { /* behavioral tracker may not be initialized yet */ }
973
- // ─── CONNECT: Git Intelligence (behavior + journey + user analysis) ──────
1125
+ catch (e) {
1126
+ hookResults.push({ hook: 'behavioral-tracker', ok: false, error: String(e) });
1127
+ console.warn('[cell] Hook failed: behavioral-tracker:', e instanceof Error ? e.message : String(e));
1128
+ }
1129
+ // ─── CONNECT: Git Intelligence ──────
974
1130
  try {
975
1131
  const { buildDeveloperIntelligence } = require('./developer-intelligence');
976
1132
  const gitIntel = buildDeveloperIntelligence(dirPath);
977
1133
  if (gitIntel) {
978
1134
  console.log(`[cell] Git intelligence: ${gitIntel.topBlindSpots.length} blind spots, ${gitIntel.topMistakes.length} repeat mistakes, score: ${gitIntel.behavioralScore}/100`);
979
1135
  }
1136
+ hookResults.push({ hook: 'developer-intelligence', ok: true });
980
1137
  }
981
- catch { /* git intelligence may not be available */ }
982
- // ─── CONNECT: Style Pull → Generate .cursorrules, CLAUDE.md, etc. ────
1138
+ catch (e) {
1139
+ hookResults.push({ hook: 'developer-intelligence', ok: false, error: String(e) });
1140
+ console.warn('[cell] Hook failed: developer-intelligence:', e instanceof Error ? e.message : String(e));
1141
+ }
1142
+ // ─── CONNECT: Style Pull ────
983
1143
  try {
984
1144
  const { writeStyleFiles, buildStyleSummary } = require('./style-pull');
985
1145
  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(', ')}`);
1146
+ const styleResult = writeStyleFiles(dirPath, summary, { force: false });
1147
+ if (styleResult.written.length > 0) {
1148
+ console.log(`[cell] Generated: ${styleResult.written.join(', ')}`);
989
1149
  }
1150
+ hookResults.push({ hook: 'style-pull', ok: true });
1151
+ }
1152
+ catch (e) {
1153
+ hookResults.push({ hook: 'style-pull', ok: false, error: String(e) });
1154
+ console.warn('[cell] Hook failed: style-pull:', e instanceof Error ? e.message : String(e));
990
1155
  }
991
- catch { /* style-pull may not be available */ }
992
- // ─── CONNECT: Stack Detector → Deep project understanding ──────────
1156
+ // ─── CONNECT: Stack Detector ──────────
993
1157
  try {
994
1158
  const dna = (0, stack_detector_1.detectProjectDNA)(dirPath);
995
1159
  const projectName = dna.name || project;
996
1160
  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, '');
1161
+ 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] || '');
1162
+ 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
1163
  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
1164
  console.log('[cell] Arch: ' + dna.architecture.type + ' (' + dna.architecture.confidence + '), Entry: ' + dna.architecture.entryPoints.join(', '));
1165
+ hookResults.push({ hook: 'stack-detector', ok: true });
1001
1166
  }
1002
1167
  catch (e) {
1003
- console.log('[cell] Stack detection failed:', String(e));
1168
+ hookResults.push({ hook: 'stack-detector', ok: false, error: String(e) });
1169
+ console.warn('[cell] Hook failed: stack-detector:', e instanceof Error ? e.message : String(e));
1004
1170
  }
1005
1171
  // ─── CONNECT: Knowledge Graph ────────────────────────────────────
1006
1172
  try {
1007
1173
  const { buildKnowledgeGraph } = require('./knowledge-graph-builder');
1008
1174
  const graph = buildKnowledgeGraph(dirPath);
1009
1175
  console.log(`[cell] Graph: ${graph.nodes.length} nodes, ${graph.mostCoupled.length} most-coupled, Entry: ${graph.entryPoints.join(', ')}`);
1176
+ hookResults.push({ hook: 'knowledge-graph', ok: true });
1010
1177
  }
1011
1178
  catch (e) {
1012
- console.log('[cell] Graph failed:', String(e));
1179
+ hookResults.push({ hook: 'knowledge-graph', ok: false, error: String(e) });
1180
+ console.warn('[cell] Hook failed: knowledge-graph:', e instanceof Error ? e.message : String(e));
1181
+ }
1182
+ // ─── CONNECT: Blind Spot Engine ──────────────────────────────
1183
+ try {
1184
+ const { BlindSpotEngine } = require('./core/blind-spot-engine');
1185
+ const engine = new BlindSpotEngine(path.join(os.homedir(), '.fivo', 'cell'));
1186
+ let totalBlindSpots = 0;
1187
+ let totalHit = 0;
1188
+ let totalMissed = 0;
1189
+ let analyzed = 0;
1190
+ for (const analysis of analyses) {
1191
+ try {
1192
+ if (!analysis.filePath || typeof analysis.filePath !== 'string')
1193
+ continue;
1194
+ const content = fs.readFileSync(analysis.filePath, 'utf-8');
1195
+ const spots = engine.analyze(content, analysis.language);
1196
+ analyzed++;
1197
+ totalBlindSpots += spots.length;
1198
+ for (const s of spots) {
1199
+ totalHit += Math.round(s.hitRate);
1200
+ totalMissed += Math.round(s.missedRate);
1201
+ }
1202
+ }
1203
+ catch { }
1204
+ }
1205
+ console.log(`[cell] Blind spots: ${totalBlindSpots} categories, ${totalMissed} missed checks, ${totalHit} hits across ${analyzed}/${analyses.length} files`);
1206
+ result.blindSpotStats = { totalBlindSpots, totalHit, totalMissed, files: analyzed };
1207
+ hookResults.push({ hook: 'blind-spot-engine', ok: true });
1208
+ }
1209
+ catch (e) {
1210
+ hookResults.push({ hook: 'blind-spot-engine', ok: false, error: String(e) });
1211
+ console.warn('[cell] Hook failed: blind-spot-engine:', e instanceof Error ? e.message : String(e));
1212
+ }
1213
+ const failed = hookResults.filter(h => !h.ok);
1214
+ if (failed.length > 0) {
1215
+ console.warn(`[cell] Scan completed with ${failed.length} hook failures: ${failed.map(f => f.hook).join(', ')}`);
1013
1216
  }
1217
+ result.hookResults = hookResults;
1014
1218
  return result;
1015
1219
  }
1016
1220
  function getDeveloperProfile(project) {