distyll 0.1.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 (243) hide show
  1. package/CONTRIBUTING.md +159 -0
  2. package/POSTMORTEM.json +60 -0
  3. package/README.md +218 -0
  4. package/SETUP.md +79 -0
  5. package/action.yml +37 -0
  6. package/dist/cache.d.ts +26 -0
  7. package/dist/cache.d.ts.map +1 -0
  8. package/dist/cache.js +115 -0
  9. package/dist/cache.js.map +1 -0
  10. package/dist/cli.d.ts +3 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +153 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/commands/ci.d.ts +7 -0
  15. package/dist/commands/ci.d.ts.map +1 -0
  16. package/dist/commands/ci.js +101 -0
  17. package/dist/commands/ci.js.map +1 -0
  18. package/dist/commands/diff.d.ts +10 -0
  19. package/dist/commands/diff.d.ts.map +1 -0
  20. package/dist/commands/diff.js +95 -0
  21. package/dist/commands/diff.js.map +1 -0
  22. package/dist/commands/fingerprint.d.ts +2 -0
  23. package/dist/commands/fingerprint.d.ts.map +1 -0
  24. package/dist/commands/fingerprint.js +77 -0
  25. package/dist/commands/fingerprint.js.map +1 -0
  26. package/dist/commands/hook.d.ts +3 -0
  27. package/dist/commands/hook.d.ts.map +1 -0
  28. package/dist/commands/hook.js +110 -0
  29. package/dist/commands/hook.js.map +1 -0
  30. package/dist/commands/init.d.ts +2 -0
  31. package/dist/commands/init.d.ts.map +1 -0
  32. package/dist/commands/init.js +75 -0
  33. package/dist/commands/init.js.map +1 -0
  34. package/dist/config.d.ts +7 -0
  35. package/dist/config.d.ts.map +1 -0
  36. package/dist/config.js +100 -0
  37. package/dist/config.js.map +1 -0
  38. package/dist/errors.d.ts +30 -0
  39. package/dist/errors.d.ts.map +1 -0
  40. package/dist/errors.js +133 -0
  41. package/dist/errors.js.map +1 -0
  42. package/dist/fingerprint/analyzer.d.ts +3 -0
  43. package/dist/fingerprint/analyzer.d.ts.map +1 -0
  44. package/dist/fingerprint/analyzer.js +230 -0
  45. package/dist/fingerprint/analyzer.js.map +1 -0
  46. package/dist/fingerprint/comparator.d.ts +4 -0
  47. package/dist/fingerprint/comparator.d.ts.map +1 -0
  48. package/dist/fingerprint/comparator.js +78 -0
  49. package/dist/fingerprint/comparator.js.map +1 -0
  50. package/dist/fingerprint/profile.d.ts +5 -0
  51. package/dist/fingerprint/profile.d.ts.map +1 -0
  52. package/dist/fingerprint/profile.js +68 -0
  53. package/dist/fingerprint/profile.js.map +1 -0
  54. package/dist/fixes/index.d.ts +12 -0
  55. package/dist/fixes/index.d.ts.map +1 -0
  56. package/dist/fixes/index.js +42 -0
  57. package/dist/fixes/index.js.map +1 -0
  58. package/dist/fixes/single-use-wrapper.d.ts +8 -0
  59. package/dist/fixes/single-use-wrapper.d.ts.map +1 -0
  60. package/dist/fixes/single-use-wrapper.js +54 -0
  61. package/dist/fixes/single-use-wrapper.js.map +1 -0
  62. package/dist/fixes/unnecessary-try-catch.d.ts +8 -0
  63. package/dist/fixes/unnecessary-try-catch.d.ts.map +1 -0
  64. package/dist/fixes/unnecessary-try-catch.js +37 -0
  65. package/dist/fixes/unnecessary-try-catch.js.map +1 -0
  66. package/dist/fixes/unused-imports.d.ts +7 -0
  67. package/dist/fixes/unused-imports.d.ts.map +1 -0
  68. package/dist/fixes/unused-imports.js +41 -0
  69. package/dist/fixes/unused-imports.js.map +1 -0
  70. package/dist/fixes/verbose-comments.d.ts +7 -0
  71. package/dist/fixes/verbose-comments.d.ts.map +1 -0
  72. package/dist/fixes/verbose-comments.js +29 -0
  73. package/dist/fixes/verbose-comments.js.map +1 -0
  74. package/dist/formatter.d.ts +4 -0
  75. package/dist/formatter.d.ts.map +1 -0
  76. package/dist/formatter.js +72 -0
  77. package/dist/formatter.js.map +1 -0
  78. package/dist/git.d.ts +22 -0
  79. package/dist/git.d.ts.map +1 -0
  80. package/dist/git.js +130 -0
  81. package/dist/git.js.map +1 -0
  82. package/dist/index.d.ts +16 -0
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +40 -0
  85. package/dist/index.js.map +1 -0
  86. package/dist/languages/index.d.ts +8 -0
  87. package/dist/languages/index.d.ts.map +1 -0
  88. package/dist/languages/index.js +50 -0
  89. package/dist/languages/index.js.map +1 -0
  90. package/dist/languages/javascript.d.ts +6 -0
  91. package/dist/languages/javascript.d.ts.map +1 -0
  92. package/dist/languages/javascript.js +39 -0
  93. package/dist/languages/javascript.js.map +1 -0
  94. package/dist/languages/python.d.ts +6 -0
  95. package/dist/languages/python.d.ts.map +1 -0
  96. package/dist/languages/python.js +50 -0
  97. package/dist/languages/python.js.map +1 -0
  98. package/dist/parser.d.ts +8 -0
  99. package/dist/parser.d.ts.map +1 -0
  100. package/dist/parser.js +55 -0
  101. package/dist/parser.js.map +1 -0
  102. package/dist/reporters/github.d.ts +4 -0
  103. package/dist/reporters/github.d.ts.map +1 -0
  104. package/dist/reporters/github.js +70 -0
  105. package/dist/reporters/github.js.map +1 -0
  106. package/dist/reporters/terminal.d.ts +4 -0
  107. package/dist/reporters/terminal.d.ts.map +1 -0
  108. package/dist/reporters/terminal.js +59 -0
  109. package/dist/reporters/terminal.js.map +1 -0
  110. package/dist/rules/dead-code-paths.d.ts +3 -0
  111. package/dist/rules/dead-code-paths.d.ts.map +1 -0
  112. package/dist/rules/dead-code-paths.js +57 -0
  113. package/dist/rules/dead-code-paths.js.map +1 -0
  114. package/dist/rules/excessive-comments.d.ts +3 -0
  115. package/dist/rules/excessive-comments.d.ts.map +1 -0
  116. package/dist/rules/excessive-comments.js +86 -0
  117. package/dist/rules/excessive-comments.js.map +1 -0
  118. package/dist/rules/hallucinated-imports.d.ts +3 -0
  119. package/dist/rules/hallucinated-imports.d.ts.map +1 -0
  120. package/dist/rules/hallucinated-imports.js +228 -0
  121. package/dist/rules/hallucinated-imports.js.map +1 -0
  122. package/dist/rules/index.d.ts +4 -0
  123. package/dist/rules/index.d.ts.map +1 -0
  124. package/dist/rules/index.js +34 -0
  125. package/dist/rules/index.js.map +1 -0
  126. package/dist/rules/magic-values.d.ts +3 -0
  127. package/dist/rules/magic-values.d.ts.map +1 -0
  128. package/dist/rules/magic-values.js +168 -0
  129. package/dist/rules/magic-values.js.map +1 -0
  130. package/dist/rules/near-duplicate-functions.d.ts +3 -0
  131. package/dist/rules/near-duplicate-functions.d.ts.map +1 -0
  132. package/dist/rules/near-duplicate-functions.js +78 -0
  133. package/dist/rules/near-duplicate-functions.js.map +1 -0
  134. package/dist/rules/over-defensive-nulls.d.ts +3 -0
  135. package/dist/rules/over-defensive-nulls.d.ts.map +1 -0
  136. package/dist/rules/over-defensive-nulls.js +129 -0
  137. package/dist/rules/over-defensive-nulls.js.map +1 -0
  138. package/dist/rules/redundant-else-return.d.ts +3 -0
  139. package/dist/rules/redundant-else-return.d.ts.map +1 -0
  140. package/dist/rules/redundant-else-return.js +57 -0
  141. package/dist/rules/redundant-else-return.js.map +1 -0
  142. package/dist/rules/single-option-object.d.ts +3 -0
  143. package/dist/rules/single-option-object.d.ts.map +1 -0
  144. package/dist/rules/single-option-object.js +88 -0
  145. package/dist/rules/single-option-object.js.map +1 -0
  146. package/dist/rules/single-use-wrapper.d.ts +3 -0
  147. package/dist/rules/single-use-wrapper.d.ts.map +1 -0
  148. package/dist/rules/single-use-wrapper.js +172 -0
  149. package/dist/rules/single-use-wrapper.js.map +1 -0
  150. package/dist/rules/unnecessary-try-catch.d.ts +3 -0
  151. package/dist/rules/unnecessary-try-catch.d.ts.map +1 -0
  152. package/dist/rules/unnecessary-try-catch.js +116 -0
  153. package/dist/rules/unnecessary-try-catch.js.map +1 -0
  154. package/dist/rules/unused-imports.d.ts +3 -0
  155. package/dist/rules/unused-imports.d.ts.map +1 -0
  156. package/dist/rules/unused-imports.js +103 -0
  157. package/dist/rules/unused-imports.js.map +1 -0
  158. package/dist/rules/verbose-comments.d.ts +3 -0
  159. package/dist/rules/verbose-comments.d.ts.map +1 -0
  160. package/dist/rules/verbose-comments.js +100 -0
  161. package/dist/rules/verbose-comments.js.map +1 -0
  162. package/dist/scanner.d.ts +11 -0
  163. package/dist/scanner.d.ts.map +1 -0
  164. package/dist/scanner.js +196 -0
  165. package/dist/scanner.js.map +1 -0
  166. package/dist/scorer.d.ts +3 -0
  167. package/dist/scorer.d.ts.map +1 -0
  168. package/dist/scorer.js +23 -0
  169. package/dist/scorer.js.map +1 -0
  170. package/dist/types.d.ts +62 -0
  171. package/dist/types.d.ts.map +1 -0
  172. package/dist/types.js +3 -0
  173. package/dist/types.js.map +1 -0
  174. package/hn_post.md +13 -0
  175. package/marketing/COMPETITIVE_ANALYSIS.md +62 -0
  176. package/marketing/EMAIL_ANNOUNCEMENT.md +91 -0
  177. package/marketing/LANDING_PAGE_COPY.md +123 -0
  178. package/marketing/LAUNCH_POST.md +68 -0
  179. package/marketing/PRODUCT_HUNT.md +39 -0
  180. package/marketing/TWITTER_THREAD.md +70 -0
  181. package/package.json +44 -0
  182. package/producthunt.md +52 -0
  183. package/reddit_post.md +39 -0
  184. package/site/favicon.svg +10 -0
  185. package/site/index.html +281 -0
  186. package/site/script.js +82 -0
  187. package/site/style.css +516 -0
  188. package/src/cache.ts +114 -0
  189. package/src/cli.ts +169 -0
  190. package/src/commands/ci.ts +111 -0
  191. package/src/commands/diff.ts +108 -0
  192. package/src/commands/fingerprint.ts +47 -0
  193. package/src/commands/hook.ts +85 -0
  194. package/src/commands/init.ts +42 -0
  195. package/src/config.ts +75 -0
  196. package/src/errors.ts +105 -0
  197. package/src/fingerprint/analyzer.ts +214 -0
  198. package/src/fingerprint/comparator.ts +93 -0
  199. package/src/fingerprint/profile.ts +32 -0
  200. package/src/fixes/index.ts +58 -0
  201. package/src/fixes/single-use-wrapper.ts +60 -0
  202. package/src/fixes/unnecessary-try-catch.ts +43 -0
  203. package/src/fixes/unused-imports.ts +53 -0
  204. package/src/fixes/verbose-comments.ts +35 -0
  205. package/src/formatter.ts +79 -0
  206. package/src/git.ts +115 -0
  207. package/src/index.ts +15 -0
  208. package/src/languages/index.ts +50 -0
  209. package/src/languages/javascript.ts +36 -0
  210. package/src/languages/python.ts +47 -0
  211. package/src/parser.ts +52 -0
  212. package/src/reporters/github.ts +75 -0
  213. package/src/reporters/terminal.ts +67 -0
  214. package/src/rules/dead-code-paths.ts +62 -0
  215. package/src/rules/excessive-comments.ts +94 -0
  216. package/src/rules/hallucinated-imports.ts +195 -0
  217. package/src/rules/index.ts +32 -0
  218. package/src/rules/magic-values.ts +167 -0
  219. package/src/rules/near-duplicate-functions.ts +89 -0
  220. package/src/rules/over-defensive-nulls.ts +137 -0
  221. package/src/rules/redundant-else-return.ts +61 -0
  222. package/src/rules/single-option-object.ts +97 -0
  223. package/src/rules/single-use-wrapper.ts +184 -0
  224. package/src/rules/unnecessary-try-catch.ts +121 -0
  225. package/src/rules/unused-imports.ts +115 -0
  226. package/src/rules/verbose-comments.ts +105 -0
  227. package/src/scanner.ts +184 -0
  228. package/src/scorer.ts +26 -0
  229. package/src/types.ts +70 -0
  230. package/tests/commands/diff.test.ts +107 -0
  231. package/tests/config.test.ts +69 -0
  232. package/tests/e2e.test.ts +163 -0
  233. package/tests/edge-cases.test.ts +167 -0
  234. package/tests/fingerprint/analyzer.test.ts +131 -0
  235. package/tests/fixes/unnecessary-try-catch.test.ts +62 -0
  236. package/tests/git.test.ts +79 -0
  237. package/tests/rules/hallucinated-imports.test.ts +59 -0
  238. package/tests/rules/near-duplicate-functions.test.ts +90 -0
  239. package/tests/rules/unnecessary-try-catch.test.ts +81 -0
  240. package/tests/scanner.test.ts +88 -0
  241. package/tsconfig.json +20 -0
  242. package/twitter_thread.md +46 -0
  243. package/vitest.config.ts +7 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verbose-comments.js","sourceRoot":"","sources":["../../src/rules/verbose-comments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { ScanResult, ScanSummary, Rule, StyleProfile } from './types';
2
+ export interface ScanPathsOptions {
3
+ rules?: Rule[];
4
+ configDir?: string;
5
+ style?: boolean;
6
+ verbose?: boolean;
7
+ }
8
+ export declare function scanPaths(paths: string[], options?: Rule[] | ScanPathsOptions): Promise<ScanSummary>;
9
+ export declare function resolveFiles(paths: string[], extraIgnore?: string[]): Promise<string[]>;
10
+ export declare function scanFile(filePath: string, rules?: Rule[], profile?: StyleProfile | null, verbose?: boolean): ScanResult | null;
11
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAW3E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAgE1G;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAgC7F;AAED,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,IAAI,EAAE,EACd,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI,EAC7B,OAAO,UAAQ,GACd,UAAU,GAAG,IAAI,CAiDnB"}
@@ -0,0 +1,196 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.scanPaths = scanPaths;
40
+ exports.resolveFiles = resolveFiles;
41
+ exports.scanFile = scanFile;
42
+ const fs = __importStar(require("fs"));
43
+ const fast_glob_1 = __importDefault(require("fast-glob"));
44
+ const parser_1 = require("./parser");
45
+ const rules_1 = require("./rules");
46
+ const scorer_1 = require("./scorer");
47
+ const config_1 = require("./config");
48
+ const languages_1 = require("./languages");
49
+ const fixes_1 = require("./fixes");
50
+ const profile_1 = require("./fingerprint/profile");
51
+ const comparator_1 = require("./fingerprint/comparator");
52
+ const errors_1 = require("./errors");
53
+ function countLines(source) {
54
+ if (source.length === 0)
55
+ return 0;
56
+ let count = 1;
57
+ for (let i = 0; i < source.length; i++) {
58
+ if (source[i] === '\n')
59
+ count++;
60
+ }
61
+ return count;
62
+ }
63
+ async function scanPaths(paths, options) {
64
+ let activeRules;
65
+ let configDir;
66
+ let useStyle = false;
67
+ let verbose = false;
68
+ if (Array.isArray(options)) {
69
+ activeRules = options;
70
+ }
71
+ else if (options && !Array.isArray(options)) {
72
+ activeRules = options.rules;
73
+ configDir = options.configDir;
74
+ useStyle = options.style ?? false;
75
+ verbose = options.verbose ?? false;
76
+ }
77
+ const config = (0, config_1.loadConfig)(configDir ?? (paths.length > 0 ? paths[0] : process.cwd()));
78
+ let rules = activeRules ?? rules_1.allRules;
79
+ if (config.rules) {
80
+ rules = rules.filter((rule) => {
81
+ const setting = config.rules?.[rule.name];
82
+ return setting !== 'off';
83
+ });
84
+ rules = rules.map((rule) => {
85
+ const setting = config.rules?.[rule.name];
86
+ if (setting === 'warn' || setting === 'error') {
87
+ return { ...rule, severity: setting === 'warn' ? 'warning' : 'error' };
88
+ }
89
+ return rule;
90
+ });
91
+ }
92
+ let profile = null;
93
+ if (useStyle) {
94
+ const profileDir = configDir ?? (paths.length > 0 ? paths[0] : process.cwd());
95
+ profile = (0, profile_1.loadProfile)(profileDir);
96
+ if (!profile) {
97
+ profile = (0, profile_1.loadProfile)(process.cwd());
98
+ }
99
+ }
100
+ const files = await resolveFiles(paths, config.ignore);
101
+ if (verbose) {
102
+ console.error(`Scanning ${files.length} file(s) with ${rules.length} rule(s)...`);
103
+ }
104
+ const results = [];
105
+ for (const filePath of files) {
106
+ const startTime = verbose ? performance.now() : 0;
107
+ const result = scanFile(filePath, rules, profile, verbose);
108
+ if (verbose && result) {
109
+ const elapsed = (performance.now() - startTime).toFixed(1);
110
+ console.error(` ${filePath}: ${result.findings.length} finding(s) in ${elapsed}ms`);
111
+ }
112
+ if (result) {
113
+ results.push(result);
114
+ }
115
+ }
116
+ return (0, scorer_1.computeScore)(results);
117
+ }
118
+ async function resolveFiles(paths, extraIgnore) {
119
+ const files = [];
120
+ const supportedExts = (0, languages_1.getSupportedExtensions)();
121
+ const ignorePatterns = [
122
+ '**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**', '**/vendor/**',
123
+ ...(extraIgnore ?? []),
124
+ ];
125
+ for (const p of paths) {
126
+ let stat;
127
+ try {
128
+ stat = fs.statSync(p);
129
+ }
130
+ catch {
131
+ continue;
132
+ }
133
+ if (stat.isFile()) {
134
+ const lang = (0, parser_1.detectLanguage)(p);
135
+ if (lang)
136
+ files.push(p);
137
+ }
138
+ else if (stat.isDirectory()) {
139
+ const pattern = `**/*.{${supportedExts.join(',')}}`;
140
+ const found = await (0, fast_glob_1.default)(pattern, {
141
+ cwd: p,
142
+ absolute: true,
143
+ ignore: ignorePatterns,
144
+ });
145
+ files.push(...found);
146
+ }
147
+ }
148
+ return files.sort();
149
+ }
150
+ function scanFile(filePath, rules, profile, verbose = false) {
151
+ const activeRules = rules ?? rules_1.allRules;
152
+ const language = (0, parser_1.detectLanguage)(filePath);
153
+ if (!language) {
154
+ if (verbose)
155
+ console.error(` [skip] ${filePath}: unsupported language`);
156
+ return null;
157
+ }
158
+ const fileData = (0, errors_1.safeReadFile)(filePath, verbose);
159
+ if (!fileData)
160
+ return null;
161
+ const { source } = fileData;
162
+ const loc = countLines(source);
163
+ let tree;
164
+ try {
165
+ tree = (0, parser_1.parse)(source, language);
166
+ }
167
+ catch (err) {
168
+ if (verbose) {
169
+ console.error(` [skip] ${filePath}: parse error — ${err.message}`);
170
+ }
171
+ return null;
172
+ }
173
+ let findings = activeRules.flatMap((rule) => {
174
+ try {
175
+ const ruleStart = verbose ? performance.now() : 0;
176
+ const ruleFindings = rule.check(tree, source, filePath);
177
+ if (verbose) {
178
+ const elapsed = (performance.now() - ruleStart).toFixed(1);
179
+ if (ruleFindings.length > 0) {
180
+ console.error(` [rule] ${rule.name}: ${ruleFindings.length} finding(s) (${elapsed}ms)`);
181
+ }
182
+ }
183
+ return ruleFindings;
184
+ }
185
+ catch {
186
+ return [];
187
+ }
188
+ });
189
+ findings = (0, fixes_1.attachFixes)(findings, tree, source);
190
+ if (profile) {
191
+ const styleFindings = (0, comparator_1.compareFileToProfile)(filePath, source, tree, profile);
192
+ findings.push(...styleFindings);
193
+ }
194
+ return { file: filePath, findings, loc };
195
+ }
196
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ScanResult, ScanSummary } from './types';
2
+ export declare function computeScore(results: ScanResult[]): ScanSummary;
3
+ //# sourceMappingURL=scorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAY,MAAM,SAAS,CAAC;AAQjE,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,WAAW,CAiB/D"}
package/dist/scorer.js ADDED
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeScore = computeScore;
4
+ const SEVERITY_WEIGHTS = {
5
+ info: 1,
6
+ warning: 3,
7
+ error: 5,
8
+ };
9
+ function computeScore(results) {
10
+ const totalLoc = results.reduce((sum, r) => sum + r.loc, 0);
11
+ const totalFindings = results.reduce((sum, r) => sum + r.findings.length, 0);
12
+ if (totalLoc === 0 || totalFindings === 0) {
13
+ return { results, totalFindings: 0, score: 0 };
14
+ }
15
+ const weightedSum = results.reduce((sum, r) => {
16
+ return sum + r.findings.reduce((fSum, f) => fSum + SEVERITY_WEIGHTS[f.severity], 0);
17
+ }, 0);
18
+ // Normalize: weighted findings per 100 lines of code, capped at 100
19
+ const rawScore = (weightedSum / totalLoc) * 100;
20
+ const score = Math.min(100, Math.round(rawScore));
21
+ return { results, totalFindings, score };
22
+ }
23
+ //# sourceMappingURL=scorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorer.js","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":";;AAQA,oCAiBC;AAvBD,MAAM,gBAAgB,GAA6B;IACjD,IAAI,EAAE,CAAC;IACP,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,CAAC;CACT,CAAC;AAEF,SAAgB,YAAY,CAAC,OAAqB;IAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAC5D,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAE7E,IAAI,QAAQ,KAAK,CAAC,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;QAC1C,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QAC5C,OAAO,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IACtF,CAAC,EAAE,CAAC,CAAC,CAAC;IAEN,oEAAoE;IACpE,MAAM,QAAQ,GAAG,CAAC,WAAW,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC;IAChD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAElD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,62 @@
1
+ import type Parser from 'tree-sitter';
2
+ export type Severity = 'info' | 'warning' | 'error';
3
+ export interface FixSuggestion {
4
+ description: string;
5
+ replacement: string;
6
+ }
7
+ export interface Finding {
8
+ file: string;
9
+ line: number;
10
+ column: number;
11
+ endLine: number;
12
+ endColumn: number;
13
+ rule: string;
14
+ severity: Severity;
15
+ message: string;
16
+ snippet?: string;
17
+ fix?: FixSuggestion;
18
+ }
19
+ export interface Rule {
20
+ name: string;
21
+ description: string;
22
+ severity: Severity;
23
+ check(tree: Parser.Tree, source: string, filePath: string): Finding[];
24
+ }
25
+ export interface ScanResult {
26
+ file: string;
27
+ findings: Finding[];
28
+ loc: number;
29
+ }
30
+ export interface ScanSummary {
31
+ results: ScanResult[];
32
+ totalFindings: number;
33
+ score: number;
34
+ }
35
+ export type Language = 'javascript' | 'typescript' | 'tsx' | 'python';
36
+ export interface ScanOptions {
37
+ paths: string[];
38
+ format?: 'text' | 'json';
39
+ threshold?: number;
40
+ style?: boolean;
41
+ }
42
+ export interface StyleProfile {
43
+ generatedAt: string;
44
+ fileCount: number;
45
+ totalLoc: number;
46
+ metrics: {
47
+ medianFunctionLength: number;
48
+ averageFunctionLength: number;
49
+ maxFunctionLength: number;
50
+ namingConventions: {
51
+ camelCase: number;
52
+ snake_case: number;
53
+ PascalCase: number;
54
+ other: number;
55
+ };
56
+ commentToCodeRatio: number;
57
+ averageNestingDepth: number;
58
+ tryCatchDensity: number;
59
+ averageImportsPerFile: number;
60
+ };
61
+ }
62
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,aAAa,CAAC;CACrB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CAAC;CACvE;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,YAAY,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEtE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE;QACP,oBAAoB,EAAE,MAAM,CAAC;QAC7B,qBAAqB,EAAE,MAAM,CAAC;QAC9B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,iBAAiB,EAAE;YACjB,SAAS,EAAE,MAAM,CAAC;YAClB,UAAU,EAAE,MAAM,CAAC;YACnB,UAAU,EAAE,MAAM,CAAC;YACnB,KAAK,EAAE,MAAM,CAAC;SACf,CAAC;QACF,kBAAkB,EAAE,MAAM,CAAC;QAC3B,mBAAmB,EAAE,MAAM,CAAC;QAC5B,eAAe,EAAE,MAAM,CAAC;QACxB,qBAAqB,EAAE,MAAM,CAAC;KAC/B,CAAC;CACH"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/hn_post.md ADDED
@@ -0,0 +1,13 @@
1
+ **Title:** Show HN: Distyll — Catch AI-generated code slop before it ships
2
+
3
+ **URL:** [GITHUB_URL]
4
+
5
+ **Text:**
6
+
7
+ Distyll is a CLI tool that detects the structural anti-patterns that AI coding tools (Copilot, Claude Code, Cursor) consistently produce. It uses tree-sitter for AST analysis — no LLM required — and assigns a "slop score" (0-100) to your code with specific fix suggestions.
8
+
9
+ The core insight is that AI-generated code has predictable failure modes that existing linters miss: unnecessary try-catch around synchronous functions, single-use abstractions that add indirection without value, verbose comments restating the obvious, hallucinated imports, near-duplicate functions with subtle variations, and over-engineered options objects for one-off calls. These aren't style issues — they're structural bloat that compounds into unmaintainable codebases. Distyll has 12 detection rules targeting these specific patterns across JavaScript, TypeScript, and Python.
10
+
11
+ You can run it as a one-off scan (`distyll scan .`), on git diffs only (`distyll diff`), as a pre-commit hook (`distyll hook install`), or in CI with GitHub Actions annotations (`distyll ci`). There's also a `fingerprint` command that profiles your codebase's existing patterns — naming conventions, abstraction depth, comment density — and flags AI-generated code that deviates from your team's style. Everything is configurable via `.distyll.json` with per-rule severity overrides and threshold settings.
12
+
13
+ I built this after realizing I was rubber-stamping AI-generated PRs that "worked" but were quietly bloating my projects. Curious to hear if others have found similar patterns in their AI-assisted codebases.
@@ -0,0 +1,62 @@
1
+ # Competitive Analysis
2
+
3
+ ## Landscape
4
+
5
+ The code quality tooling space has no tool purpose-built for AI-generated code anti-patterns. Existing tools fall into three categories: syntax linters, generic AI code reviewers, and complexity analyzers. Distyll is the first to target the structural bloat patterns that AI coding tools specifically produce.
6
+
7
+ ## Alternatives
8
+
9
+ ### 1. ESLint / Ruff
10
+ **What they do:** Syntax and style linting for JS/TS (ESLint) and Python (Ruff).
11
+ **Strengths:** Mature ecosystems, thousands of rules, fast, well-integrated into every editor and CI system.
12
+ **Gap:** They check whether your code *follows formatting rules*, not whether it's *structurally bloated*. An unnecessary wrapper function that follows all style rules passes ESLint without a flag. They don't detect over-abstraction, hallucinated imports, near-duplicate functions, or verbose comments that restate code.
13
+
14
+ ### 2. CodeRabbit
15
+ **What they do:** AI-powered code review that posts comments on PRs.
16
+ **Strengths:** Good at catching logic issues, broad coverage, integrates with GitHub/GitLab.
17
+ **Gap:** Generic AI review — not specifically targeting AI-generated anti-patterns. Requires cloud API calls (can't run offline). $12/user/month. Review quality varies; it doesn't assign a quantitative slop score or track trends. No pre-commit hook or local-first workflow.
18
+
19
+ ### 3. SonarQube / SonarCloud
20
+ **What they do:** Code quality and security analysis with complexity metrics.
21
+ **Strengths:** Deep security analysis, technical debt tracking, enterprise adoption, broad language support.
22
+ **Gap:** Measures cyclomatic complexity and code duplication, but misses AI-specific patterns. Won't flag a try-catch around pure code (low complexity, so it passes), won't catch hallucinated imports, won't detect that a wrapper function adds no logic. Heavy infrastructure for self-hosting. Starts at $13/month for cloud.
23
+
24
+ ### 4. AI-SLOP-Detector
25
+ **What they do:** Python-based slop detection with 25 patterns, AST analysis, optional ML pipeline.
26
+ **Strengths:** Broad pattern coverage, self-calibrating scoring, VS Code extension.
27
+ **Gap:** Python-only tool (not ideal for JS/TS projects). Limited adoption (1 active contributor). DX issues (inconsistent CLI formatting). No git integration, no CI mode, no pre-commit hooks. No style fingerprinting.
28
+
29
+ ### 5. KarpeSlop
30
+ **What they do:** JS/TS slop detection via regex pattern matching.
31
+ **Strengths:** Easy npx invocation, JSON output for CI.
32
+ **Gap:** Regex-based detection causes significant false positives — matches patterns inside comments and string literals, can't distinguish code structure from text. No AST parsing. Limited adoption and active development.
33
+
34
+ ## Comparison Matrix
35
+
36
+ | Capability | Distyll | ESLint/Ruff | CodeRabbit | SonarQube | AI-SLOP-Detector | KarpeSlop |
37
+ |---|---|---|---|---|---|---|
38
+ | AI slop detection | 12 rules | No | Generic | No | 25 rules | 8 rules |
39
+ | AST-based analysis | tree-sitter | Yes | N/A | Yes | Python AST | No (regex) |
40
+ | Slop score | 0-100 | No | No | Complexity only | Yes | Yes |
41
+ | Fix suggestions | Yes | Some | Yes | Some | No | No |
42
+ | Style fingerprinting | Yes | No | No | No | No | No |
43
+ | Git hook integration | Built-in | Via plugin | No | No | No | No |
44
+ | Diff-only scanning | Yes | No | PR-based | PR-based | No | No |
45
+ | CI / GitHub Actions | Native | Native | Native | Native | No | JSON output |
46
+ | Offline / local-first | Yes | Yes | No | Self-host | Yes | Yes |
47
+ | Multi-language | JS/TS, Python | Per tool | Many | Many | Python only | JS/TS only |
48
+ | False positive rate | Low (conservative) | N/A | Medium | Low | Medium | High |
49
+ | Price | Free (OSS) | Free (OSS) | $12/user/mo | $13+/mo | Free (OSS) | Free (OSS) |
50
+
51
+ ## Key Differentiators
52
+
53
+ 1. **Purpose-built for AI slop** — Not a generic linter or AI reviewer. Every rule targets patterns that AI coding tools specifically produce.
54
+ 2. **AST-based, not regex** — Tree-sitter parsing eliminates the false positives that plague regex-based alternatives.
55
+ 3. **Conservative by default** — The #1 lesson from prior art: tools that cry wolf get turned off. Distyll only flags patterns that are clearly AI-generated bloat.
56
+ 4. **Diff-first workflow** — Designed to scan PRs and staged changes, not audit entire codebases. Integrates as a pre-commit hook and CI check.
57
+ 5. **Style fingerprinting** — Unique capability: learns your team's actual coding patterns and flags deviations, not just generic anti-patterns.
58
+ 6. **Fully offline** — No API calls, no cloud dependency. Runs in seconds on local hardware.
59
+
60
+ ## Positioning Statement
61
+
62
+ **For engineering teams using AI coding tools** who need to maintain code quality without slowing down their AI-assisted workflow, **Distyll is a code quality gate** that detects AI-generated anti-patterns in pull requests using AST analysis. **Unlike ESLint** (which checks syntax), **CodeRabbit** (which does generic AI review), or **SonarQube** (which measures complexity), **Distyll specifically targets the structural bloat patterns that AI coding tools produce** — unnecessary abstractions, hallucinated imports, verbose comments, and copy-paste duplication — and catches them in seconds with zero false-positive tolerance.
@@ -0,0 +1,91 @@
1
+ # Launch Email
2
+
3
+ ## Subject Line
4
+ Distyll: Stop merging AI-generated code slop
5
+
6
+ ### Alternative Subject Lines
7
+ - Your AI-assisted codebase is 30% bigger than it needs to be
8
+ - A slop score for every PR — catch AI code bloat automatically
9
+
10
+ ## Preview Text
11
+ 12 detection rules for the anti-patterns AI coding tools love to create. Free, open source, runs in seconds.
12
+
13
+ ---
14
+
15
+ ## Email Body
16
+
17
+ ### Hero
18
+ **Your AI coding tools write code that works. They also write code that's bloated.**
19
+
20
+ Distyll catches the difference — automatically, in seconds, before it ships.
21
+
22
+ ### The Problem
23
+ AI coding tools produce predictable anti-patterns:
24
+
25
+ - **Wrapper functions** called once that add zero logic
26
+ - **Try-catch blocks** around synchronous code that can't throw
27
+ - **Comments** that restate the code verbatim
28
+ - **Copy-paste functions** that are 90% identical
29
+ - **Hallucinated imports** of modules that don't exist
30
+
31
+ None of these break your build. They all make your codebase worse. And after months of merging AI-generated PRs, the bloat compounds into real maintenance burden.
32
+
33
+ ### The Solution
34
+ Distyll is a CLI that scans your code for 12 AI-specific anti-patterns using tree-sitter AST analysis. It gives you:
35
+
36
+ - A **slop score** (0-100) for any file, directory, or git diff
37
+ - **Specific findings** with file, line number, and explanation
38
+ - **Fix suggestions** showing the minimal change to remove the bloat
39
+
40
+ ### Key Features
41
+
42
+ **Scan anything** — files, directories, or just your staged changes:
43
+ ```
44
+ npx distyll scan .
45
+ distyll diff --staged
46
+ ```
47
+
48
+ **Block slop in CI** — GitHub Actions integration with inline PR annotations:
49
+ ```
50
+ distyll ci --threshold 50 --ref main
51
+ ```
52
+
53
+ **Learn your style** — fingerprint your codebase so Distyll flags code that deviates from YOUR patterns, not generic rules:
54
+ ```
55
+ distyll fingerprint
56
+ distyll scan --style .
57
+ ```
58
+
59
+ **Pre-commit hooks** — catch slop before it's committed:
60
+ ```
61
+ distyll hook install --threshold 70
62
+ ```
63
+
64
+ ### Get Started
65
+ ```
66
+ npm install -g distyll
67
+ distyll scan .
68
+ ```
69
+
70
+ Works on JavaScript, TypeScript, and Python. Runs offline. MIT licensed.
71
+
72
+ [Install Distyll →]
73
+
74
+ ---
75
+
76
+ ## Plain Text Version
77
+
78
+ Your AI coding tools write working code. They also write bloated code — unnecessary wrappers, try-catch around code that can't throw, comments restating the obvious, copy-paste with subtle variations.
79
+
80
+ Distyll catches these patterns automatically.
81
+
82
+ It's a CLI that scans your code (or just your git diff) for 12 AI-specific anti-patterns using AST analysis. You get a slop score (0-100) with specific findings and fix suggestions.
83
+
84
+ Install: npm install -g distyll
85
+ Scan: distyll scan .
86
+ Git hook: distyll hook install
87
+ CI: distyll ci --threshold 50
88
+
89
+ Supports JS/TS and Python. Runs in seconds. Works offline. MIT licensed.
90
+
91
+ Try it: npx distyll scan .
@@ -0,0 +1,123 @@
1
+ # Landing Page Copy
2
+
3
+ ## Hero
4
+
5
+ ### Headline
6
+ Catch AI-generated code slop before it ships
7
+
8
+ ### Subheadline
9
+ A quality gate for the vibe-coding era. 12 AST-based detection rules, a slop score on every PR, and fix suggestions that actually help. Runs in seconds, works offline.
10
+
11
+ ### CTA
12
+ ```
13
+ npm install -g distyll
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Problem Section
19
+
20
+ ### Heading
21
+ AI coding tools write code that works. They also write code like this.
22
+
23
+ ### Body
24
+ After months of merging AI-assisted PRs, your codebase has accumulated:
25
+
26
+ - **Wrapper functions** that wrap a single call and are used exactly once — abstraction that abstracts nothing
27
+ - **Try-catch blocks** around synchronous pure functions that literally cannot throw
28
+ - **Comments** like `// increment the counter` above `counter++`
29
+ - **Copy-paste functions** that are 90% identical with one variable renamed
30
+ - **Imports** of modules that don't exist — the AI hallucinated them confidently
31
+
32
+ None of these trigger your linter. None of them break your tests. All of them make your codebase harder to maintain, harder to read, and bigger than it needs to be.
33
+
34
+ Traditional linters check syntax and style. Code review catches logic bugs. **Nothing catches the structural bloat in between** — until now.
35
+
36
+ ---
37
+
38
+ ## Solution Section
39
+
40
+ ### Heading
41
+ One command. Specific findings. Actionable fixes.
42
+
43
+ ### Body
44
+ Distyll uses tree-sitter AST parsing to analyze your code for 12 anti-patterns unique to AI-generated output. No regex (which causes false positives). No AI-to-detect-AI (which is slow and expensive). Just fast, deterministic structural analysis.
45
+
46
+ ```
47
+ $ distyll scan src/
48
+ src/utils.ts
49
+ L12 warning single-use-wrapper `formatDate` wraps `dayjs().format()` and is called once — inline it
50
+ L34 error unnecessary-try-catch try-catch wraps synchronous pure function `calculateTotal`
51
+ L67 info verbose-comments Comment restates code: "// return the result" above `return result`
52
+
53
+ Slop Score: 34/100 (Moderate)
54
+ ```
55
+
56
+ Every finding includes the file, line, rule, severity, and a plain-English explanation. Fix suggestions show you the minimal change.
57
+
58
+ ---
59
+
60
+ ## Feature Blocks
61
+
62
+ ### Feature 1: 12 Detection Rules
63
+ Purpose-built for AI-generated code patterns. Unnecessary try-catch, single-use wrappers, verbose comments, unused imports, hallucinated imports, near-duplicate functions, over-defensive null checks, magic values, dead code paths, and more. Each rule is conservative — we'd rather miss slop than false-flag your code.
64
+
65
+ ### Feature 2: Git-Aware Scanning
66
+ `distyll diff --staged` checks only your changes, not the whole codebase. Use it as a pre-commit hook to block commits above a slop threshold, or run `distyll ci` in GitHub Actions to get findings as inline PR annotations.
67
+
68
+ ### Feature 3: Style Fingerprinting
69
+ `distyll fingerprint` learns your codebase's actual patterns — function length, naming conventions, comment density, nesting depth. Then `--style` mode flags AI-generated code that deviates from YOUR team's style, not some generic ruleset.
70
+
71
+ ### Feature 4: Slop Score (0-100)
72
+ Every scan produces a weighted score normalized by lines of code. Track it over time. Set thresholds in CI. Know at a glance whether a PR is clean or needs attention.
73
+
74
+ ### Feature 5: Fix Suggestions
75
+ Distyll doesn't just flag problems — it shows you the fix. "This 3-layer abstraction can be inlined to 4 lines." "This try-catch wraps a pure function — remove it." Minimal diffs, not rewrites.
76
+
77
+ ---
78
+
79
+ ## Social Proof Section
80
+
81
+ > "I ran Distyll on 6 months of AI-generated PRs. 30% of the code it flagged was genuinely unnecessary."
82
+ > — *[Placeholder for early user testimonial]*
83
+
84
+ > "The pre-commit hook is what sold me. Catches slop without slowing us down."
85
+ > — *[Placeholder for early user testimonial]*
86
+
87
+ *[Replace with real testimonials as they come in]*
88
+
89
+ ---
90
+
91
+ ## FAQ
92
+
93
+ ### What languages does Distyll support?
94
+ JavaScript, TypeScript, and Python. Go and Rust support is planned.
95
+
96
+ ### Does it require an internet connection?
97
+ No. Distyll runs entirely locally using AST analysis. No API calls, no cloud dependency, no data leaves your machine.
98
+
99
+ ### How is this different from ESLint or SonarQube?
100
+ ESLint checks syntax and formatting rules. SonarQube measures cyclomatic complexity. Neither detects the structural anti-patterns unique to AI-generated code — unnecessary abstractions, hallucinated imports, verbose comments, copy-paste duplication. Distyll fills that gap.
101
+
102
+ ### Will it slow down my commits?
103
+ No. Distyll scans typical PRs in under 10 seconds. The pre-commit hook only checks staged changes, not your whole codebase.
104
+
105
+ ### What if it flags something that's actually fine?
106
+ Every rule is conservative by default. You can disable individual rules in `.distyll.json`, set them to `warn` instead of `error`, or add files/directories to the ignore list. If you find a genuine false positive, report it — reducing false positives is the top priority.
107
+
108
+ ---
109
+
110
+ ## Final CTA
111
+
112
+ ### Heading
113
+ Stop shipping slop.
114
+
115
+ ### Body
116
+ Install Distyll in 30 seconds. See your slop score in 10 more.
117
+
118
+ ```
119
+ npm install -g distyll
120
+ distyll scan .
121
+ ```
122
+
123
+ MIT licensed. Works offline. Supports JS/TS and Python.