aztrx-cli 0.3.0 → 0.4.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 +98 -328
- package/dist/cli.js +74 -7
- package/dist/core/classifier.js +1 -0
- package/dist/core/domWalker.js +45 -21
- package/dist/core/fixPr.js +50 -0
- package/dist/core/fuzzer.js +112 -62
- package/dist/core/heal/index.js +32 -12
- package/dist/core/heal/llm.js +52 -6
- package/dist/core/interceptor.js +17 -9
- package/dist/core/llm.js +31 -5
- package/dist/core/modernize.js +1 -1
- package/dist/core/orchestrator.js +22 -11
- package/dist/core/prompt.js +12 -0
- package/dist/core/resolver.js +36 -16
- package/dist/core/specCompiler.js +31 -0
- package/dist/core/swarm.js +30 -4
- package/media/logo.png +0 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,144 +1,148 @@
|
|
|
1
1
|
# <img src="media/logo.svg" width="28" height="32" alt="Aztrx logo" align="absmiddle" /> Aztrx AI
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **Catch the runtime crash your Error Boundary hid — and prove it with a test, not a log line.**
|
|
4
4
|
|
|
5
5
|
[](https://nodejs.org)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
Aztrx AI
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Run it
|
|
8
|
+
Aztrx AI finds **runtime** bugs, not security holes. It drives your web app like a hostile
|
|
9
|
+
user and catches the crashes that ship to real users — *including ones a React Error Boundary
|
|
10
|
+
swallows* (the errors `window.onerror` never sees). Each crash comes back as an exact source
|
|
11
|
+
line plus an executable **Playwright repro** that fails `3/3` times. Then it fixes it.
|
|
15
12
|
|
|
16
13
|
```bash
|
|
17
|
-
npx aztrx-cli run http://localhost:3000
|
|
14
|
+
npx aztrx-cli run http://localhost:3000 # find crashes — zero setup, no key
|
|
15
|
+
npx aztrx-cli run http://localhost:3000 --fix # fix them — free for common bugs
|
|
18
16
|
```
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
running dev server and it finds the crashes. It drives Chromium through Playwright (the
|
|
22
|
-
first run downloads the browser automatically).
|
|
18
|
+

|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
---
|
|
25
21
|
|
|
26
|
-
|
|
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.
|
|
22
|
+
## Why Aztrx AI
|
|
29
23
|
|
|
30
|
-
|
|
24
|
+
- **Sees swallowed errors.** Error Boundaries and `window.onerror` miss the errors your app *catches*. Aztrx 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.
|
|
25
|
+
- **Proves, not reports.** Every crash ships with an executable `.spec.ts` repro and a flake-rate verdict — `[deterministic 3/3]`, `[flaky 3/5]`, or `[unreliable]`.
|
|
26
|
+
- **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.
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
npx aztrx-cli run http://localhost:3000 --fuzz # seeded chaos (replayable)
|
|
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
|
|
36
|
-
```
|
|
28
|
+
---
|
|
37
29
|
|
|
38
|
-
|
|
30
|
+
## Quickstart
|
|
39
31
|
|
|
40
32
|
```bash
|
|
41
|
-
npm i -g aztrx-cli
|
|
42
|
-
|
|
33
|
+
npm i -g aztrx-cli # or use npx — no install needed
|
|
34
|
+
|
|
35
|
+
aztrx-cli run http://localhost:3000 # 1. find the crashes (no key, no account)
|
|
36
|
+
aztrx-cli run http://localhost:3000 --repro # 2. prove them with an executable test
|
|
37
|
+
aztrx-cli run http://localhost:3000 --fix # 3. fix them
|
|
43
38
|
```
|
|
44
39
|
|
|
40
|
+
Point it at any running dev server. It drives Chromium through Playwright (the first run
|
|
41
|
+
downloads the browser automatically).
|
|
42
|
+
|
|
45
43
|
---
|
|
46
44
|
|
|
47
|
-
## Fix it
|
|
45
|
+
## Fix it — free for common crashes
|
|
46
|
+
|
|
47
|
+
`--fix` has two engines:
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
**1. Free, no key.** For the most common crash — `Cannot read properties of
|
|
50
|
+
undefined/null` — a built-in rule adds `?.` (optional chaining) and applies the fix. No LLM,
|
|
51
|
+
no key, no cost:
|
|
51
52
|
|
|
52
53
|
```bash
|
|
53
|
-
|
|
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)
|
|
54
|
+
aztrx-cli run http://localhost:3000 --fix # works out of the box for null/undefined derefs
|
|
56
55
|
```
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
**2. Your model, for complex bugs.** Logic errors, races, and anything the rule can't handle
|
|
58
|
+
— point it at any model:
|
|
60
59
|
|
|
61
60
|
```bash
|
|
62
|
-
|
|
61
|
+
# Anthropic
|
|
62
|
+
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
63
|
+
|
|
64
|
+
# or any OpenAI-compatible provider: OpenAI, Grok, DeepSeek, Gemini, Kimi, OpenRouter, Ollama
|
|
65
|
+
export AZTRX_API_BASE="https://openrouter.ai/api/v1"
|
|
63
66
|
export AZTRX_API_KEY="your-key"
|
|
64
|
-
export AZTRX_MODEL="anthropic/claude-sonnet-5"
|
|
65
|
-
npx aztrx-cli run http://localhost:3000 --fix
|
|
67
|
+
export AZTRX_MODEL="anthropic/claude-sonnet-5"
|
|
66
68
|
```
|
|
67
69
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- **`--heal`** — the same pipeline, but stops at a verified `.patch` file (no apply).
|
|
73
|
-
- **`--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.
|
|
74
|
-
|
|
75
|
-
Every patch is redacted, sandboxed in a detached git worktree, compiler-checked, and gated
|
|
76
|
-
on your own test suite before you ever see it.
|
|
70
|
+
Every fix is redacted, sandboxed in a detached git worktree, compiler-checked, and gated on
|
|
71
|
+
your test suite before you see it. Aztrx never commits. `--pr` opens a merge-ready PR;
|
|
72
|
+
`--regression-test` drops the repro into your test dir so the bug can't come back.
|
|
77
73
|
|
|
78
74
|
---
|
|
79
75
|
|
|
80
|
-
##
|
|
76
|
+
## More ways to run
|
|
81
77
|
|
|
82
|
-
|
|
78
|
+
| Flag | What it does |
|
|
79
|
+
| --- | --- |
|
|
80
|
+
| `--fuzz` | coverage-guided chaos fuzz — steers toward code it hasn't reached |
|
|
81
|
+
| `--http-fuzz` | attack the server's endpoints (turns every `5xx` into a repro) |
|
|
82
|
+
| `--swarm` / `--workers N` | parallel detection workers |
|
|
83
|
+
| `--login` | auto-login to test authenticated pages |
|
|
84
|
+
| `--badge` / `--pr-comment` / `--fail-on` | CI artifacts |
|
|
85
|
+
| `modernize <file>` | rewrite legacy JS/TS into modern idiomatic syntax |
|
|
86
|
+
| `studio` | live dashboard on `localhost:7331` |
|
|
83
87
|
|
|
84
|
-
|
|
85
|
-
`--fuzz` breaks the *client*; `--http-fuzz` attacks the *server* — it harvests your app's
|
|
86
|
-
real endpoints and throws hostile requests at them (query overflow, JSON type-confusion,
|
|
87
|
-
header injection), turning every `5xx` into an executable repro. When a 500 body leaks a
|
|
88
|
-
server stack, `--heal` can even fix it by booting the patched app and replaying the repro.
|
|
88
|
+
Full list: `aztrx-cli run --help`, or the [CLI reference](#cli-reference).
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
`--workers 4` fans detection into parallel workers (walk + several fuzz seeds + http-fuzz),
|
|
92
|
-
merged by fingerprint. `--swarm` is a hidden alias for `--workers auto`.
|
|
90
|
+
---
|
|
93
91
|
|
|
94
|
-
|
|
95
|
-
`--login` detects the login form and signs in before the pass, so every repro runs
|
|
96
|
-
authenticated:
|
|
92
|
+
## Security
|
|
97
93
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
- **Local-first.** Nothing leaves your machine unless you opt in.
|
|
95
|
+
- **Never commits.** Fixes land in a detached worktree for your review.
|
|
96
|
+
- **Redacted.** Secrets are stripped from the file, error, and stack before any LLM call.
|
|
97
|
+
- **Deny-by-default network.** Off-origin calls are blocked; destructive clicks (delete/pay/logout) are refused.
|
|
98
|
+
- **`.aztrx/` is gitignored** — repros, reports, and patches stay out of history.
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
explicit login page, `--allow-host auth.example.com` for a third-party auth backend.
|
|
100
|
+
---
|
|
105
101
|
|
|
106
|
-
|
|
107
|
-
`npx aztrx-cli modernize src/legacy.js` rewrites legacy JS/TS into modern idiomatic syntax
|
|
108
|
-
(`var` → `const`, callbacks → `async`/`await`), applied only after you confirm.
|
|
102
|
+
## Continuous Integration (GitHub Action)
|
|
109
103
|
|
|
110
|
-
|
|
111
|
-
`
|
|
104
|
+
Runtime gate on every PR — boots your dev server, runs
|
|
105
|
+
`aztrx-cli run --fail-on --repro --heal`, posts a comment with the repro + patch, and fails on
|
|
106
|
+
a crash/error.
|
|
112
107
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
108
|
+
```yaml
|
|
109
|
+
# .github/workflows/ci.yml — composite action, inline
|
|
110
|
+
on: pull_request
|
|
111
|
+
jobs:
|
|
112
|
+
aztrx:
|
|
113
|
+
runs-on: ubuntu-latest
|
|
114
|
+
permissions: { contents: read, pull-requests: write }
|
|
115
|
+
steps:
|
|
116
|
+
- uses: actions/checkout@v4
|
|
117
|
+
- uses: Aztrx-AI/aztrx@98dbad0f7b6681c7670f7068d01dc0d54813a55f
|
|
118
|
+
with:
|
|
119
|
+
url: http://localhost:3000
|
|
120
|
+
start-command: npm run dev # optional — boot the app in the background
|
|
121
|
+
token: ${{ github.token }}
|
|
122
|
+
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} # optional — enables --heal
|
|
123
|
+
```
|
|
118
124
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
`--share-data` uploads it. `--upload` streams sanitized findings to the cloud. See
|
|
122
|
-
[Security & data flow](#security--data-flow) for the invariants.
|
|
125
|
+
A status badge (`--badge`) and PR comment (`--pr-comment`) work the same way — regenerate in
|
|
126
|
+
CI on every push.
|
|
123
127
|
|
|
124
128
|
---
|
|
125
129
|
|
|
126
130
|
## CLI reference
|
|
127
131
|
|
|
128
132
|
`aztrx-cli run --help` is grouped by intent (Detect / Prove / Fix / Report & ship / Auth);
|
|
129
|
-
the table below is the complete reference — including flags hidden from `--help` (aliases
|
|
130
|
-
|
|
133
|
+
the table below is the complete reference — including flags hidden from `--help` (aliases and
|
|
134
|
+
niche tuning knobs).
|
|
131
135
|
|
|
132
136
|
| Flag | Description | Default |
|
|
133
137
|
| --- | --- | --- |
|
|
134
138
|
| `--fuzz` | Seeded chaos fuzzing instead of the deterministic walk | — |
|
|
135
139
|
| `--http-fuzz` | Server-side mutation fuzzing — hostile requests against the target origin | — |
|
|
136
140
|
| `--repro` | Minimize (ddmin) → emit Playwright spec → validate flake rate | — |
|
|
137
|
-
| `--heal` | Generate + verify
|
|
138
|
-
| `--fix` | Find → explain → heal → apply — the one-command fix (
|
|
139
|
-
| `--magic-fix` | Deprecated alias for `--fix` (hidden) | — |
|
|
141
|
+
| `--heal` | Generate + verify a fix (implies `--repro`) | — |
|
|
142
|
+
| `--fix` | Find → explain → heal → apply — the one-command fix (free for null/undefined derefs) | — |
|
|
140
143
|
| `--explain` | Print a human-language summary of the findings | — |
|
|
141
144
|
| `--yes` / `-y` | Auto-apply verified fixes without prompting (with `--fix`) | — |
|
|
145
|
+
| `--pr` | Open a merge-ready PR with the verified fixes (with `--fix`) | — |
|
|
142
146
|
| `--lang <code>` | Language for the human-language summary (`en`, `ru`) | `en` |
|
|
143
147
|
| `--upload` | Stream run findings to the cloud ingest backend | — |
|
|
144
148
|
| `--api-key <key>` | Auth key for `--upload` / `--share-data` | `$AZTRX_API_KEY` |
|
|
@@ -153,18 +157,16 @@ and niche tuning knobs).
|
|
|
153
157
|
| `--test-command <cmd>` | Test command run against a healed patch | `npm test` (auto-detected) |
|
|
154
158
|
| `--test-timeout <ms>` | Timeout for the heal test gate | `300000` |
|
|
155
159
|
| `--no-test` | Skip the test gate during healing | — |
|
|
156
|
-
| `--start-command <cmd>` | Command to boot the app for server healing | `scripts.dev` → `scripts.start`
|
|
160
|
+
| `--start-command <cmd>` | Command to boot the app for server healing | `scripts.dev` → `scripts.start` |
|
|
157
161
|
| `--pr-comment [path]` | Write a GitHub PR markdown comment | `.aztrx/pr-comment.md` |
|
|
158
162
|
| `--badge [path]` | Write a self-contained SVG status badge | `.aztrx/badge.svg` |
|
|
163
|
+
| `--regression-test [dir]` | Copy validated repro specs into the project test dir | `e2e/` or `tests/` |
|
|
159
164
|
| `--telemetry` | Collect anonymized tuples locally (opt-in) | — |
|
|
160
165
|
| `--share-data` | Also upload the sanitized tuples (opt-in) | — |
|
|
161
166
|
| `--repo <path>` | Root path for sourcemap → source resolution | cwd |
|
|
162
167
|
| `--allow-host <host>` | Add a host to the network allow-list (repeatable) | — |
|
|
163
|
-
| `--storage-state <path>` | Playwright storage-state for authenticated pages
|
|
168
|
+
| `--storage-state <path>` | Playwright storage-state for authenticated pages | — |
|
|
164
169
|
| `--login` | Auto-login before the pass (needs `AZTRX_AUTH_EMAIL`/`AZTRX_AUTH_PASSWORD`) | — |
|
|
165
|
-
| `--login-email <email>` | Email for `--login` (hidden — prefer `$AZTRX_AUTH_EMAIL`) | `$AZTRX_AUTH_EMAIL` |
|
|
166
|
-
| `--login-password <pass>` | Password for `--login` (hidden — prefer `$AZTRX_AUTH_PASSWORD`) | `$AZTRX_AUTH_PASSWORD` |
|
|
167
|
-
| `--login-url <url>` | Explicit login page URL for `--login` (hidden) | current page |
|
|
168
170
|
| `--fail-on` | Exit `1` if any crash/error finding is present | — |
|
|
169
171
|
| `--dry-run` | Log planned actions without executing them | — |
|
|
170
172
|
| `--crash-test` | Throw a deliberate error to verify capture | — |
|
|
@@ -178,252 +180,20 @@ Every run writes self-contained artifacts inside `.aztrx/` (gitignored):
|
|
|
178
180
|
|
|
179
181
|
```
|
|
180
182
|
.aztrx/
|
|
181
|
-
├── report.html #
|
|
182
|
-
├── repro
|
|
183
|
-
|
|
184
|
-
├──
|
|
185
|
-
│ └── fix.patch # gated, compiler-checked fix
|
|
186
|
-
├── events.jsonl # run log, streamed by `aztrx-cli studio`
|
|
187
|
-
├── telemetry/dataset.jsonl # opt-in anonymized tuple dataset
|
|
183
|
+
├── report.html # interactive triage report
|
|
184
|
+
├── repro/<id>.spec.ts # minimal, executable Playwright repro
|
|
185
|
+
├── heal/fix.patch # gated, compiler-checked fix
|
|
186
|
+
├── events.jsonl # run log (streamed by `aztrx-cli studio`)
|
|
188
187
|
├── pr-comment.md # GitHub PR markdown (with --pr-comment)
|
|
189
188
|
└── badge.svg # status badge (with --badge)
|
|
190
189
|
```
|
|
191
190
|
|
|
192
191
|
---
|
|
193
192
|
|
|
194
|
-
## Continuous Integration (GitHub Action)
|
|
195
|
-
|
|
196
|
-
Runtime gate on every PR. The action boots your dev server, runs
|
|
197
|
-
`aztrx-cli run --fail-on --repro --heal`, posts a markdown comment with the
|
|
198
|
-
deterministic repro + gated patch, and fails the check on a crash/error.
|
|
199
|
-
|
|
200
|
-
```yaml
|
|
201
|
-
# .github/workflows/ci.yml — composite action, inline
|
|
202
|
-
on: pull_request
|
|
203
|
-
jobs:
|
|
204
|
-
aztrx:
|
|
205
|
-
runs-on: ubuntu-latest
|
|
206
|
-
permissions: { contents: read, pull-requests: write }
|
|
207
|
-
steps:
|
|
208
|
-
- uses: actions/checkout@v4
|
|
209
|
-
- uses: DanisChaparov/aztrx@ee586a4410240efb7ed211ab0e1bf9d188361efa
|
|
210
|
-
with:
|
|
211
|
-
url: http://localhost:3000
|
|
212
|
-
start-command: npm run dev # optional — boot the app in the background
|
|
213
|
-
token: ${{ github.token }}
|
|
214
|
-
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} # optional — enables --heal
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
Or as a reusable workflow:
|
|
218
|
-
|
|
219
|
-
```yaml
|
|
220
|
-
on: pull_request
|
|
221
|
-
jobs:
|
|
222
|
-
aztrx:
|
|
223
|
-
uses: DanisChaparov/aztrx/.github/workflows/aztrx-pr.yml@ee586a4410240efb7ed211ab0e1bf9d188361efa
|
|
224
|
-
with:
|
|
225
|
-
url: http://localhost:3000
|
|
226
|
-
start-command: npm run dev
|
|
227
|
-
secrets:
|
|
228
|
-
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
---
|
|
232
|
-
|
|
233
|
-
## Status badge
|
|
234
|
-
|
|
235
|
-
Hang a live badge in your README that reflects your *actual* crash/error state —
|
|
236
|
-
not a static "protected" sticker.
|
|
237
|
-
|
|
238
|
-
```bash
|
|
239
|
-
npx aztrx-cli run http://localhost:3000 --badge badge.svg
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
```markdown
|
|
243
|
-
[](https://github.com/DanisChaparov/aztrx)
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
The badge is a self-contained SVG generated from the run's findings — green
|
|
247
|
-
`crash-free` or red `N findings`. It's honest because it's *earned*: regenerate it
|
|
248
|
-
in CI on every push to `main` and commit it back.
|
|
249
|
-
|
|
250
|
-
```yaml
|
|
251
|
-
# .github/workflows/badge.yml — keep the badge honest on every push to main
|
|
252
|
-
on:
|
|
253
|
-
push:
|
|
254
|
-
branches: [main]
|
|
255
|
-
jobs:
|
|
256
|
-
badge:
|
|
257
|
-
runs-on: ubuntu-latest
|
|
258
|
-
permissions:
|
|
259
|
-
contents: write
|
|
260
|
-
steps:
|
|
261
|
-
- uses: actions/checkout@v4
|
|
262
|
-
- uses: actions/setup-node@v4
|
|
263
|
-
with:
|
|
264
|
-
node-version: 20
|
|
265
|
-
- run: npm ci
|
|
266
|
-
- name: Boot dev server
|
|
267
|
-
run: |
|
|
268
|
-
nohup npm run dev > /tmp/dev.log 2>&1 &
|
|
269
|
-
for i in $(seq 1 60); do
|
|
270
|
-
curl -sS -o /dev/null http://localhost:3000 && break
|
|
271
|
-
sleep 2
|
|
272
|
-
done
|
|
273
|
-
- name: Generate badge
|
|
274
|
-
run: npx --yes aztrx-cli@0.3.0 run http://localhost:3000 --badge badge.svg
|
|
275
|
-
- name: Commit badge
|
|
276
|
-
run: |
|
|
277
|
-
git config user.name "github-actions[bot]"
|
|
278
|
-
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
279
|
-
git add badge.svg
|
|
280
|
-
git commit -m "chore: update aztrx badge" || echo "no change"
|
|
281
|
-
git push
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
No `--fail-on` here on purpose: the badge reflects the findings whatever they
|
|
285
|
-
are, and the run still exits 0 so the commit step always runs. Swap `push` for a
|
|
286
|
-
`schedule` cron if you'd rather regenerate daily than on every push.
|
|
287
|
-
|
|
288
|
-
---
|
|
289
|
-
|
|
290
|
-
## Smart Cloud Router
|
|
291
|
-
|
|
292
|
-
`--heal` is backed by a two-tier router: a fast/cheap model generates first, its patch
|
|
293
|
-
is gated, compiled, and replayed against the repro, and if the bug still reproduces (or
|
|
294
|
-
the patch fails a gate) aztrx falls back to the stronger model and tries again. Most
|
|
295
|
-
one-line fixes never pay for the big model. With Anthropic the defaults are
|
|
296
|
-
`claude-haiku-4-5` → `claude-sonnet-5`; with any other provider you pick both via
|
|
297
|
-
`AZTRX_FAST_MODEL` / `AZTRX_MODEL` (or `--heal-fast-model` / `--heal-model`). When only
|
|
298
|
-
one model is set, the router collapses to a single tier.
|
|
299
|
-
|
|
300
|
-
## Security & data flow
|
|
301
|
-
|
|
302
|
-
**Local-first by default.** A run never phones home unless you pass an opt-in
|
|
303
|
-
flag. By default nothing leaves your machine — no telemetry, no cloud sync, no
|
|
304
|
-
LLM call.
|
|
305
|
-
|
|
306
|
-
| What | Leaves your machine | When |
|
|
307
|
-
| --- | --- | --- |
|
|
308
|
-
| `run` (default) | nothing | — |
|
|
309
|
-
| `--heal` | redacted file + redacted error/stack, to the LLM API | only with `--heal` + `ANTHROPIC_API_KEY` |
|
|
310
|
-
| `--share-data` | a sanitized crash→repro→patch tuple | explicit opt-in |
|
|
311
|
-
| `--upload` | sanitized findings + counts | explicit opt-in |
|
|
312
|
-
|
|
313
|
-
### Invariants
|
|
314
|
-
|
|
315
|
-
- **Sourcemap containment.** A hostile sourcemap or stack URL can't read outside
|
|
316
|
-
your repo: every path is resolved against the repo root and rejected if it
|
|
317
|
-
escapes it — including through symlinks. Secret-bearing files (`.env`, `.npmrc`,
|
|
318
|
-
private keys) are never read into a report or PR comment.
|
|
319
|
-
- **Redaction before the model.** `--heal` redacts common secret patterns (keys,
|
|
320
|
-
tokens, credentials) from the file, error, and stack before they're sent; only
|
|
321
|
-
the repo-relative path and line/column are visible. Redaction is heuristic — it
|
|
322
|
-
is not a substitute for not committing secrets.
|
|
323
|
-
- **Isolated sandbox, no commits.** Patches land in a detached `git worktree` in
|
|
324
|
-
the OS temp dir — never your working tree. Aztrx AI never commits. A patch must
|
|
325
|
-
parse, add no new imports / `eval` / `child_process`, typecheck, *and* pass your
|
|
326
|
-
own test suite before it's offered as a `.patch` for you to review.
|
|
327
|
-
- **Deny-by-default network.** Only the target origin (plus explicit
|
|
328
|
-
`--allow-host`) is reachable; off-origin calls are blocked.
|
|
329
|
-
- **Destructive-action deny-list.** Never clicks delete / pay / logout.
|
|
330
|
-
- **Studio is localhost-only.** The dashboard binds `127.0.0.1` with no wildcard
|
|
331
|
-
CORS.
|
|
332
|
-
- **`.aztrx/` is gitignored** on `init` — repro specs, reports, and patches stay
|
|
333
|
-
out of history.
|
|
334
|
-
- **Pinned supply chain.** The GitHub Action pins `aztrx-cli@0.3.0` (never
|
|
335
|
-
`@latest`).
|
|
336
|
-
|
|
337
|
-
## Telemetry & privacy
|
|
338
|
-
|
|
339
|
-
Off by default and strictly opt-in. `--telemetry` collects the anonymized tuple
|
|
340
|
-
`[crash_fingerprint, min_repro_spec, verified_patch, framework_metadata,
|
|
341
|
-
model_tier_used]` locally (nothing leaves the machine); `--share-data` uploads it
|
|
342
|
-
to the telemetry endpoint. Every field passes a sanitizer that irreversibly
|
|
343
|
-
strips secrets, anonymizes URLs to `<host>`, and scrubs repo paths to `<repo>`.
|
|
344
|
-
Uploads are fire-and-forget, bounded by a 2s timeout, and never affect the exit
|
|
345
|
-
code.
|
|
346
|
-
|
|
347
|
-
---
|
|
348
|
-
|
|
349
|
-
## Open benchmark
|
|
350
|
-
|
|
351
|
-
The detector is scored against a 13-target corpus of **real Next.js App Router
|
|
352
|
-
apps** — one seeded runtime bug per app across the archetype matrix (null deref,
|
|
353
|
-
async race, JSON parse, stack overflow, Server Action, route transition, and more).
|
|
354
|
-
|
|
355
|
-
| metric | value |
|
|
356
|
-
| --- | --- |
|
|
357
|
-
| seeded bugs | 13 |
|
|
358
|
-
| detection recall | **100%** (13 / 13) |
|
|
359
|
-
| deterministic repros | **100%** (12 / 12) |
|
|
360
|
-
| repro not attempted | 1 (mount-time bug, no action history) |
|
|
361
|
-
| unseeded findings | 5 — two root causes (`/api/cart` → 500, Server Action → 500) |
|
|
362
|
-
|
|
363
|
-
```bash
|
|
364
|
-
cd bench/frameworks
|
|
365
|
-
npm install # once — installs next/react for the target apps
|
|
366
|
-
npm run bench # detection
|
|
367
|
-
npm run bench:repro # detection + repro scoring
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
Full per-case table and scoring notes live in
|
|
371
|
-
[`bench/frameworks/RESULTS.md`](bench/frameworks/RESULTS.md).
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
## Architecture
|
|
376
|
-
|
|
377
|
-
Aztrx AI is a decoupled, event-driven pipeline — modules talk only through an
|
|
378
|
-
`EventBus`; the orchestrator wires them together.
|
|
379
|
-
|
|
380
|
-
```
|
|
381
|
-
[ CDP interceptor ] ──▶ [ action ring buffer ] ──▶ [ classifier (fingerprint) ]
|
|
382
|
-
│
|
|
383
|
-
[ verified .patch ] ◀── [ LLM healer ] ◀── [ ddmin minimizer ] ◀── [ sourcemap resolver ]
|
|
384
|
-
│
|
|
385
|
-
[ Playwright spec (.spec.ts) ] ──▶ [ flake-rate validator ]
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
| Stage | Module | Role |
|
|
389
|
-
| --- | --- | --- |
|
|
390
|
-
| F1 | `interceptor.ts` | CDP interceptor — captures raw runtime errors and console/network events |
|
|
391
|
-
| F2 | `recorder.ts` | Ring buffer of the last 25 actions; selector cascade `data-testid → text → CSS path` |
|
|
392
|
-
| F3 | `classifier.ts` | Fingerprints + dedups findings, assigns severity; suppresses `.aztrx/baseline.json` (input) |
|
|
393
|
-
| F4 | `resolver.ts` | Maps minified frames to source files, lines, and snippets via sourcemaps |
|
|
394
|
-
| F5 | `fuzzer.ts` + `domWalker.ts` | Seeded chaos fuzzer; `domWalker` (F5-lite) discovers interactive elements |
|
|
395
|
-
| F6 | `networkGuard.ts` + `domWalker.ts` | Deny-by-default network policy + destructive-action deny-list |
|
|
396
|
-
| F7 | `minimizer.ts` | ddmin delta-debugging — eliminates irrelevant actions |
|
|
397
|
-
| F8 | `specCompiler.ts` | Emits standalone, clean Playwright `.spec.ts` repro |
|
|
398
|
-
| F9 | `validator.ts` | Multi-pass replays → `deterministic` / `flaky` / `unreliable` |
|
|
399
|
-
| F10 | `heal/` | Closed-loop healing — redact → generate → AST gate → sandbox → `tsc` → verify |
|
|
400
|
-
| F11 | `telemetry/` | Opt-in anonymized crash→repro→patch tuple collection (data flywheel) |
|
|
401
|
-
| F12 | `cloud/` | Opt-in cloud sync — streams sanitized findings to the ingest dashboard |
|
|
402
|
-
| F13 | `summarize.ts` + `heal/apply.ts` | Human-language "X-ray" report + opt-in apply of verified patches (`--fix`) |
|
|
403
|
-
|
|
404
|
-
---
|
|
405
|
-
|
|
406
|
-
## Roadmap
|
|
407
|
-
|
|
408
|
-
- [x] Closed-loop healing — redact → generate → gate → sandbox → verify (F10)
|
|
409
|
-
- [ ] Open-source launch — npm publish, `npx aztrx-cli run`, hero screencast
|
|
410
|
-
- [x] Hardening — `--auth`/`--storage-state`, tsc compile fast-fail, React 19/Next.js 15 triage
|
|
411
|
-
- [x] Real-project benchmark — 13 Next.js App Router targets (100% recall, 100% deterministic repro)
|
|
412
|
-
- [x] B2B ($29/mo) — GitHub Action (`action.yml` + reusable workflow), PR bot markdown comment
|
|
413
|
-
- [x] B2B ($29/mo) — Smart Cloud Router (haiku fast-tier → verify → Sonnet fallback)
|
|
414
|
-
- [x] B2B ($29/mo) — Cloud dashboard (api.aztrx.app)
|
|
415
|
-
- [x] Data flywheel — opt-in anonymized patch-tuple collection (F11)
|
|
416
|
-
- [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)
|
|
417
|
-
- [x] Human-language "X-ray" report — `--explain` / `--lang` (LLM + offline fallback)
|
|
418
|
-
- [x] One-click heal & apply — `--fix` (verified patch → working tree, `y/N`, no commit)
|
|
419
|
-
- [x] Autonomous Swarm — parallel detection: walk + multi-seed fuzz + http-fuzz workers, merged by fingerprint
|
|
420
|
-
- [x] Auth auto-login — `--login` walks login forms (synthesize test tokens — next)
|
|
421
|
-
- [x] Code modernizer — LLM-rewrite legacy JS/TS (`modernize`; Python — next)
|
|
422
|
-
|
|
423
193
|
## Contributing
|
|
424
194
|
|
|
425
195
|
```bash
|
|
426
|
-
git clone https://github.com/
|
|
196
|
+
git clone https://github.com/Aztrx-AI/aztrx
|
|
427
197
|
cd aztrx
|
|
428
198
|
npm install
|
|
429
199
|
npx playwright install chromium
|
|
@@ -435,10 +205,10 @@ node dist/cli.js http://localhost:8901/crash.html --repo fixtures --repro
|
|
|
435
205
|
# → one ● crash mapped to crash.html:13:15, minimized to 1 step
|
|
436
206
|
```
|
|
437
207
|
|
|
438
|
-
## Support
|
|
208
|
+
## Support
|
|
439
209
|
|
|
440
|
-
If Aztrx AI saved you hours of debugging
|
|
441
|
-
|
|
210
|
+
If Aztrx AI saved you hours of debugging, you can support the author directly —
|
|
211
|
+
name a fair price on Polar.sh:
|
|
442
212
|
|
|
443
213
|
**[Donate on Polar.sh →](https://buy.polar.sh/polar_cl_f1vBaxUv3S4fJ0o28GfgzQz7gHDHXkecCQtxY0WqeFs)**
|
|
444
214
|
|