code-auditor-mcp 4.0.1 → 4.0.3

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 (155) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +101 -0
  3. package/dist/analyzers/analyzerUtils.js +2 -2
  4. package/dist/analyzers/analyzerUtils.js.map +1 -1
  5. package/dist/analyzers/applicability.d.ts +13 -0
  6. package/dist/analyzers/applicability.d.ts.map +1 -1
  7. package/dist/analyzers/applicability.js +1 -1
  8. package/dist/analyzers/applicability.js.map +1 -1
  9. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts +1 -1
  10. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
  11. package/dist/analyzers/cross-language/DependencyGraphBuilder.js +3 -3
  12. package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
  13. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +1 -1
  14. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +5 -5
  15. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
  16. package/dist/analyzers/documentationAnalyzer.js +5 -5
  17. package/dist/analyzers/documentationAnalyzer.js.map +1 -1
  18. package/dist/analyzers/reactAnalyzer.js +8 -8
  19. package/dist/analyzers/reactAnalyzer.js.map +1 -1
  20. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts +2 -2
  21. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -1
  22. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +7 -7
  23. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
  24. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +4 -4
  25. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +10 -10
  26. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
  27. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  28. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +42 -5
  29. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  30. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +1 -1
  31. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +7 -7
  32. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
  33. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +18 -0
  34. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
  35. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +57 -11
  36. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  37. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +1 -1
  38. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
  39. package/dist/analyzers/universal/UniversalStylesAnalyzer.js +9 -9
  40. package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
  41. package/dist/analyzers/universal/schema/codeAnalysis.js +2 -2
  42. package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
  43. package/dist/analyzers/universal/schema/jsonSchema.js +1 -1
  44. package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -1
  45. package/dist/analyzers/universal/schema/violations.d.ts +1 -1
  46. package/dist/analyzers/universal/schema/violations.d.ts.map +1 -1
  47. package/dist/auditRouter.js +2 -2
  48. package/dist/auditRouter.js.map +1 -1
  49. package/dist/auditRunner.d.ts.map +1 -1
  50. package/dist/auditRunner.js +25 -7
  51. package/dist/auditRunner.js.map +1 -1
  52. package/dist/cli.js +73 -24
  53. package/dist/cli.js.map +1 -1
  54. package/dist/config/configLoader.js +1 -1
  55. package/dist/config/configLoader.js.map +1 -1
  56. package/dist/config/defaults.js +3 -3
  57. package/dist/config/defaults.js.map +1 -1
  58. package/dist/constants.d.ts +1 -1
  59. package/dist/daemon/lspServer.js +1 -1
  60. package/dist/daemon/lspServer.js.map +1 -1
  61. package/dist/enforcement/gate.js +2 -2
  62. package/dist/hooks/codex.d.ts.map +1 -1
  63. package/dist/hooks/codex.js +1 -1
  64. package/dist/hooks/codex.js.map +1 -1
  65. package/dist/hooks/core.d.ts +1 -1
  66. package/dist/hooks/core.d.ts.map +1 -1
  67. package/dist/hooks/core.js +4 -4
  68. package/dist/hooks/core.js.map +1 -1
  69. package/dist/hooks/cursor.d.ts.map +1 -1
  70. package/dist/hooks/cursor.js +2 -2
  71. package/dist/hooks/cursor.js.map +1 -1
  72. package/dist/invariants/invariant-rules.schema.json +1 -1
  73. package/dist/invariants/ruleValidator.js +1 -1
  74. package/dist/invariants/ruleValidator.js.map +1 -1
  75. package/dist/invariants/types.d.ts +1 -1
  76. package/dist/invariants/types.d.ts.map +1 -1
  77. package/dist/languages/LanguageOrchestrator.d.ts +2 -2
  78. package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
  79. package/dist/languages/RuntimeManager.js +2 -2
  80. package/dist/languages/RuntimeManager.js.map +1 -1
  81. package/dist/languages/go/analyzer +0 -0
  82. package/dist/languages/go/analyzer-src/analyzer.go +3 -3
  83. package/dist/languages/go/analyzer-src/solid.go +5 -5
  84. package/dist/languages/types.d.ts +1 -1
  85. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +18 -1
  86. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
  87. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +124 -16
  88. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
  89. package/dist/ledger.js +1 -1
  90. package/dist/ledger.js.map +1 -1
  91. package/dist/mcp-tools/projectTasks.js +2 -2
  92. package/dist/mcp-tools/projectTasks.js.map +1 -1
  93. package/dist/mcp-tools/workflowGuide.js +3 -3
  94. package/dist/mcp-tools/workflowGuide.js.map +1 -1
  95. package/dist/mcp-tools-shared.js +13 -13
  96. package/dist/mcp-tools-shared.js.map +1 -1
  97. package/dist/mcp-ui-simple.js +6 -6
  98. package/dist/mcp-ui-simple.js.map +1 -1
  99. package/dist/mcp.js +14 -14
  100. package/dist/mcp.js.map +1 -1
  101. package/dist/mcpAuditJobs.d.ts.map +1 -1
  102. package/dist/mcpAuditJobs.js +13 -9
  103. package/dist/mcpAuditJobs.js.map +1 -1
  104. package/dist/mcpAutoIndex.js +1 -1
  105. package/dist/mcpAutoIndex.js.map +1 -1
  106. package/dist/nextFile.d.ts +2 -2
  107. package/dist/nextFile.d.ts.map +1 -1
  108. package/dist/nextFile.js +3 -3
  109. package/dist/nextFile.js.map +1 -1
  110. package/dist/nextFileIncremental.d.ts +2 -2
  111. package/dist/nextFileIncremental.d.ts.map +1 -1
  112. package/dist/nextFileIncremental.js +16 -14
  113. package/dist/nextFileIncremental.js.map +1 -1
  114. package/dist/pipeline.d.ts.map +1 -1
  115. package/dist/pipeline.js +10 -0
  116. package/dist/pipeline.js.map +1 -1
  117. package/dist/pipelineAdapters.d.ts +39 -2
  118. package/dist/pipelineAdapters.d.ts.map +1 -1
  119. package/dist/pipelineAdapters.js +150 -7
  120. package/dist/pipelineAdapters.js.map +1 -1
  121. package/dist/reporting/csvReportGenerator.js +6 -6
  122. package/dist/reporting/csvReportGenerator.js.map +1 -1
  123. package/dist/reporting/htmlReportGenerator.js +11 -11
  124. package/dist/reporting/htmlReportGenerator.js.map +1 -1
  125. package/dist/reporting/jsonReportGenerator.js +1 -1
  126. package/dist/reporting/jsonReportGenerator.js.map +1 -1
  127. package/dist/reporting/reportGenerator.d.ts +2 -1
  128. package/dist/reporting/reportGenerator.d.ts.map +1 -1
  129. package/dist/reporting/reportGenerator.js +2 -2
  130. package/dist/reporting/reportGenerator.js.map +1 -1
  131. package/dist/reporting/sarifReportGenerator.d.ts +15 -0
  132. package/dist/reporting/sarifReportGenerator.d.ts.map +1 -1
  133. package/dist/reporting/sarifReportGenerator.js +76 -16
  134. package/dist/reporting/sarifReportGenerator.js.map +1 -1
  135. package/dist/reporting/sizeDistribution.d.ts +17 -0
  136. package/dist/reporting/sizeDistribution.d.ts.map +1 -0
  137. package/dist/reporting/sizeDistribution.js +93 -0
  138. package/dist/reporting/sizeDistribution.js.map +1 -0
  139. package/dist/scripts/benchmarkWorkers.js +1 -1
  140. package/dist/scripts/benchmarkWorkers.js.map +1 -1
  141. package/dist/telemetry.d.ts +1 -1
  142. package/dist/telemetry.d.ts.map +1 -1
  143. package/dist/types/crossLanguage.d.ts +1 -1
  144. package/dist/types/crossLanguage.d.ts.map +1 -1
  145. package/dist/types.d.ts +90 -4
  146. package/dist/types.d.ts.map +1 -1
  147. package/dist/types.js +3 -3
  148. package/dist/types.js.map +1 -1
  149. package/dist/version.generated.d.ts +1 -1
  150. package/dist/version.generated.js +1 -1
  151. package/package.json +1 -1
  152. package/plugin/.claude-plugin/plugin.json +1 -1
  153. package/plugin/skills/code-auditor/SKILL-RULE-KINDS.md +7 -7
  154. package/plugin/skills/code-auditor/SKILL.md +9 -9
  155. package/server.json +2 -2
@@ -49,10 +49,9 @@ function lazySingleton(loader) {
49
49
  return promise;
50
50
  };
51
51
  }
52
- // ── SOLID visitor ────────────────────────────────────────────────────────────
53
52
  export function createSolidVisitor() {
54
53
  const getAnalyzer = lazySingleton(() => import('./analyzers/universal/UniversalSOLIDAnalyzer.js').then((m) => new m.UniversalSOLIDAnalyzer()));
55
- return {
54
+ const visitor = {
56
55
  name: 'solid',
57
56
  stage: 'visitor',
58
57
  getRuleIds: () => getRuleIdsFor('solid'),
@@ -68,6 +67,18 @@ export function createSolidVisitor() {
68
67
  description: 'Detects violations of SOLID principles',
69
68
  category: 'architecture',
70
69
  };
70
+ return {
71
+ visitor,
72
+ getSizeSamples: async () => {
73
+ try {
74
+ const a = await getAnalyzer();
75
+ return a.sizeSamples ?? [];
76
+ }
77
+ catch {
78
+ return [];
79
+ }
80
+ },
81
+ };
71
82
  }
72
83
  export function createDryVisitor(fullFunctionIndex) {
73
84
  const getAnalyzer = lazySingleton(() => import('./analyzers/universal/UniversalDRYAnalyzer.js').then((m) => new m.UniversalDRYAnalyzer()));
@@ -544,7 +555,7 @@ export function createReactVisitor() {
544
555
  }
545
556
  }
546
557
  catch {
547
- // Cross-component checks are advisory
558
+ // Cross-component checks are high
548
559
  }
549
560
  return violations;
550
561
  },
@@ -1560,6 +1571,100 @@ function clComputeReachability(fileFacts, options) {
1560
1571
  }
1561
1572
  return { reachability, importersOf };
1562
1573
  }
1574
+ /**
1575
+ * Spec 60 R1 — classify every non-test source module as `tested`,
1576
+ * `untested-live`, or `untested-dead` off the file-level import edges
1577
+ * (`importersOf`), not `function_dependencies`.
1578
+ *
1579
+ * A module is `tested` when a test file imports it *directly* (the edge set is
1580
+ * alias-aware — built by `clResolveImport` through `classifyImportSpecifier`).
1581
+ * `untested-dead` is the *post*-exception dead bucket: a file imported by
1582
+ * nothing *and* not a framework entry point. `deadPreException` is the
1583
+ * empty-importers count before the entry-point exception, so the drop
1584
+ * (`deadPreException - untestedDead`) attributes the entry points exempted.
1585
+ */
1586
+ export function classifyTestCoverage(fileFacts, importersOf, packageEntrySet) {
1587
+ const result = {
1588
+ tested: 0,
1589
+ untestedLive: 0,
1590
+ untestedDead: 0,
1591
+ total: 0,
1592
+ deadPreException: 0,
1593
+ deadPostException: 0,
1594
+ deadDrop: 0,
1595
+ entryPointExemptions: [],
1596
+ testedFiles: [],
1597
+ untestedLiveFiles: [],
1598
+ untestedDeadFiles: [],
1599
+ };
1600
+ for (const fp of fileFacts.keys()) {
1601
+ if (clIsTestFile(fp))
1602
+ continue;
1603
+ result.total++;
1604
+ const importers = importersOf.get(fp);
1605
+ if (!importers || importers.size === 0) {
1606
+ // Imported by nothing — dead *unless* it is a framework entry point.
1607
+ result.deadPreException++;
1608
+ const isPackageEntry = packageEntrySet.has(fp);
1609
+ const isEntry = isPackageEntry || clIsEntryPointFile(fp);
1610
+ if (isEntry) {
1611
+ result.untestedLive++;
1612
+ result.untestedLiveFiles.push(fp);
1613
+ result.entryPointExemptions.push({
1614
+ file: fp,
1615
+ kind: isPackageEntry ? 'package-entry' : 'entry-point',
1616
+ });
1617
+ }
1618
+ else {
1619
+ result.untestedDead++;
1620
+ result.untestedDeadFiles.push(fp);
1621
+ }
1622
+ continue;
1623
+ }
1624
+ let hasTestImporter = false;
1625
+ for (const importer of importers) {
1626
+ if (clIsTestFile(importer)) {
1627
+ hasTestImporter = true;
1628
+ break;
1629
+ }
1630
+ }
1631
+ if (hasTestImporter) {
1632
+ result.tested++;
1633
+ result.testedFiles.push(fp);
1634
+ }
1635
+ else {
1636
+ result.untestedLive++;
1637
+ result.untestedLiveFiles.push(fp);
1638
+ }
1639
+ }
1640
+ result.deadPostException = result.untestedDead;
1641
+ result.deadDrop = result.deadPreException - result.untestedDead;
1642
+ return result;
1643
+ }
1644
+ /**
1645
+ * Spec 60 R3 — group unreferenced modules by basename, surfacing the pattern of
1646
+ * the same file name appearing in several sibling directories (e.g. two
1647
+ * `ErrorState.tsx`, three `services.ts` under separate `reports` folders). Only
1648
+ * basenames with ≥2 files become clusters; a singleton dead file is not a duplicate.
1649
+ */
1650
+ export function clusterDeadModules(deadFiles) {
1651
+ const byBasename = new Map();
1652
+ for (const fp of deadFiles) {
1653
+ const segments = fp.replace(/\\/g, '/').split('/').filter(Boolean);
1654
+ const basename = segments[segments.length - 1] ?? fp;
1655
+ const list = byBasename.get(basename) ?? [];
1656
+ list.push(fp);
1657
+ byBasename.set(basename, list);
1658
+ }
1659
+ const clusters = [];
1660
+ for (const [basename, files] of byBasename) {
1661
+ if (files.length >= 2) {
1662
+ clusters.push({ basename, count: files.length, files });
1663
+ }
1664
+ }
1665
+ clusters.sort((a, b) => b.count - a.count || a.basename.localeCompare(b.basename));
1666
+ return clusters;
1667
+ }
1563
1668
  /**
1564
1669
  * Build `calls` cross-references by resolving each entity's extracted callee
1565
1670
  * names against the corpus entity name index. Library calls (fetch, map, …)
@@ -1774,6 +1879,8 @@ export function createDependencyGraphReducer() {
1774
1879
  }
1775
1880
  // ── File-level reachability: unreferenced modules + ranking axis ──
1776
1881
  const fileFacts = clFileFacts(allFacts);
1882
+ let testCoverage;
1883
+ let deadClusters = [];
1777
1884
  if (fileFacts.size > 0) {
1778
1885
  // `context.config` is the reducer's merged config (namespace + `_infra`);
1779
1886
  // a bare reducer context in a unit test omits it, so fall back to the
@@ -1807,10 +1914,34 @@ export function createDependencyGraphReducer() {
1807
1914
  // neutral default without it.
1808
1915
  }
1809
1916
  }
1917
+ // Spec 60 R1 — persist the file-level import edges (reverse adjacency:
1918
+ // module → its direct importers) so "what tests exercise this module"
1919
+ // is answerable downstream from `importersOf`, not the symbol-level
1920
+ // `function_dependencies` table.
1921
+ if (context.indexHandle?.rawDb) {
1922
+ try {
1923
+ const db = context.indexHandle.rawDb;
1924
+ const del = db.prepare("DELETE FROM graph_cache WHERE graph_type = 'importers'");
1925
+ const ins = db.prepare("INSERT OR REPLACE INTO graph_cache (graph_type, node_key, neighbor_key, weight) VALUES ('importers', ?, ?, 1)");
1926
+ const tx = db.transaction(() => {
1927
+ del.run();
1928
+ for (const [fp, importers] of importersOf) {
1929
+ for (const importer of importers) {
1930
+ ins.run(fp, importer);
1931
+ }
1932
+ }
1933
+ });
1934
+ tx();
1935
+ }
1936
+ catch {
1937
+ // Importer-edge persistence is advisory, like reachability.
1938
+ }
1939
+ }
1810
1940
  // Flag files that export symbols yet are imported by nothing and are
1811
1941
  // not framework entry points — a dead module. This is the signal the
1812
1942
  // orphaned-nodes check missed: a whole unreferenced file whose every
1813
1943
  // internal symbol still forms a connected component.
1944
+ const deadModuleFiles = [];
1814
1945
  for (const [fp, info] of fileFacts) {
1815
1946
  if (!info.hasExports)
1816
1947
  continue;
@@ -1820,6 +1951,7 @@ export function createDependencyGraphReducer() {
1820
1951
  continue;
1821
1952
  if ((importersOf.get(fp)?.size ?? 0) > 0)
1822
1953
  continue;
1954
+ deadModuleFiles.push(fp);
1823
1955
  violations.push({
1824
1956
  file: fp,
1825
1957
  line: 1,
@@ -1834,6 +1966,12 @@ export function createDependencyGraphReducer() {
1834
1966
  details: { imports: info.imports },
1835
1967
  });
1836
1968
  }
1969
+ // Spec 60 R1 — classify each non-test module off the import edge set.
1970
+ testCoverage = classifyTestCoverage(fileFacts, importersOf, packageEntrySet);
1971
+ // Spec 60 R3 — cluster the unreferenced modules by basename so the
1972
+ // "dead-and-duplicated" pattern (same file name in sibling dirs) is
1973
+ // visible as a cluster rather than scattered one-per-file findings.
1974
+ deadClusters = clusterDeadModules(deadModuleFiles);
1837
1975
  // Spec 58 R2 — computed-specifier dynamic imports. `import(someVar)`
1838
1976
  // cannot be resolved into an edge, so any module in this corpus could
1839
1977
  // be its target and `unreferenced-module` is therefore not exhaustive.
@@ -1854,15 +1992,15 @@ export function createDependencyGraphReducer() {
1854
1992
  }
1855
1993
  const HEALTH_SEVERITY = {
1856
1994
  'break-cycles': 'severe',
1857
- 'reduce-coupling': 'advisory',
1858
- 'split-responsibilities': 'advisory',
1995
+ 'reduce-coupling': 'high',
1996
+ 'split-responsibilities': 'high',
1859
1997
  'review-orphans': 'severe',
1860
1998
  };
1861
1999
  for (const s of health.suggestions) {
1862
2000
  violations.push({
1863
2001
  file: '(multiple)',
1864
2002
  line: 0,
1865
- severity: HEALTH_SEVERITY[s.type] ?? 'advisory',
2003
+ severity: HEALTH_SEVERITY[s.type] ?? 'high',
1866
2004
  message: s.description,
1867
2005
  rule: s.type,
1868
2006
  type: s.type,
@@ -1871,7 +2009,12 @@ export function createDependencyGraphReducer() {
1871
2009
  details: s.affectedNodes ? { affectedNodes: s.affectedNodes } : undefined,
1872
2010
  });
1873
2011
  }
1874
- return { violations, facts: {}, factsConsumed: entities.length, ...(diagnostics.length > 0 && { diagnostics }) };
2012
+ const facts = {};
2013
+ if (testCoverage)
2014
+ facts.testCoverage = testCoverage;
2015
+ if (deadClusters.length > 0)
2016
+ facts.deadClusters = deadClusters;
2017
+ return { violations, facts, factsConsumed: entities.length, ...(diagnostics.length > 0 && { diagnostics }) };
1875
2018
  }
1876
2019
  catch (e) {
1877
2020
  console.error('[dependency-graph reducer] error:', e.message);