fivocell 3.1.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.
- package/dist/__tests__/behavior-intelligence-bug.test.d.ts +2 -0
- package/dist/__tests__/behavior-intelligence-bug.test.d.ts.map +1 -0
- package/dist/__tests__/behavior-intelligence-bug.test.js +21 -0
- package/dist/__tests__/behavior-intelligence-bug.test.js.map +1 -0
- package/dist/__tests__/code-scanner-arrow-return-type.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-arrow-return-type.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-arrow-return-type.test.js +76 -0
- package/dist/__tests__/code-scanner-arrow-return-type.test.js.map +1 -0
- package/dist/__tests__/code-scanner-blindspot.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-blindspot.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-blindspot.test.js +18 -0
- package/dist/__tests__/code-scanner-blindspot.test.js.map +1 -0
- package/dist/__tests__/code-scanner-error-recovery.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-error-recovery.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-error-recovery.test.js +21 -0
- package/dist/__tests__/code-scanner-error-recovery.test.js.map +1 -0
- package/dist/__tests__/code-scanner-n1-detection.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-n1-detection.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-n1-detection.test.js +113 -0
- package/dist/__tests__/code-scanner-n1-detection.test.js.map +1 -0
- package/dist/__tests__/code-scanner-nesting.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-nesting.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-nesting.test.js +113 -0
- package/dist/__tests__/code-scanner-nesting.test.js.map +1 -0
- package/dist/__tests__/code-scanner-null-check.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-null-check.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-null-check.test.js +126 -0
- package/dist/__tests__/code-scanner-null-check.test.js.map +1 -0
- package/dist/__tests__/code-scanner-sql-fix.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-sql-fix.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-sql-fix.test.js +21 -0
- package/dist/__tests__/code-scanner-sql-fix.test.js.map +1 -0
- package/dist/__tests__/code-scanner-trust-score.test.d.ts +1 -0
- package/dist/__tests__/code-scanner-trust-score.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-trust-score.test.js +39 -0
- package/dist/__tests__/code-scanner-trust-score.test.js.map +1 -0
- package/dist/__tests__/code-scanner-validation.test.d.ts +2 -0
- package/dist/__tests__/code-scanner-validation.test.d.ts.map +1 -0
- package/dist/__tests__/code-scanner-validation.test.js +131 -0
- package/dist/__tests__/code-scanner-validation.test.js.map +1 -0
- package/dist/__tests__/community-store.test.d.ts +2 -0
- package/dist/__tests__/community-store.test.d.ts.map +1 -0
- package/dist/__tests__/community-store.test.js +231 -0
- package/dist/__tests__/community-store.test.js.map +1 -0
- package/dist/__tests__/enhanced-blind-spots.test.d.ts +2 -0
- package/dist/__tests__/enhanced-blind-spots.test.d.ts.map +1 -0
- package/dist/__tests__/enhanced-blind-spots.test.js +302 -0
- package/dist/__tests__/enhanced-blind-spots.test.js.map +1 -0
- package/dist/__tests__/knowledge-graph-store.test.d.ts +2 -0
- package/dist/__tests__/knowledge-graph-store.test.d.ts.map +1 -0
- package/dist/__tests__/knowledge-graph-store.test.js +252 -0
- package/dist/__tests__/knowledge-graph-store.test.js.map +1 -0
- package/dist/__tests__/live-watcher.test.d.ts +2 -0
- package/dist/__tests__/live-watcher.test.d.ts.map +1 -0
- package/dist/__tests__/live-watcher.test.js +312 -0
- package/dist/__tests__/live-watcher.test.js.map +1 -0
- package/dist/__tests__/mcp-cell-tools.test.d.ts +2 -0
- package/dist/__tests__/mcp-cell-tools.test.d.ts.map +1 -0
- package/dist/__tests__/mcp-cell-tools.test.js +176 -0
- package/dist/__tests__/mcp-cell-tools.test.js.map +1 -0
- package/dist/__tests__/multi-project.test.d.ts +2 -0
- package/dist/__tests__/multi-project.test.d.ts.map +1 -0
- package/dist/__tests__/multi-project.test.js +145 -0
- package/dist/__tests__/multi-project.test.js.map +1 -0
- package/dist/__tests__/pc-scanner-paths.test.d.ts +2 -0
- package/dist/__tests__/pc-scanner-paths.test.d.ts.map +1 -0
- package/dist/__tests__/pc-scanner-paths.test.js +16 -0
- package/dist/__tests__/pc-scanner-paths.test.js.map +1 -0
- package/dist/__tests__/prompt-builder-realdata.test.d.ts +2 -0
- package/dist/__tests__/prompt-builder-realdata.test.d.ts.map +1 -0
- package/dist/__tests__/prompt-builder-realdata.test.js +94 -0
- package/dist/__tests__/prompt-builder-realdata.test.js.map +1 -0
- package/dist/__tests__/prompt-builder-sessions.test.d.ts +2 -0
- package/dist/__tests__/prompt-builder-sessions.test.d.ts.map +1 -0
- package/dist/__tests__/prompt-builder-sessions.test.js +124 -0
- package/dist/__tests__/prompt-builder-sessions.test.js.map +1 -0
- package/dist/__tests__/security.test.d.ts +1 -0
- package/dist/__tests__/security.test.d.ts.map +1 -0
- package/dist/__tests__/security.test.js +161 -0
- package/dist/__tests__/security.test.js.map +1 -0
- package/dist/__tests__/session-bridge.test.d.ts +2 -0
- package/dist/__tests__/session-bridge.test.d.ts.map +1 -0
- package/dist/__tests__/session-bridge.test.js +158 -0
- package/dist/__tests__/session-bridge.test.js.map +1 -0
- package/dist/__tests__/session-memory-tables.test.d.ts +2 -0
- package/dist/__tests__/session-memory-tables.test.d.ts.map +1 -0
- package/dist/__tests__/session-memory-tables.test.js +169 -0
- package/dist/__tests__/session-memory-tables.test.js.map +1 -0
- package/dist/__tests__/staleness-detection.test.d.ts +2 -0
- package/dist/__tests__/staleness-detection.test.d.ts.map +1 -0
- package/dist/__tests__/staleness-detection.test.js +105 -0
- package/dist/__tests__/staleness-detection.test.js.map +1 -0
- package/dist/__tests__/team-collaboration.test.d.ts +2 -0
- package/dist/__tests__/team-collaboration.test.d.ts.map +1 -0
- package/dist/__tests__/team-collaboration.test.js +224 -0
- package/dist/__tests__/team-collaboration.test.js.map +1 -0
- package/dist/__tests__/tool-specific-format.test.d.ts +2 -0
- package/dist/__tests__/tool-specific-format.test.d.ts.map +1 -0
- package/dist/__tests__/tool-specific-format.test.js +132 -0
- package/dist/__tests__/tool-specific-format.test.js.map +1 -0
- package/dist/__tests__/usage-intelligence-store.test.d.ts +2 -0
- package/dist/__tests__/usage-intelligence-store.test.d.ts.map +1 -0
- package/dist/__tests__/usage-intelligence-store.test.js +266 -0
- package/dist/__tests__/usage-intelligence-store.test.js.map +1 -0
- package/dist/ai-bridge.d.ts +20 -0
- package/dist/ai-bridge.d.ts.map +1 -0
- package/dist/ai-bridge.js +250 -0
- package/dist/ai-bridge.js.map +1 -0
- package/dist/behavior-intelligence.d.ts.map +1 -1
- package/dist/behavior-intelligence.js +12 -1
- package/dist/behavior-intelligence.js.map +1 -1
- package/dist/cli.js +501 -4
- package/dist/cli.js.map +1 -1
- package/dist/code-scanner.d.ts.map +1 -1
- package/dist/code-scanner.js +426 -69
- package/dist/code-scanner.js.map +1 -1
- package/dist/core/community-store.d.ts +128 -0
- package/dist/core/community-store.d.ts.map +1 -0
- package/dist/core/community-store.js +329 -0
- package/dist/core/community-store.js.map +1 -0
- package/dist/core/database.d.ts +0 -3
- package/dist/core/database.d.ts.map +1 -1
- package/dist/core/database.js +287 -15
- package/dist/core/database.js.map +1 -1
- package/dist/core/enhanced-blind-spots.d.ts +27 -0
- package/dist/core/enhanced-blind-spots.d.ts.map +1 -0
- package/dist/core/enhanced-blind-spots.js +591 -0
- package/dist/core/enhanced-blind-spots.js.map +1 -0
- package/dist/core/knowledge-graph-store.d.ts +69 -0
- package/dist/core/knowledge-graph-store.d.ts.map +1 -0
- package/dist/core/knowledge-graph-store.js +269 -0
- package/dist/core/knowledge-graph-store.js.map +1 -0
- package/dist/core/live-watcher.d.ts +52 -0
- package/dist/core/live-watcher.d.ts.map +1 -0
- package/dist/core/live-watcher.js +369 -0
- package/dist/core/live-watcher.js.map +1 -0
- package/dist/core/project-registry.d.ts +24 -0
- package/dist/core/project-registry.d.ts.map +1 -0
- package/dist/core/project-registry.js +70 -0
- package/dist/core/project-registry.js.map +1 -0
- package/dist/core/prompt-builder.d.ts +50 -0
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +533 -79
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/security.d.ts +23 -0
- package/dist/core/security.d.ts.map +1 -0
- package/dist/core/security.js +117 -0
- package/dist/core/security.js.map +1 -0
- package/dist/core/session-memory.d.ts +64 -0
- package/dist/core/session-memory.d.ts.map +1 -1
- package/dist/core/session-memory.js +111 -0
- package/dist/core/session-memory.js.map +1 -1
- package/dist/core/usage-intelligence-store.d.ts +126 -0
- package/dist/core/usage-intelligence-store.d.ts.map +1 -0
- package/dist/core/usage-intelligence-store.js +405 -0
- package/dist/core/usage-intelligence-store.js.map +1 -0
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +936 -17
- package/dist/daemon/server.js.map +1 -1
- package/dist/knowledge-graph-builder.d.ts +16 -0
- package/dist/knowledge-graph-builder.d.ts.map +1 -0
- package/dist/knowledge-graph-builder.js +186 -0
- package/dist/knowledge-graph-builder.js.map +1 -0
- package/dist/pc-scanner.d.ts +1 -0
- package/dist/pc-scanner.d.ts.map +1 -1
- package/dist/pc-scanner.js +58 -30
- package/dist/pc-scanner.js.map +1 -1
- package/dist/stack-detector.d.ts +34 -0
- package/dist/stack-detector.d.ts.map +1 -0
- package/dist/stack-detector.js +471 -0
- package/dist/stack-detector.js.map +1 -0
- package/dist/team-intel.d.ts +31 -0
- package/dist/team-intel.d.ts.map +1 -0
- package/dist/team-intel.js +310 -0
- package/dist/team-intel.js.map +1 -0
- package/package.json +1 -1
package/dist/code-scanner.js
CHANGED
|
@@ -41,8 +41,10 @@ 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");
|
|
47
|
+
const stack_detector_1 = require("./stack-detector");
|
|
46
48
|
// ─── Language Detection ──────────────────────────────────────────────────────
|
|
47
49
|
const EXT_MAP = {
|
|
48
50
|
'.ts': 'typescript', '.tsx': 'typescript', '.js': 'javascript',
|
|
@@ -394,9 +396,32 @@ function extractASTPatterns(content, filePath) {
|
|
|
394
396
|
let zodImports = false;
|
|
395
397
|
let nestDepth = 0;
|
|
396
398
|
let maxNestDepth = 0;
|
|
399
|
+
let controlFlowDepth = 0;
|
|
400
|
+
let maxControlFlowDepth = 0;
|
|
401
|
+
let nPlusOne = 0;
|
|
402
|
+
let hardcodedSecrets = 0;
|
|
403
|
+
let missingNullCheck = 0;
|
|
404
|
+
let missingInputValidation = 0;
|
|
397
405
|
const visit = (node, depth) => {
|
|
398
406
|
nestDepth = Math.max(nestDepth, depth);
|
|
399
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
|
+
}
|
|
400
425
|
// ── Async without try/catch ──────────────────────────────────────
|
|
401
426
|
if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node)) {
|
|
402
427
|
const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
|
|
@@ -414,7 +439,10 @@ function extractASTPatterns(content, filePath) {
|
|
|
414
439
|
if (!hasTryCatch)
|
|
415
440
|
asyncNoTryCatch++;
|
|
416
441
|
// Return type check
|
|
417
|
-
if (ts.isFunctionDeclaration(node) ||
|
|
442
|
+
if (ts.isFunctionDeclaration(node) ||
|
|
443
|
+
ts.isMethodDeclaration(node) ||
|
|
444
|
+
ts.isFunctionExpression(node) ||
|
|
445
|
+
ts.isArrowFunction(node)) {
|
|
418
446
|
const hasReturnType = node.type !== undefined;
|
|
419
447
|
if (hasReturnType)
|
|
420
448
|
functionsWithType++;
|
|
@@ -452,6 +480,128 @@ function extractASTPatterns(content, filePath) {
|
|
|
452
480
|
if (expr.expression.getText().startsWith('z.'))
|
|
453
481
|
zodImports = true;
|
|
454
482
|
}
|
|
483
|
+
// N+1 query detection: await/query inside loop
|
|
484
|
+
if (ts.isCallExpression(node)) {
|
|
485
|
+
const callText = expr.getText();
|
|
486
|
+
if (callText.includes('.find') || callText.includes('.query') || callText.includes('.execute') ||
|
|
487
|
+
callText.includes('fetch') || callText.includes('prisma.') || callText.includes('db.')) {
|
|
488
|
+
let parent = node.parent;
|
|
489
|
+
while (parent) {
|
|
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'))) {
|
|
498
|
+
nPlusOne++;
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
parent = parent.parent;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
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;
|
|
518
|
+
let hasNullCheck = false;
|
|
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
|
+
}
|
|
533
|
+
}
|
|
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;
|
|
545
|
+
}
|
|
546
|
+
if (hasAwait && !hasNullCheck)
|
|
547
|
+
missingNullCheck++;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
// ── Hardcoded secrets detection ─────────────────────────────────
|
|
552
|
+
if (ts.isVariableDeclaration(node)) {
|
|
553
|
+
const varNode = node;
|
|
554
|
+
const varName = ts.isIdentifier(varNode.name) ? varNode.name.text : '';
|
|
555
|
+
const lower = varName.toLowerCase();
|
|
556
|
+
if ((lower.includes('password') || lower.includes('secret') || lower.includes('api_key') ||
|
|
557
|
+
lower.includes('apikey') || (lower.includes('token') && lower.includes('auth'))) &&
|
|
558
|
+
varNode.initializer && ts.isStringLiteral(varNode.initializer)) {
|
|
559
|
+
const val = varNode.initializer.text;
|
|
560
|
+
if (val.length > 6 && !val.includes('${') && !val.startsWith('process.env')) {
|
|
561
|
+
hardcodedSecrets++;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
// ── Missing input validation in API handlers ────────────────────
|
|
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')) {
|
|
589
|
+
let hasValidation = false;
|
|
590
|
+
const checkBody = (n) => {
|
|
591
|
+
if (ts.isCallExpression(n)) {
|
|
592
|
+
const ct = n.expression.getText();
|
|
593
|
+
if (ct.includes('.parse') || ct.includes('.validate') || ct.includes('.safeParse') ||
|
|
594
|
+
ct.includes('check(') || ct.includes('body(') || ct.includes('query(')) {
|
|
595
|
+
hasValidation = true;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
ts.forEachChild(n, checkBody);
|
|
599
|
+
};
|
|
600
|
+
if (body)
|
|
601
|
+
checkBody(body);
|
|
602
|
+
if (!hasValidation)
|
|
603
|
+
missingInputValidation++;
|
|
604
|
+
}
|
|
455
605
|
}
|
|
456
606
|
// ── any type usage ──────────────────────────────────────────────
|
|
457
607
|
if (ts.isToken(node) && node.kind === ts.SyntaxKind.AnyKeyword)
|
|
@@ -505,12 +655,12 @@ function extractASTPatterns(content, filePath) {
|
|
|
505
655
|
trustScore: 85,
|
|
506
656
|
});
|
|
507
657
|
}
|
|
508
|
-
if (
|
|
658
|
+
if (maxControlFlowDepth > 4) {
|
|
509
659
|
patterns.push({
|
|
510
660
|
type: 'blind_spot_deep_nesting',
|
|
511
661
|
category: 'blind_spots',
|
|
512
|
-
value: `max_nesting:${
|
|
513
|
-
count:
|
|
662
|
+
value: `max_nesting:${maxControlFlowDepth}`,
|
|
663
|
+
count: maxControlFlowDepth,
|
|
514
664
|
trustScore: 80,
|
|
515
665
|
});
|
|
516
666
|
}
|
|
@@ -532,6 +682,42 @@ function extractASTPatterns(content, filePath) {
|
|
|
532
682
|
trustScore: 90,
|
|
533
683
|
});
|
|
534
684
|
}
|
|
685
|
+
if (nPlusOne > 0) {
|
|
686
|
+
patterns.push({
|
|
687
|
+
type: 'blind_spot_n_plus_one',
|
|
688
|
+
category: 'blind_spots',
|
|
689
|
+
value: `n_plus_one_queries:${nPlusOne}`,
|
|
690
|
+
count: nPlusOne,
|
|
691
|
+
trustScore: 85,
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
if (hardcodedSecrets > 0) {
|
|
695
|
+
patterns.push({
|
|
696
|
+
type: 'blind_spot_hardcoded_secret',
|
|
697
|
+
category: 'blind_spots',
|
|
698
|
+
value: `hardcoded_secrets:${hardcodedSecrets}`,
|
|
699
|
+
count: hardcodedSecrets,
|
|
700
|
+
trustScore: 95,
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
if (missingNullCheck > 0) {
|
|
704
|
+
patterns.push({
|
|
705
|
+
type: 'blind_spot_null_check',
|
|
706
|
+
category: 'blind_spots',
|
|
707
|
+
value: `missing_null_checks:${missingNullCheck}`,
|
|
708
|
+
count: missingNullCheck,
|
|
709
|
+
trustScore: 80,
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
if (missingInputValidation > 0) {
|
|
713
|
+
patterns.push({
|
|
714
|
+
type: 'blind_spot_no_validation',
|
|
715
|
+
category: 'blind_spots',
|
|
716
|
+
value: `missing_input_validation:${missingInputValidation}`,
|
|
717
|
+
count: missingInputValidation,
|
|
718
|
+
trustScore: 85,
|
|
719
|
+
});
|
|
720
|
+
}
|
|
535
721
|
}
|
|
536
722
|
catch { /* AST parse may fail on broken files */ }
|
|
537
723
|
return patterns;
|
|
@@ -602,8 +788,9 @@ function aggregatePatterns(analyses) {
|
|
|
602
788
|
const key = `${pattern.type}:${pattern.value}`;
|
|
603
789
|
const existing = patternMap.get(key);
|
|
604
790
|
if (existing) {
|
|
605
|
-
existing.count
|
|
606
|
-
existing.trustScore = Math.min(95, Math.round((existing.trustScore + pattern.trustScore) /
|
|
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;
|
|
607
794
|
}
|
|
608
795
|
else {
|
|
609
796
|
patternMap.set(key, { ...pattern });
|
|
@@ -688,6 +875,23 @@ function buildDeveloperProfile(patterns) {
|
|
|
688
875
|
strengths.push('Uses Zod validation for inputs');
|
|
689
876
|
else
|
|
690
877
|
improvements.push('Add input validation (Zod/Joi/Yup)');
|
|
878
|
+
// Blind spots v2
|
|
879
|
+
const nPlusOne = patterns.find(p => p.type === 'blind_spot_n_plus_one');
|
|
880
|
+
if (nPlusOne && nPlusOne.count > 0) {
|
|
881
|
+
improvements.push(`${nPlusOne.count} N+1 query patterns — DB calls inside loops`);
|
|
882
|
+
}
|
|
883
|
+
const secrets = patterns.find(p => p.type === 'blind_spot_hardcoded_secret');
|
|
884
|
+
if (secrets && secrets.count > 0) {
|
|
885
|
+
improvements.push(`${secrets.count} hardcoded secrets/API keys — move to env vars`);
|
|
886
|
+
}
|
|
887
|
+
const nullChecks = patterns.find(p => p.type === 'blind_spot_null_check');
|
|
888
|
+
if (nullChecks && nullChecks.count > 0) {
|
|
889
|
+
improvements.push(`${nullChecks.count} API responses used without null check`);
|
|
890
|
+
}
|
|
891
|
+
const noValidation = patterns.find(p => p.type === 'blind_spot_no_validation');
|
|
892
|
+
if (noValidation && noValidation.count > 0) {
|
|
893
|
+
improvements.push(`${noValidation.count} API handlers missing input validation`);
|
|
894
|
+
}
|
|
691
895
|
if (asyncNoTry && asyncNoTry.count === 0 && patterns.find(p => p.type === 'error_trycatch')) {
|
|
692
896
|
strengths.push('All async functions have try/catch error handling');
|
|
693
897
|
}
|
|
@@ -713,54 +917,68 @@ function buildDeveloperProfile(patterns) {
|
|
|
713
917
|
// ─── Database Storage ────────────────────────────────────────────────────────
|
|
714
918
|
function ensureCodePatternTable() {
|
|
715
919
|
const db = (0, database_1.getDb)();
|
|
716
|
-
db.exec(`
|
|
717
|
-
CREATE TABLE IF NOT EXISTS code_patterns (
|
|
718
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
719
|
-
project TEXT NOT NULL,
|
|
720
|
-
file_path TEXT NOT NULL,
|
|
721
|
-
pattern_type TEXT NOT NULL,
|
|
722
|
-
pattern_value TEXT NOT NULL,
|
|
723
|
-
category TEXT NOT NULL,
|
|
724
|
-
count INTEGER DEFAULT 1,
|
|
725
|
-
trust_score INTEGER DEFAULT 50,
|
|
726
|
-
language TEXT,
|
|
727
|
-
created_at TEXT DEFAULT (datetime('now'))
|
|
728
|
-
);
|
|
729
|
-
CREATE INDEX IF NOT EXISTS idx_code_patterns_project ON code_patterns(project);
|
|
730
|
-
CREATE INDEX IF NOT EXISTS idx_code_patterns_type ON code_patterns(pattern_type);
|
|
731
|
-
CREATE INDEX IF NOT EXISTS idx_code_patterns_category ON code_patterns(category);
|
|
732
|
-
|
|
733
|
-
CREATE TABLE IF NOT EXISTS developer_profiles (
|
|
734
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
735
|
-
project TEXT NOT NULL UNIQUE,
|
|
736
|
-
naming_style TEXT,
|
|
737
|
-
import_style TEXT,
|
|
738
|
-
export_style TEXT,
|
|
739
|
-
error_handling TEXT,
|
|
740
|
-
function_style TEXT,
|
|
741
|
-
async_style TEXT,
|
|
742
|
-
comment_style TEXT,
|
|
743
|
-
indent_style TEXT,
|
|
744
|
-
quote_style TEXT,
|
|
745
|
-
semicolon_style TEXT,
|
|
746
|
-
architecture_style TEXT,
|
|
747
|
-
test_pattern TEXT,
|
|
748
|
-
top_patterns TEXT,
|
|
749
|
-
strengths TEXT,
|
|
750
|
-
improvements TEXT,
|
|
751
|
-
files_scanned INTEGER DEFAULT 0,
|
|
752
|
-
total_lines INTEGER DEFAULT 0,
|
|
753
|
-
languages TEXT,
|
|
754
|
-
scanned_at TEXT DEFAULT (datetime('now'))
|
|
755
|
-
);
|
|
756
|
-
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);
|
|
757
961
|
`);
|
|
758
962
|
}
|
|
759
|
-
function saveToDatabase(project, result) {
|
|
963
|
+
function saveToDatabase(project, result, projectPath) {
|
|
760
964
|
const db = (0, database_1.getDb)();
|
|
761
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
|
+
}
|
|
762
980
|
db.prepare('DELETE FROM code_patterns WHERE project = ?').run(project);
|
|
763
|
-
const insertPattern = db.prepare('INSERT INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count,
|
|
981
|
+
const insertPattern = db.prepare('INSERT INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count, trust_score, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
|
|
764
982
|
const insertMany = db.transaction((patterns) => {
|
|
765
983
|
for (const p of patterns) {
|
|
766
984
|
insertPattern.run(project, 'scan', p.type, p.value, p.category, p.count, p.trustScore, '');
|
|
@@ -768,16 +986,23 @@ function saveToDatabase(project, result) {
|
|
|
768
986
|
});
|
|
769
987
|
insertMany(result.patterns);
|
|
770
988
|
db.prepare('DELETE FROM developer_profiles WHERE project = ?').run(project);
|
|
771
|
-
db.prepare(`INSERT INTO developer_profiles
|
|
772
|
-
(project, naming_style, import_style, export_style, error_handling, function_style,
|
|
773
|
-
async_style, comment_style, indent_style, quote_style, semicolon_style,
|
|
774
|
-
architecture_style, test_pattern, top_patterns, strengths, improvements,
|
|
775
|
-
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)
|
|
776
994
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))`)
|
|
777
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));
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
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
|
+
}
|
|
781
1006
|
}
|
|
782
1007
|
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
783
1008
|
function scanCodebase(dirPath, projectName) {
|
|
@@ -807,11 +1032,71 @@ function scanCodebase(dirPath, projectName) {
|
|
|
807
1032
|
patterns,
|
|
808
1033
|
profile,
|
|
809
1034
|
};
|
|
810
|
-
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 = [];
|
|
811
1097
|
// ─── CONNECT: Scanner → Behavioral Tracker ───────────────────────────────
|
|
812
1098
|
try {
|
|
813
1099
|
const { logError, logDecision, logContext } = require('./behavioral-tracker');
|
|
814
|
-
// Log blind spots as errors
|
|
815
1100
|
if (profile.improvements.length > 0) {
|
|
816
1101
|
for (const imp of profile.improvements) {
|
|
817
1102
|
logError({
|
|
@@ -823,7 +1108,6 @@ function scanCodebase(dirPath, projectName) {
|
|
|
823
1108
|
});
|
|
824
1109
|
}
|
|
825
1110
|
}
|
|
826
|
-
// Log architecture decision
|
|
827
1111
|
logDecision({
|
|
828
1112
|
project,
|
|
829
1113
|
file: 'scan-auto',
|
|
@@ -831,33 +1115,106 @@ function scanCodebase(dirPath, projectName) {
|
|
|
831
1115
|
approach: `Scan detected ${files.length} files, ${result.languages ? Object.keys(result.languages).join(', ') : 'unknown'}`,
|
|
832
1116
|
worked: true,
|
|
833
1117
|
});
|
|
834
|
-
// Log current context
|
|
835
1118
|
logContext({
|
|
836
1119
|
project,
|
|
837
1120
|
task: `Codebase scan completed — ${files.length} files, ${totalLines.toLocaleString()} lines`,
|
|
838
1121
|
files: [dirPath],
|
|
839
1122
|
});
|
|
1123
|
+
hookResults.push({ hook: 'behavioral-tracker', ok: true });
|
|
1124
|
+
}
|
|
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));
|
|
840
1128
|
}
|
|
841
|
-
|
|
842
|
-
// ─── CONNECT: Git Intelligence (behavior + journey + user analysis) ──────
|
|
1129
|
+
// ─── CONNECT: Git Intelligence ──────
|
|
843
1130
|
try {
|
|
844
1131
|
const { buildDeveloperIntelligence } = require('./developer-intelligence');
|
|
845
1132
|
const gitIntel = buildDeveloperIntelligence(dirPath);
|
|
846
1133
|
if (gitIntel) {
|
|
847
1134
|
console.log(`[cell] Git intelligence: ${gitIntel.topBlindSpots.length} blind spots, ${gitIntel.topMistakes.length} repeat mistakes, score: ${gitIntel.behavioralScore}/100`);
|
|
848
1135
|
}
|
|
1136
|
+
hookResults.push({ hook: 'developer-intelligence', ok: true });
|
|
849
1137
|
}
|
|
850
|
-
catch {
|
|
851
|
-
|
|
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 ────
|
|
852
1143
|
try {
|
|
853
1144
|
const { writeStyleFiles, buildStyleSummary } = require('./style-pull');
|
|
854
1145
|
const summary = buildStyleSummary(dirPath);
|
|
855
|
-
const
|
|
856
|
-
if (
|
|
857
|
-
console.log(`[cell] Generated: ${
|
|
1146
|
+
const styleResult = writeStyleFiles(dirPath, summary, { force: false });
|
|
1147
|
+
if (styleResult.written.length > 0) {
|
|
1148
|
+
console.log(`[cell] Generated: ${styleResult.written.join(', ')}`);
|
|
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));
|
|
1155
|
+
}
|
|
1156
|
+
// ─── CONNECT: Stack Detector ──────────
|
|
1157
|
+
try {
|
|
1158
|
+
const dna = (0, stack_detector_1.detectProjectDNA)(dirPath);
|
|
1159
|
+
const projectName = dna.name || project;
|
|
1160
|
+
const db = (0, database_1.getDb)();
|
|
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, '');
|
|
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(', '));
|
|
1164
|
+
console.log('[cell] Arch: ' + dna.architecture.type + ' (' + dna.architecture.confidence + '), Entry: ' + dna.architecture.entryPoints.join(', '));
|
|
1165
|
+
hookResults.push({ hook: 'stack-detector', ok: true });
|
|
1166
|
+
}
|
|
1167
|
+
catch (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));
|
|
1170
|
+
}
|
|
1171
|
+
// ─── CONNECT: Knowledge Graph ────────────────────────────────────
|
|
1172
|
+
try {
|
|
1173
|
+
const { buildKnowledgeGraph } = require('./knowledge-graph-builder');
|
|
1174
|
+
const graph = buildKnowledgeGraph(dirPath);
|
|
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 });
|
|
1177
|
+
}
|
|
1178
|
+
catch (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 { }
|
|
858
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(', ')}`);
|
|
859
1216
|
}
|
|
860
|
-
|
|
1217
|
+
result.hookResults = hookResults;
|
|
861
1218
|
return result;
|
|
862
1219
|
}
|
|
863
1220
|
function getDeveloperProfile(project) {
|