@williamthorsen/release-kit 14.2.2 โ†’ 14.2.4

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 (85) hide show
  1. package/.meta/changelog.json +88 -0
  2. package/.readyup/kits/default.js +135 -145
  3. package/.readyup/kits/npm-auto-publish.js +179 -180
  4. package/.readyup/manifest.json +31 -17
  5. package/CHANGELOG.md +35 -0
  6. package/README.md +7 -1
  7. package/dist/esm/applyChangelogOverrides.d.ts +50 -0
  8. package/dist/esm/applyChangelogOverrides.js +162 -0
  9. package/dist/esm/attachChangelogDiagnostics.d.ts +1 -1
  10. package/dist/esm/bin/release-kit.js +6 -238
  11. package/dist/esm/buildChangelogEntries.d.ts +24 -35
  12. package/dist/esm/buildChangelogEntries.js +71 -188
  13. package/dist/esm/buildChangelogItem.d.ts +58 -0
  14. package/dist/esm/buildChangelogItem.js +122 -0
  15. package/dist/esm/buildReleasedResult.d.ts +20 -0
  16. package/dist/esm/buildReleasedResult.js +78 -0
  17. package/dist/esm/changelogJsonUtils.d.ts +1 -1
  18. package/dist/esm/changelogOverrides.d.ts +29 -143
  19. package/dist/esm/changelogOverrides.js +35 -467
  20. package/dist/esm/configSchema.d.ts +225 -0
  21. package/dist/esm/configSchema.js +103 -0
  22. package/dist/esm/decideDirectReleases.d.ts +30 -0
  23. package/dist/esm/decideDirectReleases.js +66 -0
  24. package/dist/esm/defineConfig.d.ts +2 -2
  25. package/dist/esm/deriveReleaseNotesConfig.d.ts +2 -1
  26. package/dist/esm/deriveReleaseNotesConfig.js +1 -1
  27. package/dist/esm/formatPrepareFiles.d.ts +11 -0
  28. package/dist/esm/formatPrepareFiles.js +55 -0
  29. package/dist/esm/formatPrepareWarnings.d.ts +26 -0
  30. package/dist/esm/formatPrepareWarnings.js +72 -0
  31. package/dist/esm/help/initHelp.d.ts +4 -0
  32. package/dist/esm/help/initHelp.js +31 -0
  33. package/dist/esm/help/overridesHelp.d.ts +4 -0
  34. package/dist/esm/help/overridesHelp.js +32 -0
  35. package/dist/esm/help/releaseStepsHelp.d.ts +12 -0
  36. package/dist/esm/help/releaseStepsHelp.js +91 -0
  37. package/dist/esm/help/syncLabelsHelp.d.ts +8 -0
  38. package/dist/esm/help/syncLabelsHelp.js +55 -0
  39. package/dist/esm/help/usage.d.ts +2 -0
  40. package/dist/esm/help/usage.js +29 -0
  41. package/dist/esm/index.d.ts +1 -1
  42. package/dist/esm/index.js +1 -1
  43. package/dist/esm/loadChangelogOverrides.d.ts +31 -0
  44. package/dist/esm/loadChangelogOverrides.js +138 -0
  45. package/dist/esm/loadConfig.d.ts +0 -40
  46. package/dist/esm/loadConfig.js +0 -240
  47. package/dist/esm/loadValidatedConfig.d.ts +1 -1
  48. package/dist/esm/mergeConfig.d.ts +41 -0
  49. package/dist/esm/mergeConfig.js +118 -0
  50. package/dist/esm/monorepoConfigAssertions.d.ts +49 -0
  51. package/dist/esm/monorepoConfigAssertions.js +126 -0
  52. package/dist/esm/planChangelogFiles.d.ts +16 -0
  53. package/dist/esm/planChangelogFiles.js +41 -0
  54. package/dist/esm/prepareArgs.d.ts +55 -0
  55. package/dist/esm/prepareArgs.js +69 -0
  56. package/dist/esm/prepareCommand.d.ts +0 -48
  57. package/dist/esm/prepareCommand.js +6 -73
  58. package/dist/esm/prepareComposite.d.ts +16 -0
  59. package/dist/esm/prepareComposite.js +39 -0
  60. package/dist/esm/prepareRunContext.d.ts +38 -0
  61. package/dist/esm/prepareRunContext.js +39 -0
  62. package/dist/esm/prepareTarget.d.ts +2 -7
  63. package/dist/esm/prepareTarget.js +2 -118
  64. package/dist/esm/previewTagPrefixes.d.ts +1 -1
  65. package/dist/esm/releasePrepareTargets.js +13 -205
  66. package/dist/esm/reportPrepare.js +3 -125
  67. package/dist/esm/resolveCommandTags.d.ts +1 -1
  68. package/dist/esm/resolveCommandTags.js +2 -1
  69. package/dist/esm/resolveReleaseDeclaration.d.ts +2 -1
  70. package/dist/esm/resolveReleaseTargets.d.ts +2 -1
  71. package/dist/esm/resolveReleaseTargets.js +2 -1
  72. package/dist/esm/sync-labels/generateCommand.d.ts +1 -1
  73. package/dist/esm/sync-labels/resolveLabels.d.ts +1 -1
  74. package/dist/esm/topologicalSort.d.ts +12 -0
  75. package/dist/esm/topologicalSort.js +60 -0
  76. package/dist/esm/types.d.ts +1 -225
  77. package/dist/esm/types.js +1 -103
  78. package/dist/esm/validateAllChangelogOverrides.d.ts +56 -0
  79. package/dist/esm/validateAllChangelogOverrides.js +138 -0
  80. package/dist/esm/validateConfig.d.ts +1 -1
  81. package/dist/esm/validateConfig.js +7 -9
  82. package/dist/esm/validateOverridesCommand.d.ts +1 -1
  83. package/dist/esm/validateOverridesCommand.js +2 -1
  84. package/docs/changelogs.md +6 -4
  85. package/package.json +4 -4
@@ -1,6 +1,6 @@
1
1
  /** @noformat -- @generated. Do not edit. Compiled by rdy. */
2
2
  /* eslint-disable */
3
- export const __readyupVersion = "0.41.0";
3
+ export const __readyupVersion = "0.42.0";
4
4
 
5
5
 
6
6
  // .readyup/kits/npm-auto-publish.ts
@@ -13,16 +13,10 @@ import {
13
13
  fileContains,
14
14
  fileExists,
15
15
  getJsonValue,
16
- isRecord as isRecord2,
17
16
  readFile,
18
17
  readJsonFile
19
18
  } from "readyup/check-utils";
20
19
 
21
- // src/init/hasProvenance.ts
22
- function hasProvenance(workflowContent) {
23
- return /^[^#]*provenance:\s*['"]?true['"]?/im.test(workflowContent);
24
- }
25
-
26
20
  // src/npmRegistry.ts
27
21
  import { execFileSync } from "node:child_process";
28
22
 
@@ -87,10 +81,169 @@ function runNpmJson(args) {
87
81
  }
88
82
  }
89
83
 
90
- // .readyup/kits/npm-auto-publish.ts
84
+ // .readyup/lib/npm-trust.ts
85
+ import { isRecord as isRecord2 } from "readyup/check-utils";
86
+
87
+ // src/init/hasProvenance.ts
88
+ function hasProvenance(workflowContent) {
89
+ return /^[^#]*provenance:\s*['"]?true['"]?/im.test(workflowContent);
90
+ }
91
+
92
+ // .readyup/lib/npm-trust.ts
91
93
  var OTP_ERROR_CODE = "EOTP";
92
94
  var PUBLISH_WORKFLOW_FILE = "publish.yaml";
93
95
  var NO_GITHUB_REMOTE_FIX = "Add an origin remote that points to the GitHub repo, then run this check again";
96
+ function classifyNpmAuth(result) {
97
+ if (result.exitOk) {
98
+ return { status: "authenticated" };
99
+ }
100
+ const error = readNpmError(result.stdout);
101
+ if (error === void 0) {
102
+ return { status: "unreachable", detail: "The npm registry query failed without a readable error payload" };
103
+ }
104
+ if (AUTH_ERROR_CODES.has(error.code)) {
105
+ return { status: "unauthenticated", detail: `The npm registry rejected the session (${error.code})` };
106
+ }
107
+ if (UNREACHABLE_ERROR_CODES.has(error.code)) {
108
+ return { status: "unreachable", detail: `Cannot reach the npm registry (${error.code})` };
109
+ }
110
+ return { status: "unreachable", detail: `The npm registry query failed (${error.code}): ${error.summary}` };
111
+ }
112
+ function classifyProvenanceSetting(workflowContent, visibility) {
113
+ if (workflowContent === void 0) {
114
+ return {
115
+ ok: false,
116
+ detail: "Cannot read .github/workflows/publish.yaml",
117
+ fix: "Check the file's permissions"
118
+ };
119
+ }
120
+ if (typeof visibility !== "string") {
121
+ return { ok: false, detail: visibility.detail, fix: NO_GITHUB_REMOTE_FIX };
122
+ }
123
+ if (visibility === "unknown") {
124
+ return {
125
+ ok: false,
126
+ detail: "The GitHub CLI could not report the repo's visibility",
127
+ fix: "Install and authenticate the GitHub CLI: gh auth login"
128
+ };
129
+ }
130
+ const provenance = hasProvenance(workflowContent);
131
+ if (visibility === "public" && !provenance) {
132
+ return {
133
+ ok: false,
134
+ detail: "The repo is public and publish.yaml does not set provenance: true",
135
+ fix: "Set provenance: true in .github/workflows/publish.yaml; public repos should generate provenance attestations"
136
+ };
137
+ }
138
+ if (visibility === "private" && provenance) {
139
+ return {
140
+ ok: false,
141
+ detail: "The repo is private and publish.yaml sets provenance: true",
142
+ fix: "Make the GitHub repo public; OIDC publishing with provenance requires a public repo"
143
+ };
144
+ }
145
+ return { ok: true };
146
+ }
147
+ function classifyTrustCapability(auth, probe) {
148
+ if (auth.status !== "authenticated") {
149
+ return { ok: false, detail: auth.detail };
150
+ }
151
+ return probe?.status === "unanswerable" ? { ok: false, detail: probe.detail } : { ok: true };
152
+ }
153
+ function classifyTrustQuery(result, expectedRepo, expectedFile) {
154
+ if (!result.exitOk) {
155
+ const error = readNpmError(result.stdout);
156
+ if (error === void 0) {
157
+ return { status: "error", detail: "The npm trust query failed without a readable error payload" };
158
+ }
159
+ if (error.code === "E404") {
160
+ return { status: "not-configured" };
161
+ }
162
+ if (AUTH_ERROR_CODES.has(error.code) || error.code === OTP_ERROR_CODE) {
163
+ return {
164
+ status: "unanswerable",
165
+ detail: `The npm session cannot answer trust queries (${error.code}): ${error.summary}`
166
+ };
167
+ }
168
+ if (UNREACHABLE_ERROR_CODES.has(error.code)) {
169
+ return { status: "unanswerable", detail: `Cannot reach the npm registry (${error.code})` };
170
+ }
171
+ return { status: "error", detail: `The npm trust query failed (${error.code}): ${error.summary}` };
172
+ }
173
+ const relationships = readTrustRelationships(result.stdout);
174
+ if (relationships === void 0) {
175
+ return { status: "error", detail: "The npm trust query returned a payload that this check cannot read" };
176
+ }
177
+ if (relationships.length === 0) {
178
+ return { status: "not-configured" };
179
+ }
180
+ if (!expectedRepo.ok) {
181
+ return {
182
+ status: "error",
183
+ detail: `Cannot compare the trusted publisher with this repo; found ${describeTrustRelationships(relationships)}`
184
+ };
185
+ }
186
+ const isMatch = relationships.some(
187
+ (relationship) => relationship.type === "github" && relationship.repository === expectedRepo.value && relationship.file === expectedFile
188
+ );
189
+ return isMatch ? { status: "configured" } : {
190
+ status: "mismatched",
191
+ detail: `Expected github ${expectedRepo.value} (${expectedFile}); found ${describeTrustRelationships(relationships)}`
192
+ };
193
+ }
194
+ function describeNpmPackageLookup(lookup) {
195
+ if (lookup.status === "published") {
196
+ return { ok: true };
197
+ }
198
+ if (lookup.status === "unpublished") {
199
+ return { ok: false, detail: "The npm registry does not list this package" };
200
+ }
201
+ return {
202
+ ok: false,
203
+ detail: lookup.detail,
204
+ fix: "Restore access to the npm registry, then run this check again"
205
+ };
206
+ }
207
+ function describeTrustedPublisher(result, packageName, ownerRepo) {
208
+ if (result.status === "configured") {
209
+ return { ok: true };
210
+ }
211
+ const detail = result.status === "not-configured" ? "The npm registry does not list any trusted publisher for this package" : result.detail;
212
+ return ownerRepo.ok ? { ok: false, detail, fix: formatTrustCommand(packageName, ownerRepo.value) } : { ok: false, detail: `${detail}. ${ownerRepo.detail}`, fix: NO_GITHUB_REMOTE_FIX };
213
+ }
214
+ function formatTrustCommand(packageName, ownerRepo) {
215
+ return `Run: npm trust github ${packageName} --repo ${ownerRepo} --file ${PUBLISH_WORKFLOW_FILE}`;
216
+ }
217
+ function parseGitHubOwnerRepo(url) {
218
+ const match = /git@github\.com:(.+?)(?:\.git)?$/.exec(url) ?? /github\.com\/(.+?)(?:\.git)?$/.exec(url);
219
+ const ownerRepo = match?.[1];
220
+ return ownerRepo === void 0 ? { ok: false, detail: `The origin remote does not point to GitHub: ${url}` } : { ok: true, value: ownerRepo };
221
+ }
222
+ function describeTrustRelationships(relationships) {
223
+ return relationships.map((relationship) => {
224
+ const type = typeof relationship.type === "string" ? relationship.type : "(unknown)";
225
+ const repository = typeof relationship.repository === "string" ? relationship.repository : "(unknown)";
226
+ const file = typeof relationship.file === "string" ? relationship.file : "(unknown)";
227
+ return `${type} ${repository} (${file})`;
228
+ }).join(", ");
229
+ }
230
+ function readTrustRelationships(stdout) {
231
+ let parsed;
232
+ try {
233
+ parsed = JSON.parse(stdout);
234
+ } catch {
235
+ return void 0;
236
+ }
237
+ if (Array.isArray(parsed)) {
238
+ return parsed.filter((entry) => isRecord2(entry) && "type" in entry);
239
+ }
240
+ if (!isRecord2(parsed)) {
241
+ return void 0;
242
+ }
243
+ return "type" in parsed ? [parsed] : [];
244
+ }
245
+
246
+ // .readyup/kits/npm-auto-publish.ts
94
247
  var repoChecklist = defineRdyChecklist({
95
248
  name: "repo",
96
249
  checks: [
@@ -139,25 +292,28 @@ var packagesChecklist = defineRdyChecklist({
139
292
  fix: "Ensure pnpm-workspace.yaml lists package globs, or that a root package.json exists"
140
293
  }
141
294
  ],
142
- // The session gate is a sibling of the workspace rows, not their parent, so a session that cannot answer trust
143
- // queries suppresses only the trusted-publisher rows and leaves the package.json checks reporting. The gate's skip
144
- // therefore does not cover the rows, and this getter omits them for a repo that publishes nothing.
145
- get checks() {
146
- const sessionCheck = buildSessionCheck();
147
- if (skipIfNothingPublishable() !== false) {
148
- return [sessionCheck];
295
+ checks: [
296
+ {
297
+ name: "Repo publishes at least one package",
298
+ skip: () => skipIfNothingPublishable(),
299
+ check: () => true,
300
+ // Built when the checklist runs, so that the kit declares the same checks wherever it is imported. The session
301
+ // gate is a sibling of the workspace rows, not their parent, so a session that cannot answer trust queries
302
+ // suppresses only the trusted-publisher rows and leaves the package.json checks reporting.
303
+ checks: () => [
304
+ buildSessionCheck(),
305
+ ...discoverWorkspaces({ filter: belongsInPackagesChecklist }).map(
306
+ (workspace) => buildWorkspaceCheck(workspace)
307
+ )
308
+ ]
149
309
  }
150
- return [
151
- sessionCheck,
152
- ...discoverWorkspaces({ filter: belongsInPackagesChecklist }).map((workspace) => buildWorkspaceCheck(workspace))
153
- ];
154
- }
310
+ ]
155
311
  });
156
312
  var npm_auto_publish_default = defineRdyKit({
157
313
  fixLocation: "inline",
158
- // The release that introduced `CheckOutcome.fix`, on which the provenance check's remediation depends. Because an
159
- // older runner drops that `fix` silently, failing to load the kit is the lesser harm.
160
- minReadyupVersion: "0.37.0",
314
+ // The release that introduced a function-valued `checks`, which builds the per-package rows. An older runner rejects
315
+ // it when validating the kit.
316
+ minReadyupVersion: "0.42.0",
161
317
  checklists: [repoChecklist, packagesChecklist]
162
318
  });
163
319
  function belongsInPackagesChecklist(workspace) {
@@ -166,7 +322,6 @@ function belongsInPackagesChecklist(workspace) {
166
322
  function buildSessionCheck() {
167
323
  return {
168
324
  name: "npm session can answer trust queries",
169
- skip: () => skipIfNothingPublishable(),
170
325
  check: () => {
171
326
  const capability = getCachedTrustCapability();
172
327
  return capability.ok ? { ok: true } : { ok: false, detail: capability.detail };
@@ -247,135 +402,6 @@ function checkProvenanceMatchesVisibility() {
247
402
  }
248
403
  return classifyProvenanceSetting(content, visibility);
249
404
  }
250
- function classifyNpmAuth(result) {
251
- if (result.exitOk) {
252
- return { status: "authenticated" };
253
- }
254
- const error = readNpmError(result.stdout);
255
- if (error === void 0) {
256
- return { status: "unreachable", detail: "The npm registry query failed without a readable error payload" };
257
- }
258
- if (AUTH_ERROR_CODES.has(error.code)) {
259
- return { status: "unauthenticated", detail: `The npm registry rejected the session (${error.code})` };
260
- }
261
- if (UNREACHABLE_ERROR_CODES.has(error.code)) {
262
- return { status: "unreachable", detail: `Cannot reach the npm registry (${error.code})` };
263
- }
264
- return { status: "unreachable", detail: `The npm registry query failed (${error.code}): ${error.summary}` };
265
- }
266
- function classifyProvenanceSetting(workflowContent, visibility) {
267
- if (workflowContent === void 0) {
268
- return {
269
- ok: false,
270
- detail: "Cannot read .github/workflows/publish.yaml",
271
- fix: "Check the file's permissions"
272
- };
273
- }
274
- if (typeof visibility !== "string") {
275
- return { ok: false, detail: visibility.detail, fix: NO_GITHUB_REMOTE_FIX };
276
- }
277
- if (visibility === "unknown") {
278
- return {
279
- ok: false,
280
- detail: "The GitHub CLI could not report the repo's visibility",
281
- fix: "Install and authenticate the GitHub CLI: gh auth login"
282
- };
283
- }
284
- const provenance = hasProvenance(workflowContent);
285
- if (visibility === "public" && !provenance) {
286
- return {
287
- ok: false,
288
- detail: "The repo is public and publish.yaml does not set provenance: true",
289
- fix: "Set provenance: true in .github/workflows/publish.yaml; public repos should generate provenance attestations"
290
- };
291
- }
292
- if (visibility === "private" && provenance) {
293
- return {
294
- ok: false,
295
- detail: "The repo is private and publish.yaml sets provenance: true",
296
- fix: "Make the GitHub repo public; OIDC publishing with provenance requires a public repo"
297
- };
298
- }
299
- return { ok: true };
300
- }
301
- function classifyTrustCapability(auth, probe) {
302
- if (auth.status !== "authenticated") {
303
- return { ok: false, detail: auth.detail };
304
- }
305
- return probe?.status === "unanswerable" ? { ok: false, detail: probe.detail } : { ok: true };
306
- }
307
- function classifyTrustQuery(result, expectedRepo, expectedFile) {
308
- if (!result.exitOk) {
309
- const error = readNpmError(result.stdout);
310
- if (error === void 0) {
311
- return { status: "error", detail: "The npm trust query failed without a readable error payload" };
312
- }
313
- if (error.code === "E404") {
314
- return { status: "not-configured" };
315
- }
316
- if (AUTH_ERROR_CODES.has(error.code) || error.code === OTP_ERROR_CODE) {
317
- return {
318
- status: "unanswerable",
319
- detail: `The npm session cannot answer trust queries (${error.code}): ${error.summary}`
320
- };
321
- }
322
- if (UNREACHABLE_ERROR_CODES.has(error.code)) {
323
- return { status: "unanswerable", detail: `Cannot reach the npm registry (${error.code})` };
324
- }
325
- return { status: "error", detail: `The npm trust query failed (${error.code}): ${error.summary}` };
326
- }
327
- const relationships = readTrustRelationships(result.stdout);
328
- if (relationships === void 0) {
329
- return { status: "error", detail: "The npm trust query returned a payload that this check cannot read" };
330
- }
331
- if (relationships.length === 0) {
332
- return { status: "not-configured" };
333
- }
334
- if (!expectedRepo.ok) {
335
- return {
336
- status: "error",
337
- detail: `Cannot compare the trusted publisher with this repo; found ${describeTrustRelationships(relationships)}`
338
- };
339
- }
340
- const isMatch = relationships.some(
341
- (relationship) => relationship.type === "github" && relationship.repository === expectedRepo.value && relationship.file === expectedFile
342
- );
343
- return isMatch ? { status: "configured" } : {
344
- status: "mismatched",
345
- detail: `Expected github ${expectedRepo.value} (${expectedFile}); found ${describeTrustRelationships(relationships)}`
346
- };
347
- }
348
- function describeNpmPackageLookup(lookup) {
349
- if (lookup.status === "published") {
350
- return { ok: true };
351
- }
352
- if (lookup.status === "unpublished") {
353
- return { ok: false, detail: "The npm registry does not list this package" };
354
- }
355
- return {
356
- ok: false,
357
- detail: lookup.detail,
358
- fix: "Restore access to the npm registry, then run this check again"
359
- };
360
- }
361
- function describeTrustedPublisher(result, packageName, ownerRepo) {
362
- if (result.status === "configured") {
363
- return { ok: true };
364
- }
365
- const detail = result.status === "not-configured" ? "The npm registry does not list any trusted publisher for this package" : result.detail;
366
- return ownerRepo.ok ? { ok: false, detail, fix: formatTrustCommand(packageName, ownerRepo.value) } : { ok: false, detail: `${detail}. ${ownerRepo.detail}`, fix: NO_GITHUB_REMOTE_FIX };
367
- }
368
- function describeTrustRelationships(relationships) {
369
- return relationships.map((relationship) => {
370
- const type = typeof relationship.type === "string" ? relationship.type : "(unknown)";
371
- const repository = typeof relationship.repository === "string" ? relationship.repository : "(unknown)";
372
- const file = typeof relationship.file === "string" ? relationship.file : "(unknown)";
373
- return `${type} ${repository} (${file})`;
374
- }).join(", ");
375
- }
376
- function formatTrustCommand(packageName, ownerRepo) {
377
- return `Run: npm trust github ${packageName} --repo ${ownerRepo} --file ${PUBLISH_WORKFLOW_FILE}`;
378
- }
379
405
  var getCachedNpmAuthStatus = /* @__PURE__ */ (() => {
380
406
  let cached;
381
407
  return () => cached ??= classifyNpmAuth(runNpmJson(["whoami", "--json"]));
@@ -422,11 +448,6 @@ function isRepoPrivate(ownerRepo) {
422
448
  }).trim();
423
449
  return result === "true";
424
450
  }
425
- function parseGitHubOwnerRepo(url) {
426
- const match = /git@github\.com:(.+?)(?:\.git)?$/.exec(url) ?? /github\.com\/(.+?)(?:\.git)?$/.exec(url);
427
- const ownerRepo = match?.[1];
428
- return ownerRepo === void 0 ? { ok: false, detail: `The origin remote does not point to GitHub: ${url}` } : { ok: true, value: ownerRepo };
429
- }
430
451
  function probeTrustQuery() {
431
452
  const probeName = selectProbeName();
432
453
  return probeName === void 0 ? void 0 : getTrustQueryResult(probeName);
@@ -435,21 +456,6 @@ function readPublishRegistry(workspace) {
435
456
  const registry = getJsonValue(workspace.packageJson, "publishConfig", "registry");
436
457
  return typeof registry === "string" ? registry : void 0;
437
458
  }
438
- function readTrustRelationships(stdout) {
439
- let parsed;
440
- try {
441
- parsed = JSON.parse(stdout);
442
- } catch {
443
- return void 0;
444
- }
445
- if (Array.isArray(parsed)) {
446
- return parsed.filter((entry) => isRecord2(entry) && "type" in entry);
447
- }
448
- if (!isRecord2(parsed)) {
449
- return void 0;
450
- }
451
- return "type" in parsed ? [parsed] : [];
452
- }
453
459
  function resolveOwnerRepo() {
454
460
  let url;
455
461
  try {
@@ -477,15 +483,8 @@ function skipIfNotPublishable(workspace) {
477
483
  }
478
484
  export {
479
485
  buildWorkspaceCheck,
480
- classifyNpmAuth,
481
- classifyProvenanceSetting,
482
- classifyTrustCapability,
483
- classifyTrustQuery,
484
486
  npm_auto_publish_default as default,
485
- describeNpmPackageLookup,
486
- describeTrustedPublisher,
487
487
  packagesChecklist,
488
- parseGitHubOwnerRepo,
489
488
  selectProbeName,
490
489
  skipIfNotPublishable,
491
490
  skipIfNothingPublishable
@@ -7,7 +7,7 @@
7
7
  "checklist": "release-kit",
8
8
  "checks": [
9
9
  "@williamthorsen/release-kit in devDependencies",
10
- "@williamthorsen/release-kit >= 14.2.2",
10
+ "@williamthorsen/release-kit >= 14.2.4",
11
11
  "release.yaml workflow exists",
12
12
  "release.yaml matches template",
13
13
  "release.yaml does not reference deprecated tag ref",
@@ -43,12 +43,27 @@
43
43
  "esbuildVersion": "0.28.2",
44
44
  "inputs": [
45
45
  {
46
- "hash": "176a18ce",
46
+ "hash": "ad3666b8",
47
47
  "kind": "module",
48
48
  "path": "kits/default.ts"
49
49
  },
50
50
  {
51
- "hash": "92bf79b3",
51
+ "hash": "45fc235f",
52
+ "kind": "module",
53
+ "path": "lib/changelog-checks.ts"
54
+ },
55
+ {
56
+ "hash": "be2c2cb3",
57
+ "kind": "module",
58
+ "path": "lib/config-checks.ts"
59
+ },
60
+ {
61
+ "hash": "290731d6",
62
+ "kind": "module",
63
+ "path": "lib/workflow-hashes.ts"
64
+ },
65
+ {
66
+ "hash": "d2f6e29b",
52
67
  "kind": "inline",
53
68
  "path": "../package.json",
54
69
  "paths": [
@@ -83,10 +98,10 @@
83
98
  ],
84
99
  "name": "default",
85
100
  "path": "kits/default.js",
86
- "readyupVersion": "0.41.0",
101
+ "readyupVersion": "0.42.0",
87
102
  "source": "kits/default.ts",
88
- "sourceHash": "176a18ce",
89
- "targetHash": "f10b7179"
103
+ "sourceHash": "ad3666b8",
104
+ "targetHash": "da678c1d"
90
105
  },
91
106
  {
92
107
  "checklistChecks": [
@@ -104,13 +119,7 @@
104
119
  "checks": [
105
120
  "packageManager field starts with \"pnpm\"",
106
121
  "At least one workspace discovered",
107
- "npm session can answer trust queries",
108
- "@williamthorsen/release-kit",
109
- "repository field exists",
110
- "publishConfig.access is \"public\"",
111
- "published to npm",
112
- "trusted publisher configured",
113
- "files field exists"
122
+ "Repo publishes at least one package"
114
123
  ]
115
124
  }
116
125
  ],
@@ -121,10 +130,15 @@
121
130
  "esbuildVersion": "0.28.2",
122
131
  "inputs": [
123
132
  {
124
- "hash": "66081555",
133
+ "hash": "682fdd4a",
125
134
  "kind": "module",
126
135
  "path": "kits/npm-auto-publish.ts"
127
136
  },
137
+ {
138
+ "hash": "05215737",
139
+ "kind": "module",
140
+ "path": "lib/npm-trust.ts"
141
+ },
128
142
  {
129
143
  "hash": "d360febf",
130
144
  "kind": "module",
@@ -143,10 +157,10 @@
143
157
  ],
144
158
  "name": "npm-auto-publish",
145
159
  "path": "kits/npm-auto-publish.js",
146
- "readyupVersion": "0.41.0",
160
+ "readyupVersion": "0.42.0",
147
161
  "source": "kits/npm-auto-publish.ts",
148
- "sourceHash": "66081555",
149
- "targetHash": "081994f8"
162
+ "sourceHash": "682fdd4a",
163
+ "targetHash": "04adb134"
150
164
  }
151
165
  ]
152
166
  }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 14.2.4 โ€” 2026-10-21
6
+
7
+ ### ๐Ÿ› Bug fixes
8
+
9
+ - Fixes the issue that `release-kit` did not release a workspace whose files a commit changed when that commit scoped every change-record entry to other workspaces; for that workspace, the commit's title now sets the bump and the changelog item. (#1086)
10
+
11
+ ## 14.2.3 โ€” 2026-10-18
12
+
13
+ ### ๐Ÿ› Bug fixes
14
+
15
+ - Fixes the issue that the manifest of the `npm-auto-publish` kit recorded a different list of checks depending on the directory from which `rdy compile` ran, by declaring one fixed check, "Repo publishes at least one package", under which `rdy run` builds the npm session check and the per-package rows. (#1081)
16
+
17
+ ### โ™ป๏ธ Refactoring
18
+
19
+ - Splits `types.ts`, `loadConfig.ts`, `changelogOverrides.ts`, and `buildChangelogEntries.ts` to bring each under the 300-line `max-lines` limit, moving the config zod schemas into `configSchema.ts`, config merging into `mergeConfig.ts`, the cross-target checks into `monorepoConfigAssertions.ts`, override parsing, application, and repo-wide validation into `loadChangelogOverrides.ts`, `applyChangelogOverrides.ts`, and `validateAllChangelogOverrides.ts`, and changelog-item construction into `buildChangelogItem.ts`. (#1067)
20
+ - Splits the `release-kit` bin, the `prepare` pipeline (`prepareCommand`, `prepareTarget`, `releasePrepareTargets`, and `reportPrepare`), and the `default` and `npm-auto-publish` readyup kits into smaller modules under `src`, `src/help`, and `.readyup/lib`, and recompiles the kit bundles without changing their check lists. (#1069)
21
+ - Rewrites the code that the new and widened rules in `eslint-plugin-unicorn` 78 report, mostly by changing `flatMap` callbacks to return a single value rather than a one-element array. (#1072)
22
+
23
+ ### ๐Ÿงช Tests
24
+
25
+ - Splits the `release-kit` unit tests for `releasePrepareTargets`, `reportPrepare`, `prepareCommand`, `publishCommand`, `parseCommitMessage`, and `validateConfig` into `<subject>.<aspect>.unit.test.ts` files that each stay under the `max-lines` limit, and moves the mocks and fixtures that the split files share into modules under `src/test-utils/`. (#1066)
26
+
5
27
  ## 14.2.2 โ€” 2026-10-17
6
28
 
7
29
  ### ๐Ÿ“ฆ Dependencies
@@ -40,6 +62,12 @@ All notable changes to this project will be documented in this file.
40
62
  - Fixes the issue that `release-kit create-github-release` did not create a GitHub Release for the project tag; a private workspace's tag is still skipped. (#1027)
41
63
  - Makes `release-kit publish` skip a project tag named by `--tags` with the warning `Skipping v0.13.0: a project tag is not an npm package.`, since the project does not have an npm package to publish. (#1027)
42
64
 
65
+ ### ๐Ÿ—๏ธ Internal features
66
+
67
+ - Resolve package roots past dual-format marker manifests (#1016)
68
+
69
+ Replaces nmr-core's hand-written package-root and version lookups with `findPackageRoot` and `resolveSelfVersion` re-exported from `@williamthorsen/toolbelt.packaging`, which pass over the `{"type": "commonjs"}` marker manifest of a dual-format layout to reach the package that declares a `name`. `nmr`, `release-kit`, and `v11y-check` switch from `readPackageVersion` to `resolveSelfVersion`, and the boundary guard now holds `toolbelt.packaging`, like `toolbelt.terminal`, to a single importer and a single declarer in nmr-core.
70
+
43
71
  ### โ™ป๏ธ Refactoring
44
72
 
45
73
  - Replaces `releasePrepare`, `releasePrepareMono`, and `releasePrepareProject` with `releasePrepareTargets`, which prepares a release from one list of package and project targets resolved from any config shape. (#1026)
@@ -56,6 +84,13 @@ All notable changes to this project will be documented in this file.
56
84
  - Stops `release-kit init` from scaffolding `publish.yaml` and `create-github-release.yaml` when every package is private, even with `--force`, and removes the provenance and trusted-publisher steps from the next steps that it prints. (#995)
57
85
  - Stops `release-kit update-templates` from re-creating a deleted `publish.yaml` or `create-github-release.yaml` when every package is private, while it still refreshes either workflow that exists. (#995)
58
86
  - Makes `release-kit prepare` refuse, before it writes any file and in a dry run too, to release a publishable package that npm does not list or that it cannot look up, and prints `npm publish --access public` as the fix for each unlisted package. (#996)
87
+ - Let a calling repo choose the runner of the reusable workflows (#997)
88
+
89
+ Makes the reusable `audit`, `create-github-release`, `release`, and `sync-labels` workflows run their jobs on the runner named by the calling repository's `CI_RUNS_ON` configuration variable, such as a self-hosted runner, and keeps `ubuntu-latest` as the default when the variable is unset. Leaves the reusable `publish` workflow on `ubuntu-latest`, because npm generates provenance only on GitHub-hosted runners.
90
+
91
+ - Keep undeclared repo labels and warn about each (#1002)
92
+
93
+ Changes the reusable sync-labels workflow to keep each repository label that `.github/labels.yaml` does not declare, rather than delete it, and to report each such label as a warning annotation on the run and on the pull request's check. A label created by hand now stays in place across syncs until the file declares it or it is deleted with `gh label delete <name>`.
59
94
 
60
95
  ### ๐Ÿ› Bug fixes
61
96
 
package/README.md CHANGED
@@ -6,7 +6,13 @@ Version-bumping and changelog-generation toolkit for release workflows.
6
6
 
7
7
  Provides a self-contained CLI that auto-discovers workspaces from `pnpm-workspace.yaml`, parses conventional commits, determines version bumps, updates `package.json` files, and generates changelogs from the same commit history that decides each bump (with optional [editorial overrides](docs/editorial-overrides.md)).
8
8
 
9
- <!-- section:release-notes --><!-- /section:release-notes -->
9
+ <!-- section:release-notes -->
10
+ ## Release notes โ€” v14.2.4 (2026-10-21)
11
+
12
+ ### ๐Ÿ› Bug fixes
13
+
14
+ - Fixes the issue that `release-kit` did not release a workspace whose files a commit changed when that commit scoped every change-record entry to other workspaces; for that workspace, the commit's title now sets the bump and the changelog item. (#1086)
15
+ <!-- /section:release-notes -->
10
16
 
11
17
  ## Installation
12
18
 
@@ -0,0 +1,50 @@
1
+ import type { ChangelogEntry, ChangelogOverride } from './types.js';
2
+ /**
3
+ * Applies overrides to changelog entries, returning new entries without mutating the input.
4
+ *
5
+ * Each key's hash prefix is matched against the distinct `ChangelogItem.hash` values:
6
+ * - No match: The key is unmatched in this batch, and this function doesn't emit a warning.
7
+ * - One match: A bare key resolves to every item of that commit, and an ordinal key `<hash>:<n>` to the items whose
8
+ * `entry` is `n`. A key that doesn't resolve to any item is unmatched, so an ordinal key on a title-derived item
9
+ * goes stale.
10
+ * - Several matches: an error (ambiguous prefix).
11
+ *
12
+ * Two more conditions are errors, and the keys involved apply nowhere: a bare key that sets `description` or `body` on a
13
+ * commit with several items, and two keys that resolve to the same item.
14
+ *
15
+ * `matchedKeys` lists the keys that resolved to at least one item without error. The caller computes stale-key
16
+ * warnings, because in a monorepo a key may target a commit in another workspace: A key unmatched in one batch is not
17
+ * necessarily stale.
18
+ *
19
+ * An override whose audience is `'skip'` removes its item, and a section left empty is dropped; an entry left without
20
+ * sections is kept. An item without a `hash`, such as a synthetic propagation item, passes through unmatched. Errors
21
+ * are returned rather than thrown, and the caller decides whether to abort.
22
+ */
23
+ export declare function applyChangelogOverrides(entries: ChangelogEntry[], overrides: Map<string, ChangelogOverride>): {
24
+ entries: ChangelogEntry[];
25
+ warnings: string[];
26
+ errors: string[];
27
+ matchedKeys: string[];
28
+ };
29
+ /** Formats the warning for an override key that did not match any item in the changelog. */
30
+ export declare function formatStaleOverrideKeyWarning(key: string): string;
31
+ /** Collects, for each hash, the distinct `entry` positions of the items that have it. */
32
+ export declare function indexItemPositions(items: readonly {
33
+ hash?: string | undefined;
34
+ entry?: number | undefined;
35
+ }[]): Map<string, Set<number | undefined>>;
36
+ /**
37
+ * Resolves one override key against the commits' entry positions. `positions` lists the targeted items' `entry` values,
38
+ * ascending, with `undefined` standing for a title-derived item; it is empty when the key doesn't target any item of
39
+ * the commit.
40
+ */
41
+ export declare function resolveOverrideKey(overrideKey: string, positionsByHash: Map<string, Set<number | undefined>>): {
42
+ kind: 'none';
43
+ } | {
44
+ kind: 'ambiguous';
45
+ hashes: string[];
46
+ } | {
47
+ kind: 'items';
48
+ hash: string;
49
+ positions: (number | undefined)[];
50
+ };