@varlock/bumpy 1.2.1 → 1.2.2

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 (34) hide show
  1. package/README.md +49 -34
  2. package/dist/{add-DF6bawDT.mjs → add-DEqGa5gI.mjs} +8 -8
  3. package/dist/apply-release-plan-Bi9OSWks.mjs +57 -0
  4. package/dist/{bump-file-C3S_bzSf.mjs → bump-file-BTsntOO-.mjs} +6 -9
  5. package/dist/{changelog-github-DZSHX3Tb.mjs → changelog-github-CEaDCtTk.mjs} +30 -14
  6. package/dist/changelog-xKuL0IKx.mjs +109 -0
  7. package/dist/{check-BJL-YDWz.mjs → check-D3eXRyKJ.mjs} +7 -7
  8. package/dist/{ci-C88ecvIP.mjs → ci-BVTwTUUK.mjs} +49 -28
  9. package/dist/{ci-setup-CARJFhcE.mjs → ci-setup-D1NCzbNH.mjs} +3 -3
  10. package/dist/cli.mjs +14 -14
  11. package/dist/{config-D7Umr-fT.mjs → config-CJIj8xG3.mjs} +2 -80
  12. package/dist/{generate-D93b3NAD.mjs → generate-wHN6Ll6p.mjs} +6 -6
  13. package/dist/{git-H9S9z6g-.mjs → git-D0__HP86.mjs} +1 -1
  14. package/dist/index.d.mts +1 -1
  15. package/dist/index.mjs +10 -8
  16. package/dist/{init-DJhMaceS.mjs → init-DND7zRGD.mjs} +3 -3
  17. package/dist/{publish-DGSV607z.mjs → publish-BwidFqbo.mjs} +9 -9
  18. package/dist/{publish-pipeline-DiwZZ5AF.mjs → publish-pipeline-BvLIu7WF.mjs} +4 -4
  19. package/dist/{release-plan-CNOuSI-d.mjs → release-plan-21H89Cx1.mjs} +3 -2
  20. package/dist/{status-S2ztf_8E.mjs → status-CDGxgXWd.mjs} +7 -7
  21. package/dist/types-CSM0c2-m.mjs +80 -0
  22. package/dist/{version-BXrP4TIO.mjs → version-ClkaCNTE.mjs} +9 -9
  23. package/dist/{workspace-BHsAPUmC.mjs → workspace-c9-TqXed.mjs} +2 -2
  24. package/package.json +1 -1
  25. package/dist/apply-release-plan-B1Wwx3HG.mjs +0 -146
  26. /package/dist/{ai-STKnq09z.mjs → ai-C66IfTzs.mjs} +0 -0
  27. /package/dist/{clack-C6bVkGxf.mjs → clack-CJT1JFFa.mjs} +0 -0
  28. /package/dist/{commit-message-BwsowSds.mjs → commit-message-DOIfDxfj.mjs} +0 -0
  29. /package/dist/{dep-graph-DiLeAhl9.mjs → dep-graph-E-9-eQ2J.mjs} +0 -0
  30. /package/dist/{names-C-TuOPbd.mjs → names-CBy7d8K_.mjs} +0 -0
  31. /package/dist/{package-manager-ByJ0wKYh.mjs → package-manager-CClZtIHP.mjs} +0 -0
  32. /package/dist/{picomatch-DMmqYjgq.mjs → picomatch-TGJi--_I.mjs} +0 -0
  33. /package/dist/{semver-BJzWIuRz.mjs → semver-DfQyVLM_.mjs} +0 -0
  34. /package/dist/{shell-CY7OD48z.mjs → shell-u3bYGxNy.mjs} +0 -0
package/README.md CHANGED
@@ -3,29 +3,30 @@
3
3
  <img src="https://raw.githubusercontent.com/dmno-dev/bumpy/refs/heads/main/images/github-readme-banner.png" alt="Bumpy banner">
4
4
  </a>
5
5
  </p>
6
- <br/>
7
6
  <p align="center">
8
7
  <a href="https://npmjs.com/package/@varlock/bumpy"><img src="https://img.shields.io/npm/v/@varlock/bumpy.svg" alt="npm package"></a>
9
8
  <a href="https://github.com/dmno-dev/bumpy/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@varlock/bumpy.svg" alt="license"></a>
10
9
  <a href="https://github.com/dmno-dev/bumpy/actions/workflows/ci.yaml"><img src="https://img.shields.io/github/actions/workflow/status/dmno-dev/bumpy/ci.yaml?style=flat&logo=github&label=CI" alt="build status"></a>
11
10
  <a href="https://chat.dmno.dev"><img src="https://img.shields.io/badge/chat-discord-5865F2?style=flat&logo=discord" alt="discord chat"></a>
12
11
  </p>
12
+
13
+ <p align="center">Brought to you by <a href="https://varlock.dev">Varlock</a> 🧙‍♂️🔐 <a href="https://varlock.dev">check it out to secure your secrets</a></p>
13
14
  <br/>
14
15
 
15
16
  # @varlock/bumpy 🐸
16
17
 
17
- A modern package versioning and changelog generation tool built for monorepos (works great in single packages too).
18
+ A modern package versioning, release, and changelog generation tool. Built for monorepos, but works great in simpler projects too.
18
19
 
19
20
  ## How It Works
20
21
 
21
- Bumpy uses **bump files** (you may know them as "changesets" if coming from [that tool 🦋](https://github.com/changesets/changesets)) small markdown files that declare an intent to release packages with a bump level (patch/minor/major), and a description that ends up in changelogs. Developers create these files as part of their PRs, and these files are then used to consolidate changes, generate changelogs, and trigger publishing. Specifically:
22
+ Bumpy uses **bump files** (you may know them as "changesets" if coming from [that tool 🦋](https://github.com/changesets/changesets)) - small markdown files that declare an intent to release packages with a bump level (patch/minor/major), and a description that ends up in changelogs. Developers create these files as part of their PRs, and these files are then used to consolidate changes, generate changelogs, and trigger publishing. Specifically:
22
23
 
23
24
  - Devs/agents create bump files as part of their PRs (using `bumpy add` or manually)
24
25
  - A pre-push git hook can enforce bump files exist for changed packages
25
26
  - In CI, a workflow checks PRs for bump files, leaves a comment on the PR detailing changed packages
26
27
  - As PRs merge to the base branch, a "release PR" is kept up to date
27
28
  - Shows what packages will be released and their changelogs
28
- Including packages bumped automatically due to dependency relationships
29
+ - Including packages bumped automatically due to dependency relationships
29
30
  - When release PR is merged, publishing is triggered
30
31
  - Oending bump files are deleted and packages are published with updated versions and changelogs
31
32
 
@@ -47,15 +48,15 @@ Fixed locale fallback logic in utils.
47
48
 
48
49
  ## Features
49
50
 
50
- - **All package managers** npm, pnpm, yarn, and bun workspaces
51
- - **Smart dependency propagation** configurable rules for how version bumps cascade through your dependency graph (see [version propagation docs](https://github.com/dmno-dev/bumpy/blob/main/docs/version-propagation.md))
52
- - **Pack-then-publish** by default, publishes to npm (resolving `workspace:` and `catalog:` protocols, with OIDC/provenance support). Per-package custom publish commands let you target anything VSCode extensions, Docker images, JSR, private registries, etc.
53
- - **Flexible package management** include/exclude any package individually via per-package config, glob patterns, or `privatePackages` setting
54
- - **Non-interactive CLI** `bumpy add` works fully non-interactively for CI/CD and AI-assisted development
55
- - **Aggregated GitHub releases** optionally create a single consolidated release instead of one per package
56
- - **Auto-generate from commits** `bumpy generate` creates bump files from branch commits works with any commit style, with enhanced detection for conventional commits
57
- - **Pluggable changelog formatters** built-in `"default"` and `"github"` formatters, or write your own
58
- - **Zero runtime dependencies** dependencies are minimal and bundled at release time
51
+ - **All package managers** - npm, pnpm, yarn, and bun workspaces
52
+ - **Smart dependency propagation** - configurable rules for how version bumps cascade through your dependency graph (see [version propagation docs](https://github.com/dmno-dev/bumpy/blob/main/docs/version-propagation.md))
53
+ - **Pack-then-publish** - by default, publishes to npm (resolving `workspace:` and `catalog:` protocols, with OIDC/provenance support). Per-package custom publish commands let you target anything - VSCode extensions, Docker images, JSR, private registries, etc.
54
+ - **Flexible package management** - include/exclude any package individually via per-package config, glob patterns, or `privatePackages` setting
55
+ - **Non-interactive CLI** - `bumpy add` works fully non-interactively for CI/CD and AI-assisted development
56
+ - **Aggregated GitHub releases** - optionally create a single consolidated release instead of one per package
57
+ - **Auto-generate from commits** - `bumpy generate` creates bump files from branch commits - works with any commit style, with enhanced detection for conventional commits
58
+ - **Pluggable changelog formatters** - built-in `"default"` and `"github"` formatters, or write your own
59
+ - **Zero runtime dependencies** - dependencies are minimal and bundled at release time
59
60
 
60
61
  ## Getting Started
61
62
 
@@ -77,10 +78,10 @@ Then set up CI to automate versioning and publishing (see below).
77
78
 
78
79
  ## CI / GitHub Actions
79
80
 
80
- No GitHub App to install, no separate action to rely on just call `bumpy ci` directly in your workflows. Two commands handle the entire release lifecycle:
81
+ No GitHub App to install, no separate action to rely on - just call `bumpy ci` directly in your workflows. Two commands handle the entire release lifecycle:
81
82
 
82
- - **`bumpy ci check`** runs on every PR. Computes the release plan from pending bump files and posts/updates a comment on the PR showing what versions would be released. Warns if any changed packages are missing bump files.
83
- - **`bumpy ci release`** runs on push to main. If pending bump files exist, it opens (or updates) a "Version Packages" PR that applies all version bumps and changelog updates. If the current push _is_ the Version Packages PR being merged, it publishes the new versions, creates git tags, and creates GitHub releases.
83
+ - **`bumpy ci check`** - runs on every PR. Computes the release plan from pending bump files and posts/updates a comment on the PR showing what versions would be released. Warns if any changed packages are missing bump files.
84
+ - **`bumpy ci release`** - runs on push to main. If pending bump files exist, it opens (or updates) a "Version Packages" PR that applies all version bumps and changelog updates. If the current push _is_ the Version Packages PR being merged, it publishes the new versions, creates git tags, and creates GitHub releases.
84
85
 
85
86
  _examples use bun, but works with Node.js_
86
87
 
@@ -109,7 +110,7 @@ jobs:
109
110
  ### Release workflow
110
111
 
111
112
  ```yaml
112
- # .github/workflows/bumpy-release.yml trusted publishing (OIDC, no secret needed)
113
+ # .github/workflows/bumpy-release.yml - trusted publishing (OIDC, no secret needed)
113
114
  name: Bumpy Release
114
115
  on:
115
116
  push:
@@ -137,13 +138,13 @@ jobs:
137
138
  BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # additonal PAT, needed to trigger CI checks on release PR
138
139
  ```
139
140
 
140
- > **Trusted publishing setup:** Configure each package on [npmjs.com](https://docs.npmjs.com/trusted-publishers/) → Package Settings → Trusted Publishers → GitHub Actions. Specify your org/user, repo, and the workflow filename (`bumpy-release.yml`). No `NPM_TOKEN` secret needed. Requires npm >= 11.5.1 bumpy will warn if your version is too old.
141
+ > **Trusted publishing setup:** Configure each package on [npmjs.com](https://docs.npmjs.com/trusted-publishers/) → Package Settings → Trusted Publishers → GitHub Actions. Specify your org/user, repo, and the workflow filename (`bumpy-release.yml`). No `NPM_TOKEN` secret needed. Requires npm >= 11.5.1 - bumpy will warn if your version is too old.
141
142
 
142
143
  <details>
143
144
  <summary>Alternative: token-based auth (NPM_TOKEN secret)</summary>
144
145
 
145
146
  ```yaml
146
- # .github/workflows/bumpy-release.yml token-based auth
147
+ # .github/workflows/bumpy-release.yml - token-based auth
147
148
  name: Bumpy Release
148
149
  on:
149
150
  push:
@@ -174,7 +175,7 @@ You can also use `bumpy ci release --auto-publish` to version + publish directly
174
175
 
175
176
  ### Token setup
176
177
 
177
- The default `github.token` works for basic functionality, but GitHub's anti-recursion guard means PRs created by the default token won't trigger other workflows so your regular CI (tests, linting, etc.) won't run automatically on the Version Packages PR. To fix this, provide a `BUMPY_GH_TOKEN` secret using either a **fine-grained PAT** or a **GitHub App token**. See the [full token setup guide](https://github.com/dmno-dev/bumpy/blob/main/docs/github-actions.md#token-setup) for details.
178
+ The default `github.token` works for basic functionality, but GitHub's anti-recursion guard means PRs created by the default token won't trigger other workflows - so your regular CI (tests, linting, etc.) won't run automatically on the Version Packages PR. To fix this, provide a `BUMPY_GH_TOKEN` secret using either a **fine-grained PAT** or a **GitHub App token**. See the [full token setup guide](https://github.com/dmno-dev/bumpy/blob/main/docs/github-actions.md#token-setup) for details.
178
179
 
179
180
  Run `bumpy ci setup` for interactive guidance, or set it up manually:
180
181
 
@@ -210,30 +211,30 @@ bumpy ai setup --target cursor # creates Cursor rule file
210
211
  bumpy ai setup --target codex # creates Codex instruction file
211
212
  ```
212
213
 
213
- The skill teaches the AI to examine git changes, identify affected packages, choose bump levels, and create bump files with `bumpy add`. It also instructs the AI to keep existing bump files up to date as work continues on a branch updating packages, bump levels, and summaries to reflect the final state of changes.
214
+ The skill teaches the AI to examine git changes, identify affected packages, choose bump levels, and create bump files with `bumpy add`. It also instructs the AI to keep existing bump files up to date as work continues on a branch - updating packages, bump levels, and summaries to reflect the final state of changes.
214
215
 
215
216
  ## Documentation
216
217
 
217
- - [Bump file format](https://github.com/dmno-dev/bumpy/blob/main/docs/bump-files.md) syntax, bump levels, cascade control
218
- - [Configuration reference](https://github.com/dmno-dev/bumpy/blob/main/docs/configuration.md) all `.bumpy/_config.json` and per-package options
219
- - [CLI reference](https://github.com/dmno-dev/bumpy/blob/main/docs/cli.md) every command with flags and examples
220
- - [GitHub Actions setup](https://github.com/dmno-dev/bumpy/blob/main/docs/github-actions.md) CI workflows, token setup, trusted publishing
221
- - [Version propagation](https://github.com/dmno-dev/bumpy/blob/main/docs/version-propagation.md) how dependency bumps cascade through your graph
218
+ - [Bump file format](https://github.com/dmno-dev/bumpy/blob/main/docs/bump-files.md) - syntax, bump levels, cascade control
219
+ - [Configuration reference](https://github.com/dmno-dev/bumpy/blob/main/docs/configuration.md) - all `.bumpy/_config.json` and per-package options
220
+ - [CLI reference](https://github.com/dmno-dev/bumpy/blob/main/docs/cli.md) - every command with flags and examples
221
+ - [GitHub Actions setup](https://github.com/dmno-dev/bumpy/blob/main/docs/github-actions.md) - CI workflows, token setup, trusted publishing
222
+ - [Version propagation](https://github.com/dmno-dev/bumpy/blob/main/docs/version-propagation.md) - how dependency bumps cascade through your graph
222
223
 
223
224
  ## Why files instead of conventional commits?
224
225
 
225
- Tools like semantic-release infer version bumps from commit messages (`feat:` → minor, `fix:` → patch). This works for simple projects but breaks down in monorepos a single PR often touches multiple packages with different bump levels, squash merges lose per-commit metadata, and commit messages are a poor place to write user-facing changelog entries. Bump files are explicit, reviewable in the PR diff, and can describe changes in language meant for consumers rather than developers. If you prefer commit-based workflows, `bumpy generate` can bridge the gap by auto-creating bump files from your branch commits it works with any commit style, not just conventional commits.
226
+ Tools like semantic-release infer version bumps from commit messages (`feat:` → minor, `fix:` → patch). This works for simple projects but breaks down in monorepos - a single PR often touches multiple packages with different bump levels, squash merges lose per-commit metadata, and commit messages are a poor place to write user-facing changelog entries. Bump files are explicit, reviewable in the PR diff, and can describe changes in language meant for consumers rather than developers. If you prefer commit-based workflows, `bumpy generate` can bridge the gap by auto-creating bump files from your branch commits - it works with any commit style, not just conventional commits.
226
227
 
227
228
  ## Why not just use changesets?
228
229
 
229
- Bumpy is built as a successor to [@changesets/changesets](https://github.com/changesets/changesets). Changesets is mature and widely adopted, but has stagnated hundreds of open issues around core design problems that are unlikely to be fixed without a rewrite. See [differences from changesets](https://github.com/dmno-dev/bumpy/blob/main/docs/differences-from-changesets.md) for a detailed comparison with links to specific issues. The biggest pain points bumpy addresses:
230
+ Bumpy is built as a successor to [@changesets/changesets](https://github.com/changesets/changesets). Changesets is mature and widely adopted, but has stagnated - hundreds of open issues around core design problems that are unlikely to be fixed without a rewrite. See [differences from changesets](https://github.com/dmno-dev/bumpy/blob/main/docs/differences-from-changesets.md) for a detailed comparison with links to specific issues. The biggest pain points bumpy addresses:
230
231
 
231
- - **Sane dependency propagation** changesets hardcodes aggressive behavior where a minor bump triggers a major bump on all peer dependents. Bumpy uses a [three-phase algorithm](https://github.com/dmno-dev/bumpy/blob/main/docs/version-propagation.md) with sensible defaults and full configurability.
232
- - **Workspace protocol resolution** changesets uses `npm publish` even in pnpm/yarn workspaces, so `workspace:^` and `catalog:` protocols are NOT resolved, resulting in broken published packages.
233
- - **Custom publish commands** changesets is hardcoded to `npm publish`. Bumpy supports per-package custom publish for VSCode extensions, Docker images, JSR, etc.
234
- - **Flexible package management** changesets treats all private packages the same. Bumpy lets you include/exclude any package individually.
235
- - **CI without a separate action or bot** changesets requires installing a [GitHub App](https://github.com/apps/changeset-bot) _and_ using a [separate GitHub Action](https://github.com/changesets/action). Bumpy replaces both with two CLI commands (`bumpy ci check` + `bumpy ci release`) that run directly in your workflows no extra repos to trust, no app installation requiring org admin approval.
236
- - **Automatic migration** `bumpy init` detects `.changeset/`, renames it to `.bumpy/`, migrates config, keeps pending files, and offers to uninstall `@changesets/cli`.
232
+ - **Sane dependency propagation** - changesets hardcodes aggressive behavior where a minor bump triggers a major bump on all peer dependents. Bumpy uses a [three-phase algorithm](https://github.com/dmno-dev/bumpy/blob/main/docs/version-propagation.md) with sensible defaults and full configurability.
233
+ - **Workspace protocol resolution** - changesets uses `npm publish` even in pnpm/yarn workspaces, so `workspace:^` and `catalog:` protocols are NOT resolved, resulting in broken published packages.
234
+ - **Custom publish commands** - changesets is hardcoded to `npm publish`. Bumpy supports per-package custom publish for VSCode extensions, Docker images, JSR, etc.
235
+ - **Flexible package management** - changesets treats all private packages the same. Bumpy lets you include/exclude any package individually.
236
+ - **CI without a separate action or bot** - changesets requires installing a [GitHub App](https://github.com/apps/changeset-bot) _and_ using a [separate GitHub Action](https://github.com/changesets/action). Bumpy replaces both with two CLI commands (`bumpy ci check` + `bumpy ci release`) that run directly in your workflows - no extra repos to trust, no app installation requiring org admin approval.
237
+ - **Automatic migration** - `bumpy init` detects `.changeset/`, renames it to `.bumpy/`, migrates config, keeps pending files, and offers to uninstall `@changesets/cli`.
237
238
 
238
239
  ## Development
239
240
 
@@ -253,4 +254,18 @@ bunx bumpy --help # invoke built cli
253
254
  - Tracking workspace-level / non-publishable changes
254
255
  - More frogs 🐸
255
256
 
257
+ ---
258
+
259
+ <p align="center">
260
+ <a href="https://varlock.dev" target="_blank" rel="noopener noreferrer">
261
+ <img src="https://raw.githubusercontent.com/dmno-dev/bumpy/refs/heads/main/images/github-readme-footer.jpg" alt="Bumpy was created by Varlock" >
262
+ </a>
263
+ </p>
264
+ <p align="center">
265
+ <b>Bumpy is a creation of the team behind <a href="https://varlock.dev">Varlock</a> 🧙‍♂️</b><br/>
266
+ <a href="https://varlock.dev">
267
+ Check it out for secure secret sorcery - get your keys out of plaintext!
268
+ </a>
269
+ </p>
270
+
256
271
  <!-- note this readme is also used for the bumpy package! -->
@@ -1,13 +1,13 @@
1
1
  import { n as log, o as __toESM, r as require_picocolors } from "./logger-C2dEe5Su.mjs";
2
2
  import { n as exists, t as ensureDir } from "./fs-DnDogVn-.mjs";
3
- import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir, s as matchGlob } from "./config-D7Umr-fT.mjs";
4
- import { t as discoverPackages } from "./workspace-BHsAPUmC.mjs";
5
- import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
6
- import { i as writeBumpFile } from "./bump-file-C3S_bzSf.mjs";
7
- import { r as getChangedFiles } from "./git-H9S9z6g-.mjs";
8
- import { c as ot, d as yt, i as _t, l as pt, o as gt, r as Ot, s as mt, t as unwrap, u as wt } from "./clack-C6bVkGxf.mjs";
9
- import { n as slugify, t as randomName } from "./names-C-TuOPbd.mjs";
10
- import { t as require_picomatch } from "./picomatch-DMmqYjgq.mjs";
3
+ import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir, s as matchGlob } from "./config-CJIj8xG3.mjs";
4
+ import { t as discoverPackages } from "./workspace-c9-TqXed.mjs";
5
+ import { t as DependencyGraph } from "./dep-graph-E-9-eQ2J.mjs";
6
+ import { i as writeBumpFile } from "./bump-file-BTsntOO-.mjs";
7
+ import { r as getChangedFiles } from "./git-D0__HP86.mjs";
8
+ import { c as ot, d as yt, i as _t, l as pt, o as gt, r as Ot, s as mt, t as unwrap, u as wt } from "./clack-CJT1JFFa.mjs";
9
+ import { n as slugify, t as randomName } from "./names-CBy7d8K_.mjs";
10
+ import { t as require_picomatch } from "./picomatch-TGJi--_I.mjs";
11
11
  import { relative, resolve } from "node:path";
12
12
  import * as readline from "node:readline";
13
13
  //#region src/prompts/bump-select.ts
@@ -0,0 +1,57 @@
1
+ import { a as readJson, c as removeFile, f as writeText, i as listFiles, l as updateJsonFields, n as exists, s as readText, u as updateJsonNestedField } from "./fs-DnDogVn-.mjs";
2
+ import { r as getBumpyDir } from "./config-CJIj8xG3.mjs";
3
+ import { a as prependToChangelog, i as loadFormatter, n as generateChangelogEntry } from "./changelog-xKuL0IKx.mjs";
4
+ import { resolve } from "node:path";
5
+ //#region src/core/apply-release-plan.ts
6
+ /** Apply the release plan: bump versions, update changelogs, delete bump files */
7
+ async function applyReleasePlan(releasePlan, packages, rootDir, config) {
8
+ const releaseMap = new Map(releasePlan.releases.map((r) => [r.name, r]));
9
+ const formatter = config.changelog !== false ? await loadFormatter(config.changelog, rootDir) : null;
10
+ for (const release of releasePlan.releases) {
11
+ const pkgJsonPath = resolve(packages.get(release.name).dir, "package.json");
12
+ const pkgJson = await readJson(pkgJsonPath);
13
+ await updateJsonFields(pkgJsonPath, { version: release.newVersion });
14
+ for (const depField of [
15
+ "dependencies",
16
+ "devDependencies",
17
+ "peerDependencies",
18
+ "optionalDependencies"
19
+ ]) {
20
+ const deps = pkgJson[depField];
21
+ if (!deps) continue;
22
+ for (const [depName, range] of Object.entries(deps)) {
23
+ const depRelease = releaseMap.get(depName);
24
+ if (!depRelease) continue;
25
+ await updateJsonNestedField(pkgJsonPath, depField, depName, updateRange(range, depRelease.newVersion));
26
+ }
27
+ }
28
+ }
29
+ if (formatter) for (const release of releasePlan.releases) {
30
+ const changelogPath = resolve(packages.get(release.name).dir, "CHANGELOG.md");
31
+ const entry = await generateChangelogEntry(release, releasePlan.bumpFiles, formatter);
32
+ let existingContent = "";
33
+ if (await exists(changelogPath)) existingContent = await readText(changelogPath);
34
+ await writeText(changelogPath, prependToChangelog(existingContent, entry));
35
+ }
36
+ const bumpyDir = getBumpyDir(rootDir);
37
+ const allBumpFiles = await listFiles(bumpyDir, ".md");
38
+ for (const file of allBumpFiles) {
39
+ if (file === "README.md") continue;
40
+ await removeFile(resolve(bumpyDir, file));
41
+ }
42
+ }
43
+ /** Update a version range to include a new version, preserving the range prefix */
44
+ function updateRange(range, newVersion) {
45
+ let protocol = "";
46
+ let cleanRange = range;
47
+ const protoMatch = range.match(/^(workspace:|catalog:)/);
48
+ if (protoMatch) {
49
+ protocol = protoMatch[1];
50
+ cleanRange = range.slice(protocol.length);
51
+ }
52
+ const prefix = cleanRange.match(/^(\^|~|>=|>|<=|<|=)?/)?.[1] ?? "^";
53
+ if (cleanRange === "*" || cleanRange === "" || cleanRange === "^" || cleanRange === "~") return range;
54
+ return `${protocol}${prefix}${newVersion}`;
55
+ }
56
+ //#endregion
57
+ export { applyReleasePlan as t };
@@ -1,7 +1,7 @@
1
1
  import { f as writeText, i as listFiles, s as readText } from "./fs-DnDogVn-.mjs";
2
- import { r as getBumpyDir } from "./config-D7Umr-fT.mjs";
3
- import { i as jsYaml } from "./package-manager-ByJ0wKYh.mjs";
4
- import { s as tryRunArgs } from "./shell-CY7OD48z.mjs";
2
+ import { r as getBumpyDir } from "./config-CJIj8xG3.mjs";
3
+ import { i as jsYaml } from "./package-manager-CClZtIHP.mjs";
4
+ import { s as tryRunArgs } from "./shell-u3bYGxNy.mjs";
5
5
  import { resolve } from "node:path";
6
6
  import { existsSync } from "node:fs";
7
7
  //#region src/core/bump-file.ts
@@ -190,21 +190,18 @@ function extractBumpFileIdsFromChangedFiles(changedFiles) {
190
190
  function filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir, parseErrors = []) {
191
191
  const branchBumpFileIds = extractBumpFileIdsFromChangedFiles(changedFiles);
192
192
  const branchBumpFiles = allBumpFiles.filter((bf) => branchBumpFileIds.has(bf.id));
193
- let hasEmptyBumpFile = false;
193
+ const emptyBumpFileIds = [];
194
194
  if (rootDir) {
195
195
  const parsedIds = new Set(branchBumpFiles.map((bf) => bf.id));
196
196
  const bumpyDir = getBumpyDir(rootDir);
197
197
  for (const id of branchBumpFileIds) if (!parsedIds.has(id) && existsSync(resolve(bumpyDir, `${id}.md`))) {
198
- if (!parseErrors.some((e) => e.includes(`"${id}"`))) {
199
- hasEmptyBumpFile = true;
200
- break;
201
- }
198
+ if (!parseErrors.some((e) => e.includes(`"${id}"`))) emptyBumpFileIds.push(id);
202
199
  }
203
200
  }
204
201
  return {
205
202
  branchBumpFiles,
206
203
  branchBumpFileIds,
207
- hasEmptyBumpFile
204
+ emptyBumpFileIds
208
205
  };
209
206
  }
210
207
  //#endregion
@@ -1,4 +1,5 @@
1
- import { s as tryRunArgs } from "./shell-CY7OD48z.mjs";
1
+ import { s as tryRunArgs } from "./shell-u3bYGxNy.mjs";
2
+ import { o as sortBumpFilesByType, r as getBumpTypeForPackage } from "./changelog-xKuL0IKx.mjs";
2
3
  //#region src/core/changelog-github.ts
3
4
  /** Authors filtered from "Thanks" attribution by default (e.g. bots) */
4
5
  /** Authors filtered from "Thanks" attribution by default (e.g. AI/automation bots) */
@@ -34,21 +35,32 @@ function createGithubFormatter(options = {}) {
34
35
  const serverUrl = process.env.GITHUB_SERVER_URL || "https://github.com";
35
36
  const lines = [];
36
37
  lines.push(`## ${release.newVersion}`);
37
- lines.push("");
38
- lines.push(`_${date}_`);
38
+ lines.push(`<sub>${date}</sub>`);
39
39
  lines.push("");
40
40
  const relevantBumpFiles = bumpFiles.filter((bf) => release.bumpFiles.includes(bf.id));
41
- if (relevantBumpFiles.length > 0) for (const bf of relevantBumpFiles) {
41
+ const sorted = sortBumpFilesByType(relevantBumpFiles, release.name);
42
+ for (const bf of sorted) {
42
43
  if (!bf.summary) continue;
44
+ const type = getBumpTypeForPackage(bf, release.name);
45
+ const tag = type !== release.type ? ` *(${type})*` : "";
43
46
  const { cleanSummary, overrides } = extractSummaryMeta(bf.summary);
44
47
  const gitInfo = resolveBumpFileInfo(bf.id, repoSlug, serverUrl, overrides);
45
48
  const summaryLines = cleanSummary.split("\n");
46
49
  const firstLine = linkifyIssueRefs(summaryLines[0], serverUrl, repoSlug);
47
- const prefix = formatPrefix(gitInfo, serverUrl, repoSlug, includeCommitLink, thankContributors, internalAuthorsSet);
48
- lines.push(`-${prefix ? ` ${prefix} -` : ""} ${firstLine}`);
50
+ const { links, thanks } = formatPrefix(gitInfo, serverUrl, repoSlug, includeCommitLink, thankContributors, internalAuthorsSet);
51
+ const parts = [
52
+ links,
53
+ tag,
54
+ thanks
55
+ ].filter(Boolean);
56
+ const hasMeta = parts.length > 0;
57
+ lines.push(`- ${parts.join(" ")}${hasMeta ? " - " : ""}${firstLine}`);
49
58
  for (let i = 1; i < summaryLines.length; i++) if (summaryLines[i].trim()) lines.push(` ${linkifyIssueRefs(summaryLines[i], serverUrl, repoSlug)}`);
50
59
  }
51
- if (release.isDependencyBump && relevantBumpFiles.length === 0) lines.push("- Updated dependencies");
60
+ if (release.isDependencyBump) {
61
+ const depTag = release.type !== "patch" ? ` *(patch)* -` : "";
62
+ lines.push(`-${depTag} Updated dependencies`);
63
+ }
52
64
  if (release.isCascadeBump && !release.isDependencyBump && relevantBumpFiles.length === 0) lines.push("- Version bump via cascade rule");
53
65
  lines.push("");
54
66
  return lines.join("\n");
@@ -169,18 +181,22 @@ function findBumpFileCommitInfo(bumpFileId, repo) {
169
181
  }
170
182
  }
171
183
  /**
172
- * Build the prefix portion of a changelog line: PR link, commit link, thanks.
173
- * Matches the format used by @changesets/changelog-github.
184
+ * Build the prefix portions of a changelog line, split into links and thanks
185
+ * so the bump type tag can be inserted between them.
174
186
  */
175
187
  function formatPrefix(info, serverUrl, repo, includeCommitLink, thankContributors, internalAuthors) {
176
- const parts = [];
177
- if (info.prNumber && info.prUrl) parts.push(`[#${info.prNumber}](${info.prUrl})`);
188
+ const linkParts = [];
189
+ if (info.prNumber && info.prUrl) linkParts.push(`[#${info.prNumber}](${info.prUrl})`);
178
190
  if (includeCommitLink && info.commitHash && repo) {
179
191
  const short = info.commitHash.slice(0, 7);
180
- parts.push(`[\`${short}\`](${serverUrl}/${repo}/commit/${info.commitHash})`);
192
+ linkParts.push(`[\`${short}\`](${serverUrl}/${repo}/commit/${info.commitHash})`);
181
193
  }
182
- if (thankContributors && info.author && !internalAuthors.has(info.author.toLowerCase())) parts.push(`Thanks [@${info.author}](${serverUrl}/${info.author})!`);
183
- return parts.join(" ");
194
+ let thanks = "";
195
+ if (thankContributors && info.author && !internalAuthors.has(info.author.toLowerCase())) thanks = `Thanks [@${info.author}](${serverUrl}/${info.author})!`;
196
+ return {
197
+ links: linkParts.join(" "),
198
+ thanks
199
+ };
184
200
  }
185
201
  /**
186
202
  * Linkify bare issue/PR references like #123 in text,
@@ -0,0 +1,109 @@
1
+ import { n as log } from "./logger-C2dEe5Su.mjs";
2
+ import { t as BUMP_LEVELS } from "./types-CSM0c2-m.mjs";
3
+ import { relative, resolve } from "node:path";
4
+ import { realpathSync } from "node:fs";
5
+ //#region src/core/changelog.ts
6
+ /** Get the bump type a bump file applies to a specific package */
7
+ function getBumpTypeForPackage(bf, packageName) {
8
+ const rel = bf.releases.find((r) => r.name === packageName);
9
+ return rel?.type === "none" ? "patch" : rel?.type ?? "patch";
10
+ }
11
+ /** Sort bump files by bump type for a specific package (major → minor → patch) */
12
+ function sortBumpFilesByType(bumpFiles, packageName) {
13
+ return [...bumpFiles].sort((a, b) => {
14
+ const aLevel = BUMP_LEVELS[getBumpTypeForPackage(a, packageName)];
15
+ return BUMP_LEVELS[getBumpTypeForPackage(b, packageName)] - aLevel;
16
+ });
17
+ }
18
+ /** Default formatter — version heading with date, bullet points sorted by bump type */
19
+ const defaultFormatter = (ctx) => {
20
+ const { release, bumpFiles, date } = ctx;
21
+ const lines = [];
22
+ lines.push(`## ${release.newVersion}`);
23
+ lines.push(`<sub>${date}</sub>`);
24
+ lines.push("");
25
+ const relevantBumpFiles = bumpFiles.filter((bf) => release.bumpFiles.includes(bf.id));
26
+ const sorted = sortBumpFilesByType(relevantBumpFiles, release.name);
27
+ for (const bf of sorted) {
28
+ if (!bf.summary) continue;
29
+ const type = getBumpTypeForPackage(bf, release.name);
30
+ const tag = type !== release.type ? `*(${type})* ` : "";
31
+ const summaryLines = bf.summary.split("\n");
32
+ lines.push(`- ${tag}${summaryLines[0]}`);
33
+ for (let i = 1; i < summaryLines.length; i++) if (summaryLines[i].trim()) lines.push(` ${summaryLines[i]}`);
34
+ }
35
+ if (release.isDependencyBump) {
36
+ const tag = release.type !== "patch" ? `*(patch)* ` : "";
37
+ lines.push(`- ${tag}Updated dependencies`);
38
+ }
39
+ if (release.isCascadeBump && !release.isDependencyBump && relevantBumpFiles.length === 0) lines.push("- Version bump via cascade rule");
40
+ lines.push("");
41
+ return lines.join("\n");
42
+ };
43
+ const BUILTIN_FORMATTERS = {
44
+ default: defaultFormatter,
45
+ github: async () => {
46
+ const { createGithubFormatter } = await import("./changelog-github-CEaDCtTk.mjs");
47
+ return createGithubFormatter();
48
+ }
49
+ };
50
+ /**
51
+ * Load a changelog formatter from config.
52
+ * Supports: "default", "./path/to/formatter.ts", or a module name.
53
+ */
54
+ async function loadFormatter(changelog, rootDir) {
55
+ const [name, options] = Array.isArray(changelog) ? changelog : [changelog, {}];
56
+ if (name === "github") {
57
+ const { createGithubFormatter } = await import("./changelog-github-CEaDCtTk.mjs");
58
+ return createGithubFormatter(options);
59
+ }
60
+ if (typeof name === "string" && BUILTIN_FORMATTERS[name]) {
61
+ const builtin = BUILTIN_FORMATTERS[name];
62
+ if (typeof builtin === "function" && builtin.length === 0) return builtin();
63
+ return builtin;
64
+ }
65
+ if (typeof name === "string") try {
66
+ let modulePath;
67
+ if (name.startsWith(".")) {
68
+ modulePath = resolve(rootDir, name);
69
+ try {
70
+ modulePath = realpathSync(modulePath);
71
+ } catch {}
72
+ const rel = relative(realpathSync(rootDir), modulePath);
73
+ if (rel.startsWith("..") || resolve("/", rel) === resolve("/")) throw new Error(`Changelog formatter path "${name}" resolves outside the project root`);
74
+ } else modulePath = name;
75
+ const mod = await import(modulePath);
76
+ const exported = mod.default || mod.changelogFormatter;
77
+ if (typeof exported === "function") {
78
+ const result = exported(options);
79
+ if (typeof result === "function") return result;
80
+ return exported;
81
+ }
82
+ throw new Error(`Changelog module "${name}" does not export a function`);
83
+ } catch (err) {
84
+ log.warn(`Failed to load changelog formatter "${name}": ${err instanceof Error ? err.message : err}`);
85
+ log.warn("Falling back to default formatter");
86
+ return defaultFormatter;
87
+ }
88
+ return defaultFormatter;
89
+ }
90
+ /** Generate a changelog entry using the configured formatter */
91
+ async function generateChangelogEntry(release, bumpFiles, formatter = defaultFormatter, date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0]) {
92
+ return formatter({
93
+ release,
94
+ bumpFiles,
95
+ date
96
+ });
97
+ }
98
+ /** Prepend a new entry to an existing CHANGELOG.md content */
99
+ function prependToChangelog(existingContent, newEntry) {
100
+ const headerMatch = existingContent.match(/^# /m);
101
+ if (headerMatch && headerMatch.index !== void 0) {
102
+ const afterTitle = existingContent.indexOf("\n##");
103
+ if (afterTitle !== -1) return existingContent.slice(0, afterTitle + 1) + "\n" + newEntry + "\n" + existingContent.slice(afterTitle + 1);
104
+ return existingContent.trimEnd() + "\n\n" + newEntry;
105
+ }
106
+ return "# Changelog\n\n" + newEntry;
107
+ }
108
+ //#endregion
109
+ export { prependToChangelog as a, loadFormatter as i, generateChangelogEntry as n, sortBumpFilesByType as o, getBumpTypeForPackage as r, defaultFormatter as t };
@@ -1,9 +1,9 @@
1
1
  import { n as log, o as __toESM, t as colorize } from "./logger-C2dEe5Su.mjs";
2
- import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-D7Umr-fT.mjs";
3
- import { n as discoverWorkspace } from "./workspace-BHsAPUmC.mjs";
4
- import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-C3S_bzSf.mjs";
5
- import { r as getChangedFiles } from "./git-H9S9z6g-.mjs";
6
- import { t as require_picomatch } from "./picomatch-DMmqYjgq.mjs";
2
+ import { a as loadConfig, o as loadPackageConfig, r as getBumpyDir } from "./config-CJIj8xG3.mjs";
3
+ import { n as discoverWorkspace } from "./workspace-c9-TqXed.mjs";
4
+ import { r as readBumpFiles, t as filterBranchBumpFiles } from "./bump-file-BTsntOO-.mjs";
5
+ import { r as getChangedFiles } from "./git-D0__HP86.mjs";
6
+ import { t as require_picomatch } from "./picomatch-TGJi--_I.mjs";
7
7
  import { relative } from "node:path";
8
8
  //#region src/commands/check.ts
9
9
  var import_picomatch = /* @__PURE__ */ __toESM(require_picomatch(), 1);
@@ -30,8 +30,8 @@ async function checkCommand(rootDir, opts = {}) {
30
30
  for (const err of parseErrors) log.error(err);
31
31
  process.exit(1);
32
32
  }
33
- const { branchBumpFiles, hasEmptyBumpFile } = filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir);
34
- if (hasEmptyBumpFile) {
33
+ const { branchBumpFiles, emptyBumpFileIds } = filterBranchBumpFiles(allBumpFiles, changedFiles, rootDir);
34
+ if (emptyBumpFileIds.length > 0) {
35
35
  log.success("Empty bump file found — no releases needed.");
36
36
  return;
37
37
  }