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.
Files changed (117) hide show
  1. package/.claude/skills/.validation/schemas/skill-eval.schema.json +11 -1
  2. package/.claude/skills/pr-review/SKILL.md +2 -2
  3. package/.claude/skills/qcsd-production-swarm/SKILL.md +2781 -0
  4. package/.claude/skills/qcsd-production-swarm/evals/qcsd-production-swarm.yaml +246 -0
  5. package/.claude/skills/qcsd-production-swarm/schemas/output.json +505 -0
  6. package/.claude/skills/qcsd-production-swarm/scripts/validate-config.json +25 -0
  7. package/.claude/skills/skills-manifest.json +5 -5
  8. package/package.json +1 -1
  9. package/scripts/benchmark-hnsw-loading.ts +480 -0
  10. package/scripts/benchmark-kg-assisted.ts +725 -0
  11. package/scripts/collect-production-telemetry.sh +291 -0
  12. package/scripts/detect-skill-conflicts.ts +347 -0
  13. package/scripts/eval-driven-workflow.ts +704 -0
  14. package/scripts/run-skill-eval.ts +210 -10
  15. package/scripts/score-skill-quality.ts +511 -0
  16. package/v3/CHANGELOG.md +44 -0
  17. package/v3/assets/skills/pr-review/SKILL.md +2 -2
  18. package/v3/dist/cli/bundle.js +1526 -700
  19. package/v3/dist/cli/commands/code.d.ts.map +1 -1
  20. package/v3/dist/cli/commands/code.js +9 -85
  21. package/v3/dist/cli/commands/code.js.map +1 -1
  22. package/v3/dist/cli/commands/coverage.d.ts.map +1 -1
  23. package/v3/dist/cli/commands/coverage.js +3 -28
  24. package/v3/dist/cli/commands/coverage.js.map +1 -1
  25. package/v3/dist/cli/commands/hooks.d.ts.map +1 -1
  26. package/v3/dist/cli/commands/hooks.js +143 -2
  27. package/v3/dist/cli/commands/hooks.js.map +1 -1
  28. package/v3/dist/cli/commands/security.d.ts.map +1 -1
  29. package/v3/dist/cli/commands/security.js +3 -29
  30. package/v3/dist/cli/commands/security.js.map +1 -1
  31. package/v3/dist/cli/commands/test.d.ts.map +1 -1
  32. package/v3/dist/cli/commands/test.js +11 -58
  33. package/v3/dist/cli/commands/test.js.map +1 -1
  34. package/v3/dist/cli/utils/file-discovery.d.ts +27 -0
  35. package/v3/dist/cli/utils/file-discovery.d.ts.map +1 -0
  36. package/v3/dist/cli/utils/file-discovery.js +105 -0
  37. package/v3/dist/cli/utils/file-discovery.js.map +1 -0
  38. package/v3/dist/coordination/task-executor.d.ts.map +1 -1
  39. package/v3/dist/coordination/task-executor.js +304 -44
  40. package/v3/dist/coordination/task-executor.js.map +1 -1
  41. package/v3/dist/domains/code-intelligence/coordinator.d.ts.map +1 -1
  42. package/v3/dist/domains/code-intelligence/coordinator.js +8 -1
  43. package/v3/dist/domains/code-intelligence/coordinator.js.map +1 -1
  44. package/v3/dist/domains/code-intelligence/services/metric-collector/index.d.ts.map +1 -1
  45. package/v3/dist/domains/code-intelligence/services/metric-collector/index.js +10 -0
  46. package/v3/dist/domains/code-intelligence/services/metric-collector/index.js.map +1 -1
  47. package/v3/dist/domains/code-intelligence/services/metric-collector/interfaces.d.ts +7 -1
  48. package/v3/dist/domains/code-intelligence/services/metric-collector/interfaces.d.ts.map +1 -1
  49. package/v3/dist/domains/code-intelligence/services/metric-collector/interfaces.js +10 -1
  50. package/v3/dist/domains/code-intelligence/services/metric-collector/interfaces.js.map +1 -1
  51. package/v3/dist/domains/code-intelligence/services/metric-collector/loc-counter.js +34 -10
  52. package/v3/dist/domains/code-intelligence/services/metric-collector/loc-counter.js.map +1 -1
  53. package/v3/dist/domains/coverage-analysis/services/hnsw-index.d.ts +9 -0
  54. package/v3/dist/domains/coverage-analysis/services/hnsw-index.d.ts.map +1 -1
  55. package/v3/dist/domains/coverage-analysis/services/hnsw-index.js +38 -3
  56. package/v3/dist/domains/coverage-analysis/services/hnsw-index.js.map +1 -1
  57. package/v3/dist/domains/test-generation/generators/jest-vitest-generator.d.ts.map +1 -1
  58. package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js +58 -6
  59. package/v3/dist/domains/test-generation/generators/jest-vitest-generator.js.map +1 -1
  60. package/v3/dist/domains/test-generation/generators/mocha-generator.d.ts.map +1 -1
  61. package/v3/dist/domains/test-generation/generators/mocha-generator.js +79 -7
  62. package/v3/dist/domains/test-generation/generators/mocha-generator.js.map +1 -1
  63. package/v3/dist/domains/test-generation/generators/pytest-generator.d.ts +4 -0
  64. package/v3/dist/domains/test-generation/generators/pytest-generator.d.ts.map +1 -1
  65. package/v3/dist/domains/test-generation/generators/pytest-generator.js +77 -10
  66. package/v3/dist/domains/test-generation/generators/pytest-generator.js.map +1 -1
  67. package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts +21 -0
  68. package/v3/dist/domains/test-generation/interfaces/test-generator.interface.d.ts.map +1 -1
  69. package/v3/dist/domains/test-generation/interfaces.d.ts +21 -0
  70. package/v3/dist/domains/test-generation/interfaces.d.ts.map +1 -1
  71. package/v3/dist/domains/test-generation/services/test-generator.d.ts +22 -0
  72. package/v3/dist/domains/test-generation/services/test-generator.d.ts.map +1 -1
  73. package/v3/dist/domains/test-generation/services/test-generator.js +163 -3
  74. package/v3/dist/domains/test-generation/services/test-generator.js.map +1 -1
  75. package/v3/dist/init/init-wizard-hooks.d.ts +8 -1
  76. package/v3/dist/init/init-wizard-hooks.d.ts.map +1 -1
  77. package/v3/dist/init/init-wizard-hooks.js +47 -39
  78. package/v3/dist/init/init-wizard-hooks.js.map +1 -1
  79. package/v3/dist/init/phases/07-hooks.d.ts +11 -1
  80. package/v3/dist/init/phases/07-hooks.d.ts.map +1 -1
  81. package/v3/dist/init/phases/07-hooks.js +46 -50
  82. package/v3/dist/init/phases/07-hooks.js.map +1 -1
  83. package/v3/dist/init/settings-merge.d.ts +35 -0
  84. package/v3/dist/init/settings-merge.d.ts.map +1 -0
  85. package/v3/dist/init/settings-merge.js +140 -0
  86. package/v3/dist/init/settings-merge.js.map +1 -0
  87. package/v3/dist/integrations/agentic-flow/model-router/router.js +1 -1
  88. package/v3/dist/integrations/agentic-flow/model-router/router.js.map +1 -1
  89. package/v3/dist/integrations/agentic-flow/model-router/score-calculator.d.ts.map +1 -1
  90. package/v3/dist/integrations/agentic-flow/model-router/score-calculator.js +18 -3
  91. package/v3/dist/integrations/agentic-flow/model-router/score-calculator.js.map +1 -1
  92. package/v3/dist/integrations/agentic-flow/model-router/signal-collector.d.ts +3 -3
  93. package/v3/dist/integrations/agentic-flow/model-router/signal-collector.d.ts.map +1 -1
  94. package/v3/dist/integrations/agentic-flow/model-router/signal-collector.js +18 -0
  95. package/v3/dist/integrations/agentic-flow/model-router/signal-collector.js.map +1 -1
  96. package/v3/dist/kernel/unified-memory-hnsw.d.ts +29 -0
  97. package/v3/dist/kernel/unified-memory-hnsw.d.ts.map +1 -1
  98. package/v3/dist/kernel/unified-memory-hnsw.js +136 -0
  99. package/v3/dist/kernel/unified-memory-hnsw.js.map +1 -1
  100. package/v3/dist/kernel/unified-memory.d.ts +2 -2
  101. package/v3/dist/kernel/unified-memory.d.ts.map +1 -1
  102. package/v3/dist/kernel/unified-memory.js +7 -9
  103. package/v3/dist/kernel/unified-memory.js.map +1 -1
  104. package/v3/dist/learning/qe-hooks.d.ts.map +1 -1
  105. package/v3/dist/learning/qe-hooks.js +34 -3
  106. package/v3/dist/learning/qe-hooks.js.map +1 -1
  107. package/v3/dist/mcp/bundle.js +1403 -425
  108. package/v3/dist/mcp/handlers/domain-handler-configs.d.ts.map +1 -1
  109. package/v3/dist/mcp/handlers/domain-handler-configs.js +40 -31
  110. package/v3/dist/mcp/handlers/domain-handler-configs.js.map +1 -1
  111. package/v3/dist/mcp/handlers/task-handlers.d.ts.map +1 -1
  112. package/v3/dist/mcp/handlers/task-handlers.js +68 -5
  113. package/v3/dist/mcp/handlers/task-handlers.js.map +1 -1
  114. package/v3/dist/mcp/protocol-server.d.ts.map +1 -1
  115. package/v3/dist/mcp/protocol-server.js +16 -2
  116. package/v3/dist/mcp/protocol-server.js.map +1 -1
  117. 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
- let extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
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'].includes(entry.name)) {
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
- const tempPath = `/tmp/aqe-temp-${uuidv4()}.ts`;
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 TypeScript/JavaScript files found in ${targetPath}`,
688
+ warning: `No source files found in ${targetPath}`,
646
689
  });
647
690
  }
648
- // Convert string paths to FilePath value objects
649
- const filePathObjects = filesToScan.map(filePath => FilePath.create(filePath));
650
- // Run SAST scan if requested
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 - create mutable copy
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 || ['typescript', 'javascript'],
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
- if (['ts', 'tsx'].includes(ext))
759
- detectedLanguages.add('typescript');
760
- if (['js', 'jsx', 'mjs', 'cjs'].includes(ext))
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
- return ok({
872
- predictedDefects: [
873
- {
874
- file: `${payload.target}/complex-module.ts`,
875
- probability: 0.78,
876
- reason: 'High cyclomatic complexity combined with low test coverage',
877
- },
878
- {
879
- file: `${payload.target}/legacy-handler.ts`,
880
- probability: 0.65,
881
- reason: 'Frequent changes in recent commits with error-prone patterns',
882
- },
883
- ],
884
- riskScore: 42,
885
- recommendations: [
886
- 'Add integration tests for complex-module.ts',
887
- 'Refactor legacy-handler.ts to reduce complexity',
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) => {