From 6ac6eeef03fb9c6694e27958726a7aba44c16674 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 20:03:45 +0000 Subject: [PATCH] chore: version packages --- .changeset/action-base-ref-sha.md | 11 - .changeset/action-pin-head-sha.md | 11 - .changeset/action-smoke-test.md | 6 - .changeset/agents-md-orientation.md | 2 - .changeset/ai-change-analyzer.md | 5 - .changeset/ai-false-positive-fixes.md | 11 - .changeset/ai-prompt-token-diet.md | 13 - .changeset/ai-smoke-deflake-notify.md | 4 - .changeset/analyzer-rewrite.md | 5 - .changeset/baseline-artifact.md | 12 - .changeset/baseline-producer-stamp.md | 5 - .../breaking-first-report-ai-coverage.md | 19 -- .changeset/changesets-release-pat.md | 2 - .../ci-concurrency-and-baseline-pins.md | 6 - .changeset/ci-redesign.md | 2 - .../comment-size-and-ai-verdict-guard.md | 15 -- .changeset/composite-action.md | 5 - .changeset/coverage-growth-additions.md | 35 --- .changeset/dependabot-changeset-exempt.md | 2 - .changeset/dependabot-gha-bump.md | 2 - .changeset/dependabot-npm.md | 6 - .changeset/deps-anthropic-sdk-0-100.md | 5 - .changeset/deps-commander-15.md | 5 - .changeset/deps-safe-batch.md | 2 - .changeset/deps-typescript-6.md | 2 - .changeset/deps-zod-4.md | 7 - .changeset/drop-sourcemaps.md | 5 - .changeset/enforce-sha-pinned-actions.md | 7 - .changeset/exempt-release-pr-changeset.md | 2 - .changeset/fail-soft-per-entry.md | 14 -- .../fix-baseline-artifact-hidden-files.md | 7 - .changeset/fix-release-pnpm-version.md | 2 - .changeset/fix-rest-parameter-detection.md | 10 - .changeset/gitignore-readme-housekeeping.md | 4 - .changeset/harden-gh-actions.md | 2 - .changeset/ignore-hashed-chunks.md | 11 - .changeset/import-notation-normalization.md | 9 - .changeset/license-and-release-pipeline.md | 5 - .changeset/lint-workflows-and-action-shell.md | 5 - .changeset/no-stray-api-report.md | 5 - .changeset/oss-readiness.md | 2 - .changeset/oss-sweep-hardening.md | 9 - .changeset/pkg-pr-new-workflow.md | 4 - .changeset/pnpm-11.md | 2 - .changeset/production-readiness.md | 5 - .changeset/release-version-run-script.md | 8 - .changeset/rename-break-check.md | 5 - .changeset/reporter-static-vs-ai-voices.md | 5 - .changeset/reporter-version-target.md | 5 - .changeset/secure-baseline-filenames.md | 11 - .changeset/security-action-fail-closed.md | 7 - .changeset/security-detect-false-negatives.md | 7 - .changeset/security-overrides.md | 5 - .changeset/security-report-ai-hardening.md | 7 - .changeset/self-dogfood.md | 4 - .changeset/snapi-ai-model-env.md | 5 - .changeset/subpath-exports.md | 5 - .changeset/test-init-and-api-diff-branches.md | 6 - .changeset/unified-diff-rendering.md | 11 - .changeset/unresolvable-subpath-refs.md | 13 - .changeset/version-analyzer-tests.md | 4 - .changeset/wildcard-subpath-expansion.md | 11 - CHANGELOG.md | 227 ++++++++++++++++++ package.json | 2 +- 64 files changed, 228 insertions(+), 430 deletions(-) delete mode 100644 .changeset/action-base-ref-sha.md delete mode 100644 .changeset/action-pin-head-sha.md delete mode 100644 .changeset/action-smoke-test.md delete mode 100644 .changeset/agents-md-orientation.md delete mode 100644 .changeset/ai-change-analyzer.md delete mode 100644 .changeset/ai-false-positive-fixes.md delete mode 100644 .changeset/ai-prompt-token-diet.md delete mode 100644 .changeset/ai-smoke-deflake-notify.md delete mode 100644 .changeset/analyzer-rewrite.md delete mode 100644 .changeset/baseline-artifact.md delete mode 100644 .changeset/baseline-producer-stamp.md delete mode 100644 .changeset/breaking-first-report-ai-coverage.md delete mode 100644 .changeset/changesets-release-pat.md delete mode 100644 .changeset/ci-concurrency-and-baseline-pins.md delete mode 100644 .changeset/ci-redesign.md delete mode 100644 .changeset/comment-size-and-ai-verdict-guard.md delete mode 100644 .changeset/composite-action.md delete mode 100644 .changeset/coverage-growth-additions.md delete mode 100644 .changeset/dependabot-changeset-exempt.md delete mode 100644 .changeset/dependabot-gha-bump.md delete mode 100644 .changeset/dependabot-npm.md delete mode 100644 .changeset/deps-anthropic-sdk-0-100.md delete mode 100644 .changeset/deps-commander-15.md delete mode 100644 .changeset/deps-safe-batch.md delete mode 100644 .changeset/deps-typescript-6.md delete mode 100644 .changeset/deps-zod-4.md delete mode 100644 .changeset/drop-sourcemaps.md delete mode 100644 .changeset/enforce-sha-pinned-actions.md delete mode 100644 .changeset/exempt-release-pr-changeset.md delete mode 100644 .changeset/fail-soft-per-entry.md delete mode 100644 .changeset/fix-baseline-artifact-hidden-files.md delete mode 100644 .changeset/fix-release-pnpm-version.md delete mode 100644 .changeset/fix-rest-parameter-detection.md delete mode 100644 .changeset/gitignore-readme-housekeeping.md delete mode 100644 .changeset/harden-gh-actions.md delete mode 100644 .changeset/ignore-hashed-chunks.md delete mode 100644 .changeset/import-notation-normalization.md delete mode 100644 .changeset/license-and-release-pipeline.md delete mode 100644 .changeset/lint-workflows-and-action-shell.md delete mode 100644 .changeset/no-stray-api-report.md delete mode 100644 .changeset/oss-readiness.md delete mode 100644 .changeset/oss-sweep-hardening.md delete mode 100644 .changeset/pkg-pr-new-workflow.md delete mode 100644 .changeset/pnpm-11.md delete mode 100644 .changeset/production-readiness.md delete mode 100644 .changeset/release-version-run-script.md delete mode 100644 .changeset/rename-break-check.md delete mode 100644 .changeset/reporter-static-vs-ai-voices.md delete mode 100644 .changeset/reporter-version-target.md delete mode 100644 .changeset/secure-baseline-filenames.md delete mode 100644 .changeset/security-action-fail-closed.md delete mode 100644 .changeset/security-detect-false-negatives.md delete mode 100644 .changeset/security-overrides.md delete mode 100644 .changeset/security-report-ai-hardening.md delete mode 100644 .changeset/self-dogfood.md delete mode 100644 .changeset/snapi-ai-model-env.md delete mode 100644 .changeset/subpath-exports.md delete mode 100644 .changeset/test-init-and-api-diff-branches.md delete mode 100644 .changeset/unified-diff-rendering.md delete mode 100644 .changeset/unresolvable-subpath-refs.md delete mode 100644 .changeset/version-analyzer-tests.md delete mode 100644 .changeset/wildcard-subpath-expansion.md create mode 100644 CHANGELOG.md diff --git a/.changeset/action-base-ref-sha.md b/.changeset/action-base-ref-sha.md deleted file mode 100644 index 30ef0e7..0000000 --- a/.changeset/action-base-ref-sha.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Action: anchor the baseline on the PR's `base.sha`, not `base_ref`. - -The composite Action defaulted `base-ref` to `${{ github.base_ref }}` (a branch name) and then ran `git worktree add ... "origin/$BASE_REF"`. That checks out the _current tip_ of the base branch at the moment the workflow runs, not the commit the PR was actually opened against. When `main` advanced between the PR being opened and the check running, break-check diffed against a tree the PR author never saw, producing inverted or fabricated change reports. - -The default is now `${{ github.event.pull_request.base.sha || github.base_ref }}` and the fetch/worktree step checks out `FETCH_HEAD` so it works for both SHAs and branch names. The dogfood workflow (`.github/workflows/api-check.yml`) gets the same treatment. - -Fixes #32. diff --git a/.changeset/action-pin-head-sha.md b/.changeset/action-pin-head-sha.md deleted file mode 100644 index 8a566f6..0000000 --- a/.changeset/action-pin-head-sha.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Action: pin the "current" side of the diff to the PR head SHA, not the `refs/pull/N/merge` ref. - -The composite Action (and the dogfood workflow) built whatever the caller checked out as the "current" side. On `pull_request` events `actions/checkout` resolves `refs/pull/N/merge` by default: the PR head merged into the _moving_ tip of the base branch. Once the base branch advanced, that merged tree absorbed unrelated changes and break-check reported them as the PR's own, e.g. a phantom `configureSSOMobileNavbar` addition on a CI-only PR (#32). Anchoring the baseline on `base.sha` was necessary but not sufficient; the current side floated too. - -The Action now takes a `head-ref` input (default `${{ github.event.pull_request.head.sha }}`), builds it in an isolated worktree symmetric with the baseline, and runs detect there. Non-PR events fall back to building the workspace. `.github/workflows/api-check.yml` gets the same treatment. - -Completes the fix for #32. diff --git a/.changeset/action-smoke-test.md b/.changeset/action-smoke-test.md deleted file mode 100644 index acdb13d..0000000 --- a/.changeset/action-smoke-test.md +++ /dev/null @@ -1,6 +0,0 @@ ---- ---- - -CI: add an Action Smoke workflow that runs the composite Action (action.yml) -end-to-end against this repo, driving the real CLI from a locally packed -tarball. Tooling-only; no change to the published package. diff --git a/.changeset/agents-md-orientation.md b/.changeset/agents-md-orientation.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/agents-md-orientation.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/ai-change-analyzer.md b/.changeset/ai-change-analyzer.md deleted file mode 100644 index 1b3aa21..0000000 --- a/.changeset/ai-change-analyzer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Add opt-in AI-powered analysis of detected API changes. When `BREAK_CHECK_ANTHROPIC_API_KEY` is set, break-check sends each package's rule-based change list and a compact view of the baseline/current API surface to Anthropic's Claude. The model re-classifies changes (overriding the rule-based verdict in either direction, with rationale and migration guidance) and scans for breaks the rules missed. Failures fall back to rule-based output, so the CLI exit code never depends on AI availability. By default the AI call is skipped for diffs that the rule-based pass classified as pure additions; set `BREAK_CHECK_AI_STRICT=1` (or `ai.strict: true` in config, or pass `--ai-strict`) to run the deeper scan in those cases too. Configurable via a new `ai` block in `break-check.config.json` and the `--no-ai` / `--ai-model` / `--ai-strict` CLI flags. diff --git a/.changeset/ai-false-positive-fixes.md b/.changeset/ai-false-positive-fixes.md deleted file mode 100644 index d719a49..0000000 --- a/.changeset/ai-false-positive-fixes.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Stop the AI reviewer confirming two backwards-compatible changes as breaking, and add a config escape hatch for the rest. - -Adding an optional property (including one widened into a `Pick`/`Omit`) was confirmed breaking because the prompt never said it was safe and never forbade a verdict left conditional on a fact already in context. New classification rules fix that. Adding a required field to a read-only output type was confirmed breaking because the model only ever saw a type's forward references, never its callers, so it couldn't tell an input type from an output one. The focused verdict context now also carries a "Usage sites" block: the signatures that reference each changed type, gathered across the package's sibling subpath surfaces (the type and the function returning it usually live in different rollups). Both fixes only ever enable a downgrade, which still stays gated behind `--ai-apply-downgrades`. - -New `acknowledgedChanges` config option: list a breaking change by name (`OAuthConsentInfo`, `@clerk/shared#OAuthConsentInfo`, or a `Clerk.__internal_*` glob) to downgrade it to non-breaking and tag it `acknowledged` in the report. Unlike an AI downgrade this is unconditional. - -Fixes #56. diff --git a/.changeset/ai-prompt-token-diet.md b/.changeset/ai-prompt-token-diet.md deleted file mode 100644 index 261645d..0000000 --- a/.changeset/ai-prompt-token-diet.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Rework the AI reviewer around the downgrade decision and split the old `strict` flag into two orthogonal opt-ins. - -The verdict call now sends a focused context instead of the whole API surface: for each change, only the definitions of the types its signature references (resolved transitively through API Extractor's canonical references), with a referenced type's baseline definition included where it changed so equivalence can be judged old-vs-new. On a large package that is a handful of types instead of hundreds of signatures. The change list is compact JSON and rationales are capped at one sentence. - -Downgrades are no longer applied by default. A `breaking -> non-breaking` verdict is the only operation that can clear a flagged break, so by default it is recorded as a suggestion (the change stays breaking) and applied only with `--ai-apply-downgrades` / `BREAK_CHECK_AI_APPLY_DOWNGRADES` / `ai.applyDowngrades`. The default path therefore cannot turn a flagged break into a non-break, and if a referenced type can't be resolved the model is told to keep "breaking", so a thin context costs a missed downgrade (noise), never a shipped break. - -The old `strict` flag is removed. Its missed-breaks audit (which sends both the baseline and current surfaces so the model can diff old vs new, and reviews additions-only diffs) is now its own opt-in: `--ai-scan` / `BREAK_CHECK_AI_SCAN` / `ai.scanForMissed`. Applying downgrades and running the audit are independent; combine them for the most thorough run. - -Migration: `--ai-strict` and `ai.strict` no longer exist. The flag errors as an unknown option, and a config that still sets `ai.strict` now fails validation with an "unrecognized key" error (the `ai` block rejects unknown keys) instead of silently doing nothing. Replace it with `ai.scanForMissed: true` (the audit) and/or `ai.applyDowngrades: true` (relax verdicts). diff --git a/.changeset/ai-smoke-deflake-notify.md b/.changeset/ai-smoke-deflake-notify.md deleted file mode 100644 index 4d9ad2b..0000000 --- a/.changeset/ai-smoke-deflake-notify.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -ci: make the nightly AI smoke audit test non-gating and alert on failure. Workflow- and test-only, no published-package impact. diff --git a/.changeset/analyzer-rewrite.md b/.changeset/analyzer-rewrite.md deleted file mode 100644 index 2fbc8c1..0000000 --- a/.changeset/analyzer-rewrite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Rewrite the API diff analyzer to use structured comparison instead of joined-token string diffs. Parameter renames and whitespace differences no longer surface as breaking changes; optional/required parameter flips, added optional parameters, return-type changes, and property-type changes are now classified individually. Interface body edits are no longer double-counted at the container level. diff --git a/.changeset/baseline-artifact.md b/.changeset/baseline-artifact.md deleted file mode 100644 index ba16e0c..0000000 --- a/.changeset/baseline-artifact.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Composite Action can now consume a baseline snapshot uploaded from a separate -push-to-main workflow, instead of always rebuilding the base ref. Set the new -`baseline-artifact-name` input to the artifact name; the Action downloads the -most recent matching artifact on `base-ref` and uses it as the baseline. Falls -back to the worktree rebuild on miss, expiry, or download failure, so existing -configurations keep working unchanged. Optional `baseline-max-age` (hours) -caps how old a downloaded artifact may be before falling back. See the -"Larger monorepos" section of the README for the producer workflow. diff --git a/.changeset/baseline-producer-stamp.md b/.changeset/baseline-producer-stamp.md deleted file mode 100644 index 13bcd7a..0000000 --- a/.changeset/baseline-producer-stamp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Snapshot metadata (`break-check.snapshot.json`) now records the producing `breakCheckVersion` and `apiExtractorVersion` under `schemaVersion: 3`. On `break-check detect`, a baseline whose recorded `@microsoft/api-extractor` major differs from the running one is refused with a structured error, since the hand-rolled `.api.json` reader is not guaranteed compatible across API Extractor majors and would otherwise produce silently nonsensical diffs. Pre-stamp baselines (schemaVersion 1 or 2) still load, with a stderr warning suggesting regeneration. `parseApiJson` also gained a shape check that throws on an unrecognized `.api.json` structure rather than returning an empty surface. diff --git a/.changeset/breaking-first-report-ai-coverage.md b/.changeset/breaking-first-report-ai-coverage.md deleted file mode 100644 index 8233599..0000000 --- a/.changeset/breaking-first-report-ai-coverage.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Make the report breaking-first and stop silently trusting incomplete AI reviews. - -A single AI review call that fails (the classic trigger: one huge type whose -before/after snippet dominated the request) used to leave every change in that -subpath with its pessimistic rule-based verdict and no annotation, while the -report still claimed full AI coverage. The analyzer now caps oversized -before/after snippets and bounds the focused-surface block by size so the call -fits, splits-and-retries a failed batch into smaller ones, and records any -review it still can't complete. Those gaps surface in the report: the "reviewed -by" stamp is marked `(partial)` and a callout lists the affected subpaths. - -The report also leads with breaking changes: a breaking-changes index up front -(survives the size-budget truncation), packages and subpaths ordered -breaking-first, breaking sections never collapsed, and non-breaking sections -collapsed behind `
` in large reports. diff --git a/.changeset/changesets-release-pat.md b/.changeset/changesets-release-pat.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/changesets-release-pat.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/ci-concurrency-and-baseline-pins.md b/.changeset/ci-concurrency-and-baseline-pins.md deleted file mode 100644 index eb653c0..0000000 --- a/.changeset/ci-concurrency-and-baseline-pins.md +++ /dev/null @@ -1,6 +0,0 @@ ---- ---- - -CI: add a concurrency group to the CI workflow (cancel superseded runs) and bump -the baseline workflow's checkout/setup-node/pnpm-action-setup pins to match the -rest of the repo. Tooling-only; no change to the published package. diff --git a/.changeset/ci-redesign.md b/.changeset/ci-redesign.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/ci-redesign.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/comment-size-and-ai-verdict-guard.md b/.changeset/comment-size-and-ai-verdict-guard.md deleted file mode 100644 index de73d20..0000000 --- a/.changeset/comment-size-and-ai-verdict-guard.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Keep PR comments under GitHub's 65 KB limit, and reject bogus `addition` -verdicts from the AI reviewer. - -- Markdown reporter truncates oversized before/after snippets to head + tail - and wraps them in a `
` block (`snippetMaxLines`, default 60). -- Rule-based diff descriptions for changed type literals are summarized - instead of repeating the full type body twice; the diff block already - carries the detail. -- AI reviewer now coerces an `addition` verdict to `non-breaking` when the - rule-based pass flagged an in-place modification. `addition` is reserved - for brand-new exports. diff --git a/.changeset/composite-action.md b/.changeset/composite-action.md deleted file mode 100644 index c7e22d0..0000000 --- a/.changeset/composite-action.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Ship a reusable GitHub Action. Consumers can replace a hand-rolled snapshot/detect/comment workflow with `uses: clerk/break-check@v1` after their checkout/node/pnpm setup. The Action uses a git worktree for the baseline (so the PR checkout is never disturbed), runs `break-check` via `pnpm dlx`, and posts (or updates) a single PR comment with the report. Inputs cover the config path, base ref, setup command, break-check version, comment toggle, and `fail-on-breaking`; outputs expose `has-breaking-changes` and the report path. diff --git a/.changeset/coverage-growth-additions.md b/.changeset/coverage-growth-additions.md deleted file mode 100644 index 3283610..0000000 --- a/.changeset/coverage-growth-additions.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Stop reporting coverage/discovery growth as phantom API additions, and bound -the total report size. - -When an already-baselined package gained subpaths (a coverage bump, a genuine -new export, or a discovery change such as wildcard subpath expansion), `detect` -diffed each new subpath against an empty baseline and emitted one addition per -exported member. On `@clerk/shared` that meant a ~440 KB report claiming -thousands of additions, none of them real API changes, which then exceeded -GitHub's 65 KB comment limit and failed to post. Three fixes: - -- A current subpath with no baseline entry in an already-baselined package is - now collapsed to a single "New subpath export" addition instead of one per - member (symmetric with the existing subpath-removal handling). Brand-new - packages still stay silent on first run. -- Snapshot metadata records a new `discoveryVersion` (`schemaVersion: 4`). - `detect` refuses a baseline whose discovery version is older than the running - break-check, and refuses a producer-stamped baseline that predates the field, with - the same "regenerate against the base ref" error the API Extractor major gate - uses. break-check's Action regenerates the baseline every run, so it is unaffected; - consumers caching a baseline across a break-check upgrade must regenerate once. -- The markdown reporter now enforces a total-size budget (`maxReportChars`, - default 60,000): whole package sections are included until the budget is - reached, then the remainder is dropped with a notice pointing at the full - JSON report, so an oversized diff still posts a valid comment. - -`break-check detect` now exits with code 3 (distinct from the generic error exit 1) -when it refuses a baseline as incompatible, so CI can recognize the condition. -The GitHub Action recovers automatically: on an incompatible-baseline refuse it -rebuilds the baseline with the current break-check and retries instead of failing. - -Fixes #40. diff --git a/.changeset/dependabot-changeset-exempt.md b/.changeset/dependabot-changeset-exempt.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/dependabot-changeset-exempt.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/dependabot-gha-bump.md b/.changeset/dependabot-gha-bump.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/dependabot-gha-bump.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/dependabot-npm.md b/.changeset/dependabot-npm.md deleted file mode 100644 index da5f654..0000000 --- a/.changeset/dependabot-npm.md +++ /dev/null @@ -1,6 +0,0 @@ ---- ---- - -CI: have Dependabot watch the npm ecosystem (grouped prod/dev PRs, with API -Extractor majors held back for a deliberate upgrade). Tooling-only; no change to -the published package. diff --git a/.changeset/deps-anthropic-sdk-0-100.md b/.changeset/deps-anthropic-sdk-0-100.md deleted file mode 100644 index fd77270..0000000 --- a/.changeset/deps-anthropic-sdk-0-100.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Bump `@anthropic-ai/sdk` from 0.97.1 to 0.100.1. The intervening releases add `claude-opus-4-8`, mid-conversation system blocks, `usage.output_tokens_details`, and a few streaming fixes. break-check only touches the `Anthropic` constructor and `messages.create`, whose signatures are unchanged, so the AI reviewer's behavior is unaffected. diff --git a/.changeset/deps-commander-15.md b/.changeset/deps-commander-15.md deleted file mode 100644 index 8e54a6a..0000000 --- a/.changeset/deps-commander-15.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Bump commander from 14 to 15. v15 is ESM-only and requires Node >=22.12; break-check is already ESM and pins Node >=22.13, so neither constraint tightens for consumers. The only behavioral change that touches our CLI is v15's `--no-*` handling, and it only affects options that define both a positive and negative form. `--no-ai` is a lone negative option, so it still defaults to `true` and the `options.ai === false` check is unchanged. diff --git a/.changeset/deps-safe-batch.md b/.changeset/deps-safe-batch.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/deps-safe-batch.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/deps-typescript-6.md b/.changeset/deps-typescript-6.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/deps-typescript-6.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/deps-zod-4.md b/.changeset/deps-zod-4.md deleted file mode 100644 index 327c374..0000000 --- a/.changeset/deps-zod-4.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -**Breaking:** `ConfigSchema` is no longer exported from the package root. It was an internal validation detail used by `loadConfig`, and re-exporting it forced consumers to upgrade zod in lockstep whenever zod's `ZodObject`/`ZodArray`/`ZodEnum` generic shapes change (which is exactly what v3 → v4 just did, and what break-check's self-dogfood flagged). Use `BreakCheckConfig` (the inferred output type) instead; that export is unchanged. - -Also bumps zod from 3 to 4. diff --git a/.changeset/drop-sourcemaps.md b/.changeset/drop-sourcemaps.md deleted file mode 100644 index 080f229..0000000 --- a/.changeset/drop-sourcemaps.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Stop publishing source maps. The build no longer emits `.js.map` or `.d.ts.map` files; they previously shipped in the package but pointed at `src/`, which is not included in the tarball, so they were dangling. The published package now contains only `.js` and `.d.ts`. diff --git a/.changeset/enforce-sha-pinned-actions.md b/.changeset/enforce-sha-pinned-actions.md deleted file mode 100644 index 92d3672..0000000 --- a/.changeset/enforce-sha-pinned-actions.md +++ /dev/null @@ -1,7 +0,0 @@ ---- ---- - -CI: enforce that every third-party GitHub Action is pinned to a full commit SHA. -Adds a `check-action-pins` script and a Lint job that fails any workflow or -action.yml change introducing a tag/branch ref. Tooling-only; no change to the -published package. diff --git a/.changeset/exempt-release-pr-changeset.md b/.changeset/exempt-release-pr-changeset.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/exempt-release-pr-changeset.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/fail-soft-per-entry.md b/.changeset/fail-soft-per-entry.md deleted file mode 100644 index d0c9921..0000000 --- a/.changeset/fail-soft-per-entry.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Make per-entry extraction failures non-fatal. - -Previously, a single subpath that API Extractor couldn't process (ambient-global augmentations like `@clerk/testing/cypress`, root-level `.d.ts` files like `@clerk/astro/env`, anything that triggered an `InternalError` from AE) tanked the entire `snapshot` or `detect` run. Common Cypress, Playwright, and Astro patterns made break-check unusable on real monorepos. - -Per-entry failures now emit a `[break-check] warning: skipping : ` line on stderr, are collected on the detector (`detector.lastSkippedEntries`), and surface in the detect report as a "could not snapshot N subpaths" callout above the diff so reviewers don't mistake an omitted surface for a clean one. The run continues with whatever extracted. Package-level fatals (missing `package.json`, zero discoverable entries) still throw, since those usually mean the config is wrong rather than one subpath is weird. - -`AnalysisResult` gains an optional `skippedEntries` array (`{ packageName, subpath, reason }[]`); JSON consumers can read it directly. Both `snapshot` and `detect` accept `--fail-on-skipped`, which turns any skip back into a non-zero exit, the safer setting when producing a committed baseline where a silently-omitted surface would otherwise read as "no changes." - -Fixes #34 (ambient-global crash on `@clerk/testing/cypress`). -Fixes #33 (`Unable to determine module` crash on `@clerk/astro/env`). diff --git a/.changeset/fix-baseline-artifact-hidden-files.md b/.changeset/fix-baseline-artifact-hidden-files.md deleted file mode 100644 index 4ea77a5..0000000 --- a/.changeset/fix-baseline-artifact-hidden-files.md +++ /dev/null @@ -1,7 +0,0 @@ ---- ---- - -Fix the Break Check baseline workflow: upload-artifact@v4 skipped the -dot-prefixed `.api-baseline-main` directory as hidden, so the baseline -artifact was never produced. Add `include-hidden-files: true` (workflow and -README example). CI/docs only; no published package change. diff --git a/.changeset/fix-release-pnpm-version.md b/.changeset/fix-release-pnpm-version.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/fix-release-pnpm-version.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/fix-rest-parameter-detection.md b/.changeset/fix-rest-parameter-detection.md deleted file mode 100644 index 38287e4..0000000 --- a/.changeset/fix-rest-parameter-detection.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Detect rest-parameter changes. API Extractor's `.api.json` does not emit an -`isRest` flag, so the callable diff never saw rest-ness: turning `x: T[]` into -`...x: T[]` (a breaking change) went unreported, and adding a `...rest` -parameter was misclassified as a new required parameter. `isRest` is now -recovered from the parameter excerpt, so rest-ness flips are flagged breaking -and adding a rest parameter reads as a non-breaking optional add. diff --git a/.changeset/gitignore-readme-housekeeping.md b/.changeset/gitignore-readme-housekeeping.md deleted file mode 100644 index 7951dc4..0000000 --- a/.changeset/gitignore-readme-housekeeping.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Gitignore `.worktrees/` and update README Node version to match `engines` (>=22.13). diff --git a/.changeset/harden-gh-actions.md b/.changeset/harden-gh-actions.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/harden-gh-actions.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/ignore-hashed-chunks.md b/.changeset/ignore-hashed-chunks.md deleted file mode 100644 index 555fbb8..0000000 --- a/.changeset/ignore-hashed-chunks.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Stop reporting content-hashed bundler chunks under `"./*"` as breaking add/remove subpaths. - -When a wildcard export globs into a bundler output dir, the shared chunks emitted by rolldown/tsdown/esbuild/rollup (`index-Dq-_K2VH.mjs`, `url-CcPzUbGM.mjs`, ...) were each turned into a public subpath by the #26 wildcard expansion. Those chunks are not public API and their content hash flips every build, so any real change renamed them and surfaced as a removed subpath (breaking) plus an added one, recommending a phantom major. - -Wildcard expansion now drops matches whose basename ends in a high-entropy `-<8 base64url chars>` suffix, controlled by a new `ignoreHashedChunks` config field (on by default). The filter runs on both the current discovery and the baseline read, so an older baseline that recorded chunk subpaths reconciles without a forced regeneration (no `DISCOVERY_VERSION` bump). `ignoreSubpaths` now also accepts globs (`./internal-*`, `./chunk-*`) as the explicit escape hatch for anything the heuristic misses. - -Fixes #49. diff --git a/.changeset/import-notation-normalization.md b/.changeset/import-notation-normalization.md deleted file mode 100644 index 4580e35..0000000 --- a/.changeset/import-notation-normalization.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Normalize equivalent import-reference notation in the static differ. - -API Extractor resolves a namespace-import alias (`_ns.Foo`) and an inline import type (`import("pkg").Foo`) to the same canonical reference, but emits whichever spelling the package's `.d.ts` build produced. The differ compared the raw token text, so a baseline and head built with different declaration strategies surfaced every imported type as a spurious breaking change. We now rewrite each resolved `Reference` token to a single `import("pkg").Name` spelling (dropping the redundant inline-import prefix) before diffing, so this class of false positive is caught in the static layer instead of relying on the AI reviewer. - -Fixes #44. diff --git a/.changeset/license-and-release-pipeline.md b/.changeset/license-and-release-pipeline.md deleted file mode 100644 index 114a908..0000000 --- a/.changeset/license-and-release-pipeline.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Add MIT LICENSE file and wire up the changesets release pipeline. diff --git a/.changeset/lint-workflows-and-action-shell.md b/.changeset/lint-workflows-and-action-shell.md deleted file mode 100644 index c44229d..0000000 --- a/.changeset/lint-workflows-and-action-shell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- ---- - -CI: add actionlint for workflow files and a shellcheck gate for the composite -Action's embedded shell. Tooling-only; no change to the published package. diff --git a/.changeset/no-stray-api-report.md b/.changeset/no-stray-api-report.md deleted file mode 100644 index 35fa0af..0000000 --- a/.changeset/no-stray-api-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Stop API Extractor from writing a stray `.api.md` file at the project root during `break-check snapshot`. The temp report folder now matches the configured report folder, so every generated file lives under the snapshot output directory. diff --git a/.changeset/oss-readiness.md b/.changeset/oss-readiness.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/oss-readiness.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/oss-sweep-hardening.md b/.changeset/oss-sweep-hardening.md deleted file mode 100644 index ce915ec..0000000 --- a/.changeset/oss-sweep-hardening.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Three hardening fixes from the pre-open-source sweep. - -- Entry-point discovery now refuses a `types`/`exports` path that resolves outside the package root, instead of pulling an out-of-package `.d.ts` into the snapshot, report, and AI payload. A package.json is attacker-controlled when the Action builds a PR, so this closes a path-traversal read (issue #7). -- The composite Action gains a `policy-mode` input. With it on, the Action enforces `break-check.config.json` from the base ref, so a PR can no longer suppress its own breaking change by editing its config (dropping the package, self-acknowledging, widening the ignore lists). Recommended when the Action is a required merge gate (issue #1). -- `break-check --version` now reports the installed version instead of a hardcoded `0.0.1`. diff --git a/.changeset/pkg-pr-new-workflow.md b/.changeset/pkg-pr-new-workflow.md deleted file mode 100644 index 9488206..0000000 --- a/.changeset/pkg-pr-new-workflow.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Move pkg.pr.new publishing to its own workflow and run it on pushes to `main` in addition to pull requests. diff --git a/.changeset/pnpm-11.md b/.changeset/pnpm-11.md deleted file mode 100644 index a845151..0000000 --- a/.changeset/pnpm-11.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ---- diff --git a/.changeset/production-readiness.md b/.changeset/production-readiness.md deleted file mode 100644 index 8197fbe..0000000 --- a/.changeset/production-readiness.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Harden production usage by failing invalid snapshots, fixing config-relative baseline resolution, preserving snapshot metadata, and adding regression checks. diff --git a/.changeset/release-version-run-script.md b/.changeset/release-version-run-script.md deleted file mode 100644 index dc3f67a..0000000 --- a/.changeset/release-version-run-script.md +++ /dev/null @@ -1,8 +0,0 @@ ---- ---- - -Fix the Release workflow so it can actually open a Version Packages PR. The -changesets action invoked `pnpm version`, which runs pnpm's built-in version -command (requires a semver argument) instead of the `version` package.json -script. It now uses `pnpm run version` / `pnpm run release`. Tooling-only; no -published-package impact. diff --git a/.changeset/rename-break-check.md b/.changeset/rename-break-check.md deleted file mode 100644 index 6490ad0..0000000 --- a/.changeset/rename-break-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Rename the package to `@clerk/break-check` and the CLI binary to `break-check`. The default config file is now `break-check.config.json` and per-package snapshot metadata is written as `break-check.snapshot.json`; the pre-rename `snapi.config.json` and `snapi.snapshot.json` are still read as deprecated fallbacks. Environment variables are renamed from `SNAPI_*` to `BREAK_CHECK_*`, and the GitHub Action's PR comment marker is now `break-check-action`. diff --git a/.changeset/reporter-static-vs-ai-voices.md b/.changeset/reporter-static-vs-ai-voices.md deleted file mode 100644 index 657ba87..0000000 --- a/.changeset/reporter-static-vs-ai-voices.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Markdown report now labels the rule-based description as **Static analyzer:** and re-labels the AI block by source (`AI review (reclassified as ...)`, `(confirmed)`, or `(additional finding)`) when the AI reviewer ran. Resolves the apparent contradiction when an AI verdict overrides the static analyzer (e.g. a "Breaking change in..." line rendered under a non-breaking heading). diff --git a/.changeset/reporter-version-target.md b/.changeset/reporter-version-target.md deleted file mode 100644 index 20b5da1..0000000 --- a/.changeset/reporter-version-target.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Markdown report no longer renders `Version: X → X` when the PR hasn't bumped the version yet. Instead it shows `Current version: X` and projects the target on the recommended-bump line, e.g. `Recommended bump: MINOR → 4.14.0`. When the PR does bump, the existing `Version: X → Y` form is preserved. diff --git a/.changeset/secure-baseline-filenames.md b/.changeset/secure-baseline-filenames.md deleted file mode 100644 index 535d72e..0000000 --- a/.changeset/secure-baseline-filenames.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Reject baseline metadata entries whose `apiJsonFile`/`apiReportFile` are not -plain, contained filenames. `detect` previously `path.join`ed these recorded -names onto the package directory without validation, so a tampered or committed -`break-check.snapshot.json` could traverse out (e.g. `../../`) and have an -arbitrary file read into the diff or the AI surface payload. Such entries are -now dropped. Also declares `publishConfig` (`access: public`, `provenance: true`) -so npm publishing is explicit rather than relying on implicit defaults. diff --git a/.changeset/security-action-fail-closed.md b/.changeset/security-action-fail-closed.md deleted file mode 100644 index 75941d2..0000000 --- a/.changeset/security-action-fail-closed.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Close fail-open and secret-exposure gaps in the Action and CI workflows. - -The Action's `has-breaking-changes` output is now derived from a JSON detect pass that fails closed: a swallowed non-zero exit or an unparseable report no longer defaults the flag to false and lets `fail-on-breaking` pass on a real break. The baseline-artifact lookup is bound to the PR's exact base SHA (`workflow_run.head_sha`) instead of the base branch name, so it cannot diff against a newer snapshot than the PR was opened against. And the nightly AI smoke workflow only exposes the Anthropic key on `main`, so a write-capable actor cannot dispatch a modified branch to read it. diff --git a/.changeset/security-detect-false-negatives.md b/.changeset/security-detect-false-negatives.md deleted file mode 100644 index f04c31a..0000000 --- a/.changeset/security-detect-false-negatives.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Fix three cases where detection could miss a breaking change or pass a scan it never actually ran. - -When every entry in the current build failed extraction, `detect` returned an empty result before recording the skips, so `--fail-on-skipped` saw nothing and the run reported "no changes" for a surface it never read. It now records the skipped entries (and fails when asked to). The rule-based diff keyed nested members by their immediate parent only, so `A.Inner.value` and `B.Inner.value` collided and one silently overwrote the other; the key now carries the full parent chain. And a reference to a dependency whose package root is export-blocked with `exports: { ".": null }` is no longer assumed resolvable (a top-level `exports: null` still falls back to legacy resolution, so it is left inconclusive rather than flagged). diff --git a/.changeset/security-overrides.md b/.changeset/security-overrides.md deleted file mode 100644 index 0290c23..0000000 --- a/.changeset/security-overrides.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Pin transitive ajv, lodash, and minimatch to versions that address recent advisories. diff --git a/.changeset/security-report-ai-hardening.md b/.changeset/security-report-ai-hardening.md deleted file mode 100644 index 7dd88d8..0000000 --- a/.changeset/security-report-ai-hardening.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Harden the markdown report and the AI audit against untrusted input. - -Package names, symbol names, descriptions, and AI rationales are now escaped before they enter the report (the Action posts it verbatim as a PR comment), so a crafted public API name can no longer forge a heading, table row, or link. A single very long declaration line is capped so it can't push the comment past GitHub's size limit, and the missed-breaks audit caps the API surface it sends rather than serializing an unbounded prompt. When that audit fails on an additions-only diff, or runs against a surface trimmed to fit the cap, the report now flags the partial coverage instead of claiming a complete review. diff --git a/.changeset/self-dogfood.md b/.changeset/self-dogfood.md deleted file mode 100644 index 992b35c..0000000 --- a/.changeset/self-dogfood.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Internal: break-check now runs against its own published surface on every PR via `.github/workflows/api-check.yml`, posting the diff report as a PR comment. diff --git a/.changeset/snapi-ai-model-env.md b/.changeset/snapi-ai-model-env.md deleted file mode 100644 index 44e900b..0000000 --- a/.changeset/snapi-ai-model-env.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Add `BREAK_CHECK_AI_MODEL` environment variable for selecting the AI reviewer's model from CI without editing config. Priority is `--ai-model` > `BREAK_CHECK_AI_MODEL` > `ai.model` in `break-check.config.json` > `claude-sonnet-4-6`. The README now documents the AI reviewer's env vars, the `ai` config block, and when to opt into Opus 4.7. diff --git a/.changeset/subpath-exports.md b/.changeset/subpath-exports.md deleted file mode 100644 index ffb7b60..0000000 --- a/.changeset/subpath-exports.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Snapshot every subpath export, not just the package root. Break Check now walks the full `exports` map per package and produces one API snapshot per non-wildcard subpath (e.g. `@clerk/shared`'s `./react`, `./errors`, `./utils`, etc.). Wildcard patterns (`./*`, `./internal/foo/*`) are skipped with a warning since they're not single API surfaces. Each snapshot lives in `/__.api.json` and a per-package `break-check.snapshot.json` (schema v2) lists every entry. Diffs report changes per subpath, including a synthesized BREAKING change when an entire subpath is removed. Old v1 baseline directories with a single root snapshot continue to read correctly during the transition. A new top-level `ignoreSubpaths: string[]` config option drops matching subpaths from discovery (exact match, e.g. `"./internal"`). diff --git a/.changeset/test-init-and-api-diff-branches.md b/.changeset/test-init-and-api-diff-branches.md deleted file mode 100644 index 394be4b..0000000 --- a/.changeset/test-init-and-api-diff-branches.md +++ /dev/null @@ -1,6 +0,0 @@ ---- ---- - -Tests: cover the `break-check init` command (default/`--force`/`-o`, refuse -existing) and the api-diff enum-value, readonly, and kind-switch breaking -branches. Test-only; no change to the published package. diff --git a/.changeset/unified-diff-rendering.md b/.changeset/unified-diff-rendering.md deleted file mode 100644 index 54d3eeb..0000000 --- a/.changeset/unified-diff-rendering.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@clerk/break-check": patch ---- - -Markdown reporter now renders before/after snippets as a unified diff anchored -on the aligned common prefix and suffix, with a few lines of context and an -elision marker for the unchanged bulk. Previously, large mostly-identical -snippets were truncated head+tail on each side independently, which buried -the actual change in the elided middle and produced ~120 lines of duplicate -content for a 1-line edit. When the two sides share no structure, the -reporter still falls back to per-side head+tail truncation. diff --git a/.changeset/unresolvable-subpath-refs.md b/.changeset/unresolvable-subpath-refs.md deleted file mode 100644 index bb581b7..0000000 --- a/.changeset/unresolvable-subpath-refs.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Stop the AI reviewer from downgrading a reference to an export-blocked dependency subpath. - -When a bundler moves a re-exported type into an internal chunk the dependency blocks in its `exports` (e.g. `@clerk/shared` declares `"./_chunks/*": null`), a public `.d.ts` can emit `import("@clerk/shared/_chunks/index-DcO1-lAR").Jwt`. The structural shape is unchanged, but the specifier does not resolve for consumers: under `nodenext` it errors (`TS2307`), and with `skipLibCheck: true` it silently degrades to `any`. The rule pass flagged this breaking, but the AI reviewer downgraded it as a "build artifact rename", so with `--ai-apply-downgrades` it shipped green. - -break-check now extracts the inline `import("...")` specifiers a new signature introduces (present in the after snippet, absent in the before) and classifies each against the target dependency's `package.json` `exports`: a subpath that resolves to `null`, or matches no key, is non-resolvable. When the dependency can't be located on disk it falls back to a `/_chunks/` and content-hash heuristic. A change carrying such a reference is pinned breaking and the AI may not relax it, even under `--ai-apply-downgrades`; the report shows a callout naming the specifier and drops the "re-run with --ai-apply-downgrades" nudge for it. The note bypasses break-check's own canonicalization, which discards the subpath before the diff or AI ever see it, so the signal is read from the raw `.d.ts` text. - -New `resolvableSpecifiers` config option: specifier globs to exempt from the guard when a referenced subpath is a legitimate public entry point the heuristic mis-flags. An explicit `acknowledgedChanges` entry also clears it. - -Fixes #60. diff --git a/.changeset/version-analyzer-tests.md b/.changeset/version-analyzer-tests.md deleted file mode 100644 index 7e6d486..0000000 --- a/.changeset/version-analyzer-tests.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Internal: add unit tests for `VersionAnalyzer`. diff --git a/.changeset/wildcard-subpath-expansion.md b/.changeset/wildcard-subpath-expansion.md deleted file mode 100644 index 5e4b88a..0000000 --- a/.changeset/wildcard-subpath-expansion.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@clerk/break-check": minor ---- - -Expand wildcard subpath exports (e.g. `"./*": "./dist/runtime/*.d.mts"`) instead of silently skipping them. - -Packages like `@clerk/shared` expose most of their public surface through a single wildcard subpath. break-check was dropping every wildcard key in `findEntryPoints` and only logging it at verbose level, so breaking changes under `@clerk/shared/file`, `@clerk/shared/url`, etc. never showed up in reports. - -The discovery layer now globs the wildcard's value against the package directory, derives the captured portion of each match, and substitutes it back into the key pattern to synthesize one concrete `PackageEntry` per file (single-segment `*` only; multi-segment nested wildcards remain unhandled and skip silently). Expanded entries are sorted by subpath so the resulting `break-check.snapshot.json` is byte-stable across runners (`fs.globSync` ordering is not guaranteed). Concrete keys still win over wildcard-expanded ones if both produce the same subpath. Both the wildcard key itself and individual expanded subpaths can still be excluded via `ignoreSubpaths`. - -Fixes #26. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5f85f18 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,227 @@ +# @clerk/break-check + +## 0.1.0 + +### Minor Changes + +- [#18](https://github.com/clerk/break-check/pull/18) [`edca94c`](https://github.com/clerk/break-check/commit/edca94c470ee0b0a6a95e6f85d156d13820f0bd2) Thanks [@jacekradko](https://github.com/jacekradko)! - Add opt-in AI-powered analysis of detected API changes. When `BREAK_CHECK_ANTHROPIC_API_KEY` is set, break-check sends each package's rule-based change list and a compact view of the baseline/current API surface to Anthropic's Claude. The model re-classifies changes (overriding the rule-based verdict in either direction, with rationale and migration guidance) and scans for breaks the rules missed. Failures fall back to rule-based output, so the CLI exit code never depends on AI availability. By default the AI call is skipped for diffs that the rule-based pass classified as pure additions; set `BREAK_CHECK_AI_STRICT=1` (or `ai.strict: true` in config, or pass `--ai-strict`) to run the deeper scan in those cases too. Configurable via a new `ai` block in `break-check.config.json` and the `--no-ai` / `--ai-model` / `--ai-strict` CLI flags. + +- [#57](https://github.com/clerk/break-check/pull/57) [`e6f0b3e`](https://github.com/clerk/break-check/commit/e6f0b3e20848d6d36c48529de9c7630c535de04e) Thanks [@jacekradko](https://github.com/jacekradko)! - Stop the AI reviewer confirming two backwards-compatible changes as breaking, and add a config escape hatch for the rest. + + Adding an optional property (including one widened into a `Pick`/`Omit`) was confirmed breaking because the prompt never said it was safe and never forbade a verdict left conditional on a fact already in context. New classification rules fix that. Adding a required field to a read-only output type was confirmed breaking because the model only ever saw a type's forward references, never its callers, so it couldn't tell an input type from an output one. The focused verdict context now also carries a "Usage sites" block: the signatures that reference each changed type, gathered across the package's sibling subpath surfaces (the type and the function returning it usually live in different rollups). Both fixes only ever enable a downgrade, which still stays gated behind `--ai-apply-downgrades`. + + New `acknowledgedChanges` config option: list a breaking change by name (`OAuthConsentInfo`, `@clerk/shared#OAuthConsentInfo`, or a `Clerk.__internal_*` glob) to downgrade it to non-breaking and tag it `acknowledged` in the report. Unlike an AI downgrade this is unconditional. + + Fixes [#56](https://github.com/clerk/break-check/issues/56). + +- [#51](https://github.com/clerk/break-check/pull/51) [`98cb225`](https://github.com/clerk/break-check/commit/98cb22591751a1628e4e260064ddffa5647d6de5) Thanks [@jacekradko](https://github.com/jacekradko)! - Rework the AI reviewer around the downgrade decision and split the old `strict` flag into two orthogonal opt-ins. + + The verdict call now sends a focused context instead of the whole API surface: for each change, only the definitions of the types its signature references (resolved transitively through API Extractor's canonical references), with a referenced type's baseline definition included where it changed so equivalence can be judged old-vs-new. On a large package that is a handful of types instead of hundreds of signatures. The change list is compact JSON and rationales are capped at one sentence. + + Downgrades are no longer applied by default. A `breaking -> non-breaking` verdict is the only operation that can clear a flagged break, so by default it is recorded as a suggestion (the change stays breaking) and applied only with `--ai-apply-downgrades` / `BREAK_CHECK_AI_APPLY_DOWNGRADES` / `ai.applyDowngrades`. The default path therefore cannot turn a flagged break into a non-break, and if a referenced type can't be resolved the model is told to keep "breaking", so a thin context costs a missed downgrade (noise), never a shipped break. + + The old `strict` flag is removed. Its missed-breaks audit (which sends both the baseline and current surfaces so the model can diff old vs new, and reviews additions-only diffs) is now its own opt-in: `--ai-scan` / `BREAK_CHECK_AI_SCAN` / `ai.scanForMissed`. Applying downgrades and running the audit are independent; combine them for the most thorough run. + + Migration: `--ai-strict` and `ai.strict` no longer exist. The flag errors as an unknown option, and a config that still sets `ai.strict` now fails validation with an "unrecognized key" error (the `ai` block rejects unknown keys) instead of silently doing nothing. Replace it with `ai.scanForMissed: true` (the audit) and/or `ai.applyDowngrades: true` (relax verdicts). + +- [#5](https://github.com/clerk/break-check/pull/5) [`dcabe04`](https://github.com/clerk/break-check/commit/dcabe04ff57e36ff4212070e1630d9817d5a0e47) Thanks [@jacekradko](https://github.com/jacekradko)! - Rewrite the API diff analyzer to use structured comparison instead of joined-token string diffs. Parameter renames and whitespace differences no longer surface as breaking changes; optional/required parameter flips, added optional parameters, return-type changes, and property-type changes are now classified individually. Interface body edits are no longer double-counted at the container level. + +- [#25](https://github.com/clerk/break-check/pull/25) [`14ec529`](https://github.com/clerk/break-check/commit/14ec52980ed06e214f6d78c0ea16488441b68b5c) Thanks [@jacekradko](https://github.com/jacekradko)! - Composite Action can now consume a baseline snapshot uploaded from a separate + push-to-main workflow, instead of always rebuilding the base ref. Set the new + `baseline-artifact-name` input to the artifact name; the Action downloads the + most recent matching artifact on `base-ref` and uses it as the baseline. Falls + back to the worktree rebuild on miss, expiry, or download failure, so existing + configurations keep working unchanged. Optional `baseline-max-age` (hours) + caps how old a downloaded artifact may be before falling back. See the + "Larger monorepos" section of the README for the producer workflow. + +- [#27](https://github.com/clerk/break-check/pull/27) [`11da46c`](https://github.com/clerk/break-check/commit/11da46c25498504948edb35854b5f6173172756b) Thanks [@jacekradko](https://github.com/jacekradko)! - Snapshot metadata (`break-check.snapshot.json`) now records the producing `breakCheckVersion` and `apiExtractorVersion` under `schemaVersion: 3`. On `break-check detect`, a baseline whose recorded `@microsoft/api-extractor` major differs from the running one is refused with a structured error, since the hand-rolled `.api.json` reader is not guaranteed compatible across API Extractor majors and would otherwise produce silently nonsensical diffs. Pre-stamp baselines (schemaVersion 1 or 2) still load, with a stderr warning suggesting regeneration. `parseApiJson` also gained a shape check that throws on an unrecognized `.api.json` structure rather than returning an empty surface. + +- [#59](https://github.com/clerk/break-check/pull/59) [`aae2962`](https://github.com/clerk/break-check/commit/aae2962cd76869d26dfc06e438c4af825827078b) Thanks [@jacekradko](https://github.com/jacekradko)! - Make the report breaking-first and stop silently trusting incomplete AI reviews. + + A single AI review call that fails (the classic trigger: one huge type whose + before/after snippet dominated the request) used to leave every change in that + subpath with its pessimistic rule-based verdict and no annotation, while the + report still claimed full AI coverage. The analyzer now caps oversized + before/after snippets and bounds the focused-surface block by size so the call + fits, splits-and-retries a failed batch into smaller ones, and records any + review it still can't complete. Those gaps surface in the report: the "reviewed + by" stamp is marked `(partial)` and a callout lists the affected subpaths. + + The report also leads with breaking changes: a breaking-changes index up front + (survives the size-budget truncation), packages and subpaths ordered + breaking-first, breaking sections never collapsed, and non-breaking sections + collapsed behind `
` in large reports. + +- [#9](https://github.com/clerk/break-check/pull/9) [`126506d`](https://github.com/clerk/break-check/commit/126506d06071242e16ad33139e04177ce790be90) Thanks [@jacekradko](https://github.com/jacekradko)! - Ship a reusable GitHub Action. Consumers can replace a hand-rolled snapshot/detect/comment workflow with `uses: clerk/break-check@v1` after their checkout/node/pnpm setup. The Action uses a git worktree for the baseline (so the PR checkout is never disturbed), runs `break-check` via `pnpm dlx`, and posts (or updates) a single PR comment with the report. Inputs cover the config path, base ref, setup command, break-check version, comment toggle, and `fail-on-breaking`; outputs expose `has-breaking-changes` and the report path. + +- [#41](https://github.com/clerk/break-check/pull/41) [`d8abb51`](https://github.com/clerk/break-check/commit/d8abb511d1e28b688c8fc99aa9c1057e8f0fcb77) Thanks [@jacekradko](https://github.com/jacekradko)! - Stop reporting coverage/discovery growth as phantom API additions, and bound + the total report size. + + When an already-baselined package gained subpaths (a coverage bump, a genuine + new export, or a discovery change such as wildcard subpath expansion), `detect` + diffed each new subpath against an empty baseline and emitted one addition per + exported member. On `@clerk/shared` that meant a ~440 KB report claiming + thousands of additions, none of them real API changes, which then exceeded + GitHub's 65 KB comment limit and failed to post. Three fixes: + - A current subpath with no baseline entry in an already-baselined package is + now collapsed to a single "New subpath export" addition instead of one per + member (symmetric with the existing subpath-removal handling). Brand-new + packages still stay silent on first run. + - Snapshot metadata records a new `discoveryVersion` (`schemaVersion: 4`). + `detect` refuses a baseline whose discovery version is older than the running + break-check, and refuses a producer-stamped baseline that predates the field, with + the same "regenerate against the base ref" error the API Extractor major gate + uses. break-check's Action regenerates the baseline every run, so it is unaffected; + consumers caching a baseline across a break-check upgrade must regenerate once. + - The markdown reporter now enforces a total-size budget (`maxReportChars`, + default 60,000): whole package sections are included until the budget is + reached, then the remainder is dropped with a notice pointing at the full + JSON report, so an oversized diff still posts a valid comment. + + `break-check detect` now exits with code 3 (distinct from the generic error exit 1) + when it refuses a baseline as incompatible, so CI can recognize the condition. + The GitHub Action recovers automatically: on an incompatible-baseline refuse it + rebuilds the baseline with the current break-check and retries instead of failing. + + Fixes [#40](https://github.com/clerk/break-check/issues/40). + +- [#14](https://github.com/clerk/break-check/pull/14) [`e7ece09`](https://github.com/clerk/break-check/commit/e7ece094b0619ef841a45d14282c8a623c1589d2) Thanks [@jacekradko](https://github.com/jacekradko)! - **Breaking:** `ConfigSchema` is no longer exported from the package root. It was an internal validation detail used by `loadConfig`, and re-exporting it forced consumers to upgrade zod in lockstep whenever zod's `ZodObject`/`ZodArray`/`ZodEnum` generic shapes change (which is exactly what v3 → v4 just did, and what break-check's self-dogfood flagged). Use `BreakCheckConfig` (the inferred output type) instead; that export is unchanged. + + Also bumps zod from 3 to 4. + +- [#36](https://github.com/clerk/break-check/pull/36) [`6b60743`](https://github.com/clerk/break-check/commit/6b60743f6bf1f4c82a2cd7b84d76fdf30251bdd1) Thanks [@jacekradko](https://github.com/jacekradko)! - Make per-entry extraction failures non-fatal. + + Previously, a single subpath that API Extractor couldn't process (ambient-global augmentations like `@clerk/testing/cypress`, root-level `.d.ts` files like `@clerk/astro/env`, anything that triggered an `InternalError` from AE) tanked the entire `snapshot` or `detect` run. Common Cypress, Playwright, and Astro patterns made break-check unusable on real monorepos. + + Per-entry failures now emit a `[break-check] warning: skipping : ` line on stderr, are collected on the detector (`detector.lastSkippedEntries`), and surface in the detect report as a "could not snapshot N subpaths" callout above the diff so reviewers don't mistake an omitted surface for a clean one. The run continues with whatever extracted. Package-level fatals (missing `package.json`, zero discoverable entries) still throw, since those usually mean the config is wrong rather than one subpath is weird. + + `AnalysisResult` gains an optional `skippedEntries` array (`{ packageName, subpath, reason }[]`); JSON consumers can read it directly. Both `snapshot` and `detect` accept `--fail-on-skipped`, which turns any skip back into a non-zero exit, the safer setting when producing a committed baseline where a silently-omitted surface would otherwise read as "no changes." + + Fixes [#34](https://github.com/clerk/break-check/issues/34) (ambient-global crash on `@clerk/testing/cypress`). + Fixes [#33](https://github.com/clerk/break-check/issues/33) (`Unable to determine module` crash on `@clerk/astro/env`). + +- [#50](https://github.com/clerk/break-check/pull/50) [`d2f9d66`](https://github.com/clerk/break-check/commit/d2f9d6668b810bd185172a5b871a8ed2c266c2d9) Thanks [@jacekradko](https://github.com/jacekradko)! - Stop reporting content-hashed bundler chunks under `"./*"` as breaking add/remove subpaths. + + When a wildcard export globs into a bundler output dir, the shared chunks emitted by rolldown/tsdown/esbuild/rollup (`index-Dq-_K2VH.mjs`, `url-CcPzUbGM.mjs`, ...) were each turned into a public subpath by the [#26](https://github.com/clerk/break-check/issues/26) wildcard expansion. Those chunks are not public API and their content hash flips every build, so any real change renamed them and surfaced as a removed subpath (breaking) plus an added one, recommending a phantom major. + + Wildcard expansion now drops matches whose basename ends in a high-entropy `-<8 base64url chars>` suffix, controlled by a new `ignoreHashedChunks` config field (on by default). The filter runs on both the current discovery and the baseline read, so an older baseline that recorded chunk subpaths reconciles without a forced regeneration (no `DISCOVERY_VERSION` bump). `ignoreSubpaths` now also accepts globs (`./internal-*`, `./chunk-*`) as the explicit escape hatch for anything the heuristic misses. + + Fixes [#49](https://github.com/clerk/break-check/issues/49). + +- [#42](https://github.com/clerk/break-check/pull/42) [`3008f95`](https://github.com/clerk/break-check/commit/3008f95ac37baac5071a1de50f2403575eee0dc8) Thanks [@jacekradko](https://github.com/jacekradko)! - Rename the package to `@clerk/break-check` and the CLI binary to `break-check`. The default config file is now `break-check.config.json` and per-package snapshot metadata is written as `break-check.snapshot.json`; the pre-rename `snapi.config.json` and `snapi.snapshot.json` are still read as deprecated fallbacks. Environment variables are renamed from `SNAPI_*` to `BREAK_CHECK_*`, and the GitHub Action's PR comment marker is now `break-check-action`. + +- [#22](https://github.com/clerk/break-check/pull/22) [`48383cc`](https://github.com/clerk/break-check/commit/48383ccae7e70c6dc6f8ea7aed543cb5a96eff0a) Thanks [@jacekradko](https://github.com/jacekradko)! - Add `BREAK_CHECK_AI_MODEL` environment variable for selecting the AI reviewer's model from CI without editing config. Priority is `--ai-model` > `BREAK_CHECK_AI_MODEL` > `ai.model` in `break-check.config.json` > `claude-sonnet-4-6`. The README now documents the AI reviewer's env vars, the `ai` config block, and when to opt into Opus 4.7. + +- [#19](https://github.com/clerk/break-check/pull/19) [`ce9211c`](https://github.com/clerk/break-check/commit/ce9211c8c27fea50045624f1c8a4e45b814ab9e2) Thanks [@jacekradko](https://github.com/jacekradko)! - Snapshot every subpath export, not just the package root. Break Check now walks the full `exports` map per package and produces one API snapshot per non-wildcard subpath (e.g. `@clerk/shared`'s `./react`, `./errors`, `./utils`, etc.). Wildcard patterns (`./*`, `./internal/foo/*`) are skipped with a warning since they're not single API surfaces. Each snapshot lives in `/__.api.json` and a per-package `break-check.snapshot.json` (schema v2) lists every entry. Diffs report changes per subpath, including a synthesized BREAKING change when an entire subpath is removed. Old v1 baseline directories with a single root snapshot continue to read correctly during the transition. A new top-level `ignoreSubpaths: string[]` config option drops matching subpaths from discovery (exact match, e.g. `"./internal"`). + +- [#61](https://github.com/clerk/break-check/pull/61) [`eb295f1`](https://github.com/clerk/break-check/commit/eb295f136409a7ba45908bf7591f7209e0bc371f) Thanks [@jacekradko](https://github.com/jacekradko)! - Stop the AI reviewer from downgrading a reference to an export-blocked dependency subpath. + + When a bundler moves a re-exported type into an internal chunk the dependency blocks in its `exports` (e.g. `@clerk/shared` declares `"./_chunks/*": null`), a public `.d.ts` can emit `import("@clerk/shared/_chunks/index-DcO1-lAR").Jwt`. The structural shape is unchanged, but the specifier does not resolve for consumers: under `nodenext` it errors (`TS2307`), and with `skipLibCheck: true` it silently degrades to `any`. The rule pass flagged this breaking, but the AI reviewer downgraded it as a "build artifact rename", so with `--ai-apply-downgrades` it shipped green. + + break-check now extracts the inline `import("...")` specifiers a new signature introduces (present in the after snippet, absent in the before) and classifies each against the target dependency's `package.json` `exports`: a subpath that resolves to `null`, or matches no key, is non-resolvable. When the dependency can't be located on disk it falls back to a `/_chunks/` and content-hash heuristic. A change carrying such a reference is pinned breaking and the AI may not relax it, even under `--ai-apply-downgrades`; the report shows a callout naming the specifier and drops the "re-run with --ai-apply-downgrades" nudge for it. The note bypasses break-check's own canonicalization, which discards the subpath before the diff or AI ever see it, so the signal is read from the raw `.d.ts` text. + + New `resolvableSpecifiers` config option: specifier globs to exempt from the guard when a referenced subpath is a legitimate public entry point the heuristic mis-flags. An explicit `acknowledgedChanges` entry also clears it. + + Fixes [#60](https://github.com/clerk/break-check/issues/60). + +- [#37](https://github.com/clerk/break-check/pull/37) [`8558b8e`](https://github.com/clerk/break-check/commit/8558b8e66e756b390d86c51bb1f28231e211dfcf) Thanks [@jacekradko](https://github.com/jacekradko)! - Expand wildcard subpath exports (e.g. `"./*": "./dist/runtime/*.d.mts"`) instead of silently skipping them. + + Packages like `@clerk/shared` expose most of their public surface through a single wildcard subpath. break-check was dropping every wildcard key in `findEntryPoints` and only logging it at verbose level, so breaking changes under `@clerk/shared/file`, `@clerk/shared/url`, etc. never showed up in reports. + + The discovery layer now globs the wildcard's value against the package directory, derives the captured portion of each match, and substitutes it back into the key pattern to synthesize one concrete `PackageEntry` per file (single-segment `*` only; multi-segment nested wildcards remain unhandled and skip silently). Expanded entries are sorted by subpath so the resulting `break-check.snapshot.json` is byte-stable across runners (`fs.globSync` ordering is not guaranteed). Concrete keys still win over wildcard-expanded ones if both produce the same subpath. Both the wildcard key itself and individual expanded subpaths can still be excluded via `ignoreSubpaths`. + + Fixes [#26](https://github.com/clerk/break-check/issues/26). + +### Patch Changes + +- [#35](https://github.com/clerk/break-check/pull/35) [`01ed12d`](https://github.com/clerk/break-check/commit/01ed12d95e5d4a9e179ed6ab675afbcd13755138) Thanks [@jacekradko](https://github.com/jacekradko)! - Action: anchor the baseline on the PR's `base.sha`, not `base_ref`. + + The composite Action defaulted `base-ref` to `${{ github.base_ref }}` (a branch name) and then ran `git worktree add ... "origin/$BASE_REF"`. That checks out the _current tip_ of the base branch at the moment the workflow runs, not the commit the PR was actually opened against. When `main` advanced between the PR being opened and the check running, break-check diffed against a tree the PR author never saw, producing inverted or fabricated change reports. + + The default is now `${{ github.event.pull_request.base.sha || github.base_ref }}` and the fetch/worktree step checks out `FETCH_HEAD` so it works for both SHAs and branch names. The dogfood workflow (`.github/workflows/api-check.yml`) gets the same treatment. + + Fixes [#32](https://github.com/clerk/break-check/issues/32). + +- [#43](https://github.com/clerk/break-check/pull/43) [`aa433ae`](https://github.com/clerk/break-check/commit/aa433ae78821569e741c5ea6803659164b445e30) Thanks [@jacekradko](https://github.com/jacekradko)! - Action: pin the "current" side of the diff to the PR head SHA, not the `refs/pull/N/merge` ref. + + The composite Action (and the dogfood workflow) built whatever the caller checked out as the "current" side. On `pull_request` events `actions/checkout` resolves `refs/pull/N/merge` by default: the PR head merged into the _moving_ tip of the base branch. Once the base branch advanced, that merged tree absorbed unrelated changes and break-check reported them as the PR's own, e.g. a phantom `configureSSOMobileNavbar` addition on a CI-only PR ([#32](https://github.com/clerk/break-check/issues/32)). Anchoring the baseline on `base.sha` was necessary but not sufficient; the current side floated too. + + The Action now takes a `head-ref` input (default `${{ github.event.pull_request.head.sha }}`), builds it in an isolated worktree symmetric with the baseline, and runs detect there. Non-PR events fall back to building the workspace. `.github/workflows/api-check.yml` gets the same treatment. + + Completes the fix for [#32](https://github.com/clerk/break-check/issues/32). + +- [#30](https://github.com/clerk/break-check/pull/30) [`763ad1b`](https://github.com/clerk/break-check/commit/763ad1bb1da1da52fd8525a038405bb6ee1b7347) Thanks [@jacekradko](https://github.com/jacekradko)! - Keep PR comments under GitHub's 65 KB limit, and reject bogus `addition` + verdicts from the AI reviewer. + - Markdown reporter truncates oversized before/after snippets to head + tail + and wraps them in a `
` block (`snippetMaxLines`, default 60). + - Rule-based diff descriptions for changed type literals are summarized + instead of repeating the full type body twice; the diff block already + carries the detail. + - AI reviewer now coerces an `addition` verdict to `non-breaking` when the + rule-based pass flagged an in-place modification. `addition` is reserved + for brand-new exports. + +- [#58](https://github.com/clerk/break-check/pull/58) [`a0e406b`](https://github.com/clerk/break-check/commit/a0e406bd05231eba85bd5d0ad7974d9ba02d6ae2) Thanks [@jacekradko](https://github.com/jacekradko)! - Bump `@anthropic-ai/sdk` from 0.97.1 to 0.100.1. The intervening releases add `claude-opus-4-8`, mid-conversation system blocks, `usage.output_tokens_details`, and a few streaming fixes. break-check only touches the `Anthropic` constructor and `messages.create`, whose signatures are unchanged, so the AI reviewer's behavior is unaffected. + +- [#55](https://github.com/clerk/break-check/pull/55) [`59f1c4f`](https://github.com/clerk/break-check/commit/59f1c4fcacdb99107ea164fc8770a944d48f16fb) Thanks [@jacekradko](https://github.com/jacekradko)! - Bump commander from 14 to 15. v15 is ESM-only and requires Node >=22.12; break-check is already ESM and pins Node >=22.13, so neither constraint tightens for consumers. The only behavioral change that touches our CLI is v15's `--no-*` handling, and it only affects options that define both a positive and negative form. `--no-ai` is a lone negative option, so it still defaults to `true` and the `options.ai === false` check is unchanged. + +- [#54](https://github.com/clerk/break-check/pull/54) [`6d15131`](https://github.com/clerk/break-check/commit/6d15131d76542e5fffe46bc8ddab80eacedb1bf2) Thanks [@jacekradko](https://github.com/jacekradko)! - Stop publishing source maps. The build no longer emits `.js.map` or `.d.ts.map` files; they previously shipped in the package but pointed at `src/`, which is not included in the tarball, so they were dangling. The published package now contains only `.js` and `.d.ts`. + +- [#70](https://github.com/clerk/break-check/pull/70) [`fe548ec`](https://github.com/clerk/break-check/commit/fe548ecd10c9495ed41d2b30ad77edb2cf2d00b2) Thanks [@jacekradko](https://github.com/jacekradko)! - Detect rest-parameter changes. API Extractor's `.api.json` does not emit an + `isRest` flag, so the callable diff never saw rest-ness: turning `x: T[]` into + `...x: T[]` (a breaking change) went unreported, and adding a `...rest` + parameter was misclassified as a new required parameter. `isRest` is now + recovered from the parameter excerpt, so rest-ness flips are flagged breaking + and adding a rest parameter reads as a non-breaking optional add. + +- [#45](https://github.com/clerk/break-check/pull/45) [`a4db93a`](https://github.com/clerk/break-check/commit/a4db93a68e43e45a71cc958cc4a722d91c5f62b2) Thanks [@jacekradko](https://github.com/jacekradko)! - Normalize equivalent import-reference notation in the static differ. + + API Extractor resolves a namespace-import alias (`_ns.Foo`) and an inline import type (`import("pkg").Foo`) to the same canonical reference, but emits whichever spelling the package's `.d.ts` build produced. The differ compared the raw token text, so a baseline and head built with different declaration strategies surfaced every imported type as a spurious breaking change. We now rewrite each resolved `Reference` token to a single `import("pkg").Name` spelling (dropping the redundant inline-import prefix) before diffing, so this class of false positive is caught in the static layer instead of relying on the AI reviewer. + + Fixes [#44](https://github.com/clerk/break-check/issues/44). + +- [#5](https://github.com/clerk/break-check/pull/5) [`dcabe04`](https://github.com/clerk/break-check/commit/dcabe04ff57e36ff4212070e1630d9817d5a0e47) Thanks [@jacekradko](https://github.com/jacekradko)! - Add MIT LICENSE file and wire up the changesets release pipeline. + +- [#8](https://github.com/clerk/break-check/pull/8) [`d6b71be`](https://github.com/clerk/break-check/commit/d6b71be966d68e454865ff9cc450dfe49abc2c4c) Thanks [@jacekradko](https://github.com/jacekradko)! - Stop API Extractor from writing a stray `.api.md` file at the project root during `break-check snapshot`. The temp report folder now matches the configured report folder, so every generated file lives under the snapshot output directory. + +- [#64](https://github.com/clerk/break-check/pull/64) [`02d5167`](https://github.com/clerk/break-check/commit/02d5167c667243a21de978e61038e9c0730a9d5c) Thanks [@jacekradko](https://github.com/jacekradko)! - Three hardening fixes from the pre-open-source sweep. + - Entry-point discovery now refuses a `types`/`exports` path that resolves outside the package root, instead of pulling an out-of-package `.d.ts` into the snapshot, report, and AI payload. A package.json is attacker-controlled when the Action builds a PR, so this closes a path-traversal read (issue [#7](https://github.com/clerk/break-check/issues/7)). + - The composite Action gains a `policy-mode` input. With it on, the Action enforces `break-check.config.json` from the base ref, so a PR can no longer suppress its own breaking change by editing its config (dropping the package, self-acknowledging, widening the ignore lists). Recommended when the Action is a required merge gate (issue [#1](https://github.com/clerk/break-check/issues/1)). + - `break-check --version` now reports the installed version instead of a hardcoded `0.0.1`. + +- [#3](https://github.com/clerk/break-check/pull/3) [`f86aaa9`](https://github.com/clerk/break-check/commit/f86aaa9519da57286e9608c581c60378a4a73aa3) Thanks [@jacekradko](https://github.com/jacekradko)! - Harden production usage by failing invalid snapshots, fixing config-relative baseline resolution, preserving snapshot metadata, and adding regression checks. + +- [#29](https://github.com/clerk/break-check/pull/29) [`87362c1`](https://github.com/clerk/break-check/commit/87362c16e0178ca51286fd7ea775b1e28012c247) Thanks [@jacekradko](https://github.com/jacekradko)! - Markdown report now labels the rule-based description as **Static analyzer:** and re-labels the AI block by source (`AI review (reclassified as ...)`, `(confirmed)`, or `(additional finding)`) when the AI reviewer ran. Resolves the apparent contradiction when an AI verdict overrides the static analyzer (e.g. a "Breaking change in..." line rendered under a non-breaking heading). + +- [#29](https://github.com/clerk/break-check/pull/29) [`87362c1`](https://github.com/clerk/break-check/commit/87362c16e0178ca51286fd7ea775b1e28012c247) Thanks [@jacekradko](https://github.com/jacekradko)! - Markdown report no longer renders `Version: X → X` when the PR hasn't bumped the version yet. Instead it shows `Current version: X` and projects the target on the recommended-bump line, e.g. `Recommended bump: MINOR → 4.14.0`. When the PR does bump, the existing `Version: X → Y` form is preserved. + +- [#48](https://github.com/clerk/break-check/pull/48) [`952a4bb`](https://github.com/clerk/break-check/commit/952a4bb14533050b3a9e077e46528533eff87a6d) Thanks [@jacekradko](https://github.com/jacekradko)! - Reject baseline metadata entries whose `apiJsonFile`/`apiReportFile` are not + plain, contained filenames. `detect` previously `path.join`ed these recorded + names onto the package directory without validation, so a tampered or committed + `break-check.snapshot.json` could traverse out (e.g. `../../`) and have an + arbitrary file read into the diff or the AI surface payload. Such entries are + now dropped. Also declares `publishConfig` (`access: public`, `provenance: true`) + so npm publishing is explicit rather than relying on implicit defaults. + +- [#62](https://github.com/clerk/break-check/pull/62) [`61b1f0d`](https://github.com/clerk/break-check/commit/61b1f0d66fdfa308ef13d1a4868552488b96f25f) Thanks [@jacekradko](https://github.com/jacekradko)! - Close fail-open and secret-exposure gaps in the Action and CI workflows. + + The Action's `has-breaking-changes` output is now derived from a JSON detect pass that fails closed: a swallowed non-zero exit or an unparseable report no longer defaults the flag to false and lets `fail-on-breaking` pass on a real break. The baseline-artifact lookup is bound to the PR's exact base SHA (`workflow_run.head_sha`) instead of the base branch name, so it cannot diff against a newer snapshot than the PR was opened against. And the nightly AI smoke workflow only exposes the Anthropic key on `main`, so a write-capable actor cannot dispatch a modified branch to read it. + +- [#62](https://github.com/clerk/break-check/pull/62) [`61b1f0d`](https://github.com/clerk/break-check/commit/61b1f0d66fdfa308ef13d1a4868552488b96f25f) Thanks [@jacekradko](https://github.com/jacekradko)! - Fix three cases where detection could miss a breaking change or pass a scan it never actually ran. + + When every entry in the current build failed extraction, `detect` returned an empty result before recording the skips, so `--fail-on-skipped` saw nothing and the run reported "no changes" for a surface it never read. It now records the skipped entries (and fails when asked to). The rule-based diff keyed nested members by their immediate parent only, so `A.Inner.value` and `B.Inner.value` collided and one silently overwrote the other; the key now carries the full parent chain. And a reference to a dependency whose package root is export-blocked with `exports: { ".": null }` is no longer assumed resolvable (a top-level `exports: null` still falls back to legacy resolution, so it is left inconclusive rather than flagged). + +- [#4](https://github.com/clerk/break-check/pull/4) [`92524c8`](https://github.com/clerk/break-check/commit/92524c8ea230c6bf18384a0117232a60324043aa) Thanks [@dependabot](https://github.com/apps/dependabot)! - Pin transitive ajv, lodash, and minimatch to versions that address recent advisories. + +- [#62](https://github.com/clerk/break-check/pull/62) [`61b1f0d`](https://github.com/clerk/break-check/commit/61b1f0d66fdfa308ef13d1a4868552488b96f25f) Thanks [@jacekradko](https://github.com/jacekradko)! - Harden the markdown report and the AI audit against untrusted input. + + Package names, symbol names, descriptions, and AI rationales are now escaped before they enter the report (the Action posts it verbatim as a PR comment), so a crafted public API name can no longer forge a heading, table row, or link. A single very long declaration line is capped so it can't push the comment past GitHub's size limit, and the missed-breaks audit caps the API surface it sends rather than serializing an unbounded prompt. When that audit fails on an additions-only diff, or runs against a surface trimmed to fit the cap, the report now flags the partial coverage instead of claiming a complete review. + +- [#31](https://github.com/clerk/break-check/pull/31) [`2479ffc`](https://github.com/clerk/break-check/commit/2479ffce1adb8ff5f1caf95509268774224c121d) Thanks [@jacekradko](https://github.com/jacekradko)! - Markdown reporter now renders before/after snippets as a unified diff anchored + on the aligned common prefix and suffix, with a few lines of context and an + elision marker for the unchanged bulk. Previously, large mostly-identical + snippets were truncated head+tail on each side independently, which buried + the actual change in the elided middle and produced ~120 lines of duplicate + content for a 1-line edit. When the two sides share no structure, the + reporter still falls back to per-side head+tail truncation. diff --git a/package.json b/package.json index 39b14d8..4755026 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@clerk/break-check", - "version": "0.0.1", + "version": "0.1.0", "description": "Detect API breaking changes in TypeScript packages", "type": "module", "packageManager": "pnpm@11.2.2+sha512.36e6621fad506178936455e70247b8808ef4ec25797a9f437a93281a020484e2607f6a469a22e982987c3dbb8866e3071514ab10a4a1749e06edcd1ec118436f",