@ontrails/trails 1.0.0-beta.23 → 1.0.0-beta.29
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/CHANGELOG.md +209 -0
- package/README.md +6 -5
- package/package.json +16 -14
- package/src/app.ts +42 -3
- package/src/cli.ts +17 -3
- package/src/local-state-io.ts +20 -0
- package/src/mcp-app.ts +10 -0
- package/src/mcp-options.ts +2 -3
- package/src/project-writes.ts +11 -11
- package/src/release/check.ts +41 -25
- package/src/release/index.ts +40 -0
- package/src/release/native-bun-registry.ts +282 -19
- package/src/release/pack-coherence.ts +457 -0
- package/src/release/policy.ts +1684 -0
- package/src/release/semver.ts +104 -0
- package/src/release/wayfinder-dogfood-smoke.ts +600 -66
- package/src/run-completions-install.ts +2 -2
- package/src/run-schema.ts +41 -0
- package/src/run-wayfind-outline.ts +166 -0
- package/src/trails/adapter-check.ts +1 -1
- package/src/trails/add-surface.ts +1 -1
- package/src/trails/add-verify.ts +3 -3
- package/src/trails/compile.ts +17 -25
- package/src/trails/create-scaffold.ts +14 -14
- package/src/trails/create.ts +5 -5
- package/src/trails/dev-support.ts +44 -24
- package/src/trails/doctor.ts +23 -2
- package/src/trails/draft-promote.ts +7 -7
- package/src/trails/guide.ts +15 -19
- package/src/trails/load-app.ts +58 -9
- package/src/trails/operator-context.ts +66 -0
- package/src/trails/regrade.ts +72 -0
- package/src/trails/release-check.ts +1 -0
- package/src/trails/run-example.ts +21 -37
- package/src/trails/run-examples.ts +16 -32
- package/src/trails/run.ts +81 -57
- package/src/trails/survey.ts +76 -62
- package/src/trails/topo-output-schemas.ts +11 -0
- package/src/trails/topo-pin.ts +6 -20
- package/src/trails/topo-read-support.ts +91 -41
- package/src/trails/topo-reports.ts +4 -2
- package/src/trails/topo-store-support.ts +172 -39
- package/src/trails/topo-support.ts +1 -2
- package/src/trails/topo.ts +5 -19
- package/src/trails/validate.ts +9 -20
- package/src/trails/version-lifecycle-support.ts +10 -20
- package/src/trails/warden.ts +18 -0
- package/src/trails/wayfind.ts +1001 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { readFile, readdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
|
|
4
|
+
export interface ReleasePackCoherenceInput {
|
|
5
|
+
readonly branchName?: string | undefined;
|
|
6
|
+
readonly changedFiles: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ReleasePackCoherenceWorkspace {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly path: string;
|
|
12
|
+
readonly version?: string | undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ReleasePackCoherenceLockfileWorkspace {
|
|
16
|
+
readonly name?: string | undefined;
|
|
17
|
+
readonly version?: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ReleasePackCoherenceLockfileInput {
|
|
21
|
+
readonly lockfileWorkspaces: Readonly<
|
|
22
|
+
Record<string, ReleasePackCoherenceLockfileWorkspace | undefined>
|
|
23
|
+
>;
|
|
24
|
+
readonly sourceWorkspaces: readonly ReleasePackCoherenceWorkspace[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ReleasePackCoherenceLockfileSyncResult {
|
|
28
|
+
readonly text: string;
|
|
29
|
+
readonly updates: readonly string[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface RootPackageJson {
|
|
33
|
+
readonly workspaces?: readonly string[] | undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface WorkspacePackageJson {
|
|
37
|
+
readonly name?: string | undefined;
|
|
38
|
+
readonly version?: string | undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface BunLockfile {
|
|
42
|
+
readonly workspaces?:
|
|
43
|
+
| Readonly<
|
|
44
|
+
Record<string, ReleasePackCoherenceLockfileWorkspace | undefined>
|
|
45
|
+
>
|
|
46
|
+
| undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const RELEASE_BRANCH_NAME = 'changeset-release/main';
|
|
50
|
+
const REPO_ROOT = process.cwd();
|
|
51
|
+
|
|
52
|
+
export const isReleasePackCoherenceFile = (path: string): boolean =>
|
|
53
|
+
path === 'bun.lock' ||
|
|
54
|
+
path === '.changeset/pre.json' ||
|
|
55
|
+
path === 'package.json' ||
|
|
56
|
+
path.endsWith('/package.json') ||
|
|
57
|
+
path.endsWith('/CHANGELOG.md');
|
|
58
|
+
|
|
59
|
+
export const shouldRunReleasePackCoherenceCheck = ({
|
|
60
|
+
branchName,
|
|
61
|
+
changedFiles,
|
|
62
|
+
}: ReleasePackCoherenceInput): boolean =>
|
|
63
|
+
branchName === RELEASE_BRANCH_NAME ||
|
|
64
|
+
changedFiles.some(isReleasePackCoherenceFile);
|
|
65
|
+
|
|
66
|
+
const commandText = (cmd: readonly string[]): string => cmd.join(' ');
|
|
67
|
+
|
|
68
|
+
const spawnCapture = async (cmd: readonly string[]): Promise<string> => {
|
|
69
|
+
const proc = Bun.spawn(cmd as string[], {
|
|
70
|
+
stderr: 'pipe',
|
|
71
|
+
stdin: 'ignore',
|
|
72
|
+
stdout: 'pipe',
|
|
73
|
+
});
|
|
74
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
75
|
+
new Response(proc.stdout).text(),
|
|
76
|
+
new Response(proc.stderr).text(),
|
|
77
|
+
proc.exited,
|
|
78
|
+
]);
|
|
79
|
+
if (exitCode !== 0) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
[
|
|
82
|
+
`Command failed: ${commandText(cmd)}`,
|
|
83
|
+
`exit: ${exitCode}`,
|
|
84
|
+
stdout.trim() ? `stdout:\n${stdout}` : undefined,
|
|
85
|
+
stderr.trim() ? `stderr:\n${stderr}` : undefined,
|
|
86
|
+
]
|
|
87
|
+
.filter((line): line is string => typeof line === 'string')
|
|
88
|
+
.join('\n')
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return stdout;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const spawnInherit = async (cmd: readonly string[]): Promise<number> =>
|
|
95
|
+
await Bun.spawn(cmd as string[], {
|
|
96
|
+
env: { ...process.env, GIT_PAGER: 'cat' },
|
|
97
|
+
stderr: 'inherit',
|
|
98
|
+
stdin: 'inherit',
|
|
99
|
+
stdout: 'inherit',
|
|
100
|
+
}).exited;
|
|
101
|
+
|
|
102
|
+
const currentBranchName = async (): Promise<string | undefined> => {
|
|
103
|
+
const output = await spawnCapture(['git', 'branch', '--show-current']);
|
|
104
|
+
const branch = output.trim();
|
|
105
|
+
return branch.length > 0 ? branch : undefined;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const changedFilesFromGit = async (): Promise<readonly string[]> => {
|
|
109
|
+
const mergeBaseOutput = await spawnCapture([
|
|
110
|
+
'git',
|
|
111
|
+
'merge-base',
|
|
112
|
+
'origin/main',
|
|
113
|
+
'HEAD',
|
|
114
|
+
]);
|
|
115
|
+
const mergeBase = mergeBaseOutput.trim();
|
|
116
|
+
const output = await spawnCapture([
|
|
117
|
+
'git',
|
|
118
|
+
'diff',
|
|
119
|
+
'--name-only',
|
|
120
|
+
'--diff-filter=ACMRT',
|
|
121
|
+
`${mergeBase}...HEAD`,
|
|
122
|
+
]);
|
|
123
|
+
return output
|
|
124
|
+
.split(/\r?\n/u)
|
|
125
|
+
.map((line) => line.trim())
|
|
126
|
+
.filter(Boolean);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const changedFilesFromPath = async (
|
|
130
|
+
path: string
|
|
131
|
+
): Promise<readonly string[]> => {
|
|
132
|
+
const text = await readFile(path, 'utf8');
|
|
133
|
+
return text
|
|
134
|
+
.split(/\r?\n/u)
|
|
135
|
+
.map((line) => line.trim())
|
|
136
|
+
.filter(Boolean);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const removeJsonTrailingCommas = (text: string): string =>
|
|
140
|
+
text.replaceAll(/,(\s*[}\]])/gu, '$1');
|
|
141
|
+
|
|
142
|
+
const readJson = async <T>(path: string): Promise<T> =>
|
|
143
|
+
JSON.parse(await readFile(path, 'utf8')) as T;
|
|
144
|
+
|
|
145
|
+
const readJsonc = async <T>(path: string): Promise<T> =>
|
|
146
|
+
JSON.parse(removeJsonTrailingCommas(await readFile(path, 'utf8'))) as T;
|
|
147
|
+
|
|
148
|
+
const discoverWorkspaceDirs = async (
|
|
149
|
+
patterns: readonly string[]
|
|
150
|
+
): Promise<string[]> => {
|
|
151
|
+
const dirs: string[] = [];
|
|
152
|
+
for (const pattern of patterns) {
|
|
153
|
+
if (pattern.endsWith('/*')) {
|
|
154
|
+
const parent = join(REPO_ROOT, pattern.slice(0, -2));
|
|
155
|
+
let names: string[] = [];
|
|
156
|
+
try {
|
|
157
|
+
const entries = await readdir(parent, { withFileTypes: true });
|
|
158
|
+
names = entries
|
|
159
|
+
.filter((entry) => entry.isDirectory())
|
|
160
|
+
.map((entry) => entry.name);
|
|
161
|
+
} catch {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
for (const name of names) {
|
|
165
|
+
const dir = join(parent, name);
|
|
166
|
+
if (await Bun.file(join(dir, 'package.json')).exists()) {
|
|
167
|
+
dirs.push(dir);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const dir = join(REPO_ROOT, pattern);
|
|
174
|
+
if (await Bun.file(join(dir, 'package.json')).exists()) {
|
|
175
|
+
dirs.push(dir);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return dirs;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const discoverSourceWorkspaces = async (): Promise<
|
|
182
|
+
ReleasePackCoherenceWorkspace[]
|
|
183
|
+
> => {
|
|
184
|
+
const root = await readJson<RootPackageJson>(join(REPO_ROOT, 'package.json'));
|
|
185
|
+
if (!root.workspaces || root.workspaces.length === 0) {
|
|
186
|
+
throw new Error('Root package.json has no "workspaces" field');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const dirs = await discoverWorkspaceDirs(root.workspaces);
|
|
190
|
+
const workspaces: ReleasePackCoherenceWorkspace[] = [];
|
|
191
|
+
for (const dir of dirs) {
|
|
192
|
+
const pkg = await readJson<WorkspacePackageJson>(join(dir, 'package.json'));
|
|
193
|
+
if (!pkg.name) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
workspaces.push({
|
|
197
|
+
name: pkg.name,
|
|
198
|
+
path: relative(REPO_ROOT, dir),
|
|
199
|
+
version: pkg.version,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return workspaces;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export const findLockfileWorkspaceMetadataMismatches = ({
|
|
206
|
+
lockfileWorkspaces,
|
|
207
|
+
sourceWorkspaces,
|
|
208
|
+
}: ReleasePackCoherenceLockfileInput): string[] => {
|
|
209
|
+
const mismatches: string[] = [];
|
|
210
|
+
for (const workspace of sourceWorkspaces) {
|
|
211
|
+
const lockWorkspace = lockfileWorkspaces[workspace.path];
|
|
212
|
+
if (!lockWorkspace) {
|
|
213
|
+
mismatches.push(
|
|
214
|
+
`${workspace.path}/package.json is missing from bun.lock workspaces`
|
|
215
|
+
);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (lockWorkspace.name !== workspace.name) {
|
|
220
|
+
mismatches.push(
|
|
221
|
+
`${workspace.path}/package.json has name ${workspace.name}, but bun.lock records ${lockWorkspace.name ?? '(missing)'}`
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (
|
|
226
|
+
typeof workspace.version === 'string' &&
|
|
227
|
+
lockWorkspace.version !== workspace.version
|
|
228
|
+
) {
|
|
229
|
+
mismatches.push(
|
|
230
|
+
`${workspace.path}/package.json has version ${workspace.version}, but bun.lock records ${lockWorkspace.version ?? '(missing)'}`
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return mismatches;
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const escapeRegExp = (text: string): string =>
|
|
238
|
+
text.replaceAll(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
239
|
+
|
|
240
|
+
const findWorkspaceBlockRange = (
|
|
241
|
+
text: string,
|
|
242
|
+
workspacePath: string
|
|
243
|
+
): { readonly start: number; readonly end: number } | undefined => {
|
|
244
|
+
const keyMatch = new RegExp(
|
|
245
|
+
`^ "${escapeRegExp(workspacePath)}": \\{`,
|
|
246
|
+
'mu'
|
|
247
|
+
).exec(text);
|
|
248
|
+
if (!keyMatch) {
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const openBrace = text.indexOf('{', keyMatch.index);
|
|
253
|
+
if (openBrace === -1) {
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let depth = 0;
|
|
258
|
+
let inString = false;
|
|
259
|
+
let escaped = false;
|
|
260
|
+
for (let index = openBrace; index < text.length; index += 1) {
|
|
261
|
+
const char = text[index];
|
|
262
|
+
if (escaped) {
|
|
263
|
+
escaped = false;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (char === '\\') {
|
|
267
|
+
escaped = true;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (char === '"') {
|
|
271
|
+
inString = !inString;
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (inString) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (char === '{') {
|
|
278
|
+
depth += 1;
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
if (char === '}') {
|
|
282
|
+
depth -= 1;
|
|
283
|
+
if (depth === 0) {
|
|
284
|
+
return { end: index + 1, start: openBrace };
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return undefined;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
export const syncLockfileWorkspaceMetadataText = (
|
|
293
|
+
text: string,
|
|
294
|
+
sourceWorkspaces: readonly ReleasePackCoherenceWorkspace[]
|
|
295
|
+
): ReleasePackCoherenceLockfileSyncResult => {
|
|
296
|
+
let nextText = text;
|
|
297
|
+
const updates: string[] = [];
|
|
298
|
+
|
|
299
|
+
for (const workspace of sourceWorkspaces) {
|
|
300
|
+
if (typeof workspace.version !== 'string') {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const range = findWorkspaceBlockRange(nextText, workspace.path);
|
|
305
|
+
if (!range) {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const block = nextText.slice(range.start, range.end);
|
|
310
|
+
const versionMatch = /^(\s*"version":\s*")([^"]*)(",?)$/mu.exec(block);
|
|
311
|
+
if (!versionMatch || versionMatch[2] === workspace.version) {
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const replacement = `${versionMatch[1]}${workspace.version}${versionMatch[3]}`;
|
|
316
|
+
const blockStart = range.start + versionMatch.index;
|
|
317
|
+
const valueEnd = blockStart + versionMatch[0].length;
|
|
318
|
+
nextText =
|
|
319
|
+
nextText.slice(0, blockStart) + replacement + nextText.slice(valueEnd);
|
|
320
|
+
updates.push(
|
|
321
|
+
`${workspace.path}/package.json: ${versionMatch[2]} -> ${workspace.version}`
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return { text: nextText, updates };
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const loadBunLockfile = async (): Promise<BunLockfile> =>
|
|
329
|
+
await readJsonc<BunLockfile>(join(REPO_ROOT, 'bun.lock'));
|
|
330
|
+
|
|
331
|
+
const syncLockfileWorkspaceMetadata = async (): Promise<void> => {
|
|
332
|
+
const lockfilePath = join(REPO_ROOT, 'bun.lock');
|
|
333
|
+
const [lockfile, sourceWorkspaces] = await Promise.all([
|
|
334
|
+
readFile(lockfilePath, 'utf8'),
|
|
335
|
+
discoverSourceWorkspaces(),
|
|
336
|
+
]);
|
|
337
|
+
const { text, updates } = syncLockfileWorkspaceMetadataText(
|
|
338
|
+
lockfile,
|
|
339
|
+
sourceWorkspaces
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
if (updates.length === 0) {
|
|
343
|
+
console.error('release-pack: bun.lock workspace metadata already synced');
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
await writeFile(lockfilePath, text);
|
|
348
|
+
console.error('release-pack: synced bun.lock workspace metadata');
|
|
349
|
+
for (const update of updates) {
|
|
350
|
+
console.error(` ${update}`);
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const runLockfileWorkspaceMetadataCheck = async (): Promise<number> => {
|
|
355
|
+
const lockfile = await loadBunLockfile();
|
|
356
|
+
if (!lockfile.workspaces) {
|
|
357
|
+
throw new Error('bun.lock has no "workspaces" object');
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const mismatches = findLockfileWorkspaceMetadataMismatches({
|
|
361
|
+
lockfileWorkspaces: lockfile.workspaces,
|
|
362
|
+
sourceWorkspaces: await discoverSourceWorkspaces(),
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
if (mismatches.length === 0) {
|
|
366
|
+
console.error('release-pack: bun.lock workspace metadata is coherent');
|
|
367
|
+
return 0;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
console.error('release-pack: bun.lock workspace metadata is stale');
|
|
371
|
+
for (const mismatch of mismatches) {
|
|
372
|
+
console.error(` ${mismatch}`);
|
|
373
|
+
}
|
|
374
|
+
return 1;
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
export interface ReleasePackCoherenceParsedArgs {
|
|
378
|
+
readonly branchName?: string | undefined;
|
|
379
|
+
readonly changedFilesPath?: string | undefined;
|
|
380
|
+
readonly fixLockfile: boolean;
|
|
381
|
+
readonly lockfileOnly: boolean;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export const parseReleasePackCoherenceArgs = (
|
|
385
|
+
args: readonly string[]
|
|
386
|
+
): ReleasePackCoherenceParsedArgs => {
|
|
387
|
+
let branchName: string | undefined;
|
|
388
|
+
let changedFilesPath: string | undefined;
|
|
389
|
+
let fixLockfile = false;
|
|
390
|
+
let lockfileOnly = false;
|
|
391
|
+
const readValue = (index: number, flag: string): string => {
|
|
392
|
+
const value = args[index + 1];
|
|
393
|
+
if (!value || value.startsWith('--')) {
|
|
394
|
+
throw new Error(
|
|
395
|
+
`Missing value for release pack coherence argument: ${flag}`
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
return value;
|
|
399
|
+
};
|
|
400
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
401
|
+
const arg = args[index];
|
|
402
|
+
if (arg === '--branch') {
|
|
403
|
+
branchName = readValue(index, arg);
|
|
404
|
+
index += 1;
|
|
405
|
+
} else if (arg === '--changed-files') {
|
|
406
|
+
changedFilesPath = readValue(index, arg);
|
|
407
|
+
index += 1;
|
|
408
|
+
} else if (arg === '--lockfile-only') {
|
|
409
|
+
lockfileOnly = true;
|
|
410
|
+
} else if (arg === '--fix-lockfile') {
|
|
411
|
+
fixLockfile = true;
|
|
412
|
+
} else {
|
|
413
|
+
throw new Error(`Unknown release pack coherence argument: ${arg}`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return { branchName, changedFilesPath, fixLockfile, lockfileOnly };
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
export const runReleasePackCoherenceCli = async (
|
|
420
|
+
args: readonly string[] = process.argv.slice(2)
|
|
421
|
+
): Promise<number> => {
|
|
422
|
+
try {
|
|
423
|
+
const parsed = parseReleasePackCoherenceArgs(args);
|
|
424
|
+
if (parsed.fixLockfile) {
|
|
425
|
+
await syncLockfileWorkspaceMetadata();
|
|
426
|
+
console.error('release-pack: checking bun.lock workspace metadata');
|
|
427
|
+
return await runLockfileWorkspaceMetadataCheck();
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const [branchName, changedFiles] = await Promise.all([
|
|
431
|
+
parsed.branchName
|
|
432
|
+
? Promise.resolve(parsed.branchName)
|
|
433
|
+
: currentBranchName(),
|
|
434
|
+
parsed.changedFilesPath
|
|
435
|
+
? changedFilesFromPath(parsed.changedFilesPath)
|
|
436
|
+
: changedFilesFromGit(),
|
|
437
|
+
]);
|
|
438
|
+
|
|
439
|
+
if (!shouldRunReleasePackCoherenceCheck({ branchName, changedFiles })) {
|
|
440
|
+
console.error(
|
|
441
|
+
'release-pack: skipped; no package release metadata changed'
|
|
442
|
+
);
|
|
443
|
+
return 0;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (parsed.lockfileOnly) {
|
|
447
|
+
console.error('release-pack: checking bun.lock workspace metadata');
|
|
448
|
+
return await runLockfileWorkspaceMetadataCheck();
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
console.error('release-pack: checking packed workspace metadata');
|
|
452
|
+
return await spawnInherit(['bun', 'run', 'publish:check']);
|
|
453
|
+
} catch (error) {
|
|
454
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
455
|
+
return 1;
|
|
456
|
+
}
|
|
457
|
+
};
|