agentic-qe 3.6.9 → 3.6.11
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/.claude/skills/.validation/schemas/skill-eval.schema.json +11 -1
- package/.claude/skills/pr-review/SKILL.md +2 -2
- package/.claude/skills/qcsd-production-swarm/SKILL.md +2781 -0
- package/.claude/skills/qcsd-production-swarm/evals/qcsd-production-swarm.yaml +246 -0
- package/.claude/skills/qcsd-production-swarm/schemas/output.json +505 -0
- package/.claude/skills/qcsd-production-swarm/scripts/validate-config.json +25 -0
- package/.claude/skills/skills-manifest.json +5 -5
- package/package.json +1 -1
- package/scripts/benchmark-hnsw-loading.ts +480 -0
- package/scripts/benchmark-kg-assisted.ts +725 -0
- package/scripts/collect-production-telemetry.sh +291 -0
- package/scripts/detect-skill-conflicts.ts +347 -0
- package/scripts/eval-driven-workflow.ts +704 -0
- package/scripts/run-skill-eval.ts +210 -10
- package/scripts/score-skill-quality.ts +511 -0
- package/v3/CHANGELOG.md +44 -0
- package/v3/assets/skills/pr-review/SKILL.md +2 -2
- package/v3/dist/cli/bundle.js +1526 -700
- package/v3/dist/cli/commands/code.d.ts.map +1 -1
- package/v3/dist/cli/commands/code.js +9 -85
- package/v3/dist/cli/commands/code.js.map +1 -1
- package/v3/dist/cli/commands/coverage.d.ts.map +1 -1
- package/v3/dist/cli/commands/coverage.js +3 -28
- package/v3/dist/cli/commands/coverage.js.map +1 -1
- package/v3/dist/cli/commands/hooks.d.ts.map +1 -1
- package/v3/dist/cli/commands/hooks.js +143 -2
- package/v3/dist/cli/commands/hooks.js.map +1 -1
- package/v3/dist/cli/commands/security.d.ts.map +1 -1
- package/v3/dist/cli/commands/security.js +3 -29
- package/v3/dist/cli/commands/security.js.map +1 -1
- package/v3/dist/cli/commands/test.d.ts.map +1 -1
- package/v3/dist/cli/commands/test.js +11 -58
- package/v3/dist/cli/commands/test.js.map +1 -1
- package/v3/dist/cli/utils/file-discovery.d.ts +27 -0
- package/v3/dist/cli/utils/file-discovery.d.ts.map +1 -0
- package/v3/dist/cli/utils/file-discovery.js +105 -0
- package/v3/dist/cli/utils/file-discovery.js.map +1 -0
- package/v3/dist/coordination/task-executor.d.ts.map +1 -1
- package/v3/dist/coordination/task-executor.js +304 -44
- package/v3/dist/coordination/task-executor.js.map +1 -1
- package/v3/dist/domains/code-intelligence/coordinator.d.ts.map +1 -1
- package/v3/dist/domains/code-intelligence/coordinator.js +8 -1
- package/v3/dist/domains/code-intelligence/coordinator.js.map +1 -1
- package/v3/dist/domains/code-intelligence/services/metric-collector/index.d.ts.map +1 -1
- package/v3/dist/domains/code-intelligence/services/metric-collector/index.js +10 -0
- package/v3/dist/domains/code-intelligence/services/metric-collector/index.js.map +1 -1
- package/v3/dist/domains/code-intelligence/services/metric-collector/interfaces.d.ts +7 -1
- package/v3/dist/domains/code-intelligence/services/metric-collector/interfaces.d.ts.map +1 -1
- package/v3/dist/domains/code-intelligence/services/metric-collector/interfaces.js +10 -1
- package/v3/dist/domains/code-intelligence/services/metric-collector/interfaces.js.map +1 -1
- package/v3/dist/domains/code-intelligence/services/metric-collector/loc-counter.js +34 -10
- package/v3/dist/domains/code-intelligence/services/metric-collector/loc-counter.js.map +1 -1
- package/v3/dist/domains/coverage-analysis/services/hnsw-index.d.ts +9 -0
- package/v3/dist/domains/coverage-analysis/services/hnsw-index.d.ts.map +1 -1
- package/v3/dist/domains/coverage-analysis/services/hnsw-index.js +38 -3
- package/v3/dist/domains/coverage-analysis/services/hnsw-index.js.map +1 -1
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js +58 -6
- package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js.map +1 -1
- package/v3/dist/domains/test-generation/generators/mocha-generator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/generators/mocha-generator.js +79 -7
- package/v3/dist/domains/test-generation/generators/mocha-generator.js.map +1 -1
- package/v3/dist/domains/test-generation/generators/pytest-generator.d.ts +4 -0
- package/v3/dist/domains/test-generation/generators/pytest-generator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/generators/pytest-generator.js +77 -10
- package/v3/dist/domains/test-generation/generators/pytest-generator.js.map +1 -1
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts +21 -0
- package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/interfaces.d.ts +21 -0
- package/v3/dist/domains/test-generation/interfaces.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/services/test-generator.d.ts +22 -0
- package/v3/dist/domains/test-generation/services/test-generator.d.ts.map +1 -1
- package/v3/dist/domains/test-generation/services/test-generator.js +163 -3
- package/v3/dist/domains/test-generation/services/test-generator.js.map +1 -1
- package/v3/dist/init/init-wizard-hooks.d.ts +8 -1
- package/v3/dist/init/init-wizard-hooks.d.ts.map +1 -1
- package/v3/dist/init/init-wizard-hooks.js +47 -39
- package/v3/dist/init/init-wizard-hooks.js.map +1 -1
- package/v3/dist/init/phases/07-hooks.d.ts +11 -1
- package/v3/dist/init/phases/07-hooks.d.ts.map +1 -1
- package/v3/dist/init/phases/07-hooks.js +46 -50
- package/v3/dist/init/phases/07-hooks.js.map +1 -1
- package/v3/dist/init/settings-merge.d.ts +35 -0
- package/v3/dist/init/settings-merge.d.ts.map +1 -0
- package/v3/dist/init/settings-merge.js +140 -0
- package/v3/dist/init/settings-merge.js.map +1 -0
- package/v3/dist/integrations/agentic-flow/model-router/router.js +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/router.js.map +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/score-calculator.d.ts.map +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/score-calculator.js +18 -3
- package/v3/dist/integrations/agentic-flow/model-router/score-calculator.js.map +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.d.ts +3 -3
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.d.ts.map +1 -1
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.js +18 -0
- package/v3/dist/integrations/agentic-flow/model-router/signal-collector.js.map +1 -1
- package/v3/dist/kernel/unified-memory-hnsw.d.ts +29 -0
- package/v3/dist/kernel/unified-memory-hnsw.d.ts.map +1 -1
- package/v3/dist/kernel/unified-memory-hnsw.js +136 -0
- package/v3/dist/kernel/unified-memory-hnsw.js.map +1 -1
- package/v3/dist/kernel/unified-memory.d.ts +2 -2
- package/v3/dist/kernel/unified-memory.d.ts.map +1 -1
- package/v3/dist/kernel/unified-memory.js +7 -9
- package/v3/dist/kernel/unified-memory.js.map +1 -1
- package/v3/dist/learning/qe-hooks.d.ts.map +1 -1
- package/v3/dist/learning/qe-hooks.js +34 -3
- package/v3/dist/learning/qe-hooks.js.map +1 -1
- package/v3/dist/mcp/bundle.js +1403 -425
- package/v3/dist/mcp/handlers/domain-handler-configs.d.ts.map +1 -1
- package/v3/dist/mcp/handlers/domain-handler-configs.js +40 -31
- package/v3/dist/mcp/handlers/domain-handler-configs.js.map +1 -1
- package/v3/dist/mcp/handlers/task-handlers.d.ts.map +1 -1
- package/v3/dist/mcp/handlers/task-handlers.js +68 -5
- package/v3/dist/mcp/handlers/task-handlers.js.map +1 -1
- package/v3/dist/mcp/protocol-server.d.ts.map +1 -1
- package/v3/dist/mcp/protocol-server.js +16 -2
- package/v3/dist/mcp/protocol-server.js.map +1 -1
- package/v3/package.json +1 -1
|
@@ -297,7 +297,20 @@ async function discoverSourceFiles(targetPath, options = {}) {
|
|
|
297
297
|
const files = [];
|
|
298
298
|
const { includeTests = true, languages } = options;
|
|
299
299
|
// Determine file extensions to include
|
|
300
|
-
|
|
300
|
+
// Default: scan ALL common source languages unless explicitly filtered
|
|
301
|
+
let extensions = [
|
|
302
|
+
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', // JavaScript/TypeScript
|
|
303
|
+
'.py', '.pyw', // Python
|
|
304
|
+
'.go', // Go
|
|
305
|
+
'.rs', // Rust
|
|
306
|
+
'.java', '.kt', '.kts', // Java/Kotlin
|
|
307
|
+
'.rb', // Ruby
|
|
308
|
+
'.cs', // C#
|
|
309
|
+
'.php', // PHP
|
|
310
|
+
'.swift', // Swift
|
|
311
|
+
'.c', '.h', '.cpp', '.hpp', '.cc', // C/C++
|
|
312
|
+
'.scala', // Scala
|
|
313
|
+
];
|
|
301
314
|
if (languages && languages.length > 0) {
|
|
302
315
|
extensions = [];
|
|
303
316
|
for (const lang of languages) {
|
|
@@ -306,7 +319,27 @@ async function discoverSourceFiles(targetPath, options = {}) {
|
|
|
306
319
|
if (lang === 'javascript')
|
|
307
320
|
extensions.push('.js', '.jsx', '.mjs', '.cjs');
|
|
308
321
|
if (lang === 'python')
|
|
309
|
-
extensions.push('.py');
|
|
322
|
+
extensions.push('.py', '.pyw');
|
|
323
|
+
if (lang === 'go')
|
|
324
|
+
extensions.push('.go');
|
|
325
|
+
if (lang === 'rust')
|
|
326
|
+
extensions.push('.rs');
|
|
327
|
+
if (lang === 'java')
|
|
328
|
+
extensions.push('.java');
|
|
329
|
+
if (lang === 'kotlin')
|
|
330
|
+
extensions.push('.kt', '.kts');
|
|
331
|
+
if (lang === 'ruby')
|
|
332
|
+
extensions.push('.rb');
|
|
333
|
+
if (lang === 'csharp' || lang === 'c#')
|
|
334
|
+
extensions.push('.cs');
|
|
335
|
+
if (lang === 'php')
|
|
336
|
+
extensions.push('.php');
|
|
337
|
+
if (lang === 'swift')
|
|
338
|
+
extensions.push('.swift');
|
|
339
|
+
if (lang === 'c' || lang === 'cpp' || lang === 'c++')
|
|
340
|
+
extensions.push('.c', '.h', '.cpp', '.hpp', '.cc');
|
|
341
|
+
if (lang === 'scala')
|
|
342
|
+
extensions.push('.scala');
|
|
310
343
|
}
|
|
311
344
|
}
|
|
312
345
|
async function walkDir(dir) {
|
|
@@ -316,7 +349,9 @@ async function discoverSourceFiles(targetPath, options = {}) {
|
|
|
316
349
|
const fullPath = path.join(dir, entry.name);
|
|
317
350
|
// Skip common non-source directories
|
|
318
351
|
if (entry.isDirectory()) {
|
|
319
|
-
if (['node_modules', '.git', 'dist', 'build', 'coverage', '.nyc_output'
|
|
352
|
+
if (['node_modules', '.git', 'dist', 'build', 'coverage', '.nyc_output',
|
|
353
|
+
'__pycache__', '.venv', 'venv', '.tox', '.mypy_cache', 'target',
|
|
354
|
+
'.gradle', 'vendor', '.bundle'].includes(entry.name)) {
|
|
320
355
|
continue;
|
|
321
356
|
}
|
|
322
357
|
await walkDir(fullPath);
|
|
@@ -515,7 +550,15 @@ export class DomainTaskExecutor {
|
|
|
515
550
|
}
|
|
516
551
|
else if (payload.sourceCode) {
|
|
517
552
|
// Write temporary file for analysis if only source code provided
|
|
518
|
-
|
|
553
|
+
// Use correct file extension based on language parameter
|
|
554
|
+
const langExtMap = {
|
|
555
|
+
python: '.py', typescript: '.ts', javascript: '.js',
|
|
556
|
+
go: '.go', rust: '.rs', java: '.java', ruby: '.rb',
|
|
557
|
+
kotlin: '.kt', csharp: '.cs', php: '.php', swift: '.swift',
|
|
558
|
+
cpp: '.cpp', c: '.c', scala: '.scala',
|
|
559
|
+
};
|
|
560
|
+
const ext = langExtMap[payload.language?.toLowerCase() || 'typescript'] || '.ts';
|
|
561
|
+
const tempPath = `/tmp/aqe-temp-${uuidv4()}${ext}`;
|
|
519
562
|
await fs.writeFile(tempPath, payload.sourceCode, 'utf-8');
|
|
520
563
|
sourceFiles = [tempPath];
|
|
521
564
|
}
|
|
@@ -642,14 +685,113 @@ export class DomainTaskExecutor {
|
|
|
642
685
|
sast: payload.sast !== false,
|
|
643
686
|
dast: payload.dast || false,
|
|
644
687
|
},
|
|
645
|
-
warning: `No
|
|
688
|
+
warning: `No source files found in ${targetPath}`,
|
|
646
689
|
});
|
|
647
690
|
}
|
|
648
|
-
//
|
|
649
|
-
const
|
|
650
|
-
|
|
691
|
+
// Separate files by language capability
|
|
692
|
+
const jstsFiles = filesToScan.filter(f => /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(f));
|
|
693
|
+
const otherFiles = filesToScan.filter(f => !/\.(ts|tsx|js|jsx|mjs|cjs)$/.test(f));
|
|
694
|
+
// Run basic cross-language security patterns on non-JS/TS files
|
|
695
|
+
const crossLangVulns = [];
|
|
696
|
+
for (const filePath of otherFiles) {
|
|
697
|
+
try {
|
|
698
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
699
|
+
const lines = content.split('\n');
|
|
700
|
+
const relPath = filePath.startsWith(targetPath)
|
|
701
|
+
? filePath.slice(targetPath.length).replace(/^\//, '')
|
|
702
|
+
: filePath;
|
|
703
|
+
// Pattern: Hardcoded secrets/keys
|
|
704
|
+
const secretPatterns = [
|
|
705
|
+
{ regex: /(?:secret|password|api_key|apikey|token|jwt_secret|private_key)\s*[=:]\s*['"][^'"]{8,}['"]/gi, title: 'Hardcoded secret', severity: 'critical' },
|
|
706
|
+
{ regex: /(?:AWS_SECRET|GITHUB_TOKEN|SLACK_TOKEN)\s*[=:]\s*['"][^'"]+['"]/gi, title: 'Hardcoded cloud credential', severity: 'critical' },
|
|
707
|
+
];
|
|
708
|
+
for (const pattern of secretPatterns) {
|
|
709
|
+
for (let i = 0; i < lines.length; i++) {
|
|
710
|
+
if (pattern.regex.test(lines[i])) {
|
|
711
|
+
crossLangVulns.push({
|
|
712
|
+
title: pattern.title,
|
|
713
|
+
severity: pattern.severity,
|
|
714
|
+
location: { file: relPath, line: i + 1 },
|
|
715
|
+
description: `Potential hardcoded secret found at line ${i + 1}`,
|
|
716
|
+
category: 'sensitive-data',
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
// Reset regex lastIndex for global regexes
|
|
720
|
+
pattern.regex.lastIndex = 0;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
// Pattern: SQL injection risks
|
|
724
|
+
const sqlPatterns = /(?:execute|query|cursor\.execute)\s*\(\s*(?:f['"]|['"].*%s|['"].*\+\s*\w)/gi;
|
|
725
|
+
for (let i = 0; i < lines.length; i++) {
|
|
726
|
+
if (sqlPatterns.test(lines[i])) {
|
|
727
|
+
crossLangVulns.push({
|
|
728
|
+
title: 'Potential SQL injection',
|
|
729
|
+
severity: 'high',
|
|
730
|
+
location: { file: relPath, line: i + 1 },
|
|
731
|
+
description: 'String interpolation in SQL query — use parameterized queries',
|
|
732
|
+
category: 'injection',
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
sqlPatterns.lastIndex = 0;
|
|
736
|
+
}
|
|
737
|
+
// Pattern: CORS wildcard
|
|
738
|
+
if (/allow_origins\s*=\s*\[?\s*['"]?\*['"]?\s*\]?/i.test(content)) {
|
|
739
|
+
crossLangVulns.push({
|
|
740
|
+
title: 'CORS wildcard origin',
|
|
741
|
+
severity: 'high',
|
|
742
|
+
location: { file: relPath, line: lines.findIndex(l => /allow_origins/i.test(l)) + 1 },
|
|
743
|
+
description: 'CORS configured with wildcard (*) origin — restrict to specific domains',
|
|
744
|
+
category: 'security-misconfiguration',
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
// Pattern: Debug/development mode enabled
|
|
748
|
+
if (/(?:DEBUG|debug)\s*[=:]\s*(?:True|true|1)/i.test(content)) {
|
|
749
|
+
crossLangVulns.push({
|
|
750
|
+
title: 'Debug mode enabled',
|
|
751
|
+
severity: 'medium',
|
|
752
|
+
location: { file: relPath, line: lines.findIndex(l => /DEBUG\s*[=:]\s*(?:True|true|1)/i.test(l)) + 1 },
|
|
753
|
+
description: 'Debug mode should be disabled in production',
|
|
754
|
+
category: 'security-misconfiguration',
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
// Pattern: Eval/exec usage
|
|
758
|
+
if (/\b(?:eval|exec)\s*\(/i.test(content)) {
|
|
759
|
+
crossLangVulns.push({
|
|
760
|
+
title: 'Dangerous eval/exec usage',
|
|
761
|
+
severity: 'high',
|
|
762
|
+
location: { file: relPath, line: lines.findIndex(l => /\b(?:eval|exec)\s*\(/.test(l)) + 1 },
|
|
763
|
+
description: 'eval/exec can lead to code injection — avoid using with user input',
|
|
764
|
+
category: 'injection',
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
catch {
|
|
769
|
+
// Skip unreadable files
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
// Also check dependency manifests for known vulnerable packages
|
|
773
|
+
const depManifests = ['requirements.txt', 'pyproject.toml', 'Gemfile', 'go.mod', 'Cargo.toml'];
|
|
774
|
+
for (const manifest of depManifests) {
|
|
775
|
+
const manifestPath = path.join(targetPath, manifest);
|
|
776
|
+
try {
|
|
777
|
+
await fs.access(manifestPath);
|
|
778
|
+
crossLangVulns.push({
|
|
779
|
+
title: 'Dependency audit recommended',
|
|
780
|
+
severity: 'informational',
|
|
781
|
+
location: { file: manifest, line: 1 },
|
|
782
|
+
description: `Found ${manifest} — run language-specific dependency audit (e.g., pip-audit, npm audit, cargo audit)`,
|
|
783
|
+
category: 'dependencies',
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
catch {
|
|
787
|
+
// Manifest doesn't exist
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
// Convert JS/TS file paths to FilePath value objects for the SAST scanner
|
|
791
|
+
const filePathObjects = jstsFiles.map(filePath => FilePath.create(filePath));
|
|
792
|
+
// Run SAST scan on JS/TS files if requested and files exist
|
|
651
793
|
let sastResult = null;
|
|
652
|
-
if (payload.sast !== false) {
|
|
794
|
+
if (payload.sast !== false && filePathObjects.length > 0) {
|
|
653
795
|
const result = await scanner.scanFiles(filePathObjects);
|
|
654
796
|
if (result.success) {
|
|
655
797
|
sastResult = result.value;
|
|
@@ -667,18 +809,26 @@ export class DomainTaskExecutor {
|
|
|
667
809
|
dastResult = result.value;
|
|
668
810
|
}
|
|
669
811
|
}
|
|
670
|
-
// Combine results -
|
|
812
|
+
// Combine results from all scan sources - SAST, DAST, and cross-language patterns
|
|
813
|
+
const crossLangSeverityCounts = {
|
|
814
|
+
critical: crossLangVulns.filter(v => v.severity === 'critical').length,
|
|
815
|
+
high: crossLangVulns.filter(v => v.severity === 'high').length,
|
|
816
|
+
medium: crossLangVulns.filter(v => v.severity === 'medium').length,
|
|
817
|
+
low: crossLangVulns.filter(v => v.severity === 'low').length,
|
|
818
|
+
informational: crossLangVulns.filter(v => v.severity === 'informational').length,
|
|
819
|
+
};
|
|
671
820
|
const summary = {
|
|
672
|
-
critical: (sastResult?.summary?.critical || 0) + (dastResult?.summary?.critical || 0),
|
|
673
|
-
high: (sastResult?.summary?.high || 0) + (dastResult?.summary?.high || 0),
|
|
674
|
-
medium: (sastResult?.summary?.medium || 0) + (dastResult?.summary?.medium || 0),
|
|
675
|
-
low: (sastResult?.summary?.low || 0) + (dastResult?.summary?.low || 0),
|
|
676
|
-
informational: (sastResult?.summary?.informational || 0) + (dastResult?.summary?.informational || 0),
|
|
821
|
+
critical: (sastResult?.summary?.critical || 0) + (dastResult?.summary?.critical || 0) + crossLangSeverityCounts.critical,
|
|
822
|
+
high: (sastResult?.summary?.high || 0) + (dastResult?.summary?.high || 0) + crossLangSeverityCounts.high,
|
|
823
|
+
medium: (sastResult?.summary?.medium || 0) + (dastResult?.summary?.medium || 0) + crossLangSeverityCounts.medium,
|
|
824
|
+
low: (sastResult?.summary?.low || 0) + (dastResult?.summary?.low || 0) + crossLangSeverityCounts.low,
|
|
825
|
+
informational: (sastResult?.summary?.informational || 0) + (dastResult?.summary?.informational || 0) + crossLangSeverityCounts.informational,
|
|
677
826
|
};
|
|
678
|
-
// Extract top vulnerabilities
|
|
827
|
+
// Extract top vulnerabilities from all sources
|
|
679
828
|
const allVulns = [
|
|
680
829
|
...(sastResult?.vulnerabilities || []),
|
|
681
830
|
...(dastResult?.vulnerabilities || []),
|
|
831
|
+
...crossLangVulns,
|
|
682
832
|
];
|
|
683
833
|
const topVulnerabilities = allVulns
|
|
684
834
|
.sort((a, b) => {
|
|
@@ -709,7 +859,12 @@ export class DomainTaskExecutor {
|
|
|
709
859
|
dast: payload.dast || false,
|
|
710
860
|
},
|
|
711
861
|
filesScanned: filesToScan.length,
|
|
862
|
+
jstsFilesScanned: jstsFiles.length,
|
|
863
|
+
otherFilesScanned: otherFiles.length,
|
|
712
864
|
coverage: sastResult?.coverage,
|
|
865
|
+
...(otherFiles.length > 0 && jstsFiles.length === 0 ? {
|
|
866
|
+
note: 'Non-JS/TS files were scanned with cross-language pattern matching. For deeper analysis, use language-specific security tools.',
|
|
867
|
+
} : {}),
|
|
713
868
|
});
|
|
714
869
|
}
|
|
715
870
|
catch (error) {
|
|
@@ -735,9 +890,9 @@ export class DomainTaskExecutor {
|
|
|
735
890
|
edgesCreated: 0,
|
|
736
891
|
target: targetPath,
|
|
737
892
|
incremental: payload.incremental || false,
|
|
738
|
-
languages: payload.languages || [
|
|
893
|
+
languages: payload.languages || [],
|
|
739
894
|
duration: Date.now() - startTime,
|
|
740
|
-
warning: `No source files found in ${targetPath}
|
|
895
|
+
warning: `No source files found in ${targetPath}. Searched for: TypeScript, JavaScript, Python, Go, Rust, Java, Ruby, C/C++, and more.`,
|
|
741
896
|
});
|
|
742
897
|
}
|
|
743
898
|
// Use the real KnowledgeGraphService to index files
|
|
@@ -753,14 +908,21 @@ export class DomainTaskExecutor {
|
|
|
753
908
|
const indexResult = result.value;
|
|
754
909
|
// Detect languages from files
|
|
755
910
|
const detectedLanguages = new Set();
|
|
911
|
+
const extToLang = {
|
|
912
|
+
ts: 'typescript', tsx: 'typescript',
|
|
913
|
+
js: 'javascript', jsx: 'javascript', mjs: 'javascript', cjs: 'javascript',
|
|
914
|
+
py: 'python', pyw: 'python',
|
|
915
|
+
go: 'go', rs: 'rust',
|
|
916
|
+
java: 'java', kt: 'kotlin', kts: 'kotlin',
|
|
917
|
+
rb: 'ruby', cs: 'csharp', php: 'php', swift: 'swift',
|
|
918
|
+
c: 'c', h: 'c', cpp: 'cpp', hpp: 'cpp', cc: 'cpp',
|
|
919
|
+
scala: 'scala',
|
|
920
|
+
};
|
|
756
921
|
for (const file of filesToIndex) {
|
|
757
922
|
const ext = path.extname(file).slice(1);
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
detectedLanguages.add('javascript');
|
|
762
|
-
if (ext === 'py')
|
|
763
|
-
detectedLanguages.add('python');
|
|
923
|
+
const lang = extToLang[ext];
|
|
924
|
+
if (lang)
|
|
925
|
+
detectedLanguages.add(lang);
|
|
764
926
|
}
|
|
765
927
|
return ok({
|
|
766
928
|
filesIndexed: indexResult.filesIndexed,
|
|
@@ -865,28 +1027,126 @@ export class DomainTaskExecutor {
|
|
|
865
1027
|
failedTests: failed > 0 ? ['example.test.ts:42'] : [],
|
|
866
1028
|
});
|
|
867
1029
|
});
|
|
868
|
-
// Register defect prediction handler
|
|
1030
|
+
// Register defect prediction handler - REAL IMPLEMENTATION
|
|
869
1031
|
this.taskHandlers.set('predict-defects', async (task) => {
|
|
870
1032
|
const payload = task.payload;
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
]
|
|
889
|
-
|
|
1033
|
+
try {
|
|
1034
|
+
const targetPath = payload.target || process.cwd();
|
|
1035
|
+
const minConfidence = payload.minConfidence || 0.5;
|
|
1036
|
+
// Discover actual source files in the target directory
|
|
1037
|
+
const sourceFiles = await discoverSourceFiles(targetPath, { includeTests: false });
|
|
1038
|
+
if (sourceFiles.length === 0) {
|
|
1039
|
+
return ok({
|
|
1040
|
+
predictedDefects: [],
|
|
1041
|
+
riskScore: 0,
|
|
1042
|
+
recommendations: [
|
|
1043
|
+
`No source files found in ${targetPath}. Ensure the path contains source code files.`,
|
|
1044
|
+
],
|
|
1045
|
+
warning: `No source files found in ${targetPath}`,
|
|
1046
|
+
filesAnalyzed: 0,
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
// Analyze each file for defect indicators based on real metrics
|
|
1050
|
+
const predictedDefects = [];
|
|
1051
|
+
for (const filePath of sourceFiles) {
|
|
1052
|
+
try {
|
|
1053
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
1054
|
+
const lines = content.split('\n');
|
|
1055
|
+
const lineCount = lines.length;
|
|
1056
|
+
// Calculate complexity indicators from real code
|
|
1057
|
+
let probability = 0;
|
|
1058
|
+
const reasons = [];
|
|
1059
|
+
// Factor 1: File size (large files are more defect-prone)
|
|
1060
|
+
if (lineCount > 500) {
|
|
1061
|
+
probability += 0.25;
|
|
1062
|
+
reasons.push(`Large file (${lineCount} lines)`);
|
|
1063
|
+
}
|
|
1064
|
+
else if (lineCount > 300) {
|
|
1065
|
+
probability += 0.15;
|
|
1066
|
+
reasons.push(`Medium-large file (${lineCount} lines)`);
|
|
1067
|
+
}
|
|
1068
|
+
// Factor 2: Cyclomatic complexity indicators
|
|
1069
|
+
const branchKeywords = content.match(/\b(if|else|switch|case|for|while|catch|&&|\|\|)\b/g) || [];
|
|
1070
|
+
const branchDensity = branchKeywords.length / Math.max(lineCount, 1);
|
|
1071
|
+
if (branchDensity > 0.15) {
|
|
1072
|
+
probability += 0.25;
|
|
1073
|
+
reasons.push(`High branch density (${branchKeywords.length} branches in ${lineCount} lines)`);
|
|
1074
|
+
}
|
|
1075
|
+
else if (branchDensity > 0.08) {
|
|
1076
|
+
probability += 0.10;
|
|
1077
|
+
reasons.push('Moderate branch complexity');
|
|
1078
|
+
}
|
|
1079
|
+
// Factor 3: Deeply nested code
|
|
1080
|
+
const maxIndent = Math.max(...lines.map(l => {
|
|
1081
|
+
const match = l.match(/^(\s*)/);
|
|
1082
|
+
return match ? match[1].length : 0;
|
|
1083
|
+
}));
|
|
1084
|
+
if (maxIndent > 20) {
|
|
1085
|
+
probability += 0.15;
|
|
1086
|
+
reasons.push('Deep nesting detected');
|
|
1087
|
+
}
|
|
1088
|
+
// Factor 4: TODO/FIXME/HACK comments
|
|
1089
|
+
const debtComments = (content.match(/\b(TODO|FIXME|HACK|XXX|WORKAROUND)\b/gi) || []).length;
|
|
1090
|
+
if (debtComments > 3) {
|
|
1091
|
+
probability += 0.15;
|
|
1092
|
+
reasons.push(`${debtComments} technical debt markers`);
|
|
1093
|
+
}
|
|
1094
|
+
// Factor 5: Long functions (heuristic)
|
|
1095
|
+
const functionStarts = (content.match(/\b(function|def|func|async)\b/g) || []).length;
|
|
1096
|
+
if (functionStarts > 0 && lineCount / functionStarts > 80) {
|
|
1097
|
+
probability += 0.10;
|
|
1098
|
+
reasons.push('Potentially long functions');
|
|
1099
|
+
}
|
|
1100
|
+
probability = Math.min(probability, 0.95);
|
|
1101
|
+
if (probability >= minConfidence) {
|
|
1102
|
+
// Use relative path for readability
|
|
1103
|
+
const relativePath = filePath.startsWith(targetPath)
|
|
1104
|
+
? filePath.slice(targetPath.length).replace(/^\//, '')
|
|
1105
|
+
: filePath;
|
|
1106
|
+
predictedDefects.push({
|
|
1107
|
+
file: relativePath,
|
|
1108
|
+
probability: Math.round(probability * 100) / 100,
|
|
1109
|
+
reason: reasons.join('; '),
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
catch {
|
|
1114
|
+
// Skip files that can't be read
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
// Sort by probability descending
|
|
1118
|
+
predictedDefects.sort((a, b) => b.probability - a.probability);
|
|
1119
|
+
// Calculate overall risk score
|
|
1120
|
+
const avgProb = predictedDefects.length > 0
|
|
1121
|
+
? predictedDefects.reduce((sum, d) => sum + d.probability, 0) / predictedDefects.length
|
|
1122
|
+
: 0;
|
|
1123
|
+
const riskScore = Math.round(avgProb * 100);
|
|
1124
|
+
// Generate recommendations from actual findings
|
|
1125
|
+
const recommendations = [];
|
|
1126
|
+
if (predictedDefects.length > 0) {
|
|
1127
|
+
recommendations.push(`${predictedDefects.length} files flagged for potential defects out of ${sourceFiles.length} analyzed`);
|
|
1128
|
+
const topFile = predictedDefects[0];
|
|
1129
|
+
recommendations.push(`Highest risk: ${topFile.file} (${Math.round(topFile.probability * 100)}%) — ${topFile.reason}`);
|
|
1130
|
+
}
|
|
1131
|
+
if (predictedDefects.some(d => d.reason.includes('Large file'))) {
|
|
1132
|
+
recommendations.push('Consider splitting large files to reduce complexity');
|
|
1133
|
+
}
|
|
1134
|
+
if (predictedDefects.some(d => d.reason.includes('technical debt'))) {
|
|
1135
|
+
recommendations.push('Address TODO/FIXME comments to reduce technical debt');
|
|
1136
|
+
}
|
|
1137
|
+
if (predictedDefects.length === 0) {
|
|
1138
|
+
recommendations.push('No files exceeded the defect probability threshold — code looks healthy');
|
|
1139
|
+
}
|
|
1140
|
+
return ok({
|
|
1141
|
+
predictedDefects: predictedDefects.slice(0, 20), // Top 20
|
|
1142
|
+
riskScore,
|
|
1143
|
+
recommendations,
|
|
1144
|
+
filesAnalyzed: sourceFiles.length,
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
catch (error) {
|
|
1148
|
+
return err(toError(error));
|
|
1149
|
+
}
|
|
890
1150
|
});
|
|
891
1151
|
// Register requirements validation handler
|
|
892
1152
|
this.taskHandlers.set('validate-requirements', async (task) => {
|