@eduardbar/drift 1.2.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 (61) 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 +98 -6
  4. package/AGENTS.md +6 -0
  5. package/README.md +160 -10
  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 +453 -62
  12. package/dist/diff.js +74 -10
  13. package/dist/git.js +12 -0
  14. package/dist/index.d.ts +5 -3
  15. package/dist/index.js +3 -1
  16. package/dist/plugins.d.ts +2 -1
  17. package/dist/plugins.js +177 -28
  18. package/dist/printer.js +4 -0
  19. package/dist/review.js +2 -2
  20. package/dist/rules/comments.js +2 -2
  21. package/dist/rules/complexity.js +2 -7
  22. package/dist/rules/nesting.js +3 -13
  23. package/dist/rules/phase0-basic.js +10 -10
  24. package/dist/rules/shared.d.ts +2 -0
  25. package/dist/rules/shared.js +27 -3
  26. package/dist/saas.d.ts +143 -7
  27. package/dist/saas.js +478 -37
  28. package/dist/trust-kpi.d.ts +9 -0
  29. package/dist/trust-kpi.js +445 -0
  30. package/dist/trust.d.ts +65 -0
  31. package/dist/trust.js +571 -0
  32. package/dist/types.d.ts +154 -0
  33. package/docs/PRD.md +187 -109
  34. package/docs/plugin-contract.md +61 -0
  35. package/docs/trust-core-release-checklist.md +55 -0
  36. package/package.json +5 -3
  37. package/src/analyzer.ts +484 -155
  38. package/src/benchmark.ts +244 -0
  39. package/src/cli.ts +562 -79
  40. package/src/diff.ts +75 -10
  41. package/src/git.ts +16 -0
  42. package/src/index.ts +48 -0
  43. package/src/plugins.ts +354 -26
  44. package/src/printer.ts +4 -0
  45. package/src/review.ts +2 -2
  46. package/src/rules/comments.ts +2 -2
  47. package/src/rules/complexity.ts +2 -7
  48. package/src/rules/nesting.ts +3 -13
  49. package/src/rules/phase0-basic.ts +11 -12
  50. package/src/rules/shared.ts +31 -3
  51. package/src/saas.ts +641 -43
  52. package/src/trust-kpi.ts +518 -0
  53. package/src/trust.ts +774 -0
  54. package/src/types.ts +171 -0
  55. package/tests/diff.test.ts +124 -0
  56. package/tests/new-features.test.ts +71 -0
  57. package/tests/plugins.test.ts +219 -0
  58. package/tests/rules.test.ts +23 -1
  59. package/tests/saas-foundation.test.ts +358 -1
  60. package/tests/trust-kpi.test.ts +120 -0
  61. 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
 
@@ -13,21 +13,105 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
15
  - name: Checkout
16
- uses: actions/checkout@v4
16
+ uses: actions/checkout@v5
17
17
  with:
18
18
  fetch-depth: 0
19
19
 
20
20
  - name: Setup Node.js
21
- uses: actions/setup-node@v4
21
+ uses: actions/setup-node@v5
22
22
  with:
23
- node-version: '20'
23
+ node-version: '22'
24
24
  cache: 'npm'
25
25
 
26
26
  - name: Install dependencies
27
27
  run: npm ci
28
28
 
29
+ # Run directly from TypeScript source in this PR to avoid stale dist artifacts.
29
30
  - name: Generate drift review markdown
30
- run: npx @eduardbar/drift review --base "origin/${{ github.base_ref }}" --comment > drift-review.md
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
31
115
 
32
116
  - name: Post or update PR comment (non-fork only)
33
117
  if: github.event.pull_request.head.repo.fork == false
@@ -38,7 +122,13 @@ jobs:
38
122
  run: |
39
123
  COMMENT_BODY="<!-- drift-review -->"
40
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'
41
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 }} -->"
42
132
 
43
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')
44
134
 
@@ -52,10 +142,12 @@ jobs:
52
142
  if: github.event.pull_request.head.repo.fork == true
53
143
  run: |
54
144
  {
145
+ echo "## drift trust"
146
+ echo
147
+ cat drift-trust.md
148
+ echo
55
149
  echo "## drift review"
56
150
  echo
57
151
  cat drift-review.md
58
152
  } >> "$GITHUB_STEP_SUMMARY"
59
153
 
60
- - name: Enforce drift threshold
61
- run: npx @eduardbar/drift review --base "origin/${{ github.base_ref }}" --fail-on 5 --comment > /dev/null
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,6 +153,91 @@ 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]`
@@ -290,11 +382,18 @@ drift fix ./src --dry-run # alias of --preview
290
382
 
291
383
  ### `drift cloud`
292
384
 
293
- Local SaaS foundations backed by `.drift-cloud/store.json`.
385
+ Local multi-tenant foundations backed by `.drift-cloud/store.json`.
294
386
 
295
387
  ```bash
296
- drift cloud ingest ./src --workspace acme --user u-123 --repo webapp
388
+ drift cloud ingest ./src --org acme --workspace core --user u-123 --role owner --plan sponsor --repo webapp
297
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
298
397
  drift cloud summary --json
299
398
  drift cloud dashboard --output drift-cloud-dashboard.html
300
399
  ```
@@ -303,11 +402,26 @@ drift cloud dashboard --output drift-cloud-dashboard.html
303
402
 
304
403
  | Command | Description |
305
404
  |---------|-------------|
306
- | `drift cloud ingest [path] --workspace <id> --user <id> [--repo <name>] [--store <file>]` | Scans the path and stores one SaaS snapshot |
307
- | `drift cloud summary [--json] [--store <file>]` | Shows users/workspaces/repos usage and runs per month |
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 |
308
410
  | `drift cloud dashboard [--output <file>] [--store <file>]` | Generates an HTML dashboard with trends and hotspots |
309
411
 
310
- `drift cloud` ships with a free-until-7,500 strategy and configurable guardrails for the free phase: max runs per workspace per month, max repos per workspace, and retention window.
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
+ ```
311
425
 
312
426
  ---
313
427
 
@@ -369,11 +483,27 @@ import type { DriftConfig } from '@eduardbar/drift'
369
483
 
370
484
  export default {
371
485
  plugins: ['drift-plugin-example'],
486
+ performance: {
487
+ lowMemory: true,
488
+ chunkSize: 40,
489
+ maxFiles: 8000,
490
+ maxFileSizeKb: 1024,
491
+ includeSemanticDuplication: false,
492
+ },
372
493
  architectureRules: {
373
494
  controllerNoDb: true,
374
495
  serviceNoHttp: true,
375
496
  maxFunctionLines: 80,
376
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
+ },
377
507
  layers: [
378
508
  { name: 'domain', patterns: ['src/domain/**'], canImportFrom: [] },
379
509
  { name: 'app', patterns: ['src/app/**'], canImportFrom: ['domain'] },
@@ -396,6 +526,20 @@ export default {
396
526
 
397
527
  Without a config file, `layer-violation` and `cross-boundary-import` are silently skipped. All other rules run with their defaults.
398
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
+
399
543
  ---
400
544
 
401
545
  ## CI Integration
@@ -445,10 +589,16 @@ jobs:
445
589
  ### Auto PR comment with `drift review`
446
590
 
447
591
  The repository includes `.github/workflows/review-pr.yml`, which:
448
- - generates a PR-ready markdown comment from `drift review --comment`
592
+ - generates a PR-ready markdown comment with `drift trust --markdown` first and `drift review --comment` as supplementary context
449
593
  - updates a single sticky comment (`<!-- drift-review -->`) on non-fork PRs
450
594
  - falls back to `$GITHUB_STEP_SUMMARY` for fork PRs
451
- - enforces a score delta threshold with `--fail-on`
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)
452
602
 
453
603
  ---
454
604
 
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