@eduardbar/drift 1.1.0 → 1.3.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 (66) hide show
  1. package/.github/workflows/publish-vscode.yml +3 -3
  2. package/.github/workflows/publish.yml +3 -3
  3. package/.github/workflows/review-pr.yml +153 -0
  4. package/AGENTS.md +6 -0
  5. package/README.md +192 -4
  6. package/ROADMAP.md +6 -5
  7. package/dist/analyzer.d.ts +2 -2
  8. package/dist/analyzer.js +420 -159
  9. package/dist/benchmark.d.ts +2 -0
  10. package/dist/benchmark.js +185 -0
  11. package/dist/cli.js +509 -23
  12. package/dist/diff.js +74 -10
  13. package/dist/git.js +12 -0
  14. package/dist/index.d.ts +5 -1
  15. package/dist/index.js +3 -0
  16. package/dist/map.d.ts +3 -2
  17. package/dist/map.js +98 -10
  18. package/dist/plugins.d.ts +2 -1
  19. package/dist/plugins.js +177 -28
  20. package/dist/printer.js +4 -0
  21. package/dist/review.js +2 -2
  22. package/dist/rules/comments.js +2 -2
  23. package/dist/rules/complexity.js +2 -7
  24. package/dist/rules/nesting.js +3 -13
  25. package/dist/rules/phase0-basic.js +10 -10
  26. package/dist/rules/shared.d.ts +2 -0
  27. package/dist/rules/shared.js +27 -3
  28. package/dist/saas.d.ts +219 -0
  29. package/dist/saas.js +762 -0
  30. package/dist/trust-kpi.d.ts +9 -0
  31. package/dist/trust-kpi.js +445 -0
  32. package/dist/trust.d.ts +65 -0
  33. package/dist/trust.js +571 -0
  34. package/dist/types.d.ts +160 -0
  35. package/docs/PRD.md +199 -172
  36. package/docs/plugin-contract.md +61 -0
  37. package/docs/trust-core-release-checklist.md +55 -0
  38. package/package.json +5 -3
  39. package/packages/vscode-drift/src/code-actions.ts +53 -0
  40. package/packages/vscode-drift/src/extension.ts +11 -0
  41. package/src/analyzer.ts +484 -155
  42. package/src/benchmark.ts +244 -0
  43. package/src/cli.ts +628 -36
  44. package/src/diff.ts +75 -10
  45. package/src/git.ts +16 -0
  46. package/src/index.ts +63 -0
  47. package/src/map.ts +112 -10
  48. package/src/plugins.ts +354 -26
  49. package/src/printer.ts +4 -0
  50. package/src/review.ts +2 -2
  51. package/src/rules/comments.ts +2 -2
  52. package/src/rules/complexity.ts +2 -7
  53. package/src/rules/nesting.ts +3 -13
  54. package/src/rules/phase0-basic.ts +11 -12
  55. package/src/rules/shared.ts +31 -3
  56. package/src/saas.ts +1031 -0
  57. package/src/trust-kpi.ts +518 -0
  58. package/src/trust.ts +774 -0
  59. package/src/types.ts +177 -0
  60. package/tests/diff.test.ts +124 -0
  61. package/tests/new-features.test.ts +98 -0
  62. package/tests/plugins.test.ts +219 -0
  63. package/tests/rules.test.ts +23 -1
  64. package/tests/saas-foundation.test.ts +464 -0
  65. package/tests/trust-kpi.test.ts +120 -0
  66. package/tests/trust.test.ts +584 -0
@@ -24,14 +24,14 @@ jobs:
24
24
 
25
25
  steps:
26
26
  - name: Checkout
27
- uses: actions/checkout@v4
27
+ uses: actions/checkout@v5
28
28
  with:
29
29
  ref: ${{ github.event_name == 'release' && github.ref || github.event.repository.default_branch }}
30
30
 
31
31
  - name: Setup Node.js
32
- uses: actions/setup-node@v4
32
+ uses: actions/setup-node@v5
33
33
  with:
34
- node-version: '20'
34
+ node-version: '22'
35
35
  cache: 'npm'
36
36
  cache-dependency-path: packages/vscode-drift/package-lock.json
37
37
 
@@ -18,14 +18,14 @@ jobs:
18
18
  runs-on: ubuntu-latest
19
19
  steps:
20
20
  - name: Checkout
21
- uses: actions/checkout@v4
21
+ uses: actions/checkout@v5
22
22
  with:
23
23
  ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/v{0}', inputs.tag) || github.ref }}
24
24
 
25
25
  - name: Setup Node.js
26
- uses: actions/setup-node@v4
26
+ uses: actions/setup-node@v5
27
27
  with:
28
- node-version: '20'
28
+ node-version: '22'
29
29
  registry-url: 'https://registry.npmjs.org'
30
30
  cache: 'npm'
31
31
 
@@ -0,0 +1,153 @@
1
+ name: Drift PR Review
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, reopened]
6
+
7
+ permissions:
8
+ contents: read
9
+ pull-requests: write
10
+
11
+ jobs:
12
+ drift-review:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v5
17
+ with:
18
+ fetch-depth: 0
19
+
20
+ - name: Setup Node.js
21
+ uses: actions/setup-node@v5
22
+ with:
23
+ node-version: '22'
24
+ cache: 'npm'
25
+
26
+ - name: Install dependencies
27
+ run: npm ci
28
+
29
+ # Run directly from TypeScript source in this PR to avoid stale dist artifacts.
30
+ - name: Generate drift review markdown
31
+ run: npx --no-install tsx ./src/cli.ts review --base "origin/${{ github.base_ref }}" --comment > drift-review.md
32
+
33
+ - name: Generate drift trust markdown
34
+ run: npx --no-install tsx ./src/cli.ts trust . --base "origin/${{ github.base_ref }}" --markdown --json-output drift-trust.json > drift-trust.md
35
+
36
+ - name: Extract trust KPI values
37
+ id: trust_kpi
38
+ run: |
39
+ node --input-type=module -e "
40
+ import fs from 'node:fs'
41
+ const payload = JSON.parse(fs.readFileSync('drift-trust.json', 'utf8'))
42
+ const score = payload.trust_score ?? 'n/a'
43
+ const risk = payload.merge_risk ?? 'n/a'
44
+ const diff = payload.diff_context ?? {}
45
+ const newIssues = diff.newIssues ?? 'n/a'
46
+ const resolvedIssues = diff.resolvedIssues ?? 'n/a'
47
+ fs.appendFileSync(process.env.GITHUB_OUTPUT, [
48
+ 'trust_score=' + score,
49
+ 'merge_risk=' + risk,
50
+ 'new_issues=' + newIssues,
51
+ 'resolved_issues=' + resolvedIssues,
52
+ ].join('\\n') + '\\n')
53
+ "
54
+
55
+ - name: Publish trust KPI step summary
56
+ run: |
57
+ {
58
+ echo "## drift trust KPI"
59
+ echo
60
+ echo "- Trust score: **${{ steps.trust_kpi.outputs.trust_score }}**"
61
+ echo "- Merge risk: **${{ steps.trust_kpi.outputs.merge_risk }}**"
62
+ echo "- New issues vs base: **${{ steps.trust_kpi.outputs.new_issues }}**"
63
+ echo "- Resolved issues vs base: **${{ steps.trust_kpi.outputs.resolved_issues }}**"
64
+ } >> "$GITHUB_STEP_SUMMARY"
65
+
66
+ - name: Validate trust gate from generated JSON
67
+ run: |
68
+ set -euo pipefail
69
+ npx --no-install tsx ./src/cli.ts trust-gate drift-trust.json --min-trust 40 --max-risk HIGH | tee drift-trust-gate.txt
70
+
71
+ - name: Aggregate trust KPI from trust JSON artifact
72
+ run: npx --no-install tsx ./src/cli.ts kpi drift-trust.json --no-summary > drift-trust-kpi.json
73
+
74
+ - name: Extract aggregated KPI values
75
+ id: trust_kpi_aggregate
76
+ run: |
77
+ node --input-type=module -e "
78
+ import fs from 'node:fs'
79
+ const payload = JSON.parse(fs.readFileSync('drift-trust-kpi.json', 'utf8'))
80
+ const files = payload.files ?? {}
81
+ const trustScore = payload.trustScore ?? {}
82
+ const highRiskRatio = payload.highRiskRatio
83
+ fs.appendFileSync(process.env.GITHUB_OUTPUT, [
84
+ 'matched=' + (files.matched ?? 'n/a'),
85
+ 'parsed=' + (files.parsed ?? 'n/a'),
86
+ 'malformed=' + (files.malformed ?? 'n/a'),
87
+ 'prs=' + (payload.prsEvaluated ?? 'n/a'),
88
+ 'avg=' + (trustScore.average ?? 'n/a'),
89
+ 'high_risk_ratio=' + (highRiskRatio == null ? 'n/a' : Number(highRiskRatio * 100).toFixed(2) + '%'),
90
+ ].join('\\n') + '\\n')
91
+ "
92
+
93
+ - name: Publish trust KPI aggregate summary
94
+ run: |
95
+ {
96
+ echo
97
+ echo "## drift trust KPI aggregate"
98
+ echo
99
+ echo "- Files matched/parsed/malformed: **${{ steps.trust_kpi_aggregate.outputs.matched }} / ${{ steps.trust_kpi_aggregate.outputs.parsed }} / ${{ steps.trust_kpi_aggregate.outputs.malformed }}**"
100
+ echo "- PR samples evaluated: **${{ steps.trust_kpi_aggregate.outputs.prs }}**"
101
+ echo "- Aggregate trust score avg: **${{ steps.trust_kpi_aggregate.outputs.avg }}**"
102
+ echo "- High-risk ratio (HIGH+CRITICAL): **${{ steps.trust_kpi_aggregate.outputs.high_risk_ratio }}**"
103
+ } >> "$GITHUB_STEP_SUMMARY"
104
+
105
+ - name: Upload drift trust JSON artifact
106
+ uses: actions/upload-artifact@v4
107
+ with:
108
+ name: drift-trust-json-pr-${{ github.event.pull_request.number }}-run-${{ github.run_attempt }}
109
+ path: |
110
+ drift-trust.json
111
+ drift-trust-gate.txt
112
+ drift-trust-kpi.json
113
+ if-no-files-found: error
114
+ retention-days: 14
115
+
116
+ - name: Post or update PR comment (non-fork only)
117
+ if: github.event.pull_request.head.repo.fork == false
118
+ env:
119
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
120
+ PR_NUMBER: ${{ github.event.pull_request.number }}
121
+ REPO: ${{ github.repository }}
122
+ run: |
123
+ COMMENT_BODY="<!-- drift-review -->"
124
+ COMMENT_BODY+=$'\n'
125
+ COMMENT_BODY+="## drift trust"$'\n\n'
126
+ COMMENT_BODY+="$(cat drift-trust.md)"
127
+ COMMENT_BODY+=$'\n\n'
128
+ COMMENT_BODY+="## drift review"$'\n\n'
129
+ COMMENT_BODY+="$(cat drift-review.md)"
130
+ COMMENT_BODY+=$'\n\n'
131
+ COMMENT_BODY+="<!-- drift-trust-kpi score=${{ steps.trust_kpi.outputs.trust_score }} risk=${{ steps.trust_kpi.outputs.merge_risk }} new=${{ steps.trust_kpi.outputs.new_issues }} resolved=${{ steps.trust_kpi.outputs.resolved_issues }} -->"
132
+
133
+ EXISTING_ID=$(gh api "repos/$REPO/issues/$PR_NUMBER/comments" --jq '.[] | select(.user.login == "github-actions[bot]") | select(.body | contains("<!-- drift-review -->")) | .id' | sed -n '1p')
134
+
135
+ if [ -n "$EXISTING_ID" ]; then
136
+ gh api -X PATCH "repos/$REPO/issues/comments/$EXISTING_ID" -f "body=$COMMENT_BODY"
137
+ else
138
+ gh api -X POST "repos/$REPO/issues/$PR_NUMBER/comments" -f "body=$COMMENT_BODY"
139
+ fi
140
+
141
+ - name: Fallback summary for fork PRs
142
+ if: github.event.pull_request.head.repo.fork == true
143
+ run: |
144
+ {
145
+ echo "## drift trust"
146
+ echo
147
+ cat drift-trust.md
148
+ echo
149
+ echo "## drift review"
150
+ echo
151
+ cat drift-review.md
152
+ } >> "$GITHUB_STEP_SUMMARY"
153
+
package/AGENTS.md CHANGED
@@ -106,6 +106,11 @@ npm run test:watch # vitest (watch mode)
106
106
  | `--ai` | boolean | JSON optimizado para LLMs (`AIOutput`) |
107
107
  | `--fix` | boolean | Muestra sugerencias de fix en consola |
108
108
  | `--min-score <n>` | number | Exit code 1 si score supera umbral (CI) |
109
+ | `--low-memory` | boolean | Activa análisis por chunks para bajar el pico de RAM |
110
+ | `--chunk-size <n>` | number | Cantidad de archivos por chunk en low-memory mode |
111
+ | `--max-files <n>` | number | Límite blando de archivos analizados (el resto se reporta como skip) |
112
+ | `--max-file-size-kb <n>` | number | Saltea archivos grandes y agrega diagnóstico de skip |
113
+ | `--with-semantic-duplication` | boolean | Rehabilita semantic-duplication en low-memory mode |
109
114
 
110
115
  **Uso básico:**
111
116
  ```bash
@@ -114,6 +119,7 @@ npx @eduardbar/drift scan ./src --min-score 60
114
119
  npx @eduardbar/drift scan ./src --ai | pbcopy # pegar en Claude/GPT
115
120
  npx @eduardbar/drift scan ./src --fix # ver sugerencias inline
116
121
  npx @eduardbar/drift scan ./src -o report.md # exportar Markdown
122
+ npx @eduardbar/drift scan ./src --low-memory --max-file-size-kb 1024
117
123
  ```
118
124
 
119
125
  ---
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
- ![drift technical debt detector for AI-generated code](./assets/og.png)
1
+ ![drift - AI Code Audit CLI for merge trust](./assets/og.png)
2
2
 
3
3
  # drift
4
4
 
5
- Detect technical debt in AI-generated TypeScript code. One command. Zero config.
5
+ AI Code Audit CLI for AI-assisted PRs. Drift turns static signals into merge trust decisions before you merge.
6
6
 
7
7
  ![npm](https://img.shields.io/npm/v/@eduardbar/drift?color=6366f1&label=npm)
8
8
  ![license](https://img.shields.io/badge/license-MIT-green.svg)
@@ -20,7 +20,7 @@ AI coding tools ship code fast. They also leave behind consistent, predictable s
20
20
 
21
21
  GitClear's 2024 analysis of 211M lines of code found a **39.9% drop in refactoring activity** and an **8x increase in duplicated code blocks** since AI tools became mainstream. A senior engineer on r/vibecoding put it plainly: _"The code looks reviewed. It isn't. Nobody's reading 400-line files the AI dumped in one shot."_
22
22
 
23
- drift gives you a 0–100 score per file and project so you know what to look at before it reaches production.
23
+ drift gives you debt signals (`scan`, `review`) and a trust decision layer (`trust`) so teams can merge with confidence instead of guesswork.
24
24
 
25
25
  **How drift compares to existing tools:**
26
26
 
@@ -50,6 +50,7 @@ npm install --save-dev @eduardbar/drift
50
50
  ## Product Docs
51
51
 
52
52
  - Product requirements and roadmap: [`docs/PRD.md`](./docs/PRD.md)
53
+ - Trust core release checklist: [`docs/trust-core-release-checklist.md`](./docs/trust-core-release-checklist.md)
53
54
  - Contributor/agent workflow guide: [`docs/AGENTS.md`](./docs/AGENTS.md)
54
55
 
55
56
  ---
@@ -68,6 +69,7 @@ drift scan ./src --json
68
69
  drift scan ./src --ai
69
70
  drift scan ./src --fix
70
71
  drift scan ./src --min-score 50
72
+ drift scan ./src --low-memory --max-file-size-kb 1024
71
73
  ```
72
74
 
73
75
  **Options:**
@@ -79,6 +81,11 @@ drift scan ./src --min-score 50
79
81
  | `--ai` | Output structured JSON optimized for LLM consumption (Claude, GPT, etc.) |
80
82
  | `--fix` | Print inline fix suggestions for each detected issue |
81
83
  | `--min-score <n>` | Exit with code 1 if the overall score meets or exceeds this threshold |
84
+ | `--low-memory` | Analyze files in bounded chunks to reduce peak RAM |
85
+ | `--chunk-size <n>` | Files per chunk in low-memory mode (default: 40) |
86
+ | `--max-files <n>` | Soft cap on analyzed files; extra files are skipped with diagnostics |
87
+ | `--max-file-size-kb <n>` | Skip oversized files with diagnostics to avoid OOM |
88
+ | `--with-semantic-duplication` | Keep semantic duplication rule enabled in low-memory mode |
82
89
 
83
90
  **Example output:**
84
91
 
@@ -146,11 +153,96 @@ drift review --base origin/main --fail-on 5
146
153
  | `--comment` | Print only the markdown body for PR comments |
147
154
  | `--fail-on <n>` | Exit code 1 when score delta is greater than or equal to `n` |
148
155
 
156
+ `drift review` is best used as supplementary diff context alongside `drift trust` in pull-request workflows.
157
+
158
+ ---
159
+
160
+ ### `drift trust [path]`
161
+
162
+ Compute merge trust baseline for local checks and CI merge gates.
163
+
164
+ ```bash
165
+ drift trust
166
+ drift trust ./src
167
+ drift trust ./src --json
168
+ drift trust ./src --base origin/main
169
+ drift trust ./src --base origin/main --markdown
170
+ drift trust ./src --markdown --output trust.md
171
+ drift trust ./src --min-trust 45
172
+ drift trust ./src --max-risk HIGH
173
+ drift trust ./src --branch main
174
+ drift trust ./src --branch release/v1.4.0 --policy-pack strict --explain-policy
175
+ drift trust ./src --advanced-trust
176
+ drift trust ./src --advanced-trust --previous-trust ./artifacts/prev-trust.json
177
+ drift trust ./src --advanced-trust --history-file ./drift-history.json --markdown
178
+ ```
179
+
180
+ | Flag | Description |
181
+ |------|-------------|
182
+ | `--base <ref>` | Compare against a git base ref and include deterministic diff-aware penalties/bonuses |
183
+ | `--json` | Output structured trust JSON (`trust_score`, `merge_risk`, `top_reasons`, `fix_priorities`, optional `diff_context`) |
184
+ | `--markdown` | Output PR-ready markdown trust summary |
185
+ | `--output <file>` | Write selected trust output format to file |
186
+ | `--min-trust <n>` | Exit code 1 when trust score is below `n` |
187
+ | `--max-risk <level>` | Exit code 1 when computed merge risk exceeds `LOW`, `MEDIUM`, `HIGH`, or `CRITICAL` |
188
+ | `--branch <name>` | Branch used for `drift.config` trust policy matching (falls back to CI env vars) |
189
+ | `--policy-pack <name>` | Optional trust policy pack from `trustGate.policyPacks` in `drift.config.*` |
190
+ | `--explain-policy` | Print base/pack/branch/override resolution and effective gate policy to stderr |
191
+ | `--advanced-trust` | Enable optional advanced trust layer (historical comparison + team guidance metadata) |
192
+ | `--previous-trust <file>` | Compare current trust against a prior trust JSON file in advanced mode |
193
+ | `--history-file <file>` | Use a specific `drift-history.json` file for advanced historical fallback |
194
+
195
+ When `trustGate` policy is configured in `drift.config.*`, branch-based thresholds are applied automatically. CLI flags still override policy values.
196
+
197
+ ---
198
+
199
+ ### `drift trust-gate <trust-json-file>`
200
+
201
+ Evaluate trust gate thresholds from a previously generated trust JSON file. This is ideal for CI workflows that already produced `drift-trust.json` and want a single source of truth for gate logic.
202
+
203
+ ```bash
204
+ drift trust-gate drift-trust.json --min-trust 45 --max-risk HIGH
205
+ drift trust-gate drift-trust.json --branch release/v1.2.0
206
+ drift trust-gate drift-trust.json --branch main --policy-pack balanced --explain-policy
207
+ ```
208
+
209
+ | Flag | Description |
210
+ |------|-------------|
211
+ | `--min-trust <n>` | Exit code 1 when trust score in JSON is below `n` |
212
+ | `--max-risk <level>` | Exit code 1 when merge risk in JSON exceeds `LOW`, `MEDIUM`, `HIGH`, or `CRITICAL` |
213
+ | `--branch <name>` | Branch used for `drift.config` trust policy matching (falls back to CI env vars) |
214
+ | `--policy-pack <name>` | Optional trust policy pack from `trustGate.policyPacks` in `drift.config.*` |
215
+ | `--explain-policy` | Print base/pack/branch/override resolution and effective gate policy to stderr |
216
+
217
+ ---
218
+
219
+ ### `drift kpi <path>`
220
+
221
+ Aggregate trust KPI evidence from local artifacts (directory or glob). Prints a compact console summary to stderr and structured KPI JSON to stdout.
222
+
223
+ ```bash
224
+ drift kpi ./artifacts/trust
225
+ drift kpi "./artifacts/**/drift-trust-*.json"
226
+ drift kpi ./artifacts/trust --no-summary
227
+ ```
228
+
229
+ | Flag | Description |
230
+ |------|-------------|
231
+ | `--no-summary` | Disable stderr console summary and output JSON only |
232
+
233
+ Computed KPI fields include:
234
+ - PRs evaluated count
235
+ - Merge risk distribution (`LOW`, `MEDIUM`, `HIGH`, `CRITICAL`)
236
+ - Trust score average/median/min/max
237
+ - High-risk ratio (`HIGH` + `CRITICAL`)
238
+ - Diff trend aggregates when `diff_context` exists (`scoreDelta`, new/resolved issues, status distribution)
239
+ - Diagnostics for malformed/missing/invalid JSON artifacts
240
+
149
241
  ---
150
242
 
151
243
  ### `drift map [path]`
152
244
 
153
- Generate an `architecture.svg` map with inferred layer dependencies.
245
+ Generate an `architecture.svg` map with inferred layer dependencies. When layer config is present, the SVG also highlights cycle edges and layer violations.
154
246
 
155
247
  ```bash
156
248
  drift map
@@ -162,6 +254,11 @@ drift map ./src --output docs/architecture.svg
162
254
  |------|-------------|
163
255
  | `--output <file>` | Output path for the SVG file (default: `architecture.svg`) |
164
256
 
257
+ Edge legend in SVG:
258
+ - Gray: normal dependency
259
+ - Orange: cycle edge
260
+ - Red: layer violation edge
261
+
165
262
  ---
166
263
 
167
264
  ### `drift report [path]`
@@ -270,6 +367,7 @@ Auto-fix safe issues with explicit preview/write modes.
270
367
  ```bash
271
368
  drift fix ./src --preview
272
369
  drift fix ./src --write
370
+ drift fix ./src --write --yes
273
371
  drift fix ./src --dry-run # alias of --preview
274
372
  ```
275
373
 
@@ -278,6 +376,52 @@ drift fix ./src --dry-run # alias of --preview
278
376
  | `--preview` | Preview before/after without writing files |
279
377
  | `--write` | Apply fixes to disk |
280
378
  | `--dry-run` | Backward-compatible alias for preview mode |
379
+ | `--yes` | Skip interactive confirmation for write mode |
380
+
381
+ ---
382
+
383
+ ### `drift cloud`
384
+
385
+ Local multi-tenant foundations backed by `.drift-cloud/store.json`.
386
+
387
+ ```bash
388
+ drift cloud ingest ./src --org acme --workspace core --user u-123 --role owner --plan sponsor --repo webapp
389
+ drift cloud summary
390
+ drift cloud summary --org acme --workspace core
391
+ drift cloud summary --org acme --workspace core --actor u-owner
392
+ drift cloud ingest ./src --org acme --workspace core --user u-member --actor u-owner
393
+ drift cloud ingest ./src --org acme --workspace core --user u-member --actor u-member # strict actor mode ready
394
+ drift cloud plan-set --org acme --plan team --actor u-owner --reason "annual upgrade"
395
+ drift cloud plan-changes --org acme --actor u-owner
396
+ drift cloud usage --org acme --actor u-owner
397
+ drift cloud summary --json
398
+ drift cloud dashboard --output drift-cloud-dashboard.html
399
+ ```
400
+
401
+ **Subcommands:**
402
+
403
+ | Command | Description |
404
+ |---------|-------------|
405
+ | `drift cloud ingest [path] --org <id> --workspace <id> --user <id> [--role <owner\|member\|viewer>] [--plan <free\|sponsor\|team\|business>] [--repo <name>] [--actor <user>] [--store <file>]` | Scans the path and stores one tenant-scoped snapshot (`--actor` optional by default, required only when `saas.strictActorEnforcement=true`) |
406
+ | `drift cloud summary [--json] [--org <id>] [--workspace <id>] [--actor <user>] [--store <file>]` | Shows users/workspaces/repos usage and runs per month; in strict mode, scoped reads (`--org`/`--workspace`) require `--actor` |
407
+ | `drift cloud plan-set --org <id> --plan <free\|sponsor\|team\|business> --actor <user> [--reason <text>] [--store <file>]` | Updates organization plan and writes an audited plan-change event (owner-gated by actor) |
408
+ | `drift cloud plan-changes --org <id> --actor <user> [--json] [--store <file>]` | Lists audited plan lifecycle events for the organization |
409
+ | `drift cloud usage --org <id> --actor <user> [--month <yyyy-mm>] [--json] [--store <file>]` | Shows organization usage plus effective limits for current plan |
410
+ | `drift cloud dashboard [--output <file>] [--store <file>]` | Generates an HTML dashboard with trends and hotspots |
411
+
412
+ `drift cloud` ships with tenant identity boundaries (`organizationId` + `workspaceId`), role primitives (`owner`/`member`/`viewer`), and plan placeholders (`free`/`sponsor`/`team`/`business`). It is an infrastructure foundation, not a full auth/billing platform.
413
+
414
+ By default, local guardrails enforce one plan-based limit: max workspaces per organization (`free:20`, `sponsor:50`, `team:200`, `business:1000`), plus existing free-phase limits (runs per workspace, repos per workspace, retention window).
415
+
416
+ To require actor identity on scoped cloud operations, enable strict actor mode in `drift.config.*`:
417
+
418
+ ```ts
419
+ export default {
420
+ saas: {
421
+ strictActorEnforcement: true,
422
+ },
423
+ }
424
+ ```
281
425
 
282
426
  ---
283
427
 
@@ -339,11 +483,27 @@ import type { DriftConfig } from '@eduardbar/drift'
339
483
 
340
484
  export default {
341
485
  plugins: ['drift-plugin-example'],
486
+ performance: {
487
+ lowMemory: true,
488
+ chunkSize: 40,
489
+ maxFiles: 8000,
490
+ maxFileSizeKb: 1024,
491
+ includeSemanticDuplication: false,
492
+ },
342
493
  architectureRules: {
343
494
  controllerNoDb: true,
344
495
  serviceNoHttp: true,
345
496
  maxFunctionLines: 80,
346
497
  },
498
+ trustGate: {
499
+ minTrust: 45,
500
+ maxRisk: 'HIGH',
501
+ presets: [
502
+ { branch: 'main', minTrust: 70, maxRisk: 'MEDIUM' },
503
+ { branch: 'release/*', minTrust: 80, maxRisk: 'LOW' },
504
+ { branch: 'legacy/*', enabled: false },
505
+ ],
506
+ },
347
507
  layers: [
348
508
  { name: 'domain', patterns: ['src/domain/**'], canImportFrom: [] },
349
509
  { name: 'app', patterns: ['src/app/**'], canImportFrom: ['domain'] },
@@ -366,6 +526,20 @@ export default {
366
526
 
367
527
  Without a config file, `layer-violation` and `cross-boundary-import` are silently skipped. All other rules run with their defaults.
368
528
 
529
+ ### Memory guardrails (recommended for large repos)
530
+
531
+ If your repository is large or your machine has limited RAM, start with:
532
+
533
+ ```bash
534
+ drift scan . --low-memory --max-file-size-kb 1024 --max-files 8000
535
+ ```
536
+
537
+ Practical tuning:
538
+ - Lower `--chunk-size` to reduce peak memory further (slower but safer).
539
+ - Keep `includeSemanticDuplication: false` in low-memory mode for the lowest memory footprint.
540
+ - Set `maxFileSizeKb` to skip generated/vendor files that can explode AST memory usage.
541
+ - Set `maxFiles` to protect CI runners from worst-case monorepo scans.
542
+
369
543
  ---
370
544
 
371
545
  ## CI Integration
@@ -412,6 +586,20 @@ jobs:
412
586
 
413
587
  `drift ci` emits `::error` and `::warning` annotations that appear inline in the PR diff and writes a formatted summary to `$GITHUB_STEP_SUMMARY`. Use this when you want visibility beyond a pass/fail exit code.
414
588
 
589
+ ### Auto PR comment with `drift review`
590
+
591
+ The repository includes `.github/workflows/review-pr.yml`, which:
592
+ - generates a PR-ready markdown comment with `drift trust --markdown` first and `drift review --comment` as supplementary context
593
+ - updates a single sticky comment (`<!-- drift-review -->`) on non-fork PRs
594
+ - falls back to `$GITHUB_STEP_SUMMARY` for fork PRs
595
+ - enforces a trust baseline gate with `drift trust-gate drift-trust.json --min-trust 45 --max-risk HIGH`
596
+ - uploads `drift trust --json` as `drift-trust-json-pr-<PR_NUMBER>-run-<RUN_ATTEMPT>` for manual KPI tracking
597
+ - publishes a compact trust KPI summary in `$GITHUB_STEP_SUMMARY` (score, merge risk, new/resolved issues when diff context is available)
598
+
599
+ Default gate behavior in this repo:
600
+ - fail when trust is below 45
601
+ - fail when merge risk is above `HIGH` (that means `CRITICAL` is blocked)
602
+
415
603
  ---
416
604
 
417
605
  ## drift-ignore
package/ROADMAP.md CHANGED
@@ -21,19 +21,20 @@ drift's goal is to be the tool that sits between ESLint and SonarQube — lightw
21
21
  **What drift is not:**
22
22
  - Not an ESLint replacement for style or correctness rules
23
23
  - Not a SonarQube replacement for security scanning
24
- - Not a cloud product, not a SaaS, not freemium
24
+ - Not a cloud-only product or mandatory hosted backend
25
25
 
26
26
  **What drift is:**
27
27
  - A zero-config static analysis CLI that scores your TypeScript project's structural health
28
- - A CI gate that blocks debt from accumulating silently
28
+ - An AI code audit CLI that helps teams decide merge trust on AI-assisted PRs
29
+ - A CI gate that blocks risky merges using trust thresholds
29
30
  - A shared language for teams to talk about code quality: "our drift score went from 40 to 18 this sprint"
30
- - Always free. MIT. No tiers.
31
+ - Core CLI is free and MIT; premium governance/sponsor tiers are a product direction for teams
31
32
 
32
33
  ---
33
34
 
34
35
  ## Principles that don't change
35
36
 
36
- - **Always free for the developer.** MIT. Forever. No paid tier, no cloud lock-in.
37
+ - **Core stays free for developers.** MIT for the OSS CLI, no backend lock-in for the core workflow.
37
38
  - **Zero config to start.** One command, one number. Config is optional and additive.
38
39
  - **Fast.** Results in under 3 seconds on any normal project.
39
40
  - **One actionable number, not 400 warnings nobody reads.**
@@ -153,7 +154,7 @@ A score of 45 means nothing without context. A score that went from 80 to 45 ove
153
154
 
154
155
  - **26 rules active** across 9 detection categories
155
156
  - **Self-scan score: 14/100 (LOW)**
156
- - Published on npm as `@eduardbar/drift` — MIT, always free
157
+ - Published on npm as `@eduardbar/drift` — MIT core CLI, optional premium direction documented in PRD
157
158
  - Cross-platform: Windows / Linux / macOS via `npx`
158
159
 
159
160
  ---
@@ -1,4 +1,4 @@
1
- import type { DriftIssue, FileReport, DriftConfig, LoadedPlugin } from './types.js';
1
+ import type { DriftIssue, FileReport, DriftConfig, DriftAnalysisOptions, LoadedPlugin } from './types.js';
2
2
  export { TrendAnalyzer } from './git/trend.js';
3
3
  export { BlameAnalyzer } from './git/blame.js';
4
4
  export declare const RULE_WEIGHTS: Record<string, {
@@ -10,5 +10,5 @@ export declare function analyzeFile(file: import('ts-morph').SourceFile, options
10
10
  loadedPlugins?: LoadedPlugin[];
11
11
  projectRoot?: string;
12
12
  }): FileReport;
13
- export declare function analyzeProject(targetPath: string, config?: DriftConfig): FileReport[];
13
+ export declare function analyzeProject(targetPath: string, config?: DriftConfig, options?: DriftAnalysisOptions): FileReport[];
14
14
  //# sourceMappingURL=analyzer.d.ts.map