@williamthorsen/release-kit 10.4.4 → 10.6.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 (105) hide show
  1. package/.meta/changelog.json +1502 -0
  2. package/.readyup/kits/default.js +120 -4
  3. package/.readyup/kits/npm-auto-publish.js +11 -3
  4. package/.readyup/manifest.json +16 -11
  5. package/CHANGELOG.md +57 -0
  6. package/README.md +64 -4
  7. package/dist/esm/assertCleanWorkingTree.d.ts +5 -0
  8. package/dist/esm/buildChangelogEntries.d.ts +22 -0
  9. package/dist/esm/buildChangelogEntries.js +5 -0
  10. package/dist/esm/buildDependencyGraph.d.ts +16 -0
  11. package/dist/esm/buildEmptyReleaseEntry.d.ts +8 -0
  12. package/dist/esm/buildReleaseSummary.d.ts +10 -0
  13. package/dist/esm/buildSyntheticChangelogEntry.d.ts +6 -0
  14. package/dist/esm/bumpVersion.d.ts +8 -0
  15. package/dist/esm/changelogJsonFile.d.ts +11 -0
  16. package/dist/esm/changelogJsonUtils.d.ts +16 -2
  17. package/dist/esm/changelogJsonUtils.js +0 -13
  18. package/dist/esm/changelogOverrides.d.ts +143 -0
  19. package/dist/esm/changelogOverrides.js +8 -0
  20. package/dist/esm/checkWorkTypesDrift.d.ts +25 -0
  21. package/dist/esm/collectPolicyViolations.d.ts +9 -0
  22. package/dist/esm/commitCommand.d.ts +6 -0
  23. package/dist/esm/compareVersions.d.ts +7 -0
  24. package/dist/esm/createGithubRelease.d.ts +30 -0
  25. package/dist/esm/createGithubReleaseCommand.d.ts +7 -0
  26. package/dist/esm/createTags.d.ts +5 -0
  27. package/dist/esm/decideRelease.d.ts +37 -0
  28. package/dist/esm/defaults.d.ts +25 -0
  29. package/dist/esm/defineConfig.d.ts +9 -0
  30. package/dist/esm/deleteFileIfExists.d.ts +1 -0
  31. package/dist/esm/deriveWorkspaceConfig.d.ts +9 -0
  32. package/dist/esm/detectPackageManager.d.ts +6 -0
  33. package/dist/esm/detectUndeclaredTagPrefixes.d.ts +18 -0
  34. package/dist/esm/determineBumpFromCommits.d.ts +5 -0
  35. package/dist/esm/determineBumpType.d.ts +12 -0
  36. package/dist/esm/discoverWorkspaces.d.ts +12 -0
  37. package/dist/esm/extractMigration.d.ts +14 -0
  38. package/dist/esm/extractMigration.js +18 -0
  39. package/dist/esm/format.d.ts +3 -0
  40. package/dist/esm/formatPrivateSkip.d.ts +6 -0
  41. package/dist/esm/generateChangelogs.d.ts +25 -0
  42. package/dist/esm/getCommitsSinceTarget.d.ts +16 -0
  43. package/dist/esm/hasPrettierConfig.d.ts +6 -0
  44. package/dist/esm/help/prepareHelp.d.ts +6 -0
  45. package/dist/esm/init/checks.d.ts +4 -0
  46. package/dist/esm/init/detectRepoType.d.ts +7 -0
  47. package/dist/esm/init/initCommand.d.ts +6 -0
  48. package/dist/esm/init/parseJsonRecord.d.ts +4 -0
  49. package/dist/esm/init/scaffold.d.ts +3 -1
  50. package/dist/esm/init/templates.d.ts +13 -0
  51. package/dist/esm/injectReleaseNotesIntoReadme.d.ts +39 -0
  52. package/dist/esm/injectSection.d.ts +6 -0
  53. package/dist/esm/loadConfig.d.ts +46 -0
  54. package/dist/esm/loadValidatedConfig.d.ts +8 -0
  55. package/dist/esm/packsPath.d.ts +15 -0
  56. package/dist/esm/packsPath.js +47 -0
  57. package/dist/esm/parseCommitMessage.d.ts +42 -0
  58. package/dist/esm/parseRequestedTags.d.ts +7 -0
  59. package/dist/esm/planReleaseNotesPreviews.d.ts +20 -0
  60. package/dist/esm/planVersionBump.d.ts +12 -0
  61. package/dist/esm/prepareCommand.d.ts +10 -0
  62. package/dist/esm/previewTagPrefixes.d.ts +21 -1
  63. package/dist/esm/propagateBumps.d.ts +15 -0
  64. package/dist/esm/publish.d.ts +1 -0
  65. package/dist/esm/publishCommand.d.ts +4 -0
  66. package/dist/esm/pushCommand.d.ts +4 -0
  67. package/dist/esm/pushRelease.d.ts +6 -0
  68. package/dist/esm/readCurrentVersion.d.ts +1 -0
  69. package/dist/esm/releaseFiles.d.ts +22 -0
  70. package/dist/esm/releasePlan.d.ts +23 -0
  71. package/dist/esm/releasePrepare.d.ts +40 -0
  72. package/dist/esm/releasePrepare.js +0 -3
  73. package/dist/esm/releasePrepareMono.d.ts +8 -0
  74. package/dist/esm/releasePrepareMono.js +0 -4
  75. package/dist/esm/releasePrepareProject.d.ts +42 -0
  76. package/dist/esm/renderChangelogMarkdown.d.ts +17 -0
  77. package/dist/esm/renderReleaseNotes.d.ts +25 -0
  78. package/dist/esm/reportPrepare.d.ts +14 -0
  79. package/dist/esm/reportPrepare.js +4 -2
  80. package/dist/esm/resolveCliffConfigPath.d.ts +10 -0
  81. package/dist/esm/resolveCommandTags.d.ts +13 -1
  82. package/dist/esm/resolveReleaseNotesConfig.d.ts +14 -0
  83. package/dist/esm/resolveReleaseTags.d.ts +22 -0
  84. package/dist/esm/runGitCliff.d.ts +37 -1
  85. package/dist/esm/runGitCliff.js +4 -10
  86. package/dist/esm/showTagPrefixesCommand.d.ts +11 -0
  87. package/dist/esm/stripScope.d.ts +7 -0
  88. package/dist/esm/sync-labels/generateCommand.d.ts +17 -0
  89. package/dist/esm/sync-labels/initCommand.d.ts +9 -0
  90. package/dist/esm/sync-labels/presets.d.ts +6 -0
  91. package/dist/esm/sync-labels/resolveLabels.d.ts +10 -0
  92. package/dist/esm/sync-labels/retiredConfig.d.ts +8 -0
  93. package/dist/esm/sync-labels/syncCommand.d.ts +6 -0
  94. package/dist/esm/sync-labels/templates.d.ts +14 -0
  95. package/dist/esm/sync-labels/types.d.ts +4 -0
  96. package/dist/esm/syncWorkTypes.d.ts +18 -0
  97. package/dist/esm/tagCommand.d.ts +1 -0
  98. package/dist/esm/typeGuards.d.ts +2 -0
  99. package/dist/esm/types.d.ts +302 -0
  100. package/dist/esm/validateConfig.d.ts +14 -1
  101. package/dist/esm/validateOnlyExcludesStrandedDependents.d.ts +21 -0
  102. package/dist/esm/validateOverridesCommand.d.ts +30 -0
  103. package/dist/esm/workTypesData.d.ts +27 -0
  104. package/dist/esm/workTypesUtils.d.ts +17 -0
  105. package/package.json +12 -11
@@ -1,4 +1,26 @@
1
+ /**
2
+ * File written by the release preparation step, containing one tag per line.
3
+ *
4
+ * Relative to the project root so it works identically in CI and local runs. The reusable
5
+ * release workflow reads it at this path, so the path and the line-delimited format are a
6
+ * published contract rather than an internal detail.
7
+ */
1
8
  export declare const RELEASE_TAGS_FILE = "tmp/.release-tags";
9
+ /**
10
+ * File written by the release preparation step, containing the commit body summary.
11
+ * Relative to the project root so it works identically in CI and local runs.
12
+ */
2
13
  export declare const RELEASE_SUMMARY_FILE = "tmp/.release-summary";
14
+ /** Resolves the tags file against the current working directory, for use in diagnostics. */
3
15
  export declare function resolveReleaseTagsPath(): string;
16
+ /**
17
+ * Reads the tag names written by `prepare`, one per line, discarding blank lines.
18
+ *
19
+ * Both consumers — `commit` and `tag` — share this reader so their diagnostics cannot drift.
20
+ * Failure messages name the path as resolved against `process.cwd()`, which is what separates
21
+ * a genuinely absent file from one the command looked for under a different worktree, and
22
+ * they preserve the underlying errno instead of reporting every failure as a missing file.
23
+ *
24
+ * An empty or blank file yields an empty array; callers decide whether that is an error.
25
+ */
4
26
  export declare function readReleaseTags(): string[];
@@ -1,10 +1,33 @@
1
1
  import type { PrepareResult } from './types.js';
2
+ /** One file a release will write, carried as its complete intended content. */
2
3
  export interface PlannedWrite {
3
4
  path: string;
4
5
  content: string;
5
6
  }
7
+ /**
8
+ * A release computed in full but not yet written.
9
+ *
10
+ * Holding every intended file up front is what lets `prepare` fail during computation without
11
+ * leaving anything on disk. {@link applyReleasePlan} is the only step that mutates the tree, so
12
+ * a dry run is this same plan with the apply step skipped rather than a separate code path.
13
+ *
14
+ * Extends the reporting view with the two fields only the apply step needs, so `reportPrepare`
15
+ * can render a plan without knowing about file content.
16
+ */
6
17
  export interface ReleasePlan extends PrepareResult {
7
18
  writes: readonly PlannedWrite[];
19
+ /** Body of the release commit message, written alongside the tags file. */
8
20
  summary: string;
9
21
  }
22
+ /**
23
+ * Writes every file a plan describes: content files first, then the summary, then the tags file.
24
+ *
25
+ * The tags file goes last so its presence means the whole plan landed. Both `release-kit commit`
26
+ * and the reusable release workflow read it as the signal that a release is ready to commit, so
27
+ * writing it earlier would let a failure produce a tree that claims to be releasable.
28
+ *
29
+ * Returns the paths written, in order.
30
+ *
31
+ * @throws If any write fails, naming what reached disk and what did not.
32
+ */
10
33
  export declare function applyReleasePlan(plan: ReleasePlan): string[];
@@ -1,10 +1,50 @@
1
1
  import type { ReleasePlan } from './releasePlan.js';
2
2
  import type { ReleaseConfig, ReleaseType } from './types.js';
3
+ /**
4
+ * Options for the release preparation workflow.
5
+ *
6
+ * Carries no dry-run flag: preparation only ever computes a plan, and whether that plan is
7
+ * applied is the caller's decision.
8
+ */
3
9
  export interface ReleasePrepareOptions {
10
+ /**
11
+ * Release even when no commits or no bump-worthy commits exist since the last tag
12
+ * (monorepo only). Orthogonal to `bumpOverride`: when `bumpOverride` is not given,
13
+ * the release falls back to `patch`.
14
+ */
4
15
  force?: boolean;
16
+ /** Override the bump type instead of determining it from commits. */
5
17
  bumpOverride?: ReleaseType;
18
+ /**
19
+ * Explicit target version (canonical `N.N.N`) that bypasses commit-derived bump logic.
20
+ * Mutually exclusive with `bumpOverride`. In monorepo mode the caller must narrow
21
+ * `config.workspaces` to a single workspace before invoking.
22
+ */
6
23
  setVersion?: string;
24
+ /**
25
+ * Workspace directories the run was narrowed to by `--only` (monorepo only), with
26
+ * `config.workspaces` already filtered to match. Present only for a narrowed run, which
27
+ * skips the project release: the project tier rolls up every contributing workspace, and
28
+ * the narrowing has changed which workspaces those are.
29
+ */
7
30
  only?: string[];
31
+ /**
32
+ * If true, write per-workspace release-notes previews under `{workspacePath}/docs/`
33
+ * (`README.v{version}.md` and `RELEASE_NOTES.v{version}.md`) after each workspace's
34
+ * `changelog.json` is produced. Requires `config.changelogJson.enabled`; when disabled,
35
+ * a warning is recorded on the plan and no previews are generated.
36
+ */
8
37
  withReleaseNotes?: boolean;
9
38
  }
39
+ /**
40
+ * Orchestrate the release preparation workflow for a single package.
41
+ *
42
+ * 1. Gets commits since the last tag.
43
+ * 2. Determines the bump type from commits (or uses the override).
44
+ * 3. Bumps all configured package.json version fields.
45
+ * 4. Generates changelogs via git-cliff.
46
+ * 5. Runs the optional format command.
47
+ *
48
+ * Returns a structured `PrepareResult` with all data needed for presentation.
49
+ */
10
50
  export declare function releasePrepare(config: ReleaseConfig, options: ReleasePrepareOptions): ReleasePlan;
@@ -16,7 +16,6 @@ import { planVersionBump, planVersionSet } from "./planVersionBump.js";
16
16
  import { readCurrentVersion } from "./readCurrentVersion.js";
17
17
  import { renderChangelogMarkdown } from "./renderChangelogMarkdown.js";
18
18
  import { deriveSectionOrder } from "./resolveReleaseNotesConfig.js";
19
- import { refreshGitCliffCache } from "./runGitCliff.js";
20
19
  export function releasePrepare(config, options) {
21
20
  const { bumpOverride, setVersion, withReleaseNotes } = options;
22
21
  const writes = [];
@@ -46,7 +45,6 @@ export function releasePrepare(config, options) {
46
45
  if (!isForwardVersion(currentVersion, setVersion)) {
47
46
  throw new Error(`--set-version ${setVersion} is not greater than current version ${currentVersion}`);
48
47
  }
49
- refreshGitCliffCache();
50
48
  bump = planVersionSet(config.packageFiles, setVersion);
51
49
  }
52
50
  else {
@@ -78,7 +76,6 @@ export function releasePrepare(config, options) {
78
76
  formatCommand: undefined,
79
77
  };
80
78
  }
81
- refreshGitCliffCache();
82
79
  bump = planVersionBump(config.packageFiles, releaseType);
83
80
  }
84
81
  writes.push(...bump.writes);
@@ -1,4 +1,12 @@
1
1
  import type { ReleasePlan } from './releasePlan.js';
2
2
  import type { ReleasePrepareOptions } from './releasePrepare.js';
3
3
  import type { MonorepoReleaseConfig } from './types.js';
4
+ /**
5
+ * Orchestrate release preparation for a monorepo with multiple workspaces.
6
+ *
7
+ * Phase 1: Determine direct bumps from commits for each workspace.
8
+ * Phase 2: Build the dependency graph and propagate bumps to dependents.
9
+ * Phase 2b: Topologically sort the full release set.
10
+ * Phase 3: Execute bumps and generate changelogs in dependency order.
11
+ */
4
12
  export declare function releasePrepareMono(config: MonorepoReleaseConfig, options: ReleasePrepareOptions): ReleasePlan;
@@ -23,7 +23,6 @@ import { readCurrentVersion } from "./readCurrentVersion.js";
23
23
  import { releasePrepareProject } from "./releasePrepareProject.js";
24
24
  import { renderChangelogMarkdown } from "./renderChangelogMarkdown.js";
25
25
  import { deriveSectionOrder } from "./resolveReleaseNotesConfig.js";
26
- import { refreshGitCliffCache } from "./runGitCliff.js";
27
26
  export function releasePrepareMono(config, options) {
28
27
  const { only, withReleaseNotes } = options;
29
28
  const writes = [];
@@ -53,9 +52,6 @@ export function releasePrepareMono(config, options) {
53
52
  enabled: withReleaseNotes === true && config.changelogJson.enabled,
54
53
  sectionOrder,
55
54
  };
56
- if (fullReleaseSet.size > 0) {
57
- refreshGitCliffCache();
58
- }
59
55
  const { tags, modifiedFiles } = executeReleaseSet({
60
56
  sortedDirs,
61
57
  fullReleaseSet,
@@ -1,15 +1,57 @@
1
1
  import type { PlannedWrite } from './releasePlan.js';
2
2
  import type { ReleasePrepareOptions } from './releasePrepare.js';
3
3
  import type { ChangelogOverride, MonorepoReleaseConfig, ProjectPrepareResult } from './types.js';
4
+ /** Inputs to the project-release stage. */
4
5
  export interface ReleasePrepareProjectArgs {
6
+ /** Resolved monorepo config; `config.project` must be defined when this function is called. */
5
7
  config: MonorepoReleaseConfig;
6
8
  options: ReleasePrepareOptions;
9
+ /** Mutated in-place to append project-level files (root package.json, root CHANGELOG.md, root changelog.json). */
7
10
  modifiedFiles: string[];
11
+ /** Mutated in-place to append every file this stage intends to write. */
8
12
  writes: PlannedWrite[];
13
+ /** Mutated in-place to append the project tag. */
9
14
  tags: string[];
15
+ /**
16
+ * Mutated in-place to surface warnings this stage raises that are not override-specific
17
+ * (currently the release-notes previews' skip reasons). Defaults to a discardable sink.
18
+ */
10
19
  warnings?: string[];
20
+ /**
21
+ * Root-tier editorial overrides loaded once at the top of the prepare run. Defaults to an
22
+ * empty map when omitted (no overrides applied). The project changelog applies only the
23
+ * root-tier file — per-workspace files describe per-workspace editorial intent and have no
24
+ * meaning at the aggregated project tier.
25
+ */
11
26
  rootOverrides?: Map<string, ChangelogOverride>;
27
+ /**
28
+ * Mutated in-place to surface override warnings (currently empty by design — stale-key
29
+ * warnings are emitted by the orchestrator after aggregating across batches). Defaults to
30
+ * a discardable sink when omitted.
31
+ */
12
32
  overrideWarnings?: string[];
33
+ /**
34
+ * Mutated in-place: every root-tier override key matched in this stage is added so the
35
+ * orchestrator can dedupe stale-key warnings across the run. Defaults to a discardable
36
+ * sink when omitted.
37
+ */
13
38
  globalMatchedRootKeys?: Set<string>;
14
39
  }
40
+ /**
41
+ * Run the project-level release stage.
42
+ *
43
+ * Mirrors the per-workspace pipeline shape — find baseline tag → derive bump → bump version →
44
+ * regenerate CHANGELOG → optionally emit changelog.json and release-notes previews — but
45
+ * targets the root `package.json` and the root `CHANGELOG.md`. Contributing paths come from
46
+ * the resolved `project.paths`, which defaults to the union of every (already-filtered)
47
+ * workspace's `paths`.
48
+ *
49
+ * Returns a structured `{ status: 'skipped', skipReason, ... }` result when neither
50
+ * commits nor `--force` provide a release signal. The caller should attach the returned
51
+ * result to `PrepareResult.project`. `undefined` is returned only when there is no
52
+ * configured `project` block — handled at the call site, not here.
53
+ *
54
+ * Caller contract: `prepareCommand` rejects `--only` upstream when a project block is
55
+ * configured, so this orchestrator never has to reason about workspace-narrowing flags.
56
+ */
15
57
  export declare function releasePrepareProject(args: ReleasePrepareProjectArgs): ProjectPrepareResult;
@@ -1,5 +1,22 @@
1
1
  import type { ChangelogEntry } from './types.js';
2
+ /** Options for `renderChangelogMarkdown`. */
2
3
  export interface RenderChangelogMarkdownOptions {
4
+ /** Section titles in canonical order; passed through to `renderReleaseNotesMulti`. */
3
5
  sectionOrder?: string[];
4
6
  }
7
+ /**
8
+ * Render `ChangelogEntry[]` into a complete `CHANGELOG.md`-shaped string.
9
+ *
10
+ * Format:
11
+ * `# Changelog`
12
+ * blank line
13
+ * `All notable changes …`
14
+ * blank line
15
+ * per-entry sections (delegated to `renderReleaseNotesMulti`)
16
+ * blank line
17
+ * footer comment
18
+ *
19
+ * Entries are rendered in the order provided; the caller sorts (typically newest-first via
20
+ * `changelogJsonFile`'s SemVer-aware comparator).
21
+ */
5
22
  export declare function renderChangelogMarkdown(entries: ChangelogEntry[], options?: RenderChangelogMarkdownOptions): string;
@@ -1,9 +1,34 @@
1
1
  import type { ChangelogAudience, ChangelogEntry, ChangelogSection } from './types.js';
2
+ /** Options for rendering a single changelog entry to markdown. */
2
3
  export interface RenderOptions {
4
+ /** Predicate to filter sections. When absent, all sections are included. */
3
5
  filter?: (section: ChangelogSection) => boolean;
6
+ /** Whether to include the version/date heading. Defaults to `true`. */
4
7
  includeHeading?: boolean;
8
+ /**
9
+ * Section titles in desired priority order. Known titles are emitted first in this order;
10
+ * titles not listed preserve their relative position after known ones. When absent, section
11
+ * order is preserved from the entry.
12
+ */
5
13
  sectionOrder?: string[];
6
14
  }
15
+ /**
16
+ * Create a predicate that matches sections visible to the given audience.
17
+ *
18
+ * `"all"` matches only sections with `audience: "all"` (public-facing).
19
+ * `"dev"` matches all sections (developers see everything).
20
+ */
7
21
  export declare function matchesAudience(audience: ChangelogAudience): (section: ChangelogSection) => boolean;
22
+ /**
23
+ * Render a single `ChangelogEntry` to markdown.
24
+ *
25
+ * Output format mirrors the existing CHANGELOG.md style: an H2 version heading followed by
26
+ * H3 section headings with bulleted items.
27
+ */
8
28
  export declare function renderReleaseNotesSingle(entry: ChangelogEntry, options?: RenderOptions): string;
29
+ /**
30
+ * Render multiple `ChangelogEntry` values to a single markdown document.
31
+ *
32
+ * Entries are rendered in the order provided; the caller is responsible for sorting.
33
+ */
9
34
  export declare function renderReleaseNotesMulti(entries: ChangelogEntry[], options?: RenderOptions): string;
@@ -1,6 +1,20 @@
1
1
  import type { PrepareResult } from './types.js';
2
+ /** How the plan was carried out, which decides the tense the report is rendered in. */
2
3
  export interface ReportPrepareOptions {
4
+ /** True when the plan was written to disk; false for a dry run. */
3
5
  applied: boolean;
6
+ /** The format command's failure message, when it ran and failed. */
4
7
  formatError?: string;
5
8
  }
9
+ /**
10
+ * Format a release plan into styled terminal output.
11
+ *
12
+ * Pure function: accepts structured data, returns a string. Never writes to stdout.
13
+ * Single-workspace mode (no `name` field) renders flat output; multi-workspace mode
14
+ * renders section headers per workspace, an optional project section, and a tag summary
15
+ * at the end.
16
+ *
17
+ * Whether the plan was applied is a property of the render, not of the plan: the same plan
18
+ * produces the dry-run report and the applied report.
19
+ */
6
20
  export declare function reportPrepare(plan: PrepareResult, options: ReportPrepareOptions): string;
@@ -1,4 +1,6 @@
1
1
  import { bold, dim, sectionHeader } from "./format.js";
2
+ import { GIT_CLIFF_NPX_ARGS } from "./runGitCliff.js";
3
+ const CLIFF_DRY_RUN_COMMAND = `npx ${GIT_CLIFF_NPX_ARGS.join(' ')} ...`;
2
4
  export function reportPrepare(plan, options) {
3
5
  const isMultiWorkspace = plan.workspaces.some((w) => w.name !== undefined) || plan.project !== undefined;
4
6
  if (isMultiWorkspace) {
@@ -103,7 +105,7 @@ function formatProjectSection(lines, project, dryRun) {
103
105
  lines.push(dim(' Generating changelogs...'));
104
106
  for (const file of project.changelogFiles) {
105
107
  if (dryRun) {
106
- lines.push(dim(` [dry-run] Would run: npx --yes git-cliff ... --output ${file}`));
108
+ lines.push(dim(` [dry-run] Would run: ${CLIFF_DRY_RUN_COMMAND} --output ${file}`));
107
109
  }
108
110
  else {
109
111
  lines.push(dim(` Generating changelog: ${file}`));
@@ -195,7 +197,7 @@ function formatBumpFiles(lines, workspace, dryRun, indent = '') {
195
197
  function formatChangelogFiles(lines, workspace, dryRun, indent = '') {
196
198
  for (const file of workspace.changelogFiles) {
197
199
  if (dryRun) {
198
- lines.push(dim(`${indent} [dry-run] Would run: npx --yes git-cliff ... --output ${file}`));
200
+ lines.push(dim(`${indent} [dry-run] Would run: ${CLIFF_DRY_RUN_COMMAND} --output ${file}`));
199
201
  }
200
202
  else {
201
203
  lines.push(dim(`${indent} Generating changelog: ${file}`));
@@ -1 +1,11 @@
1
+ /**
2
+ * Resolve the git-cliff configuration file path.
3
+ *
4
+ * Checks candidates in order: explicit `cliffConfigPath` -> `.config/git-cliff.toml` ->
5
+ * `cliff.toml` -> bundled `cliff.toml.template`. Returns the first path that exists,
6
+ * or throws if even the bundled template cannot be found.
7
+ *
8
+ * When an explicit `cliffConfigPath` is provided, it is returned as-is without checking
9
+ * existence, preserving current behavior (git-cliff reports the error if the file is missing).
10
+ */
1
11
  export declare function resolveCliffConfigPath(cliffConfigPath: string | undefined, metaUrl: string): string;
@@ -1,2 +1,14 @@
1
- import type { ResolvedTag } from './resolveReleaseTags.js';
1
+ import { type ResolvedTag } from './resolveReleaseTags.js';
2
+ /**
3
+ * Discover workspaces, resolve release tags from HEAD, validate `--tags` names against the
4
+ * full resolved tag names (e.g., `nmr-core-v1.3.0`), and return the filtered tag list.
5
+ * Works in both single-package and monorepo modes. Exits with an error message on any validation
6
+ * failure — including `deriveWorkspaceConfig()` throws for workspaces missing a `package.json` `name` field.
7
+ *
8
+ * In both modes `deriveWorkspaceConfig` is called so `WorkspaceConfig.isPublishable` (read
9
+ * from `package.json#private`) propagates onto each `ResolvedTag`. Single-package mode now
10
+ * derives `./package.json`'s workspace config too — consumers that previously relied on
11
+ * single-package mode skipping the derive step need a `name` field on `./package.json`,
12
+ * but in practice every npm/pnpm package already has one.
13
+ */
2
14
  export declare function resolveCommandTags(tags: string[] | undefined): Promise<ResolvedTag[]>;
@@ -2,12 +2,26 @@ import type { ReleaseNotesConfig } from './types.js';
2
2
  export interface ResolvedReleaseNotesConfig {
3
3
  releaseNotes: ReleaseNotesConfig;
4
4
  changelogJsonOutputPath: string;
5
+ /** Section titles in priority order, derived from the merged workTypes record. */
5
6
  sectionOrder: string[];
6
7
  }
7
8
  export interface ResolveReleaseNotesConfigOptions {
9
+ /**
10
+ * When `true`, a `loadConfig()` rejection causes `process.exit(1)` rather than a fallback to
11
+ * defaults. Use from CLI commands whose entire behavior depends on the resolved config (e.g.
12
+ * `create-github-release`), so a corrupt or unreadable config cannot silently send the command
13
+ * to the wrong changelog path.
14
+ */
8
15
  strictLoad?: boolean;
9
16
  }
17
+ /**
18
+ * Load and validate the release-kit config.
19
+ *
20
+ * By default, falls back to defaults when `loadConfig()` rejects (legacy publish behavior).
21
+ * When `strictLoad` is `true`, a load failure prints an error and calls `process.exit(1)`.
22
+ */
10
23
  export declare function resolveReleaseNotesConfig(options?: ResolveReleaseNotesConfigOptions): Promise<ResolvedReleaseNotesConfig>;
24
+ /** Extract section headers in declaration order from a merged workTypes record. */
11
25
  export declare function deriveSectionOrder(workTypes: Record<string, {
12
26
  header: string;
13
27
  }>): string[];
@@ -3,12 +3,34 @@ export interface ResolvedTag {
3
3
  tag: string;
4
4
  dir: string;
5
5
  workspacePath: string;
6
+ /**
7
+ * Whether the workspace this tag belongs to can be published to a registry. Propagated
8
+ * from the matched `WorkspaceConfig.isPublishable` (monorepo) or from the single-package
9
+ * workspace config (single-package mode). Consumed by `release-kit publish` to filter the
10
+ * tag set; other commands ignore it.
11
+ */
6
12
  isPublishable: boolean;
7
13
  }
14
+ /** Discriminated argument to `resolveReleaseTags`: exactly one of the two keys is meaningful. */
8
15
  type ResolveReleaseTagsArgs = {
9
16
  workspaces: readonly WorkspaceConfig[];
10
17
  } | {
11
18
  singleWorkspace: WorkspaceConfig;
12
19
  };
20
+ /**
21
+ * Resolve release tags pointing at HEAD into publishable package descriptors.
22
+ *
23
+ * Pass `{ workspaces }` for monorepo mode: each tag is matched against the workspace
24
+ * whose `tagPrefix` it starts with, and that workspace's `isPublishable` propagates onto
25
+ * the `ResolvedTag`. Because `tagPrefix` is derived from `deriveWorkspaceConfig()` (the
26
+ * same source that produced the tag), encoding and decoding stay colocated.
27
+ *
28
+ * Pass `{ singleWorkspace }` for single-package mode: tags like `v1.2.3` are matched and
29
+ * each carries the workspace's `isPublishable` bit derived from `./package.json#private`.
30
+ *
31
+ * The no-arg form is a test-isolation convenience for unit tests that exercise tag
32
+ * matching without needing `isPublishable` propagation; resolved tags default to
33
+ * `isPublishable: true`. Production callers should pass one of the named forms.
34
+ */
13
35
  export declare function resolveReleaseTags(args?: ResolveReleaseTagsArgs): ResolvedTag[];
14
36
  export {};
@@ -1,2 +1,38 @@
1
+ /**
2
+ * The exact `git-cliff` version every invocation resolves.
3
+ *
4
+ * npm's `git-cliff` trails the upstream release, so this pin normally sits behind the newest version cliff
5
+ * itself reports. Bumping it is an edit to this line, once npm publishes the version you want.
6
+ */
7
+ export declare const GIT_CLIFF_VERSION = "2.13.1";
8
+ /** The npx arguments that precede the cliff args at every invocation, and that the dry-run report renders. */
9
+ export declare const GIT_CLIFF_NPX_ARGS: readonly string[];
10
+ /**
11
+ * Invokes `git-cliff` via `npx` and returns the output it produced.
12
+ *
13
+ * Single entry point for `git-cliff` invocations from `release-kit`. Owns three pieces of shared lifecycle
14
+ * that would otherwise duplicate (and silently drift) across call sites: the npx flags, the spawned-process
15
+ * environment, and the temp dir holding both the `.template`→`.toml` config copy and cliff's output file.
16
+ *
17
+ * Output is routed through `--output` to a temp file and read back. `--context` emits a workspace's
18
+ * entire matching tag history on every run, so its size grows without bound with the repo;
19
+ * a file accommodates that, while a pipe is bounded by `maxBuffer`.
20
+ *
21
+ * The npx spec names an exact version, which leaves npm no staleness to check, so `--prefer-offline` skips the
22
+ * per-call registry revalidation round-trip (~2.5 s per invocation on a warm cache) without stranding the run
23
+ * on whatever the cache happens to hold.
24
+ *
25
+ * Two env entries are set for the child. `npm_config_progress=false` suppresses npx's animated stderr spinner,
26
+ * which otherwise renders as a transient flicker. `RUST_LOG=warn` drops cliff's INFO lines, among them the
27
+ * crates.io update notice it emits on every invocation while npm trails upstream, and leaves warnings and errors
28
+ * in place; an inherited `RUST_LOG` wins, so raising the level for debugging still works.
29
+ *
30
+ * The helper injects `--config <path>` and `--output <path>` itself — callers must NOT include either in `cliffArgs`.
31
+ * `--output` is appended last so a caller that passes one anyway cannot redirect the output the helper then reads.
32
+ * The caller is responsible for resolving the cliff config path (via `resolveCliffConfigPath`) before calling,
33
+ * since the resolution depends on the caller's `import.meta.url`.
34
+ *
35
+ * Errors from `execFileSync` are not caught: callers wrap with site-specific messages.
36
+ * The temp-dir cleanup runs in a `finally` so it still happens on throw.
37
+ */
1
38
  export declare function runGitCliff(cliffConfigPath: string, cliffArgs: readonly string[]): string;
2
- export declare function refreshGitCliffCache(): void;
@@ -2,7 +2,8 @@ import { execFileSync } from 'node:child_process';
2
2
  import { copyFileSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { join } from 'node:path';
5
- import { GIT_OUTPUT_LIMIT } from '@williamthorsen/nmr-core';
5
+ export const GIT_CLIFF_VERSION = '2.13.1';
6
+ export const GIT_CLIFF_NPX_ARGS = ['--prefer-offline', '--yes', `git-cliff@${GIT_CLIFF_VERSION}`];
6
7
  export function runGitCliff(cliffConfigPath, cliffArgs) {
7
8
  const tempDir = mkdtempSync(join(tmpdir(), 'cliff-'));
8
9
  try {
@@ -12,9 +13,9 @@ export function runGitCliff(cliffConfigPath, cliffArgs) {
12
13
  copyFileSync(cliffConfigPath, configPath);
13
14
  }
14
15
  const outputPath = join(tempDir, 'output.json');
15
- execFileSync('npx', ['--prefer-offline', '--yes', 'git-cliff', '--config', configPath, ...cliffArgs, '--output', outputPath], {
16
+ execFileSync('npx', [...GIT_CLIFF_NPX_ARGS, '--config', configPath, ...cliffArgs, '--output', outputPath], {
16
17
  stdio: ['ignore', 'ignore', 'inherit'],
17
- env: { ...process.env, npm_config_progress: 'false' },
18
+ env: { ...process.env, npm_config_progress: 'false', RUST_LOG: process.env['RUST_LOG'] ?? 'warn' },
18
19
  });
19
20
  return readFileSync(outputPath, 'utf8');
20
21
  }
@@ -22,10 +23,3 @@ export function runGitCliff(cliffConfigPath, cliffArgs) {
22
23
  rmSync(tempDir, { recursive: true, force: true });
23
24
  }
24
25
  }
25
- export function refreshGitCliffCache() {
26
- execFileSync('npx', ['--yes', 'git-cliff', '--version'], {
27
- maxBuffer: GIT_OUTPUT_LIMIT,
28
- stdio: ['ignore', 'pipe', 'inherit'],
29
- env: { ...process.env, npm_config_progress: 'false' },
30
- });
31
- }
@@ -1 +1,12 @@
1
+ /**
2
+ * Orchestrate the CLI `show-tag-prefixes` command.
3
+ *
4
+ * Prints a per-workspace table of derived prefixes, tag counts, and declared legacy
5
+ * entries, followed by an "Undeclared tag prefixes" section when candidate-shaped tags
6
+ * exist outside the known set. Exits `0` on full derivation success and no collisions;
7
+ * `1` on any derivation failure or collision. Undeclared candidates do not affect the
8
+ * exit code.
9
+ *
10
+ * @returns The exit code the caller should use.
11
+ */
1
12
  export declare function showTagPrefixesCommand(): Promise<number>;
@@ -1 +1,8 @@
1
+ /**
2
+ * Strip scope indicators from a raw commit message.
3
+ *
4
+ * Handles `scope|type: desc`, `type(scope): desc`, and messages with
5
+ * ticket prefixes (e.g., `#72 release-kit|fix: ...`). Returns the
6
+ * message unchanged when no scope is detected.
7
+ */
1
8
  export declare function stripScope(message: string): string;
@@ -1,10 +1,27 @@
1
1
  import type { RepoLabelsConfig } from '../types.js';
2
2
  import type { LabelDefinition } from './types.js';
3
+ /** Output path for the generated labels file. */
3
4
  export declare const LABELS_OUTPUT_PATH = ".github/labels.yaml";
5
+ /** Formats resolved labels as YAML with generated header including preset hashes. */
4
6
  export declare function formatLabelsYaml(labels: LabelDefinition[], presetHashes: Map<string, string>): string;
7
+ /**
8
+ * Loads `.config/release-kit.config.ts` and returns its `repoLabels` block.
9
+ *
10
+ * Reports an actionable error and returns `undefined` when the config file is missing,
11
+ * fails to load or validate, or carries no `repoLabels` block.
12
+ */
5
13
  export declare function loadRepoLabelsConfig(): Promise<RepoLabelsConfig | undefined>;
14
+ /** Options for the `sync-labels generate` subcommand. */
6
15
  interface GenerateOptions {
16
+ /** Compare the regenerated content against the committed file instead of writing. */
7
17
  check?: boolean;
8
18
  }
19
+ /**
20
+ * Runs the `sync-labels generate` command.
21
+ *
22
+ * Loads the `repoLabels` block from `.config/release-kit.config.ts`, resolves presets and label adjustments,
23
+ * and writes `.github/labels.yaml` -- or, with `check`, regenerates in memory and reports whether the committed file
24
+ * is stale, writing nothing. Returns 0 on success, 1 on failure.
25
+ */
9
26
  export declare function generateCommand({ check }?: GenerateOptions): Promise<number>;
10
27
  export {};
@@ -1,6 +1,15 @@
1
+ /** Options for the `sync-labels init` subcommand. */
1
2
  interface InitOptions {
2
3
  dryRun: boolean;
3
4
  force: boolean;
4
5
  }
6
+ /**
7
+ * Run the `sync-labels init` subcommand.
8
+ *
9
+ * Discovers workspaces and retired packages, scaffolds the caller workflow, then seeds the
10
+ * `repoLabels` block: into a new `.config/release-kit.config.ts` when none exists, or
11
+ * printed to stdout for manual paste when the file is already there — an existing,
12
+ * hand-authored config is never rewritten. Returns 0 on success, 1 on failure.
13
+ */
5
14
  export declare function syncLabelsInitCommand({ dryRun, force }: InitOptions): Promise<number>;
6
15
  export {};
@@ -1,3 +1,9 @@
1
1
  import type { LabelDefinition } from './types.js';
2
+ /** Computes SHA-256 hex digest of a preset file's raw content. Throws if the preset does not exist. */
2
3
  export declare function hashPresetFile(presetName: string): string;
4
+ /**
5
+ * Loads a named preset from the bundled YAML files.
6
+ *
7
+ * Returns the parsed label definitions. Throws if the preset does not exist or has invalid content.
8
+ */
3
9
  export declare function loadPreset(presetName: string): LabelDefinition[];
@@ -1,3 +1,13 @@
1
1
  import type { RepoLabelsConfig } from '../types.js';
2
2
  import type { LabelDefinition } from './types.js';
3
+ /**
4
+ * Resolves the repository's label set from a `repoLabels` config block.
5
+ *
6
+ * Resolution is an ordered fold with last-writer-wins: presets are loaded in `extends` order (a later preset replaces
7
+ * an earlier preset's label of the same name), then the `labels` record is applied: An entry adds a label, replaces
8
+ * one an earlier layer defined, or removes it (`null`). Replacement is wholesale, so an entry omitting `description`
9
+ * drops the one an earlier layer supplied rather than inheriting it.
10
+ * Throws only on a dangling `null`: a removal naming a label no preset defined, which is a stale reference that
11
+ * would otherwise produce no output diff to review.
12
+ */
3
13
  export declare function resolveLabels(config: RepoLabelsConfig): LabelDefinition[];
@@ -1,2 +1,10 @@
1
+ /** Path of the retired standalone sync-labels config file. */
1
2
  export declare const RETIRED_SYNC_LABELS_CONFIG_PATH = ".config/sync-labels.config.ts";
3
+ /**
4
+ * Report an actionable migration error when the retired standalone config file is present.
5
+ *
6
+ * Returns `true` when the file exists, in which case the caller must abort. The check is
7
+ * unconditional on config content: file presence alone triggers it, so a half-migrated
8
+ * repo cannot silently lose its custom labels.
9
+ */
2
10
  export declare function checkRetiredSyncLabelsConfig(): boolean;
@@ -1 +1,7 @@
1
+ /**
2
+ * Run the `sync-labels sync` subcommand.
3
+ *
4
+ * Validates prerequisites (gh CLI, workflow file), then triggers the sync-labels workflow
5
+ * via `gh workflow run`. Returns 0 on success, 1 on failure.
6
+ */
1
7
  export declare function syncLabelsCommand(): number;
@@ -1,5 +1,19 @@
1
1
  import type { LabelDefinition } from './types.js';
2
+ /** Generates the caller workflow YAML for `sync-labels`. */
2
3
  export declare function syncLabelsWorkflow(): string;
4
+ /**
5
+ * Generates scope labels from workspace paths and retired-package names.
6
+ *
7
+ * Workspace labels are named after the path basename; retired-package labels after the unscoped package name.
8
+ * None carries a description: GitHub renders a described label taller and more prominently than a bare one, and
9
+ * the scope labels are meant to read as a compact group.
10
+ * Describing only the retired scopes would single them out for that prominence.
11
+ */
3
12
  export declare function buildScopeLabels(workspacePaths: string[], retiredNames?: string[]): LabelDefinition[];
13
+ /**
14
+ * Renders the `repoLabels` config block, indented for pasting into the object passed to `defineConfig` in
15
+ * `.config/release-kit.config.ts`.
16
+ */
4
17
  export declare function renderRepoLabelsBlock(scopeLabels: LabelDefinition[]): string;
18
+ /** Generates a new `.config/release-kit.config.ts` carrying the `repoLabels` block. */
5
19
  export declare function repoLabelsConfigScript(scopeLabels: LabelDefinition[]): string;
@@ -1,5 +1,9 @@
1
+ /** A single GitHub label definition compatible with EndBug/label-sync. */
1
2
  export interface LabelDefinition {
3
+ /** Display name of the label. */
2
4
  name: string;
5
+ /** Hex color code without the leading `#`. */
3
6
  color: string;
7
+ /** Short description shown in the GitHub UI. Absent when the label carries none. */
4
8
  description?: string;
5
9
  }