@eduardbar/drift 0.3.0 → 0.4.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.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something is broken or behaving unexpectedly
4
+ title: "fix: "
5
+ labels: bug
6
+ assignees: ""
7
+ ---
8
+
9
+ ## What happened
10
+
11
+ <!-- A clear description of the bug. -->
12
+
13
+ ## Steps to reproduce
14
+
15
+ 1. Run `npx @eduardbar/drift scan ...`
16
+ 2. ...
17
+
18
+ ## Expected behavior
19
+
20
+ <!-- What should have happened. -->
21
+
22
+ ## Actual behavior
23
+
24
+ <!-- What actually happened. Include the full terminal output if relevant. -->
25
+
26
+ ## Environment
27
+
28
+ - drift version: <!-- run `npx @eduardbar/drift --version` -->
29
+ - Node.js version: <!-- run `node --version` -->
30
+ - OS: <!-- e.g. Windows 11, macOS 14, Ubuntu 22.04 -->
31
+ - Shell: <!-- e.g. PowerShell, bash, zsh -->
32
+
33
+ ## Minimal reproduction
34
+
35
+ ```typescript
36
+ // Paste the smallest possible file that triggers the bug
37
+ ```
38
+
39
+ ## Additional context
40
+
41
+ <!-- Screenshots, links, anything else that helps. -->
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: Feature request
3
+ about: Propose a new detection rule or CLI feature
4
+ title: "feat: "
5
+ labels: enhancement
6
+ assignees: ""
7
+ ---
8
+
9
+ ## Problem
10
+
11
+ <!-- What specific AI-generated pattern or technical debt is NOT currently detected?
12
+ Or what workflow friction does this feature address? -->
13
+
14
+ ## Proposed solution
15
+
16
+ <!-- Describe the rule or feature. If it's a new detection rule, include:
17
+ - Rule name (kebab-case)
18
+ - Severity: error | warning | info
19
+ - Suggested weight (1–20)
20
+ - What it detects and why it matters -->
21
+
22
+ ## Example
23
+
24
+ ```typescript
25
+ // Code that SHOULD trigger the new rule
26
+ function example() {
27
+ // ...
28
+ }
29
+ ```
30
+
31
+ ## Why drift and not ESLint
32
+
33
+ <!-- drift is NOT an ESLint replacement. It targets patterns ESLint can't catch:
34
+ architectural violations, AI-specific habits, historical debt trends.
35
+ Explain why this belongs in drift. -->
36
+
37
+ ## Additional context
38
+
39
+ <!-- Links, references, real-world examples that motivated this request. -->
@@ -0,0 +1,46 @@
1
+ # Pull Request
2
+
3
+ ## Type
4
+
5
+ - [ ] Bug fix
6
+ - [ ] New detection rule
7
+ - [ ] New CLI feature
8
+ - [ ] Refactor / performance
9
+ - [ ] Docs
10
+ - [ ] Other
11
+
12
+ ## Summary
13
+
14
+ <!-- What does this PR do and why? 1–3 sentences max. -->
15
+
16
+ ## Changes
17
+
18
+ -
19
+ -
20
+
21
+ ## New rule checklist (skip if not applicable)
22
+
23
+ - [ ] Entry added to `RULE_WEIGHTS` in `src/analyzer.ts`
24
+ - [ ] Detection logic implemented using ts-morph AST
25
+ - [ ] `fix_suggestion` added for the rule in `src/printer.ts`
26
+ - [ ] Rule documented in `README.md` (What it detects table)
27
+ - [ ] Rule documented in `AGENTS.md` (Rules table)
28
+
29
+ ## Testing
30
+
31
+ ```bash
32
+ # Command you ran to verify this works
33
+ npx @eduardbar/drift scan ./src
34
+ ```
35
+
36
+ <!-- Paste the relevant part of the output. -->
37
+
38
+ ## Breaking changes
39
+
40
+ <!-- Does this change the score of existing scans, remove a flag, or change output format?
41
+ If yes, describe the impact. -->
42
+
43
+ ## Commit convention
44
+
45
+ This PR follows [Conventional Commits](https://www.conventionalcommits.org/).
46
+ All commits are in the format `type(scope): description`.
package/AGENTS.md ADDED
@@ -0,0 +1,229 @@
1
+ # AGENTS.md — drift
2
+
3
+ ## Qué es drift
4
+
5
+ `@eduardbar/drift` es un CLI TypeScript que escanea proyectos TypeScript con análisis AST (ts-morph) y asigna un score de 0 a 100 a cada archivo según la cantidad de deuda técnica AI-generada que contiene.
6
+
7
+ - **0** = código limpio
8
+ - **100** = reescribí esto antes de que alguien lo vea
9
+
10
+ Publicado en npm como `@eduardbar/drift`. MIT.
11
+
12
+ ---
13
+
14
+ ## Stack técnico
15
+
16
+ | Dep | Rol |
17
+ |-----|-----|
18
+ | `ts-morph ^27` | Motor AST — traversal de nodos TypeScript |
19
+ | `commander ^14` | CLI flags y subcomandos |
20
+ | `kleur ^4` | Colores en consola (sin dependencias) |
21
+ | `typescript ^5.9` | Dev — compilación |
22
+ | `@types/node ^25` | Dev — tipos Node.js |
23
+
24
+ **Runtime:** Node.js 18+, ES Modules (`"type": "module"`).
25
+
26
+ ---
27
+
28
+ ## Estructura del proyecto
29
+
30
+ ```
31
+ drift/
32
+ ├── bin/
33
+ │ └── drift.js ← wrapper cross-platform (Windows npx fix)
34
+ ├── src/
35
+ │ ├── types.ts ← interfaces: DriftIssue, FileReport, DriftReport, AIOutput
36
+ │ ├── analyzer.ts ← motor AST + 10 reglas de detección + drift-ignore
37
+ │ ├── reporter.ts ← buildReport(), formatMarkdown(), formatAIOutput()
38
+ │ ├── printer.ts ← salida consola con colores y score bar ASCII
39
+ │ ├── utils.ts ← scoreToGrade, severityIcon, scoreBar
40
+ │ ├── index.ts ← re-exports públicos (librería)
41
+ │ └── cli.ts ← entry point Commander.js
42
+ ├── assets/
43
+ │ ├── og.svg / og.png ← imagen OG original
44
+ │ ├── og-v030-linkedin.svg/png ← imagen post LinkedIn v0.3.0
45
+ │ └── og-v030-x.svg/png ← imagen hilo X v0.3.0
46
+ ├── dist/ ← output tsc (no editar a mano)
47
+ ├── .github/workflows/publish.yml
48
+ ├── package.json
49
+ ├── tsconfig.json
50
+ └── AGENTS.md ← este archivo
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Comandos de desarrollo
56
+
57
+ ```bash
58
+ npm run build # tsc — compila src/ → dist/
59
+ npm run dev # tsc --watch
60
+ npm start # node dist/cli.js (desarrollo local)
61
+ ```
62
+
63
+ **Pre-publicación:** `prepublishOnly` corre `build` automáticamente.
64
+
65
+ ---
66
+
67
+ ## CLI — flags disponibles
68
+
69
+ | Flag | Tipo | Descripción |
70
+ |------|------|-------------|
71
+ | `scan <path>` | positional | Ruta a escanear (requerido) |
72
+ | `--output <file>` / `-o` | string | Escribe reporte Markdown a archivo |
73
+ | `--json` | boolean | Imprime `DriftReport` crudo como JSON |
74
+ | `--ai` | boolean | JSON optimizado para LLMs (`AIOutput`) |
75
+ | `--fix` | boolean | Muestra sugerencias de fix en consola |
76
+ | `--min-score <n>` | number | Exit code 1 si score supera umbral (CI) |
77
+
78
+ **Uso básico:**
79
+ ```bash
80
+ npx @eduardbar/drift scan .
81
+ npx @eduardbar/drift scan ./src --min-score 60
82
+ npx @eduardbar/drift scan ./src --ai | pbcopy # pegar en Claude/GPT
83
+ npx @eduardbar/drift scan ./src --fix # ver sugerencias inline
84
+ npx @eduardbar/drift scan ./src -o report.md # exportar Markdown
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Reglas del analyzer
90
+
91
+ | Regla | Severidad | Peso | Qué detecta |
92
+ |-------|-----------|------|-------------|
93
+ | `large-file` | error | 20 | Archivos > 300 líneas |
94
+ | `large-function` | error | 15 | Funciones > 50 líneas |
95
+ | `duplicate-function-name` | error | 18 | Nombres de función duplicados (case-insensitive) |
96
+ | `debug-leftover` | warning | 10 | `console.log/warn/error` + `TODO/FIXME/HACK/XXX/TEMP` |
97
+ | `catch-swallow` | warning | 10 | Bloques `catch {}` vacíos |
98
+ | `dead-code` | warning | 8 | Imports nombrados sin usar |
99
+ | `any-abuse` | warning | 8 | Uso explícito de `any` como tipo |
100
+ | `comment-contradiction` | warning | 12 | (reservado — definido en RULE_WEIGHTS) |
101
+ | `no-return-type` | info | 5 | Funciones sin tipo de retorno explícito |
102
+ | `magic-number` | info | 3 | (reservado — definido en RULE_WEIGHTS) |
103
+
104
+ **Score = suma de pesos capped a 100. Score del proyecto = promedio de archivos.**
105
+
106
+ ---
107
+
108
+ ## drift-ignore
109
+
110
+ **Por línea** (`// drift-ignore`):
111
+ - Suprime el issue en la línea actual o en la línea inmediatamente superior al problema.
112
+ - Funciona para cualquier regla.
113
+
114
+ **Por archivo** (`// drift-ignore-file`):
115
+ - Se coloca en las primeras 10 líneas del archivo.
116
+ - `analyzeFile()` devuelve reporte vacío (score 0, cero issues) para ese archivo.
117
+ - Usar en archivos con `console.log` intencional (ej: `printer.ts`).
118
+
119
+ ---
120
+
121
+ ## Formato `--ai` (`AIOutput`)
122
+
123
+ ```typescript
124
+ interface AIOutput {
125
+ summary: {
126
+ score: number
127
+ grade: string // "CLEAN" | "LOW" | "MEDIUM" | "HIGH" | "CRITICAL"
128
+ total_issues: number
129
+ files_affected: number
130
+ files_clean: number
131
+ }
132
+ priority_order: Array<{
133
+ rank: number
134
+ file: string
135
+ line: number
136
+ rule: string
137
+ severity: "error" | "warning" | "info"
138
+ message: string
139
+ snippet: string
140
+ fix_suggestion: string
141
+ effort: "low" | "medium" | "high"
142
+ }>
143
+ context_for_ai: {
144
+ project_type: "typescript"
145
+ scan_path: string
146
+ rules_detected: string[]
147
+ recommended_action: string
148
+ }
149
+ }
150
+ ```
151
+
152
+ Los issues se ordenan: error > warning > info, luego low effort primero (quick wins).
153
+
154
+ ---
155
+
156
+ ## Formato `--fix` en consola
157
+
158
+ ```
159
+ ┌──────────────────────────────────────────────────────┐
160
+ │ - console.log(userData)
161
+ │ + Remove this console.log statement
162
+ │ + Or replace with a proper logging library
163
+ └──────────────────────────────────────────────────────┘
164
+ ```
165
+
166
+ Las sugerencias por regla están hardcodeadas en `src/printer.ts`.
167
+
168
+ ---
169
+
170
+ ## CI/CD — GitHub Actions
171
+
172
+ Workflow en `.github/workflows/publish.yml`:
173
+ - **Trigger único:** `release: published` (evita doble publish)
174
+ - **Fallback manual:** `workflow_dispatch` con input `tag`
175
+ - **Guard:** verifica `npm view @eduardbar/drift@$VERSION` antes de publicar
176
+
177
+ **Integración CI en proyectos externos:**
178
+ ```yaml
179
+ - name: Check drift score
180
+ run: npx @eduardbar/drift scan ./src --min-score 60
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Compatibilidad Windows
186
+
187
+ `bin/drift.js` es el wrapper cross-platform:
188
+ ```javascript
189
+ #!/usr/bin/env node
190
+ import('../dist/cli.js')
191
+ ```
192
+
193
+ `package.json` apunta `bin.drift` a `bin/drift.js`, **no** a `dist/cli.js`.
194
+ Sin esto, Windows no ejecuta el shebang correctamente con ES modules.
195
+
196
+ ---
197
+
198
+ ## Versiones
199
+
200
+ | Versión | Cambios principales |
201
+ |---------|---------------------|
202
+ | **0.3.0** | `--ai` (LLM-optimized JSON output) + `--fix` (inline suggestions) |
203
+ | **0.2.3** | Fix: bin wrapper para compatibilidad Windows npx |
204
+ | **0.2.2** | Refactor: `formatMarkdown` dividido en helpers + fix CI doble publish |
205
+ | **0.2.1** | `drift-ignore` por línea y por archivo + fix console output propio |
206
+ | **0.2.0** | Score bar ASCII + header hierarchy + DRY utils + file count en CLI |
207
+ | **0.1.x** | Bootstrap: tipos, analyzer (10 reglas), reporter, printer, CLI, CI/CD |
208
+
209
+ ---
210
+
211
+ ## Convenciones de código
212
+
213
+ - Todo en TypeScript — sin `any` explícito (drift se corre sobre sí mismo)
214
+ - ES Modules — `import/export`, sin CommonJS
215
+ - Conventional Commits obligatorios (ver AGENTS.md global)
216
+ - `// drift-ignore-file` en `printer.ts` — sus `console.log` son output intencional
217
+ - `scoreToGrade`, `severityIcon`, `scoreBar` viven en `utils.ts` — no duplicar
218
+ - Nuevas reglas: agregar entrada en `RULE_WEIGHTS` en `analyzer.ts` + lógica de detección AST
219
+
220
+ ---
221
+
222
+ ## Agregar una nueva regla — checklist
223
+
224
+ 1. Agregar `"rule-name": <peso>` a `RULE_WEIGHTS` en `src/analyzer.ts`
225
+ 2. Implementar la lógica de detección AST usando ts-morph en `analyzeFile()`
226
+ 3. Agregar `fix_suggestion` para la regla en `src/printer.ts` (objeto de sugerencias por regla)
227
+ 4. Actualizar `README.md` — tabla de reglas
228
+ 5. Actualizar este `AGENTS.md` — tabla de reglas
229
+ 6. Commit: `feat(analyzer): add <rule-name> rule`
package/CHANGELOG.md ADDED
@@ -0,0 +1,105 @@
1
+ # Changelog
2
+
3
+ All notable changes to drift are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
+ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ---
9
+
10
+ ## [Unreleased]
11
+
12
+ ---
13
+
14
+ ## [0.4.0] — 2026-02-23
15
+
16
+ ### Added
17
+ - **Phase 2: cross-file dead code detection** — three new rules that require project-level import graph analysis (ESLint cannot do this by design — issue wontfix #371):
18
+ - `unused-export` (warning, weight 8): named exports that are never imported anywhere in the project.
19
+ - `dead-file` (warning, weight 10): source files that are never imported by any other file.
20
+ - `unused-dependency` (warning, weight 6): packages listed in `dependencies` in `package.json` that are never imported in source code.
21
+ - `analyzeProject()` now builds a cross-file import graph before per-file analysis, enabling project-level rules without additional dependencies.
22
+ - Fix suggestions for all three new rules in `src/printer.ts`.
23
+ - **Phase 3: structural architecture analysis**:
24
+ - `circular-dependency` (error, weight 14): detects circular import chains using DFS cycle detection. Reports the full cycle path as `A → B → C → A`.
25
+ - `layer-violation` (error, weight 16): flags imports that violate declared architectural layers. Requires `drift.config.ts`.
26
+ - `cross-boundary-import` (warning, weight 10): flags imports across module boundaries outside allowed paths. Requires `drift.config.ts`.
27
+ - `loadConfig()` — new async config loader in `src/config.ts`. Discovers `drift.config.ts / .js / .json` at project root. All rules except `layer-violation` and `cross-boundary-import` work without any config.
28
+ - `DriftConfig`, `LayerDefinition`, `ModuleBoundary` types exported from the package.
29
+ - Fix suggestions for all Phase 3 rules in `src/printer.ts`.
30
+ - **Phase 4: `drift diff` — historical comparison**:
31
+ - `drift diff [ref]` command: compare current project state against any git ref (commit, branch, tag). Default ref: `HEAD~1`.
32
+ - Uses `git show <ref>:<file>` for non-destructive extraction — no checkout, no stash, no repo state changes.
33
+ - Detects new issues introduced and issues resolved per file.
34
+ - Shows score delta per file and overall (`+N` red = regression, `-N` green = improvement).
35
+ - `--json` flag outputs raw `DriftDiff` JSON for CI consumption.
36
+ - New types `DriftDiff` and `FileDiff` exported from the package.
37
+ - New `computeDiff()` function exported for programmatic use.
38
+
39
+ ---
40
+
41
+ ## [0.3.0]
42
+
43
+ ### Added
44
+ - `--ai` flag: outputs LLM-optimized JSON (`AIOutput`) designed to be pasted directly into Claude, GPT, or any other model as context. Issues are ranked by severity and effort — quick wins first. Each issue includes `fix_suggestion` and `effort` level. The output includes `recommended_action` generated from the scan.
45
+ - `--fix` flag: shows inline fix suggestions in the console for each detected issue, rendered as a visual diff block.
46
+
47
+ ### Changed
48
+ - `formatAIOutput()` added to `reporter.ts` — produces the `AIOutput` structure with `summary`, `priority_order`, and `context_for_ai`.
49
+
50
+ ---
51
+
52
+ ## [0.2.3]
53
+
54
+ ### Fixed
55
+ - `npx @eduardbar/drift` now works correctly on Windows. The issue was that Node.js on Windows does not execute the shebang (`#!/usr/bin/env node`) in ES module `.js` files reliably. Added `bin/drift.js` as a thin wrapper with a dynamic `import()` that works cross-platform.
56
+
57
+ ---
58
+
59
+ ## [0.2.2]
60
+
61
+ ### Fixed
62
+ - CI workflow was triggering a double publish on the same release. Removed the duplicate `push: tags` trigger — now uses only `release: published`. Added a guard step that checks `npm view @eduardbar/drift@$VERSION` before publishing to skip if already published.
63
+
64
+ ### Refactored
65
+ - `formatMarkdown()` in `reporter.ts` split into smaller helper functions for readability.
66
+
67
+ ---
68
+
69
+ ## [0.2.1]
70
+
71
+ ### Added
72
+ - `drift-ignore` comment support: add `// drift-ignore` on a line (or the line above it) to suppress that specific issue.
73
+ - `drift-ignore-file` comment support: add `// drift-ignore-file` in the first 10 lines of a file to exclude the entire file from analysis. Used in `printer.ts` itself — its `console.log` calls are intentional CLI output, not debug leftovers.
74
+
75
+ ### Fixed
76
+ - drift was reporting issues in its own `printer.ts` when run on itself. Fixed by adding `// drift-ignore-file` to that file.
77
+
78
+ ---
79
+
80
+ ## [0.2.0]
81
+
82
+ ### Added
83
+ - ASCII score bar in console output (`█████████████░░░░░░░ 67/100`).
84
+ - Executive summary header with total file count, error/warning/info counts, and top issues.
85
+ - File count shown after scan completes.
86
+ - `scoreToGrade`, `severityIcon`, and `scoreBar` extracted to `src/utils.ts` — shared between printer and reporter.
87
+
88
+ ### Changed
89
+ - Console output restructured with cleaner visual hierarchy.
90
+
91
+ ---
92
+
93
+ ## [0.1.0]
94
+
95
+ ### Added
96
+ - Initial release.
97
+ - AST analysis engine using ts-morph.
98
+ - 8 detection rules: `large-file`, `large-function`, `debug-leftover`, `dead-code`, `duplicate-function-name`, `any-abuse`, `catch-swallow`, `no-return-type`.
99
+ - Score 0–100 per file and per project (average).
100
+ - Console printer with color output using kleur.
101
+ - Markdown reporter (`--output`).
102
+ - Raw JSON output (`--json`).
103
+ - CI integration via `--min-score` (exit code 1 if score exceeds threshold).
104
+ - CLI entry point with Commander.js.
105
+ - GitHub Actions workflow for automated npm publish on release.
@@ -0,0 +1,30 @@
1
+ # Code of Conduct
2
+
3
+ ## Our Commitment
4
+
5
+ drift is a technical project. We keep discussion focused on code, architecture, and technical debt patterns.
6
+
7
+ Everyone who participates — through issues, PRs, discussions, or comments — is expected to:
8
+
9
+ - Be direct and specific. Vague complaints don't help anyone.
10
+ - Criticize ideas, not people.
11
+ - Provide actionable feedback when rejecting a PR or issue.
12
+ - Assume good intent by default.
13
+
14
+ ## What we don't tolerate
15
+
16
+ - Personal attacks, insults, or harassment of any kind.
17
+ - Dismissing contributions without explanation.
18
+ - Spam, self-promotion unrelated to drift, or off-topic debates.
19
+
20
+ ## Scope
21
+
22
+ This applies in all project spaces: GitHub Issues, Pull Requests, Discussions, and any other channel where drift is represented.
23
+
24
+ ## Enforcement
25
+
26
+ Violations can be reported to [ing.eduardbarrera@gmail.com](mailto:ing.eduardbarrera@gmail.com). All reports will be reviewed and responded to. Maintainers have final say on enforcement decisions.
27
+
28
+ ## Note
29
+
30
+ This project does not adopt any third-party code of conduct document verbatim. These are our own rules, written to be simple and enforceable.
@@ -0,0 +1,125 @@
1
+ # Contributing to drift
2
+
3
+ Thanks for taking the time. drift exists because ESLint solves correctness and SonarQube solves enterprise complexity — but nobody solved the middle: code that compiles, passes linting, and quietly accumulates into a codebase no one can maintain six months later.
4
+
5
+ Every rule in drift was added because real developers kept finding the same pattern in AI-generated code and had no automated way to catch it. That's the contribution model: you see something repeatedly, you open an issue, we add a rule.
6
+
7
+ **The gap drift fills:**
8
+
9
+ | Tool | What it catches | What it misses |
10
+ |------|-----------------|----------------|
11
+ | ESLint | Correctness, style, per-file patterns | Cross-file dead code, architecture violations, complexity trends |
12
+ | SonarQube | Enterprise security, deep complexity | Lightweight, fast, free for small teams |
13
+ | knip | Unused exports and files | Structural health, AI-specific patterns, score |
14
+ | **drift** | Structural debt, AI patterns, cross-file analysis, score | Style, correctness (intentionally) |
15
+
16
+ ## How to contribute
17
+
18
+ ### Report a bug
19
+
20
+ Open an issue using the **Bug Report** template. Include:
21
+ - The command you ran
22
+ - What you expected vs what happened
23
+ - Your Node.js version and OS
24
+
25
+ ### Suggest a new rule
26
+
27
+ This is the most valuable contribution. If you keep seeing a specific AI-generated pattern that drift doesn't catch yet, open an issue using the **Rule Request** template with:
28
+ - A short description of the pattern
29
+ - A real code snippet that triggers it (anonymized is fine)
30
+ - Why it's harmful or a sign of AI-generated debt
31
+
32
+ ### Submit a PR
33
+
34
+ ```bash
35
+ # 1. Fork and clone
36
+ git clone https://github.com/eduardbar/drift
37
+ cd drift
38
+
39
+ # 2. Install dependencies
40
+ npm install
41
+
42
+ # 3. Build
43
+ npm run build
44
+
45
+ # 4. Create a branch
46
+ git checkout -b feat/rule-name
47
+ # or
48
+ git checkout -b fix/issue-description
49
+ ```
50
+
51
+ #### Adding a new rule
52
+
53
+ 1. Add the rule weight in `RULE_WEIGHTS` in `src/analyzer.ts`:
54
+ ```typescript
55
+ const RULE_WEIGHTS: Record<string, number> = {
56
+ 'your-rule-name': 10, // weight between 1 and 20
57
+ }
58
+ ```
59
+
60
+ 2. Implement the detection logic in `analyzeFile()` using ts-morph AST traversal.
61
+
62
+ 3. Add a fix suggestion in `src/printer.ts`:
63
+ ```typescript
64
+ const FIX_SUGGESTIONS: Record<string, string[]> = {
65
+ 'your-rule-name': [
66
+ 'First suggestion',
67
+ 'Alternative suggestion',
68
+ ],
69
+ }
70
+ ```
71
+
72
+ 4. Update the rules table in `README.md`.
73
+
74
+ 5. Run drift on itself to make sure nothing breaks:
75
+ ```bash
76
+ node dist/cli.js scan ./src
77
+ ```
78
+
79
+ 6. Open a PR with a clear description of what the rule detects and why it matters.
80
+
81
+ #### Commit convention
82
+
83
+ This project follows [Conventional Commits](https://www.conventionalcommits.org/):
84
+
85
+ ```
86
+ feat(analyzer): add high-complexity rule for cyclomatic detection
87
+ fix(printer): align snippet indentation for long file paths
88
+ docs(readme): add rule description for deep-nesting
89
+ ```
90
+
91
+ Types: `feat`, `fix`, `refactor`, `perf`, `docs`, `chore`, `ci`, `test`
92
+
93
+ ### What makes a good rule
94
+
95
+ A good drift rule:
96
+ - Detects a **specific, reproducible** pattern — not a matter of style preference
97
+ - Has a **measurable signal** that AI tools leave this more than humans do
98
+ - Is **false-positive resistant** — it should almost never fire on intentional code
99
+ - Can be **ignored with `// drift-ignore`** when the pattern is intentional
100
+
101
+ ### What drift is NOT
102
+
103
+ drift is not a linter for style or correctness. That's ESLint's job and it does it well. drift does not replace ESLint — it runs alongside it.
104
+
105
+ drift detects patterns that are:
106
+ - Syntactically correct and pass linting
107
+ - But accumulate into a codebase no one can maintain
108
+ - Specifically amplified by AI code generation tools
109
+
110
+ If your proposed rule overlaps with an existing ESLint rule (e.g. `no-unused-vars`, `complexity`, `no-empty`), it does not belong in drift — unless drift can do something ESLint fundamentally cannot (e.g. cross-file analysis, architectural context, project-wide scoring).
111
+
112
+ The test: *"Could ESLint catch this with a single-file rule?"* If yes, it's probably not a drift rule.
113
+
114
+ ## Development setup
115
+
116
+ ```bash
117
+ npm install # install dependencies
118
+ npm run build # compile TypeScript → dist/
119
+ npm run dev # watch mode
120
+ node dist/cli.js scan ./src # run on the project itself
121
+ ```
122
+
123
+ ## Questions?
124
+
125
+ Open a [Discussion](https://github.com/eduardbar/drift/discussions) — not an issue. Issues are for bugs and rule requests.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Eduard Barrera
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.