@vyuhlabs/dxkit 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/CHANGELOG.md +272 -0
  2. package/README.md +272 -358
  3. package/THIRD_PARTY_NOTICES.md +40 -0
  4. package/dist/analyzers/developer/detailed.d.ts +26 -0
  5. package/dist/analyzers/developer/detailed.d.ts.map +1 -0
  6. package/dist/analyzers/developer/detailed.js +193 -0
  7. package/dist/analyzers/developer/detailed.js.map +1 -0
  8. package/dist/analyzers/developer/gather.d.ts +11 -0
  9. package/dist/analyzers/developer/gather.d.ts.map +1 -0
  10. package/dist/analyzers/developer/gather.js +167 -0
  11. package/dist/analyzers/developer/gather.js.map +1 -0
  12. package/dist/analyzers/developer/index.d.ts +8 -0
  13. package/dist/analyzers/developer/index.d.ts.map +1 -0
  14. package/dist/analyzers/developer/index.js +168 -0
  15. package/dist/analyzers/developer/index.js.map +1 -0
  16. package/dist/analyzers/developer/types.d.ts +49 -0
  17. package/dist/analyzers/developer/types.d.ts.map +1 -0
  18. package/dist/analyzers/developer/types.js +6 -0
  19. package/dist/analyzers/developer/types.js.map +1 -0
  20. package/dist/analyzers/docs/shallow.d.ts +9 -0
  21. package/dist/analyzers/docs/shallow.d.ts.map +1 -0
  22. package/dist/analyzers/docs/shallow.js +8 -0
  23. package/dist/analyzers/docs/shallow.js.map +1 -0
  24. package/dist/analyzers/dx/shallow.d.ts +9 -0
  25. package/dist/analyzers/dx/shallow.d.ts.map +1 -0
  26. package/dist/analyzers/dx/shallow.js +8 -0
  27. package/dist/analyzers/dx/shallow.js.map +1 -0
  28. package/dist/analyzers/evidence.d.ts +36 -0
  29. package/dist/analyzers/evidence.d.ts.map +1 -0
  30. package/dist/analyzers/evidence.js +3 -0
  31. package/dist/analyzers/evidence.js.map +1 -0
  32. package/dist/analyzers/health/actions.d.ts +10 -0
  33. package/dist/analyzers/health/actions.d.ts.map +1 -0
  34. package/dist/analyzers/health/actions.js +284 -0
  35. package/dist/analyzers/health/actions.js.map +1 -0
  36. package/dist/analyzers/health/detailed.d.ts +26 -0
  37. package/dist/analyzers/health/detailed.d.ts.map +1 -0
  38. package/dist/analyzers/health/detailed.js +147 -0
  39. package/dist/analyzers/health/detailed.js.map +1 -0
  40. package/dist/analyzers/health.d.ts +22 -0
  41. package/dist/analyzers/health.d.ts.map +1 -0
  42. package/dist/analyzers/health.js +270 -0
  43. package/dist/analyzers/health.js.map +1 -0
  44. package/dist/analyzers/index.d.ts +3 -0
  45. package/dist/analyzers/index.d.ts.map +1 -0
  46. package/dist/analyzers/index.js +6 -0
  47. package/dist/analyzers/index.js.map +1 -0
  48. package/dist/analyzers/maintainability/shallow.d.ts +9 -0
  49. package/dist/analyzers/maintainability/shallow.d.ts.map +1 -0
  50. package/dist/analyzers/maintainability/shallow.js +8 -0
  51. package/dist/analyzers/maintainability/shallow.js.map +1 -0
  52. package/dist/analyzers/quality/actions.d.ts +5 -0
  53. package/dist/analyzers/quality/actions.d.ts.map +1 -0
  54. package/dist/analyzers/quality/actions.js +158 -0
  55. package/dist/analyzers/quality/actions.js.map +1 -0
  56. package/dist/analyzers/quality/detailed.d.ts +17 -0
  57. package/dist/analyzers/quality/detailed.d.ts.map +1 -0
  58. package/dist/analyzers/quality/detailed.js +122 -0
  59. package/dist/analyzers/quality/detailed.js.map +1 -0
  60. package/dist/analyzers/quality/gather.d.ts +38 -0
  61. package/dist/analyzers/quality/gather.d.ts.map +1 -0
  62. package/dist/analyzers/quality/gather.js +279 -0
  63. package/dist/analyzers/quality/gather.js.map +1 -0
  64. package/dist/analyzers/quality/index.d.ts +12 -0
  65. package/dist/analyzers/quality/index.d.ts.map +1 -0
  66. package/dist/analyzers/quality/index.js +281 -0
  67. package/dist/analyzers/quality/index.js.map +1 -0
  68. package/dist/analyzers/quality/shallow.d.ts +9 -0
  69. package/dist/analyzers/quality/shallow.d.ts.map +1 -0
  70. package/dist/analyzers/quality/shallow.js +8 -0
  71. package/dist/analyzers/quality/shallow.js.map +1 -0
  72. package/dist/analyzers/quality/types.d.ts +66 -0
  73. package/dist/analyzers/quality/types.d.ts.map +1 -0
  74. package/dist/analyzers/quality/types.js +3 -0
  75. package/dist/analyzers/quality/types.js.map +1 -0
  76. package/dist/analyzers/remediation.d.ts +42 -0
  77. package/dist/analyzers/remediation.d.ts.map +1 -0
  78. package/dist/analyzers/remediation.js +28 -0
  79. package/dist/analyzers/remediation.js.map +1 -0
  80. package/dist/analyzers/scoring.d.ts +32 -0
  81. package/dist/analyzers/scoring.d.ts.map +1 -0
  82. package/dist/analyzers/scoring.js +410 -0
  83. package/dist/analyzers/scoring.js.map +1 -0
  84. package/dist/analyzers/security/actions.d.ts +7 -0
  85. package/dist/analyzers/security/actions.d.ts.map +1 -0
  86. package/dist/analyzers/security/actions.js +104 -0
  87. package/dist/analyzers/security/actions.js.map +1 -0
  88. package/dist/analyzers/security/detailed.d.ts +14 -0
  89. package/dist/analyzers/security/detailed.d.ts.map +1 -0
  90. package/dist/analyzers/security/detailed.js +124 -0
  91. package/dist/analyzers/security/detailed.js.map +1 -0
  92. package/dist/analyzers/security/gather.d.ts +12 -0
  93. package/dist/analyzers/security/gather.d.ts.map +1 -0
  94. package/dist/analyzers/security/gather.js +195 -0
  95. package/dist/analyzers/security/gather.js.map +1 -0
  96. package/dist/analyzers/security/index.d.ts +8 -0
  97. package/dist/analyzers/security/index.d.ts.map +1 -0
  98. package/dist/analyzers/security/index.js +173 -0
  99. package/dist/analyzers/security/index.js.map +1 -0
  100. package/dist/analyzers/security/scoring.d.ts +29 -0
  101. package/dist/analyzers/security/scoring.d.ts.map +1 -0
  102. package/dist/analyzers/security/scoring.js +40 -0
  103. package/dist/analyzers/security/scoring.js.map +1 -0
  104. package/dist/analyzers/security/shallow.d.ts +10 -0
  105. package/dist/analyzers/security/shallow.d.ts.map +1 -0
  106. package/dist/analyzers/security/shallow.js +8 -0
  107. package/dist/analyzers/security/shallow.js.map +1 -0
  108. package/dist/analyzers/security/types.d.ts +43 -0
  109. package/dist/analyzers/security/types.d.ts.map +1 -0
  110. package/dist/analyzers/security/types.js +6 -0
  111. package/dist/analyzers/security/types.js.map +1 -0
  112. package/dist/analyzers/tests/actions.d.ts +6 -0
  113. package/dist/analyzers/tests/actions.d.ts.map +1 -0
  114. package/dist/analyzers/tests/actions.js +80 -0
  115. package/dist/analyzers/tests/actions.js.map +1 -0
  116. package/dist/analyzers/tests/detailed.d.ts +14 -0
  117. package/dist/analyzers/tests/detailed.d.ts.map +1 -0
  118. package/dist/analyzers/tests/detailed.js +121 -0
  119. package/dist/analyzers/tests/detailed.js.map +1 -0
  120. package/dist/analyzers/tests/gather.d.ts +5 -0
  121. package/dist/analyzers/tests/gather.d.ts.map +1 -0
  122. package/dist/analyzers/tests/gather.js +270 -0
  123. package/dist/analyzers/tests/gather.js.map +1 -0
  124. package/dist/analyzers/tests/import-graph.d.ts +48 -0
  125. package/dist/analyzers/tests/import-graph.d.ts.map +1 -0
  126. package/dist/analyzers/tests/import-graph.js +231 -0
  127. package/dist/analyzers/tests/import-graph.js.map +1 -0
  128. package/dist/analyzers/tests/index.d.ts +8 -0
  129. package/dist/analyzers/tests/index.d.ts.map +1 -0
  130. package/dist/analyzers/tests/index.js +247 -0
  131. package/dist/analyzers/tests/index.js.map +1 -0
  132. package/dist/analyzers/tests/scoring.d.ts +27 -0
  133. package/dist/analyzers/tests/scoring.d.ts.map +1 -0
  134. package/dist/analyzers/tests/scoring.js +38 -0
  135. package/dist/analyzers/tests/scoring.js.map +1 -0
  136. package/dist/analyzers/tests/shallow.d.ts +9 -0
  137. package/dist/analyzers/tests/shallow.d.ts.map +1 -0
  138. package/dist/analyzers/tests/shallow.js +8 -0
  139. package/dist/analyzers/tests/shallow.js.map +1 -0
  140. package/dist/analyzers/tests/types.d.ts +49 -0
  141. package/dist/analyzers/tests/types.d.ts.map +1 -0
  142. package/dist/analyzers/tests/types.js +6 -0
  143. package/dist/analyzers/tests/types.js.map +1 -0
  144. package/dist/analyzers/tools/cloc.d.ts +8 -0
  145. package/dist/analyzers/tools/cloc.d.ts.map +1 -0
  146. package/dist/analyzers/tools/cloc.js +49 -0
  147. package/dist/analyzers/tools/cloc.js.map +1 -0
  148. package/dist/analyzers/tools/coverage.d.ts +59 -0
  149. package/dist/analyzers/tools/coverage.d.ts.map +1 -0
  150. package/dist/analyzers/tools/coverage.js +280 -0
  151. package/dist/analyzers/tools/coverage.js.map +1 -0
  152. package/dist/analyzers/tools/cvss-v4-lookup.d.ts +10 -0
  153. package/dist/analyzers/tools/cvss-v4-lookup.d.ts.map +1 -0
  154. package/dist/analyzers/tools/cvss-v4-lookup.js +284 -0
  155. package/dist/analyzers/tools/cvss-v4-lookup.js.map +1 -0
  156. package/dist/analyzers/tools/cvss-v4.d.ts +24 -0
  157. package/dist/analyzers/tools/cvss-v4.d.ts.map +1 -0
  158. package/dist/analyzers/tools/cvss-v4.js +362 -0
  159. package/dist/analyzers/tools/cvss-v4.js.map +1 -0
  160. package/dist/analyzers/tools/default-exclusions.gitignore +56 -0
  161. package/dist/analyzers/tools/exclusions.d.ts +70 -0
  162. package/dist/analyzers/tools/exclusions.d.ts.map +1 -0
  163. package/dist/analyzers/tools/exclusions.js +250 -0
  164. package/dist/analyzers/tools/exclusions.js.map +1 -0
  165. package/dist/analyzers/tools/generic.d.ts +4 -0
  166. package/dist/analyzers/tools/generic.d.ts.map +1 -0
  167. package/dist/analyzers/tools/generic.js +198 -0
  168. package/dist/analyzers/tools/generic.js.map +1 -0
  169. package/dist/analyzers/tools/gitleaks.d.ts +8 -0
  170. package/dist/analyzers/tools/gitleaks.d.ts.map +1 -0
  171. package/dist/analyzers/tools/gitleaks.js +58 -0
  172. package/dist/analyzers/tools/gitleaks.js.map +1 -0
  173. package/dist/analyzers/tools/graphify.d.ts +4 -0
  174. package/dist/analyzers/tools/graphify.d.ts.map +1 -0
  175. package/dist/analyzers/tools/graphify.js +222 -0
  176. package/dist/analyzers/tools/graphify.js.map +1 -0
  177. package/dist/analyzers/tools/osv.d.ts +51 -0
  178. package/dist/analyzers/tools/osv.d.ts.map +1 -0
  179. package/dist/analyzers/tools/osv.js +188 -0
  180. package/dist/analyzers/tools/osv.js.map +1 -0
  181. package/dist/analyzers/tools/parallel.d.ts +8 -0
  182. package/dist/analyzers/tools/parallel.d.ts.map +1 -0
  183. package/dist/analyzers/tools/parallel.js +195 -0
  184. package/dist/analyzers/tools/parallel.js.map +1 -0
  185. package/dist/analyzers/tools/runner.d.ts +13 -0
  186. package/dist/analyzers/tools/runner.d.ts.map +1 -0
  187. package/dist/analyzers/tools/runner.js +109 -0
  188. package/dist/analyzers/tools/runner.js.map +1 -0
  189. package/dist/analyzers/tools/suppressions.d.ts +55 -0
  190. package/dist/analyzers/tools/suppressions.d.ts.map +1 -0
  191. package/dist/analyzers/tools/suppressions.js +203 -0
  192. package/dist/analyzers/tools/suppressions.js.map +1 -0
  193. package/dist/analyzers/tools/timing.d.ts +9 -0
  194. package/dist/analyzers/tools/timing.d.ts.map +1 -0
  195. package/dist/analyzers/tools/timing.js +29 -0
  196. package/dist/analyzers/tools/timing.js.map +1 -0
  197. package/dist/analyzers/tools/tool-registry.d.ts +86 -0
  198. package/dist/analyzers/tools/tool-registry.d.ts.map +1 -0
  199. package/dist/analyzers/tools/tool-registry.js +705 -0
  200. package/dist/analyzers/tools/tool-registry.js.map +1 -0
  201. package/dist/analyzers/types.d.ts +125 -0
  202. package/dist/analyzers/types.d.ts.map +1 -0
  203. package/dist/analyzers/types.js +11 -0
  204. package/dist/analyzers/types.js.map +1 -0
  205. package/dist/cli.d.ts.map +1 -1
  206. package/dist/cli.js +462 -0
  207. package/dist/cli.js.map +1 -1
  208. package/dist/detect.d.ts.map +1 -1
  209. package/dist/detect.js +24 -15
  210. package/dist/detect.js.map +1 -1
  211. package/dist/languages/csharp.d.ts +5 -0
  212. package/dist/languages/csharp.d.ts.map +1 -0
  213. package/dist/languages/csharp.js +265 -0
  214. package/dist/languages/csharp.js.map +1 -0
  215. package/dist/languages/go.d.ts +11 -0
  216. package/dist/languages/go.d.ts.map +1 -0
  217. package/dist/languages/go.js +321 -0
  218. package/dist/languages/go.js.map +1 -0
  219. package/dist/languages/index.d.ts +6 -0
  220. package/dist/languages/index.d.ts.map +1 -0
  221. package/dist/languages/index.js +18 -0
  222. package/dist/languages/index.js.map +1 -0
  223. package/dist/languages/python.d.ts +3 -0
  224. package/dist/languages/python.d.ts.map +1 -0
  225. package/dist/languages/python.js +284 -0
  226. package/dist/languages/python.js.map +1 -0
  227. package/dist/languages/rust.d.ts +17 -0
  228. package/dist/languages/rust.d.ts.map +1 -0
  229. package/dist/languages/rust.js +333 -0
  230. package/dist/languages/rust.js.map +1 -0
  231. package/dist/languages/types.d.ts +38 -0
  232. package/dist/languages/types.d.ts.map +1 -0
  233. package/dist/languages/types.js +3 -0
  234. package/dist/languages/types.js.map +1 -0
  235. package/dist/languages/typescript.d.ts +15 -0
  236. package/dist/languages/typescript.d.ts.map +1 -0
  237. package/dist/languages/typescript.js +353 -0
  238. package/dist/languages/typescript.js.map +1 -0
  239. package/dist/logger.d.ts +1 -0
  240. package/dist/logger.d.ts.map +1 -1
  241. package/dist/logger.js +25 -12
  242. package/dist/logger.js.map +1 -1
  243. package/dist/project-yaml.d.ts.map +1 -1
  244. package/dist/project-yaml.js +1 -0
  245. package/dist/project-yaml.js.map +1 -1
  246. package/dist/tools-cli.d.ts +2 -0
  247. package/dist/tools-cli.d.ts.map +1 -0
  248. package/dist/tools-cli.js +231 -0
  249. package/dist/tools-cli.js.map +1 -0
  250. package/dist/types.d.ts +10 -0
  251. package/dist/types.d.ts.map +1 -1
  252. package/package.json +6 -2
  253. package/templates/.claude/commands/dev-report.md +34 -4
  254. package/templates/.claude/commands/health.md +45 -2
  255. package/templates/.claude/commands/quality.md.template +38 -15
  256. package/templates/.claude/commands/test-gaps.md +36 -2
  257. package/templates/.claude/commands/vulnerabilities.md +36 -2
  258. package/templates/.project/scripts/setup/interactive-setup.sh +6 -2
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildSlopActions = buildSlopActions;
4
+ /** Build the candidate action list for the given metrics. */
5
+ function buildSlopActions(m) {
6
+ const actions = [];
7
+ // 1. Delete committed stale files (.pyc, .swp, .bak, .orig, .tmp, .log)
8
+ if (m.staleFiles.length > 0) {
9
+ const evidence = m.staleFiles.map((f) => ({
10
+ file: f,
11
+ rule: 'stale-file',
12
+ tool: 'git',
13
+ message: 'Temp/backup file committed to git',
14
+ }));
15
+ actions.push({
16
+ id: 'slop.delete-stale-files',
17
+ title: `Delete ${m.staleFiles.length} stale file${m.staleFiles.length === 1 ? '' : 's'} from git`,
18
+ rationale: 'Temp/backup files (.pyc, .swp, .bak, .orig) in git add noise and suggest missing .gitignore rules.',
19
+ evidence,
20
+ patch: (cur) => ({ ...cur, staleFiles: [] }),
21
+ });
22
+ }
23
+ // 2. Remove console statements (down to <=20)
24
+ if (m.consoleLogCount > 20) {
25
+ const target = 20;
26
+ const evidence = (m.topConsoleFiles || []).map((f) => ({
27
+ file: f.file,
28
+ rule: 'console-log',
29
+ tool: 'grep',
30
+ message: `${f.count} console statements`,
31
+ }));
32
+ actions.push({
33
+ id: 'slop.remove-console-statements',
34
+ title: `Remove console statements (currently ${m.consoleLogCount}, target <=${target})`,
35
+ rationale: 'Console logging in production code indicates missing structured logging. Use a logger library instead.',
36
+ evidence,
37
+ patch: (cur) => ({ ...cur, consoleLogCount: target }),
38
+ });
39
+ }
40
+ // 3. Triage TODO/FIXME/HACK comments (down to <=20)
41
+ const hygieneTotal = m.todoCount + m.fixmeCount + m.hackCount;
42
+ if (hygieneTotal > 20) {
43
+ const evidence = (m.topTodoFiles || []).map((f) => ({
44
+ file: f.file,
45
+ rule: 'hygiene-marker',
46
+ tool: 'grep',
47
+ message: `${f.count} TODO/FIXME/HACK markers`,
48
+ }));
49
+ actions.push({
50
+ id: 'slop.triage-todos',
51
+ title: `Triage TODO/FIXME/HACK comments (${hygieneTotal} total — file issues or delete)`,
52
+ rationale: 'Unresolved markers suggest forgotten work. Convert real work to tracked issues; delete obsolete ones.',
53
+ evidence,
54
+ patch: (cur) => ({
55
+ ...cur,
56
+ todoCount: Math.min(cur.todoCount, 15),
57
+ fixmeCount: 0,
58
+ hackCount: 0,
59
+ }),
60
+ });
61
+ }
62
+ // 4. Split the densest file (god file)
63
+ if (m.maxFunctionsInFile !== null && m.maxFunctionsInFile > 50) {
64
+ const ev = m.maxFunctionsFilePath
65
+ ? [
66
+ {
67
+ file: m.maxFunctionsFilePath,
68
+ rule: 'god-file',
69
+ tool: 'graphify',
70
+ message: `${m.maxFunctionsInFile} functions in one file`,
71
+ },
72
+ ]
73
+ : [];
74
+ actions.push({
75
+ id: 'slop.split-god-file',
76
+ title: `Split the densest file (${m.maxFunctionsInFile} functions)`,
77
+ rationale: 'Files with >50 functions are hard to navigate, test, and review. Break into focused modules.',
78
+ evidence: ev,
79
+ patch: (cur) => ({ ...cur, maxFunctionsInFile: 40 }),
80
+ });
81
+ }
82
+ // 5. Remove dead imports
83
+ if (m.deadImportCount !== null && m.deadImportCount > 20) {
84
+ actions.push({
85
+ id: 'slop.remove-dead-imports',
86
+ title: `Remove ${m.deadImportCount} dead imports`,
87
+ rationale: 'Imports never called add cognitive load. Most editors auto-remove them.',
88
+ evidence: [],
89
+ patch: (cur) => ({ ...cur, deadImportCount: 0 }),
90
+ });
91
+ }
92
+ // 6. Address large duplication
93
+ if (m.duplication && m.duplication.percentage > 5) {
94
+ const evidence = m.duplication.topClones?.flatMap((c) => [
95
+ {
96
+ file: c.a.file,
97
+ line: c.a.startLine,
98
+ endLine: c.a.endLine,
99
+ rule: 'duplicate-block',
100
+ tool: 'jscpd',
101
+ message: `${c.lines}-line clone with ${c.b.file}:${c.b.startLine}`,
102
+ },
103
+ ]) ?? [];
104
+ const target = 5;
105
+ actions.push({
106
+ id: 'slop.extract-duplicates',
107
+ title: `Extract shared code (duplication ${m.duplication.percentage}% → target ${target}%)`,
108
+ rationale: 'Duplicate blocks multiply maintenance cost. Extract into shared helpers/modules starting with the largest clones.',
109
+ evidence,
110
+ patch: (cur) => ({
111
+ ...cur,
112
+ duplication: cur.duplication ? { ...cur.duplication, percentage: target } : null,
113
+ }),
114
+ });
115
+ }
116
+ // 7. Unify JS/TS
117
+ if (m.mixedLanguages) {
118
+ actions.push({
119
+ id: 'slop.unify-js-ts',
120
+ title: 'Convert stray .js files to TypeScript',
121
+ rationale: 'Mixing .js and .ts in source defeats type-safety gains. Convert or move generated JS to /dist.',
122
+ evidence: [],
123
+ patch: (cur) => ({ ...cur, mixedLanguages: false }),
124
+ });
125
+ }
126
+ // 8. Clear lint errors
127
+ if (m.lintErrors > 10) {
128
+ actions.push({
129
+ id: 'slop.fix-lint-errors',
130
+ title: `Fix ${m.lintErrors} lint errors`,
131
+ rationale: 'Lint errors often indicate real bugs. Most are auto-fixable.',
132
+ evidence: [],
133
+ patch: (cur) => ({ ...cur, lintErrors: 0 }),
134
+ });
135
+ }
136
+ // 9. Reduce comment-heavy files
137
+ if (m.commentRatio !== null && m.commentRatio > 0.4) {
138
+ actions.push({
139
+ id: 'slop.reduce-comment-bloat',
140
+ title: `Reduce comment bloat (ratio ${(m.commentRatio * 100).toFixed(1)}%)`,
141
+ rationale: 'Very high comment ratios often signal commented-out code (should be deleted) or over-documentation.',
142
+ evidence: [],
143
+ patch: (cur) => ({ ...cur, commentRatio: 0.2 }),
144
+ });
145
+ }
146
+ // 10. Address orphan modules
147
+ if (m.orphanModuleCount !== null && m.orphanModuleCount > 30) {
148
+ actions.push({
149
+ id: 'slop.remove-orphan-modules',
150
+ title: `Review ${m.orphanModuleCount} orphan modules (no inbound imports)`,
151
+ rationale: 'Modules never imported are dead code or entry points. Delete dead ones; document entry points.',
152
+ evidence: [],
153
+ patch: (cur) => ({ ...cur, orphanModuleCount: 20 }),
154
+ });
155
+ }
156
+ return actions;
157
+ }
158
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../src/analyzers/quality/actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Detailed quality report — JSON schema + markdown formatter.
3
+ *
4
+ * The JSON is the canonical, agent-consumable artifact. The markdown is
5
+ * generated from the JSON so they never diverge.
6
+ */
7
+ import { QualityReport, QualityMetrics } from './types';
8
+ import { RankedAction } from '../remediation';
9
+ export interface QualityDetailedReport extends QualityReport {
10
+ /** Schema version for agent consumers. Bump on breaking shape changes. */
11
+ schemaVersion: string;
12
+ /** Ranked remediation actions with simulated score deltas. */
13
+ actions: Array<RankedAction<QualityMetrics>>;
14
+ }
15
+ export declare function buildQualityDetailed(report: QualityReport): QualityDetailedReport;
16
+ export declare function formatQualityDetailedMarkdown(detailed: QualityDetailedReport, elapsed: string): string;
17
+ //# sourceMappingURL=detailed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detailed.d.ts","sourceRoot":"","sources":["../../../src/analyzers/quality/detailed.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,YAAY,EAAQ,MAAM,gBAAgB,CAAC;AAIpD,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,0EAA0E;IAC1E,aAAa,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC;CAC9C;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,qBAAqB,CASjF;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,qBAAqB,EAC/B,OAAO,EAAE,MAAM,GACd,MAAM,CAiHR"}
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildQualityDetailed = buildQualityDetailed;
4
+ exports.formatQualityDetailedMarkdown = formatQualityDetailedMarkdown;
5
+ const remediation_1 = require("../remediation");
6
+ const actions_1 = require("./actions");
7
+ const index_1 = require("./index");
8
+ function buildQualityDetailed(report) {
9
+ const actions = (0, remediation_1.rank)((0, actions_1.buildSlopActions)(report.metrics), report.metrics, (m) => ({
10
+ score: (0, index_1.computeSlopScore)(m),
11
+ }));
12
+ return {
13
+ ...report,
14
+ schemaVersion: '10c.1',
15
+ actions,
16
+ };
17
+ }
18
+ function formatQualityDetailedMarkdown(detailed, elapsed) {
19
+ const L = [];
20
+ const m = detailed.metrics;
21
+ L.push('# Code Quality Review — Detailed');
22
+ L.push('');
23
+ L.push(`**Date:** ${detailed.analyzedAt.slice(0, 10)}`);
24
+ L.push(`**Repository:** ${detailed.repo}`);
25
+ L.push(`**Branch:** ${detailed.branch} (${detailed.commitSha})`);
26
+ L.push(`**Slop Score:** ${detailed.slopScore}/100`);
27
+ L.push(`**Schema version:** ${detailed.schemaVersion}`);
28
+ L.push('');
29
+ L.push('---');
30
+ L.push('');
31
+ // Ranked actions
32
+ L.push('## Recommended Actions');
33
+ L.push('');
34
+ if (detailed.actions.length === 0) {
35
+ L.push('No remediation actions suggested — slop score has no actionable deductions.');
36
+ }
37
+ else {
38
+ L.push('Actions are ranked by projected score improvement. Each delta is computed by simulating the scorer with the patched metrics.');
39
+ L.push('');
40
+ L.push('| # | Action | Score Δ | Projected | Evidence |');
41
+ L.push('|---|--------|--------:|----------:|----------|');
42
+ detailed.actions.forEach((a, i) => {
43
+ const evSuffix = a.evidence.length
44
+ ? `${a.evidence.length} item${a.evidence.length === 1 ? '' : 's'}`
45
+ : '—';
46
+ L.push(`| ${i + 1} | ${a.title} | +${a.scoreDelta} | ${a.projectedScore}/100 | ${evSuffix} |`);
47
+ });
48
+ L.push('');
49
+ for (const a of detailed.actions) {
50
+ L.push(`### ${a.title} (+${a.scoreDelta})`);
51
+ L.push('');
52
+ L.push(`- **ID:** \`${a.id}\``);
53
+ L.push(`- **Baseline:** ${a.baselineScore}/100`);
54
+ L.push(`- **Projected:** ${a.projectedScore}/100`);
55
+ if (a.rationale)
56
+ L.push(`- **Why:** ${a.rationale}`);
57
+ if (a.evidence.length) {
58
+ L.push('- **Evidence:**');
59
+ for (const e of a.evidence.slice(0, 10)) {
60
+ const loc = e.line ? `:${e.line}${e.endLine ? `-${e.endLine}` : ''}` : '';
61
+ L.push(` - \`${e.file}${loc}\` — ${e.message || e.rule}`);
62
+ }
63
+ if (a.evidence.length > 10) {
64
+ L.push(` - … and ${a.evidence.length - 10} more`);
65
+ }
66
+ }
67
+ L.push('');
68
+ }
69
+ }
70
+ L.push('---');
71
+ L.push('');
72
+ // Top duplicate clones
73
+ if (m.duplication?.topClones && m.duplication.topClones.length > 0) {
74
+ L.push('## Top Duplicate Clones');
75
+ L.push('');
76
+ L.push('| Lines | File A | File B |');
77
+ L.push('|------:|--------|--------|');
78
+ for (const c of m.duplication.topClones) {
79
+ L.push(`| ${c.lines} | \`${c.a.file}:${c.a.startLine}-${c.a.endLine}\` | \`${c.b.file}:${c.b.startLine}-${c.b.endLine}\` |`);
80
+ }
81
+ L.push('');
82
+ L.push('---');
83
+ L.push('');
84
+ }
85
+ // Top offenders
86
+ if (m.topConsoleFiles && m.topConsoleFiles.length > 0) {
87
+ L.push('## Files with Most Console Statements');
88
+ L.push('');
89
+ L.push('| File | Count |');
90
+ L.push('|------|------:|');
91
+ for (const f of m.topConsoleFiles)
92
+ L.push(`| \`${f.file}\` | ${f.count} |`);
93
+ L.push('');
94
+ }
95
+ if (m.topTodoFiles && m.topTodoFiles.length > 0) {
96
+ L.push('## Files with Most TODO/FIXME/HACK');
97
+ L.push('');
98
+ L.push('| File | Count |');
99
+ L.push('|------|------:|');
100
+ for (const f of m.topTodoFiles)
101
+ L.push(`| \`${f.file}\` | ${f.count} |`);
102
+ L.push('');
103
+ }
104
+ if (m.staleFiles.length > 0) {
105
+ L.push('## Stale Files Committed to Git');
106
+ L.push('');
107
+ for (const f of m.staleFiles)
108
+ L.push(`- \`${f}\``);
109
+ L.push('');
110
+ }
111
+ L.push('---');
112
+ L.push('');
113
+ L.push(`**Tools used:** ${detailed.toolsUsed.join(', ')}`);
114
+ if (detailed.toolsUnavailable.length > 0) {
115
+ L.push(`**Tools unavailable:** ${detailed.toolsUnavailable.join(', ')}`);
116
+ }
117
+ L.push(`**Analysis time:** ${elapsed}s`);
118
+ L.push('');
119
+ L.push('*Generated by [VyuhLabs DXKit](https://www.npmjs.com/package/@vyuhlabs/dxkit) — detailed mode*');
120
+ return L.join('\n');
121
+ }
122
+ //# sourceMappingURL=detailed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detailed.js","sourceRoot":"","sources":["../../../src/analyzers/quality/detailed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { DuplicationStats, FileOffender } from './types';
2
+ export declare function gatherDuplication(cwd: string): {
3
+ stats: DuplicationStats | null;
4
+ toolUsed: string | null;
5
+ };
6
+ export declare function gatherStructuralMetrics(cwd: string): {
7
+ maxFunctionsInFile: number | null;
8
+ maxFunctionsFilePath: string | null;
9
+ avgCohesion: number | null;
10
+ communityCount: number | null;
11
+ functionCount: number | null;
12
+ deadImportCount: number | null;
13
+ orphanModuleCount: number | null;
14
+ toolUsed: string | null;
15
+ };
16
+ export declare function gatherCommentRatio(cwd: string): {
17
+ ratio: number | null;
18
+ toolUsed: string | null;
19
+ };
20
+ /** Collect per-file top offenders for detailed reports. Slow — only call when needed. */
21
+ export declare function gatherHygieneTopOffenders(cwd: string): {
22
+ topConsoleFiles: FileOffender[];
23
+ topTodoFiles: FileOffender[];
24
+ };
25
+ export declare function gatherHygieneMarkers(cwd: string): {
26
+ todoCount: number;
27
+ fixmeCount: number;
28
+ hackCount: number;
29
+ consoleLogCount: number;
30
+ staleFiles: string[];
31
+ mixedLanguages: boolean;
32
+ };
33
+ export declare function gatherLintMetrics(cwd: string): Promise<{
34
+ errors: number;
35
+ warnings: number;
36
+ tool: string | null;
37
+ }>;
38
+ //# sourceMappingURL=gather.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gather.d.ts","sourceRoot":"","sources":["../../../src/analyzers/quality/gather.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAc,gBAAgB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA4CrE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG;IAC9C,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAwCA;AAyCD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG;IACpD,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CA+BA;AAID,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG;IAC/C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAkBA;AAID,yFAAyF;AACzF,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG;IACtD,eAAe,EAAE,YAAY,EAAE,CAAC;IAChC,YAAY,EAAE,YAAY,EAAE,CAAC;CAC9B,CAKA;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;CACzB,CA4DA;AAID,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC,CAcD"}
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.gatherDuplication = gatherDuplication;
37
+ exports.gatherStructuralMetrics = gatherStructuralMetrics;
38
+ exports.gatherCommentRatio = gatherCommentRatio;
39
+ exports.gatherHygieneTopOffenders = gatherHygieneTopOffenders;
40
+ exports.gatherHygieneMarkers = gatherHygieneMarkers;
41
+ exports.gatherLintMetrics = gatherLintMetrics;
42
+ /**
43
+ * Quality gathering — one function per tool, all accessed via registry.
44
+ *
45
+ * PRINCIPLE: Every external tool is accessed via findTool(TOOL_DEFS.xxx).
46
+ * No direct binary paths. No ad-hoc execSync calls for tools.
47
+ * If a tool isn't in tool-registry.ts, it can't be used here.
48
+ *
49
+ * Tool boundaries:
50
+ * jscpd → duplicate code detection
51
+ * graphify → structural complexity (god files, dead code, cohesion)
52
+ * cloc → comment-to-code ratio
53
+ * eslint → lint errors/warnings (when available)
54
+ * grep → hygiene markers (TODO, FIXME, HACK, console.log)
55
+ */
56
+ const fs = __importStar(require("fs"));
57
+ const runner_1 = require("../tools/runner");
58
+ const tool_registry_1 = require("../tools/tool-registry");
59
+ const exclusions_1 = require("../tools/exclusions");
60
+ const graphify_1 = require("../tools/graphify");
61
+ const cloc_1 = require("../tools/cloc");
62
+ const languages_1 = require("../../languages");
63
+ /** Extract top N clone pairs sorted by size descending. */
64
+ function topClonesFrom(duplicates, limit = 15) {
65
+ return duplicates
66
+ .filter((d) => d.firstFile?.name && d.secondFile?.name && d.lines)
67
+ .map((d) => ({
68
+ lines: d.lines || 0,
69
+ tokens: d.tokens || 0,
70
+ a: {
71
+ file: d.firstFile.name,
72
+ startLine: d.firstFile.start || 0,
73
+ endLine: d.firstFile.end || 0,
74
+ },
75
+ b: {
76
+ file: d.secondFile.name,
77
+ startLine: d.secondFile.start || 0,
78
+ endLine: d.secondFile.end || 0,
79
+ },
80
+ }))
81
+ .sort((x, y) => y.lines - x.lines)
82
+ .slice(0, limit);
83
+ }
84
+ function gatherDuplication(cwd) {
85
+ const status = (0, tool_registry_1.findTool)(tool_registry_1.TOOL_DEFS.jscpd, cwd);
86
+ if (!status.available || !status.path)
87
+ return { stats: null, toolUsed: null };
88
+ const reportDir = `/tmp/dxkit-jscpd-${Date.now()}`;
89
+ // Key flags:
90
+ // --gitignore: respect .gitignore (skips node_modules/dist/build if listed)
91
+ // --pattern: only scan source files (not configs, markdown, etc.)
92
+ // Without --gitignore, jscpd crawls into node_modules and OOMs on large repos.
93
+ (0, runner_1.run)(`${status.path} --reporters json --output '${reportDir}' --gitignore --pattern '**/*.{ts,tsx,js,jsx,py,go,rs,cs}' --min-lines 5 --min-tokens 50 '${cwd}' > /dev/null 2>&1`, cwd, 300000);
94
+ const reportRaw = (0, runner_1.run)(`cat '${reportDir}/jscpd-report.json' 2>/dev/null`, cwd);
95
+ (0, runner_1.run)(`rm -rf '${reportDir}'`, cwd);
96
+ if (!reportRaw)
97
+ return { stats: null, toolUsed: 'jscpd' };
98
+ try {
99
+ const data = JSON.parse(reportRaw);
100
+ const t = data.statistics?.total;
101
+ if (!t)
102
+ return { stats: null, toolUsed: 'jscpd' };
103
+ const duplicates = data.duplicates || [];
104
+ return {
105
+ stats: {
106
+ totalLines: t.lines,
107
+ duplicatedLines: t.duplicatedLines,
108
+ percentage: Math.round(t.percentage * 100) / 100,
109
+ cloneCount: duplicates.length,
110
+ topClones: topClonesFrom(duplicates),
111
+ },
112
+ toolUsed: 'jscpd',
113
+ };
114
+ }
115
+ catch {
116
+ return { stats: null, toolUsed: 'jscpd' };
117
+ }
118
+ }
119
+ // ─── grep: per-file hygiene offender counts ─────────────────────────────────
120
+ /**
121
+ * Count matches per file and return the top N offenders.
122
+ * Uses `grep -rc` which emits `file:count` per matched file.
123
+ */
124
+ function grepPerFile(cwd, pattern, limit = 10) {
125
+ const patternFile = `/tmp/dxkit-qgrep-${Date.now()}-${Math.random().toString(36).slice(2)}.pat`;
126
+ fs.writeFileSync(patternFile, pattern);
127
+ const excludeDirs = (0, exclusions_1.getGrepExcludeDirFlags)(cwd);
128
+ const raw = (0, runner_1.run)(`grep -rcEf '${patternFile}' ${excludeDirs} --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' --include='*.py' --include='*.go' . 2>/dev/null`, cwd, 60000);
129
+ try {
130
+ fs.unlinkSync(patternFile);
131
+ }
132
+ catch {
133
+ /* ignore */
134
+ }
135
+ if (!raw)
136
+ return [];
137
+ const offenders = [];
138
+ for (const line of raw.split('\n')) {
139
+ const idx = line.lastIndexOf(':');
140
+ if (idx < 0)
141
+ continue;
142
+ const file = line.slice(0, idx);
143
+ const count = parseInt(line.slice(idx + 1), 10);
144
+ if (!count || !file)
145
+ continue;
146
+ // grep's --exclude-dir is basename-only; use centralized predicate to
147
+ // drop multi-segment path exclusions (public/assets) + file patterns.
148
+ if ((0, exclusions_1.isExcludedPath)(cwd, file.replace(/^\.\//, '')))
149
+ continue;
150
+ offenders.push({ file, count });
151
+ }
152
+ offenders.sort((a, b) => b.count - a.count);
153
+ return offenders.slice(0, limit);
154
+ }
155
+ // ─── graphify: structural complexity ────────────────────────────────────────
156
+ function gatherStructuralMetrics(cwd) {
157
+ // Reuse graphify data from health metrics if already gathered,
158
+ // otherwise just report null. Graphify runs during health orchestration,
159
+ // not re-run per deep analyzer (too slow to run twice).
160
+ // The quality report inherits these from the health pipeline.
161
+ // For standalone `vyuh-dxkit quality`, we gather them fresh.
162
+ const result = (0, graphify_1.gatherGraphifyMetrics)(cwd);
163
+ if (result.functionCount !== undefined && result.functionCount !== null) {
164
+ return {
165
+ maxFunctionsInFile: result.maxFunctionsInFile ?? null,
166
+ maxFunctionsFilePath: result.maxFunctionsFilePath ?? null,
167
+ avgCohesion: result.avgCohesion ?? null,
168
+ communityCount: result.communityCount ?? null,
169
+ functionCount: result.functionCount ?? null,
170
+ deadImportCount: result.deadImportCount ?? null,
171
+ orphanModuleCount: result.orphanModuleCount ?? null,
172
+ toolUsed: 'graphify',
173
+ };
174
+ }
175
+ return {
176
+ maxFunctionsInFile: null,
177
+ maxFunctionsFilePath: null,
178
+ avgCohesion: null,
179
+ communityCount: null,
180
+ functionCount: null,
181
+ deadImportCount: null,
182
+ orphanModuleCount: null,
183
+ toolUsed: result.toolsUnavailable ? null : 'graphify',
184
+ };
185
+ }
186
+ // ─── cloc: comment ratio ────────────────────────────────────────────────────
187
+ function gatherCommentRatio(cwd) {
188
+ const status = (0, tool_registry_1.findTool)(tool_registry_1.TOOL_DEFS.cloc, cwd);
189
+ if (!status.available)
190
+ return { ratio: null, toolUsed: null };
191
+ const result = (0, cloc_1.gatherClocMetrics)(cwd);
192
+ if (result.clocLanguages && Array.isArray(result.clocLanguages)) {
193
+ let totalCode = 0;
194
+ let totalComment = 0;
195
+ for (const lang of result.clocLanguages) {
196
+ totalCode += lang.code;
197
+ totalComment += lang.comment;
198
+ }
199
+ const ratio = totalCode + totalComment > 0 ? totalComment / (totalCode + totalComment) : 0;
200
+ return { ratio: Math.round(ratio * 1000) / 1000, toolUsed: 'cloc' };
201
+ }
202
+ return { ratio: null, toolUsed: null };
203
+ }
204
+ // ─── grep: hygiene markers ──────────────────────────────────────────────────
205
+ /** Collect per-file top offenders for detailed reports. Slow — only call when needed. */
206
+ function gatherHygieneTopOffenders(cwd) {
207
+ return {
208
+ topConsoleFiles: grepPerFile(cwd, 'console\\.(log|error|warn)'),
209
+ topTodoFiles: grepPerFile(cwd, '(TODO|FIXME|HACK)'),
210
+ };
211
+ }
212
+ function gatherHygieneMarkers(cwd) {
213
+ // Sum match counts across source files, excluding vendored paths.
214
+ // grep --exclude-dir handles basename dirs (node_modules etc.) at traversal.
215
+ // Path-based exclusions (public/assets, static/js) are post-filtered because
216
+ // grep's --exclude-dir only matches basenames, not paths.
217
+ function grepCountSimple(pattern) {
218
+ const patternFile = `/tmp/dxkit-qgrep-${Date.now()}-${Math.random().toString(36).slice(2)}.pat`;
219
+ fs.writeFileSync(patternFile, pattern);
220
+ const excludeDirs = (0, exclusions_1.getGrepExcludeDirFlags)(cwd);
221
+ const result = (0, runner_1.run)(`grep -rcEf '${patternFile}' ${excludeDirs} --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' --include='*.py' --include='*.go' . 2>/dev/null`, cwd, 60000);
222
+ try {
223
+ fs.unlinkSync(patternFile);
224
+ }
225
+ catch {
226
+ /* ignore */
227
+ }
228
+ if (!result)
229
+ return 0;
230
+ let total = 0;
231
+ for (const line of result.split('\n')) {
232
+ const idx = line.lastIndexOf(':');
233
+ if (idx < 0)
234
+ continue;
235
+ const file = line.slice(0, idx);
236
+ const count = parseInt(line.slice(idx + 1), 10);
237
+ if (!count || !file)
238
+ continue;
239
+ // Centralized filter — same predicate used by security/quality/tests.
240
+ if ((0, exclusions_1.isExcludedPath)(cwd, file.replace(/^\.\//, '')))
241
+ continue;
242
+ total += count;
243
+ }
244
+ return total;
245
+ }
246
+ // Stale files: vim swap, backup, temp files tracked in git
247
+ const staleRaw = (0, runner_1.run)(`git ls-files '*.swp' '*.swo' '*.bak' '*.orig' '*.tmp' '*.log' '*.pyc' 2>/dev/null`, cwd);
248
+ const staleFiles = staleRaw ? staleRaw.split('\n').filter((l) => l.trim()) : [];
249
+ // Mixed languages: .js files alongside .ts in same source directories (not config files at root)
250
+ const jsInSrc = (0, runner_1.run)("find . -path '*/src/*.js' -not -path '*/node_modules/*' -not -path '*/dist/*' -not -name '*.min.js' 2>/dev/null | head -5", cwd);
251
+ const tsInSrc = (0, runner_1.run)("find . -path '*/src/*.ts' -not -path '*/node_modules/*' -not -path '*/dist/*' 2>/dev/null | head -1", cwd);
252
+ const mixedLanguages = !!(jsInSrc && tsInSrc);
253
+ return {
254
+ todoCount: grepCountSimple('TODO'),
255
+ fixmeCount: grepCountSimple('FIXME'),
256
+ hackCount: grepCountSimple('HACK'),
257
+ consoleLogCount: grepCountSimple('console\\.(log|error|warn)'),
258
+ staleFiles,
259
+ mixedLanguages,
260
+ };
261
+ }
262
+ // ─── lint errors (via language registry) ─────────────────────────────────────
263
+ async function gatherLintMetrics(cwd) {
264
+ // Dispatch through language registry — first language with a lint result wins.
265
+ for (const lang of (0, languages_1.detectActiveLanguages)(cwd)) {
266
+ if (!lang.gatherMetrics)
267
+ continue;
268
+ const result = await lang.gatherMetrics(cwd);
269
+ if (result.lintTool) {
270
+ return {
271
+ errors: result.lintErrors ?? 0,
272
+ warnings: result.lintWarnings ?? 0,
273
+ tool: result.lintTool ?? null,
274
+ };
275
+ }
276
+ }
277
+ return { errors: 0, warnings: 0, tool: null };
278
+ }
279
+ //# sourceMappingURL=gather.js.map