@eduardbar/drift 0.9.1 → 1.0.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 (68) hide show
  1. package/.github/workflows/publish-vscode.yml +76 -0
  2. package/AGENTS.md +30 -12
  3. package/README.md +1 -1
  4. package/ROADMAP.md +130 -98
  5. package/dist/analyzer.d.ts +4 -38
  6. package/dist/analyzer.js +85 -1543
  7. package/dist/cli.js +47 -4
  8. package/dist/config.js +1 -1
  9. package/dist/fix.d.ts +13 -0
  10. package/dist/fix.js +120 -0
  11. package/dist/git/blame.d.ts +22 -0
  12. package/dist/git/blame.js +227 -0
  13. package/dist/git/helpers.d.ts +36 -0
  14. package/dist/git/helpers.js +152 -0
  15. package/dist/git/trend.d.ts +21 -0
  16. package/dist/git/trend.js +80 -0
  17. package/dist/git.d.ts +0 -4
  18. package/dist/git.js +2 -2
  19. package/dist/report.js +620 -293
  20. package/dist/rules/phase0-basic.d.ts +11 -0
  21. package/dist/rules/phase0-basic.js +176 -0
  22. package/dist/rules/phase1-complexity.d.ts +31 -0
  23. package/dist/rules/phase1-complexity.js +277 -0
  24. package/dist/rules/phase2-crossfile.d.ts +27 -0
  25. package/dist/rules/phase2-crossfile.js +122 -0
  26. package/dist/rules/phase3-arch.d.ts +31 -0
  27. package/dist/rules/phase3-arch.js +148 -0
  28. package/dist/rules/phase5-ai.d.ts +8 -0
  29. package/dist/rules/phase5-ai.js +262 -0
  30. package/dist/rules/phase8-semantic.d.ts +22 -0
  31. package/dist/rules/phase8-semantic.js +109 -0
  32. package/dist/rules/shared.d.ts +7 -0
  33. package/dist/rules/shared.js +27 -0
  34. package/package.json +8 -3
  35. package/packages/vscode-drift/.vscodeignore +9 -0
  36. package/packages/vscode-drift/LICENSE +21 -0
  37. package/packages/vscode-drift/README.md +64 -0
  38. package/packages/vscode-drift/images/icon.png +0 -0
  39. package/packages/vscode-drift/images/icon.svg +30 -0
  40. package/packages/vscode-drift/package-lock.json +485 -0
  41. package/packages/vscode-drift/package.json +119 -0
  42. package/packages/vscode-drift/src/analyzer.ts +38 -0
  43. package/packages/vscode-drift/src/diagnostics.ts +55 -0
  44. package/packages/vscode-drift/src/extension.ts +111 -0
  45. package/packages/vscode-drift/src/statusbar.ts +47 -0
  46. package/packages/vscode-drift/src/treeview.ts +108 -0
  47. package/packages/vscode-drift/tsconfig.json +18 -0
  48. package/packages/vscode-drift/vscode-drift-0.1.0.vsix +0 -0
  49. package/packages/vscode-drift/vscode-drift-0.1.1.vsix +0 -0
  50. package/src/analyzer.ts +124 -1773
  51. package/src/cli.ts +53 -4
  52. package/src/config.ts +1 -1
  53. package/src/fix.ts +154 -0
  54. package/src/git/blame.ts +279 -0
  55. package/src/git/helpers.ts +198 -0
  56. package/src/git/trend.ts +116 -0
  57. package/src/git.ts +2 -2
  58. package/src/report.ts +631 -296
  59. package/src/rules/phase0-basic.ts +187 -0
  60. package/src/rules/phase1-complexity.ts +302 -0
  61. package/src/rules/phase2-crossfile.ts +149 -0
  62. package/src/rules/phase3-arch.ts +179 -0
  63. package/src/rules/phase5-ai.ts +292 -0
  64. package/src/rules/phase8-semantic.ts +132 -0
  65. package/src/rules/shared.ts +39 -0
  66. package/tests/helpers.ts +45 -0
  67. package/tests/rules.test.ts +1269 -0
  68. package/vitest.config.ts +15 -0
@@ -0,0 +1,76 @@
1
+ name: Publish VS Code Extension
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+ inputs:
8
+ version:
9
+ description: 'Version to publish (e.g. 0.1.1)'
10
+ required: true
11
+ type: string
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ publish:
18
+ runs-on: ubuntu-latest
19
+ defaults:
20
+ run:
21
+ working-directory: packages/vscode-drift
22
+
23
+ steps:
24
+ - name: Checkout
25
+ uses: actions/checkout@v4
26
+ with:
27
+ ref: ${{ github.event_name == 'release' && github.ref || github.event.repository.default_branch }}
28
+
29
+ - name: Setup Node.js
30
+ uses: actions/setup-node@v4
31
+ with:
32
+ node-version: '20'
33
+ cache: 'npm'
34
+ cache-dependency-path: packages/vscode-drift/package-lock.json
35
+
36
+ - name: Verify version matches tag
37
+ if: github.event_name == 'release'
38
+ run: |
39
+ if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
40
+ TAG_VERSION="${{ inputs.version }}"
41
+ else
42
+ TAG_VERSION="${GITHUB_REF#refs/tags/v}"
43
+ fi
44
+ PKG_VERSION=$(node -p "require('./package.json').version")
45
+ if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
46
+ echo "Error: Tag version ($TAG_VERSION) does not match package.json version ($PKG_VERSION)"
47
+ exit 1
48
+ fi
49
+ echo "Version check passed: $PKG_VERSION"
50
+
51
+ - name: Check if version already published
52
+ run: |
53
+ PKG_VERSION=$(node -p "require('./package.json').version")
54
+ PUBLISHED=$(npx @vscode/vsce show eduardbar.vscode-drift 2>&1 | grep "Version:" | awk '{print $2}' || echo "none")
55
+ if [ "$PUBLISHED" = "$PKG_VERSION" ]; then
56
+ echo "Version $PKG_VERSION already published on Marketplace. Skipping."
57
+ echo "skip_publish=true" >> $GITHUB_ENV
58
+ fi
59
+
60
+ - name: Install dependencies
61
+ if: env.skip_publish != 'true'
62
+ run: npm ci
63
+
64
+ - name: Build extension
65
+ if: env.skip_publish != 'true'
66
+ run: npm run build
67
+
68
+ - name: Package extension
69
+ if: env.skip_publish != 'true'
70
+ run: npx @vscode/vsce package --no-dependencies
71
+
72
+ - name: Publish to VS Code Marketplace
73
+ if: env.skip_publish != 'true'
74
+ run: npx @vscode/vsce publish --no-dependencies
75
+ env:
76
+ VSCE_PAT: ${{ secrets.VSCE_PAT }}
package/AGENTS.md CHANGED
@@ -88,18 +88,35 @@ npx @eduardbar/drift scan ./src -o report.md # exportar Markdown
88
88
 
89
89
  ## Reglas del analyzer
90
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) |
91
+ | Regla | Severidad | Peso |
92
+ |-------|-----------|------|
93
+ | `large-file` | error | 20 |
94
+ | `large-function` | error | 15 |
95
+ | `duplicate-function-name` | error | 18 |
96
+ | `high-complexity` | error | 15 |
97
+ | `circular-dependency` | error | 14 |
98
+ | `layer-violation` | error | 16 |
99
+ | `comment-contradiction` | warning | 12 |
100
+ | `deep-nesting` | warning | 12 |
101
+ | `semantic-duplication` | warning | 12 |
102
+ | `debug-leftover` | warning | 10 |
103
+ | `catch-swallow` | warning | 10 |
104
+ | `high-coupling` | warning | 10 |
105
+ | `dead-file` | warning | 10 |
106
+ | `hardcoded-config` | warning | 10 |
107
+ | `cross-boundary-import` | warning | 10 |
108
+ | `dead-code` | warning | 8 |
109
+ | `any-abuse` | warning | 8 |
110
+ | `too-many-params` | warning | 8 |
111
+ | `unused-export` | warning | 8 |
112
+ | `inconsistent-error-handling` | warning | 8 |
113
+ | `promise-style-mix` | warning | 7 |
114
+ | `unnecessary-abstraction` | warning | 7 |
115
+ | `naming-inconsistency` | warning | 6 |
116
+ | `unused-dependency` | warning | 6 |
117
+ | `no-return-type` | info | 5 |
118
+ | `over-commented` | info | 4 |
119
+ | `magic-number` | info | 3 |
103
120
 
104
121
  **Score = suma de pesos capped a 100. Score del proyecto = promedio de archivos.**
105
122
 
@@ -199,6 +216,7 @@ Sin esto, Windows no ejecuta el shebang correctamente con ES modules.
199
216
 
200
217
  | Versión | Cambios principales |
201
218
  |---------|---------------------|
219
+ | **1.0.0** | 26 reglas, 131 tests, modular rules, JS/JSX, drift fix/report/diff/ci/badge/trend/blame, VS Code extension |
202
220
  | **0.3.0** | `--ai` (LLM-optimized JSON output) + `--fix` (inline suggestions) |
203
221
  | **0.2.3** | Fix: bin wrapper para compatibilidad Windows npx |
204
222
  | **0.2.2** | Refactor: `formatMarkdown` dividido en helpers + fix CI doble publish |
package/README.md CHANGED
@@ -418,7 +418,7 @@ See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) before participating.
418
418
  | [`commander`](https://github.com/tj/commander.js) | CLI commands and flags |
419
419
  | [`kleur`](https://github.com/lukeed/kleur) | Terminal colors (zero dependencies) |
420
420
 
421
- **Runtime:** Node.js 18+ · TypeScript 5.x · ES Modules
421
+ **Runtime:** Node.js 18+ · TypeScript 5.x · ES Modules · Supports TypeScript (`.ts`, `.tsx`) and JavaScript (`.js`, `.jsx`) files
422
422
 
423
423
  ---
424
424
 
package/ROADMAP.md CHANGED
@@ -42,165 +42,197 @@ drift's goal is to be the tool that sits between ESLint and SonarQube — lightw
42
42
 
43
43
  ---
44
44
 
45
- ## What's already done
45
+ ## Completed phases
46
46
 
47
- - AST analysis with ts-morph 10 detection rules
48
- - Score 0–100 per file and project
49
- - `--json`, `--ai` (LLM-optimized output), `--fix` (inline suggestions)
50
- - `--min-score` for CI (exit 1 if score exceeds threshold)
51
- - `drift-ignore` per line and per file
52
- - Windows / Linux / macOS compatible via `npx`
47
+ ### Phase 0 Basic rules `v0.1.0`
53
48
 
54
- ---
49
+ Foundation: AST analysis with ts-morph, score 0–100, `--json`, `--ai`, `--fix`, `--min-score`, `drift-ignore` per line and per file, Windows / Linux / macOS compatible via `npx`.
55
50
 
56
- ## What's next
51
+ **Rules shipped:**
57
52
 
58
- Ordered by real developer pain most common complaint first.
53
+ | Rule | Severity | Weight |
54
+ |------|----------|--------|
55
+ | `large-file` | error | 20 |
56
+ | `large-function` | error | 15 |
57
+ | `duplicate-function-name` | error | 18 |
58
+ | `debug-leftover` | warning | 10 |
59
+ | `dead-code` | warning | 8 |
60
+ | `any-abuse` | warning | 8 |
61
+ | `catch-swallow` | warning | 10 |
62
+ | `no-return-type` | info | 5 |
59
63
 
60
64
  ---
61
65
 
62
- ### 1. Complexity detection
66
+ ### Phase 1 Complexity detection `v0.2.0` ✅
63
67
 
64
- > *"AI generates a nuclear option for a problem that needed a screwdriver."*
65
- > — Hacker News
68
+ ESLint measures cyclomatic complexity per branch. drift measures cognitive load how hard code is to *understand*. AI generates correct code, not simple code.
66
69
 
67
- > *"One of my devs implemented a batching process. He presented extremely robust, high-quality code. The problem was that it was MASSIVE overkill."*
68
- > — Hacker News, r/ExperiencedDevs
70
+ **Rules shipped:**
69
71
 
70
- ESLint has a `complexity` rule. It measures cyclomatic complexity — the number of branches. That's not the same as cognitive complexity — how hard it is to *understand*. Biome has `noExcessiveCognitiveComplexity`. Neither gives you a score.
72
+ | Rule | Severity | Weight |
73
+ |------|----------|--------|
74
+ | `high-complexity` | error | 15 |
75
+ | `deep-nesting` | warning | 12 |
76
+ | `too-many-params` | warning | 8 |
77
+ | `high-coupling` | warning | 10 |
78
+ | `promise-style-mix` | warning | 7 |
79
+ | `magic-number` | info | 3 |
80
+ | `comment-contradiction` | warning | 12 |
71
81
 
72
- **Planned rules:**
73
- - `high-complexity` — cyclomatic complexity > 10 per function
74
- - `deep-nesting` — nesting depth > 3 levels (if inside if inside for inside try = unreadable)
75
- - `too-many-params` — functions with more than 4 parameters (AI doesn't refactor into objects)
76
- - `high-coupling` — files importing more than 10 distinct modules
77
- - `promise-style-mix` — `async/await` and `.then()` mixed in the same file
82
+ ---
78
83
 
79
- **Why this matters:** Complexity is the #1 reason codebases become write-only. AI generates correct code. Not simple code.
84
+ ### Phase 2 Cross-file dead code `v0.3.0`
80
85
 
81
- ---
86
+ ESLint detects unused variables inside a file. It cannot detect unused exports, dead files, or dead modules across a project — this is a fundamental architectural limitation (typescript-eslint issue #371, marked `wontfix`). drift builds a full import graph.
82
87
 
83
- ### 2. Cross-file dead code detection
88
+ **Rules shipped:**
84
89
 
85
- > *"After integrating Knip I removed around 3,500 lines of dead code at once."*
86
- > — dev.to
90
+ | Rule | Severity | What it detects |
91
+ |------|----------|-----------------|
92
+ | `unused-export` | warning | Exported symbol never imported anywhere in the project |
93
+ | `dead-file` | warning | File never imported by anything |
94
+ | `unused-dependency` | warning | Package in `package.json` with zero imports in the codebase |
87
95
 
88
- > *"ESLint's architecture works on a file-by-file basis and was never intended to provide linting based on project-wide usage stats."*
89
- > — typescript-eslint issue #371, marked **wontfix**
96
+ ---
97
+
98
+ ### Phase 3 — Architectural boundaries `v0.4.0` ✅
90
99
 
91
- ESLint detects unused variables *inside a file*. It cannot detect unused exports, unused files, or dead modules across the project. This is a fundamental architectural limitation not a missing rule.
100
+ Architecture violations are invisible until they're catastrophic. ESLint can validate import paths with `no-restricted-imports`. It cannot tell you if your UI layer is importing directly from your database layer, or if your domain logic has dependencies on your HTTP framework. AI generates code that works today and breaks your architecture silently.
92
101
 
93
- **Planned features:**
94
- - `unused-export` — exported symbol never imported anywhere in the project
95
- - `dead-file` — file never imported by anything
96
- - `unused-dependency` — package in `package.json` with zero imports in the codebase
102
+ **Rules shipped:**
97
103
 
98
- **Why this matters:** Dead code is cognitive overhead. Every unused export is a trap for the next developer. ESLint will never fix this — the `wontfix` label is permanent.
104
+ | Rule | Severity | What it detects |
105
+ |------|----------|-----------------|
106
+ | `circular-dependency` | error | Module A depends on B which depends on A |
107
+ | `layer-violation` | error | Import from a prohibited architectural layer |
108
+ | `cross-boundary-import` | warning | Module outside its domain importing from another domain |
99
109
 
100
110
  ---
101
111
 
102
- ### 3. Architectural boundary detection
112
+ ### Phase 5 AI authorship heuristics `v0.6.0` ✅
103
113
 
104
- > *"AI coding tools keep breaking architecture so I built a guard layer."*
105
- > — Reddit, r/javascript
114
+ Patterns that are statistically more common in AI-generated code than human-written code. These don't fail tests. ESLint doesn't catch them. They accumulate until the codebase is unmaintainable.
106
115
 
107
- This is the largest unaddressed gap in the ecosystem. ESLint can validate import paths with `no-restricted-imports`. It cannot tell you if your UI layer is importing directly from your database layer, or if your domain logic has dependencies on your HTTP framework.
116
+ **Rules shipped:**
108
117
 
109
- **Planned rules:**
110
- - `circular-dependency` — module A depends on B which depends on A
111
- - `layer-violation` import from a prohibited architectural layer
112
- - `cross-boundary-import` module outside its domain importing from another domain
118
+ | Rule | Severity | What it detects |
119
+ |------|----------|-----------------|
120
+ | `hardcoded-config` | warning | URLs, tokens, or env-specific paths hardcoded in logic |
121
+ | `inconsistent-error-handling` | warning | Different error handling patterns in equivalent functions |
122
+ | `unnecessary-abstraction` | warning | Class or interface used in exactly one place |
123
+ | `naming-inconsistency` | warning | Mixed naming conventions in the same module |
124
+ | `over-commented` | info | Comments that describe exactly what the code already says |
113
125
 
114
- Zero config by default — drift infers what it can from the import graph. For teams that want explicit enforcement:
126
+ ---
115
127
 
116
- ```ts
117
- // drift.config.ts — optional
118
- export default {
119
- boundaries: {
120
- layers: ['ui', 'domain', 'infrastructure'],
121
- rules: [{ from: 'ui', allow: ['domain'] }]
122
- }
123
- }
124
- ```
128
+ ### Phase 8 — Semantic duplication `v0.7.0` ✅
125
129
 
126
- **Why this matters:** Architecture violations are invisible until they're catastrophic. AI generates code that works today and breaks your architecture silently.
130
+ AI doesn't reuse it regenerates. The same logic appears in 4 different forms across the same file. Text-comparison is what grep does. drift uses AST fingerprinting for Type-2 clone detection: structurally equivalent code regardless of variable names.
127
131
 
128
- ---
132
+ **Rules shipped:**
129
133
 
130
- ### 4. Historical drift (`drift diff` / `drift trend`)
134
+ | Rule | Severity | What it detects |
135
+ |------|----------|-----------------|
136
+ | `semantic-duplication` | warning | Code blocks with equivalent logic via AST fingerprinting |
131
137
 
132
- > *"Zero visibility on whether we're actually improving."*
133
- > — Reddit, r/devsecops
138
+ ---
134
139
 
135
- The current score matters. The trend matters more. Is your codebase getting better or worse sprint over sprint? Nobody knows — because no tool measures it in a way that's easy to track.
140
+ ### Phase 4 Historical analysis `v0.9.0`
136
141
 
137
- **Planned commands:**
138
- - `drift diff HEAD~N` — what got worse between two commits
139
- - `drift trend --commits 30` — ASCII chart of score evolution over time
140
- - `drift blame` — which commits introduced the most debt
142
+ A score of 45 means nothing without context. A score that went from 80 to 45 over 4 sprints means your team is actually improving. No database. No server. Git is the source of truth.
141
143
 
142
- No database. No server. Git is the source of truth.
144
+ **Commands shipped:**
145
+ - `drift trend` — linear regression over project history with uniform sampling of 10 points
146
+ - `drift blame` — debt attribution by author via git blame
143
147
 
144
- **Why this matters:** A score of 45 means nothing without context. A score that went from 80 to 45 over 4 sprints means your team is actually improving.
148
+ **v0.9.1 fix:** Full project snapshot per commit, uniform 10-point sampling for consistent trend lines.
145
149
 
146
150
  ---
147
151
 
148
- ### 5. AI authorship heuristics
152
+ ## Current state February 2026
149
153
 
150
- > *"Companies will try to overcome AI-generated technical debt by throwing more AI at the problem."*
151
- > Hacker News
154
+ - **26 rules active** across 9 detection categories
155
+ - **Self-scan score: 14/100 (LOW)**
156
+ - Published on npm as `@eduardbar/drift` — MIT, always free
157
+ - Cross-platform: Windows / Linux / macOS via `npx`
152
158
 
153
- > *"When 95% of code is projected to be AI-generated by 2030 but 45% of it fails basic security tests, we're building a house of cards."*
154
- > — Reddit, r/vibecoding
159
+ ---
155
160
 
156
- The hardest and most differentiated item on this list. Patterns that are statistically more common in AI-generated code than human-written code.
161
+ ## Path to v1.0.0
157
162
 
158
- **Planned rules:**
159
- - `over-commented` — comments that describe exactly what the code already says (AI documents the obvious)
160
- - `unnecessary-abstraction` — class or interface used in exactly one place (AI loves creating things it doesn't use)
161
- - `hardcoded-config` — strings that look like URLs, tokens, or environment-specific paths hardcoded in logic
162
- - `inconsistent-error-handling` — different error handling patterns in equivalent functions across the same file
163
+ ### Unit test suite ✅
163
164
 
164
- **Why this matters:** These patterns don't fail tests. ESLint doesn't catch them. They accumulate until the codebase is unmaintainable.
165
+ **Status:** complete
166
+ **Target:** vitest suite covering all 26 rules
167
+
168
+ Every rule needs at minimum: one test with a fixture that triggers the rule, one test with a fixture that doesn't. No rule ships without a test from v1.0.0 onward.
165
169
 
166
170
  ---
167
171
 
168
- ### 6. Static HTML report + README badge
172
+ ### Modular refactor
173
+
174
+ **Status:** complete
175
+ **Target:** split `analyzer.ts` into `src/rules/*` and `src/git/*`
176
+
177
+ ```
178
+ src/
179
+ ├── rules/
180
+ │ ├── phase0*.ts
181
+ │ ├── phase1*.ts
182
+ │ ├── phase2*.ts
183
+ │ ├── phase3*.ts
184
+ │ ├── phase5*.ts
185
+ │ └── phase8*.ts
186
+ ├── git/
187
+ │ ├── trend.ts
188
+ │ └── blame.ts
189
+ ├── analyzer.ts ← orchestrator only, no rule logic
190
+ └── ...
191
+ ```
169
192
 
170
- > *"It's all disconnected — different dashboards, zero visibility."*
171
- > — Reddit, r/devsecops
193
+ ---
172
194
 
173
- No server. No account. No cloud.
195
+ ### JavaScript / JSX support
174
196
 
175
- **Planned features:**
176
- - `drift report`single self-contained `drift-report.html`, open in any browser
177
- - `drift badge` — `badge.svg` with the current score for your README
178
- - `drift ci` — GitHub Actions annotations on the exact lines with issues (inline in the PR diff)
197
+ **Status:** complete
198
+ **Target:** ts-morph can parse JS extend scan to `.js` and `.jsx` files
179
199
 
180
200
  ---
181
201
 
182
- ### 7. ESLint plugin
202
+ ### VS Code extension ✅
203
+
204
+ **Status:** complete
205
+ **Target:** extension that shows inline warnings directly in the editor
183
206
 
184
- Meet developers where they already are.
207
+ Published as `eduardbar.vscode-drift` v0.1.1.
185
208
 
186
- - `eslint-plugin-drift` — exposes drift's rules as standard ESLint rules
187
- - Compatible with ESLint 9 flat config
188
- - The CLI remains canonical — the plugin is an integration path for teams already deep in ESLint
209
+ ---
189
210
 
190
- **Why this matters:** Not everyone will install a new CLI. An ESLint plugin removes all friction and puts drift's rules into a toolchain devs already trust.
211
+ ### `drift fix` automated corrections
212
+
213
+ **Status:** complete
214
+ **Target:** automatic application of simple fixes for low-effort rules
191
215
 
192
216
  ---
193
217
 
194
- ### 8. Pattern inconsistency detection
218
+ ### Interactive HTML report
195
219
 
196
- > *"8x increase in duplicated code blocks with AI tools."*
197
- > GitClear
220
+ **Status:** complete
221
+ **Target:** `drift report` command generates a self-contained `drift-report.html`
198
222
 
199
- AI doesn't reuse — it regenerates. The same logic appears in 4 different forms across the same file.
223
+ ---
200
224
 
201
- **Planned rules:**
202
- - `semantic-duplication` — code blocks with equivalent logic detected via AST fingerprinting (not text comparison — that's what grep does)
203
- - `naming-inconsistency` mixed naming conventions in the same module (camelCase + snake_case + PascalCase for the same concept)
225
+ ## v1.0.0 — Stable Release ✅
226
+
227
+ - [x] 26 detection rules across 6 phases
228
+ - [x] Full test coverage: 131 tests, all passing
229
+ - [x] Modular rule architecture: `src/rules/phase{0,1,2,3,5,8}*.ts`
230
+ - [x] JS/JSX support
231
+ - [x] `drift fix` auto-fix command
232
+ - [x] `drift report` HTML interactive report
233
+ - [x] `drift diff`, `drift ci`, `drift badge`, `drift trend`, `drift blame`
234
+ - [x] VS Code extension published (eduardbar.vscode-drift v0.1.1)
235
+ - [x] Self-scan score: 18/100 (LOW)
204
236
 
205
237
  ---
206
238
 
@@ -1,44 +1,10 @@
1
- import { SourceFile } from 'ts-morph';
2
- import type { DriftIssue, FileReport, DriftConfig, TrendDataPoint, BlameAttribution, DriftTrendReport, DriftBlameReport } from './types.js';
1
+ import type { DriftIssue, FileReport, DriftConfig } from './types.js';
2
+ export { TrendAnalyzer } from './git/trend.js';
3
+ export { BlameAnalyzer } from './git/blame.js';
3
4
  export declare const RULE_WEIGHTS: Record<string, {
4
5
  severity: DriftIssue['severity'];
5
6
  weight: number;
6
7
  }>;
7
- export declare function analyzeFile(file: SourceFile): FileReport;
8
+ export declare function analyzeFile(file: import('ts-morph').SourceFile): FileReport;
8
9
  export declare function analyzeProject(targetPath: string, config?: DriftConfig): FileReport[];
9
- export declare class TrendAnalyzer {
10
- private readonly projectPath;
11
- private readonly config;
12
- constructor(projectPath: string, config?: DriftConfig);
13
- static calculateMovingAverage(data: TrendDataPoint[], windowSize: number): number[];
14
- static linearRegression(data: TrendDataPoint[]): {
15
- slope: number;
16
- intercept: number;
17
- r2: number;
18
- };
19
- /** Generate a simple horizontal ASCII bar chart (one bar per data point). */
20
- static generateTrendChart(data: TrendDataPoint[]): string;
21
- analyzeTrend(options: {
22
- period?: 'week' | 'month' | 'quarter' | 'year';
23
- since?: string;
24
- until?: string;
25
- }): Promise<DriftTrendReport>;
26
- }
27
- export declare class BlameAnalyzer {
28
- private readonly projectPath;
29
- private readonly config;
30
- constructor(projectPath: string, config?: DriftConfig);
31
- /** Blame a single file: returns per-author attribution. */
32
- static analyzeFileBlame(filePath: string): Promise<BlameAttribution[]>;
33
- /** Blame for a specific rule across all files in targetPath. */
34
- static analyzeRuleBlame(rule: string, targetPath: string): Promise<BlameAttribution[]>;
35
- /** Overall blame across all files and rules. */
36
- static analyzeOverallBlame(targetPath: string): Promise<BlameAttribution[]>;
37
- analyzeBlame(options: {
38
- target?: 'file' | 'rule' | 'overall';
39
- top?: number;
40
- filePath?: string;
41
- rule?: string;
42
- }): Promise<DriftBlameReport>;
43
- }
44
10
  //# sourceMappingURL=analyzer.d.ts.map