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