@vibedrift/cli 0.4.1 → 0.4.3
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.
- package/README.md +115 -22
- package/dist/index.js +71 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,27 +21,66 @@ vibedrift ./my-project
|
|
|
21
21
|
|
|
22
22
|
That's it. No signup, no API key, no config file. The default run produces an interactive HTML report and serves it on a local port.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
### Free deep scan
|
|
25
|
+
|
|
26
|
+
Every account gets **1 free deep scan** on signup — no card required. Deep scans add Claude-powered AI analysis on top of the local scan (semantic duplicates, intent mismatches, anomaly detection):
|
|
25
27
|
|
|
26
28
|
```bash
|
|
27
|
-
vibedrift login # one-time browser sign-in
|
|
28
|
-
vibedrift . --deep #
|
|
29
|
+
vibedrift login # one-time browser sign-in
|
|
30
|
+
vibedrift . --deep # uses your free credit (or Pro subscription)
|
|
29
31
|
```
|
|
30
32
|
|
|
31
33
|
---
|
|
32
34
|
|
|
33
35
|
## What It Catches
|
|
34
36
|
|
|
37
|
+
### Layer 1 — Static Analysis (13 analyzers, runs locally)
|
|
35
38
|
- **Architectural contradictions** — when half your handlers use a repository pattern and the other half hit raw SQL
|
|
36
|
-
- **Hidden duplicates** — functions that do the same thing under different names in different files
|
|
37
|
-
- **Security gaps** — routes missing auth, validation, or rate limiting
|
|
38
39
|
- **Naming inconsistency** — `getUserData()`, `get_order_items()`, `FetchProductList()` in the same project
|
|
40
|
+
- **Security patterns** — hardcoded secrets, SQL injection, command injection, weak crypto, unsafe functions
|
|
41
|
+
- **Dependency health** — phantom deps, missing deps, undocumented env vars
|
|
42
|
+
- **Code quality** — cyclomatic complexity, dead code, TODO density, long functions, unclear naming
|
|
43
|
+
|
|
44
|
+
### Layer 1.5 — Cross-File Drift Detection (5 detectors)
|
|
45
|
+
- **Architectural consistency** — data access patterns, error handling, DI, config approaches
|
|
46
|
+
- **Convention oscillation** — naming conventions, file naming across the whole project
|
|
47
|
+
- **Security consistency** — auth middleware, input validation, rate limiting across routes
|
|
48
|
+
- **Semantic duplication** — functions that do the same thing under different names in different files
|
|
39
49
|
- **Phantom scaffolding** — CRUD endpoints the AI generated but never wired up
|
|
40
50
|
|
|
51
|
+
### Layer 1.7 — Code DNA Engine (5 modules, runs locally)
|
|
52
|
+
- **Semantic fingerprinting** — normalizes function bodies and hashes them. Identical hashes = exact semantic duplicates at confidence 1.0
|
|
53
|
+
- **Operation sequence analysis** — reduces functions to abstract operations (INPUT, QUERY, MUTATE, RETURN) and compares via LCS
|
|
54
|
+
- **Pattern classification** — structural pattern detection with probability distributions per file
|
|
55
|
+
- **Taint analysis** — tracks user input from sources (req.params) to dangerous sinks (db.query) within functions
|
|
56
|
+
- **Deviation heuristics** — scores whether architectural deviations are justified or accidental
|
|
57
|
+
|
|
58
|
+
### Layer 2 — AI Deep Analysis (requires `--deep`)
|
|
59
|
+
- **ML duplicate detection** — UniXcoder embeddings + cosine similarity for near-duplicates
|
|
60
|
+
- **Intent mismatch** — detects functions whose name doesn't match their behavior
|
|
61
|
+
- **Anomaly detection** — DBSCAN outlier detection on handler embeddings
|
|
62
|
+
- **Surgical LLM validation** — Claude validates medium-confidence ML findings
|
|
63
|
+
|
|
41
64
|
VibeDrift learns the dominant patterns your codebase follows and flags files that deviate from them. A codebase isn't wrong because it uses raw SQL — it's *drifting* because 8 of its 10 handlers use a repository and 2 don't.
|
|
42
65
|
|
|
43
66
|
---
|
|
44
67
|
|
|
68
|
+
## Scoring
|
|
69
|
+
|
|
70
|
+
VibeDrift scores across 5 categories, each 0–20 points:
|
|
71
|
+
|
|
72
|
+
| Category | What it measures |
|
|
73
|
+
|----------|-----------------|
|
|
74
|
+
| **Architectural Consistency** | Naming, imports, error handling, patterns, drift detection |
|
|
75
|
+
| **Redundancy** | Duplicates, dead code, TODO density, Code DNA fingerprints |
|
|
76
|
+
| **Dependency Health** | Phantom/missing deps, env var documentation |
|
|
77
|
+
| **Security Posture** | Hardcoded secrets, injection risks, taint flows, security drift |
|
|
78
|
+
| **Intent Clarity** | Complexity, unclear naming, commented-out code, documentation |
|
|
79
|
+
|
|
80
|
+
**Composite score** = sum of applicable categories (0–100). Grade thresholds: A ≥ 90, B ≥ 75, C ≥ 50, D ≥ 25, F < 25.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
45
84
|
## Usage
|
|
46
85
|
|
|
47
86
|
```
|
|
@@ -57,6 +96,7 @@ Commands:
|
|
|
57
96
|
billing Open the Stripe Customer Portal
|
|
58
97
|
doctor Diagnose CLI installation, auth, and API
|
|
59
98
|
update Update the CLI to the latest version
|
|
99
|
+
feedback [message] Send feedback, bug reports, or feature requests
|
|
60
100
|
|
|
61
101
|
Scan options:
|
|
62
102
|
--format <type> Output format: html, terminal, json, csv, docx (default: html)
|
|
@@ -64,9 +104,11 @@ Scan options:
|
|
|
64
104
|
--json Shorthand for --format json
|
|
65
105
|
--fail-on-score <n> Exit with code 1 if composite score is below threshold
|
|
66
106
|
--no-codedna Skip Code DNA semantic analysis
|
|
67
|
-
--deep Enable AI-powered deep analysis (requires
|
|
107
|
+
--deep Enable AI-powered deep analysis (requires login)
|
|
108
|
+
--project-name <name> Override the auto-detected project name
|
|
68
109
|
--include <pattern> Only scan files matching this glob (repeatable)
|
|
69
110
|
--exclude <pattern> Exclude files matching this glob (repeatable)
|
|
111
|
+
--feedback [message] Send feedback (alias for `vibedrift feedback`)
|
|
70
112
|
--update Update the VibeDrift CLI to the latest version
|
|
71
113
|
--verbose Show timing breakdown and analyzer details
|
|
72
114
|
-V, --version Show installed version
|
|
@@ -76,6 +118,7 @@ Scan options:
|
|
|
76
118
|
### Examples
|
|
77
119
|
|
|
78
120
|
```bash
|
|
121
|
+
# Scanning
|
|
79
122
|
vibedrift # scan the current directory
|
|
80
123
|
vibedrift ./my-project # scan a specific project
|
|
81
124
|
vibedrift --format terminal # print results to the terminal
|
|
@@ -83,12 +126,20 @@ vibedrift --json > report.json # pipe JSON output to a file
|
|
|
83
126
|
vibedrift --fail-on-score 70 # fail CI if score drops below 70
|
|
84
127
|
vibedrift --include "src/**" # only scan files under src/
|
|
85
128
|
vibedrift --exclude "**/*.spec.*" # skip test files
|
|
86
|
-
vibedrift --deep # run
|
|
87
|
-
|
|
88
|
-
|
|
129
|
+
vibedrift --deep # run AI-powered deep analysis
|
|
130
|
+
|
|
131
|
+
# Account
|
|
132
|
+
vibedrift login # sign in (opens browser)
|
|
133
|
+
vibedrift status # check auth + credit balance
|
|
89
134
|
vibedrift usage # view this month's scan usage
|
|
90
|
-
vibedrift billing # manage your
|
|
135
|
+
vibedrift billing # manage your subscription
|
|
91
136
|
vibedrift update # update to the latest version
|
|
137
|
+
|
|
138
|
+
# Feedback
|
|
139
|
+
vibedrift feedback # interactive prompt
|
|
140
|
+
vibedrift feedback "the report is great but needs dark mode"
|
|
141
|
+
vibedrift --feedback "inline shortcut works too"
|
|
142
|
+
echo "piped input" | vibedrift feedback
|
|
92
143
|
```
|
|
93
144
|
|
|
94
145
|
### Environment
|
|
@@ -103,27 +154,56 @@ vibedrift update # update to the latest version
|
|
|
103
154
|
|
|
104
155
|
| Format | Description |
|
|
105
156
|
|--------|-------------|
|
|
106
|
-
| `html` (default) | Interactive report with charts,
|
|
157
|
+
| `html` (default) | Interactive report with charts, category breakdowns, drift findings, Code DNA results, and export options |
|
|
107
158
|
| `terminal` | Color-coded terminal output with tables |
|
|
108
|
-
| `json` | Full
|
|
109
|
-
| `csv` |
|
|
110
|
-
| `docx` | Word document with formatted
|
|
159
|
+
| `json` | Full ScanResult serialization for CI pipelines |
|
|
160
|
+
| `csv` | Multi-section tabular export (metadata, scores, findings, drift, Code DNA, per-file) |
|
|
161
|
+
| `docx` | Word document with formatted title page, AI summary, scores, and all findings |
|
|
111
162
|
|
|
112
163
|
### CI Integration
|
|
113
164
|
|
|
114
|
-
```
|
|
115
|
-
#
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
165
|
+
```yaml
|
|
166
|
+
# GitHub Actions
|
|
167
|
+
name: VibeDrift
|
|
168
|
+
on: [pull_request]
|
|
169
|
+
jobs:
|
|
170
|
+
drift-check:
|
|
171
|
+
runs-on: ubuntu-latest
|
|
172
|
+
steps:
|
|
173
|
+
- uses: actions/checkout@v4
|
|
174
|
+
- run: npx @vibedrift/cli . --deep --json --fail-on-score 70
|
|
175
|
+
env:
|
|
176
|
+
VIBEDRIFT_TOKEN: ${{ secrets.VIBEDRIFT_TOKEN }}
|
|
121
177
|
```
|
|
122
178
|
|
|
123
179
|
Exit code 1 when the score drops below the threshold. JSON output includes every finding for downstream tooling.
|
|
124
180
|
|
|
125
181
|
---
|
|
126
182
|
|
|
183
|
+
## Dashboard
|
|
184
|
+
|
|
185
|
+
All scans (free and deep) are logged to your dashboard at [vibedrift.ai/dashboard](https://vibedrift.ai/dashboard) when you're logged in:
|
|
186
|
+
|
|
187
|
+
- **Project overview** — score trends, sparklines, grade history
|
|
188
|
+
- **Scan detail** — embedded HTML report, export (JSON/CSV/DOCX), share via public link
|
|
189
|
+
- **Billing** — manage subscription, cancel/switch plans, view credits
|
|
190
|
+
- **Settings** — API tokens, preferences, account management
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Pricing
|
|
195
|
+
|
|
196
|
+
| Tier | Price | What you get |
|
|
197
|
+
|------|-------|-------------|
|
|
198
|
+
| **Free** | $0 | Unlimited local scans + 1 free deep scan on signup |
|
|
199
|
+
| **Per scan** | $5/scan | One-time deep scan credit (Claude AI + ML embeddings) |
|
|
200
|
+
| **Pro** | $29/month | Unlimited deep scans + GitHub Action + dashboard |
|
|
201
|
+
| **Team** | $99/month | Everything in Pro + team features + API access |
|
|
202
|
+
|
|
203
|
+
See [vibedrift.ai/#pricing](https://vibedrift.ai/#pricing) for details.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
127
207
|
## Supported Languages
|
|
128
208
|
|
|
129
209
|
JavaScript · TypeScript · Python · Go · Rust
|
|
@@ -139,6 +219,18 @@ JavaScript · TypeScript · Python · Go · Rust
|
|
|
139
219
|
|
|
140
220
|
---
|
|
141
221
|
|
|
222
|
+
## Feedback
|
|
223
|
+
|
|
224
|
+
Found a bug? Have a feature request? Send it directly from the CLI:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
vibedrift feedback "the naming analyzer flags Go acronyms incorrectly"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Feedback goes straight to the maintainer. If you're logged in, your account email is attached so we can follow up. Anonymous feedback works too.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
142
234
|
## License
|
|
143
235
|
|
|
144
236
|
VibeDrift is proprietary software. Free to install and run for personal and internal commercial use; see [LICENSE](./LICENSE) for full terms.
|
|
@@ -155,5 +247,6 @@ For commercial licensing, partnerships, or enterprise terms: **sami.ahmadkhan12@
|
|
|
155
247
|
|
|
156
248
|
## Links
|
|
157
249
|
|
|
158
|
-
- **Website:** https://vibedrift.ai
|
|
250
|
+
- **Website:** [vibedrift.ai](https://vibedrift.ai)
|
|
251
|
+
- **Dashboard:** [vibedrift.ai/dashboard](https://vibedrift.ai/dashboard)
|
|
159
252
|
- **Issues / Support:** sami.ahmadkhan12@gmail.com
|
package/dist/index.js
CHANGED
|
@@ -6802,7 +6802,7 @@ function buildAiSummaryWidget(result) {
|
|
|
6802
6802
|
return `<section class="section" style="margin-bottom:32px">
|
|
6803
6803
|
<div style="background:rgba(255,208,0,0.03);border:1px solid var(--border);border-radius:0;padding:24px 28px;position:relative;overflow:hidden">
|
|
6804
6804
|
<div style="position:absolute;top:0;left:0;width:3px;height:100%;background:var(--border)"></div>
|
|
6805
|
-
<div style="display:flex;align-items:flex-start;gap:20px;flex-wrap:wrap">
|
|
6805
|
+
<div class="score-layout" style="display:flex;align-items:flex-start;gap:20px;flex-wrap:wrap">
|
|
6806
6806
|
<div style="flex:1;min-width:280px">
|
|
6807
6807
|
<div style="display:flex;align-items:center;gap:8px;margin-bottom:10px">
|
|
6808
6808
|
<span style="font-size:16px">🤖</span>
|
|
@@ -6844,7 +6844,7 @@ function buildScoreSection(result) {
|
|
|
6844
6844
|
}).join("");
|
|
6845
6845
|
return `<section class="section">
|
|
6846
6846
|
<div class="label">SCORE OVERVIEW</div>
|
|
6847
|
-
<div style="display:flex;gap:40px;align-items:flex-start;flex-wrap:wrap">
|
|
6847
|
+
<div class="score-layout" style="display:flex;gap:40px;align-items:flex-start;flex-wrap:wrap">
|
|
6848
6848
|
<div style="text-align:center;min-width:120px">
|
|
6849
6849
|
<div class="mono" style="font-size:72px;font-weight:800;color:${color};line-height:1">${compositeScore}</div>
|
|
6850
6850
|
<div class="mono" style="font-size:16px;color:var(--text-tertiary)">/ ${maxCompositeScore}</div>
|
|
@@ -6858,7 +6858,7 @@ function buildRadarSection(result) {
|
|
|
6858
6858
|
const cats = getDriftCats(result);
|
|
6859
6859
|
const n = cats.length;
|
|
6860
6860
|
if (n === 0) return "";
|
|
6861
|
-
const cx =
|
|
6861
|
+
const cx = 260, cy = 200, r = 130, step = 2 * Math.PI / n;
|
|
6862
6862
|
let grid = "", dots = "", labels = "";
|
|
6863
6863
|
const pts = [];
|
|
6864
6864
|
for (const ring of [0.25, 0.5, 0.75, 1]) {
|
|
@@ -6875,14 +6875,14 @@ function buildRadarSection(result) {
|
|
|
6875
6875
|
const px = cx + r * ratio * Math.cos(a), py = cy + r * ratio * Math.sin(a);
|
|
6876
6876
|
pts.push(`${px},${py}`);
|
|
6877
6877
|
dots += `<circle cx="${px}" cy="${py}" r="5" fill="var(--text-secondary)" stroke="var(--bg-page)" stroke-width="2"/>`;
|
|
6878
|
-
const labelDist = r +
|
|
6878
|
+
const labelDist = r + 35;
|
|
6879
6879
|
const lx = cx + labelDist * Math.cos(a), ly = cy + labelDist * Math.sin(a);
|
|
6880
6880
|
const anchor = Math.abs(Math.cos(a)) < 0.3 ? "middle" : Math.cos(a) > 0 ? "start" : "end";
|
|
6881
6881
|
const { color: catColor } = gradeFor(cats[i].score, cats[i].max);
|
|
6882
6882
|
labels += `<text x="${lx}" y="${ly - 7}" fill="${catColor}" font-size="12" font-weight="600" font-family="-apple-system,sans-serif" text-anchor="${anchor}" dominant-baseline="middle">${esc(cats[i].shortName)}</text>`;
|
|
6883
6883
|
labels += `<text x="${lx}" y="${ly + 8}" fill="#5A6A7E" font-size="11" font-weight="500" font-family="'SF Mono',Consolas,monospace" text-anchor="${anchor}" dominant-baseline="middle">${cats[i].score}/${cats[i].max} ${cats[i].findings > 0 ? "(" + cats[i].findings + " issues)" : ""}</text>`;
|
|
6884
6884
|
}
|
|
6885
|
-
const radar = `<svg viewBox="0 0
|
|
6885
|
+
const radar = `<svg viewBox="0 0 520 440" style="width:100%;max-width:560px;height:auto;margin:0 auto;display:block">${grid}<polygon points="${pts.join(" ")}" fill="rgba(255,208,0,0.04)" stroke="rgba(255,208,0,0.3)" stroke-width="1.5"/>${dots}${labels}</svg>`;
|
|
6886
6886
|
const weakest = [...cats].sort((a, b) => {
|
|
6887
6887
|
const pctA = a.max > 0 ? a.score / a.max : 1;
|
|
6888
6888
|
const pctB = b.max > 0 ? b.score / b.max : 1;
|
|
@@ -7475,9 +7475,73 @@ th[data-sort]:hover { color: var(--text-primary); }
|
|
|
7475
7475
|
::-webkit-scrollbar-thumb { background: #3A3A3D; }
|
|
7476
7476
|
::-webkit-scrollbar-thumb:hover { background: #555; }
|
|
7477
7477
|
@media (max-width: 768px) {
|
|
7478
|
-
.page { padding:
|
|
7479
|
-
.
|
|
7478
|
+
.page { padding: 16px 10px; }
|
|
7479
|
+
.section { margin-bottom: 28px; }
|
|
7480
|
+
.label { font-size: 10px; letter-spacing: 1.5px; margin-bottom: 10px; }
|
|
7481
|
+
|
|
7482
|
+
/* Score hero: stack vertically */
|
|
7483
|
+
.score-layout { flex-direction: column !important; gap: 16px !important; }
|
|
7484
|
+
.score-layout > div { min-width: 0 !important; width: 100% !important; }
|
|
7485
|
+
|
|
7486
|
+
/* Category bars: stack, remove min-widths */
|
|
7487
|
+
.score-layout [style*="min-width:300px"],
|
|
7488
|
+
.score-layout [style*="min-width:280px"],
|
|
7489
|
+
.score-layout [style*="min-width:200px"],
|
|
7490
|
+
.score-layout [style*="min-width:120px"] {
|
|
7491
|
+
min-width: 0 !important; width: 100% !important;
|
|
7492
|
+
}
|
|
7493
|
+
|
|
7494
|
+
/* Radar chart: constrain to viewport */
|
|
7495
|
+
svg[viewBox] { max-width: 100% !important; }
|
|
7496
|
+
|
|
7497
|
+
/* Strongest/Weakest cards: 2-col, tighter */
|
|
7498
|
+
.section > div[style*="display:flex"][style*="gap:12px"] {
|
|
7499
|
+
gap: 8px !important;
|
|
7500
|
+
}
|
|
7501
|
+
.section > div[style*="display:flex"] > div[style*="min-width:160px"] {
|
|
7502
|
+
min-width: 0 !important; flex: 1 !important;
|
|
7503
|
+
}
|
|
7504
|
+
|
|
7505
|
+
/* Findings list: tighter padding */
|
|
7506
|
+
details > div { padding: 8px 10px !important; }
|
|
7507
|
+
details summary { padding: 10px 12px !important; font-size: 13px !important; }
|
|
7508
|
+
|
|
7509
|
+
/* File ranking table: horizontal scroll */
|
|
7510
|
+
table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; white-space: nowrap; }
|
|
7511
|
+
table th, table td { padding: 5px 8px !important; font-size: 11px !important; }
|
|
7512
|
+
|
|
7513
|
+
/* Code snippets: wrap text */
|
|
7514
|
+
pre, code { white-space: pre-wrap !important; word-break: break-word !important; font-size: 12px !important; }
|
|
7515
|
+
|
|
7516
|
+
/* Drift coherence bars: full width */
|
|
7517
|
+
.section div[style*="display:flex"][style*="gap:40px"] {
|
|
7518
|
+
flex-direction: column !important; gap: 16px !important;
|
|
7519
|
+
}
|
|
7520
|
+
|
|
7521
|
+
/* Summary + AI section: stack */
|
|
7522
|
+
.section div[style*="display:flex"][style*="gap:20px"] {
|
|
7523
|
+
flex-direction: column !important; gap: 12px !important;
|
|
7524
|
+
}
|
|
7525
|
+
|
|
7526
|
+
/* Sticky header: tighter padding */
|
|
7527
|
+
.sticky-header { padding: 0 12px; font-size: 12px; }
|
|
7480
7528
|
.sticky-project { display: none !important; }
|
|
7529
|
+
|
|
7530
|
+
/* Export buttons: smaller */
|
|
7531
|
+
.export-btn { padding: 5px 10px; font-size: 11px; }
|
|
7532
|
+
|
|
7533
|
+
/* Code DNA / ML sections: reduce gap */
|
|
7534
|
+
.section div[style*="gap:10px"] { gap: 6px !important; }
|
|
7535
|
+
|
|
7536
|
+
/* Hide long file paths, truncate */
|
|
7537
|
+
td[data-scroll-to] { max-width: 140px !important; }
|
|
7538
|
+
}
|
|
7539
|
+
@media (max-width: 480px) {
|
|
7540
|
+
.page { padding: 12px 8px; }
|
|
7541
|
+
body { font-size: 13px; }
|
|
7542
|
+
.label { font-size: 9px; }
|
|
7543
|
+
.sticky-header { height: 38px; }
|
|
7544
|
+
table th, table td { padding: 4px 6px !important; font-size: 10px !important; }
|
|
7481
7545
|
}
|
|
7482
7546
|
@media print {
|
|
7483
7547
|
body { background: #fff; color: #111; font-size: 11px; line-height: 1.4; }
|