aztrx-cli 0.1.1 → 0.2.1
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 +137 -99
- package/dist/cli/help.js +85 -0
- package/dist/cli.js +150 -33
- package/dist/core/auth.js +76 -0
- package/dist/core/heal/apply.js +52 -0
- package/dist/core/modernize.js +144 -0
- package/dist/core/orchestrator.js +52 -100
- package/dist/core/prompt.js +22 -0
- package/dist/core/summarize.js +173 -0
- package/dist/core/swarm.js +235 -0
- package/dist/core/version.js +15 -0
- package/dist/ui/app.js +3 -1
- package/package.json +24 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# <img src="media/logo.svg" width="28" height="32" alt="Aztrx logo" align="absmiddle" /> Aztrx AI
|
|
2
2
|
|
|
3
|
-
> **Autonomous runtime stress-tester, deterministic bug minimizer, and self-healing engine for web applications.**
|
|
3
|
+
> **Autonomous runtime stress-tester, deterministic bug minimizer, human-language explainer, and self-healing engine for web applications.**
|
|
4
4
|
|
|
5
5
|
[](https://nodejs.org)
|
|
6
6
|
[](LICENSE)
|
|
@@ -11,111 +11,132 @@ Aztrx AI drives your web app like a hostile user — clicking, entering boundary
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## Run it
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- **Safe by default.** A deny-by-default network guard blocks off-origin calls, and a destructive-action deny-list refuses to click "delete", "pay", or "logout".
|
|
16
|
+
```bash
|
|
17
|
+
npx aztrx-cli run http://localhost:3000
|
|
18
|
+
```
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
That's the whole setup — no install, no config, no account, no API key. Point it at your
|
|
21
|
+
running dev server and it finds the crashes. It drives Chromium through Playwright (the
|
|
22
|
+
first run downloads the browser automatically).
|
|
23
|
+
|
|
24
|
+
What that one command gives you:
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
- **Sees swallowed errors.** Error Boundaries and `window.onerror` miss the errors your app *catches*. Aztrx AI reads the real throw-site stack off the `Error` object — a crash you've never seen in your logs becomes a finding you can't ignore.
|
|
27
|
+
- **Proves, not reports.** Every crash/error finding ships with an executable `.spec.ts` repro and a flake-rate verdict — `[deterministic 5/5]`, `[flaky 3/5]`, or `[unreliable]`.
|
|
28
|
+
- **Safe by default.** A deny-by-default network guard blocks off-origin calls, a destructive-action deny-list refuses to click "delete", "pay", or "logout", and nothing leaves your machine unless you opt in.
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
More ways to run — all optional flags on top of the same command:
|
|
26
31
|
|
|
27
32
|
```bash
|
|
28
|
-
npx aztrx-cli run http://localhost:3000 # deterministic walk
|
|
29
33
|
npx aztrx-cli run http://localhost:3000 --fuzz # seeded chaos (replayable)
|
|
30
|
-
npx aztrx-cli run http://localhost:3000 --
|
|
31
|
-
npx aztrx-cli run http://localhost:3000 --http-fuzz
|
|
34
|
+
npx aztrx-cli run http://localhost:3000 --repro # minimize → compile → validate
|
|
35
|
+
npx aztrx-cli run http://localhost:3000 --http-fuzz # server-side 5xx hunt
|
|
32
36
|
```
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
Prefer a global install?
|
|
35
39
|
|
|
36
40
|
```bash
|
|
37
41
|
npm i -g aztrx-cli
|
|
38
|
-
aztrx-cli run http://localhost:3000
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Or install from source (contributors):
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
git clone https://github.com/DanisChaparov/aztrx
|
|
45
|
-
cd aztrx
|
|
46
|
-
npm install
|
|
47
|
-
npm run build
|
|
48
|
-
npm link # puts `aztrx-cli` on your PATH
|
|
42
|
+
aztrx-cli run http://localhost:3000
|
|
49
43
|
```
|
|
50
44
|
|
|
51
|
-
Aztrx AI drives Chromium through Playwright — the first run downloads the browser
|
|
52
|
-
automatically (`npx playwright install chromium` to force it).
|
|
53
|
-
|
|
54
45
|
---
|
|
55
46
|
|
|
56
|
-
##
|
|
57
|
-
|
|
58
|
-
### 1. Initialize configuration
|
|
47
|
+
## Fix it, not just find it
|
|
59
48
|
|
|
60
|
-
|
|
49
|
+
The only feature that needs a key. `--fix` hands the crash to an LLM and applies a
|
|
50
|
+
verified patch to your working tree. Set `ANTHROPIC_API_KEY` and run:
|
|
61
51
|
|
|
62
52
|
```bash
|
|
63
|
-
|
|
53
|
+
export ANTHROPIC_API_KEY="your-api-key"
|
|
54
|
+
npx aztrx-cli run http://localhost:3000 --fix # find → explain → heal → apply
|
|
55
|
+
npx aztrx-cli run http://localhost:3000 --fix --yes # non-interactive (CI)
|
|
64
56
|
```
|
|
65
57
|
|
|
66
|
-
|
|
58
|
+
`--fix` chains find → explain → heal, then asks *"Apply the fix?"* (`y/N`). On yes, the
|
|
59
|
+
verified patch lands in your working tree — `git diff` shows the result. Aztrx AI never
|
|
60
|
+
commits.
|
|
67
61
|
|
|
68
|
-
|
|
62
|
+
- **`--heal`** — the same pipeline, but stops at a verified `.patch` file (no apply).
|
|
63
|
+
- **`--explain`** — a human-language "X-ray" summary of what broke, where, and whether a fix is ready. No key required: it falls back to a deterministic offline summary.
|
|
69
64
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
npx aztrx-cli run http://localhost:3000 --fuzz --repro --heal
|
|
73
|
-
```
|
|
65
|
+
Every patch is redacted, sandboxed in a detached git worktree, compiler-checked, and gated
|
|
66
|
+
on your own test suite before you ever see it.
|
|
74
67
|
|
|
75
|
-
|
|
68
|
+
---
|
|
76
69
|
|
|
77
|
-
|
|
70
|
+
## Advanced
|
|
78
71
|
|
|
79
|
-
|
|
80
|
-
npx aztrx-cli studio
|
|
81
|
-
# → listening at http://localhost:7331
|
|
82
|
-
```
|
|
72
|
+
Everything else is optional. One line each — the full table is in the [CLI reference](#cli-reference).
|
|
83
73
|
|
|
84
|
-
###
|
|
74
|
+
### Fuzz harder
|
|
75
|
+
`--fuzz` breaks the *client*; `--http-fuzz` attacks the *server* — it harvests your app's
|
|
76
|
+
real endpoints and throws hostile requests at them (query overflow, JSON type-confusion,
|
|
77
|
+
header injection), turning every `5xx` into an executable repro. When a 500 body leaks a
|
|
78
|
+
server stack, `--heal` can even fix it by booting the patched app and replaying the repro.
|
|
85
79
|
|
|
86
|
-
|
|
80
|
+
### Parallel swarm
|
|
81
|
+
`--workers 4` fans detection into parallel workers (walk + several fuzz seeds + http-fuzz),
|
|
82
|
+
merged by fingerprint. `--swarm` is a hidden alias for `--workers auto`.
|
|
83
|
+
|
|
84
|
+
### Authenticated testing
|
|
85
|
+
`--login` detects the login form and signs in before the pass, so every repro runs
|
|
86
|
+
authenticated:
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
|
-
|
|
89
|
+
AZTRX_AUTH_EMAIL=you@example.com AZTRX_AUTH_PASSWORD=secret \
|
|
90
|
+
npx aztrx-cli run http://localhost:3000 --login
|
|
90
91
|
```
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
Ship a runtime gate on every PR — see [Continuous Integration](#continuous-integration-github-action) below.
|
|
93
|
+
Or `--storage-state <path>` with a saved Playwright state. Use `--login-url` for an
|
|
94
|
+
explicit login page, `--allow-host auth.example.com` for a third-party auth backend.
|
|
95
95
|
|
|
96
|
-
###
|
|
96
|
+
### Code modernizer
|
|
97
|
+
`npx aztrx-cli modernize src/legacy.js` rewrites legacy JS/TS into modern idiomatic syntax
|
|
98
|
+
(`var` → `const`, callbacks → `async`/`await`), applied only after you confirm.
|
|
97
99
|
|
|
98
|
-
|
|
100
|
+
### Live studio
|
|
101
|
+
`npx aztrx-cli studio` — triage findings in a localhost dashboard (binds `127.0.0.1`).
|
|
99
102
|
|
|
100
|
-
|
|
103
|
+
### Config & CI
|
|
104
|
+
`npx aztrx-cli init` scaffolds `aztrx.config.ts` and gitignores `.aztrx/`. For a per-PR
|
|
105
|
+
runtime gate, use the [GitHub Action](#continuous-integration-github-action). `--pr-comment`
|
|
106
|
+
/ `--badge` write a PR comment / status badge; `--upload --api-key` streams findings to your
|
|
107
|
+
cloud dashboard.
|
|
101
108
|
|
|
102
|
-
|
|
109
|
+
### Privacy
|
|
110
|
+
Off by default and strictly opt-in. `--telemetry` collects an anonymized tuple locally;
|
|
111
|
+
`--share-data` uploads it. `--upload` streams sanitized findings to the cloud. See
|
|
112
|
+
[Security & data flow](#security--data-flow) for the invariants.
|
|
103
113
|
|
|
104
114
|
---
|
|
105
115
|
|
|
106
116
|
## CLI reference
|
|
107
117
|
|
|
118
|
+
`aztrx-cli run --help` is grouped by intent (Detect / Prove / Fix / Report & ship / Auth);
|
|
119
|
+
the table below is the complete reference — including flags hidden from `--help` (aliases
|
|
120
|
+
and niche tuning knobs).
|
|
121
|
+
|
|
108
122
|
| Flag | Description | Default |
|
|
109
123
|
| --- | --- | --- |
|
|
110
124
|
| `--fuzz` | Seeded chaos fuzzing instead of the deterministic walk | — |
|
|
111
125
|
| `--http-fuzz` | Server-side mutation fuzzing — hostile requests against the target origin | — |
|
|
112
126
|
| `--repro` | Minimize (ddmin) → emit Playwright spec → validate flake rate | — |
|
|
113
127
|
| `--heal` | Generate + verify an LLM patch (implies `--repro`) | — |
|
|
128
|
+
| `--fix` | Find → explain → heal → apply — the one-command fix (implies `--heal`) | — |
|
|
129
|
+
| `--magic-fix` | Deprecated alias for `--fix` (hidden) | — |
|
|
130
|
+
| `--explain` | Print a human-language summary of the findings | — |
|
|
131
|
+
| `--yes` / `-y` | Auto-apply verified fixes without prompting (with `--fix`) | — |
|
|
132
|
+
| `--lang <code>` | Language for the human-language summary (`en`, `ru`) | `en` |
|
|
114
133
|
| `--upload` | Stream run findings to the cloud ingest backend | — |
|
|
115
134
|
| `--api-key <key>` | Auth key for `--upload` / `--share-data` | `$AZTRX_API_KEY` |
|
|
116
135
|
| `--cloud-url <url>` | Ingest server base URL | `https://api.aztrx.app` |
|
|
117
136
|
| `--max-actions <n>` | Max actions per pass | `100` |
|
|
118
137
|
| `--seed <n>` | PRNG seed for deterministic fuzz | `42` |
|
|
138
|
+
| `--workers <n>` | Number of parallel detection workers | `1` |
|
|
139
|
+
| `--swarm` | Hidden alias for `--workers auto` | — |
|
|
119
140
|
| `--repro-runs <n>` | Flake-rate replay iterations | `3` |
|
|
120
141
|
| `--heal-model <model>` | Fallback LLM tier | `claude-sonnet-5` |
|
|
121
142
|
| `--heal-fast-model <model>` | Fast/cheap first tier | `claude-haiku-4-5` |
|
|
@@ -129,7 +150,11 @@ When the 500 body leaks that server stack, `--heal` can also *fix* it: it boots
|
|
|
129
150
|
| `--share-data` | Also upload the sanitized tuples (opt-in) | — |
|
|
130
151
|
| `--repo <path>` | Root path for sourcemap → source resolution | cwd |
|
|
131
152
|
| `--allow-host <host>` | Add a host to the network allow-list (repeatable) | — |
|
|
132
|
-
| `--
|
|
153
|
+
| `--storage-state <path>` | Playwright storage-state for authenticated pages (`--auth` is a hidden alias) | — |
|
|
154
|
+
| `--login` | Auto-login before the pass (needs `AZTRX_AUTH_EMAIL`/`AZTRX_AUTH_PASSWORD`) | — |
|
|
155
|
+
| `--login-email <email>` | Email for `--login` (hidden — prefer `$AZTRX_AUTH_EMAIL`) | `$AZTRX_AUTH_EMAIL` |
|
|
156
|
+
| `--login-password <pass>` | Password for `--login` (hidden — prefer `$AZTRX_AUTH_PASSWORD`) | `$AZTRX_AUTH_PASSWORD` |
|
|
157
|
+
| `--login-url <url>` | Explicit login page URL for `--login` (hidden) | current page |
|
|
133
158
|
| `--fail-on` | Exit `1` if any crash/error finding is present | — |
|
|
134
159
|
| `--dry-run` | Log planned actions without executing them | — |
|
|
135
160
|
| `--crash-test` | Throw a deliberate error to verify capture | — |
|
|
@@ -156,36 +181,6 @@ Every run writes self-contained artifacts inside `.aztrx/` (gitignored):
|
|
|
156
181
|
|
|
157
182
|
---
|
|
158
183
|
|
|
159
|
-
## Architecture
|
|
160
|
-
|
|
161
|
-
Aztrx AI is a decoupled, event-driven pipeline — modules talk only through an
|
|
162
|
-
`EventBus`; the orchestrator wires them together.
|
|
163
|
-
|
|
164
|
-
```
|
|
165
|
-
[ CDP interceptor ] ──▶ [ action ring buffer ] ──▶ [ classifier (fingerprint) ]
|
|
166
|
-
│
|
|
167
|
-
[ verified .patch ] ◀── [ LLM healer ] ◀── [ ddmin minimizer ] ◀── [ sourcemap resolver ]
|
|
168
|
-
│
|
|
169
|
-
[ Playwright spec (.spec.ts) ] ──▶ [ flake-rate validator ]
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
| Stage | Module | Role |
|
|
173
|
-
| --- | --- | --- |
|
|
174
|
-
| F1 | `interceptor.ts` | CDP interceptor — captures raw runtime errors and console/network events |
|
|
175
|
-
| F2 | `recorder.ts` | Ring buffer of the last 25 actions; selector cascade `data-testid → text → CSS path` |
|
|
176
|
-
| F3 | `classifier.ts` | Fingerprints + dedups findings, assigns severity; suppresses `.aztrx/baseline.json` (input) |
|
|
177
|
-
| F4 | `resolver.ts` | Maps minified frames to source files, lines, and snippets via sourcemaps |
|
|
178
|
-
| F5 | `fuzzer.ts` + `domWalker.ts` | Seeded chaos fuzzer; `domWalker` (F5-lite) discovers interactive elements |
|
|
179
|
-
| F6 | `networkGuard.ts` + `domWalker.ts` | Deny-by-default network policy + destructive-action deny-list |
|
|
180
|
-
| F7 | `minimizer.ts` | ddmin delta-debugging — eliminates irrelevant actions |
|
|
181
|
-
| F8 | `specCompiler.ts` | Emits standalone, clean Playwright `.spec.ts` repro |
|
|
182
|
-
| F9 | `validator.ts` | Multi-pass replays → `deterministic` / `flaky` / `unreliable` |
|
|
183
|
-
| F10 | `heal/` | Closed-loop healing — redact → generate → AST gate → sandbox → `tsc` → verify |
|
|
184
|
-
| F11 | `telemetry/` | Opt-in anonymized crash→repro→patch tuple collection (data flywheel) |
|
|
185
|
-
| F12 | `cloud/` | Opt-in cloud sync — streams sanitized findings to the ingest dashboard |
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
184
|
## Continuous Integration (GitHub Action)
|
|
190
185
|
|
|
191
186
|
Runtime gate on every PR. The action boots your dev server, runs
|
|
@@ -201,7 +196,7 @@ jobs:
|
|
|
201
196
|
permissions: { contents: read, pull-requests: write }
|
|
202
197
|
steps:
|
|
203
198
|
- uses: actions/checkout@v4
|
|
204
|
-
- uses: DanisChaparov/aztrx@
|
|
199
|
+
- uses: DanisChaparov/aztrx@94d1173e6b363bc60e2237775cca11addd39b10f
|
|
205
200
|
with:
|
|
206
201
|
url: http://localhost:3000
|
|
207
202
|
start-command: npm run dev # optional — boot the app in the background
|
|
@@ -215,7 +210,7 @@ Or as a reusable workflow:
|
|
|
215
210
|
on: pull_request
|
|
216
211
|
jobs:
|
|
217
212
|
aztrx:
|
|
218
|
-
uses: DanisChaparov/aztrx/.github/workflows/aztrx-pr.yml@
|
|
213
|
+
uses: DanisChaparov/aztrx/.github/workflows/aztrx-pr.yml@94d1173e6b363bc60e2237775cca11addd39b10f
|
|
219
214
|
with:
|
|
220
215
|
url: http://localhost:3000
|
|
221
216
|
start-command: npm run dev
|
|
@@ -266,7 +261,7 @@ jobs:
|
|
|
266
261
|
sleep 2
|
|
267
262
|
done
|
|
268
263
|
- name: Generate badge
|
|
269
|
-
run: npx --yes aztrx-cli@0.
|
|
264
|
+
run: npx --yes aztrx-cli@0.2.1 run http://localhost:3000 --badge badge.svg
|
|
270
265
|
- name: Commit badge
|
|
271
266
|
run: |
|
|
272
267
|
git config user.name "github-actions[bot]"
|
|
@@ -291,16 +286,6 @@ aztrx falls back to `claude-sonnet-5` and tries again. Most one-line fixes never
|
|
|
291
286
|
pay for the big model. Tiers are configurable via `AZTRX_FAST_MODEL` /
|
|
292
287
|
`AZTRX_MODEL` or `--heal-fast-model` / `--heal-model`.
|
|
293
288
|
|
|
294
|
-
## Telemetry & privacy
|
|
295
|
-
|
|
296
|
-
Off by default and strictly opt-in. `--telemetry` collects the anonymized tuple
|
|
297
|
-
`[crash_fingerprint, min_repro_spec, verified_patch, framework_metadata,
|
|
298
|
-
model_tier_used]` locally (nothing leaves the machine); `--share-data` uploads it
|
|
299
|
-
to the telemetry endpoint. Every field passes a sanitizer that irreversibly
|
|
300
|
-
strips secrets, anonymizes URLs to `<host>`, and scrubs repo paths to `<repo>`.
|
|
301
|
-
Uploads are fire-and-forget, bounded by a 2s timeout, and never affect the exit
|
|
302
|
-
code.
|
|
303
|
-
|
|
304
289
|
## Security & data flow
|
|
305
290
|
|
|
306
291
|
**Local-first by default.** A run never phones home unless you pass an opt-in
|
|
@@ -335,9 +320,19 @@ LLM call.
|
|
|
335
320
|
CORS.
|
|
336
321
|
- **`.aztrx/` is gitignored** on `init` — repro specs, reports, and patches stay
|
|
337
322
|
out of history.
|
|
338
|
-
- **Pinned supply chain.** The GitHub Action pins `aztrx-cli@0.
|
|
323
|
+
- **Pinned supply chain.** The GitHub Action pins `aztrx-cli@0.2.1` (never
|
|
339
324
|
`@latest`).
|
|
340
325
|
|
|
326
|
+
## Telemetry & privacy
|
|
327
|
+
|
|
328
|
+
Off by default and strictly opt-in. `--telemetry` collects the anonymized tuple
|
|
329
|
+
`[crash_fingerprint, min_repro_spec, verified_patch, framework_metadata,
|
|
330
|
+
model_tier_used]` locally (nothing leaves the machine); `--share-data` uploads it
|
|
331
|
+
to the telemetry endpoint. Every field passes a sanitizer that irreversibly
|
|
332
|
+
strips secrets, anonymizes URLs to `<host>`, and scrubs repo paths to `<repo>`.
|
|
333
|
+
Uploads are fire-and-forget, bounded by a 2s timeout, and never affect the exit
|
|
334
|
+
code.
|
|
335
|
+
|
|
341
336
|
---
|
|
342
337
|
|
|
343
338
|
## Open benchmark
|
|
@@ -366,6 +361,37 @@ Full per-case table and scoring notes live in
|
|
|
366
361
|
|
|
367
362
|
---
|
|
368
363
|
|
|
364
|
+
## Architecture
|
|
365
|
+
|
|
366
|
+
Aztrx AI is a decoupled, event-driven pipeline — modules talk only through an
|
|
367
|
+
`EventBus`; the orchestrator wires them together.
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
[ CDP interceptor ] ──▶ [ action ring buffer ] ──▶ [ classifier (fingerprint) ]
|
|
371
|
+
│
|
|
372
|
+
[ verified .patch ] ◀── [ LLM healer ] ◀── [ ddmin minimizer ] ◀── [ sourcemap resolver ]
|
|
373
|
+
│
|
|
374
|
+
[ Playwright spec (.spec.ts) ] ──▶ [ flake-rate validator ]
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
| Stage | Module | Role |
|
|
378
|
+
| --- | --- | --- |
|
|
379
|
+
| F1 | `interceptor.ts` | CDP interceptor — captures raw runtime errors and console/network events |
|
|
380
|
+
| F2 | `recorder.ts` | Ring buffer of the last 25 actions; selector cascade `data-testid → text → CSS path` |
|
|
381
|
+
| F3 | `classifier.ts` | Fingerprints + dedups findings, assigns severity; suppresses `.aztrx/baseline.json` (input) |
|
|
382
|
+
| F4 | `resolver.ts` | Maps minified frames to source files, lines, and snippets via sourcemaps |
|
|
383
|
+
| F5 | `fuzzer.ts` + `domWalker.ts` | Seeded chaos fuzzer; `domWalker` (F5-lite) discovers interactive elements |
|
|
384
|
+
| F6 | `networkGuard.ts` + `domWalker.ts` | Deny-by-default network policy + destructive-action deny-list |
|
|
385
|
+
| F7 | `minimizer.ts` | ddmin delta-debugging — eliminates irrelevant actions |
|
|
386
|
+
| F8 | `specCompiler.ts` | Emits standalone, clean Playwright `.spec.ts` repro |
|
|
387
|
+
| F9 | `validator.ts` | Multi-pass replays → `deterministic` / `flaky` / `unreliable` |
|
|
388
|
+
| F10 | `heal/` | Closed-loop healing — redact → generate → AST gate → sandbox → `tsc` → verify |
|
|
389
|
+
| F11 | `telemetry/` | Opt-in anonymized crash→repro→patch tuple collection (data flywheel) |
|
|
390
|
+
| F12 | `cloud/` | Opt-in cloud sync — streams sanitized findings to the ingest dashboard |
|
|
391
|
+
| F13 | `summarize.ts` + `heal/apply.ts` | Human-language "X-ray" report + opt-in apply of verified patches (`--fix`) |
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
369
395
|
## Roadmap
|
|
370
396
|
|
|
371
397
|
- [x] Closed-loop healing — redact → generate → gate → sandbox → verify (F10)
|
|
@@ -377,6 +403,11 @@ Full per-case table and scoring notes live in
|
|
|
377
403
|
- [x] B2B ($29/mo) — Cloud dashboard (api.aztrx.app)
|
|
378
404
|
- [x] Data flywheel — opt-in anonymized patch-tuple collection (F11)
|
|
379
405
|
- [x] Server-side healing — heal server `5xx` findings (verify a patch by booting the patched server; requires a leaked server stack + a resolvable start command)
|
|
406
|
+
- [x] Human-language "X-ray" report — `--explain` / `--lang` (LLM + offline fallback)
|
|
407
|
+
- [x] One-click heal & apply — `--fix` (verified patch → working tree, `y/N`, no commit)
|
|
408
|
+
- [x] Autonomous Swarm — parallel detection: walk + multi-seed fuzz + http-fuzz workers, merged by fingerprint
|
|
409
|
+
- [x] Auth auto-login — `--login` walks login forms (synthesize test tokens — next)
|
|
410
|
+
- [x] Code modernizer — LLM-rewrite legacy JS/TS (`modernize`; Python — next)
|
|
380
411
|
|
|
381
412
|
## Contributing
|
|
382
413
|
|
|
@@ -393,6 +424,13 @@ node dist/cli.js http://localhost:8901/crash.html --repo fixtures --repro
|
|
|
393
424
|
# → one ● crash mapped to crash.html:13:15, minimized to 1 step
|
|
394
425
|
```
|
|
395
426
|
|
|
427
|
+
## Support the project
|
|
428
|
+
|
|
429
|
+
If Aztrx AI saved you hours of debugging or helped you ship a clean release, you
|
|
430
|
+
can support the author directly — name a fair price on Polar.sh:
|
|
431
|
+
|
|
432
|
+
**[Donate on Polar.sh →](https://buy.polar.sh/polar_cl_f1vBaxUv3S4fJ0o28GfgzQz7gHDHXkecCQtxY0WqeFs)**
|
|
433
|
+
|
|
396
434
|
## License
|
|
397
435
|
|
|
398
436
|
Apache-2.0 © DanisChaparov
|
package/dist/cli/help.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Option } from "commander";
|
|
2
|
+
const GROUP_HEADINGS = {
|
|
3
|
+
detect: "Detect",
|
|
4
|
+
prove: "Prove",
|
|
5
|
+
fix: "Fix",
|
|
6
|
+
ship: "Report & ship",
|
|
7
|
+
auth: "Auth",
|
|
8
|
+
advanced: "Advanced options",
|
|
9
|
+
};
|
|
10
|
+
// Primary groups render first, in this order, with aligned descriptions.
|
|
11
|
+
const PRIMARY_GROUPS = ["detect", "prove", "fix", "ship", "auth"];
|
|
12
|
+
/** Build a commander Option tagged with a help group (defaults to "advanced"). */
|
|
13
|
+
export function opt(flags, description, group = "advanced") {
|
|
14
|
+
const option = new Option(flags, description);
|
|
15
|
+
option.__aztrxGroup = group;
|
|
16
|
+
return option;
|
|
17
|
+
}
|
|
18
|
+
function groupOf(option) {
|
|
19
|
+
return option.__aztrxGroup ?? "advanced";
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Standalone `Help.formatHelp` override, registered via
|
|
23
|
+
* `runCommand.configureHelp({ formatHelp })`. Mirrors commander's built-in
|
|
24
|
+
* layout (Usage / Description / Arguments / Commands) but replaces the flat
|
|
25
|
+
* "Options:" list with named groups, and compresses the advanced flags into a
|
|
26
|
+
* single wrapped line of flag names.
|
|
27
|
+
*/
|
|
28
|
+
export function formatHelp(cmd, helper) {
|
|
29
|
+
const termWidth = helper.padWidth(cmd, helper);
|
|
30
|
+
const helpWidth = helper.helpWidth || 80;
|
|
31
|
+
const itemIndentWidth = 2;
|
|
32
|
+
const itemSeparatorWidth = 2;
|
|
33
|
+
const formatItem = (term, description) => {
|
|
34
|
+
if (description) {
|
|
35
|
+
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
|
|
36
|
+
return helper.wrap(fullText, helpWidth - itemIndentWidth, termWidth + itemSeparatorWidth);
|
|
37
|
+
}
|
|
38
|
+
return term;
|
|
39
|
+
};
|
|
40
|
+
const formatList = (lines) => lines.join("\n").replace(/^/gm, " ".repeat(itemIndentWidth));
|
|
41
|
+
const output = [`Usage: ${helper.commandUsage(cmd)}`, ""];
|
|
42
|
+
const description = helper.commandDescription(cmd);
|
|
43
|
+
if (description.length > 0) {
|
|
44
|
+
output.push(helper.wrap(description, helpWidth, 0), "");
|
|
45
|
+
}
|
|
46
|
+
const argumentList = helper
|
|
47
|
+
.visibleArguments(cmd)
|
|
48
|
+
.map((arg) => formatItem(helper.argumentTerm(arg), helper.argumentDescription(arg)));
|
|
49
|
+
if (argumentList.length > 0) {
|
|
50
|
+
output.push("Arguments:", formatList(argumentList), "");
|
|
51
|
+
}
|
|
52
|
+
// Separate the implicit `-h, --help` so it isn't swallowed by a group.
|
|
53
|
+
const visible = helper.visibleOptions(cmd);
|
|
54
|
+
const helpOption = visible.find((o) => o.short === "-h" && o.long === "--help");
|
|
55
|
+
const grouped = visible.filter((o) => o !== helpOption);
|
|
56
|
+
const buckets = new Map();
|
|
57
|
+
for (const o of grouped) {
|
|
58
|
+
const g = groupOf(o);
|
|
59
|
+
if (!buckets.has(g))
|
|
60
|
+
buckets.set(g, []);
|
|
61
|
+
buckets.get(g).push(o);
|
|
62
|
+
}
|
|
63
|
+
for (const g of PRIMARY_GROUPS) {
|
|
64
|
+
const opts = buckets.get(g);
|
|
65
|
+
if (!opts || opts.length === 0)
|
|
66
|
+
continue;
|
|
67
|
+
const list = opts.map((o) => formatItem(helper.optionTerm(o), helper.optionDescription(o)));
|
|
68
|
+
output.push(`${GROUP_HEADINGS[g]}:`, formatList(list), "");
|
|
69
|
+
}
|
|
70
|
+
const advanced = buckets.get("advanced");
|
|
71
|
+
if (advanced && advanced.length > 0) {
|
|
72
|
+
const names = advanced.map((o) => helper.optionTerm(o)).join(", ");
|
|
73
|
+
output.push(`${GROUP_HEADINGS.advanced}:`, formatList([helper.wrap(names, helpWidth - itemIndentWidth, 0)]), "");
|
|
74
|
+
}
|
|
75
|
+
if (helpOption) {
|
|
76
|
+
output.push(formatList([formatItem(helper.optionTerm(helpOption), helper.optionDescription(helpOption))]), "");
|
|
77
|
+
}
|
|
78
|
+
const commandList = helper
|
|
79
|
+
.visibleCommands(cmd)
|
|
80
|
+
.map((c) => formatItem(helper.subcommandTerm(c), helper.subcommandDescription(c)));
|
|
81
|
+
if (commandList.length > 0) {
|
|
82
|
+
output.push("Commands:", formatList(commandList), "");
|
|
83
|
+
}
|
|
84
|
+
return output.join("\n");
|
|
85
|
+
}
|