uptide 0.2.0-next.20261003163159 → 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 CHANGED
@@ -2,143 +2,150 @@
2
2
 
3
3
  **Renovate updates the version. We update the code.**
4
4
 
5
- Uptide tells you which of your call sites a dependency upgrade breaks, then migrates
6
- them on a branch it has verified with your own compiler and tests. Today it covers
7
- **zod 3 → 4** and **stripe**, in TypeScript repositories.
5
+ Uptide tells you which of your lines a dependency upgrade breaks, then migrates them on a
6
+ branch it has verified with your own compiler and tests. TypeScript repositories; verified
7
+ migrations for **zod 3 → 4** and **stripe** today.
8
8
 
9
9
  ## Quickstart (30 seconds)
10
10
 
11
11
  No account, no config. In your repository, with dependencies installed:
12
12
 
13
13
  ```sh
14
- npx uptide # where zod and stripe stand: installed, latest, majors behind
15
- npx uptide check # which of your lines the upgrade breaks
16
- npx uptide fix --only zod # migrate on a new branch; nothing is pushed
14
+ npx uptide check # which of your lines the upgrade breaks
15
+ npx uptide fix --only zod # migrate on a new branch, verified; nothing is pushed
16
+ npx uptide pr --branch uptide/zod-4.6.5 # prints the plan; add --yes to push and open the PR
17
17
  ```
18
18
 
19
- Requires Node 20 or newer. `check` reads npm, pnpm (workspaces and catalogs), yarn
20
- classic and bun (text lockfile) repositories. `fix` supports npm (lockfile v2/v3, including workspaces), pnpm, and Yarn classic/Berry with the node-modules linker.
19
+ `npx uptide ` alone shows where zod and stripe stand: installed, latest, majors behind.
20
+ Requires Node 20 or newer. Works with npm, pnpm and Yarn (node-modules linker).
21
21
 
22
- ## What `check` prints
22
+ ## Before and after
23
23
 
24
- Real output, zod 3.23.8 → 4.6.5 on the pnpm workspace fixture in
25
- [`packages/cli/smoke/fixtures/pnpm`](packages/cli/smoke/fixtures/pnpm):
24
+ [`fixtures/repos/storefront`](fixtures/repos/storefront) is a small pnpm workspace in this
25
+ repository, written to exercise Uptide: two packages on zod 3 and stripe 14, with a few
26
+ tests. Everything below is real output from it.
27
+
28
+ **Before: `check`.** What breaks, where, and who can fix it:
26
29
 
27
30
  ```console
28
- $ uptide check --only zod
29
- uptide check · smoke-pnpm (pnpm, 2 packages) · 3.0s
31
+ $ npx uptide check
32
+ uptide check · storefront (pnpm, 2 packages) · 8.3s
30
33
 
31
- zod 3.23.8 → 4.6.5 major ✗ 4 breaking in 2 files 4 by rule
34
+ zod 3.25.76 → 4.6.5 major · latest on npm ✗ 28 breaking in 7 files 24 by rule · 4 by agent
35
+ stripe (packages/api) 14.25.0 → 23.0.0 major · latest on npm ✗ 4 breaking in 3 files 1 by rule · 3 by agent
32
36
 
33
37
  zod
34
- ✗ New error API (required_error → error) 4 sites by rule
38
+ ✗ New error API (required_error → error) 24 sites by rule
39
+ ✗ ZodTypeDef removed 1 fix, 3 errors by agent
40
+ ✗ .ip() removed monitoring.ts:6 by agent
41
+ ! 15 deprecated calls (.uuid, .datetime, .email, ...) 8 by rule
42
+
43
+ stripe
44
+ ✗ Test fixture casts widened renewal.test.ts:7 by rule
45
+ ✗ Subscription billing period moved to items 2 sites by agent
46
+ ✗ apiVersion no longer matches the SDK client.ts:9 by agent
47
+ 1 API change since 2023-10-16 affects your code
35
48
 
36
49
  Next
37
- npx uptide fix --only zod migrate on a new branch, verify, no push
38
- npx uptide check --only zod --details every site and reason
50
+ npx uptide fix --only zod migrate on a new branch, verify, no push
51
+ npx uptide fix --only stripe migrate on a new branch, verify, no push
52
+ npx uptide check --details every site and reason
39
53
  ```
40
54
 
41
- One row per dependency, one line per change, and the commands to run next. Each change
42
- says who migrates it, from a dry run of the same rules `fix` applies: **by rule** (a
43
- deterministic transform), **by agent** (the assisted fixer, verified by your compiler), or
44
- **manual** (no migration pack covers it). `--details` lists every site with its snippet,
45
- the reason, the raw compiler message and the analysis notes.
46
-
47
- While it runs, a terminal shows one live line with the current phase, which disappears
48
- when the work ends; `--verbose` keeps one line per phase with timings. In a pipe or with
49
- `--ci`, stderr gets a start line and the final timing. The report is on stdout. `check`
50
- diffs the public API of the installed and the target version, finds your usages of what
51
- changed, compiles your code against the target, and loads both versions in a sandboxed
52
- Node. Nothing in your repository is executed.
53
-
54
- | Flag | Meaning |
55
- | --- | --- |
56
- | `--only zod,stripe` | dependencies to check (the default); `--only all` checks every dependency |
57
- | `--target zod@4.6.5` | exact target, repeatable; default is `latest` |
58
- | `--details` | every site, reason, compiler message and analysis note |
59
- | `--verbose` | one progress line per analysis phase, with timings |
60
- | `--cwd <dir>` | repository to work on |
61
- | `--json` | the full report as JSON on stdout |
62
- | `--ci` | plain log output: no color, no spinner (`NO_COLOR` is respected too) |
63
-
64
- Exit codes, for scripts and CI: **0** nothing breaking, **1** breaking changes found,
65
- **2** uptide could not answer (bad arguments, unsupported repository, no network). When
66
- it cannot answer, it says why and prints the exact command to run next.
55
+ **After: `fix`**, one dependency at a time, each on its own verified branch:
56
+
57
+ ```console
58
+ $ npx uptide fix --only zod
59
+ uptide fix · zod 3.25.76 → 4.6.5 (latest on npm) · verification passed · 36s
60
+
61
+ Risk Medium: request validation in webhooks
62
+ Changes 29 sites in 8 files · 25 by rule · 4 by agent
63
+ Types ✅ 29 errors after the bump → 1 (1 pre-existing)
64
+ Behavior ✅ 9 schemas identical · 2 not checked · 21/21 custom-message assertions
65
+ Tests ✅ 5 tests in 3 files passed
66
+ ```
67
67
 
68
- ## What `fix` does, and how it verifies
68
+ No compiler sees this one: zod 4 words its default messages differently, and a test that
69
+ asserted the old wording failed after the migration. Uptide updated it and says so in the
70
+ pull request, so you can check that nothing else reads that text:
69
71
 
70
- On the same fixture (output abridged):
72
+ ```diff
73
+ - expect(parsed.error?.issues[0]?.message).toBe('Required');
74
+ + expect(parsed.error?.issues[0]?.message).toBe('Invalid input: expected string, received undefined');
75
+ ```
71
76
 
72
77
  ```console
73
- $ uptide fix --only zod --no-llm
74
- uptide fix · zod 3.23.8 → 4.6.5 (latest on npm) · verification passed · 5.3s
75
-
76
- Risk Low: rule-based edits, verified
77
- Changes 4 sites in 2 files · 4 by rule · 0 by agent
78
- Types ✅ 4 errors after the bump → 0
79
- Behavior ✅ 2 schemas identical
80
- Tests ✅ 12 related tests passed
78
+ $ npx uptide fix --only stripe
79
+ uptide fix · stripe 14.25.0 → 23.0.0 (latest on npm) · verification passed · 41s
80
+
81
+ Risk High: behavior changes
82
+ Changes 6 sites in 3 files · 3 by rule · 3 by agent
83
+ Types ✅ 5 errors after the bump → 1 (1 pre-existing)
84
+ Behavior ⚠️ 1 of 570 API changes affects your code · 47 touch resources you use (8 breaking)
85
+ Tests ✅ 3 tests in 2 files passed · the test script of packages/api
86
+ ```
81
87
 
82
- Branch uptide/zod-4.6.5 (in your repository, not checked out)
83
- git diff main..uptide/zod-4.6.5 --stat
88
+ Stripe moved a subscription's billing period from the subscription to its items. Uptide
89
+ added a `subscriptionPeriod` helper and migrated the code that read the old fields:
84
90
 
85
- Next
86
- npx uptide pr --branch uptide/zod-4.6.5 push the branch and open a draft PR on you/app
87
- open .git/uptide/uptide__zod-4.6.5/report.html the migration report
88
- .git/uptide/uptide__zod-4.6.5/pr-body.md the PR description
91
+ ```diff
92
+ - renewsAt: new Date(subscription.current_period_end * 1000),
93
+ + renewsAt: new Date(period.end * 1000),
89
94
  ```
90
95
 
91
- While it runs, a terminal shows one live line with the phase and what it is verifying
92
- (`verify · tests (api, web)`); `--verbose` prints one line per phase with timings. The
93
- target is the npm `latest` dist-tag, the same one `check` compares against, unless
94
- `--target` names a version.
95
-
96
- Everything below happens in a temporary clone of your repository, never in your checkout:
97
- your branch, files, git hooks and git config are compared before and after and must be
98
- the same. You get the migration branch as a ref and the run stored inside `.git`. The
99
- clone is removed when the run is over; it is kept, and its path printed, when the run
100
- fails or you pass `--keep`, and `uptide clean` removes kept clones older than 7 days.
101
-
102
- 1. **Starts clean.** It needs a git repository with a clean working tree, and works on a
103
- new branch `uptide/<package>-<version>`. Nothing is pushed unless you pass `--pr --yes`,
104
- or later run `uptide pr --branch <branch> --yes`, which loads the stored run, checks the
105
- branch is still at the verified commit (else `uptide verify`), prints which repository
106
- the PR goes to (a fork itself, never its parent unless `--repo` names it) and opens it
107
- with the stored description.
108
- 2. **Upgrades.** Bumps the version in every workspace that declares it (and in pnpm
109
- catalogs), preserving `^`, `~`, or exact ranges. Installs run in a temporary git worktree with lifecycle scripts disabled. The real package manager produces the lockfile; Uptide rejects changes outside the target dependency subtree before copying it back unchanged. One commit.
110
- 3. **Rule-based fixes.** Deterministic rewrites for the changes it has rules for, such as
111
- zod's `required_error` / `invalid_type_error` (add `--include-deprecated` for
112
- `z.string().email()`-style chains). One commit.
113
- 4. **Assisted fixes (optional).** With `ANTHROPIC_API_KEY` set, sites the rules cannot
114
- migrate go to the LLM one at a time. A patch is kept only if it removes its compiler
115
- error and introduces none; otherwise it is reverted and the site is left for you.
116
- `--no-llm` turns this off.
117
- 5. **Verifies.** Type-checks with *your* TypeScript (or the bundled compiler when absent) before and after and subtracts the
118
- errors you already had; runs the tests of the affected workspaces (each workspace's
119
- `test` script, else the vitest or jest configuration that covers it, scoped to the
120
- tests related to the migrated files, else the root `test` script) and reports what ran;
121
- by default only tests that need no database, cache or queue run, and the report counts the
122
- integration tests it left out (`--with-services --yes` includes them, after printing what
123
- they connect to); formats the files it edited, and only those, with your formatter and runs your lint
124
- (biome, prettier, eslint) on them, where a new lint failure fails verification; for zod,
125
- compares v3 and v4 behaviour of your schemas on generated inputs. The exit code is 0
126
- only if no new type error remains and tests pass. Passing compilation does not prove
127
- runtime equivalence, so the report (`pr-body.md` and `report.html` next to the stored
128
- run in `.git/uptide/<branch>/`) lists what to review.
129
-
130
- Stripe API-version changes are never rewritten by rule: they are assisted or left for
131
- you, with the relevant changelog entries and a dashboard/webhook checklist in the report.
132
-
133
- ## Scope
134
-
135
- - **Dependencies:** zod 3 → 4 and stripe (14 and newer). Other dependencies can be
136
- checked with `uptide check --only <package>`, but that generic check is frozen
137
- ([decision](docs/decisions/0010-check-freeze.md)) and has no migrations.
96
+ The risk is High on purpose: types and tests pass, but a new API version changes what
97
+ Stripe sends, and the pull request asks what only you can answer (which item's period
98
+ counts when a subscription has several).
99
+
100
+ The one type error left in both runs is the fixture's own, there on purpose: errors a
101
+ repository already had are subtracted, never blamed on the upgrade.
102
+
103
+ ## What is supported
104
+
105
+ | Tier | Dependencies | What you get |
106
+ | --- | --- | --- |
107
+ | **Verified** | zod 3 → 4, stripe 14 and newer | `check` with a migration plan per change, `fix` with rules written for that dependency, behavior checks (zod schemas compared on generated inputs; Stripe changelog filtered to what you call), a reviewed pull request body |
108
+ | **Generic** | any other dependency, with `--only <package>` | `check` only: the API diff between the two versions, your usages of what changed, and the compiler's errors against the target. No migrations. |
109
+
110
+ Verified means a migration pack exists: rules, a guide for the assisted fixer, and ground
111
+ truth from a real upgrade that the pack is scored against. Generic is the same analysis
112
+ without that knowledge; it is frozen while the packs mature
113
+ ([decision](docs/decisions/0010-check-freeze.md)), and generic *migrations* are planned,
114
+ not shipped.
115
+
138
116
  - **Languages:** TypeScript, and JavaScript the compiler can see (`allowJs`).
139
- - **Package managers:** `check` on npm, pnpm, yarn classic, bun; `fix` on npm v2/v3, pnpm, and Yarn classic/Berry (node-modules).
117
+ - **Package managers:** `check` on npm, pnpm (workspaces and catalogs), Yarn classic and
118
+ bun (text lockfile); `fix` on npm (lockfile v2/v3), pnpm, and Yarn classic/Berry with the
119
+ node-modules linker.
140
120
  - **Not supported:** Yarn Plug'n'Play, bun's binary lockfile, Deno.
141
121
 
122
+ ## How verification works
123
+
124
+ `fix` never works in your checkout. It clones your repository into a temporary directory
125
+ and, there:
126
+
127
+ 1. **Baseline.** Type-checks and notes the errors you already have.
128
+ 2. **Upgrades.** Bumps the version everywhere it is declared. Your package manager
129
+ produces the lockfile, with lifecycle scripts disabled; a lockfile change outside the
130
+ upgraded dependency's subtree is rejected.
131
+ 3. **Rule-based fixes.** Deterministic rewrites, only at the sites `check` reported.
132
+ 4. **Assisted fixes (optional).** Sites no rule covers go to the LLM one at a time. A patch
133
+ is kept only if it removes its compiler error, introduces none, and passes the pack's
134
+ own validator; otherwise it is reverted and the site is left for you.
135
+ 5. **Verifies.** Type-checks with *your* TypeScript and subtracts the baseline; runs the
136
+ tests related to the files it touched; formats and lints only those files with your
137
+ tools. Tests that need a database, cache or queue do not run unless you ask
138
+ (`--with-services --yes`), and the report counts what was left out.
139
+
140
+ The exit code is 0 only if no new type error remains and the tests pass. You get the branch
141
+ as a ref in your repository and the run stored in `.git/uptide/`; your branch, files, hooks
142
+ and git config are compared before and after and must be identical. Nothing is pushed
143
+ until you run `uptide pr` or pass `--pr --yes`.
144
+
145
+ Passing compilation does not prove runtime equivalence. The report says what was verified,
146
+ what was not, and what to review; server API changes (Stripe API versions) are never
147
+ rewritten by rule.
148
+
142
149
  ## Privacy
143
150
 
144
151
  Analysis runs locally. Your code is sent only to the LLM provider (Anthropic), only
@@ -148,117 +155,35 @@ error. `uptide fix --no-llm` turns assisted fixes off. No telemetry, no account.
148
155
  Other network use: your npm registry for package metadata and tarballs, and GitHub
149
156
  only when you pass `fix --pr` or run `pr-body`.
150
157
 
151
- ## GitHub Action: Renovate / Dependabot
152
-
153
- Use [the example workflow](examples/uptide-workflow.yml), pinning a reviewed commit of `lucasbraum/uptide`. It checks same-repository bot PRs on `pull_request`
154
- `opened`/`synchronize`, detects zod/stripe upgrades from manifests, catalogs and lockfile
155
- importers, and maintains one sticky findings comment. `only` selects dependencies;
156
- `paths` selects repository-relative source directories/globs.
157
-
158
- `fix: 'true'` plus `anthropic-api-key` enables migration. Comparison uses **PR-head
159
- source with the base dependency graph** in a temporary worktree. Final verification
160
- uses the actual PR-head manifests/lockfile; only source patches are transferred. A
161
- passing migration pushes **one commit on the existing PR branch**. Manual sites,
162
- failed tests/types, or a changed PR head prevent publication. No force-push or merge.
163
- Current migration support is TypeScript, zod and stripe, using npm, pnpm or Yarn with node_modules. Missing workspace test
164
- scripts are reported, not claimed as passing tests. Code context may be sent to
165
- Anthropic only in assisted mode. Install/test children receive no API/token secrets.
166
-
167
- Use `contents: write` and `pull-requests: write`, `persist-credentials: false`, and the
168
- same-PR concurrency group shown in the example. Dependabot PRs normally receive a
169
- read-only `GITHUB_TOKEN` and do not receive ordinary Actions secrets: configure the
170
- key and an appropriately scoped write token as **Dependabot secrets**, or run in a
171
- maintainer-controlled workflow. Do not change to `pull_request_target` to bypass
172
- this boundary. Fork PRs are skipped. See [GitHub's Dependabot restrictions](https://docs.github.com/en/code-security/reference/supply-chain-security/troubleshoot-dependabot/dependabot-on-actions).
173
-
174
- ```sh
175
- pnpm eval:action # local GitHub API simulation + real check/fix/tsc/tests/git remote
176
- ```
177
-
178
- This creates an isolated demo repository and bare local remote under `eval-out/`,
179
- with a zod 3 baseline, a Renovate-style bump branch, and the verified migration result.
180
- It also proves that a final-verification failure cannot push. The generated README
181
- contains commands to publish your throwaway repository. **No hosted GitHub run or PR
182
- is created by this evaluation.** The real workflow requires a bot-authored PR; a
183
- human-authored imitation is intentionally rejected.
184
-
185
- ## PR descriptions
186
-
187
- `fix` saves `.uptide/report.json` with the verified commit, Uptide version/commit, rule IDs, patches, agent
188
- reasoning and run metadata. PR bodies show a computed risk, a five-row summary, changes
189
- grouped by rule, and actionable review items.
190
-
191
- To regenerate an existing description without another migration or any push:
158
+ There is no Uptide server. In a table:
192
159
 
193
- ```sh
194
- uptide pr-body --pr 82 --preview # review the complete proposal first
195
- uptide pr-body --pr 82 # update only the description
196
- # For a retained eval run, add --cwd /path/to/target/repo --run /path/to/report.json.
197
- ```
198
-
199
- The selected PR must match the stored run's branch and verified commit. Risk is Low
200
- for verified rule-only edits, Medium for agent edits, sensitive paths or missing tests,
201
- and High for unverified sites, behavior changes or remaining manual work. Unchecked
202
- schema samples are called out separately; they do not imply unresolved compiler sites.
160
+ | | Where it runs | What leaves your machine |
161
+ | --- | --- | --- |
162
+ | `check` | locally | nothing of yours; it downloads package tarballs from your npm registry. No LLM call, and nothing in your repository is executed. |
163
+ | `fix`, rules and verification | locally, in a temporary clone | nothing of yours |
164
+ | `fix`, assisted fixes | Anthropic's API, with **your** `ANTHROPIC_API_KEY` | per site no rule covers: the finding, the enclosing function or declaration, and the compiler error |
165
+ | `pr`, `fix --pr` | GitHub, through your own `gh` | the branch and the pull request, when you say so |
203
166
 
204
- Builds embed the Uptide commit and whether its source checkout had working-tree changes.
205
- `pnpm exec tsx scripts/reverify-run.ts <run.json> [output.json]` refreshes behavior
206
- and type verification on the recorded commit without installing or changing source.
207
- Diffs, file lists, verification and run details are collapsed; the Action comment and
208
- terminal share the compact migration renderer.
167
+ Without a key, or with `--no-llm`, those sites are listed for you instead. The full model, and how to report a problem, is in
168
+ [SECURITY.md](SECURITY.md).
209
169
 
210
- ## Development
170
+ ## Exit codes
211
171
 
212
- ```sh
213
- pnpm test # offline regressions
214
- UPTIDE_NETWORK=1 pnpm test # real package digests and Stripe tsc fixture
215
- pnpm eval:fix ../wayapi --without-key
216
- pnpm eval:fix ../wayapi --with-key
217
- # Only after reviewing a successful eval, publish from another temporary worktree:
218
- pnpm eval:fix ../wayapi --with-key --pr --yes
219
- pnpm eval:fix /path/to/repo --only=stripe --target=stripe@22.6.2 --without-key
220
- pnpm eval:check /path/to/repo --only=stripe --target=stripe@23.0.0 --truth=fixtures/truth/traceroot-stripe.json
221
- ```
222
-
223
- `eval:check --truth` scores a check against the new `tsc` errors a real upgrade produced
224
- (`fixtures/truth/*.json`: wayapi on zod 4 and stripe 22, the traceroot fork on stripe 23);
225
- a case's `runtime` sites are what no compiler shows, such as a Stripe client created
226
- without `apiVersion`, scored apart.
227
-
228
- `eval:fix` creates a temporary git worktree, copies installed dependencies (not symlinks
229
- to the source repo), and retains the result for review. Artifacts go in `eval-out/`.
230
- `--with-key` fails explicitly when no key is configured. `pnpm eval:stripe-fixture`
231
- measures the checked-in Stripe consumer with real `tsc`; `pnpm build:stripe-changelog`
232
- refreshes the versioned public changelog JSON. Migration execution never fetches it.
172
+ For scripts and CI: **0** nothing breaking, **1** breaking changes found,
173
+ **2** uptide could not answer (bad arguments, unsupported repository, no network). When
174
+ it cannot answer, it says why and prints the exact command to run next.
233
175
 
234
- `uptide diff <pkg> <from> <to> [--json]` compares the full public surface of two
235
- versions. Tarballs, surfaces and runtime probes are cached in `~/.cache/uptide/`.
236
- Releasing is described in [docs/releasing.md](docs/releasing.md); `pnpm smoke` runs the
237
- packed CLI against npm v3, npm workspaces v2, pnpm catalogs, Yarn classic and Yarn Berry fixtures in clean Node 20/22 containers. Run `pnpm smoke 20` and `pnpm smoke 22`. Each case verifies zod migration and a compatible Stripe SDK upgrade without an LLM; lifecycle-script traps must remain untouched. Lockfile diffs and JSON results are saved beside the temporary CLI tarball.
176
+ ## Documentation
238
177
 
239
- Yarn PnP remains unsupported. Missing package-manager binaries or mismatched pinned versions fail with an exact Corepack recovery command. Unsupported range/lockfile syntax fails explicitly rather than silently broadening the upgrade.
178
+ - [CLI reference](docs/cli.md): flags, the HTML report, each step of `fix`, pull request
179
+ descriptions
180
+ - [GitHub Action](docs/github-action.md): check and migrate Renovate and Dependabot pull
181
+ requests
182
+ - [Architecture](docs/architecture.md) and [decisions](docs/decisions/): how it works and why
183
+ - [Security](SECURITY.md): the isolation model
184
+ - [Contributing](CONTRIBUTING.md): setup, tests, how migration packs work
185
+ - [Development](docs/development.md) and [releasing](docs/releasing.md)
240
186
 
241
187
  ## License
242
188
 
243
189
  [MIT](LICENSE).
244
-
245
- ### Share a local HTML check report
246
-
247
- ```sh
248
- uptide check --html # terminal output + <OS temp>/uptide/<repo>-<timestamp>.html
249
- uptide check --html review.html # explicit output path, relative to your current directory
250
- uptide check --html --open # open the default browser in an interactive terminal
251
- uptide check --json --html --ci # stdout stays JSON; the HTML path is printed on stderr
252
- ```
253
-
254
- The report uses the terminal's migration plan: dependency summary first, then expandable
255
- rules and sites, deprecated calls, analysis notes, and copyable next commands. Search
256
- and severity filters work with plain inline JavaScript; the report remains readable
257
- without it. Printing expands the details. Dark/light themes follow your system.
258
-
259
- One self-contained file, no network requests, web fonts, images, or analytics. It includes
260
- only the reported source excerpts (three lines before/after, up to 50 excerpts per group),
261
- with VS Code file links. Missing or out-of-repository files are disclosed instead of read.
262
- Long lines/excerpts and very large reports are trimmed with a notice to keep the file
263
- below 300 KB. Review excerpts before sharing. `--open` never opens a browser in CI or
264
- when output is redirected; `--open` requires `--html`.