sublyzer-snapshot 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -193
- package/dist/cli.js +83 -38
- package/dist/cli.js.map +1 -1
- package/dist/commands/ci.d.ts.map +1 -1
- package/dist/commands/ci.js +15 -14
- package/dist/commands/ci.js.map +1 -1
- package/dist/commands/compare.d.ts +1 -0
- package/dist/commands/compare.d.ts.map +1 -1
- package/dist/commands/compare.js +14 -8
- package/dist/commands/compare.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +47 -45
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +70 -28
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/open.d.ts.map +1 -1
- package/dist/commands/open.js +6 -1
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +4 -1
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/report.d.ts +1 -0
- package/dist/commands/report.d.ts.map +1 -1
- package/dist/commands/report.js +19 -19
- package/dist/commands/report.js.map +1 -1
- package/dist/commands/run.d.ts +5 -12
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +12 -90
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/scan.d.ts +13 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +17 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +31 -22
- package/dist/commands/status.js.map +1 -1
- package/dist/config.d.ts +17 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +27 -4
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +4 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/detect/scan-target.d.ts +13 -0
- package/dist/detect/scan-target.d.ts.map +1 -0
- package/dist/detect/scan-target.js +95 -0
- package/dist/detect/scan-target.js.map +1 -0
- package/dist/report/markdown.d.ts +1 -1
- package/dist/report/markdown.d.ts.map +1 -1
- package/dist/report/markdown.js +5 -0
- package/dist/report/markdown.js.map +1 -1
- package/dist/scan/bundle-size.d.ts +12 -0
- package/dist/scan/bundle-size.d.ts.map +1 -0
- package/dist/scan/bundle-size.js +50 -0
- package/dist/scan/bundle-size.js.map +1 -0
- package/dist/scan/execute.d.ts +28 -0
- package/dist/scan/execute.d.ts.map +1 -0
- package/dist/scan/execute.js +135 -0
- package/dist/scan/execute.js.map +1 -0
- package/dist/scan/history.d.ts +5 -5
- package/dist/scan/history.d.ts.map +1 -1
- package/dist/scan/history.js +15 -15
- package/dist/scan/history.js.map +1 -1
- package/dist/scan/snapshot.d.ts +8 -0
- package/dist/scan/snapshot.d.ts.map +1 -1
- package/dist/scan/snapshot.js +37 -9
- package/dist/scan/snapshot.js.map +1 -1
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -2,35 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
# Sublyzer Snapshot
|
|
4
4
|
|
|
5
|
-
<img src="./Sublyzer1.png" alt="Sublyzer" width="96" />
|
|
5
|
+
<img src="./Sublyzer1.png" alt="Sublyzer Snapshot" width="96" />
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**Local project health scanner for any Node.js codebase.**
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Works **standalone** — no account required. Optionally sync to [Sublyzer](https://sublyzer.com) cloud when you want a live dashboard.
|
|
10
10
|
|
|
11
11
|
<br />
|
|
12
12
|
|
|
13
|
-
[](https://www.npmjs.com/package/sublyzer-snapshot)
|
|
14
14
|
[](LICENSE)
|
|
15
15
|
[](https://nodejs.org)
|
|
16
|
-
[](https://www.typescriptlang.org)
|
|
17
|
-
[](https://sublyzer.com)
|
|
18
16
|
|
|
19
17
|
<br />
|
|
20
18
|
|
|
21
|
-
[`Quick Start`](#-quick-start) · [`
|
|
19
|
+
[`Quick Start`](#-quick-start) · [`Standalone vs Cloud`](#-standalone-vs-cloud) · [`Monorepos`](#-monorepos) · [`Commands`](#-commands) · [`Roadmap`](#-roadmap)
|
|
22
20
|
|
|
23
21
|
<br />
|
|
24
22
|
|
|
25
23
|
```
|
|
26
|
-
$ npx sublyzer-snapshot
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Stack:
|
|
30
|
-
Health:
|
|
31
|
-
Routes:
|
|
32
|
-
|
|
33
|
-
✓
|
|
24
|
+
$ npx sublyzer-snapshot scan
|
|
25
|
+
|
|
26
|
+
Scan root: frontend (auto-selected)
|
|
27
|
+
Stack: Next.js (high)
|
|
28
|
+
Health: [████████░░] 84/100 grade B
|
|
29
|
+
Routes: 42
|
|
30
|
+
Build output: 12.4 MB (.next)
|
|
31
|
+
✓ Saved to .sublyzer/ (local)
|
|
34
32
|
```
|
|
35
33
|
|
|
36
34
|
</div>
|
|
@@ -39,268 +37,191 @@ Scan routes, dependencies, and vulnerabilities locally — get a health score
|
|
|
39
37
|
|
|
40
38
|
## ✨ Introduction
|
|
41
39
|
|
|
42
|
-
**Sublyzer Snapshot** is an open-source CLI that
|
|
40
|
+
**Sublyzer Snapshot** is an open-source CLI that scans your repo and answers:
|
|
43
41
|
|
|
44
|
-
> *
|
|
42
|
+
> *How healthy is this project right now?*
|
|
45
43
|
|
|
46
|
-
|
|
44
|
+
It runs **entirely on your machine**: stack detection, routes, dependency audit, outdated packages, build size, git metadata, and a **0–100 health score**.
|
|
47
45
|
|
|
48
|
-
|
|
46
|
+
**Sublyzer cloud is optional** — use it when you want events in a shared dashboard, agents (Hermes), or team visibility. Without cloud, you still get reports, history, CI gates, and compare diffs.
|
|
49
47
|
|
|
50
48
|
---
|
|
51
49
|
|
|
52
|
-
##
|
|
50
|
+
## 🔀 Standalone vs Cloud
|
|
53
51
|
|
|
54
|
-
|
|
|
55
|
-
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
| **Trend tracking** | `compare` shows what changed since last scan |
|
|
61
|
-
| **Sublyzer onboarding** | Data in your dashboard before installing the browser SDK |
|
|
52
|
+
| | **Standalone (default)** | **Cloud (optional)** |
|
|
53
|
+
|---|--------------------------|----------------------|
|
|
54
|
+
| Account | None | [Sublyzer](https://sublyzer.com) integration code |
|
|
55
|
+
| Command | `npx sublyzer-snapshot scan` | `init --code …` then `run --push` |
|
|
56
|
+
| Output | Terminal + `.sublyzer/` history | + Sublyzer dashboard |
|
|
57
|
+
| CI | `scan --fail-on high` | + optional push via secret |
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|--------|---------------------------|
|
|
67
|
-
| Sentry + Dependabot + manual spreadsheet | One CLI, one dashboard |
|
|
68
|
-
| 45+ min setup | ~30 seconds |
|
|
69
|
-
| No unified health score | 0–100 score with grade A–F |
|
|
70
|
-
| Hard to show clients "project status" | Export `report.md` in one command |
|
|
71
|
-
|
|
72
|
-
---
|
|
59
|
+
```bash
|
|
60
|
+
# Standalone — zero setup
|
|
61
|
+
npx sublyzer-snapshot scan
|
|
73
62
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
flowchart LR
|
|
78
|
-
A[Your repo] --> B[sublyzer-snapshot run]
|
|
79
|
-
B --> C[Local scan]
|
|
80
|
-
C --> D[Routes · deps · audit · git]
|
|
81
|
-
D --> E[Health score 0-100]
|
|
82
|
-
E --> F[Sublyzer API]
|
|
83
|
-
F --> G[Dashboard]
|
|
84
|
-
G --> H[Hermes / agents / team]
|
|
85
|
-
|
|
86
|
-
style A fill:#1e293b,stroke:#475569,color:#f8fafc
|
|
87
|
-
style G fill:#2563eb,stroke:#1d4ed8,color:#fff
|
|
88
|
-
style E fill:#22c55e,stroke:#16a34a,color:#fff
|
|
63
|
+
# Optional cloud link
|
|
64
|
+
npx sublyzer-snapshot init --code YOUR_24_CHAR_CODE -y
|
|
65
|
+
npx sublyzer-snapshot run --push
|
|
89
66
|
```
|
|
90
67
|
|
|
91
|
-
1. **`init`** — Links your project folder to a Sublyzer integration (24-char code).
|
|
92
|
-
2. **`run`** — Scans locally: framework, routes, `npm audit`, outdated packages, git metadata.
|
|
93
|
-
3. **Score** — Computes health grade from vulnerabilities, routes, env hygiene, and more.
|
|
94
|
-
4. **Push** — Sends events to `POST /data-collection/collect-batch` on Sublyzer.
|
|
95
|
-
5. **Dashboard** — Data appears under your integration; optional SDK for live telemetry later.
|
|
96
|
-
|
|
97
|
-
Scan history is stored in `.sublyzer/` (gitignored automatically) so `compare` can show diffs over time.
|
|
98
|
-
|
|
99
68
|
---
|
|
100
69
|
|
|
101
70
|
## 🚀 Quick start
|
|
102
71
|
|
|
103
|
-
###
|
|
104
|
-
|
|
105
|
-
- **Node.js 18+**
|
|
106
|
-
- **npm** (for audit/outdated; optional with `--skip-audit`)
|
|
107
|
-
- A [Sublyzer](https://sublyzer.com) account + **integration code** (24 chars, from Dashboard → Integrations)
|
|
108
|
-
|
|
109
|
-
### Install & run
|
|
72
|
+
### Install (use npx — recommended)
|
|
110
73
|
|
|
111
74
|
```bash
|
|
112
|
-
|
|
113
|
-
npx sublyzer-snapshot init
|
|
114
|
-
|
|
115
|
-
# 2. Scan and push
|
|
116
|
-
npx sublyzer-snapshot run
|
|
117
|
-
|
|
118
|
-
# 3. Open dashboard
|
|
119
|
-
npx sublyzer-snapshot open
|
|
75
|
+
npx sublyzer-snapshot@latest --version
|
|
120
76
|
```
|
|
121
77
|
|
|
122
|
-
|
|
78
|
+
Do **not** run `npm i sublyzer-snapshot` in random folders — use `npx` to avoid unrelated peer dependency conflicts.
|
|
79
|
+
|
|
80
|
+
### Scan any project
|
|
123
81
|
|
|
124
82
|
```bash
|
|
125
|
-
|
|
126
|
-
npx sublyzer-snapshot
|
|
127
|
-
npx sublyzer-snapshot
|
|
83
|
+
cd your-project
|
|
84
|
+
npx sublyzer-snapshot scan
|
|
85
|
+
npx sublyzer-snapshot report --out HEALTH.md
|
|
86
|
+
npx sublyzer-snapshot compare
|
|
128
87
|
```
|
|
129
88
|
|
|
130
|
-
###
|
|
89
|
+
### Save preferences (local)
|
|
131
90
|
|
|
132
91
|
```bash
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
node dist/cli.js init --code YOUR_CODE -y
|
|
136
|
-
node dist/cli.js run --dry-run
|
|
92
|
+
npx sublyzer-snapshot init --local
|
|
93
|
+
npx sublyzer-snapshot run
|
|
137
94
|
```
|
|
138
95
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
## 🧰 Commands
|
|
142
|
-
|
|
143
|
-
| Command | Description |
|
|
144
|
-
|---------|-------------|
|
|
145
|
-
| `init` | Detect stack, validate code, write `.sublyzer/snapshot.json` |
|
|
146
|
-
| `run` | Full scan + push to Sublyzer |
|
|
147
|
-
| `report` | Generate Markdown health report (`--out report.md`) |
|
|
148
|
-
| `compare` | Diff routes, vulns, and score vs previous scan |
|
|
149
|
-
| `ci` | Print or write GitHub Actions workflow |
|
|
150
|
-
| `status` | Show linked integration + last scan |
|
|
151
|
-
| `doctor` | Verify config, API, integration code, read key |
|
|
152
|
-
| `pull` | Fetch data back via public read API (needs `apiReadKey`) |
|
|
153
|
-
| `open` | Open integration in browser |
|
|
154
|
-
|
|
155
|
-
### Common flags
|
|
96
|
+
### Optional cloud sync
|
|
156
97
|
|
|
157
98
|
```bash
|
|
158
|
-
sublyzer-snapshot
|
|
159
|
-
sublyzer-snapshot run --
|
|
160
|
-
sublyzer-snapshot
|
|
161
|
-
sublyzer-snapshot run --json # CI-friendly JSON output
|
|
162
|
-
|
|
163
|
-
sublyzer-snapshot report --out HEALTH.md
|
|
164
|
-
sublyzer-snapshot compare --rescan
|
|
165
|
-
sublyzer-snapshot ci --out .github/workflows/sublyzer-snapshot.yml
|
|
99
|
+
npx sublyzer-snapshot init --code YOUR_24_CHAR_CODE -y
|
|
100
|
+
npx sublyzer-snapshot run --push
|
|
101
|
+
npx sublyzer-snapshot open
|
|
166
102
|
```
|
|
167
103
|
|
|
168
104
|
---
|
|
169
105
|
|
|
170
|
-
##
|
|
106
|
+
## 📦 Monorepos
|
|
171
107
|
|
|
172
|
-
|
|
108
|
+
Snapshot **auto-picks** the best package in monorepos (npm/pnpm workspaces, `frontend/`, `backend/`, etc.).
|
|
173
109
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
| High CVEs | −10 each (max −30) |
|
|
178
|
-
| Moderate CVEs | −3 each |
|
|
179
|
-
| Web stack with 0 routes detected | −8 |
|
|
180
|
-
| Dirty git working tree | −3 |
|
|
181
|
-
| Missing `.env.example` | −2 |
|
|
182
|
-
| Major outdated packages | −3 each |
|
|
183
|
-
|
|
184
|
-
Example terminal output:
|
|
110
|
+
```bash
|
|
111
|
+
# From repo root — auto-selects e.g. frontend/
|
|
112
|
+
npx sublyzer-snapshot scan
|
|
185
113
|
|
|
186
|
-
|
|
187
|
-
|
|
114
|
+
# Force a subfolder
|
|
115
|
+
npx sublyzer-snapshot scan --path backend
|
|
116
|
+
npx sublyzer-snapshot init --local --path frontend
|
|
188
117
|
```
|
|
189
118
|
|
|
190
|
-
|
|
119
|
+
On `init`, other scannable packages in the repo are listed as hints.
|
|
191
120
|
|
|
192
121
|
---
|
|
193
122
|
|
|
194
|
-
##
|
|
195
|
-
|
|
196
|
-
| Stack | Signals |
|
|
197
|
-
|-------|---------|
|
|
198
|
-
| **Next.js** | `next` in package.json, `app/` & `pages/` routes |
|
|
199
|
-
| **NestJS** | `@nestjs/core`, decorator routes |
|
|
200
|
-
| **Express / Fastify** | Route patterns in source |
|
|
201
|
-
| **Remix / Nuxt / SvelteKit** | package.json dependencies |
|
|
202
|
-
| **React / Vue / Node** | Fallback detection |
|
|
203
|
-
| **Monorepos** | npm & pnpm workspaces |
|
|
204
|
-
|
|
205
|
-
Each `run` sends:
|
|
206
|
-
|
|
207
|
-
- `custom_event` → `project_snapshot` (stack, routes, git, audit summary)
|
|
208
|
-
- `vulnerability` → top npm audit findings
|
|
209
|
-
- `performance` → health score + route count
|
|
210
|
-
|
|
211
|
-
---
|
|
212
|
-
|
|
213
|
-
## 🔄 CI/CD
|
|
123
|
+
## 🧰 Commands
|
|
214
124
|
|
|
215
|
-
|
|
125
|
+
| Command | Description |
|
|
126
|
+
|---------|-------------|
|
|
127
|
+
| **`scan`** | Local scan — **no init, no account** |
|
|
128
|
+
| `init` | Save config — `--local` or `--code` for cloud |
|
|
129
|
+
| `run` | Scan + history (pushes in cloud mode or with `--push`) |
|
|
130
|
+
| `report` | Markdown report (`--out file.md`) |
|
|
131
|
+
| `compare` | Diff vs previous scan |
|
|
132
|
+
| `doctor` | Verify Node, scan target, optional cloud |
|
|
133
|
+
| `status` | Config + last scan |
|
|
134
|
+
| `ci` | GitHub Actions template |
|
|
135
|
+
| `pull` / `open` | Cloud only (read API / dashboard) |
|
|
136
|
+
|
|
137
|
+
### Flags
|
|
216
138
|
|
|
217
139
|
```bash
|
|
218
|
-
sublyzer-snapshot
|
|
140
|
+
npx sublyzer-snapshot scan --path frontend
|
|
141
|
+
npx sublyzer-snapshot scan --fail-on high --json
|
|
142
|
+
npx sublyzer-snapshot run --local # never push
|
|
143
|
+
npx sublyzer-snapshot run --push # force cloud push
|
|
144
|
+
npx sublyzer-snapshot run --skip-audit # faster
|
|
219
145
|
```
|
|
220
146
|
|
|
221
|
-
|
|
147
|
+
---
|
|
222
148
|
|
|
223
|
-
|
|
149
|
+
## 📊 What gets scanned
|
|
224
150
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
151
|
+
- **Stack** — Next.js, NestJS, Express, Fastify, Remix, Nuxt, SvelteKit, React, Vue
|
|
152
|
+
- **Routes** — `app/` / `pages/` or source patterns
|
|
153
|
+
- **Dependencies** + `npm audit` + outdated packages
|
|
154
|
+
- **Build size** — `dist/`, `.next/`, `build/` folders
|
|
155
|
+
- **Git** — branch, commit, dirty state
|
|
156
|
+
- **Health score** — 0–100, grade A–F
|
|
228
157
|
|
|
229
|
-
|
|
158
|
+
---
|
|
230
159
|
|
|
231
|
-
|
|
160
|
+
## 🔄 CI/CD
|
|
232
161
|
|
|
233
|
-
|
|
162
|
+
Local-only CI (no secrets):
|
|
234
163
|
|
|
235
|
-
|
|
164
|
+
```yaml
|
|
165
|
+
- run: npx sublyzer-snapshot@latest scan --fail-on high --json
|
|
166
|
+
```
|
|
236
167
|
|
|
237
|
-
|
|
168
|
+
Generate full workflow:
|
|
238
169
|
|
|
239
170
|
```bash
|
|
240
|
-
|
|
241
|
-
curl "https://api.sublyzer.com/integrations/{id}/read-access" \
|
|
242
|
-
-H "Authorization: Bearer YOUR_JWT"
|
|
243
|
-
|
|
244
|
-
# Or via CLI
|
|
245
|
-
sublyzer-snapshot pull --read-key YOUR_READ_KEY
|
|
171
|
+
npx sublyzer-snapshot ci --out .github/workflows/sublyzer-snapshot.yml
|
|
246
172
|
```
|
|
247
173
|
|
|
248
|
-
|
|
174
|
+
Optional cloud push when `SUBLYZER_INTEGRATION_CODE` secret is set.
|
|
249
175
|
|
|
250
176
|
---
|
|
251
177
|
|
|
252
178
|
## 🔐 Environment variables
|
|
253
179
|
|
|
254
|
-
| Variable |
|
|
255
|
-
|
|
256
|
-
| `SUBLYZER_INTEGRATION_CODE` |
|
|
257
|
-
| `SUBLYZER_READ_KEY` |
|
|
258
|
-
| `SUBLYZER_API_URL` |
|
|
259
|
-
| `SUBLYZER_DASHBOARD_URL` | No | Default: `https://sublyzer.com` |
|
|
260
|
-
|
|
261
|
-
> **Security:** `.sublyzer/snapshot.json` contains your integration code. It is auto-added to `.gitignore` on `init` — never commit it to public repos.
|
|
180
|
+
| Variable | When |
|
|
181
|
+
|----------|------|
|
|
182
|
+
| `SUBLYZER_INTEGRATION_CODE` | Cloud `init` |
|
|
183
|
+
| `SUBLYZER_READ_KEY` | Cloud `pull` |
|
|
184
|
+
| `SUBLYZER_API_URL` | Custom API (default: `https://api.sublyzer.com`) |
|
|
262
185
|
|
|
263
186
|
---
|
|
264
187
|
|
|
265
|
-
## 📁
|
|
188
|
+
## 📁 Local data
|
|
266
189
|
|
|
267
190
|
```
|
|
268
191
|
your-project/
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
├── src/
|
|
274
|
-
└── package.json
|
|
192
|
+
└── .sublyzer/ # gitignored on init
|
|
193
|
+
├── snapshot.json # config (local or cloud)
|
|
194
|
+
├── last-snapshot.json
|
|
195
|
+
└── history/ # for compare
|
|
275
196
|
```
|
|
276
197
|
|
|
277
198
|
---
|
|
278
199
|
|
|
279
200
|
## 🛣️ Roadmap
|
|
280
201
|
|
|
281
|
-
- [
|
|
282
|
-
- [
|
|
283
|
-
- [
|
|
284
|
-
- [
|
|
202
|
+
- [x] npm publish — [sublyzer-snapshot](https://www.npmjs.com/package/sublyzer-snapshot)
|
|
203
|
+
- [x] Standalone `scan` (no account)
|
|
204
|
+
- [x] Local vs cloud modes
|
|
205
|
+
- [x] Monorepo auto-target (`frontend/`, workspaces)
|
|
206
|
+
- [x] Build output size scan
|
|
207
|
+
- [x] Health score + compare + report + CI template
|
|
208
|
+
- [ ] `login` OAuth (no manual code paste)
|
|
209
|
+
- [ ] SARIF export for GitHub Security
|
|
210
|
+
- [ ] PR comment bot
|
|
211
|
+
- [ ] Python / Go stack detection
|
|
285
212
|
|
|
286
213
|
---
|
|
287
214
|
|
|
288
215
|
## 📄 License
|
|
289
216
|
|
|
290
|
-
MIT
|
|
217
|
+
MIT — see [LICENSE](./LICENSE).
|
|
291
218
|
|
|
292
219
|
---
|
|
293
220
|
|
|
294
221
|
<div align="center">
|
|
295
222
|
|
|
296
|
-
**[
|
|
297
|
-
|
|
298
|
-
<br />
|
|
299
|
-
|
|
300
|
-
If this saved you time, ⭐ star the repo — it helps other devs find it.
|
|
301
|
-
|
|
302
|
-
<br />
|
|
223
|
+
**[npm](https://www.npmjs.com/package/sublyzer-snapshot)** · **[Sublyzer Cloud](https://sublyzer.com)** · **[Docs](https://sublyzer.com/docs)**
|
|
303
224
|
|
|
304
|
-
<sub>
|
|
225
|
+
<sub>Standalone by default · Cloud when you need it</sub>
|
|
305
226
|
|
|
306
227
|
</div>
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,8 @@ import { runInit } from './commands/init.js';
|
|
|
8
8
|
import { runOpen } from './commands/open.js';
|
|
9
9
|
import { runPull } from './commands/pull.js';
|
|
10
10
|
import { runReport } from './commands/report.js';
|
|
11
|
-
import {
|
|
11
|
+
import { runRunCommand } from './commands/run.js';
|
|
12
|
+
import { runScanCommand } from './commands/scan.js';
|
|
12
13
|
import { runStatus } from './commands/status.js';
|
|
13
14
|
const program = new Command();
|
|
14
15
|
function handleError(e) {
|
|
@@ -17,24 +18,62 @@ function handleError(e) {
|
|
|
17
18
|
process.exit(1);
|
|
18
19
|
}
|
|
19
20
|
const FAIL_ON_LEVELS = ['critical', 'high', 'moderate', 'any'];
|
|
21
|
+
function sharedScanOptions(cmd) {
|
|
22
|
+
return cmd
|
|
23
|
+
.option('--path <dir>', 'Scan a subfolder (e.g. frontend, backend)')
|
|
24
|
+
.option('--skip-audit', 'Skip npm audit')
|
|
25
|
+
.option('--skip-outdated', 'Skip npm outdated check')
|
|
26
|
+
.option('--skip-bundle', 'Skip build output size scan')
|
|
27
|
+
.option('--json', 'JSON output')
|
|
28
|
+
.option('--fail-on <level>', 'Exit 1 on vulns: critical|high|moderate|any');
|
|
29
|
+
}
|
|
20
30
|
program
|
|
21
31
|
.name('sublyzer-snapshot')
|
|
22
|
-
.description('
|
|
32
|
+
.description('Local project health scanner — optional Sublyzer cloud sync')
|
|
23
33
|
.version(SDK_VERSION);
|
|
34
|
+
sharedScanOptions(program
|
|
35
|
+
.command('scan')
|
|
36
|
+
.description('Scan project locally (no account, no init required)')
|
|
37
|
+
.option('--push', 'Push to Sublyzer if cloud config exists'))
|
|
38
|
+
.action(async (opts) => {
|
|
39
|
+
try {
|
|
40
|
+
const failOn = FAIL_ON_LEVELS.includes(opts.failOn) ? opts.failOn : undefined;
|
|
41
|
+
const result = await runScanCommand({
|
|
42
|
+
path: opts.path,
|
|
43
|
+
push: opts.push,
|
|
44
|
+
skipAudit: opts.skipAudit,
|
|
45
|
+
skipOutdated: opts.skipOutdated,
|
|
46
|
+
skipBundle: opts.skipBundle,
|
|
47
|
+
json: opts.json,
|
|
48
|
+
failOn,
|
|
49
|
+
});
|
|
50
|
+
if (opts.json)
|
|
51
|
+
console.log(JSON.stringify(result, null, 2));
|
|
52
|
+
if (result.policyFailed)
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
handleError(e);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
24
59
|
program
|
|
25
60
|
.command('init')
|
|
26
|
-
.description('
|
|
27
|
-
.option('--
|
|
28
|
-
.option('--
|
|
29
|
-
.option('--
|
|
30
|
-
.option('--
|
|
31
|
-
.option('-
|
|
61
|
+
.description('Save scan preferences — local-only or link Sublyzer cloud')
|
|
62
|
+
.option('--local', 'Local mode only (no Sublyzer account)')
|
|
63
|
+
.option('--code <code>', 'Cloud: integration code (24 chars)')
|
|
64
|
+
.option('--read-key <key>', 'Cloud: apiReadKey for pull')
|
|
65
|
+
.option('--path <dir>', 'Preferred scan directory in monorepos')
|
|
66
|
+
.option('--api-url <url>', 'Sublyzer API URL')
|
|
67
|
+
.option('--dashboard-url <url>', 'Dashboard URL')
|
|
68
|
+
.option('-y, --yes', 'Non-interactive')
|
|
32
69
|
.option('--skip-gitignore', 'Do not update .gitignore')
|
|
33
70
|
.action(async (opts) => {
|
|
34
71
|
try {
|
|
35
72
|
await runInit({
|
|
73
|
+
local: opts.local,
|
|
36
74
|
code: opts.code,
|
|
37
75
|
readKey: opts.readKey,
|
|
76
|
+
path: opts.path,
|
|
38
77
|
apiUrl: opts.apiUrl,
|
|
39
78
|
dashboardUrl: opts.dashboardUrl,
|
|
40
79
|
yes: opts.yes,
|
|
@@ -45,21 +84,23 @@ program
|
|
|
45
84
|
handleError(e);
|
|
46
85
|
}
|
|
47
86
|
});
|
|
48
|
-
program
|
|
87
|
+
sharedScanOptions(program
|
|
49
88
|
.command('run')
|
|
50
|
-
.description('Scan
|
|
51
|
-
.option('--dry-run', 'Scan
|
|
52
|
-
.option('--
|
|
53
|
-
.option('--
|
|
54
|
-
.option('--json', 'Output machine-readable JSON (CI friendly)')
|
|
55
|
-
.option('--fail-on <level>', 'Exit 1 if vulns at level: critical|high|moderate|any')
|
|
89
|
+
.description('Scan + save history (pushes only in cloud mode or with --push)')
|
|
90
|
+
.option('--dry-run', 'Scan without saving push')
|
|
91
|
+
.option('--push', 'Force push to Sublyzer cloud')
|
|
92
|
+
.option('--local', 'Force local-only (no push)'))
|
|
56
93
|
.action(async (opts) => {
|
|
57
94
|
try {
|
|
58
95
|
const failOn = FAIL_ON_LEVELS.includes(opts.failOn) ? opts.failOn : undefined;
|
|
59
|
-
const result = await
|
|
96
|
+
const result = await runRunCommand({
|
|
97
|
+
path: opts.path,
|
|
60
98
|
dryRun: opts.dryRun,
|
|
99
|
+
push: opts.push,
|
|
100
|
+
local: opts.local,
|
|
61
101
|
skipAudit: opts.skipAudit,
|
|
62
102
|
skipOutdated: opts.skipOutdated,
|
|
103
|
+
skipBundle: opts.skipBundle,
|
|
63
104
|
json: opts.json,
|
|
64
105
|
failOn,
|
|
65
106
|
});
|
|
@@ -74,8 +115,8 @@ program
|
|
|
74
115
|
});
|
|
75
116
|
program
|
|
76
117
|
.command('status')
|
|
77
|
-
.description('Show
|
|
78
|
-
.option('--json', '
|
|
118
|
+
.description('Show config and last scan')
|
|
119
|
+
.option('--json', 'JSON output')
|
|
79
120
|
.action(async (opts) => {
|
|
80
121
|
try {
|
|
81
122
|
const data = await runStatus({ json: opts.json });
|
|
@@ -88,8 +129,8 @@ program
|
|
|
88
129
|
});
|
|
89
130
|
program
|
|
90
131
|
.command('doctor')
|
|
91
|
-
.description('Verify
|
|
92
|
-
.option('--json', '
|
|
132
|
+
.description('Verify Node, scan target, optional cloud link')
|
|
133
|
+
.option('--json', 'JSON output')
|
|
93
134
|
.action(async (opts) => {
|
|
94
135
|
try {
|
|
95
136
|
const result = await runDoctor({ json: opts.json });
|
|
@@ -104,15 +145,17 @@ program
|
|
|
104
145
|
});
|
|
105
146
|
program
|
|
106
147
|
.command('compare')
|
|
107
|
-
.description('Diff
|
|
108
|
-
.option('--json', '
|
|
109
|
-
.option('--rescan', '
|
|
110
|
-
.option('--
|
|
148
|
+
.description('Diff vs previous scan')
|
|
149
|
+
.option('--json', 'JSON output')
|
|
150
|
+
.option('--rescan', 'Fresh scan before compare')
|
|
151
|
+
.option('--path <dir>', 'Scan path with --rescan')
|
|
152
|
+
.option('--skip-audit', 'Skip audit with --rescan')
|
|
111
153
|
.action(async (opts) => {
|
|
112
154
|
try {
|
|
113
155
|
const data = await runCompare({
|
|
114
156
|
json: opts.json,
|
|
115
157
|
rescan: opts.rescan,
|
|
158
|
+
path: opts.path,
|
|
116
159
|
skipAudit: opts.skipAudit,
|
|
117
160
|
});
|
|
118
161
|
if (opts.json)
|
|
@@ -124,16 +167,18 @@ program
|
|
|
124
167
|
});
|
|
125
168
|
program
|
|
126
169
|
.command('report')
|
|
127
|
-
.description('
|
|
128
|
-
.option('--out <file>', 'Write
|
|
129
|
-
.option('--rescan', '
|
|
130
|
-
.option('--
|
|
131
|
-
.option('--
|
|
170
|
+
.description('Markdown health report')
|
|
171
|
+
.option('--out <file>', 'Write to file')
|
|
172
|
+
.option('--rescan', 'Fresh scan')
|
|
173
|
+
.option('--path <dir>', 'Scan path with --rescan')
|
|
174
|
+
.option('--skip-audit', 'Skip audit')
|
|
175
|
+
.option('--json', 'JSON wrapper')
|
|
132
176
|
.action(async (opts) => {
|
|
133
177
|
try {
|
|
134
178
|
const out = await runReport({
|
|
135
179
|
out: opts.out,
|
|
136
180
|
rescan: opts.rescan,
|
|
181
|
+
path: opts.path,
|
|
137
182
|
skipAudit: opts.skipAudit,
|
|
138
183
|
json: opts.json,
|
|
139
184
|
});
|
|
@@ -146,9 +191,9 @@ program
|
|
|
146
191
|
});
|
|
147
192
|
program
|
|
148
193
|
.command('ci')
|
|
149
|
-
.description('
|
|
150
|
-
.option('--out <path>', 'Write workflow file
|
|
151
|
-
.option('--print', 'Print
|
|
194
|
+
.description('GitHub Actions workflow template')
|
|
195
|
+
.option('--out <path>', 'Write workflow file')
|
|
196
|
+
.option('--print', 'Print to stdout')
|
|
152
197
|
.action(async (opts) => {
|
|
153
198
|
try {
|
|
154
199
|
await runCi({ out: opts.out, print: opts.print ?? !opts.out });
|
|
@@ -159,12 +204,12 @@ program
|
|
|
159
204
|
});
|
|
160
205
|
program
|
|
161
206
|
.command('pull')
|
|
162
|
-
.description('Fetch
|
|
163
|
-
.option('--read-key <key>', 'apiReadKey
|
|
207
|
+
.description('Fetch data from Sublyzer cloud (requires apiReadKey)')
|
|
208
|
+
.option('--read-key <key>', 'apiReadKey')
|
|
164
209
|
.option('--limit <n>', 'Max events', (v) => parseInt(v, 10))
|
|
165
|
-
.option('--window-days <n>', 'Lookback
|
|
166
|
-
.option('--include <csv>', '
|
|
167
|
-
.option('--json', '
|
|
210
|
+
.option('--window-days <n>', 'Lookback days', (v) => parseInt(v, 10))
|
|
211
|
+
.option('--include <csv>', 'API include list')
|
|
212
|
+
.option('--json', 'JSON output')
|
|
168
213
|
.action(async (opts) => {
|
|
169
214
|
try {
|
|
170
215
|
const data = await runPull({
|
|
@@ -183,7 +228,7 @@ program
|
|
|
183
228
|
});
|
|
184
229
|
program
|
|
185
230
|
.command('open')
|
|
186
|
-
.description('Open
|
|
231
|
+
.description('Open Sublyzer dashboard (cloud mode only)')
|
|
187
232
|
.action(async () => {
|
|
188
233
|
try {
|
|
189
234
|
await runOpen();
|