@williamthorsen/release-kit 10.9.0 → 12.0.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.
Files changed (97) hide show
  1. package/.meta/changelog.json +119 -2
  2. package/.readyup/kits/default.js +1 -17
  3. package/.readyup/kits/npm-auto-publish.js +42 -22
  4. package/.readyup/manifest.json +7 -7
  5. package/CHANGELOG.md +88 -0
  6. package/README.md +32 -32
  7. package/dist/esm/attachChangelogDiagnostics.d.ts +4 -0
  8. package/dist/esm/attachChangelogDiagnostics.js +11 -0
  9. package/dist/esm/bin/release-kit.js +34 -25
  10. package/dist/esm/buildChangelogEntries.d.ts +59 -17
  11. package/dist/esm/buildChangelogEntries.js +195 -111
  12. package/dist/esm/buildReleaseSummary.js +2 -2
  13. package/dist/esm/changelogOverrides.d.ts +31 -13
  14. package/dist/esm/changelogOverrides.js +138 -58
  15. package/dist/esm/classifyChangelogCommit.d.ts +38 -0
  16. package/dist/esm/classifyChangelogCommit.js +33 -0
  17. package/dist/esm/configFlagSchema.d.ts +12 -0
  18. package/dist/esm/configFlagSchema.js +3 -0
  19. package/dist/esm/createGithubReleaseCommand.js +6 -2
  20. package/dist/esm/decideRelease.d.ts +11 -37
  21. package/dist/esm/decideRelease.js +5 -27
  22. package/dist/esm/defaults.d.ts +1 -1
  23. package/dist/esm/defaults.js +3 -0
  24. package/dist/esm/determineBumpType.d.ts +11 -11
  25. package/dist/esm/determineBumpType.js +6 -7
  26. package/dist/esm/discoverWorkspaces.d.ts +53 -8
  27. package/dist/esm/discoverWorkspaces.js +57 -37
  28. package/dist/esm/enumerateReleaseWindows.d.ts +50 -0
  29. package/dist/esm/enumerateReleaseWindows.js +124 -0
  30. package/dist/esm/generateChangelogs.d.ts +5 -23
  31. package/dist/esm/generateChangelogs.js +0 -14
  32. package/dist/esm/glyphs.d.ts +1 -1
  33. package/dist/esm/help/prepareHelp.d.ts +1 -1
  34. package/dist/esm/help/prepareHelp.js +5 -6
  35. package/dist/esm/index.d.ts +1 -1
  36. package/dist/esm/init/initCommand.js +1 -1
  37. package/dist/esm/init/scaffold.d.ts +0 -2
  38. package/dist/esm/init/scaffold.js +2 -30
  39. package/dist/esm/loadConfig.d.ts +8 -5
  40. package/dist/esm/loadConfig.js +7 -7
  41. package/dist/esm/loadValidatedConfig.d.ts +46 -5
  42. package/dist/esm/loadValidatedConfig.js +32 -15
  43. package/dist/esm/parseChangeRecordBlock.d.ts +37 -0
  44. package/dist/esm/parseChangeRecordBlock.js +134 -0
  45. package/dist/esm/parseCommitMessage.d.ts +31 -6
  46. package/dist/esm/parseCommitMessage.js +6 -5
  47. package/dist/esm/prepareCommand.d.ts +5 -0
  48. package/dist/esm/prepareCommand.js +30 -47
  49. package/dist/esm/previewTagPrefixes.d.ts +9 -6
  50. package/dist/esm/previewTagPrefixes.js +12 -24
  51. package/dist/esm/publishCommand.d.ts +2 -2
  52. package/dist/esm/publishCommand.js +8 -2
  53. package/dist/esm/pushCommand.d.ts +1 -1
  54. package/dist/esm/pushCommand.js +2 -2
  55. package/dist/esm/releasePrepare.d.ts +7 -8
  56. package/dist/esm/releasePrepare.js +53 -73
  57. package/dist/esm/releasePrepareMono.js +48 -85
  58. package/dist/esm/releasePrepareProject.d.ts +1 -1
  59. package/dist/esm/releasePrepareProject.js +19 -37
  60. package/dist/esm/reportPrepare.js +45 -30
  61. package/dist/esm/resolveCommandTags.d.ts +3 -2
  62. package/dist/esm/resolveCommandTags.js +10 -6
  63. package/dist/esm/resolveReleaseNotesConfig.d.ts +9 -11
  64. package/dist/esm/resolveReleaseNotesConfig.js +9 -28
  65. package/dist/esm/showTagPrefixesCommand.d.ts +4 -2
  66. package/dist/esm/showTagPrefixesCommand.js +17 -3
  67. package/dist/esm/sync-labels/generateCommand.d.ts +16 -8
  68. package/dist/esm/sync-labels/generateCommand.js +12 -11
  69. package/dist/esm/sync-labels/initCommand.d.ts +9 -4
  70. package/dist/esm/sync-labels/initCommand.js +21 -15
  71. package/dist/esm/sync-labels/retiredConfig.d.ts +4 -2
  72. package/dist/esm/sync-labels/retiredConfig.js +2 -2
  73. package/dist/esm/types.d.ts +99 -55
  74. package/dist/esm/types.js +1 -1
  75. package/dist/esm/validateConfig.js +4 -0
  76. package/dist/esm/validateOverridesCommand.d.ts +16 -9
  77. package/dist/esm/validateOverridesCommand.js +39 -54
  78. package/docs/changelogs.md +64 -25
  79. package/docs/configuration.md +14 -3
  80. package/docs/editorial-overrides.md +75 -16
  81. package/docs/labels.md +2 -0
  82. package/docs/project-releases.md +4 -4
  83. package/docs/releasing.md +13 -8
  84. package/docs/work-types.md +13 -9
  85. package/package.json +5 -7
  86. package/schemas/changelog-overrides.json +39 -0
  87. package/cliff.toml.template +0 -65
  88. package/dist/esm/collectPolicyViolations.d.ts +0 -15
  89. package/dist/esm/collectPolicyViolations.js +0 -12
  90. package/dist/esm/determineBumpFromCommits.d.ts +0 -17
  91. package/dist/esm/determineBumpFromCommits.js +0 -28
  92. package/dist/esm/getCommitsSinceTarget.d.ts +0 -21
  93. package/dist/esm/getCommitsSinceTarget.js +0 -66
  94. package/dist/esm/resolveCliffConfigPath.d.ts +0 -11
  95. package/dist/esm/resolveCliffConfigPath.js +0 -20
  96. package/dist/esm/runGitCliff.d.ts +0 -38
  97. package/dist/esm/runGitCliff.js +0 -25
@@ -1,4 +1,121 @@
1
1
  [
2
+ {
3
+ "version": "12.0.0",
4
+ "date": "2026-09-23",
5
+ "sections": [
6
+ {
7
+ "title": "🎉 Features",
8
+ "audience": "all",
9
+ "items": [
10
+ {
11
+ "description": "Assign changelog sections from the work-type taxonomy (#877)",
12
+ "body": "- Adds `excludedFromChangelog` to a `workTypes` entry, which keeps commits of that type out of every changelog while they still count toward the version bump.\n- Fixes the silent omission of a ticketed commit written as `type(scope):` or with a capitalized type such as `FEAT:`, which counted toward the version bump but reached no changelog.\n- Documents that a scaffolded `.config/git-cliff.toml` may vary its enumeration keys alone: a `commit_parsers` entry that skips or narrows drops the commit before classification, with no error.",
13
+ "hash": "52d4ea928d35b99101947e0509da6699f06f821a"
14
+ },
15
+ {
16
+ "description": "Build changelog items from a merge commit's change-record block (#882)",
17
+ "body": "Builds `release-kit` changelog items from a commit's `change-record` block, the fenced YAML block at the end of a squash-merge commit that lists the change's outcomes, so that a merge with several outcomes of different types yields one item per outcome, each under its own type's section. Makes `release-kit prepare` warn about a block that cannot be read, an entry whose type is undeclared, and an entry that violates its type's breaking policy. Keeps reading a commit with no usable block from its title, as before.",
18
+ "hash": "094aac7048a54b6f07d1c97cd37fff570630b936"
19
+ },
20
+ {
21
+ "description": "Derive the version bump from the changelog items (#885)",
22
+ "body": "Derives the version bump in every `release-kit prepare` path (single-package, project, and monorepo) from the changelog items of the unreleased commits, so that the bump and the changelog describe the same release. A commit that yields no changelog item no longer bumps, and a `BREAKING CHANGE:` footer no longer raises a major bump. Single-package mode now follows the monorepo rules for `--bump` and `--force`, and the `prepare` report shows the diagnostics of a skipped target.\n\nMigration: Mark a breaking change with a `!` on the commit subject or with `breaking: true` on its change-record entry, because a `BREAKING CHANGE:` footer alone now gets the bump of the commit's type. Give each commit that should bump a ticket-ID prefix and a type that the changelog does not exclude. In single-package mode, add `--force` to a release that used `--bump=X` alone, or that relied on the patch floor, when no commit yields a changelog item; without it, `prepare` skips the release.",
23
+ "breaking": true,
24
+ "migration": "Mark a breaking change with a `!` on the commit subject or with `breaking: true` on its change-record entry, because a `BREAKING CHANGE:` footer alone now gets the bump of the commit's type. Give each commit that should bump a ticket-ID prefix and a type that the changelog does not exclude. In single-package mode, add `--force` to a release that used `--bump=X` alone, or that relied on the patch floor, when no commit yields a changelog item; without it, `prepare` skips the release.",
25
+ "hash": "f3d0d8f01d6cd5b5638012a4798e64ab3a3def6d"
26
+ },
27
+ {
28
+ "description": "Key an editorial override to one of several items on a commit (#886)",
29
+ "body": "Adds the `<hash>:<n>` key to `.meta/changelog-overrides.json`. It targets one of the several changelog items that a commit's change-record block yields, while a bare `<hash>` key still targets all of them. Also makes `release-kit prepare` and `release-kit overrides validate` fail when override keys conflict on an item, and publishes a JSON Schema for the override file.\n\nMigration: Replace a bare key that sets `description` or `body` on a commit with several items with one `<hash>:<n>` key per item, as listed by the error message. Where two keys match the same item, such as `abc1234` beside `abc1234:2`, remove one of them. This includes a root-file key that overlaps a workspace-file key, which now fails even though the two files are separate. In each scope passed to `validateAllChangelogOverrides`, rename `hashes` to `items` and pass `OverrideTargetItem` objects (`{ hash, entry? }`) instead of hash strings.",
30
+ "breaking": true,
31
+ "migration": "Replace a bare key that sets `description` or `body` on a commit with several items with one `<hash>:<n>` key per item, as listed by the error message. Where two keys match the same item, such as `abc1234` beside `abc1234:2`, remove one of them. This includes a root-file key that overlaps a workspace-file key, which now fails even though the two files are separate. In each scope passed to `validateAllChangelogOverrides`, rename `hashes` to `items` and pass `OverrideTargetItem` objects (`{ hash, entry? }`) instead of hash strings.",
32
+ "hash": "f90db5596196e501fef1734bcd978d23f9a0540a"
33
+ }
34
+ ]
35
+ },
36
+ {
37
+ "title": "🪦 Removed",
38
+ "audience": "all",
39
+ "items": [
40
+ {
41
+ "description": "Build changelogs from release-kit's own enumeration and remove git-cliff (#880)",
42
+ "body": "Removes git-cliff from `@williamthorsen/release-kit`: `prepare` now builds every changelog from the same commit history that decides each version bump, and no longer fetches a git-cliff binary through `npx`. A config that still sets `cliffConfigPath` now fails validation. Two ways in which the changelog and the bump read different commits are gone, affecting single-package repositories with a tag prefix other than `v` and `paths` entries that name a bare directory.\n\nMigration: Remove `cliffConfigPath` from `.config/release-kit.config.ts`, and delete `.config/git-cliff.toml` or `cliff.toml` if the repository has one. Any customization in that file, such as `tag_pattern` or its tag-skipping keys, no longer has an effect: `release-kit` now splits the changelog on the configured tag prefixes alone.",
43
+ "breaking": true,
44
+ "migration": "Remove `cliffConfigPath` from `.config/release-kit.config.ts`, and delete `.config/git-cliff.toml` or `cliff.toml` if the repository has one. Any customization in that file, such as `tag_pattern` or its tag-skipping keys, no longer has an effect: `release-kit` now splits the changelog on the configured tag prefixes alone.",
45
+ "hash": "3dc091ff6067f1c2cbe1576a55114c481294ce22"
46
+ }
47
+ ]
48
+ },
49
+ {
50
+ "title": "🏗️ Internal features",
51
+ "audience": "dev",
52
+ "items": [
53
+ {
54
+ "description": "Enumerate release windows and read them on the bump path (#879)",
55
+ "body": "Adds `enumerateReleaseWindows`, which splits the history reachable from HEAD into release windows from tag prefixes and a path list, and rebuilds `getCommitsSinceTarget` on the newest of those windows in place of its `git describe` baseline lookup. Leaves the changelog on git-cliff's enumeration.",
56
+ "hash": "30586d1e045ed69dbf81a1c35773c97b89e0c8dc"
57
+ }
58
+ ]
59
+ }
60
+ ]
61
+ },
62
+ {
63
+ "version": "11.0.0",
64
+ "date": "2026-09-22",
65
+ "sections": [
66
+ {
67
+ "title": "🎉 Features",
68
+ "audience": "all",
69
+ "items": [
70
+ {
71
+ "description": "Return the provenance check's remediation as the outcome's fix (#855)",
72
+ "body": "- Moves the remediation of the `npm-auto-publish` kit's `Provenance setting matches repo visibility` check from the failing outcome's `detail` into its `fix`, so that readyup marks it as a remedy, lists it in the `Fixes` recap, and reports it under `rdy run --json --detail summary` instead of printing it as a plain reason line.\n- Declares `minReadyupVersion: '0.37.0'` on the kit, the readyup release that introduced `CheckOutcome.fix`, which retires the kit's `version-skew` advisory and makes an older runner fail to load the kit.\n\nMigration: Upgrade readyup to 0.37.0 or later before consuming this release of the `npm-auto-publish` kit.",
73
+ "breaking": true,
74
+ "migration": "Upgrade readyup to 0.37.0 or later before consuming this release of the `npm-auto-publish` kit.",
75
+ "hash": "2455edc46611a47e95707f79cdebda539a844431"
76
+ },
77
+ {
78
+ "description": "Accept a --config argument on every config-reading subcommand (#857)",
79
+ "body": "- Adds `--config <path>` to `prepare`, `publish`, `create-github-release`, `show-tag-prefixes`, `overrides validate`, `sync-labels init`, and `sync-labels generate`, each of which then reads the named file in place of `.config/release-kit.config.ts`.\n- Requires a named `--config` file to exist, failing if it does not; an absent default path continues to mean that the repo declares no config.\n- Confines scaffolding to the default path: `release-kit init` and `sync-labels init` still write `.config/release-kit.config.ts`, and `sync-labels init --config` reads the named file and fails when it is absent.",
80
+ "hash": "f605a6fd7e48b27b17fb90bad161f4507979e5aa"
81
+ },
82
+ {
83
+ "description": "Adopt the shared workspace resolver in release-kit, honoring exclusions (#865)",
84
+ "body": "- 🚨 **Breaking:** Narrows `no-pattern` in `@williamthorsen/nmr-core`'s `EmptyWorkspaceCause`, moving an absent or empty `packages` list onto `no-packages-list` and a value that is not a list of strings onto `unreadable-packages`.\n- Stops `release-kit` from tagging, publishing, and label-syncing a package that a `!` entry in `pnpm-workspace.yaml` excludes, which its previous `glob`-based resolution could not remove from the match.\n- Replaces the release of the root package alone with a failure naming the condition that emptied the workspace, when `pnpm-workspace.yaml` does not hold valid YAML or declares a workspace that does not resolve to a package.\n- Replaces the `no-pattern` remedy that `nmr` printed for a `pnpm-workspace.yaml` declaring no `packages` list, and for one declaring a `packages` value that is not a list of strings.\n- Raises `engines.node` to `>=24.16.0` in `@williamthorsen/nmr-core` and `@williamthorsen/release-kit`, because Node 24.0 through 24.15 ignores the `followSymlinks` option that the workspace matcher passes to `globSync` and drops a symlinked package directory from the resolution without reporting it.\n\nMigration: Add a `no-packages-list` arm and an `unreadable-packages` arm to any `switch` that covers `EmptyWorkspaceCause` exhaustively. `no-pattern` now names only a list that the resolver read in full and whose entries all failed to become a positive pattern, so move the handling of an absent `packages` key, an empty list, and a value that is not a list of strings out of the `no-pattern` arm into the two new ones. Route `no-packages-list` to single-package behavior rather than to a failure path: pnpm resolves such a manifest to the root package alone.",
85
+ "breaking": true,
86
+ "migration": "Add a `no-packages-list` arm and an `unreadable-packages` arm to any `switch` that covers `EmptyWorkspaceCause` exhaustively. `no-pattern` now names only a list that the resolver read in full and whose entries all failed to become a positive pattern, so move the handling of an absent `packages` key, an empty list, and a value that is not a list of strings out of the `no-pattern` arm into the two new ones. Route `no-packages-list` to single-package behavior rather than to a failure path: pnpm resolves such a manifest to the root package alone.",
87
+ "hash": "b1126866159402b8f027a9b82f2a19591a6e9e1b"
88
+ }
89
+ ]
90
+ },
91
+ {
92
+ "title": "🐛 Bug fixes",
93
+ "audience": "all",
94
+ "items": [
95
+ {
96
+ "description": "Truncate release-kit commit subjects by display column (#840)",
97
+ "body": "- Fixes the issue that the `release-kit` prepare report cut a commit subject at 69 UTF-16 code units instead of at display columns, so a subject of CJK characters printed about twice the intended 72-column width and a cut inside an emoji left a broken character that a terminal drew as a replacement glyph.\n- Replaces the `...` marker on a truncated subject with `…`, the default of the width-aware truncation that now does the cutting.\n- Exports `truncateToWidth` and `measureWidth` from `@williamthorsen/nmr-core`, which measure and cut text by display width without splitting a grapheme cluster.",
98
+ "hash": "f75d9b4abd9fbda264d5dd40ca5b7abb64f5a3f3"
99
+ },
100
+ {
101
+ "description": "Abort show-tag-prefixes on an unusable config (#861)",
102
+ "body": "- Fixes the issue that `release-kit show-tag-prefixes` silently ignored a config file that failed schema validation, which left the preview reading no `legacyIdentities` and no `retiredPackages` and reporting already-declared and retired tag prefixes as undeclared candidates; the command now prints those validation errors and exits 1 with no preview.",
103
+ "hash": "2177873d9a79247385e5a1f09e95971449488d9f"
104
+ },
105
+ {
106
+ "description": "Abort every config-reading command on an unusable default config (#869)",
107
+ "body": "- Fixes `publish` proceeding on derived defaults when the default config file exists and fails to load, which silently dropped a configured `releaseNotes.shouldInjectIntoReadme`, `changelogJson.outputPath`, or `workTypes`; it now reports the failure and exits 1, as every other config-reading subcommand does.\n- Fixes `publish` and `create-github-release` ignoring a broken or invalid default config when every requested tag names a private package, a case in which both commands return before any loader runs.",
108
+ "hash": "5b2873f2b9b7e42f1011d90506ca7ea6945d09a1"
109
+ },
110
+ {
111
+ "description": "Strip trailing Change trailers from changelog item bodies (#870)",
112
+ "body": "- Fixes a changelog item body that kept a commit's trailing `Change:` trailers, which then appeared verbatim in the rendered release notes, including the notes injected into a README.",
113
+ "hash": "250e52b3a2947202e3a7246fb39ebcb79e2bd1fc"
114
+ }
115
+ ]
116
+ }
117
+ ]
118
+ },
2
119
  {
3
120
  "version": "10.9.0",
4
121
  "date": "2026-09-18",
@@ -351,7 +468,7 @@
351
468
  },
352
469
  {
353
470
  "description": "Adopt `isError` and consolidate errno narrowing on a shared helper (#697)",
354
- "body": "Replaces every hand-rolled `instanceof Error` narrowing with `hasErrnoCode`, a new predicate exported from `@williamthorsen/nmr-core`, or with `isError` from `@williamthorsen/toolbelt.errors`. Previously the errno question was answered by inline copies alongside two private helpers of differing shape; both helpers are removed.\r\n\r\nSeparately, `eslint.config.ts` now bans `instanceof Error` in every position rather than in a ternary alone.",
471
+ "body": "Replaces every hand-rolled `instanceof Error` narrowing with `hasErrnoCode`, a new predicate exported from `@williamthorsen/nmr-core`, or with `isError` from `@williamthorsen/toolbelt.errors`. Previously the errno question was answered by inline copies alongside two private helpers of differing shape; both helpers are removed.\n\nSeparately, `eslint.config.ts` now bans `instanceof Error` in every position rather than in a ternary alone.",
355
472
  "hash": "c5e8e8a5e006b451e8c5aeea75d35772926d503c"
356
473
  }
357
474
  ]
@@ -472,7 +589,7 @@
472
589
  },
473
590
  {
474
591
  "description": "Make prepare all-or-nothing and report the tags file by path (#601)",
475
- "body": "Fixes an issue where a failed `prepare` could leave the release flow in a broken intermediate state. A release now lands completely or not at all, and a formatting failure no longer discards one that already landed. When a write fails partway, the error names every file that reached disk, every file that did not, and the commands that undo them.\r\n\r\n`commit` and `tag` now report the full path of the tags file they looked for, and distinguish a missing file from one that could not be read, so that running from the wrong directory or worktree is no longer reported as a release that never happened.\r\n\r\nRuns with `--with-release-notes` now list the preview files they write, and `--dry-run` names the ones a real run would write.",
592
+ "body": "Fixes an issue where a failed `prepare` could leave the release flow in a broken intermediate state. A release now lands completely or not at all, and a formatting failure no longer discards one that already landed. When a write fails partway, the error names every file that reached disk, every file that did not, and the commands that undo them.\n\n`commit` and `tag` now report the full path of the tags file they looked for, and distinguish a missing file from one that could not be read, so that running from the wrong directory or worktree is no longer reported as a release that never happened.\n\nRuns with `--with-release-notes` now list the preview files they write, and `--dry-run` names the ones a real run would write.",
476
593
  "hash": "83ac6e45cf9d4b5371650cda42d7830ed4988660"
477
594
  }
478
595
  ]
@@ -98,7 +98,7 @@ function translateGlob(pattern) {
98
98
 
99
99
  // .readyup/kits/default.ts
100
100
  function getMinVersion() {
101
- const picked = { "version": "10.9.0" };
101
+ const picked = { "version": "12.0.0" };
102
102
  if (typeof picked["version"] !== "string") {
103
103
  throw new TypeError("release-kit/package.json: 'version' must be a string");
104
104
  }
@@ -114,7 +114,6 @@ var CONFIG_EXPORT_PATTERNS = [
114
114
  /export\s*\{[^}]*\b(?:config|default)\b[^}]*\}/,
115
115
  /export\s*\*/
116
116
  ];
117
- var CLIFF_TEMPLATE_HASH = "93b72e0b1393cd6b1fe8e2a0e303cd326fd323435951b0493396b305af32d2ec";
118
117
  var COMMON_PRESET_HASH = "8c52654d4eee216c22377dd1e65b89f6bbb0a3478d74379bd28b04a877f0b02a";
119
118
  var SYNC_LABELS_WORKFLOW_HASH = "d6e2403fb551d2d415f679125989c92760444eec887644565b2e05c9bf8f4c1e";
120
119
  var RELEASE_WORKFLOW_HASH_MONOREPO = "0a9724b7b3c5e24087fd3a8f36fed8e990d699267fcf36028ce048ab40dc2946";
@@ -296,13 +295,6 @@ var default_default = defineRdyKit({
296
295
  check: () => fileDoesNotContain(".config/release-kit.config.ts", /shouldCreateGithubRelease/),
297
296
  fix: "Remove 'shouldCreateGithubRelease' from .config/release-kit.config.ts. Adoption of GitHub Releases is now signaled by installing the create-github-release workflow, which `release-kit init` scaffolds."
298
297
  },
299
- {
300
- name: "git-cliff not in devDependencies",
301
- severity: "recommend",
302
- quiet: true,
303
- check: () => !hasDevDependency("git-cliff"),
304
- fix: "pnpm remove git-cliff \u2014 release-kit handles changelog generation directly"
305
- },
306
298
  {
307
299
  name: "@changesets/cli not in devDependencies",
308
300
  severity: "recommend",
@@ -310,13 +302,6 @@ var default_default = defineRdyKit({
310
302
  check: () => !hasDevDependency("@changesets/cli"),
311
303
  fix: "pnpm remove @changesets/cli, then delete .changeset/ and any changeset:* scripts; release-kit supersedes changesets"
312
304
  },
313
- {
314
- name: ".config/git-cliff.toml matches current template",
315
- severity: "warn",
316
- skip: () => !fileExists(".config/git-cliff.toml") ? "no local cliff config (using fallback)" : false,
317
- check: () => fileMatchesHash(".config/git-cliff.toml", CLIFF_TEMPLATE_HASH),
318
- fix: "Update .config/git-cliff.toml to match the current cliff.toml.template from release-kit, or delete it to use the bundled fallback"
319
- },
320
305
  {
321
306
  name: "sync-labels.yaml workflow exists",
322
307
  severity: "warn",
@@ -425,7 +410,6 @@ function resolveChangelogJsonOutputPath() {
425
410
  return match?.[1] ?? DEFAULT_CHANGELOG_JSON_PATH;
426
411
  }
427
412
  export {
428
- CLIFF_TEMPLATE_HASH,
429
413
  COMMON_PRESET_HASH,
430
414
  CREATE_GITHUB_RELEASE_WORKFLOW_HASH_MONOREPO,
431
415
  CREATE_GITHUB_RELEASE_WORKFLOW_HASH_SINGLE,
@@ -94,6 +94,9 @@ var packagesChecklist = defineRdyChecklist({
94
94
  });
95
95
  var npm_auto_publish_default = defineRdyKit({
96
96
  fixLocation: "inline",
97
+ // The release that introduced `CheckOutcome.fix`, on which the provenance check's remediation depends. An older
98
+ // runner drops that `fix` silently, so failing to load the kit is the lesser harm.
99
+ minReadyupVersion: "0.37.0",
97
100
  checklists: [repoChecklist, packagesChecklist]
98
101
  });
99
102
  function belongsInPackagesChecklist(workspace) {
@@ -107,8 +110,8 @@ function buildSessionCheck() {
107
110
  const capability = getCachedTrustCapability();
108
111
  return capability.ok ? { ok: true } : { ok: false, detail: capability.detail };
109
112
  },
110
- // A plain string rather than a getter, because readyup takes outcome-specific wording in `detail`, which the
111
- // check above already carries.
113
+ // A plain string rather than a getter, because the remediation is the same however the session fails; only
114
+ // the `detail` above varies.
112
115
  fix: 'Restore a usable npm session: log in with "npm login", supplying the one-time password when prompted, or restore access to the registry, which the trusted-publisher check queries directly'
113
116
  };
114
117
  }
@@ -175,29 +178,13 @@ function buildWorkspaceCheck(workspace) {
175
178
  function checkProvenanceMatchesVisibility() {
176
179
  const workflowPath = ".github/workflows/publish.yaml";
177
180
  const content = readFile(workflowPath);
178
- if (content === void 0) {
179
- return { ok: false, detail: `Cannot read ${workflowPath} \u2014 check file permissions` };
180
- }
181
- const hasProvenance = parseProvenanceSetting(content);
182
- let isPrivate;
181
+ let visibility;
183
182
  try {
184
- isPrivate = isRepoPrivate();
183
+ visibility = isRepoPrivate() ? "private" : "public";
185
184
  } catch {
186
- return { ok: false, detail: "Install and authenticate the GitHub CLI: gh auth login" };
187
- }
188
- if (!isPrivate && !hasProvenance) {
189
- return {
190
- ok: false,
191
- detail: "Set provenance: true in .github/workflows/publish.yaml \u2014 public repos should generate provenance attestations"
192
- };
193
- }
194
- if (isPrivate && hasProvenance) {
195
- return {
196
- ok: false,
197
- detail: "Make the GitHub repo public \u2014 OIDC publishing with provenance requires a public repo"
198
- };
185
+ visibility = "unknown";
199
186
  }
200
- return { ok: true };
187
+ return classifyProvenanceSetting(content, visibility);
201
188
  }
202
189
  function checkTrustedPublisher(packageName) {
203
190
  const result = getTrustQueryResult(packageName);
@@ -226,6 +213,38 @@ function classifyNpmAuth(result) {
226
213
  }
227
214
  return { status: "unreachable", detail: `The npm registry query failed (${error.code}): ${error.summary}` };
228
215
  }
216
+ function classifyProvenanceSetting(workflowContent, visibility) {
217
+ if (workflowContent === void 0) {
218
+ return {
219
+ ok: false,
220
+ detail: "Cannot read .github/workflows/publish.yaml",
221
+ fix: "Check the file's permissions"
222
+ };
223
+ }
224
+ if (visibility === "unknown") {
225
+ return {
226
+ ok: false,
227
+ detail: "The GitHub CLI could not report the repo's visibility",
228
+ fix: "Install and authenticate the GitHub CLI: gh auth login"
229
+ };
230
+ }
231
+ const hasProvenance = parseProvenanceSetting(workflowContent);
232
+ if (visibility === "public" && !hasProvenance) {
233
+ return {
234
+ ok: false,
235
+ detail: "The repo is public and publish.yaml does not set provenance: true",
236
+ fix: "Set provenance: true in .github/workflows/publish.yaml \u2014 public repos should generate provenance attestations"
237
+ };
238
+ }
239
+ if (visibility === "private" && hasProvenance) {
240
+ return {
241
+ ok: false,
242
+ detail: "The repo is private and publish.yaml sets provenance: true",
243
+ fix: "Make the GitHub repo public \u2014 OIDC publishing with provenance requires a public repo"
244
+ };
245
+ }
246
+ return { ok: true };
247
+ }
229
248
  function classifyTrustCapability(auth, probe) {
230
249
  if (auth.status !== "authenticated") {
231
250
  return { ok: false, detail: auth.detail };
@@ -409,6 +428,7 @@ function skipIfNotPublishable(workspace) {
409
428
  export {
410
429
  buildWorkspaceCheck,
411
430
  classifyNpmAuth,
431
+ classifyProvenanceSetting,
412
432
  classifyTrustCapability,
413
433
  classifyTrustQuery,
414
434
  npm_auto_publish_default as default,
@@ -8,12 +8,12 @@
8
8
  "esbuildVersion": "0.28.2",
9
9
  "inputs": [
10
10
  {
11
- "hash": "a20ce64b",
11
+ "hash": "07f5fe58",
12
12
  "kind": "module",
13
13
  "path": "kits/default.ts"
14
14
  },
15
15
  {
16
- "hash": "beeecbc7",
16
+ "hash": "54c6b74c",
17
17
  "kind": "inline",
18
18
  "path": "../package.json",
19
19
  "paths": [
@@ -45,8 +45,8 @@
45
45
  "path": "kits/default.js",
46
46
  "readyupVersion": "0.38.0",
47
47
  "source": "kits/default.ts",
48
- "sourceHash": "a20ce64b",
49
- "targetHash": "d3d5b51c"
48
+ "sourceHash": "07f5fe58",
49
+ "targetHash": "cece8501"
50
50
  },
51
51
  {
52
52
  "checklists": [
@@ -56,7 +56,7 @@
56
56
  "esbuildVersion": "0.28.2",
57
57
  "inputs": [
58
58
  {
59
- "hash": "4eed1e9c",
59
+ "hash": "c2d2d375",
60
60
  "kind": "module",
61
61
  "path": "kits/npm-auto-publish.ts"
62
62
  }
@@ -65,8 +65,8 @@
65
65
  "path": "kits/npm-auto-publish.js",
66
66
  "readyupVersion": "0.38.0",
67
67
  "source": "kits/npm-auto-publish.ts",
68
- "sourceHash": "4eed1e9c",
69
- "targetHash": "d6126351"
68
+ "sourceHash": "c2d2d375",
69
+ "targetHash": "9d2d224b"
70
70
  }
71
71
  ]
72
72
  }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,94 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 12.0.0 — 2026-09-23
6
+
7
+ ### 🎉 Features
8
+
9
+ - Assign changelog sections from the work-type taxonomy (#877)
10
+
11
+ - Adds `excludedFromChangelog` to a `workTypes` entry, which keeps commits of that type out of every changelog while they still count toward the version bump.
12
+ - Fixes the silent omission of a ticketed commit written as `type(scope):` or with a capitalized type such as `FEAT:`, which counted toward the version bump but reached no changelog.
13
+ - Documents that a scaffolded `.config/git-cliff.toml` may vary its enumeration keys alone: a `commit_parsers` entry that skips or narrows drops the commit before classification, with no error.
14
+
15
+ - Build changelog items from a merge commit's change-record block (#882)
16
+
17
+ Builds `release-kit` changelog items from a commit's `change-record` block, the fenced YAML block at the end of a squash-merge commit that lists the change's outcomes, so that a merge with several outcomes of different types yields one item per outcome, each under its own type's section. Makes `release-kit prepare` warn about a block that cannot be read, an entry whose type is undeclared, and an entry that violates its type's breaking policy. Keeps reading a commit with no usable block from its title, as before.
18
+
19
+ - 🚨 **Breaking:** Derive the version bump from the changelog items (#885)
20
+
21
+ Derives the version bump in every `release-kit prepare` path (single-package, project, and monorepo) from the changelog items of the unreleased commits, so that the bump and the changelog describe the same release. A commit that yields no changelog item no longer bumps, and a `BREAKING CHANGE:` footer no longer raises a major bump. Single-package mode now follows the monorepo rules for `--bump` and `--force`, and the `prepare` report shows the diagnostics of a skipped target.
22
+
23
+ Migration: Mark a breaking change with a `!` on the commit subject or with `breaking: true` on its change-record entry, because a `BREAKING CHANGE:` footer alone now gets the bump of the commit's type. Give each commit that should bump a ticket-ID prefix and a type that the changelog does not exclude. In single-package mode, add `--force` to a release that used `--bump=X` alone, or that relied on the patch floor, when no commit yields a changelog item; without it, `prepare` skips the release.
24
+
25
+ - 🚨 **Breaking:** Key an editorial override to one of several items on a commit (#886)
26
+
27
+ Adds the `<hash>:<n>` key to `.meta/changelog-overrides.json`. It targets one of the several changelog items that a commit's change-record block yields, while a bare `<hash>` key still targets all of them. Also makes `release-kit prepare` and `release-kit overrides validate` fail when override keys conflict on an item, and publishes a JSON Schema for the override file.
28
+
29
+ Migration: Replace a bare key that sets `description` or `body` on a commit with several items with one `<hash>:<n>` key per item, as listed by the error message. Where two keys match the same item, such as `abc1234` beside `abc1234:2`, remove one of them. This includes a root-file key that overlaps a workspace-file key, which now fails even though the two files are separate. In each scope passed to `validateAllChangelogOverrides`, rename `hashes` to `items` and pass `OverrideTargetItem` objects (`{ hash, entry? }`) instead of hash strings.
30
+
31
+ ### 🪦 Removed
32
+
33
+ - 🚨 **Breaking:** Build changelogs from release-kit's own enumeration and remove git-cliff (#880)
34
+
35
+ Removes git-cliff from `@williamthorsen/release-kit`: `prepare` now builds every changelog from the same commit history that decides each version bump, and no longer fetches a git-cliff binary through `npx`. A config that still sets `cliffConfigPath` now fails validation. Two ways in which the changelog and the bump read different commits are gone, affecting single-package repositories with a tag prefix other than `v` and `paths` entries that name a bare directory.
36
+
37
+ Migration: Remove `cliffConfigPath` from `.config/release-kit.config.ts`, and delete `.config/git-cliff.toml` or `cliff.toml` if the repository has one. Any customization in that file, such as `tag_pattern` or its tag-skipping keys, no longer has an effect: `release-kit` now splits the changelog on the configured tag prefixes alone.
38
+
39
+ ### 🏗️ Internal features
40
+
41
+ - Enumerate release windows and read them on the bump path (#879)
42
+
43
+ Adds `enumerateReleaseWindows`, which splits the history reachable from HEAD into release windows from tag prefixes and a path list, and rebuilds `getCommitsSinceTarget` on the newest of those windows in place of its `git describe` baseline lookup. Leaves the changelog on git-cliff's enumeration.
44
+
45
+ ## 11.0.0 — 2026-09-22
46
+
47
+ ### 🎉 Features
48
+
49
+ - 🚨 **Breaking:** Return the provenance check's remediation as the outcome's fix (#855)
50
+
51
+ - Moves the remediation of the `npm-auto-publish` kit's `Provenance setting matches repo visibility` check from the failing outcome's `detail` into its `fix`, so that readyup marks it as a remedy, lists it in the `Fixes` recap, and reports it under `rdy run --json --detail summary` instead of printing it as a plain reason line.
52
+ - Declares `minReadyupVersion: '0.37.0'` on the kit, the readyup release that introduced `CheckOutcome.fix`, which retires the kit's `version-skew` advisory and makes an older runner fail to load the kit.
53
+
54
+ Migration: Upgrade readyup to 0.37.0 or later before consuming this release of the `npm-auto-publish` kit.
55
+
56
+ - Accept a --config argument on every config-reading subcommand (#857)
57
+
58
+ - Adds `--config <path>` to `prepare`, `publish`, `create-github-release`, `show-tag-prefixes`, `overrides validate`, `sync-labels init`, and `sync-labels generate`, each of which then reads the named file in place of `.config/release-kit.config.ts`.
59
+ - Requires a named `--config` file to exist, failing if it does not; an absent default path continues to mean that the repo declares no config.
60
+ - Confines scaffolding to the default path: `release-kit init` and `sync-labels init` still write `.config/release-kit.config.ts`, and `sync-labels init --config` reads the named file and fails when it is absent.
61
+
62
+ - 🚨 **Breaking:** Adopt the shared workspace resolver in release-kit, honoring exclusions (#865)
63
+
64
+ - 🚨 **Breaking:** Narrows `no-pattern` in `@williamthorsen/nmr-core`'s `EmptyWorkspaceCause`, moving an absent or empty `packages` list onto `no-packages-list` and a value that is not a list of strings onto `unreadable-packages`.
65
+ - Stops `release-kit` from tagging, publishing, and label-syncing a package that a `!` entry in `pnpm-workspace.yaml` excludes, which its previous `glob`-based resolution could not remove from the match.
66
+ - Replaces the release of the root package alone with a failure naming the condition that emptied the workspace, when `pnpm-workspace.yaml` does not hold valid YAML or declares a workspace that does not resolve to a package.
67
+ - Replaces the `no-pattern` remedy that `nmr` printed for a `pnpm-workspace.yaml` declaring no `packages` list, and for one declaring a `packages` value that is not a list of strings.
68
+ - Raises `engines.node` to `>=24.16.0` in `@williamthorsen/nmr-core` and `@williamthorsen/release-kit`, because Node 24.0 through 24.15 ignores the `followSymlinks` option that the workspace matcher passes to `globSync` and drops a symlinked package directory from the resolution without reporting it.
69
+
70
+ Migration: Add a `no-packages-list` arm and an `unreadable-packages` arm to any `switch` that covers `EmptyWorkspaceCause` exhaustively. `no-pattern` now names only a list that the resolver read in full and whose entries all failed to become a positive pattern, so move the handling of an absent `packages` key, an empty list, and a value that is not a list of strings out of the `no-pattern` arm into the two new ones. Route `no-packages-list` to single-package behavior rather than to a failure path: pnpm resolves such a manifest to the root package alone.
71
+
72
+ ### 🐛 Bug fixes
73
+
74
+ - Truncate release-kit commit subjects by display column (#840)
75
+
76
+ - Fixes the issue that the `release-kit` prepare report cut a commit subject at 69 UTF-16 code units instead of at display columns, so a subject of CJK characters printed about twice the intended 72-column width and a cut inside an emoji left a broken character that a terminal drew as a replacement glyph.
77
+ - Replaces the `...` marker on a truncated subject with `…`, the default of the width-aware truncation that now does the cutting.
78
+ - Exports `truncateToWidth` and `measureWidth` from `@williamthorsen/nmr-core`, which measure and cut text by display width without splitting a grapheme cluster.
79
+
80
+ - Abort show-tag-prefixes on an unusable config (#861)
81
+
82
+ - Fixes the issue that `release-kit show-tag-prefixes` silently ignored a config file that failed schema validation, which left the preview reading no `legacyIdentities` and no `retiredPackages` and reporting already-declared and retired tag prefixes as undeclared candidates; the command now prints those validation errors and exits 1 with no preview.
83
+
84
+ - Abort every config-reading command on an unusable default config (#869)
85
+
86
+ - Fixes `publish` proceeding on derived defaults when the default config file exists and fails to load, which silently dropped a configured `releaseNotes.shouldInjectIntoReadme`, `changelogJson.outputPath`, or `workTypes`; it now reports the failure and exits 1, as every other config-reading subcommand does.
87
+ - Fixes `publish` and `create-github-release` ignoring a broken or invalid default config when every requested tag names a private package, a case in which both commands return before any loader runs.
88
+
89
+ - Strip trailing Change trailers from changelog item bodies (#870)
90
+
91
+ - Fixes a changelog item body that kept a commit's trailing `Change:` trailers, which then appeared verbatim in the rendered release notes, including the notes injected into a README.
92
+
5
93
  ## 10.9.0 — 2026-09-18
6
94
 
7
95
  ### 🎉 Features
package/README.md CHANGED
@@ -4,39 +4,42 @@
4
4
 
5
5
  Version-bumping and changelog-generation toolkit for release workflows.
6
6
 
7
- Provides a self-contained CLI that auto-discovers workspaces from `pnpm-workspace.yaml`, parses conventional commits, determines version bumps, updates `package.json` files, and generates changelogs from `git-cliff --context` output rendered in-process (with optional [editorial overrides](docs/editorial-overrides.md)).
7
+ Provides a self-contained CLI that auto-discovers workspaces from `pnpm-workspace.yaml`, parses conventional commits, determines version bumps, updates `package.json` files, and generates changelogs from the same commit history that decides each bump (with optional [editorial overrides](docs/editorial-overrides.md)).
8
8
 
9
9
  <!-- section:release-notes -->
10
- ## Release notes — v10.9.0 (2026-09-18)
10
+ ## Release notes — v12.0.0 (2026-09-23)
11
11
 
12
12
  ### 🎉 Features
13
13
 
14
- - Give release-kit plain output in pipes and CI logs (#835)
14
+ - Assign changelog sections from the work-type taxonomy (#877)
15
15
 
16
- - Adds the `RELEASE_KIT_OUTPUT_STYLE` environment variable, which accepts `auto`, `plain`, or `rich` and outranks the detection from `CI`, the stream's terminal state, and `TERM`; any other value is a usage error that exits with code 1.
17
- - Changes the emoji in rich output so that none has a different meaning from the one that it has in `nmr`: warnings from ⚠️ to 🟠, skips from ⏭️ to ⏩, the errors of `show-tag-prefixes` from ⛔ to ❌, and the tag marker from 🏷️ to 🔖.
18
- - Adds a required `style` parameter to `formatValidateOverridesResult`, which the package root exports.
16
+ - Adds `excludedFromChangelog` to a `workTypes` entry, which keeps commits of that type out of every changelog while they still count toward the version bump.
17
+ - Fixes the silent omission of a ticketed commit written as `type(scope):` or with a capitalized type such as `FEAT:`, which counted toward the version bump but reached no changelog.
18
+ - Documents that a scaffolded `.config/git-cliff.toml` may vary its enumeration keys alone: a `commit_parsers` entry that skips or narrows drops the commit before classification, with no error.
19
19
 
20
- - Give nmr plain output in pipes and CI logs (#838)
20
+ - Build changelog items from a merge commit's change-record block (#882)
21
21
 
22
- - Stops `nmr` from printing emoji to a pipe or a CI log: When the output stream is not a terminal or `CI` is set, a verdict reads `PASS`, `FAIL`, `SKIP`, or `NOOP` and a command icon is omitted, so that a log can be searched for a verdict.
23
- - Adds `--output-style <auto|plain|rich>` to `nmr` and the `NMR_OUTPUT_STYLE` variable, each forcing either style; the flag outranks the variable, a value that names no style exits 1 with a usage error, and neither enters a check-cache key: A rich run and a plain run share a recorded pass.
24
- - Replaces several rich glyphs, taking the status markers from the set that release-kit and v11y-check print so that one status has one glyph across the three tools: a recalled pass shows ⏩ in place of ⏭️, a skipped empty override shows ⚪ in place of ⛔, a warning and the `--log` refusal show 🟠 in place of ⚠️ and 📭, the `--log` header shows 💾 in place of 📼, and `nmr-ensure-prepublish-hooks` reports ✅ and ❌ in place of ✓ and ✗.
22
+ Builds `release-kit` changelog items from a commit's `change-record` block, the fenced YAML block at the end of a squash-merge commit that lists the change's outcomes, so that a merge with several outcomes of different types yields one item per outcome, each under its own type's section. Makes `release-kit prepare` warn about a block that cannot be read, an entry whose type is undeclared, and an entry that violates its type's breaking policy. Keeps reading a commit with no usable block from its title, as before.
25
23
 
26
- ### 🐛 Bug fixes
24
+ - 🚨 **Breaking:** Derive the version bump from the changelog items (#885)
27
25
 
28
- - Move work-types check and sync from the CLI into maintainer scripts (#820)
26
+ Derives the version bump in every `release-kit prepare` path (single-package, project, and monorepo) from the changelog items of the unreleased commits, so that the bump and the changelog describe the same release. A commit that yields no changelog item no longer bumps, and a `BREAKING CHANGE:` footer no longer raises a major bump. Single-package mode now follows the monorepo rules for `--bump` and `--force`, and the `prepare` report shows the diagnostics of a skipped target.
29
27
 
30
- - Removes the `release-kit work-types` command, whose `sync` rewrote an unused copy of `work-types.json` inside `node_modules` and whose `check` reported drift that a consumer could not fix.
28
+ Migration: Mark a breaking change with a `!` on the commit subject or with `breaking: true` on its change-record entry, because a `BREAKING CHANGE:` footer alone now gets the bump of the commit's type. Give each commit that should bump a ticket-ID prefix and a type that the changelog does not exclude. In single-package mode, add `--force` to a release that used `--bump=X` alone, or that relied on the patch floor, when no commit yields a changelog item; without it, `prepare` skips the release.
31
29
 
32
- - Exclude distributed agent guidance from ai and documentation labels (#825)
30
+ - 🚨 **Breaking:** Key an editorial override to one of several items on a commit (#886)
33
31
 
34
- - Marks a `.github/labels.yaml` generated from the previous `common` preset as stale in the default readyup kit, whose "labels.yaml has current common preset" check reports the file until the repo regenerates it.
32
+ Adds the `<hash>:<n>` key to `.meta/changelog-overrides.json`. It targets one of the several changelog items that a commit's change-record block yields, while a bare `<hash>` key still targets all of them. Also makes `release-kit prepare` and `release-kit overrides validate` fail when override keys conflict on an item, and publishes a JSON Schema for the override file.
35
33
 
36
- - Suppress bold and dim escapes for a stream that cannot render them (#830)
34
+ Migration: Replace a bare key that sets `description` or `body` on a commit with several items with one `<hash>:<n>` key per item, as listed by the error message. Where two keys match the same item, such as `abc1234` beside `abc1234:2`, remove one of them. This includes a root-file key that overlaps a workspace-file key, which now fails even though the two files are separate. In each scope passed to `validateAllChangelogOverrides`, rename `hashes` to `items` and pass `OverrideTargetItem` objects (`{ hash, entry? }`) instead of hash strings.
37
35
 
38
- - Stops `release-kit prepare` from writing raw escape bytes into piped output, redirected files, and CI logs: It styled bold and dim unconditionally, without checking whether the destination renders escapes.
39
- - Honors `NO_COLOR`, `NODE_DISABLE_COLORS`, and `FORCE_COLOR`, which the previous styling ignored.
36
+ ### 🪦 Removed
37
+
38
+ - 🚨 **Breaking:** Build changelogs from release-kit's own enumeration and remove git-cliff (#880)
39
+
40
+ Removes git-cliff from `@williamthorsen/release-kit`: `prepare` now builds every changelog from the same commit history that decides each version bump, and no longer fetches a git-cliff binary through `npx`. A config that still sets `cliffConfigPath` now fails validation. Two ways in which the changelog and the bump read different commits are gone, affecting single-package repositories with a tag prefix other than `v` and `paths` entries that name a bare directory.
41
+
42
+ Migration: Remove `cliffConfigPath` from `.config/release-kit.config.ts`, and delete `.config/git-cliff.toml` or `cliff.toml` if the repository has one. Any customization in that file, such as `tag_pattern` or its tag-skipping keys, no longer has an effect: `release-kit` now splits the changelog on the configured tag prefixes alone.
40
43
  <!-- /section:release-notes -->
41
44
 
42
45
  ## Installation
@@ -69,7 +72,7 @@ Example output from `prepare --dry-run` in a monorepo whose `arrays` workspace h
69
72
  📦 1.2.0 → 1.3.0 (minor)
70
73
  [dry-run] Would bump packages/arrays/package.json
71
74
  Generating changelogs...
72
- [dry-run] Would run: npx --prefer-offline --yes git-cliff@<version> ... --output packages/arrays/CHANGELOG.md
75
+ [dry-run] Would generate changelog: packages/arrays/CHANGELOG.md
73
76
  🔖 arrays-v1.3.0
74
77
 
75
78
  ✅ Release preparation complete.
@@ -85,17 +88,17 @@ gh workflow run release.yaml # every workspace with release-wor
85
88
  gh workflow run release.yaml -f only=arrays # the named workspaces alone
86
89
  ```
87
90
 
88
- The CLI applies defaults to every discovered workspace and uses the bundled `cliff.toml.template` unless the repository provides a git-cliff config of its own. [Releasing](docs/releasing.md) covers `prepare`'s flags, release-notes previews, and the workflow's inputs.
91
+ The CLI applies defaults to every discovered workspace. [Releasing](docs/releasing.md) covers `prepare`'s flags, release-notes previews, and the workflow's inputs.
89
92
 
90
93
  ## How it works
91
94
 
92
- 1. **Workspace discovery**: reads `pnpm-workspace.yaml` and resolves its `packages` globs to find workspace directories. Each directory containing a `package.json` becomes a workspace. If no workspace file is found, the repo is treated as a single-package project.
93
- 2. **Config loading**: loads `.config/release-kit.config.ts` (if present) and merges it with discovered defaults.
94
- 3. **Commit analysis**: for each workspace, finds commits since the last version tag, parses them for type and scope, and determines the appropriate version bump.
95
- 4. **Version bump + changelog**: bumps `package.json` versions, builds structured `ChangelogEntry[]` from `git-cliff --context`, applies any [editorial overrides](docs/editorial-overrides.md) from per-scope `.meta/changelog-overrides.json` files, and renders both `CHANGELOG.md` and `.meta/changelog.json` from that single source. `git-cliff` is invoked only for its `--context` JSON; markdown rendering happens in-process so `.meta/changelog.json` and `CHANGELOG.md` always agree.
95
+ 1. **Workspace discovery**: reads `pnpm-workspace.yaml` and resolves its `packages` patterns to find workspace directories, applying pnpm's semantics — a `!`-prefixed entry excludes what it matches, wherever it appears in the list. Each directory containing a `package.json` becomes a workspace. The repo is treated as a single-package project when it holds no workspace file, and when the workspace file declares no `packages` list — a file kept for `catalog:` or `overrides:` alone, which pnpm likewise resolves to the root package. A workspace file that declares patterns resolving to no package is an error naming the condition that emptied it.
96
+ 2. **Config loading**: loads `.config/release-kit.config.ts` (if present), or the file named by `--config`, and merges it with discovered defaults.
97
+ 3. **Commit analysis**: for each workspace, reads the history once, builds the changelog items of the commits since the last version tag, and takes the bump as the highest level that those items call for.
98
+ 4. **Version bump + changelog**: bumps `package.json` versions, builds structured `ChangelogEntry[]` from the commits between each pair of release tags, applies any [editorial overrides](docs/editorial-overrides.md) from per-scope `.meta/changelog-overrides.json` files, and renders both `CHANGELOG.md` and `.meta/changelog.json` from that single source, so the two always agree.
96
99
  5. **Release tags file**: writes computed tags to `tmp/.release-tags` for the release workflow to read when tagging and pushing.
97
100
 
98
- [Changelogs](docs/changelogs.md) covers what reaches a published tarball, the `changelog.json` item schema, and the git-cliff config.
101
+ [Changelogs](docs/changelogs.md) covers what reaches a published tarball, the `changelog.json` item schema, and which commits reach a changelog.
99
102
 
100
103
  ## Commit format
101
104
 
@@ -118,6 +121,8 @@ The `scope|type:` format scopes a commit to a specific workspace in a monorepo.
118
121
 
119
122
  Configuration is optional. The CLI works out of the box by auto-discovering workspaces and applying defaults. Create `.config/release-kit.config.ts` only when you need to customize behavior.
120
123
 
124
+ Every subcommand that reads a config accepts `--config <path>` to read a file elsewhere. An absent default path means "no config"; an absent `--config` path fails the command. See [Config file location](docs/configuration.md#config-file-location).
125
+
121
126
  ```typescript
122
127
  import { defineConfig } from '@williamthorsen/release-kit/config';
123
128
 
@@ -144,10 +149,7 @@ Node loads the file directly, so a relative import inside it needs an explicit f
144
149
 
145
150
  ## External dependencies
146
151
 
147
- This package shells out to two external tools:
148
-
149
- - **`git`** — must be available on `PATH`. Used to find tags and retrieve commit history.
150
- - **`git-cliff`** — pinned to an exact version and fetched via `npx` on first invocation, then served from npx's cache. No need to install it as a dev dependency. The pin moves only when a new release-kit version names a newer git-cliff, so two releases cut months apart run the same changelog generator.
152
+ release-kit shells out to `git`, which must be available on `PATH`, to find tags and read commit history.
151
153
 
152
154
  ## Readiness checks
153
155
 
@@ -179,15 +181,13 @@ rdy run --packages
179
181
  5. Remove `changeset:*` scripts from `package.json` (no replacement needed — the CLI handles everything).
180
182
  6. Create an initial version tag for each package (e.g., `git tag v1.0.0` or `git tag arrays-v1.0.0`).
181
183
 
182
- No cliff config copy is needed — the bundled template is used automatically. To customize, run `release-kit init --with-config`.
183
-
184
184
  ## Documentation
185
185
 
186
186
  - [Configuration](docs/configuration.md): `ReleaseKitConfig` fields, workspace overrides and legacy identities, retired packages, tag prefixes, and version patterns
187
187
  - [Project releases](docs/project-releases.md): the `project` block, and how a project release interacts with `prepare`'s flags
188
188
  - [Releasing](docs/releasing.md): `init`, `prepare`'s flags and release-notes previews, and the release workflow
189
189
  - [Publishing](docs/publishing.md): `publish`, the publishability filter, and `create-github-release`
190
- - [Changelogs](docs/changelogs.md): the `changelog.json` item schema, the git-cliff config, and release-notes injection
190
+ - [Changelogs](docs/changelogs.md): the `changelog.json` item schema, which commits reach a changelog, and release-notes injection
191
191
  - [Editorial overrides](docs/editorial-overrides.md): correcting generated changelog entries, and `overrides validate`
192
192
  - [Work types and tiers](docs/work-types.md): tiers, the `!` policy, markers, custom work types, and maintenance of the bundled taxonomy
193
193
  - [Labels](docs/labels.md): `sync-labels`, label configuration, the workflow's triggers, and the `label-map.json` schema
@@ -0,0 +1,4 @@
1
+ import type { ChangelogDiagnostics } from './buildChangelogEntries.js';
2
+ import type { ReleasedWorkspaceResult } from './types.js';
3
+ /** Attaches a history's diagnostics to a released or skipped result, omitting each empty list. */
4
+ export declare function attachChangelogDiagnostics(result: Pick<ReleasedWorkspaceResult, 'malformedBlocks' | 'policyViolations' | 'undeclaredEntryTypes'>, diagnostics: ChangelogDiagnostics): void;
@@ -0,0 +1,11 @@
1
+ export function attachChangelogDiagnostics(result, diagnostics) {
2
+ if (diagnostics.malformedBlocks.length > 0) {
3
+ result.malformedBlocks = diagnostics.malformedBlocks;
4
+ }
5
+ if (diagnostics.undeclaredEntryTypes.length > 0) {
6
+ result.undeclaredEntryTypes = diagnostics.undeclaredEntryTypes;
7
+ }
8
+ if (diagnostics.policyViolations.length > 0) {
9
+ result.policyViolations = diagnostics.policyViolations;
10
+ }
11
+ }