@williamthorsen/release-kit 10.7.0 → 10.9.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 (58) hide show
  1. package/.meta/changelog.json +71 -3
  2. package/.readyup/kits/default.js +3 -3
  3. package/.readyup/kits/npm-auto-publish.js +1 -1
  4. package/.readyup/manifest.json +9 -9
  5. package/CHANGELOG.md +49 -3
  6. package/README.md +21 -15
  7. package/dist/esm/bin/release-kit.js +20 -102
  8. package/dist/esm/buildChangelogEntries.d.ts +1 -1
  9. package/dist/esm/buildChangelogEntries.js +14 -5
  10. package/dist/esm/createGithubReleaseCommand.d.ts +2 -1
  11. package/dist/esm/createGithubReleaseCommand.js +4 -2
  12. package/dist/esm/createTags.d.ts +2 -0
  13. package/dist/esm/createTags.js +5 -4
  14. package/dist/esm/format.d.ts +5 -5
  15. package/dist/esm/format.js +5 -4
  16. package/dist/esm/glyphs.d.ts +3 -0
  17. package/dist/esm/glyphs.js +6 -0
  18. package/dist/esm/init/initCommand.d.ts +3 -1
  19. package/dist/esm/init/initCommand.js +15 -15
  20. package/dist/esm/loadValidatedConfig.d.ts +2 -1
  21. package/dist/esm/loadValidatedConfig.js +3 -3
  22. package/dist/esm/parseCommitMessage.d.ts +4 -5
  23. package/dist/esm/prepareCommand.d.ts +2 -1
  24. package/dist/esm/prepareCommand.js +17 -16
  25. package/dist/esm/publishCommand.d.ts +2 -1
  26. package/dist/esm/publishCommand.js +2 -2
  27. package/dist/esm/reportPrepare.d.ts +2 -0
  28. package/dist/esm/reportPrepare.js +44 -38
  29. package/dist/esm/resolveReleaseNotesConfig.d.ts +2 -1
  30. package/dist/esm/resolveReleaseNotesConfig.js +4 -4
  31. package/dist/esm/resolveStylesOrExit.d.ts +10 -0
  32. package/dist/esm/resolveStylesOrExit.js +10 -0
  33. package/dist/esm/showTagPrefixesCommand.d.ts +2 -1
  34. package/dist/esm/showTagPrefixesCommand.js +16 -10
  35. package/dist/esm/sync-labels/generateCommand.d.ts +4 -2
  36. package/dist/esm/sync-labels/generateCommand.js +4 -4
  37. package/dist/esm/sync-labels/initCommand.d.ts +3 -1
  38. package/dist/esm/sync-labels/initCommand.js +7 -7
  39. package/dist/esm/tagCommand.d.ts +2 -1
  40. package/dist/esm/tagCommand.js +2 -2
  41. package/dist/esm/types.d.ts +8 -7
  42. package/dist/esm/validateOverridesCommand.d.ts +4 -4
  43. package/dist/esm/validateOverridesCommand.js +6 -6
  44. package/dist/esm/workTypesData.d.ts +10 -9
  45. package/dist/esm/workTypesData.js +97 -11
  46. package/docs/changelogs.md +8 -8
  47. package/docs/configuration.md +23 -1
  48. package/docs/work-types.md +28 -30
  49. package/package.json +11 -11
  50. package/presets/labels/common.yaml +2 -2
  51. package/dist/esm/checkWorkTypesDrift.d.ts +0 -36
  52. package/dist/esm/checkWorkTypesDrift.js +0 -117
  53. package/dist/esm/syncWorkTypes.d.ts +0 -28
  54. package/dist/esm/syncWorkTypes.js +0 -94
  55. package/dist/esm/work-types.json +0 -133
  56. package/dist/esm/work-types.schema.json +0 -100
  57. package/dist/esm/workTypesUtils.d.ts +0 -22
  58. package/dist/esm/workTypesUtils.js +0 -16
@@ -9,7 +9,7 @@ const createGithubReleaseFlagSchema = {
9
9
  dryRun: { long: '--dry-run', type: 'boolean' },
10
10
  tags: { long: '--tags', type: 'string' },
11
11
  };
12
- export async function createGithubReleaseCommand(argv) {
12
+ export async function createGithubReleaseCommand(argv, styles) {
13
13
  const parsed = parseArgsOrExit(argv, createGithubReleaseFlagSchema);
14
14
  const { dryRun } = parsed.flags;
15
15
  const requestedTags = parseRequestedTags(parsed.flags.tags);
@@ -23,7 +23,9 @@ export async function createGithubReleaseCommand(argv) {
23
23
  if (publishableTags.length === 0) {
24
24
  return;
25
25
  }
26
- const { changelogJsonOutputPath, sectionOrder } = await resolveReleaseNotesConfig({ strictLoad: true });
26
+ const { changelogJsonOutputPath, sectionOrder } = await resolveReleaseNotesConfig(styles.stderr, {
27
+ strictLoad: true,
28
+ });
27
29
  let outcome;
28
30
  try {
29
31
  outcome = createGithubReleases(publishableTags, changelogJsonOutputPath, dryRun, sectionOrder);
@@ -1,6 +1,8 @@
1
+ import { type OutputStyle } from '@williamthorsen/nmr-core';
1
2
  export interface CreateTagsOptions {
2
3
  dryRun: boolean;
3
4
  noGitChecks: boolean;
5
+ style: OutputStyle;
4
6
  }
5
7
  /**
6
8
  * Read tag names from the tags file produced by `prepare` and create annotated git tags.
@@ -1,9 +1,10 @@
1
1
  import { execFileSync } from 'node:child_process';
2
- import { GIT_OUTPUT_LIMIT, hasErrnoCode } from '@williamthorsen/nmr-core';
2
+ import { formatGlyphLine, GIT_OUTPUT_LIMIT, hasErrnoCode } from '@williamthorsen/nmr-core';
3
3
  import { deleteFileIfExists } from "./deleteFileIfExists.js";
4
+ import { RELEASE_GLYPHS } from "./glyphs.js";
4
5
  import { readReleaseTags, RELEASE_SUMMARY_FILE, RELEASE_TAGS_FILE } from "./releaseFiles.js";
5
6
  export function createTags(options) {
6
- const { dryRun, noGitChecks } = options;
7
+ const { dryRun, noGitChecks, style } = options;
7
8
  const tags = readReleaseTags();
8
9
  if (tags.length === 0) {
9
10
  return [];
@@ -14,7 +15,7 @@ export function createTags(options) {
14
15
  if (dryRun) {
15
16
  console.info('[dry-run] Would create tags:');
16
17
  for (const tag of tags) {
17
- console.info(`🏷️ ${tag}`);
18
+ console.info(formatGlyphLine(RELEASE_GLYPHS, style, 'tag', tag));
18
19
  }
19
20
  return tags;
20
21
  }
@@ -36,7 +37,7 @@ export function createTags(options) {
36
37
  }
37
38
  console.info('Created tags:');
38
39
  for (const tag of tags) {
39
- console.info(`🏷️ ${tag}`);
40
+ console.info(formatGlyphLine(RELEASE_GLYPHS, style, 'tag', tag));
40
41
  }
41
42
  deleteFileIfExists(RELEASE_TAGS_FILE);
42
43
  deleteFileIfExists(RELEASE_SUMMARY_FILE);
@@ -1,6 +1,6 @@
1
- /** Wrap text in ANSI bold. */
2
- export declare function bold(text: string): string;
3
- /** Wrap text in ANSI dim. */
4
- export declare function dim(text: string): string;
5
- /** Render a section header for separating workspaces in CLI output. */
1
+ /** Styles text bold, returning it unstyled for a stream that cannot render color. */
2
+ export declare function bold(text: string, stream?: NodeJS.WritableStream): string;
3
+ /** Styles text dim, returning it unstyled for a stream that cannot render color. */
4
+ export declare function dim(text: string, stream?: NodeJS.WritableStream): string;
5
+ /** Renders a section header for separating workspaces in CLI output. */
6
6
  export declare function sectionHeader(name: string): string;
@@ -1,8 +1,9 @@
1
- export function bold(text) {
2
- return `\u{1B}[1m${text}\u{1B}[0m`;
1
+ import { styleText } from 'node:util';
2
+ export function bold(text, stream = process.stdout) {
3
+ return styleText('bold', text, { stream });
3
4
  }
4
- export function dim(text) {
5
- return `\u{1B}[2m${text}\u{1B}[0m`;
5
+ export function dim(text, stream = process.stdout) {
6
+ return styleText('dim', text, { stream });
6
7
  }
7
8
  export function sectionHeader(name) {
8
9
  return `━━━ ${name} ━━━`;
@@ -0,0 +1,3 @@
1
+ /** Glyphs that name no status; a status marker comes from nmr-core's `STATUS_GLYPHS`. */
2
+ export declare const RELEASE_GLYPHS: Readonly<Record<"plain" | "rich", Readonly<Record<"bump" | "dryRun" | "tag", import("@williamthorsen/toolbelt.terminal/candidate").Glyph>>>>;
3
+ export type ReleaseGlyphName = keyof (typeof RELEASE_GLYPHS)['rich'];
@@ -0,0 +1,6 @@
1
+ import { defineGlyphSet } from '@williamthorsen/nmr-core';
2
+ export const RELEASE_GLYPHS = defineGlyphSet({
3
+ bump: { plain: 'BUMP', rich: '📦' },
4
+ dryRun: { plain: '', rich: '🔍' },
5
+ tag: { plain: 'TAG', rich: '🔖' },
6
+ });
@@ -1,6 +1,8 @@
1
+ import { type StreamStyles } from '@williamthorsen/nmr-core';
1
2
  interface InitOptions {
2
3
  dryRun: boolean;
3
4
  force: boolean;
5
+ styles: StreamStyles;
4
6
  withConfig: boolean;
5
7
  }
6
8
  /**
@@ -9,5 +11,5 @@ interface InitOptions {
9
11
  * Checks eligibility, detects repo type, scaffolds files, and prints next steps.
10
12
  * Returns the process exit code (0 for success, 1 for failure).
11
13
  */
12
- export declare function initCommand({ dryRun, force, withConfig }: InitOptions): number;
14
+ export declare function initCommand({ dryRun, force, styles, withConfig }: InitOptions): number;
13
15
  export {};
@@ -1,36 +1,36 @@
1
- import { printError, printStep, printSuccess, reportWriteResult } from '@williamthorsen/nmr-core';
1
+ import { printError, printStep, printSuccess, reportWriteResult, } from '@williamthorsen/nmr-core';
2
2
  import { describeError } from '@williamthorsen/toolbelt.errors';
3
3
  import { hasPackageJson, isGitRepo, usesPnpm } from "./checks.js";
4
4
  import { detectRepoType } from "./detectRepoType.js";
5
5
  import { scaffoldFiles } from "./scaffold.js";
6
- function runRequiredCheck(label, result) {
6
+ function runRequiredCheck(label, result, styles) {
7
7
  if (result.ok) {
8
- printSuccess(label);
8
+ printSuccess(label, styles.stdout);
9
9
  return true;
10
10
  }
11
- printError(result.message ?? `${label} failed`);
11
+ printError(result.message ?? `${label} failed`, styles.stderr);
12
12
  return false;
13
13
  }
14
- function checkEligibility() {
14
+ function checkEligibility(styles) {
15
15
  printStep('Checking eligibility');
16
- if (!runRequiredCheck('Git repository detected', isGitRepo()))
16
+ if (!runRequiredCheck('Git repository detected', isGitRepo(), styles))
17
17
  return false;
18
- if (!runRequiredCheck('package.json found', hasPackageJson()))
18
+ if (!runRequiredCheck('package.json found', hasPackageJson(), styles))
19
19
  return false;
20
- if (!runRequiredCheck('pnpm detected', usesPnpm()))
20
+ if (!runRequiredCheck('pnpm detected', usesPnpm(), styles))
21
21
  return false;
22
22
  return true;
23
23
  }
24
- export function initCommand({ dryRun, force, withConfig }) {
24
+ export function initCommand({ dryRun, force, styles, withConfig }) {
25
25
  if (dryRun) {
26
26
  console.info('[dry-run mode]');
27
27
  }
28
28
  let eligible;
29
29
  try {
30
- eligible = checkEligibility();
30
+ eligible = checkEligibility(styles);
31
31
  }
32
32
  catch (error) {
33
- printError(`Eligibility check failed: ${describeError(error)}`);
33
+ printError(`Eligibility check failed: ${describeError(error)}`, styles.stderr);
34
34
  return 1;
35
35
  }
36
36
  if (!eligible)
@@ -41,21 +41,21 @@ export function initCommand({ dryRun, force, withConfig }) {
41
41
  repoType = detectRepoType();
42
42
  }
43
43
  catch (error) {
44
- printError(`Failed to detect repo type: ${describeError(error)}`);
44
+ printError(`Failed to detect repo type: ${describeError(error)}`, styles.stderr);
45
45
  return 1;
46
46
  }
47
- printSuccess(`Detected: ${repoType}`);
47
+ printSuccess(`Detected: ${repoType}`, styles.stdout);
48
48
  printStep('Scaffolding files');
49
49
  let results;
50
50
  try {
51
51
  results = scaffoldFiles({ repoType, dryRun, overwrite: force, withConfig });
52
52
  }
53
53
  catch (error) {
54
- printError(`Failed to scaffold files: ${describeError(error)}`);
54
+ printError(`Failed to scaffold files: ${describeError(error)}`, styles.stderr);
55
55
  return 1;
56
56
  }
57
57
  for (const result of results) {
58
- reportWriteResult(result, dryRun);
58
+ reportWriteResult(result, dryRun, styles);
59
59
  }
60
60
  if (results.some((r) => r.outcome === 'failed')) {
61
61
  return 1;
@@ -1,3 +1,4 @@
1
+ import { type OutputStyle } from '@williamthorsen/nmr-core';
1
2
  import type { ReleaseKitConfig } from './types.js';
2
3
  /**
3
4
  * Outcome of loading and validating the consumer config file. `missing` is not reported
@@ -15,4 +16,4 @@ export type LoadValidatedConfigResult = {
15
16
  * Load `.config/release-kit.config.ts` and validate it against the shared schema,
16
17
  * reporting load failures and validation errors to stderr.
17
18
  */
18
- export declare function loadValidatedConfig(): Promise<LoadValidatedConfigResult>;
19
+ export declare function loadValidatedConfig(stderrStyle: OutputStyle): Promise<LoadValidatedConfigResult>;
@@ -1,8 +1,8 @@
1
- import { reportError } from '@williamthorsen/nmr-core';
1
+ import { printError, reportError } from '@williamthorsen/nmr-core';
2
2
  import { describeError } from '@williamthorsen/toolbelt.errors';
3
3
  import { loadConfig } from "./loadConfig.js";
4
4
  import { validateConfig } from "./validateConfig.js";
5
- export async function loadValidatedConfig() {
5
+ export async function loadValidatedConfig(stderrStyle) {
6
6
  let raw;
7
7
  try {
8
8
  raw = await loadConfig();
@@ -19,7 +19,7 @@ export async function loadValidatedConfig() {
19
19
  if (errors.length > 0) {
20
20
  process.stderr.write('Invalid config:\n');
21
21
  for (const err of errors) {
22
- process.stderr.write(` ❌ ${err}\n`);
22
+ printError(err, stderrStyle);
23
23
  }
24
24
  return { status: 'invalid' };
25
25
  }
@@ -15,10 +15,9 @@ export type PolicyViolationSurface = 'prefix' | 'body';
15
15
  /**
16
16
  * Callback invoked when `parseCommitMessage` detects a `!`-policy violation.
17
17
  *
18
- * Two-tier policy: at write-time (commit-msg hook, OOS for ticket #355), violations are
19
- * rejected outright; at release-time (this parser), violations are warn-and-continue so
20
- * legacy log entries don't block releases. Callers (`decideRelease`, `releasePrepareMono`,
21
- * etc.) collect callback invocations and surface them in the release report.
18
+ * The parser warns and continues on a violation, so legacy log entries don't block releases.
19
+ * Callers (`decideRelease`, `releasePrepareMono`, etc.) collect callback invocations and
20
+ * surface them in the release report.
22
21
  */
23
22
  export type PolicyViolationHandler = (commit: Commit, type: string, surface: PolicyViolationSurface) => void;
24
23
  /** Optional configuration for `parseCommitMessage` beyond the core inputs. */
@@ -47,6 +46,6 @@ export interface ParseCommitMessageOptions {
47
46
  * `!`-policy enforcement is **release-time tolerant**: when the resolved type's policy
48
47
  * forbids `!`, the marker is dropped from the parse (`breaking: false`) and
49
48
  * `onPolicyViolation` is invoked. When the policy requires `!`, a bare type triggers the
50
- * same warning path. The strict write-time gate (commit-msg hook) is out of scope.
49
+ * same warning path.
51
50
  */
52
51
  export declare function parseCommitMessage(message: string, hash: string, workTypes: Record<string, WorkTypeConfig>, scopeAliases?: Record<string, string>, options?: ParseCommitMessageOptions): ParsedCommit | undefined;
@@ -1,3 +1,4 @@
1
+ import { type StreamStyles } from '@williamthorsen/nmr-core';
1
2
  import type { ReleaseType } from './types.js';
2
3
  export declare const prepareFlagSchema: {
3
4
  dryRun: {
@@ -49,4 +50,4 @@ export declare function parseArgs(argv: string[]): {
49
50
  * 4. Delegates to `releasePrepare` or `releasePrepareMono` to compute the release plan.
50
51
  * 5. Applies the plan, runs the format command, and prints the result via `reportPrepare`.
51
52
  */
52
- export declare function prepareCommand(argv: string[]): Promise<void>;
53
+ export declare function prepareCommand(argv: string[], styles: StreamStyles): Promise<void>;
@@ -1,11 +1,12 @@
1
1
  import { execSync } from 'node:child_process';
2
- import { parseArgsOrExit, reportError } from '@williamthorsen/nmr-core';
2
+ import { formatGlyphLine, formatStatusLine, parseArgsOrExit, printError, reportError, } from '@williamthorsen/nmr-core';
3
3
  import { describeError } from '@williamthorsen/toolbelt.errors';
4
4
  import { assertCleanWorkingTree } from "./assertCleanWorkingTree.js";
5
5
  import { buildDependencyGraph } from "./buildDependencyGraph.js";
6
6
  import { discoverWorkspaces } from "./discoverWorkspaces.js";
7
7
  import { dim } from "./format.js";
8
8
  import { getCommitsSinceTarget } from "./getCommitsSinceTarget.js";
9
+ import { RELEASE_GLYPHS } from "./glyphs.js";
9
10
  import { loadConfig, mergeMonorepoConfig, mergeSinglePackageConfig, readRootPackageVersion } from "./loadConfig.js";
10
11
  import { RELEASE_SUMMARY_FILE, RELEASE_TAGS_FILE } from "./releaseFiles.js";
11
12
  import { applyReleasePlan } from "./releasePlan.js";
@@ -72,7 +73,7 @@ export function parseArgs(argv) {
72
73
  withReleaseNotes: flags.withReleaseNotes,
73
74
  };
74
75
  }
75
- export async function prepareCommand(argv) {
76
+ export async function prepareCommand(argv, styles) {
76
77
  const { dryRun, force, noGitChecks, bumpOverride, only, setVersion, withReleaseNotes } = parseArgs(argv);
77
78
  const options = {
78
79
  force,
@@ -81,7 +82,7 @@ export async function prepareCommand(argv) {
81
82
  ...(withReleaseNotes && { withReleaseNotes: true }),
82
83
  };
83
84
  if (dryRun) {
84
- console.info('\n🔍 DRY RUN — no files will be modified\n');
85
+ console.info(`\n${formatGlyphLine(RELEASE_GLYPHS, styles.stdout, 'dryRun', 'DRY RUN — no files will be modified')}\n`);
85
86
  }
86
87
  if (!dryRun && !noGitChecks) {
87
88
  try {
@@ -92,7 +93,7 @@ export async function prepareCommand(argv) {
92
93
  process.exit(1);
93
94
  }
94
95
  }
95
- const userConfig = await loadAndValidateConfig();
96
+ const userConfig = await loadAndValidateConfig(styles.stderr);
96
97
  let discoveredPaths;
97
98
  try {
98
99
  discoveredPaths = await discoverWorkspaces();
@@ -102,13 +103,13 @@ export async function prepareCommand(argv) {
102
103
  process.exit(1);
103
104
  }
104
105
  if (discoveredPaths === undefined) {
105
- runSinglePackageMode(userConfig, options, only, dryRun);
106
+ runSinglePackageMode(userConfig, options, only, dryRun, styles.stdout);
106
107
  }
107
108
  else {
108
- runMonorepoMode(discoveredPaths, userConfig, options, only, setVersion, dryRun);
109
+ runMonorepoMode(discoveredPaths, userConfig, options, only, setVersion, dryRun, styles.stdout);
109
110
  }
110
111
  }
111
- function runSinglePackageMode(userConfig, options, only, dryRun) {
112
+ function runSinglePackageMode(userConfig, options, only, dryRun, style) {
112
113
  if (only !== undefined) {
113
114
  reportError('--only is only supported for monorepo configurations');
114
115
  process.exit(1);
@@ -119,9 +120,9 @@ function runSinglePackageMode(userConfig, options, only, dryRun) {
119
120
  process.exit(1);
120
121
  }
121
122
  const config = mergeSinglePackageConfig(userConfig);
122
- runAndReport(() => releasePrepare(config, options), dryRun);
123
+ runAndReport(() => releasePrepare(config, options), dryRun, style);
123
124
  }
124
- function runMonorepoMode(discoveredPaths, userConfig, options, only, setVersion, dryRun) {
125
+ function runMonorepoMode(discoveredPaths, userConfig, options, only, setVersion, dryRun, style) {
125
126
  let config;
126
127
  try {
127
128
  const rootPackage = readRootPackageVersion();
@@ -177,9 +178,9 @@ function runMonorepoMode(discoveredPaths, userConfig, options, only, setVersion,
177
178
  process.exit(1);
178
179
  }
179
180
  }
180
- runAndReport(() => releasePrepareMono(config, { ...options, ...(only !== undefined && { only }) }), dryRun);
181
+ runAndReport(() => releasePrepareMono(config, { ...options, ...(only !== undefined && { only }) }), dryRun, style);
181
182
  }
182
- async function loadAndValidateConfig() {
183
+ async function loadAndValidateConfig(stderrStyle) {
183
184
  let rawConfig;
184
185
  try {
185
186
  rawConfig = await loadConfig();
@@ -195,16 +196,16 @@ async function loadAndValidateConfig() {
195
196
  if (errors.length > 0) {
196
197
  process.stderr.write('Invalid config:\n');
197
198
  for (const err of errors) {
198
- process.stderr.write(` ❌ ${err}\n`);
199
+ printError(err, stderrStyle);
199
200
  }
200
201
  process.exit(1);
201
202
  }
202
203
  for (const warning of warnings) {
203
- console.warn(` ⚠️ ${warning}`);
204
+ console.warn(` ${formatStatusLine(stderrStyle, 'warning', warning)}`);
204
205
  }
205
206
  return config;
206
207
  }
207
- function runAndReport(computePlan, dryRun) {
208
+ function runAndReport(computePlan, dryRun, style) {
208
209
  let plan;
209
210
  try {
210
211
  plan = computePlan();
@@ -215,7 +216,7 @@ function runAndReport(computePlan, dryRun) {
215
216
  process.exit(1);
216
217
  }
217
218
  if (dryRun) {
218
- process.stdout.write(reportPrepare(plan, { applied: false }) + '\n');
219
+ process.stdout.write(reportPrepare(plan, { applied: false, style }) + '\n');
219
220
  reportPlanFiles(plan, true);
220
221
  return;
221
222
  }
@@ -227,7 +228,7 @@ function runAndReport(computePlan, dryRun) {
227
228
  process.exit(1);
228
229
  }
229
230
  const formatError = runFormatCommand(plan.formatCommand);
230
- process.stdout.write(reportPrepare(plan, { applied: true, ...(formatError !== undefined && { formatError }) }) + '\n');
231
+ process.stdout.write(reportPrepare(plan, { applied: true, style, ...(formatError !== undefined && { formatError }) }) + '\n');
231
232
  reportPlanFiles(plan, false);
232
233
  if (formatError !== undefined) {
233
234
  reportError(`The format command failed, but the release is prepared and ${RELEASE_TAGS_FILE} is written. ` +
@@ -1,5 +1,6 @@
1
+ import { type StreamStyles } from '@williamthorsen/nmr-core';
1
2
  /**
2
3
  * Orchestrate the CLI `publish` command: parse flags, discover workspaces, resolve tags from HEAD,
3
4
  * detect the package manager, validate `--tags`, and publish each tag with inject/restore lifecycle.
4
5
  */
5
- export declare function publishCommand(argv: string[]): Promise<void>;
6
+ export declare function publishCommand(argv: string[], styles: StreamStyles): Promise<void>;
@@ -16,7 +16,7 @@ const publishFlagSchema = {
16
16
  provenance: { long: '--provenance', type: 'boolean' },
17
17
  tags: { long: '--tags', type: 'string' },
18
18
  };
19
- export async function publishCommand(argv) {
19
+ export async function publishCommand(argv, styles) {
20
20
  const parsed = parseArgsOrExit(argv, publishFlagSchema);
21
21
  const { dryRun, noGitChecks, provenance } = parsed.flags;
22
22
  if (!dryRun && !noGitChecks) {
@@ -39,7 +39,7 @@ export async function publishCommand(argv) {
39
39
  return;
40
40
  }
41
41
  const packageManager = detectPackageManager();
42
- const { releaseNotes, changelogJsonOutputPath, sectionOrder } = await resolveReleaseNotesConfig();
42
+ const { releaseNotes, changelogJsonOutputPath, sectionOrder } = await resolveReleaseNotesConfig(styles.stderr);
43
43
  const shouldInject = releaseNotes.shouldInjectIntoReadme;
44
44
  console.info(dryRun ? '[dry-run] Would publish:' : 'Publishing:');
45
45
  for (const { tag, workspacePath } of publishableTags) {
@@ -1,3 +1,4 @@
1
+ import { type OutputStyle } from '@williamthorsen/nmr-core';
1
2
  import type { PrepareResult } from './types.js';
2
3
  /** How the plan was carried out, which decides the tense the report is rendered in. */
3
4
  export interface ReportPrepareOptions {
@@ -5,6 +6,7 @@ export interface ReportPrepareOptions {
5
6
  applied: boolean;
6
7
  /** The format command's failure message, when it ran and failed. */
7
8
  formatError?: string;
9
+ style: OutputStyle;
8
10
  }
9
11
  /**
10
12
  * Format a release plan into styled terminal output.