@williamthorsen/release-kit 10.2.2 → 10.3.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.
- package/.readyup/kits/default.js +78 -55
- package/.readyup/kits/npm-auto-publish.js +53 -53
- package/.readyup/manifest.json +6 -6
- package/CHANGELOG.md +32 -0
- package/README.md +15 -13
- package/bin/release-kit.js +1 -1
- package/dist/esm/bin/release-kit.js +4 -4
- package/dist/esm/buildChangelogEntries.js +16 -14
- package/dist/esm/buildDependencyGraph.js +6 -2
- package/dist/esm/changelogJsonUtils.js +7 -7
- package/dist/esm/changelogOverrides.js +13 -12
- package/dist/esm/checkWorkTypesDrift.js +1 -1
- package/dist/esm/createTags.js +1 -1
- package/dist/esm/deriveWorkspaceConfig.js +3 -3
- package/dist/esm/detectPackageManager.js +2 -2
- package/dist/esm/detectUndeclaredTagPrefixes.js +1 -1
- package/dist/esm/discoverWorkspaces.js +1 -1
- package/dist/esm/getCommitsSinceTarget.js +2 -2
- package/dist/esm/help/prepareHelp.d.ts +1 -1
- package/dist/esm/help/prepareHelp.js +2 -2
- package/dist/esm/init/checks.js +1 -1
- package/dist/esm/init/detectRepoType.js +1 -1
- package/dist/esm/loadConfig.js +8 -6
- package/dist/esm/planVersionBump.js +6 -2
- package/dist/esm/propagateBumps.js +1 -1
- package/dist/esm/releasePrepareMono.js +2 -1
- package/dist/esm/reportPrepare.js +2 -1
- package/dist/esm/sync-labels/generateCommand.js +4 -2
- package/dist/esm/sync-labels/presets.js +5 -5
- package/dist/esm/sync-labels/resolveLabels.js +5 -3
- package/dist/esm/syncWorkTypes.js +1 -1
- package/dist/esm/validateConfig.js +11 -11
- package/dist/esm/workTypesUtils.js +1 -1
- package/package.json +3 -3
package/.readyup/kits/default.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @noformat — @generated. Do not edit. Compiled by rdy. */
|
|
2
2
|
/* eslint-disable */
|
|
3
|
-
export const __readyupVersion = "0.
|
|
3
|
+
export const __readyupVersion = "0.24.0";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
// .readyup/kits/default.ts
|
|
@@ -43,7 +43,7 @@ function detectRepoType() {
|
|
|
43
43
|
if (existsSync("package.json")) {
|
|
44
44
|
const raw = readFileSync("package.json", "utf8");
|
|
45
45
|
const pkg = parseJsonRecord(raw);
|
|
46
|
-
if (pkg !== void 0 && Array.isArray(pkg
|
|
46
|
+
if (pkg !== void 0 && Array.isArray(pkg["workspaces"])) {
|
|
47
47
|
return "monorepo";
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -52,15 +52,21 @@ function detectRepoType() {
|
|
|
52
52
|
|
|
53
53
|
// .readyup/kits/default.ts
|
|
54
54
|
function getMinVersion() {
|
|
55
|
-
const picked = { "version": "10.
|
|
56
|
-
if (typeof picked
|
|
55
|
+
const picked = { "version": "10.3.0" };
|
|
56
|
+
if (typeof picked["version"] !== "string") {
|
|
57
57
|
throw new TypeError("release-kit/package.json: 'version' must be a string");
|
|
58
58
|
}
|
|
59
|
-
return picked
|
|
59
|
+
return picked["version"];
|
|
60
60
|
}
|
|
61
61
|
function hasPublishablePackages() {
|
|
62
62
|
return discoverWorkspaces({ filter: (w) => w.isPackage }).length > 0;
|
|
63
63
|
}
|
|
64
|
+
var CONFIG_EXPORT_PATTERNS = [
|
|
65
|
+
/export\s+default\b/,
|
|
66
|
+
/export\s+(?:const|let|var)\s+config\b/,
|
|
67
|
+
/export\s*\{[^}]*\b(?:config|default)\b[^}]*\}/,
|
|
68
|
+
/export\s*\*/
|
|
69
|
+
];
|
|
64
70
|
var CLIFF_TEMPLATE_HASH = "93b72e0b1393cd6b1fe8e2a0e303cd326fd323435951b0493396b305af32d2ec";
|
|
65
71
|
var COMMON_PRESET_HASH = "86f9e1db9000793a91168e8c6b5695311a422ee208121324549c068fe67fa184";
|
|
66
72
|
var SYNC_LABELS_WORKFLOW_HASH = "d6e2403fb551d2d415f679125989c92760444eec887644565b2e05c9bf8f4c1e";
|
|
@@ -111,6 +117,7 @@ var default_default = defineRdyKit({
|
|
|
111
117
|
{
|
|
112
118
|
name: "release.yaml does not reference deprecated tag ref",
|
|
113
119
|
severity: "error",
|
|
120
|
+
quiet: true,
|
|
114
121
|
check: () => fileDoesNotContain(".github/workflows/release.yaml", /@(release|publish)-workflow-v[0-9]/),
|
|
115
122
|
fix: "Update release.yaml to use @workflow/release-v1 (run `release-kit init --force` to regenerate, or replace the ref manually)"
|
|
116
123
|
}
|
|
@@ -135,50 +142,79 @@ var default_default = defineRdyKit({
|
|
|
135
142
|
{
|
|
136
143
|
name: "publish.yaml does not reference deprecated tag ref",
|
|
137
144
|
severity: "error",
|
|
145
|
+
quiet: true,
|
|
138
146
|
check: () => fileDoesNotContain(".github/workflows/publish.yaml", /@(release|publish)-workflow-v[0-9]/),
|
|
139
147
|
fix: "Update publish.yaml to use @workflow/publish-v1 (run `release-kit init --force` to regenerate, or replace the ref manually)"
|
|
140
148
|
}
|
|
141
149
|
]
|
|
142
150
|
},
|
|
143
151
|
{
|
|
144
|
-
name: "
|
|
145
|
-
severity: "warn",
|
|
146
|
-
skip: () => !fileExists(".config/release-kit.config.ts") ? "no release-kit config file" : false,
|
|
147
|
-
check: () => releaseNotesConfigIsConsistent(),
|
|
148
|
-
fix: "Either enable changelogJson.enabled or disable releaseNotes.shouldInjectIntoReadme"
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
name: "config does not use removed releaseNotes.shouldCreateGithubRelease",
|
|
152
|
+
name: ".config/release-kit.config.ts exports a config",
|
|
152
153
|
severity: "error",
|
|
153
154
|
skip: () => !fileExists(".config/release-kit.config.ts") ? "no release-kit config file" : false,
|
|
154
|
-
check: () =>
|
|
155
|
-
fix: "
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
name: ".config/release-kit.config.ts uses defineConfig",
|
|
159
|
-
severity: "recommend",
|
|
160
|
-
skip: () => !fileExists(".config/release-kit.config.ts") ? "no release-kit config file" : false,
|
|
161
|
-
check: () => fileContains(".config/release-kit.config.ts", /defineConfig/),
|
|
162
|
-
fix: "Wrap your config export with defineConfig() from @williamthorsen/release-kit/config for type safety"
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
name: "releaseNotes.shouldInjectIntoReadme is true",
|
|
166
|
-
severity: "warn",
|
|
167
|
-
skip: () => !fileExists(".config/release-kit.config.ts") ? "no release-kit config file" : false,
|
|
168
|
-
check: () => releaseNotesInjectsIntoReadme(),
|
|
169
|
-
fix: "Set releaseNotes.shouldInjectIntoReadme to true in .config/release-kit.config.ts",
|
|
155
|
+
check: () => configFileExportsConfig(),
|
|
156
|
+
fix: "Export the config from .config/release-kit.config.ts as a default export or as a named `config` export; release-kit resolves no other export",
|
|
170
157
|
checks: [
|
|
171
158
|
{
|
|
172
|
-
name: "
|
|
159
|
+
name: "releaseNotes config is consistent with changelogJson",
|
|
160
|
+
severity: "warn",
|
|
161
|
+
check: () => releaseNotesConfigIsConsistent(),
|
|
162
|
+
fix: "Either enable changelogJson.enabled or disable releaseNotes.shouldInjectIntoReadme"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: ".config/release-kit.config.ts uses defineConfig",
|
|
166
|
+
severity: "recommend",
|
|
167
|
+
check: () => fileContains(".config/release-kit.config.ts", /defineConfig/),
|
|
168
|
+
fix: "Wrap your config export with defineConfig() from @williamthorsen/release-kit/config for type safety"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: "releaseNotes.shouldInjectIntoReadme is true",
|
|
172
|
+
severity: "warn",
|
|
173
|
+
check: () => releaseNotesInjectsIntoReadme(),
|
|
174
|
+
fix: "Set releaseNotes.shouldInjectIntoReadme to true in .config/release-kit.config.ts",
|
|
175
|
+
checks: [
|
|
176
|
+
{
|
|
177
|
+
name: "README contains release-notes section markers",
|
|
178
|
+
severity: "warn",
|
|
179
|
+
check: readmesHaveReleaseNotesMarkers,
|
|
180
|
+
fix: "Add `<!-- section:release-notes -->` and `<!-- /section:release-notes -->` markers to each affected README"
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "repoLabels block declared in .config/release-kit.config.ts",
|
|
186
|
+
severity: "recommend",
|
|
187
|
+
check: () => fileContains(".config/release-kit.config.ts", /repoLabels/),
|
|
188
|
+
fix: "Run `release-kit sync-labels init` to seed a repoLabels block, then customize labels"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: ".github/labels.yaml exists",
|
|
173
192
|
severity: "warn",
|
|
174
|
-
|
|
175
|
-
|
|
193
|
+
skip: () => !fileContains(".config/release-kit.config.ts", /repoLabels/) ? "no repoLabels config" : false,
|
|
194
|
+
check: () => fileExists(".github/labels.yaml"),
|
|
195
|
+
fix: "Run `release-kit sync-labels generate` to produce the labels file",
|
|
196
|
+
checks: [
|
|
197
|
+
{
|
|
198
|
+
name: "labels.yaml has current common preset",
|
|
199
|
+
severity: "warn",
|
|
200
|
+
check: () => labelsHaveCurrentPresetHash("common", COMMON_PRESET_HASH),
|
|
201
|
+
fix: "Run `release-kit sync-labels generate` to incorporate updated common labels"
|
|
202
|
+
}
|
|
203
|
+
]
|
|
176
204
|
}
|
|
177
205
|
]
|
|
178
206
|
},
|
|
207
|
+
{
|
|
208
|
+
name: "config does not use removed releaseNotes.shouldCreateGithubRelease",
|
|
209
|
+
severity: "error",
|
|
210
|
+
quiet: true,
|
|
211
|
+
check: () => fileDoesNotContain(".config/release-kit.config.ts", /shouldCreateGithubRelease/),
|
|
212
|
+
fix: "Remove 'shouldCreateGithubRelease' from .config/release-kit.config.ts. Adoption of GitHub Releases is now signaled by installing the create-github-release workflow (see release-kit README for setup)."
|
|
213
|
+
},
|
|
179
214
|
{
|
|
180
215
|
name: "git-cliff not in devDependencies",
|
|
181
216
|
severity: "recommend",
|
|
217
|
+
quiet: true,
|
|
182
218
|
check: () => !hasDevDependency("git-cliff"),
|
|
183
219
|
fix: "pnpm remove git-cliff \u2014 release-kit handles changelog generation directly"
|
|
184
220
|
},
|
|
@@ -206,41 +242,26 @@ var default_default = defineRdyKit({
|
|
|
206
242
|
{
|
|
207
243
|
name: "sync-labels.yaml does not reference deprecated tag ref",
|
|
208
244
|
severity: "error",
|
|
245
|
+
quiet: true,
|
|
209
246
|
check: () => fileDoesNotContain(".github/workflows/sync-labels.yaml", /@sync-labels-workflow-v[0-9]/),
|
|
210
247
|
fix: "Update sync-labels.yaml to use @workflow/sync-labels-v1 (run `release-kit sync-labels init --force` to regenerate, or replace the ref manually)"
|
|
211
248
|
},
|
|
212
249
|
{
|
|
213
250
|
name: "retired .config/sync-labels.config.ts is absent",
|
|
214
251
|
severity: "error",
|
|
252
|
+
quiet: true,
|
|
215
253
|
check: () => !fileExists(".config/sync-labels.config.ts"),
|
|
216
254
|
fix: "Move the labels into the repoLabels block of .config/release-kit.config.ts, then delete .config/sync-labels.config.ts"
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
name: "repoLabels block declared in .config/release-kit.config.ts",
|
|
220
|
-
severity: "recommend",
|
|
221
|
-
skip: () => !fileExists(".config/release-kit.config.ts") ? "no release-kit config file" : false,
|
|
222
|
-
check: () => fileContains(".config/release-kit.config.ts", /repoLabels/),
|
|
223
|
-
fix: "Run `release-kit sync-labels init` to seed a repoLabels block, then customize labels"
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
name: ".github/labels.yaml exists",
|
|
227
|
-
severity: "warn",
|
|
228
|
-
skip: () => !fileContains(".config/release-kit.config.ts", /repoLabels/) ? "no repoLabels config" : false,
|
|
229
|
-
check: () => fileExists(".github/labels.yaml"),
|
|
230
|
-
fix: "Run `release-kit sync-labels generate` to produce the labels file",
|
|
231
|
-
checks: [
|
|
232
|
-
{
|
|
233
|
-
name: "labels.yaml has current common preset",
|
|
234
|
-
severity: "warn",
|
|
235
|
-
check: () => labelsHaveCurrentPresetHash("common", COMMON_PRESET_HASH),
|
|
236
|
-
fix: "Run `release-kit sync-labels generate` to incorporate updated common labels"
|
|
237
|
-
}
|
|
238
|
-
]
|
|
239
255
|
}
|
|
240
256
|
]
|
|
241
257
|
}
|
|
242
258
|
]
|
|
243
259
|
});
|
|
260
|
+
function configFileExportsConfig() {
|
|
261
|
+
const content = readFile(".config/release-kit.config.ts");
|
|
262
|
+
if (content === void 0) return false;
|
|
263
|
+
return CONFIG_EXPORT_PATTERNS.some((pattern) => pattern.test(content));
|
|
264
|
+
}
|
|
244
265
|
function labelsHaveCurrentPresetHash(presetName, expectedHash) {
|
|
245
266
|
const content = readFile(".github/labels.yaml");
|
|
246
267
|
if (content === void 0) return false;
|
|
@@ -253,7 +274,8 @@ function readmeHasReleaseNotesMarkers(content) {
|
|
|
253
274
|
}
|
|
254
275
|
function readmesHaveReleaseNotesMarkers() {
|
|
255
276
|
const failing = [];
|
|
256
|
-
|
|
277
|
+
const packageWorkspaces = discoverWorkspaces({ filter: (w) => w.isPackage });
|
|
278
|
+
for (const { dir } of packageWorkspaces) {
|
|
257
279
|
const readmePath = dir === "." ? "README.md" : `${dir}/README.md`;
|
|
258
280
|
const content = readFile(readmePath);
|
|
259
281
|
if (content === void 0 || !readmeHasReleaseNotesMarkers(content)) {
|
|
@@ -287,6 +309,7 @@ export {
|
|
|
287
309
|
RELEASE_WORKFLOW_HASH_MONOREPO,
|
|
288
310
|
RELEASE_WORKFLOW_HASH_SINGLE,
|
|
289
311
|
SYNC_LABELS_WORKFLOW_HASH,
|
|
312
|
+
configFileExportsConfig,
|
|
290
313
|
default_default as default,
|
|
291
314
|
readmeHasReleaseNotesMarkers,
|
|
292
315
|
readmesHaveReleaseNotesMarkers
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
/** @noformat — @generated. Do not edit. Compiled by rdy. */
|
|
2
2
|
/* eslint-disable */
|
|
3
|
-
export const __readyupVersion = "0.
|
|
3
|
+
export const __readyupVersion = "0.24.0";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
// .readyup/kits/npm-auto-publish.ts
|
|
7
7
|
import { execSync } from "node:child_process";
|
|
8
8
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
9
9
|
import path from "node:path";
|
|
10
|
-
import {
|
|
11
|
-
defineRdyChecklist,
|
|
12
|
-
defineRdyKit,
|
|
13
|
-
defineRdyStagedChecklist
|
|
14
|
-
} from "readyup";
|
|
10
|
+
import { defineRdyChecklist, defineRdyKit } from "readyup";
|
|
15
11
|
import {
|
|
16
12
|
discoverWorkspaces,
|
|
17
13
|
fileContains,
|
|
@@ -32,32 +28,32 @@ var UNREACHABLE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
32
28
|
"ERR_SOCKET_TIMEOUT",
|
|
33
29
|
"ETIMEDOUT"
|
|
34
30
|
]);
|
|
35
|
-
var repoChecklist =
|
|
31
|
+
var repoChecklist = defineRdyChecklist({
|
|
36
32
|
name: "repo",
|
|
37
|
-
|
|
33
|
+
checks: [
|
|
38
34
|
{
|
|
39
35
|
name: "publish.yaml exists",
|
|
36
|
+
skip: () => skipIfNothingPublishable(),
|
|
40
37
|
check: () => fileExists(".github/workflows/publish.yaml"),
|
|
41
|
-
fix: 'Run "release-kit init" to scaffold the publish workflow, or create .github/workflows/publish.yaml manually'
|
|
38
|
+
fix: 'Run "release-kit init" to scaffold the publish workflow, or create .github/workflows/publish.yaml manually',
|
|
39
|
+
checks: [
|
|
40
|
+
{
|
|
41
|
+
name: "id-token: write permission declared",
|
|
42
|
+
check: () => fileContains(".github/workflows/publish.yaml", /id-token:\s*write/),
|
|
43
|
+
fix: 'Add "permissions: { id-token: write, contents: read }" to .github/workflows/publish.yaml \u2014 required for OIDC-based npm authentication'
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "No legacy token references in workflow files",
|
|
47
|
+
quiet: true,
|
|
48
|
+
check: () => !hasTokenReferences(),
|
|
49
|
+
fix: "Remove NPM_TOKEN/NODE_AUTH_TOKEN references from workflow files; OIDC auth replaces token-based auth"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "Provenance setting matches repo visibility",
|
|
53
|
+
check: checkProvenanceMatchesVisibility
|
|
54
|
+
}
|
|
55
|
+
]
|
|
42
56
|
}
|
|
43
|
-
],
|
|
44
|
-
groups: [
|
|
45
|
-
[
|
|
46
|
-
{
|
|
47
|
-
name: "id-token: write permission declared",
|
|
48
|
-
check: () => fileContains(".github/workflows/publish.yaml", /id-token:\s*write/),
|
|
49
|
-
fix: 'Add "permissions: { id-token: write, contents: read }" to .github/workflows/publish.yaml \u2014 required for OIDC-based npm authentication'
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
name: "No legacy token references in workflow files",
|
|
53
|
-
check: () => !hasTokenReferences(),
|
|
54
|
-
fix: "Remove NPM_TOKEN/NODE_AUTH_TOKEN references from workflow files; OIDC auth replaces token-based auth"
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: "Provenance setting matches repo visibility",
|
|
58
|
-
check: checkProvenanceMatchesVisibility
|
|
59
|
-
}
|
|
60
|
-
]
|
|
61
57
|
]
|
|
62
58
|
});
|
|
63
59
|
var packagesChecklist = defineRdyChecklist({
|
|
@@ -67,7 +63,7 @@ var packagesChecklist = defineRdyChecklist({
|
|
|
67
63
|
name: 'packageManager field starts with "pnpm"',
|
|
68
64
|
check: () => {
|
|
69
65
|
const rootPkg = readJsonFile("package.json");
|
|
70
|
-
const pm = typeof rootPkg?.packageManager === "string" ? rootPkg
|
|
66
|
+
const pm = typeof rootPkg?.["packageManager"] === "string" ? rootPkg["packageManager"] : "";
|
|
71
67
|
return pm.startsWith("pnpm");
|
|
72
68
|
},
|
|
73
69
|
fix: 'Set "packageManager": "pnpm@..." in root package.json'
|
|
@@ -76,21 +72,24 @@ var packagesChecklist = defineRdyChecklist({
|
|
|
76
72
|
name: "At least one workspace discovered",
|
|
77
73
|
check: () => discoverWorkspaces().length > 0,
|
|
78
74
|
fix: "Ensure pnpm-workspace.yaml lists package globs, or that a root package.json exists"
|
|
79
|
-
}
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
checks: [
|
|
80
78
|
{
|
|
81
79
|
name: "npm session is usable",
|
|
80
|
+
skip: () => skipIfNothingPublishable(),
|
|
82
81
|
check: () => {
|
|
83
82
|
const auth = getCachedNpmAuthStatus();
|
|
84
83
|
return auth.status === "authenticated" ? { ok: true } : { ok: false, detail: auth.detail };
|
|
85
84
|
},
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
// readyup reads `fix` before it consults `skip`, and again when it validates the kit, so a getter here would
|
|
86
|
+
// reach the registry on every run regardless of the skip. Per-outcome wording goes in the check's detail.
|
|
87
|
+
fix: 'Restore a usable npm session: log in with "npm login", or restore access to the registry, which the trusted-publisher check queries directly',
|
|
88
|
+
get checks() {
|
|
89
|
+
return discoverWorkspaces().map((workspace) => buildWorkspaceCheck(workspace));
|
|
88
90
|
}
|
|
89
91
|
}
|
|
90
|
-
]
|
|
91
|
-
get checks() {
|
|
92
|
-
return discoverWorkspaces().map((workspace) => buildWorkspaceCheck(workspace));
|
|
93
|
-
}
|
|
92
|
+
]
|
|
94
93
|
});
|
|
95
94
|
var npm_auto_publish_default = defineRdyKit({
|
|
96
95
|
fixLocation: "inline",
|
|
@@ -102,7 +101,7 @@ function buildWorkspaceCheck(workspace) {
|
|
|
102
101
|
const children = [
|
|
103
102
|
{
|
|
104
103
|
name: "repository field exists",
|
|
105
|
-
check: () => workspace.packageJson
|
|
104
|
+
check: () => workspace.packageJson["repository"] !== void 0 && workspace.packageJson["repository"] !== null,
|
|
106
105
|
fix: `Add a "repository" field to ${pkgJsonPath} pointing to the GitHub repo`
|
|
107
106
|
}
|
|
108
107
|
];
|
|
@@ -134,7 +133,7 @@ function buildWorkspaceCheck(workspace) {
|
|
|
134
133
|
{
|
|
135
134
|
name: "files field exists",
|
|
136
135
|
severity: "warn",
|
|
137
|
-
check: () => workspace.packageJson
|
|
136
|
+
check: () => workspace.packageJson["files"] !== void 0,
|
|
138
137
|
fix: `Add a "files" field to ${pkgJsonPath} to control which files are included in the published tarball`
|
|
139
138
|
}
|
|
140
139
|
);
|
|
@@ -237,18 +236,14 @@ function describeTrustRelationships(relationships) {
|
|
|
237
236
|
return `${type} ${repository} (${file})`;
|
|
238
237
|
}).join(", ");
|
|
239
238
|
}
|
|
240
|
-
var
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
cachedOwnerRepo = getOwnerRepo();
|
|
249
|
-
}
|
|
250
|
-
return cachedOwnerRepo;
|
|
251
|
-
}
|
|
239
|
+
var getCachedNpmAuthStatus = /* @__PURE__ */ (() => {
|
|
240
|
+
let cached;
|
|
241
|
+
return () => cached ??= classifyNpmAuth(runNpmJson("npm whoami --json"));
|
|
242
|
+
})();
|
|
243
|
+
var getCachedOwnerRepo = /* @__PURE__ */ (() => {
|
|
244
|
+
let cached;
|
|
245
|
+
return () => cached ??= getOwnerRepo();
|
|
246
|
+
})();
|
|
252
247
|
function getOwnerRepo() {
|
|
253
248
|
const url = execSync("git remote get-url origin", {
|
|
254
249
|
encoding: "utf8"
|
|
@@ -305,10 +300,10 @@ function readNpmError(stdout) {
|
|
|
305
300
|
} catch {
|
|
306
301
|
return void 0;
|
|
307
302
|
}
|
|
308
|
-
if (!isRecord(parsed) || !isRecord(parsed
|
|
303
|
+
if (!isRecord(parsed) || !isRecord(parsed["error"]) || typeof parsed["error"]["code"] !== "string") {
|
|
309
304
|
return void 0;
|
|
310
305
|
}
|
|
311
|
-
const { code, summary } = parsed
|
|
306
|
+
const { code, summary } = parsed["error"];
|
|
312
307
|
return { code, summary: typeof summary === "string" ? summary : "" };
|
|
313
308
|
}
|
|
314
309
|
function readTrustRelationships(stdout) {
|
|
@@ -330,10 +325,14 @@ function runNpmJson(command) {
|
|
|
330
325
|
try {
|
|
331
326
|
return { exitOk: true, stdout: execSync(command, { encoding: "utf8", stdio: "pipe" }) };
|
|
332
327
|
} catch (error) {
|
|
333
|
-
const stdout = isRecord(error) && typeof error
|
|
328
|
+
const stdout = isRecord(error) && typeof error["stdout"] === "string" ? error["stdout"] : "";
|
|
334
329
|
return { exitOk: false, stdout };
|
|
335
330
|
}
|
|
336
331
|
}
|
|
332
|
+
function skipIfNothingPublishable() {
|
|
333
|
+
const publishable = discoverWorkspaces({ filter: (workspace) => workspace.isPackage });
|
|
334
|
+
return publishable.length > 0 ? false : "no publishable packages";
|
|
335
|
+
}
|
|
337
336
|
function skipIfNotPublishable(workspace) {
|
|
338
337
|
return workspace.isPackage ? false : "package.json#private is true";
|
|
339
338
|
}
|
|
@@ -343,5 +342,6 @@ export {
|
|
|
343
342
|
classifyTrustQuery,
|
|
344
343
|
npm_auto_publish_default as default,
|
|
345
344
|
packagesChecklist,
|
|
346
|
-
skipIfNotPublishable
|
|
345
|
+
skipIfNotPublishable,
|
|
346
|
+
skipIfNothingPublishable
|
|
347
347
|
};
|
package/.readyup/manifest.json
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
],
|
|
8
8
|
"name": "default",
|
|
9
9
|
"path": "kits/default.js",
|
|
10
|
-
"readyupVersion": "0.
|
|
10
|
+
"readyupVersion": "0.24.0",
|
|
11
11
|
"source": "kits/default.ts",
|
|
12
|
-
"sourceHash": "
|
|
13
|
-
"targetHash": "
|
|
12
|
+
"sourceHash": "fe239d01",
|
|
13
|
+
"targetHash": "9bd8fb5d"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"checklists": [
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
],
|
|
20
20
|
"name": "npm-auto-publish",
|
|
21
21
|
"path": "kits/npm-auto-publish.js",
|
|
22
|
-
"readyupVersion": "0.
|
|
22
|
+
"readyupVersion": "0.24.0",
|
|
23
23
|
"source": "kits/npm-auto-publish.ts",
|
|
24
|
-
"sourceHash": "
|
|
25
|
-
"targetHash": "
|
|
24
|
+
"sourceHash": "ac484613",
|
|
25
|
+
"targetHash": "f790e7d5"
|
|
26
26
|
}
|
|
27
27
|
]
|
|
28
28
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 10.3.0 — 2026-08-08
|
|
6
|
+
|
|
7
|
+
### 🎉 Features
|
|
8
|
+
|
|
9
|
+
- Stop reporting absence checks that pass (#610)
|
|
10
|
+
|
|
11
|
+
A ReadyUp check that checks for a problem (such as an unwanted file or a stale config reference) now stays silent unless it finds one. The `nmr`, `release-kit`, and `v11y-check` ReadyUp kits previously printed a line for every such check on every run.
|
|
12
|
+
|
|
13
|
+
- Stop reporting non-issues in the readyup kits (#613)
|
|
14
|
+
|
|
15
|
+
Modifies the `release-kit` and `nmr` ReadyUp kits to avoid verbose reporting when an initial check determines that further checks aren't applicable. In particular, a repo with no `release-kit` config file gets a single line in the `release-kit` report, and a repo that publishes nothing now bypasses the `npm-auto-publish` kit instead of failing it.
|
|
16
|
+
|
|
17
|
+
### 🐛 Bug fixes
|
|
18
|
+
|
|
19
|
+
- Publish build output atomically so a failed build cannot destroy it (#631)
|
|
20
|
+
|
|
21
|
+
Fixes an issue where a failed or still-running `nmr build` could leave a package with no build output at all, breaking the tooling that a subsequent build depends on. Separately, the error reported when a package's build output is missing now names the correct recovery command.
|
|
22
|
+
|
|
23
|
+
### ♻️ Refactoring
|
|
24
|
+
|
|
25
|
+
- Retire the deferred-lint-rule list and enforce its rules (#628)
|
|
26
|
+
|
|
27
|
+
Errors that `release-kit` rethrows now carry the original error as their cause, previously available only as message text. Help text and documentation for `--with-release-notes` now use the same placeholder notation for its output paths.
|
|
28
|
+
|
|
29
|
+
All violations of lint rules in the `release-kit` project are now cleared, and the list of deferred lint rules is retired, restoring associated rules to a max severity of "error" during strict linting.
|
|
30
|
+
|
|
31
|
+
### ⚙️ Tooling
|
|
32
|
+
|
|
33
|
+
- Migrate to the shared tsconfig baseline (#626)
|
|
34
|
+
|
|
35
|
+
Adopts `@williamthorsen/tsconfig` as the standard TypeScript configuration for this repo, replacing the previous hand-maintained copy. Reading a property through an index signature now requires bracket notation or a type that declares the property. The `nmr` build now fails on a base TypeScript config it cannot resolve, rather than building without it, and it now resolves a base config named by package name alone.
|
|
36
|
+
|
|
5
37
|
## 10.2.2 — 2026-08-05
|
|
6
38
|
|
|
7
39
|
### 🐛 Bug fixes
|
package/README.md
CHANGED
|
@@ -5,21 +5,23 @@ Version-bumping and changelog-generation toolkit for release workflows.
|
|
|
5
5
|
Provides a self-contained CLI that auto-discovers workspaces from `pnpm-workspace.yaml`, parses conventional commits, determines version bumps, updates `package.json` files, and generates changelogs from `git-cliff --context` output rendered in-process (with optional [editorial overrides](#editorial-overrides)).
|
|
6
6
|
|
|
7
7
|
<!-- section:release-notes -->
|
|
8
|
-
## Release notes — v10.
|
|
8
|
+
## Release notes — v10.3.0 (2026-08-08)
|
|
9
9
|
|
|
10
|
-
###
|
|
10
|
+
### 🎉 Features
|
|
11
|
+
|
|
12
|
+
- Stop reporting absence checks that pass (#610)
|
|
13
|
+
|
|
14
|
+
A ReadyUp check that checks for a problem (such as an unwanted file or a stale config reference) now stays silent unless it finds one. The `nmr`, `release-kit`, and `v11y-check` ReadyUp kits previously printed a line for every such check on every run.
|
|
11
15
|
|
|
12
|
-
-
|
|
16
|
+
- Stop reporting non-issues in the readyup kits (#613)
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
Modifies the `release-kit` and `nmr` ReadyUp kits to avoid verbose reporting when an initial check determines that further checks aren't applicable. In particular, a repo with no `release-kit` config file gets a single line in the `release-kit` report, and a repo that publishes nothing now bypasses the `npm-auto-publish` kit instead of failing it.
|
|
19
|
+
|
|
20
|
+
### 🐛 Bug fixes
|
|
15
21
|
|
|
16
|
-
-
|
|
22
|
+
- Publish build output atomically so a failed build cannot destroy it (#631)
|
|
17
23
|
|
|
18
|
-
Fixes an issue where a failed `
|
|
19
|
-
|
|
20
|
-
`commit` and `tag` now report the full path of the tags file they looked for, and distinguish a missing file from one that could not be read, so that running from the wrong directory or worktree is no longer reported as a release that never happened.
|
|
21
|
-
|
|
22
|
-
Runs with `--with-release-notes` now list the preview files they write, and `--dry-run` names the ones a real run would write.
|
|
24
|
+
Fixes an issue where a failed or still-running `nmr build` could leave a package with no build output at all, breaking the tooling that a subsequent build depends on. Separately, the error reported when a package's build output is missing now names the correct recovery command.
|
|
23
25
|
<!-- /section:release-notes -->
|
|
24
26
|
|
|
25
27
|
## Installation
|
|
@@ -573,7 +575,7 @@ Run release preparation with automatic workspace discovery.
|
|
|
573
575
|
| `--set-version=X.Y.Z` | Set an explicit canonical semver version; bypasses commit-derived bumps. Requires `--only` in monorepo mode (rejected when a `project` block is configured). |
|
|
574
576
|
| `--force` | Release even when no commits or no bump-worthy commits exist since the last tag. In monorepo/project mode, defaults to patch (combine with `--bump=X` for a different level); in single-package mode, a bare `--force` is rejected — pass `--bump=major\|minor\|patch`. |
|
|
575
577
|
| `--only=name1,name2` | Only process the named workspaces (monorepo only; rejected when a `project` block is configured) |
|
|
576
|
-
| `--with-release-notes` | Write per-workspace release-notes previews under
|
|
578
|
+
| `--with-release-notes` | Write per-workspace release-notes previews under `<workspacePath>/docs/` |
|
|
577
579
|
| `--help`, `-h` | Show help |
|
|
578
580
|
|
|
579
581
|
Workspace names for `--only` match the package directory name (e.g., `arrays`, `release-kit`).
|
|
@@ -582,8 +584,8 @@ Workspace names for `--only` match the package directory name (e.g., `arrays`, `
|
|
|
582
584
|
|
|
583
585
|
`--with-release-notes` writes two versioned files per workspace after each workspace's `changelog.json` is produced:
|
|
584
586
|
|
|
585
|
-
-
|
|
586
|
-
-
|
|
587
|
+
- `<workspacePath>/docs/README.v<version>.md` — the workspace `README.md` with release notes injected at the `<!-- section:release-notes -->` marker.
|
|
588
|
+
- `<workspacePath>/docs/RELEASE_NOTES.v<version>.md` — the standalone release notes for this version.
|
|
587
589
|
|
|
588
590
|
The publish-time inject-and-revert lifecycle is unchanged; previews are additive, deterministic, and safe to regenerate. When `changelogJson.enabled` is `false`, the flag logs a warning and skips preview generation. In dry-run mode, planned writes are logged and no files are created.
|
|
589
591
|
|
package/bin/release-kit.js
CHANGED
|
@@ -3,7 +3,7 @@ try {
|
|
|
3
3
|
await import('../dist/esm/bin/release-kit.js');
|
|
4
4
|
} catch (error) {
|
|
5
5
|
if (error.code === 'ERR_MODULE_NOT_FOUND') {
|
|
6
|
-
process.stderr.write('release-kit: build output not found — run `
|
|
6
|
+
process.stderr.write('release-kit: build output not found — run `nmr build` first\n');
|
|
7
7
|
} else {
|
|
8
8
|
process.stderr.write(`release-kit: failed to load: ${error.message}\n`);
|
|
9
9
|
}
|
|
@@ -263,7 +263,7 @@ if (command === '--version' || command === '-V') {
|
|
|
263
263
|
console.info(VERSION);
|
|
264
264
|
process.exit(0);
|
|
265
265
|
}
|
|
266
|
-
if (command === '--help'
|
|
266
|
+
if (command === undefined || ['--help', '-h'].includes(command)) {
|
|
267
267
|
showUsage();
|
|
268
268
|
process.exit(0);
|
|
269
269
|
}
|
|
@@ -350,7 +350,7 @@ if (command === 'init') {
|
|
|
350
350
|
if (command === 'sync-labels') {
|
|
351
351
|
const subcommand = flags[0];
|
|
352
352
|
const subflags = flags.slice(1);
|
|
353
|
-
if (subcommand === '--help'
|
|
353
|
+
if (subcommand === undefined || ['--help', '-h'].includes(subcommand)) {
|
|
354
354
|
showSyncLabelsHelp();
|
|
355
355
|
process.exit(0);
|
|
356
356
|
}
|
|
@@ -398,7 +398,7 @@ if (command === 'sync-labels') {
|
|
|
398
398
|
if (command === 'overrides') {
|
|
399
399
|
const subcommand = flags[0];
|
|
400
400
|
const subflags = flags.slice(1);
|
|
401
|
-
if (subcommand === '--help'
|
|
401
|
+
if (subcommand === undefined || ['--help', '-h'].includes(subcommand)) {
|
|
402
402
|
showOverridesHelp();
|
|
403
403
|
process.exit(0);
|
|
404
404
|
}
|
|
@@ -427,7 +427,7 @@ if (command === 'overrides') {
|
|
|
427
427
|
if (command === 'work-types') {
|
|
428
428
|
const subcommand = flags[0];
|
|
429
429
|
const subflags = flags.slice(1);
|
|
430
|
-
if (subcommand === '--help'
|
|
430
|
+
if (subcommand === undefined || ['--help', '-h'].includes(subcommand)) {
|
|
431
431
|
showWorkTypesHelp();
|
|
432
432
|
process.exit(0);
|
|
433
433
|
}
|
|
@@ -20,7 +20,8 @@ export function buildChangelogEntries(config, tag, options) {
|
|
|
20
20
|
if (options?.tagPattern !== undefined) {
|
|
21
21
|
cliffArgs.push('--tag-pattern', options.tagPattern);
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
const includePaths = options?.includePaths ?? [];
|
|
24
|
+
for (const includePath of includePaths) {
|
|
24
25
|
cliffArgs.push('--include-path', includePath);
|
|
25
26
|
}
|
|
26
27
|
try {
|
|
@@ -30,7 +31,7 @@ export function buildChangelogEntries(config, tag, options) {
|
|
|
30
31
|
return transformReleases(releases, devOnlySections);
|
|
31
32
|
}
|
|
32
33
|
catch (error) {
|
|
33
|
-
throw new Error(`Failed to build changelog entries for tag ${tag}: ${error instanceof Error ? error.message : String(error)}
|
|
34
|
+
throw new Error(`Failed to build changelog entries for tag ${tag}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
function parseCliffContext(json) {
|
|
@@ -45,14 +46,14 @@ function toCliffContextRelease(value) {
|
|
|
45
46
|
return {};
|
|
46
47
|
}
|
|
47
48
|
const release = {};
|
|
48
|
-
if (typeof value
|
|
49
|
-
release.version = value
|
|
49
|
+
if (typeof value['version'] === 'string') {
|
|
50
|
+
release.version = value['version'];
|
|
50
51
|
}
|
|
51
|
-
if (typeof value
|
|
52
|
-
release.timestamp = value
|
|
52
|
+
if (typeof value['timestamp'] === 'number') {
|
|
53
|
+
release.timestamp = value['timestamp'];
|
|
53
54
|
}
|
|
54
|
-
if (isUnknownArray(value
|
|
55
|
-
release.commits = value
|
|
55
|
+
if (isUnknownArray(value['commits'])) {
|
|
56
|
+
release.commits = value['commits'].map(toCliffContextCommit);
|
|
56
57
|
}
|
|
57
58
|
return release;
|
|
58
59
|
}
|
|
@@ -61,13 +62,13 @@ function toCliffContextCommit(value) {
|
|
|
61
62
|
return { message: '' };
|
|
62
63
|
}
|
|
63
64
|
const commit = {
|
|
64
|
-
message: typeof value
|
|
65
|
+
message: typeof value['message'] === 'string' ? value['message'] : '',
|
|
65
66
|
};
|
|
66
|
-
if (typeof value
|
|
67
|
-
commit.group = value
|
|
67
|
+
if (typeof value['group'] === 'string') {
|
|
68
|
+
commit.group = value['group'];
|
|
68
69
|
}
|
|
69
|
-
if (typeof value
|
|
70
|
-
commit.id = value
|
|
70
|
+
if (typeof value['id'] === 'string') {
|
|
71
|
+
commit.id = value['id'];
|
|
71
72
|
}
|
|
72
73
|
return commit;
|
|
73
74
|
}
|
|
@@ -81,7 +82,8 @@ function transformReleases(releases, devOnlySections) {
|
|
|
81
82
|
const version = extractVersion(release.version);
|
|
82
83
|
const date = release.timestamp !== undefined ? new Date(release.timestamp * 1_000).toISOString().slice(0, 10) : 'unreleased';
|
|
83
84
|
const sectionMap = new Map();
|
|
84
|
-
|
|
85
|
+
const commits = release.commits ?? [];
|
|
86
|
+
for (const commit of commits) {
|
|
85
87
|
const group = stripCommentPrefix(commit.group ?? 'Other');
|
|
86
88
|
const description = extractDescription(commit.message);
|
|
87
89
|
const body = extractBody(commit.message);
|
|
@@ -51,14 +51,18 @@ function readPackageJsonSubset(filePath) {
|
|
|
51
51
|
content = readFileSync(filePath, 'utf8');
|
|
52
52
|
}
|
|
53
53
|
catch (error) {
|
|
54
|
-
throw new Error(`Failed to read ${filePath}: ${error instanceof Error ? error.message : String(error)}
|
|
54
|
+
throw new Error(`Failed to read ${filePath}: ${error instanceof Error ? error.message : String(error)}`, {
|
|
55
|
+
cause: error,
|
|
56
|
+
});
|
|
55
57
|
}
|
|
56
58
|
let parsed;
|
|
57
59
|
try {
|
|
58
60
|
parsed = JSON.parse(content);
|
|
59
61
|
}
|
|
60
62
|
catch (error) {
|
|
61
|
-
throw new Error(`Failed to parse JSON in ${filePath}: ${error instanceof Error ? error.message : String(error)}
|
|
63
|
+
throw new Error(`Failed to parse JSON in ${filePath}: ${error instanceof Error ? error.message : String(error)}`, {
|
|
64
|
+
cause: error,
|
|
65
|
+
});
|
|
62
66
|
}
|
|
63
67
|
if (!isPackageJsonSubset(parsed)) {
|
|
64
68
|
throw new Error(`Invalid package.json at ${filePath}`);
|
|
@@ -3,21 +3,21 @@ import { isRecord, isUnknownArray } from "./typeGuards.js";
|
|
|
3
3
|
export function isChangelogItem(value) {
|
|
4
4
|
if (!isRecord(value))
|
|
5
5
|
return false;
|
|
6
|
-
if (typeof value
|
|
6
|
+
if (typeof value['description'] !== 'string')
|
|
7
7
|
return false;
|
|
8
|
-
if (value
|
|
8
|
+
if (value['body'] !== undefined && typeof value['body'] !== 'string')
|
|
9
9
|
return false;
|
|
10
|
-
if (value
|
|
10
|
+
if (value['breaking'] !== undefined && typeof value['breaking'] !== 'boolean')
|
|
11
11
|
return false;
|
|
12
|
-
if (value
|
|
12
|
+
if (value['hash'] !== undefined && typeof value['hash'] !== 'string')
|
|
13
13
|
return false;
|
|
14
14
|
return true;
|
|
15
15
|
}
|
|
16
16
|
export function isChangelogEntry(value) {
|
|
17
17
|
return (isRecord(value) &&
|
|
18
|
-
typeof value
|
|
19
|
-
typeof value
|
|
20
|
-
isUnknownArray(value
|
|
18
|
+
typeof value['version'] === 'string' &&
|
|
19
|
+
typeof value['date'] === 'string' &&
|
|
20
|
+
isUnknownArray(value['sections']));
|
|
21
21
|
}
|
|
22
22
|
export function extractVersion(tag) {
|
|
23
23
|
const match = /(\d+\.\d+\.\d+.*)$/.exec(tag);
|
|
@@ -66,8 +66,8 @@ function validateSingleOverride(key, rawEntry, errors) {
|
|
|
66
66
|
entryValid = false;
|
|
67
67
|
}
|
|
68
68
|
const result = {};
|
|
69
|
-
if (rawEntry
|
|
70
|
-
const audienceResult = validateAudience(key, rawEntry
|
|
69
|
+
if (rawEntry['audience'] !== undefined) {
|
|
70
|
+
const audienceResult = validateAudience(key, rawEntry['audience'], errors);
|
|
71
71
|
if (audienceResult === undefined) {
|
|
72
72
|
entryValid = false;
|
|
73
73
|
}
|
|
@@ -75,31 +75,31 @@ function validateSingleOverride(key, rawEntry, errors) {
|
|
|
75
75
|
result.audience = audienceResult;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
if (rawEntry
|
|
79
|
-
if (typeof rawEntry
|
|
78
|
+
if (rawEntry['description'] !== undefined) {
|
|
79
|
+
if (typeof rawEntry['description'] !== 'string') {
|
|
80
80
|
errors.push(`overrides['${key}']: 'description' must be a string`);
|
|
81
81
|
entryValid = false;
|
|
82
82
|
}
|
|
83
83
|
else {
|
|
84
|
-
result.description = rawEntry
|
|
84
|
+
result.description = rawEntry['description'];
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
-
if (rawEntry
|
|
88
|
-
if (typeof rawEntry
|
|
87
|
+
if (rawEntry['body'] !== undefined) {
|
|
88
|
+
if (typeof rawEntry['body'] !== 'string') {
|
|
89
89
|
errors.push(`overrides['${key}']: 'body' must be a string`);
|
|
90
90
|
entryValid = false;
|
|
91
91
|
}
|
|
92
92
|
else {
|
|
93
|
-
result.body = rawEntry
|
|
93
|
+
result.body = rawEntry['body'];
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
-
if (rawEntry
|
|
97
|
-
if (typeof rawEntry
|
|
96
|
+
if (rawEntry['breaking'] !== undefined) {
|
|
97
|
+
if (typeof rawEntry['breaking'] !== 'boolean') {
|
|
98
98
|
errors.push(`overrides['${key}']: 'breaking' must be a boolean`);
|
|
99
99
|
entryValid = false;
|
|
100
100
|
}
|
|
101
101
|
else {
|
|
102
|
-
result.breaking = rawEntry
|
|
102
|
+
result.breaking = rawEntry['breaking'];
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
if (Object.keys(result).length === 0 && entryValid) {
|
|
@@ -236,7 +236,8 @@ export function loadOverridesForScopes(scopes) {
|
|
|
236
236
|
project = result.overrides;
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
|
-
|
|
239
|
+
const workspacePaths = scopes.workspaces ?? [];
|
|
240
|
+
for (const workspacePath of workspacePaths) {
|
|
240
241
|
const result = loadChangelogOverrides(resolveOverridePath(workspacePath));
|
|
241
242
|
if ('errors' in result) {
|
|
242
243
|
errors.push(...result.errors);
|
package/dist/esm/createTags.js
CHANGED
|
@@ -51,6 +51,6 @@ function assertCleanWorkingTree() {
|
|
|
51
51
|
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
52
52
|
throw error;
|
|
53
53
|
}
|
|
54
|
-
throw new Error('Working tree is dirty. Commit or stash changes before tagging, or use `--no-git-checks` to skip this check.');
|
|
54
|
+
throw new Error('Working tree is dirty. Commit or stash changes before tagging, or use `--no-git-checks` to skip this check.', { cause: error });
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -10,14 +10,14 @@ export function deriveWorkspaceConfig(workspacePath) {
|
|
|
10
10
|
}
|
|
11
11
|
catch (error) {
|
|
12
12
|
const message = error instanceof Error ? error.message : String(error);
|
|
13
|
-
throw new Error(`Failed to read ${packageJsonPath}: ${message}
|
|
13
|
+
throw new Error(`Failed to read ${packageJsonPath}: ${message}`, { cause: error });
|
|
14
14
|
}
|
|
15
|
-
const name = isRecord(parsed) ? parsed
|
|
15
|
+
const name = isRecord(parsed) ? parsed['name'] : undefined;
|
|
16
16
|
if (typeof name !== 'string' || name.length === 0) {
|
|
17
17
|
throw new Error(`${packageJsonPath} is missing a 'name' field (required for tag derivation).`);
|
|
18
18
|
}
|
|
19
19
|
const unscopedName = stripNpmScope(name);
|
|
20
|
-
const privateField = isRecord(parsed) ? parsed
|
|
20
|
+
const privateField = isRecord(parsed) ? parsed['private'] : undefined;
|
|
21
21
|
const isPublishable = privateField === undefined || privateField === false;
|
|
22
22
|
return {
|
|
23
23
|
dir,
|
|
@@ -6,8 +6,8 @@ export function detectPackageManager() {
|
|
|
6
6
|
try {
|
|
7
7
|
const content = readFileSync(packageJsonPath, 'utf8');
|
|
8
8
|
const parsed = JSON.parse(content);
|
|
9
|
-
if (isRecord(parsed) && typeof parsed
|
|
10
|
-
const [name, version] = parsed
|
|
9
|
+
if (isRecord(parsed) && typeof parsed['packageManager'] === 'string') {
|
|
10
|
+
const [name, version] = parsed['packageManager'].split('@', 2);
|
|
11
11
|
if (name === 'pnpm' || name === 'npm') {
|
|
12
12
|
return name;
|
|
13
13
|
}
|
|
@@ -23,7 +23,7 @@ export function detectUndeclaredTagPrefixes(knownPrefixes) {
|
|
|
23
23
|
const match = CANDIDATE_TAG_PATTERN.exec(tag);
|
|
24
24
|
if (match === null)
|
|
25
25
|
continue;
|
|
26
|
-
const prefix = match.groups?.prefix ?? '';
|
|
26
|
+
const prefix = match.groups?.['prefix'] ?? '';
|
|
27
27
|
if (prefix === '' || known.has(prefix))
|
|
28
28
|
continue;
|
|
29
29
|
let tags = grouped.get(prefix);
|
|
@@ -24,7 +24,7 @@ function findLatestTag(tagPrefixes) {
|
|
|
24
24
|
if (isNoTagError(error)) {
|
|
25
25
|
return undefined;
|
|
26
26
|
}
|
|
27
|
-
throw new Error(`Failed to run 'git describe': ${errorMessage(error)}
|
|
27
|
+
throw new Error(`Failed to run 'git describe': ${errorMessage(error)}`, { cause: error });
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
const RELEASE_COMMIT_PREFIX = 'release:';
|
|
@@ -59,7 +59,7 @@ export function getCommitsSinceTarget(tagPrefixes, paths) {
|
|
|
59
59
|
}).trim();
|
|
60
60
|
}
|
|
61
61
|
catch (error) {
|
|
62
|
-
throw new Error(`Failed to run 'git log' for range '${range}': ${errorMessage(error)}
|
|
62
|
+
throw new Error(`Failed to run 'git log' for range '${range}': ${errorMessage(error)}`, { cause: error });
|
|
63
63
|
}
|
|
64
64
|
if (logOutput === '') {
|
|
65
65
|
return { tag, commits: [] };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const prepareHelpText = "\nUsage: release-kit prepare [options]\n\nRun release preparation with automatic workspace discovery.\n\nOptions:\n --dry-run Run without modifying any files\n --bump=major|minor|patch Override the bump type for all workspaces\n --set-version=X.Y.Z Set an explicit version; bypasses commit-derived bumps.\n Requires --only in monorepo mode (rejected when a 'project' block is configured).\n --force Release even when no commits or no bump-worthy commits exist\n since the last tag. In monorepo and project mode, defaults to\n patch when --bump is not given; use --bump=X for a different\n level. In single-package mode, a bare --force is rejected \u2014\n pass --bump=major|minor|patch.\n --no-git-checks, -n Skip the clean-working-tree check\n --only=name1,name2 Only process the named workspaces (comma-separated, monorepo only;\n rejected when a 'project' block is configured)\n --with-release-notes Also write per-workspace release-notes previews under
|
|
1
|
+
export declare const prepareHelpText = "\nUsage: release-kit prepare [options]\n\nRun release preparation with automatic workspace discovery.\n\nOptions:\n --dry-run Run without modifying any files\n --bump=major|minor|patch Override the bump type for all workspaces\n --set-version=X.Y.Z Set an explicit version; bypasses commit-derived bumps.\n Requires --only in monorepo mode (rejected when a 'project' block is configured).\n --force Release even when no commits or no bump-worthy commits exist\n since the last tag. In monorepo and project mode, defaults to\n patch when --bump is not given; use --bump=X for a different\n level. In single-package mode, a bare --force is rejected \u2014\n pass --bump=major|minor|patch.\n --no-git-checks, -n Skip the clean-working-tree check\n --only=name1,name2 Only process the named workspaces (comma-separated, monorepo only;\n rejected when a 'project' block is configured)\n --with-release-notes Also write per-workspace release-notes previews under <workspacePath>/docs/\n (docs/README.v<version>.md and docs/RELEASE_NOTES.v<version>.md).\n Recommended .gitignore entry: packages/*/docs/*.v*.md (or docs/*.v*.md).\n --help, -h Show this help message\n";
|
|
2
2
|
export declare function showPrepareHelp(): void;
|
|
@@ -16,8 +16,8 @@ Options:
|
|
|
16
16
|
--no-git-checks, -n Skip the clean-working-tree check
|
|
17
17
|
--only=name1,name2 Only process the named workspaces (comma-separated, monorepo only;
|
|
18
18
|
rejected when a 'project' block is configured)
|
|
19
|
-
--with-release-notes Also write per-workspace release-notes previews under
|
|
20
|
-
(docs/README.v
|
|
19
|
+
--with-release-notes Also write per-workspace release-notes previews under <workspacePath>/docs/
|
|
20
|
+
(docs/README.v<version>.md and docs/RELEASE_NOTES.v<version>.md).
|
|
21
21
|
Recommended .gitignore entry: packages/*/docs/*.v*.md (or docs/*.v*.md).
|
|
22
22
|
--help, -h Show this help message
|
|
23
23
|
`;
|
package/dist/esm/init/checks.js
CHANGED
|
@@ -23,7 +23,7 @@ export function usesPnpm() {
|
|
|
23
23
|
}
|
|
24
24
|
const raw = readFileSync('package.json', 'utf8');
|
|
25
25
|
const pkg = parseJsonRecord(raw);
|
|
26
|
-
if (pkg !== undefined && typeof pkg
|
|
26
|
+
if (pkg !== undefined && typeof pkg['packageManager'] === 'string' && pkg['packageManager'].startsWith('pnpm')) {
|
|
27
27
|
return { ok: true };
|
|
28
28
|
}
|
|
29
29
|
return {
|
|
@@ -7,7 +7,7 @@ export function detectRepoType() {
|
|
|
7
7
|
if (existsSync('package.json')) {
|
|
8
8
|
const raw = readFileSync('package.json', 'utf8');
|
|
9
9
|
const pkg = parseJsonRecord(raw);
|
|
10
|
-
if (pkg !== undefined && Array.isArray(pkg
|
|
10
|
+
if (pkg !== undefined && Array.isArray(pkg['workspaces'])) {
|
|
11
11
|
return 'monorepo';
|
|
12
12
|
}
|
|
13
13
|
}
|
package/dist/esm/loadConfig.js
CHANGED
|
@@ -23,19 +23,19 @@ export function readRootPackageVersion() {
|
|
|
23
23
|
contents = readFileSync(absolutePath, 'utf8');
|
|
24
24
|
}
|
|
25
25
|
catch (error) {
|
|
26
|
-
throw new Error(`Failed to read root ${ROOT_PACKAGE_JSON_PATH}: ${error instanceof Error ? error.message : String(error)}
|
|
26
|
+
throw new Error(`Failed to read root ${ROOT_PACKAGE_JSON_PATH}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
27
27
|
}
|
|
28
28
|
let parsed;
|
|
29
29
|
try {
|
|
30
30
|
parsed = JSON.parse(contents);
|
|
31
31
|
}
|
|
32
32
|
catch (error) {
|
|
33
|
-
throw new Error(`Failed to parse root ${ROOT_PACKAGE_JSON_PATH}: ${error instanceof Error ? error.message : String(error)}
|
|
33
|
+
throw new Error(`Failed to parse root ${ROOT_PACKAGE_JSON_PATH}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
34
34
|
}
|
|
35
35
|
if (!isRecord(parsed)) {
|
|
36
36
|
return { exists: true, version: undefined };
|
|
37
37
|
}
|
|
38
|
-
return { exists: true, version: typeof parsed
|
|
38
|
+
return { exists: true, version: typeof parsed['version'] === 'string' ? parsed['version'] : undefined };
|
|
39
39
|
}
|
|
40
40
|
export const CONFIG_FILE_PATH = '.config/release-kit.config.ts';
|
|
41
41
|
export async function loadConfig() {
|
|
@@ -44,7 +44,7 @@ export async function loadConfig() {
|
|
|
44
44
|
return undefined;
|
|
45
45
|
}
|
|
46
46
|
const imported = await import(__rewriteRelativeImportExtension(pathToFileURL(absoluteConfigPath).href));
|
|
47
|
-
const resolved = isRecord(imported) ? (imported
|
|
47
|
+
const resolved = isRecord(imported) ? (imported['default'] ?? imported['config']) : undefined;
|
|
48
48
|
if (resolved === undefined) {
|
|
49
49
|
throw new Error('Config file must have a default export or a named `config` export (e.g., `export default { ... }` or `export const config = { ... }`)');
|
|
50
50
|
}
|
|
@@ -177,7 +177,8 @@ function assertNoTagPrefixCollisions(workspaces, retiredPackages, project) {
|
|
|
177
177
|
for (const workspace of workspaces) {
|
|
178
178
|
const owner = `ws:${workspace.dir}`;
|
|
179
179
|
sources.push({ prefix: workspace.tagPrefix, label: `workspace '${workspace.dir}'`, owner });
|
|
180
|
-
|
|
180
|
+
const legacyIdentities = workspace.legacyIdentities ?? [];
|
|
181
|
+
for (const identity of legacyIdentities) {
|
|
181
182
|
sources.push({
|
|
182
183
|
prefix: identity.tagPrefix,
|
|
183
184
|
label: `workspace '${workspace.dir}' legacyIdentities entry (name='${identity.name}')`,
|
|
@@ -185,7 +186,8 @@ function assertNoTagPrefixCollisions(workspaces, retiredPackages, project) {
|
|
|
185
186
|
});
|
|
186
187
|
}
|
|
187
188
|
}
|
|
188
|
-
|
|
189
|
+
const retiredEntries = (retiredPackages ?? []).entries();
|
|
190
|
+
for (const [index, retired] of retiredEntries) {
|
|
189
191
|
sources.push({
|
|
190
192
|
prefix: retired.tagPrefix,
|
|
191
193
|
label: `retiredPackages entry (name='${retired.name}')`,
|
|
@@ -34,14 +34,18 @@ function readPackageJson(filePath) {
|
|
|
34
34
|
content = readFileSync(filePath, 'utf8');
|
|
35
35
|
}
|
|
36
36
|
catch (error) {
|
|
37
|
-
throw new Error(`Failed to read ${filePath}: ${error instanceof Error ? error.message : String(error)}
|
|
37
|
+
throw new Error(`Failed to read ${filePath}: ${error instanceof Error ? error.message : String(error)}`, {
|
|
38
|
+
cause: error,
|
|
39
|
+
});
|
|
38
40
|
}
|
|
39
41
|
let parsed;
|
|
40
42
|
try {
|
|
41
43
|
parsed = JSON.parse(content);
|
|
42
44
|
}
|
|
43
45
|
catch (error) {
|
|
44
|
-
throw new Error(`Failed to parse JSON in ${filePath}: ${error instanceof Error ? error.message : String(error)}
|
|
46
|
+
throw new Error(`Failed to parse JSON in ${filePath}: ${error instanceof Error ? error.message : String(error)}`, {
|
|
47
|
+
cause: error,
|
|
48
|
+
});
|
|
45
49
|
}
|
|
46
50
|
if (!isPackageJson(parsed)) {
|
|
47
51
|
throw new Error(`No valid 'version' field found in ${filePath}`);
|
|
@@ -4,7 +4,7 @@ export function propagateBumps(directBumps, graph, currentVersions) {
|
|
|
4
4
|
for (const [dir, entry] of directBumps) {
|
|
5
5
|
result.set(dir, { ...entry });
|
|
6
6
|
}
|
|
7
|
-
const queue =
|
|
7
|
+
const queue = directBumps.keys().toArray();
|
|
8
8
|
const visited = new Set();
|
|
9
9
|
while (queue.length > 0) {
|
|
10
10
|
const dir = queue.shift();
|
|
@@ -472,7 +472,8 @@ function topologicalSort(releaseSet, graph) {
|
|
|
472
472
|
break;
|
|
473
473
|
}
|
|
474
474
|
sorted.push(dir);
|
|
475
|
-
|
|
475
|
+
const dependents = forwardEdges.get(dir) ?? [];
|
|
476
|
+
for (const dependent of dependents) {
|
|
476
477
|
const newDegree = (inDegree.get(dependent) ?? 1) - 1;
|
|
477
478
|
inDegree.set(dependent, newDegree);
|
|
478
479
|
if (newDegree === 0) {
|
|
@@ -202,7 +202,8 @@ function formatChangelogFiles(lines, workspace, dryRun, indent = '') {
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
function formatPreviewFiles(lines, release, dryRun, indent = '') {
|
|
205
|
-
|
|
205
|
+
const previewFiles = release.previewFiles ?? [];
|
|
206
|
+
for (const file of previewFiles) {
|
|
206
207
|
if (dryRun) {
|
|
207
208
|
lines.push(dim(`${indent} [dry-run] Would write ${file}`));
|
|
208
209
|
}
|
|
@@ -10,7 +10,8 @@ import { checkRetiredSyncLabelsConfig } from "./retiredConfig.js";
|
|
|
10
10
|
export const LABELS_OUTPUT_PATH = '.github/labels.yaml';
|
|
11
11
|
export function formatLabelsYaml(labels, presetHashes) {
|
|
12
12
|
const headerLines = ['# Generated by release-kit sync-labels — do not edit.', `# Source: ${CONFIG_FILE_PATH}`];
|
|
13
|
-
|
|
13
|
+
const sortedPresetHashes = [...presetHashes].sort(([a], [b]) => a.localeCompare(b));
|
|
14
|
+
for (const [name, hash] of sortedPresetHashes) {
|
|
14
15
|
headerLines.push(`# ${name} preset hash: ${hash}`);
|
|
15
16
|
}
|
|
16
17
|
const declared = labels.map((label) => ({ ...label, description: label.description ?? '' }));
|
|
@@ -50,7 +51,8 @@ export async function generateCommand({ check = false } = {}) {
|
|
|
50
51
|
return 1;
|
|
51
52
|
}
|
|
52
53
|
const presetHashes = new Map();
|
|
53
|
-
|
|
54
|
+
const presetNames = repoLabels.extends ?? [];
|
|
55
|
+
for (const presetName of presetNames) {
|
|
54
56
|
presetHashes.set(presetName, hashPresetFile(presetName));
|
|
55
57
|
}
|
|
56
58
|
const content = formatLabelsYaml(labels, presetHashes);
|
|
@@ -23,7 +23,7 @@ export function loadPreset(presetName) {
|
|
|
23
23
|
}
|
|
24
24
|
catch (error) {
|
|
25
25
|
const message = error instanceof Error ? error.message : String(error);
|
|
26
|
-
throw new Error(`Failed to read preset "${presetName}": ${message}
|
|
26
|
+
throw new Error(`Failed to read preset "${presetName}": ${message}`, { cause: error });
|
|
27
27
|
}
|
|
28
28
|
const parsed = parse(content);
|
|
29
29
|
if (!Array.isArray(parsed)) {
|
|
@@ -34,13 +34,13 @@ export function loadPreset(presetName) {
|
|
|
34
34
|
if (!isRecord(entry)) {
|
|
35
35
|
throw new Error(`Preset "${presetName}" contains an invalid label entry: ${JSON.stringify(entry)}`);
|
|
36
36
|
}
|
|
37
|
-
const { description } = entry;
|
|
38
|
-
if (typeof
|
|
39
|
-
typeof
|
|
37
|
+
const { color, description, name } = entry;
|
|
38
|
+
if (typeof name !== 'string' ||
|
|
39
|
+
typeof color !== 'string' ||
|
|
40
40
|
(description !== undefined && typeof description !== 'string')) {
|
|
41
41
|
throw new TypeError(`Preset "${presetName}" contains a label with invalid fields: ${JSON.stringify(entry)}`);
|
|
42
42
|
}
|
|
43
|
-
labels.push({ name
|
|
43
|
+
labels.push({ name, color, ...(description !== undefined && { description }) });
|
|
44
44
|
}
|
|
45
45
|
return labels;
|
|
46
46
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { loadPreset } from "./presets.js";
|
|
2
2
|
export function resolveLabels(config) {
|
|
3
3
|
const resolved = new Map();
|
|
4
|
-
|
|
4
|
+
const presetNames = config.extends ?? [];
|
|
5
|
+
for (const presetName of presetNames) {
|
|
5
6
|
for (const label of loadPreset(presetName)) {
|
|
6
7
|
resolved.set(label.name, label);
|
|
7
8
|
}
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
+
const labelEntries = Object.entries(config.labels ?? {});
|
|
11
|
+
for (const [name, spec] of labelEntries) {
|
|
10
12
|
if (spec === null) {
|
|
11
13
|
if (!resolved.has(name)) {
|
|
12
14
|
throw new Error(`Label '${name}' is set to null (remove), but no preset in 'extends' defines it. Fix the name or delete the entry.`);
|
|
@@ -21,7 +23,7 @@ export function resolveLabels(config) {
|
|
|
21
23
|
});
|
|
22
24
|
}
|
|
23
25
|
}
|
|
24
|
-
return sortLabels(
|
|
26
|
+
return sortLabels(resolved.values().toArray());
|
|
25
27
|
}
|
|
26
28
|
function sortLabels(labels) {
|
|
27
29
|
return [...labels].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -20,7 +20,7 @@ function extractLocalSchemaUrl(content) {
|
|
|
20
20
|
if (!isRecord(parsed)) {
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
|
-
const schema = parsed
|
|
23
|
+
const schema = parsed['$schema'];
|
|
24
24
|
return typeof schema === 'string' ? schema : undefined;
|
|
25
25
|
}
|
|
26
26
|
export async function syncWorkTypes(dependencies = {}) {
|
|
@@ -30,25 +30,25 @@ function preprocessDeprecatedKeys(raw) {
|
|
|
30
30
|
return { cleaned: raw, deprecationErrors: [] };
|
|
31
31
|
const errors = [];
|
|
32
32
|
const cleaned = { ...raw };
|
|
33
|
-
if (isRecord(cleaned
|
|
33
|
+
if (isRecord(cleaned['releaseNotes']) && Object.hasOwn(cleaned['releaseNotes'], 'shouldCreateGithubRelease')) {
|
|
34
34
|
errors.push('releaseNotes.shouldCreateGithubRelease is no longer supported. Adoption is now signaled by installing the create-github-release workflow. Remove this field from your config; see README for the updated workflow.');
|
|
35
|
-
const releaseNotesCopy = { ...cleaned
|
|
36
|
-
delete releaseNotesCopy
|
|
37
|
-
cleaned
|
|
35
|
+
const releaseNotesCopy = { ...cleaned['releaseNotes'] };
|
|
36
|
+
delete releaseNotesCopy['shouldCreateGithubRelease'];
|
|
37
|
+
cleaned['releaseNotes'] = releaseNotesCopy;
|
|
38
38
|
}
|
|
39
|
-
if (Array.isArray(cleaned
|
|
40
|
-
cleaned
|
|
39
|
+
if (Array.isArray(cleaned['workspaces'])) {
|
|
40
|
+
cleaned['workspaces'] = cleaned['workspaces'].map((ws, i) => {
|
|
41
41
|
if (!isRecord(ws))
|
|
42
42
|
return ws;
|
|
43
43
|
const wsCopy = { ...ws };
|
|
44
|
-
if ('tagPrefix'
|
|
45
|
-
const dir = typeof wsCopy
|
|
44
|
+
if (Object.hasOwn(wsCopy, 'tagPrefix')) {
|
|
45
|
+
const dir = typeof wsCopy['dir'] === 'string' && wsCopy['dir'] !== '' ? wsCopy['dir'] : '<dir>';
|
|
46
46
|
errors.push(`workspaces[${i}]: 'tagPrefix' is no longer supported; remove it to use the default '${dir}-v'`);
|
|
47
|
-
delete wsCopy
|
|
47
|
+
delete wsCopy['tagPrefix'];
|
|
48
48
|
}
|
|
49
|
-
if ('legacyTagPrefixes'
|
|
49
|
+
if (Object.hasOwn(wsCopy, 'legacyTagPrefixes')) {
|
|
50
50
|
errors.push(`workspaces[${i}]: 'legacyTagPrefixes' is no longer supported; use 'legacyIdentities: [{ name, tagPrefix }, ...]' instead`);
|
|
51
|
-
delete wsCopy
|
|
51
|
+
delete wsCopy['legacyTagPrefixes'];
|
|
52
52
|
}
|
|
53
53
|
return wsCopy;
|
|
54
54
|
});
|
|
@@ -11,7 +11,7 @@ export function errorMessage(error) {
|
|
|
11
11
|
return error instanceof Error ? error.message : String(error);
|
|
12
12
|
}
|
|
13
13
|
export function buildFetchInit() {
|
|
14
|
-
const token = process.env
|
|
14
|
+
const token = process.env['GITHUB_TOKEN'];
|
|
15
15
|
if (token === undefined || token === '') {
|
|
16
16
|
return undefined;
|
|
17
17
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@williamthorsen/release-kit",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.3.0",
|
|
4
4
|
"description": "Version-bumping and changelog-generation toolkit for release workflows",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/williamthorsen/node-monorepo-tools/tree/main/packages/release-kit#readme",
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
"semver": "7.8.5",
|
|
45
45
|
"yaml": "2.9.0",
|
|
46
46
|
"zod": "4.4.3",
|
|
47
|
-
"@williamthorsen/nmr-core": "0.9.
|
|
47
|
+
"@williamthorsen/nmr-core": "0.9.3"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@types/semver": "7.7.1",
|
|
51
|
-
"readyup": "0.
|
|
51
|
+
"readyup": "0.24.0",
|
|
52
52
|
"smol-toml": "1.7.1"
|
|
53
53
|
},
|
|
54
54
|
"engines": {
|