@cleaver/breakcheck 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -1
- package/agent-guide.md +107 -0
- package/dist/cli/commands/baseline.d.ts +19 -0
- package/dist/cli/commands/baseline.js +133 -0
- package/dist/cli/commands/baseline.js.map +1 -0
- package/dist/cli/commands/check.d.ts +27 -0
- package/dist/cli/commands/check.js +204 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/clean.d.ts +25 -0
- package/dist/cli/commands/clean.js +123 -0
- package/dist/cli/commands/clean.js.map +1 -0
- package/dist/cli/commands/compare.js +28 -6
- package/dist/cli/commands/compare.js.map +1 -1
- package/dist/cli/commands/compile.d.ts +5 -0
- package/dist/cli/commands/compile.js +23 -0
- package/dist/cli/commands/compile.js.map +1 -0
- package/dist/cli/commands/help.js +163 -4
- package/dist/cli/commands/help.js.map +1 -1
- package/dist/cli/commands/init.d.ts +26 -0
- package/dist/cli/commands/init.js +224 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/list-snapshots.js +7 -3
- package/dist/cli/commands/list-snapshots.js.map +1 -1
- package/dist/cli/commands/new.d.ts +9 -0
- package/dist/cli/commands/new.js +27 -0
- package/dist/cli/commands/new.js.map +1 -0
- package/dist/cli/commands/snapshot.d.ts +20 -0
- package/dist/cli/commands/snapshot.js +116 -39
- package/dist/cli/commands/snapshot.js.map +1 -1
- package/dist/cli/commands/view.d.ts +1 -1
- package/dist/cli/commands/view.js +12 -6
- package/dist/cli/commands/view.js.map +1 -1
- package/dist/cli/config.d.ts +14 -0
- package/dist/cli/config.js +58 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/rules.d.ts +12 -0
- package/dist/cli/rules.js +110 -0
- package/dist/cli/rules.js.map +1 -0
- package/dist/cli/site-environment.d.ts +12 -0
- package/dist/cli/site-environment.js +231 -0
- package/dist/cli/site-environment.js.map +1 -0
- package/dist/cli/url-manifest.js.map +1 -1
- package/dist/cli/utils.d.ts +1 -0
- package/dist/cli/utils.js +4 -1
- package/dist/cli/utils.js.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -116,6 +116,47 @@ css:.view-count do: rewrite_content regex:"\d{1,3}(,\d{3})* views" replace:"VIEW
|
|
|
116
116
|
|
|
117
117
|
## Command Reference
|
|
118
118
|
|
|
119
|
+
### `init`
|
|
120
|
+
|
|
121
|
+
Creates a version-1 `breakcheck.config.json` without overwriting an existing
|
|
122
|
+
file. URL and rules are optional; `--interactive` prompts for omitted values
|
|
123
|
+
when a terminal is available.
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
breakcheck init [--url <url>] [--storage-dir <directory>] [--rules <directory>]
|
|
127
|
+
breakcheck init --interactive
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### `new rule`
|
|
131
|
+
|
|
132
|
+
Creates a new named ruleset directory containing a comments-only
|
|
133
|
+
`rules.breakcheck` scaffold. The name must be a single path-safe segment, and
|
|
134
|
+
an existing rules file is never overwritten.
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
breakcheck new rule my-rules
|
|
138
|
+
breakcheck new rule dynamic --directory rules
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The first command creates `./my-rules/rules.breakcheck`; the second creates
|
|
142
|
+
`./rules/dynamic/rules.breakcheck`. Add active DSL rules to the file, then pass
|
|
143
|
+
the generated directory to `compare --rules` or set it as `comparison.rulesDir`
|
|
144
|
+
in project configuration.
|
|
145
|
+
|
|
146
|
+
### `compile`
|
|
147
|
+
|
|
148
|
+
Compiles a rules directory's `rules.breakcheck` DSL into the intermediate JSON
|
|
149
|
+
format. JSON is written to stdout for inspection or shell redirection.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
breakcheck compile ./my-rules
|
|
153
|
+
breakcheck compile ./my-rules > rules.json
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Relative directories resolve from the directory where Breakcheck is invoked.
|
|
157
|
+
Selectors, regular expressions, modifiers, and named regions are validated
|
|
158
|
+
before JSON is emitted.
|
|
159
|
+
|
|
119
160
|
### `snapshot`
|
|
120
161
|
|
|
121
162
|
Crawls a website and saves its HTML content and structure to a named snapshot.
|
|
@@ -126,17 +167,21 @@ breakcheck snapshot [options]
|
|
|
126
167
|
|
|
127
168
|
| Option | Description | Default |
|
|
128
169
|
| :---------------------------- | :-------------------------------------------------------------------- | :------------------------------ |
|
|
129
|
-
| `-u, --url <url>` |
|
|
170
|
+
| `-u, --url <url>` | Base URL to start crawling from; may come from project config. | |
|
|
130
171
|
| `-n, --name <name>` | A unique name for the snapshot. | `snapshot_YYYY-MM-DD_HH-mm-ssZ` |
|
|
131
172
|
| `-d, --depth <number>` | Maximum crawl depth. | `3` |
|
|
132
173
|
| `-c, --concurrency <number>` | Number of concurrent requests to make. | `5` |
|
|
133
174
|
| `-i, --include <patterns...>` | Glob patterns for URLs to include. | |
|
|
134
175
|
| `-e, --exclude <patterns...>` | Glob patterns for URLs to exclude. | |
|
|
176
|
+
| `--no-include` | Clear configured include patterns. | |
|
|
177
|
+
| `--no-exclude` | Clear configured exclude patterns. | |
|
|
135
178
|
| `-t, --type <type>` | The crawler to use (`cheerio` or `playwright`). | `cheerio` |
|
|
136
179
|
| `--url-file <path>` | Crawl exactly the root-relative paths in a file, or `-` for stdin. | |
|
|
137
180
|
| `-w, --write-urls <path>` | Generate a plain text file of all crawled URLs at the specified path. | |
|
|
138
181
|
| `--json-logs` | Output logs in JSON format (useful for automation). | |
|
|
139
182
|
| `--no-json-logs` | Output logs in pretty format (default, user-friendly). | |
|
|
183
|
+
| `--config <file>` | Select a project configuration file. | Nearest discovered file |
|
|
184
|
+
| `--no-config` | Disable project configuration discovery. | |
|
|
140
185
|
|
|
141
186
|
#### Exact URL manifests
|
|
142
187
|
|
|
@@ -177,8 +222,94 @@ breakcheck compare [options]
|
|
|
177
222
|
| `-a, --after <name>` | **(Required)** The name of the "after" snapshot. | |
|
|
178
223
|
| `-o, --output <name>` | A name for the comparison output directory. | `compare_default` |
|
|
179
224
|
| `-r, --rules <directory>` | Directory containing `rules.breakcheck`; relative paths resolve from the directory where Breakcheck is invoked. | None (unfiltered comparison) |
|
|
225
|
+
| `--no-rules` | Clear a configured rules directory. | |
|
|
180
226
|
| `--json-logs` | Output logs in JSON format (useful for automation). | |
|
|
181
227
|
| `--no-json-logs` | Output logs in pretty format (default, user-friendly). | |
|
|
228
|
+
| `--config <file>` | Select a project configuration file. | |
|
|
229
|
+
| `--no-config` | Disable project configuration discovery. | |
|
|
230
|
+
|
|
231
|
+
Snapshot commands exit with status `1` when snapshot creation fails.
|
|
232
|
+
Comparison commands exit with status `1` when the comparison fails or finds
|
|
233
|
+
differences (`overallResult: "fail"`), which lets CI jobs stop on regressions.
|
|
234
|
+
|
|
235
|
+
### `check`
|
|
236
|
+
|
|
237
|
+
Runs a local site regression check using the version-2 `check` section in
|
|
238
|
+
`breakcheck.config.json`. It optionally runs `check.prepare`, starts the
|
|
239
|
+
configured server, waits for `baseUrl` plus `readyPath`, snapshots only the
|
|
240
|
+
exact routes in `check.routesFile`, compares them to `check.baselineSnapshot`
|
|
241
|
+
using `comparison.rulesDir`, saves a report, and shuts down the managed server.
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
breakcheck check
|
|
245
|
+
breakcheck check --url http://127.0.0.1:4000
|
|
246
|
+
breakcheck check --json
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
`--url` uses an already-running server and skips preparation and lifecycle
|
|
250
|
+
commands. Configure foreground server commands such as `mix phx.server` with a
|
|
251
|
+
`start` array; Breakcheck stops the process group on completion. For a daemon
|
|
252
|
+
or environment manager, configure a paired `stop` command, such as
|
|
253
|
+
`["ddev", "stop"]`. Commands run without a shell, from `server.cwd`, and
|
|
254
|
+
inherit the current environment plus any `server.env` entries. Keep stop
|
|
255
|
+
commands scoped to environments owned by the check.
|
|
256
|
+
|
|
257
|
+
`--json` writes one JSON result to stdout for CI and agent integrations; build,
|
|
258
|
+
server, and crawler output goes to stderr. Reports are written under
|
|
259
|
+
`check.reportDir`, which defaults to `<storageDir>/reports`. Comparison details
|
|
260
|
+
are also saved under `<storageDir>/comparisons`.
|
|
261
|
+
|
|
262
|
+
Exit codes are `0` for no differences, `1` for page or route differences, and
|
|
263
|
+
`2` for setup, readiness, crawl, or comparison failures.
|
|
264
|
+
|
|
265
|
+
For a task-focused guide to using Breakcheck as feedback during coding-agent
|
|
266
|
+
work, see [Agent guide](agent-guide.md).
|
|
267
|
+
|
|
268
|
+
### `baseline update`
|
|
269
|
+
|
|
270
|
+
Updates the configured baseline explicitly. `--route` replaces only the
|
|
271
|
+
selected routes and preserves every other route in the baseline snapshot.
|
|
272
|
+
`--all` replaces the routes listed in `check.routesFile`.
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
breakcheck baseline update --route /about /contact
|
|
276
|
+
breakcheck baseline update --all
|
|
277
|
+
breakcheck baseline update --route /about --url http://127.0.0.1:4000
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
The update is staged and committed only after all selected routes crawl
|
|
281
|
+
successfully. A regular `check` never writes to the baseline.
|
|
282
|
+
|
|
283
|
+
### `clean`
|
|
284
|
+
|
|
285
|
+
Deletes stored snapshots or comparisons. Deletion is confirmed interactively
|
|
286
|
+
unless `--force` is supplied.
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
breakcheck clean snapshot [options]
|
|
290
|
+
breakcheck clean comparison [options]
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
| Option | Description |
|
|
294
|
+
| :---------------- | :------------------------------------------------------------------- |
|
|
295
|
+
| `--name <name>` | Delete one named snapshot or comparison. |
|
|
296
|
+
| `--all` | Delete all stored artifacts of the selected type. |
|
|
297
|
+
| `--force` | Skip confirmation; required when running without an interactive TTY. |
|
|
298
|
+
| `--json-logs` | Output logs in JSON format. |
|
|
299
|
+
| `--no-json-logs` | Output logs in pretty format (default). |
|
|
300
|
+
| `--config <file>` | Select a project configuration file. |
|
|
301
|
+
| `--no-config` | Disable project configuration discovery. |
|
|
302
|
+
|
|
303
|
+
`--name` and `--all` cannot be combined. If neither is provided in a terminal,
|
|
304
|
+
Breakcheck prompts for a name. Snapshot cleanup never deletes comparisons.
|
|
305
|
+
|
|
306
|
+
Examples:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
breakcheck clean snapshot --name before
|
|
310
|
+
breakcheck clean comparison --name filtered --force
|
|
311
|
+
breakcheck clean snapshot --all --force
|
|
312
|
+
```
|
|
182
313
|
|
|
183
314
|
### `view`
|
|
184
315
|
|
|
@@ -197,6 +328,8 @@ breakcheck view [comparison-name] [options]
|
|
|
197
328
|
| `-p, --port <number>` | The port to run the view server on. When omitted, starts at 8080 and uses the next available port. | `8080` (next available) |
|
|
198
329
|
| `--json-logs` | Output logs in JSON format (useful for automation). | |
|
|
199
330
|
| `--no-json-logs` | Output logs in pretty format (default, user-friendly). | |
|
|
331
|
+
| `--config <file>` | Select a project configuration file. | |
|
|
332
|
+
| `--no-config` | Disable project configuration discovery. | |
|
|
200
333
|
|
|
201
334
|
### `list-snapshots`
|
|
202
335
|
|
|
@@ -208,6 +341,9 @@ Lists all snapshots that have been saved locally.
|
|
|
208
341
|
breakcheck list-snapshots
|
|
209
342
|
```
|
|
210
343
|
|
|
344
|
+
`list-snapshots` uses the discovered artifact store. Pass `--config <file>` or
|
|
345
|
+
`--no-config` to select or disable configuration explicitly.
|
|
346
|
+
|
|
211
347
|
The command outputs a table of available snapshots:
|
|
212
348
|
|
|
213
349
|
```
|
package/agent-guide.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Using Breakcheck with coding agents
|
|
2
|
+
|
|
3
|
+
This guide describes a small feedback loop for coding agents working on a
|
|
4
|
+
website that has a Breakcheck baseline. It is reference material: load it when
|
|
5
|
+
a task changes user-visible website behavior, routes, content, or layout rather
|
|
6
|
+
than adding the whole guide to every agent session.
|
|
7
|
+
|
|
8
|
+
## What the check does
|
|
9
|
+
|
|
10
|
+
`breakcheck check` prepares and starts the configured local site when needed,
|
|
11
|
+
crawls the exact routes in `check.routesFile`, compares them with the named
|
|
12
|
+
`check.baselineSnapshot`, saves a report, and stops the managed server. A
|
|
13
|
+
configured `comparison.rulesDir` can normalize known dynamic content. The
|
|
14
|
+
regular check never modifies the baseline.
|
|
15
|
+
|
|
16
|
+
## Consumer project setup
|
|
17
|
+
|
|
18
|
+
Install Breakcheck as a development dependency:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install --save-dev @cleaver/breakcheck
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Add a project script so the agent and developer use the same command:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"scripts": {
|
|
29
|
+
"breakcheck:check": "breakcheck check --json"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Configure a version-2 `breakcheck.config.json` with a `baseUrl`, `storageDir`,
|
|
35
|
+
and `check` section. The check section names an exact route manifest and a
|
|
36
|
+
baseline snapshot:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"version": 2,
|
|
41
|
+
"baseUrl": "http://127.0.0.1:3000",
|
|
42
|
+
"storageDir": ".breakcheck",
|
|
43
|
+
"check": {
|
|
44
|
+
"routesFile": "./breakcheck-routes.txt",
|
|
45
|
+
"baselineSnapshot": "site-baseline"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Add server `prepare` and `server.start` settings when Breakcheck should start
|
|
51
|
+
the site itself. If the site is already running, pass `--url` to skip those
|
|
52
|
+
lifecycle commands. Review configured commands before running the check; they
|
|
53
|
+
execute with the project's environment.
|
|
54
|
+
|
|
55
|
+
Create the initial named baseline from an approved, known-good site state, then
|
|
56
|
+
commit that snapshot with the project. Keep generated check snapshots,
|
|
57
|
+
comparisons, and reports out of version control while retaining the named
|
|
58
|
+
baseline.
|
|
59
|
+
|
|
60
|
+
For example, with the local site already running:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
breakcheck snapshot \
|
|
64
|
+
--url http://127.0.0.1:3000 \
|
|
65
|
+
--url-file ./breakcheck-routes.txt \
|
|
66
|
+
--name site-baseline
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Minimal project instructions
|
|
70
|
+
|
|
71
|
+
Keep the consumer repository's `AGENTS.md` focused on local decisions. For
|
|
72
|
+
example:
|
|
73
|
+
|
|
74
|
+
```markdown
|
|
75
|
+
For changes to user-visible website behavior, run `npm run breakcheck:check`.
|
|
76
|
+
Inspect the JSON report and comparison details when differences are found.
|
|
77
|
+
Do not update the committed baseline or rules just to silence a difference;
|
|
78
|
+
confirm that the change is expected before recording it.
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The project's own instructions should identify its server start command, route
|
|
82
|
+
manifest, and any task-specific acceptance criteria. Those details vary by
|
|
83
|
+
consumer and should not be guessed from this package guide.
|
|
84
|
+
|
|
85
|
+
## Agent feedback loop
|
|
86
|
+
|
|
87
|
+
1. Read the task's expected behavior and identify which configured routes cover
|
|
88
|
+
it. The check only visits routes listed in `check.routesFile`.
|
|
89
|
+
2. Make the code change and run the project's ordinary build and tests.
|
|
90
|
+
3. Run `npm run breakcheck:check`. The command writes one JSON object to stdout;
|
|
91
|
+
build, server, and crawler output is written to stderr.
|
|
92
|
+
4. Interpret the result:
|
|
93
|
+
- `status: "passed"` and exit code `0`: no route or page differences were
|
|
94
|
+
found.
|
|
95
|
+
- `status: "differences"` and exit code `1`: inspect `comparison` and its
|
|
96
|
+
`resultsPath`, then decide whether each difference matches the task.
|
|
97
|
+
- `status: "failed"` and exit code `2`: the check did not complete
|
|
98
|
+
successfully. Fix the setup or execution problem; do not report this as a
|
|
99
|
+
passing check.
|
|
100
|
+
5. If a difference is expected, describe it in the task result. Update only the
|
|
101
|
+
accepted routes with `breakcheck baseline update --route <path> --json`,
|
|
102
|
+
then rerun the check. Use `--all` only when every configured route is meant
|
|
103
|
+
to change.
|
|
104
|
+
|
|
105
|
+
Do not use a baseline update or a new ignore rule to make an unexplained
|
|
106
|
+
difference disappear. If the expected result is unclear, report the difference
|
|
107
|
+
and ask before changing the committed baseline.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { InteractiveCommand } from "interactive-commander";
|
|
2
|
+
interface BaselineUpdateOptions {
|
|
3
|
+
all?: boolean;
|
|
4
|
+
route?: string[];
|
|
5
|
+
url?: string;
|
|
6
|
+
json?: boolean;
|
|
7
|
+
jsonLogs?: boolean;
|
|
8
|
+
noJsonLogs?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface BaselineUpdateReport {
|
|
11
|
+
status: "updated" | "failed";
|
|
12
|
+
baselineSnapshotId?: string;
|
|
13
|
+
updatedRoutes: string[];
|
|
14
|
+
errors: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare function executeBaselineUpdate(options: BaselineUpdateOptions, args?: readonly string[], cwd?: string): Promise<BaselineUpdateReport>;
|
|
17
|
+
export declare const baselineUpdateCommand: InteractiveCommand;
|
|
18
|
+
export declare const baselineCommand: InteractiveCommand;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { resolveUrlPaths, updateSnapshotRoutesFromConfig, } from "@cleaver/breakcheck-core";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { InteractiveCommand } from "interactive-commander";
|
|
4
|
+
import { addConfigOptions, resolveCliProjectConfig } from "../config.js";
|
|
5
|
+
import { parseUrlManifest, readUrlManifest } from "../url-manifest.js";
|
|
6
|
+
import { withCheckEnvironment } from "../site-environment.js";
|
|
7
|
+
import { configureLogger } from "../utils.js";
|
|
8
|
+
function messageOf(error) {
|
|
9
|
+
if (error instanceof AggregateError) {
|
|
10
|
+
return [...error.errors].map(messageOf).join("; ");
|
|
11
|
+
}
|
|
12
|
+
return error instanceof Error ? error.message : String(error);
|
|
13
|
+
}
|
|
14
|
+
function requireHttpUrl(value) {
|
|
15
|
+
if (value === undefined || value.trim().length === 0) {
|
|
16
|
+
throw new Error("A site URL is required. Set baseUrl in breakcheck.config.json or pass --url.");
|
|
17
|
+
}
|
|
18
|
+
let parsed;
|
|
19
|
+
try {
|
|
20
|
+
parsed = new URL(value);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
throw new Error("The site URL must be a valid HTTP(S) URL.", {
|
|
24
|
+
cause: error,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
if ((parsed.protocol !== "http:" && parsed.protocol !== "https:") ||
|
|
28
|
+
!parsed.hostname) {
|
|
29
|
+
throw new Error("The site URL must be a valid HTTP(S) URL.");
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
async function readConfiguredRoutes(routesFile, baseUrl) {
|
|
34
|
+
const content = await readUrlManifest(routesFile);
|
|
35
|
+
const manifest = parseUrlManifest(content, baseUrl, routesFile);
|
|
36
|
+
if (manifest.issues.length > 0) {
|
|
37
|
+
throw new Error(manifest.issues
|
|
38
|
+
.map((issue) => issue.type === "entry"
|
|
39
|
+
? `${issue.source}:${issue.line}: ${issue.message} (${issue.value})`
|
|
40
|
+
: `${issue.source}: ${issue.message}`)
|
|
41
|
+
.join("\n"));
|
|
42
|
+
}
|
|
43
|
+
return manifest.paths;
|
|
44
|
+
}
|
|
45
|
+
export async function executeBaselineUpdate(options, args = process.argv.slice(2), cwd = process.cwd()) {
|
|
46
|
+
const logger = configureLogger({
|
|
47
|
+
jsonLogs: options.jsonLogs,
|
|
48
|
+
noJsonLogs: options.noJsonLogs,
|
|
49
|
+
silent: options.json,
|
|
50
|
+
});
|
|
51
|
+
const result = {
|
|
52
|
+
status: "failed",
|
|
53
|
+
updatedRoutes: [],
|
|
54
|
+
errors: [],
|
|
55
|
+
};
|
|
56
|
+
try {
|
|
57
|
+
if (options.all && options.route !== undefined) {
|
|
58
|
+
throw new Error("Use either --all or --route, not both.");
|
|
59
|
+
}
|
|
60
|
+
if (!options.all &&
|
|
61
|
+
(options.route === undefined || options.route.length === 0)) {
|
|
62
|
+
throw new Error("Provide --route <path...> or --all.");
|
|
63
|
+
}
|
|
64
|
+
const project = await resolveCliProjectConfig(args, cwd);
|
|
65
|
+
const check = project.check;
|
|
66
|
+
if (!check) {
|
|
67
|
+
throw new Error("No check settings found. Add a version-2 check section to breakcheck.config.json.");
|
|
68
|
+
}
|
|
69
|
+
const baseUrl = requireHttpUrl(options.url ?? project.baseUrl);
|
|
70
|
+
let routes;
|
|
71
|
+
if (options.all) {
|
|
72
|
+
routes = await readConfiguredRoutes(check.routesFile, baseUrl);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const resolution = resolveUrlPaths(baseUrl, options.route ?? []);
|
|
76
|
+
if (resolution.issues.length > 0) {
|
|
77
|
+
throw new Error(resolution.issues.map((issue) => issue.message).join("; "));
|
|
78
|
+
}
|
|
79
|
+
routes = resolution.paths;
|
|
80
|
+
}
|
|
81
|
+
const baselineSnapshotId = check.baselineSnapshot;
|
|
82
|
+
result.baselineSnapshotId = baselineSnapshotId;
|
|
83
|
+
const crawlSettings = {
|
|
84
|
+
baseUrl,
|
|
85
|
+
crawlerType: project.crawl.crawlerType ?? "cheerio",
|
|
86
|
+
maxDepth: project.crawl.maxDepth ?? 3,
|
|
87
|
+
maxConcurrency: project.crawl.maxConcurrency ?? 5,
|
|
88
|
+
includePatterns: [],
|
|
89
|
+
excludePatterns: [],
|
|
90
|
+
};
|
|
91
|
+
const snapshotConfig = {
|
|
92
|
+
baseUrl,
|
|
93
|
+
name: `baseline_update_${randomUUID().slice(0, 12)}`,
|
|
94
|
+
urlPaths: routes,
|
|
95
|
+
crawlSettings,
|
|
96
|
+
};
|
|
97
|
+
const update = await withCheckEnvironment(check, baseUrl, options.url !== undefined, (signal) => updateSnapshotRoutesFromConfig(snapshotConfig, baselineSnapshotId, {
|
|
98
|
+
storageDir: project.storageDir,
|
|
99
|
+
signal,
|
|
100
|
+
}));
|
|
101
|
+
result.status = "updated";
|
|
102
|
+
result.updatedRoutes = update.updatedRoutes;
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
result.errors.push(messageOf(error));
|
|
106
|
+
}
|
|
107
|
+
if (options.json) {
|
|
108
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
109
|
+
}
|
|
110
|
+
else if (result.status === "updated") {
|
|
111
|
+
logger.info(`✅ Updated ${result.updatedRoutes.length} route(s) in baseline "${result.baselineSnapshotId}": ${result.updatedRoutes.join(", ")}`);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
logger.error("❌ Baseline update failed.");
|
|
115
|
+
result.errors.forEach((message) => logger.error(` - ${message}`));
|
|
116
|
+
}
|
|
117
|
+
process.exitCode = result.status === "updated" ? 0 : 2;
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
export const baselineUpdateCommand = addConfigOptions(new InteractiveCommand("update")
|
|
121
|
+
.description("Update selected routes in the configured baseline snapshot")
|
|
122
|
+
.option("--route <path...>", "Update only these root-relative routes")
|
|
123
|
+
.option("--all", "Update every route in check.routesFile")
|
|
124
|
+
.option("-u, --url <url>", "Use an already-running site URL")
|
|
125
|
+
.option("--json", "Write a machine-readable result to stdout")
|
|
126
|
+
.option("--json-logs", "Output logs in JSON format")
|
|
127
|
+
.option("--no-json-logs", "Output logs in pretty format (default)")
|
|
128
|
+
.action(async (options) => {
|
|
129
|
+
await executeBaselineUpdate(options);
|
|
130
|
+
}));
|
|
131
|
+
export const baselineCommand = addConfigOptions(new InteractiveCommand("baseline").description("Manage the checked-in route baseline"));
|
|
132
|
+
baselineCommand.addCommand(baselineUpdateCommand);
|
|
133
|
+
//# sourceMappingURL=baseline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline.js","sourceRoot":"","sources":["../../../src/cli/commands/baseline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type CrawlError, type SiteCheckResult } from "@cleaver/breakcheck-core";
|
|
2
|
+
import { InteractiveCommand } from "interactive-commander";
|
|
3
|
+
interface CheckCommandOptions {
|
|
4
|
+
url?: string;
|
|
5
|
+
json?: boolean;
|
|
6
|
+
jsonLogs?: boolean;
|
|
7
|
+
noJsonLogs?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface CheckReport {
|
|
10
|
+
schemaVersion: 1;
|
|
11
|
+
runId: string;
|
|
12
|
+
status: "passed" | "differences" | "failed";
|
|
13
|
+
exitCode: 0 | 1 | 2;
|
|
14
|
+
startedAt: string;
|
|
15
|
+
completedAt: string;
|
|
16
|
+
reportPath?: string;
|
|
17
|
+
baseUrl?: string;
|
|
18
|
+
baselineSnapshotId?: string;
|
|
19
|
+
snapshotId?: string;
|
|
20
|
+
routes: string[];
|
|
21
|
+
crawlErrors: CrawlError[];
|
|
22
|
+
errors: string[];
|
|
23
|
+
comparison?: SiteCheckResult["comparison"];
|
|
24
|
+
}
|
|
25
|
+
export declare function executeCheck(options: CheckCommandOptions, args?: readonly string[], cwd?: string): Promise<CheckReport>;
|
|
26
|
+
export declare const checkCommand: InteractiveCommand;
|
|
27
|
+
export {};
|