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.
- 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/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 +368 -1
- package/dist/cli.js.map +1 -1
- package/dist/code-scanner.d.ts.map +1 -1
- package/dist/code-scanner.js +301 -97
- 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 +49 -0
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +482 -67
- 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.map +1 -1
- package/dist/knowledge-graph-builder.js +18 -2
- package/dist/knowledge-graph-builder.js.map +1 -1
- 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/package.json +1 -1
package/dist/code-scanner.js
CHANGED
|
@@ -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) ||
|
|
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
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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 —
|
|
480
|
-
if (ts.isPropertyAccessExpression(expr)
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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
|
-
|
|
487
|
-
|
|
488
|
-
if (
|
|
489
|
-
|
|
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
|
-
|
|
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
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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 (
|
|
529
|
-
checkBody(
|
|
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 (
|
|
658
|
+
if (maxControlFlowDepth > 4) {
|
|
587
659
|
patterns.push({
|
|
588
660
|
type: 'blind_spot_deep_nesting',
|
|
589
661
|
category: 'blind_spots',
|
|
590
|
-
value: `max_nesting:${
|
|
591
|
-
count:
|
|
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
|
|
720
|
-
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;
|
|
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,
|
|
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
|
-
|
|
910
|
-
|
|
911
|
-
|
|
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 {
|
|
973
|
-
|
|
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 {
|
|
982
|
-
|
|
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
|
|
987
|
-
if (
|
|
988
|
-
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(', ')}`);
|
|
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
|
-
|
|
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,
|
|
998
|
-
db.prepare('INSERT OR REPLACE INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count,
|
|
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
|
-
|
|
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
|
-
|
|
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) {
|