breakage 0.8.4 → 0.8.5
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/README.md +2 -0
- package/dist/breakage-B7dJsgcu.js +1235 -0
- package/dist/breakage-B7dJsgcu.js.map +1 -0
- package/dist/breakage.d.ts +113 -1
- package/dist/breakage.d.ts.map +1 -1
- package/dist/breakage.js +1 -1
- package/dist/breakage.npm.check.schema.json +16 -0
- package/dist/breakage.npm.help.schema.json +6 -0
- package/dist/breakage.npm.schema.json +6 -0
- package/dist/breakage.npm.test.$peer.$range.schema.json +16 -0
- package/dist/breakage.npm.test.schema.json +16 -0
- package/dist/breakage.x.js +109 -5
- package/dist/breakage.x.js.map +1 -1
- package/npm.md +214 -0
- package/package.json +8 -7
- package/src/breakage.ts +14 -0
- package/src/breakage.x.ts +30 -3
- package/src/npm/check.ts +448 -0
- package/src/npm/cli.ts +126 -0
- package/src/npm/command.ts +52 -0
- package/src/npm/config.ts +86 -0
- package/src/npm/environment.ts +661 -0
- package/src/npm/manifest.ts +134 -0
- package/src/npm/release.ts +189 -0
- package/src/npm/types.ts +104 -0
- package/dist/breakage-Dc4IldeW.js +0 -435
- package/dist/breakage-Dc4IldeW.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"breakage-B7dJsgcu.js","names":["latestReleaseTag","selectLatestReleaseTag"],"sources":["../src/directory-lock.ts","../src/release-tag.ts","../src/baseline.ts","../src/test-file-state.ts","../src/npm/command.ts","../src/npm/manifest.ts","../src/npm/config.ts","../src/npm/release.ts","../src/npm/environment.ts","../src/npm/check.ts","../src/breakage.ts"],"sourcesContent":["import { mkdir, rmdir } from \"node:fs/promises\"\nimport { setTimeout } from \"node:timers/promises\"\n\nexport async function withDirectoryLock<T>(\n\tlock: string,\n\taction: () => Promise<T>,\n\twaitForCleanup = false,\n): Promise<T> {\n\tconst deadline = Date.now() + 60_000\n\tfor (;;) {\n\t\ttry {\n\t\t\tawait mkdir(lock)\n\t\t\tbreak\n\t\t} catch (thrown) {\n\t\t\tif ((thrown as NodeJS.ErrnoException).code !== `EEXIST`) throw thrown\n\t\t\tif (!waitForCleanup && Date.now() >= deadline) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Timed out waiting for ${lock}. Check for an interrupted operation before removing this lock.`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tawait setTimeout(20)\n\t\t}\n\t}\n\ttry {\n\t\treturn await action()\n\t} finally {\n\t\tawait rmdir(lock)\n\t}\n}\n","type Release = { ref: string; core: string[]; prerelease: string[] }\n\nfunction compareInteger(a: string, b: string): number {\n\treturn a.length - b.length || (a > b ? 1 : a < b ? -1 : 0)\n}\n\nfunction compareRelease(a: Release, b: Release): number {\n\tfor (let index = 0; index < 3; index++) {\n\t\tconst difference = compareInteger(a.core[index]!, b.core[index]!)\n\t\tif (difference) return difference\n\t}\n\tif (!a.prerelease.length || !b.prerelease.length) {\n\t\treturn Number(!a.prerelease.length) - Number(!b.prerelease.length)\n\t}\n\tfor (\n\t\tlet index = 0;\n\t\tindex < Math.min(a.prerelease.length, b.prerelease.length);\n\t\tindex++\n\t) {\n\t\tconst left = a.prerelease[index]!\n\t\tconst right = b.prerelease[index]!\n\t\tconst leftNumeric = /^\\d+$/.test(left)\n\t\tconst rightNumeric = /^\\d+$/.test(right)\n\t\tconst difference =\n\t\t\tleftNumeric && rightNumeric\n\t\t\t\t? compareInteger(left, right)\n\t\t\t\t: leftNumeric !== rightNumeric\n\t\t\t\t\t? Number(rightNumeric) - Number(leftNumeric)\n\t\t\t\t\t: left > right\n\t\t\t\t\t\t? 1\n\t\t\t\t\t\t: left < right\n\t\t\t\t\t\t\t? -1\n\t\t\t\t\t\t\t: 0\n\t\tif (difference) return difference\n\t}\n\treturn a.prerelease.length - b.prerelease.length\n}\n\nexport function latestReleaseTag(\n\tremoteTags: string,\n\ttagPattern?: string,\n): string | undefined {\n\tconst pattern = tagPattern ? new RegExp(tagPattern) : undefined\n\tlet latest: Release | undefined\n\tfor (const line of remoteTags.split(`\\n`)) {\n\t\tif (pattern && !pattern.test(line)) continue\n\t\tconst ref = line.split(`\\t`)[1]?.replace(/\\^\\{\\}$/, ``)\n\t\tif (!ref?.startsWith(`refs/tags/`)) continue\n\t\tconst name = ref.slice(`refs/tags/`.length)\n\t\tconst version = name.slice(name.lastIndexOf(`@`) + 1)\n\t\tconst match =\n\t\t\t/^v?(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/.exec(\n\t\t\t\tversion,\n\t\t\t)\n\t\tif (!match) continue\n\t\tconst prerelease = match[4]?.split(`.`) ?? []\n\t\tif (prerelease.some((identifier) => /^0\\d+$/.test(identifier))) continue\n\t\tconst release: Release = { ref, core: match.slice(1, 4), prerelease }\n\t\tif (!latest || compareRelease(release, latest) > 0) latest = release\n\t}\n\treturn latest?.ref\n}\n","import { randomUUID } from \"node:crypto\"\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport type { SimpleGit } from \"simple-git\"\nimport { simpleGit } from \"simple-git\"\n\nimport { withDirectoryLock } from \"./directory-lock.ts\"\nimport { latestReleaseTag } from \"./release-tag.ts\"\n\nexport type BaselineOptions = {\n\ttagPattern?: string | undefined\n\tbaseDirname?: string\n}\n\nexport type BreakagePreludeOptions = BaselineOptions & { out: string }\n\nexport type BreakageBaseline = {\n\tversion: 1\n\ttagPattern: string | null\n\tpackageDirectory: string\n\tref: string\n\tcommit: string\n}\n\nconst objectId = /^[a-f0-9]{40}(?:[a-f0-9]{24})?$/\n\nfunction isBaseline(value: unknown): value is BreakageBaseline {\n\tif (typeof value !== `object` || value === null) return false\n\tconst record = value as Partial<BreakageBaseline>\n\treturn (\n\t\trecord.version === 1 &&\n\t\t(record.tagPattern === null || typeof record.tagPattern === `string`) &&\n\t\ttypeof record.packageDirectory === `string` &&\n\t\ttypeof record.ref === `string` &&\n\t\trecord.ref.startsWith(`refs/tags/`) &&\n\t\ttypeof record.commit === `string` &&\n\t\tobjectId.test(record.commit)\n\t)\n}\n\n/** Resolve and fetch a release without running tests or changing the worktree. */\nexport async function breakagePrelude({\n\tout,\n\ttagPattern,\n\tbaseDirname = process.cwd(),\n}: BreakagePreludeOptions): Promise<BreakageBaseline> {\n\tconst filename = path.resolve(baseDirname, out)\n\tconst temporaryPath = `${filename}.${randomUUID()}.tmp`\n\tlet canInvalidate = false\n\ttry {\n\t\tconst git = simpleGit(baseDirname)\n\t\t// An ignored, untracked snapshot cannot make the compatibility check dirty.\n\t\tif (!(await git.raw([`check-ignore`, `--`, filename])).trim()) {\n\t\t\tthrow new Error(`Baseline output must be gitignored: ${filename}.`)\n\t\t}\n\t\tcanInvalidate = true\n\t\tconst remoteTags = await git.listRemote([`--tags`, `origin`])\n\t\tconst ref = latestReleaseTag(remoteTags, tagPattern)\n\t\tif (!ref) {\n\t\t\tthrow new Error(`No tags found matching the pattern \"${tagPattern}\".`)\n\t\t}\n\t\tconst refs = new Map(\n\t\t\tremoteTags\n\t\t\t\t.trim()\n\t\t\t\t.split(`\\n`)\n\t\t\t\t.map((line) => {\n\t\t\t\t\tconst [sha, name] = line.split(`\\t`)\n\t\t\t\t\treturn [name, sha]\n\t\t\t\t}),\n\t\t)\n\t\t// ls-remote supplies the peeled commit for annotated tags.\n\t\tconst commit = refs.get(`${ref}^{}`) ?? refs.get(ref)\n\t\tif (!commit || !objectId.test(commit)) {\n\t\t\tthrow new Error(`Could not resolve the release commit for ${ref}.`)\n\t\t}\n\t\tconst commonGitDirectory = await git.revparse([\n\t\t\t`--path-format=absolute`,\n\t\t\t`--git-common-dir`,\n\t\t])\n\t\tawait withDirectoryLock(\n\t\t\tpath.join(commonGitDirectory, `breakage-fetch.lock`),\n\t\t\t() => git.fetch([`origin`, commit, `--no-tags`, `--no-write-fetch-head`]),\n\t\t)\n\t\tif ((await git.raw([`cat-file`, `-t`, commit])).trim() !== `commit`) {\n\t\t\tthrow new Error(`Release ${ref} does not resolve to a commit.`)\n\t\t}\n\t\tconst baseline: BreakageBaseline = {\n\t\t\tversion: 1,\n\t\t\ttagPattern: tagPattern ?? null,\n\t\t\tpackageDirectory: await git.revparse([`--show-prefix`]),\n\t\t\tref,\n\t\t\tcommit,\n\t\t}\n\t\tawait mkdir(path.dirname(filename), { recursive: true })\n\t\tawait writeFile(temporaryPath, `${JSON.stringify(baseline, null, 2)}\\n`, {\n\t\t\tflag: `wx`,\n\t\t})\n\t\tawait rename(temporaryPath, filename)\n\t\treturn baseline\n\t} catch (cause) {\n\t\t// A failed refresh must never leave an older snapshot available as fallback.\n\t\tif (canInvalidate) await rm(filename, { force: true })\n\t\tthrow new Error(`Failed to prepare baseline ${filename}.`, { cause })\n\t} finally {\n\t\tawait rm(temporaryPath, { force: true })\n\t}\n}\n\nexport async function readBaseline(\n\tgit: SimpleGit,\n\tfilename: string,\n\t{ tagPattern }: BaselineOptions,\n): Promise<BreakageBaseline> {\n\ttry {\n\t\tconst baseline: unknown = JSON.parse(await readFile(filename, `utf8`))\n\t\tif (!isBaseline(baseline)) throw new Error(`Invalid baseline fields.`)\n\t\tif (\n\t\t\tbaseline.tagPattern !== (tagPattern ?? null) ||\n\t\t\tbaseline.packageDirectory !== (await git.revparse([`--show-prefix`]))\n\t\t) {\n\t\t\tthrow new Error(`Baseline belongs to a different package or tag pattern.`)\n\t\t}\n\t\tif (\n\t\t\t(\n\t\t\t\tawait git.raw([`check-ref-format`, `--normalize`, baseline.ref])\n\t\t\t).trim() !== baseline.ref\n\t\t) {\n\t\t\tthrow new Error(`Invalid release ref.`)\n\t\t}\n\t\tif (\n\t\t\t(await git.raw([`cat-file`, `-t`, baseline.commit])).trim() !== `commit`\n\t\t) {\n\t\t\tthrow new Error(`Pinned object is not a locally available commit.`)\n\t\t}\n\t\treturn baseline\n\t} catch (cause) {\n\t\tthrow new Error(\n\t\t\t`Missing, invalid, or unusable baseline ${filename}. Run breakage prelude again.`,\n\t\t\t{ cause },\n\t\t)\n\t}\n}\n","import { randomUUID } from \"node:crypto\"\nimport {\n\tchmod,\n\tlstat,\n\tmkdir,\n\treaddir,\n\treadFile,\n\trealpath,\n\trename,\n\trm,\n\twriteFile,\n} from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport type { SimpleGit } from \"simple-git\"\nimport { simpleGit } from \"simple-git\"\n\nimport { withDirectoryLock } from \"./directory-lock.ts\"\n\ntype ActiveCheck = {\n\tpid: number\n\tpaths: string[]\n\thead: string\n\trecoveryRequired?: boolean\n}\n\nfunction isActiveCheck(value: unknown): value is ActiveCheck {\n\tif (typeof value !== `object` || value === null) return false\n\tconst record = value as Partial<ActiveCheck>\n\treturn (\n\t\ttypeof record.pid === `number` &&\n\t\tNumber.isSafeInteger(record.pid) &&\n\t\trecord.pid > 0 &&\n\t\ttypeof record.head === `string` &&\n\t\t/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/.test(record.head) &&\n\t\t(record.recoveryRequired === undefined ||\n\t\t\ttypeof record.recoveryRequired === `boolean`) &&\n\t\tArray.isArray(record.paths) &&\n\t\trecord.paths.length > 0 &&\n\t\trecord.paths.every(\n\t\t\t(file) =>\n\t\t\t\ttypeof file === `string` &&\n\t\t\t\t!path.isAbsolute(file) &&\n\t\t\t\t!path.win32.isAbsolute(file) &&\n\t\t\t\tfile\n\t\t\t\t\t.split(`/`)\n\t\t\t\t\t.every((part) => part !== `` && part !== `.` && part !== `..`),\n\t\t)\n\t)\n}\n\nasync function readRecoveryRecord(recordPath: string): Promise<ActiveCheck> {\n\ttry {\n\t\tconst record: unknown = JSON.parse(await readFile(recordPath, `utf8`))\n\t\tif (!isActiveCheck(record))\n\t\t\tthrow new TypeError(`Invalid recovery record fields`)\n\t\treturn record\n\t} catch (cause) {\n\t\tthrow new Error(\n\t\t\t`A breakage run needs recovery. The record ${recordPath} is unreadable or invalid. Verify no check is running and recover its test files before removing this record.`,\n\t\t\t{ cause },\n\t\t)\n\t}\n}\n\nasync function writeRecoveryRecord(\n\trecordPath: string,\n\trecord: ActiveCheck,\n): Promise<void> {\n\tconst temporaryPath = `${recordPath}.${randomUUID()}.tmp`\n\ttry {\n\t\tawait writeFile(temporaryPath, JSON.stringify(record), { flag: `wx` })\n\t\tawait rename(temporaryPath, recordPath)\n\t} finally {\n\t\tawait rm(temporaryPath, { force: true })\n\t}\n}\n\ntype TestFileState = {\n\tisClean: () => Promise<boolean>\n\treplaceTests: (\n\t\trelease: string,\n\t\tfiles: string[],\n\t) => Promise<() => Promise<void>>\n}\n\nfunction assertContained(root: string, filename: string): void {\n\tconst relative = path.relative(root, filename)\n\tif (\n\t\trelative === `..` ||\n\t\trelative.startsWith(`..${path.sep}`) ||\n\t\tpath.isAbsolute(relative)\n\t) {\n\t\tthrow new Error(`Cannot replace tests outside the worktree: ${filename}.`)\n\t}\n}\n\nasync function validateParents(\n\troot: string,\n\tfilenames: string[],\n): Promise<void> {\n\tconst checked = new Set<string>()\n\tfor (const filename of filenames) {\n\t\tassertContained(root, filename)\n\t\tfor (let parent = path.dirname(filename); ; parent = path.dirname(parent)) {\n\t\t\tif (checked.has(parent)) break\n\t\t\tconst stats = await lstat(parent).catch(\n\t\t\t\t(thrown: NodeJS.ErrnoException) => {\n\t\t\t\t\tif (thrown.code !== `ENOENT`) throw thrown\n\t\t\t\t},\n\t\t\t)\n\t\t\tif (stats && !stats.isDirectory())\n\t\t\t\tthrow new Error(`Cannot replace tests through ${parent}.`)\n\t\t\tchecked.add(parent)\n\t\t\tif (parent === root) break\n\t\t}\n\t}\n}\n\n// This lock covers Git setup and restoration only. Commands run after it is released.\nexport async function withTestFileState<T>(\n\tgit: SimpleGit,\n\tbaseDirname: string,\n\taction: (state: TestFileState) => Promise<T>,\n): Promise<T> {\n\tconst root = await realpath(await git.revparse([`--show-toplevel`]))\n\tbaseDirname = await realpath(baseDirname)\n\tassertContained(root, baseDirname)\n\tconst stateDirectory = path.join(\n\t\tawait git.revparse([`--absolute-git-dir`]),\n\t\t`breakage`,\n\t)\n\tawait mkdir(stateDirectory, { recursive: true })\n\tconst lock = path.join(stateDirectory, `lock`)\n\treturn withDirectoryLock(lock, async () => {\n\t\tconst activeChecks: ActiveCheck[] = []\n\t\tfor (const entry of await readdir(stateDirectory)) {\n\t\t\tif (!entry.endsWith(`.json`)) continue\n\t\t\tconst recordPath = path.join(stateDirectory, entry)\n\t\t\tconst record = await readRecoveryRecord(recordPath)\n\t\t\tlet interrupted = record.recoveryRequired\n\t\t\ttry {\n\t\t\t\tprocess.kill(record.pid, 0)\n\t\t\t} catch (thrown) {\n\t\t\t\tif ((thrown as NodeJS.ErrnoException).code !== `EPERM`)\n\t\t\t\t\tinterrupted = true\n\t\t\t}\n\t\t\tif (interrupted)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`A breakage run needs recovery. Restore the test paths recorded in ${recordPath} before removing that record.`,\n\t\t\t\t)\n\t\t\tactiveChecks.push(record)\n\t\t}\n\t\tconst activePaths = activeChecks.flatMap((record) => record.paths)\n\t\treturn action({\n\t\t\tisClean: async () =>\n\t\t\t\t!(await simpleGit(root).raw([\n\t\t\t\t\t`--no-optional-locks`,\n\t\t\t\t\t`status`,\n\t\t\t\t\t`--porcelain`,\n\t\t\t\t\t`--untracked-files=all`,\n\t\t\t\t\t`--`,\n\t\t\t\t\t`.`,\n\t\t\t\t\t...activePaths.map((file) => `:(top,literal,exclude)${file}`),\n\t\t\t\t])),\n\t\t\treplaceTests: async (release, files) => {\n\t\t\t\tconst paths = files.map((file) =>\n\t\t\t\t\tpath\n\t\t\t\t\t\t.relative(root, path.resolve(baseDirname, file))\n\t\t\t\t\t\t.split(path.sep)\n\t\t\t\t\t\t.join(`/`),\n\t\t\t\t)\n\t\t\t\tfor (const file of paths) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tactivePaths.some(\n\t\t\t\t\t\t\t(active) =>\n\t\t\t\t\t\t\t\tfile === active ||\n\t\t\t\t\t\t\t\tfile.startsWith(`${active}/`) ||\n\t\t\t\t\t\t\t\tactive.startsWith(`${file}/`),\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`Another breakage run is using ${file}. Concurrent checks must use disjoint test paths.`,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst head = await git.revparse([`HEAD`])\n\t\t\t\tconst currentFiles = new Set(\n\t\t\t\t\t(await git.raw([`ls-tree`, `-r`, `--name-only`, `-z`, head]))\n\t\t\t\t\t\t.split(`\\0`)\n\t\t\t\t\t\t.filter(Boolean),\n\t\t\t\t)\n\t\t\t\tconst existing = files.filter((file) => currentFiles.has(file))\n\t\t\t\tconst absent = files.filter((file) => !currentFiles.has(file))\n\t\t\t\tconst modes = new Map<string, number>()\n\t\t\t\tconst filenames = files.map((file) => path.resolve(baseDirname, file))\n\t\t\t\tawait validateParents(root, filenames)\n\t\t\t\tfor (const file of files) {\n\t\t\t\t\tconst filename = path.resolve(baseDirname, file)\n\n\t\t\t\t\tconst stats = await lstat(filename).catch(\n\t\t\t\t\t\t(thrown: NodeJS.ErrnoException) => {\n\t\t\t\t\t\t\tif (thrown.code !== `ENOENT`) throw thrown\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t\tif (!currentFiles.has(file) && stats)\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`Cannot overwrite the existing untracked path ${filename}.`,\n\t\t\t\t\t\t)\n\t\t\t\t\tif (stats?.isFile()) modes.set(filename, stats.mode)\n\t\t\t\t}\n\t\t\t\tconst recordPath = path.join(stateDirectory, `${randomUUID()}.json`)\n\t\t\t\tconst record: ActiveCheck = { pid: process.pid, paths, head }\n\t\t\t\tawait writeRecoveryRecord(recordPath, record)\n\t\t\t\tconst restore = async () => {\n\t\t\t\t\tawait writeRecoveryRecord(recordPath, {\n\t\t\t\t\t\t...record,\n\t\t\t\t\t\trecoveryRequired: true,\n\t\t\t\t\t})\n\t\t\t\t\tawait validateParents(root, filenames)\n\t\t\t\t\tif (existing.length)\n\t\t\t\t\t\tawait git.raw([\n\t\t\t\t\t\t\t`--literal-pathspecs`,\n\t\t\t\t\t\t\t`restore`,\n\t\t\t\t\t\t\t`--source=${head}`,\n\t\t\t\t\t\t\t`--worktree`,\n\t\t\t\t\t\t\t`--`,\n\t\t\t\t\t\t\t...existing,\n\t\t\t\t\t\t])\n\t\t\t\t\tfor (const file of absent)\n\t\t\t\t\t\tawait rm(path.resolve(baseDirname, file), { force: true })\n\t\t\t\t\tfor (const [filename, mode] of modes) await chmod(filename, mode)\n\t\t\t\t\tawait rm(recordPath)\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait git.raw([\n\t\t\t\t\t\t`--literal-pathspecs`,\n\t\t\t\t\t\t`restore`,\n\t\t\t\t\t\t`--source=${release}`,\n\t\t\t\t\t\t`--worktree`,\n\t\t\t\t\t\t`--`,\n\t\t\t\t\t\t...files,\n\t\t\t\t\t])\n\t\t\t\t} catch (thrown) {\n\t\t\t\t\tawait restore()\n\t\t\t\t\tthrow thrown\n\t\t\t\t}\n\t\t\t\treturn () => withDirectoryLock(lock, restore, true)\n\t\t\t},\n\t\t})\n\t})\n}\n","import { spawn } from \"node:child_process\"\nimport path from \"node:path\"\n\nexport type CommandResult = { code: number; output: string }\n\n/** Capture output per environment so parallel runs cannot interleave their reports. */\nexport async function command(\n\tcommandLine: string,\n\tcwd: string,\n): Promise<CommandResult> {\n\treturn await new Promise((resolve, reject) => {\n\t\tconst child = spawn(commandLine, {\n\t\t\tcwd,\n\t\t\tshell: true,\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\tNODE_PATH: ``,\n\t\t\t\tPATH: [\n\t\t\t\t\tpath.join(cwd, `node_modules/.bin`),\n\t\t\t\t\tpath.join(cwd, `../node_modules/.bin`),\n\t\t\t\t\tprocess.env.PATH,\n\t\t\t\t].join(path.delimiter),\n\t\t\t},\n\t\t\tstdio: [`ignore`, `pipe`, `pipe`],\n\t\t})\n\t\tlet output = ``\n\t\tconst collect = (chunk: Buffer): void => {\n\t\t\t// Bound diagnostics without interrupting a command that emits lots of output.\n\t\t\toutput = (output + chunk.toString()).slice(-1_000_000)\n\t\t}\n\t\tchild.stdout.on(`data`, collect)\n\t\tchild.stderr.on(`data`, collect)\n\t\tchild.on(`error`, reject)\n\t\tchild.on(`close`, (code, signal) =>\n\t\t\tresolve({ code: signal ? 2 : (code ?? 2), output }),\n\t\t)\n\t})\n}\n\nexport async function prepare(commandLine: string, cwd: string): Promise<void> {\n\tconst result = await command(commandLine, cwd)\n\tif (result.code !== 0)\n\t\tthrow new Error(\n\t\t\t`Command failed (${result.code}) in ${cwd}: ${commandLine}\\n${result.output}`,\n\t\t)\n}\n\nexport function errorMessage(error: unknown): string {\n\treturn error instanceof Error\n\t\t? `${error.message}${error.cause ? `\\n${errorMessage(error.cause)}` : ``}`\n\t\t: String(error)\n}\n","import { readFile } from \"node:fs/promises\"\n\nimport semver from \"semver\"\n\nexport type Manifest = {\n\tname: string\n\tversion: string\n\ttype?: string\n\tdependencies?: Record<string, string>\n\toptionalDependencies?: Record<string, string>\n\tdevDependencies?: Record<string, string>\n\tpeerDependencies?: Record<string, string>\n\tpeerDependenciesMeta?: Record<string, { optional?: boolean }>\n\tbreakage?: { candidates?: string[] }\n}\n\nexport function record(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === `object` && value !== null && !Array.isArray(value)\n}\n\nexport function packageName(value: string): boolean {\n\treturn /^(?:@[a-z0-9._-]+\\/)?[a-z0-9][a-z0-9._-]*$/.test(value)\n}\n\nexport function parseManifest(value: unknown, label: string): Manifest {\n\tif (\n\t\t!record(value) ||\n\t\ttypeof value.name !== `string` ||\n\t\t!packageName(value.name) ||\n\t\ttypeof value.version !== `string` ||\n\t\t!semver.valid(value.version)\n\t) {\n\t\tthrow new Error(`Invalid package identity in ${label}.`)\n\t}\n\tif (\n\t\tvalue.peerDependenciesMeta !== undefined &&\n\t\t(!record(value.peerDependenciesMeta) ||\n\t\t\tObject.values(value.peerDependenciesMeta).some(\n\t\t\t\t(entry) =>\n\t\t\t\t\t!record(entry) ||\n\t\t\t\t\t(entry.optional !== undefined && typeof entry.optional !== `boolean`),\n\t\t\t))\n\t) {\n\t\tthrow new Error(`Invalid peerDependenciesMeta in ${label}.`)\n\t}\n\tfor (const field of [\n\t\t`dependencies`,\n\t\t`optionalDependencies`,\n\t\t`devDependencies`,\n\t\t`peerDependencies`,\n\t] as const) {\n\t\tconst entries = value[field]\n\t\tif (\n\t\t\tentries !== undefined &&\n\t\t\t(!record(entries) ||\n\t\t\t\tObject.entries(entries).some(\n\t\t\t\t\t([name, spec]) => !packageName(name) || typeof spec !== `string`,\n\t\t\t\t))\n\t\t) {\n\t\t\tthrow new Error(`Invalid ${field} in ${label}.`)\n\t\t}\n\t}\n\tif (\n\t\tvalue.breakage !== undefined &&\n\t\t(!record(value.breakage) ||\n\t\t\t(value.breakage.candidates !== undefined &&\n\t\t\t\t(!Array.isArray(value.breakage.candidates) ||\n\t\t\t\t\tvalue.breakage.candidates.some(\n\t\t\t\t\t\t(name: unknown) => typeof name !== `string` || !packageName(name),\n\t\t\t\t\t))))\n\t) {\n\t\tthrow new Error(`Invalid candidate peers in ${label}.`)\n\t}\n\treturn value as Manifest\n}\n\nexport async function readManifest(filename: string): Promise<Manifest> {\n\treturn parseManifest(JSON.parse(await readFile(filename, `utf8`)), filename)\n}\n\n/** Current support is authored explicitly; only historical shorthand is resolved. */\nexport async function normalizeWorkspacePeers(\n\tmanifest: Manifest,\n\tversionAtBaseline?: (peer: string) => Promise<string>,\n): Promise<Manifest> {\n\tif (!manifest.peerDependencies) return manifest\n\tconst entries = await Promise.all(\n\t\tObject.entries(manifest.peerDependencies).map(async ([peer, range]) => {\n\t\t\tif (!range.startsWith(`workspace:`)) return [peer, range] as const\n\t\t\tconst requested = range.slice(`workspace:`.length)\n\t\t\tif ([``, `*`, `^`, `~`].includes(requested)) {\n\t\t\t\tif (!versionAtBaseline)\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Moving workspace peer range ${peer}: ${range} in ${manifest.name}. Declare explicit support eras, for example ^1.0.0 || ^2.0.0, so local version changes cannot change the support promise.`,\n\t\t\t\t\t)\n\t\t\t\tconst version = await versionAtBaseline(peer)\n\t\t\t\tif (!semver.valid(version))\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Invalid historical workspace version for ${peer}: ${version}.`,\n\t\t\t\t\t)\n\t\t\t\treturn [\n\t\t\t\t\tpeer,\n\t\t\t\t\t`${requested === `^` || requested === `~` ? requested : ``}${version}`,\n\t\t\t\t] as const\n\t\t\t}\n\t\t\ttry {\n\t\t\t\teras(requested)\n\t\t\t} catch {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Unsupported workspace peer range for ${peer}: ${range}.`,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn [peer, requested] as const\n\t\t}),\n\t)\n\treturn { ...manifest, peerDependencies: Object.fromEntries(entries) }\n}\n\nexport function eras(range: string): string[] {\n\tconst parts = range.split(`||`).map((part) => part.trim())\n\tif (parts.some((part) => !part || semver.validRange(part) === null)) {\n\t\tthrow new Error(`Invalid peer range: ${range}.`)\n\t}\n\treturn parts\n}\n\n/** Previews only represent an explicitly enrolled exact preview. */\nexport function matches(version: string, range: string): boolean {\n\treturn eras(range).some((era) =>\n\t\tsemver.prerelease(version)\n\t\t\t? semver.valid(era.replace(/^=\\s*/, ``)) === semver.valid(version)\n\t\t\t: semver.satisfies(version, era),\n\t)\n}\n","import path from \"node:path\"\n\nimport { eras, packageName, record } from \"./manifest.ts\"\nimport type { NpmConfig } from \"./types.ts\"\n\nfunction nonempty(value: unknown): value is string {\n\treturn typeof value === `string` && value.trim().length > 0\n}\n\nexport function validateConfig(value: unknown): asserts value is NpmConfig {\n\tif (!record(value)) throw new Error(`Configuration must have an npm object.`)\n\tfor (const key of [`artifact`, `lockfile`, `prepareCommand`] as const) {\n\t\tif (!nonempty(value[key]))\n\t\t\tthrow new Error(`npm.${key} must be a nonempty string.`)\n\t}\n\tif (\n\t\tpath.isAbsolute(value.lockfile as string) ||\n\t\t(value.lockfile as string).split(/[\\\\/]/).includes(`..`)\n\t) {\n\t\tthrow new Error(`npm.lockfile must stay inside each representative.`)\n\t}\n\tfor (const key of [`packageDirectory`, `installCommand`] as const) {\n\t\tif (value[key] !== undefined && !nonempty(value[key]))\n\t\t\tthrow new Error(`Invalid npm.${key}.`)\n\t}\n\tconst globs =\n\t\ttypeof value.representatives === `string`\n\t\t\t? [value.representatives]\n\t\t\t: value.representatives\n\tif (\n\t\t!Array.isArray(globs) ||\n\t\t!globs.length ||\n\t\tglobs.some((glob: unknown) => !nonempty(glob))\n\t) {\n\t\tthrow new Error(`npm.representatives must contain directory globs.`)\n\t}\n\tif (!record(value.suites) || !Object.keys(value.suites).length)\n\t\tthrow new Error(`Configure at least one npm peer suite.`)\n\tfor (const [peer, suite] of Object.entries(value.suites)) {\n\t\tif (\n\t\t\t!packageName(peer) ||\n\t\t\t!record(suite) ||\n\t\t\t!nonempty(suite.command) ||\n\t\t\t!Array.isArray(suite.files) ||\n\t\t\t!suite.files.length ||\n\t\t\tsuite.files.some((file: unknown) => !nonempty(file))\n\t\t) {\n\t\t\tthrow new Error(`Invalid npm suite for ${peer}.`)\n\t\t}\n\t}\n\tif (\n\t\t!record(value.baseline) ||\n\t\t(`firstRelease` in value.baseline\n\t\t\t? value.baseline.firstRelease !== true ||\n\t\t\t\tObject.keys(value.baseline).length !== 1\n\t\t\t: Object.entries(value.baseline).some(\n\t\t\t\t\t([key, item]) =>\n\t\t\t\t\t\t![`tagPattern`, `baselineFile`].includes(key) || !nonempty(item),\n\t\t\t\t))\n\t) {\n\t\tthrow new Error(\n\t\t\t`Configure npm.baseline with tagPattern/baselineFile or { firstRelease: true }.`,\n\t\t)\n\t}\n\tif (value.localPeers !== undefined) {\n\t\tif (!record(value.localPeers)) throw new Error(`Invalid npm.localPeers.`)\n\t\tfor (const [peer, local] of Object.entries(value.localPeers)) {\n\t\t\tif (\n\t\t\t\t!packageName(peer) ||\n\t\t\t\t!record(local) ||\n\t\t\t\t!nonempty(local.directory) ||\n\t\t\t\t!nonempty(local.artifact)\n\t\t\t) {\n\t\t\t\tthrow new Error(`Invalid local peer ${peer}.`)\n\t\t\t}\n\t\t}\n\t}\n\tfor (const hook of [`releaseIntent`, `certifyBreaking`] as const) {\n\t\tif (value[hook] !== undefined && typeof value[hook] !== `function`)\n\t\t\tthrow new Error(`npm.${hook} must be a function.`)\n\t}\n}\n\nexport function validatePeerRanges(peers: Record<string, string>): void {\n\tfor (const range of Object.values(peers)) eras(range)\n}\n","import path from \"node:path\"\n\nimport semver from \"semver\"\nimport { simpleGit } from \"simple-git\"\n\nimport { readBaseline } from \"../baseline.ts\"\nimport { withDirectoryLock } from \"../directory-lock.ts\"\nimport { latestReleaseTag } from \"../release-tag.ts\"\nimport { validatePeerRanges } from \"./config.ts\"\nimport type { Manifest } from \"./manifest.ts\"\nimport { normalizeWorkspacePeers, parseManifest, record } from \"./manifest.ts\"\nimport type {\n\tNpmConfig,\n\tReleaseContext,\n\tReleaseIntent,\n\tSupportChange,\n} from \"./types.ts\"\n\nexport async function intent(\n\tconfig: NpmConfig,\n\tcontext: ReleaseContext,\n): Promise<ReleaseIntent> {\n\tif (!config.releaseIntent) return { status: `none` }\n\tconst result: unknown = await config.releaseIntent(context)\n\tif (record(result) && result.status === `none`) return { status: `none` }\n\tif (\n\t\t!record(result) ||\n\t\tresult.status !== `release` ||\n\t\ttypeof result.version !== `string` ||\n\t\t!semver.valid(result.version) ||\n\t\tsemver.lt(result.version, context.currentVersion)\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid release intent for ${context.packageName}; expected none or a current/newer exact version.`,\n\t\t)\n\t}\n\treturn { status: `release`, version: result.version }\n}\n\n/**\n * Compare the union, including adjacent alternatives. semver.subset compares each\n * conjunction to a single conjunction and cannot prove coverage by their union.\n * Membership can change only at comparator boundaries or prerelease tuple gates.\n */\nexport function includesRange(current: string, previous: string): boolean {\n\tconst ranges = [new semver.Range(previous), new semver.Range(current)]\n\tconst samples = new Set<string>([`0.0.0`, `0.0.0-0`])\n\tfor (const range of ranges) {\n\t\tfor (const conjunction of range.set) {\n\t\t\tfor (const comparator of conjunction) {\n\t\t\t\tconst version = comparator.semver\n\t\t\t\tif (typeof version === `symbol`) continue\n\t\t\t\tconst base = `${version.major}.${version.minor}.${version.patch}`\n\t\t\t\tsamples.add(version.version)\n\t\t\t\tsamples.add(base)\n\t\t\t\tsamples.add(`${base}-0`)\n\t\t\t\t// The immediate successor in a prerelease sequence appends numeric zero.\n\t\t\t\tif (version.prerelease.length) samples.add(`${version.version}.0`)\n\t\t\t\t// Stable versions are discrete; the next patch starts another tuple gate.\n\t\t\t\tconst next = semver.inc(base, `patch`)\n\t\t\t\tif (next) {\n\t\t\t\t\tsamples.add(next)\n\t\t\t\t\tsamples.add(`${next}-0`)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn [...samples].every(\n\t\t(version) =>\n\t\t\t!semver.satisfies(version, previous) ||\n\t\t\tsemver.satisfies(version, current),\n\t)\n}\n\nexport function supportChanges(\n\tprevious: Manifest,\n\tcurrent: Manifest,\n): SupportChange[] {\n\tconst before = previous.peerDependencies ?? {}\n\tconst after = current.peerDependencies ?? {}\n\tvalidatePeerRanges(before)\n\tvalidatePeerRanges(after)\n\treturn Object.entries(after).flatMap(([peer, range]) => {\n\t\tconst old = before[peer]\n\t\tconst wasOptional = previous.peerDependenciesMeta?.[peer]?.optional === true\n\t\tconst isOptional = current.peerDependenciesMeta?.[peer]?.optional === true\n\t\t// Absence scenarios are not generated, but making an optional peer required\n\t\t// still changes the installation contract for existing consumers.\n\t\treturn (old === undefined && isOptional) ||\n\t\t\t(old !== undefined &&\n\t\t\t\tincludesRange(range, old) &&\n\t\t\t\t!(wasOptional && !isOptional))\n\t\t\t? []\n\t\t\t: [\n\t\t\t\t\t{\n\t\t\t\t\t\tpeer,\n\t\t\t\t\t\treason:\n\t\t\t\t\t\t\told === undefined || (wasOptional && !isOptional)\n\t\t\t\t\t\t\t\t? (`required-peer` as const)\n\t\t\t\t\t\t\t\t: (`narrowed-range` as const),\n\t\t\t\t\t\tprevious: old ?? null,\n\t\t\t\t\t\tcurrent: range,\n\t\t\t\t\t},\n\t\t\t\t]\n\t})\n}\n\nexport async function previousManifest(\n\tconfig: NpmConfig,\n\tdirectory: string,\n): Promise<Manifest | undefined> {\n\tif (`firstRelease` in config.baseline) return undefined\n\tconst git = simpleGit(directory)\n\tlet commit: string\n\tif (config.baseline.baselineFile) {\n\t\tcommit = (\n\t\t\tawait readBaseline(\n\t\t\t\tgit,\n\t\t\t\tpath.resolve(directory, config.baseline.baselineFile),\n\t\t\t\tconfig.baseline,\n\t\t\t)\n\t\t).commit\n\t} else {\n\t\tconst tags = await git.listRemote([`--tags`, `origin`])\n\t\tconst ref = latestReleaseTag(tags, config.baseline.tagPattern)\n\t\tif (!ref)\n\t\t\tthrow new Error(\n\t\t\t\t`No npm release baseline found; configure a tag pattern or explicitly declare firstRelease.`,\n\t\t\t)\n\t\tconst refs = new Map(\n\t\t\ttags\n\t\t\t\t.trim()\n\t\t\t\t.split(`\\n`)\n\t\t\t\t.map((line) => {\n\t\t\t\t\tconst [sha, name] = line.split(`\\t`)\n\t\t\t\t\treturn [name, sha]\n\t\t\t\t}),\n\t\t)\n\t\tconst resolved = refs.get(`${ref}^{}`) ?? refs.get(ref)\n\t\tif (!resolved || !/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/.test(resolved))\n\t\t\tthrow new Error(`Invalid release commit for ${ref}.`)\n\t\tcommit = resolved\n\t\tconst common = await git.revparse([\n\t\t\t`--path-format=absolute`,\n\t\t\t`--git-common-dir`,\n\t\t])\n\t\tawait withDirectoryLock(path.join(common, `breakage-fetch.lock`), () =>\n\t\t\tgit.fetch([`origin`, commit, `--no-tags`, `--no-write-fetch-head`]),\n\t\t)\n\t}\n\tconst prefix = await git.revparse([`--show-prefix`])\n\tconst manifest = parseManifest(\n\t\tJSON.parse(await git.show([`${commit}:${prefix}package.json`])),\n\t\t`release ${commit}`,\n\t)\n\treturn await normalizeWorkspacePeers(manifest, async (peer) => {\n\t\tconst local = config.localPeers?.[peer]\n\t\tif (!local)\n\t\t\tthrow new Error(\n\t\t\t\t`Historical workspace peer ${peer} needs a localPeers directory to resolve release ${commit}.`,\n\t\t\t)\n\t\tconst root = await git.revparse([`--show-toplevel`])\n\t\tconst relative = path.relative(\n\t\t\troot,\n\t\t\tpath.resolve(directory, local.directory),\n\t\t)\n\t\tif (\n\t\t\trelative === `..` ||\n\t\t\trelative.startsWith(`..${path.sep}`) ||\n\t\t\tpath.isAbsolute(relative)\n\t\t)\n\t\t\tthrow new Error(\n\t\t\t\t`Historical workspace peer ${peer} escapes the release repository.`,\n\t\t\t)\n\t\tconst filename = path\n\t\t\t.join(relative, `package.json`)\n\t\t\t.split(path.sep)\n\t\t\t.join(`/`)\n\t\tconst historical = parseManifest(\n\t\t\tJSON.parse(await git.show([`${commit}:${filename}`])),\n\t\t\t`release ${commit}:${filename}`,\n\t\t)\n\t\tif (historical.name !== peer)\n\t\t\tthrow new Error(\n\t\t\t\t`Historical workspace peer identity mismatch for ${peer}.`,\n\t\t\t)\n\t\treturn historical.version\n\t})\n}\n","import { randomUUID } from \"node:crypto\"\nimport * as fs from \"node:fs/promises\"\nimport {\n\tcopyFile,\n\tlstat,\n\tmkdir,\n\treadFile,\n\trealpath,\n\trename,\n\trm,\n\twriteFile,\n} from \"node:fs/promises\"\nimport { createRequire } from \"node:module\"\nimport path from \"node:path\"\n\nimport semver from \"semver\"\nimport { simpleGit } from \"simple-git\"\n\nimport { prepare } from \"./command.ts\"\nimport { validatePeerRanges } from \"./config.ts\"\nimport type { Manifest } from \"./manifest.ts\"\nimport { matches, normalizeWorkspacePeers, readManifest } from \"./manifest.ts\"\nimport { intent } from \"./release.ts\"\nimport type { NpmConfig, NpmPeerEvidence, NpmSuite } from \"./types.ts\"\n\nexport type Environment = {\n\tdirectory: string\n\tstage: string\n\tmanifest: Manifest\n\tpeers: Record<string, NpmPeerEvidence>\n\tcandidates: Record<\n\t\tstring,\n\t\t{\n\t\t\tdirectory: string\n\t\t\tartifact: string\n\t\t\tcurrentVersion: string\n\t\t\tversion: string\n\t\t\tmanifest: Manifest\n\t\t}\n\t>\n}\n\nexport function within(parent: string, child: string): boolean {\n\tconst relative = path.relative(parent, child)\n\treturn (\n\t\trelative === `` ||\n\t\t(!relative.startsWith(`..${path.sep}`) &&\n\t\t\trelative !== `..` &&\n\t\t\t!path.isAbsolute(relative))\n\t)\n}\n\nasync function exists(filename: string): Promise<boolean> {\n\ttry {\n\t\tawait lstat(filename)\n\t\treturn true\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === `ENOENT`) return false\n\t\tthrow error\n\t}\n}\n\nexport async function discover(\n\tconfig: NpmConfig,\n\tbase: string,\n): Promise<string[]> {\n\tconst found = new Set<string>()\n\tfor await (const name of fs.glob(config.representatives, {\n\t\tcwd: base,\n\t\texclude: [`**/node_modules/**`, `**/test/**`, `**/.git/**`],\n\t})) {\n\t\tconst directory = path.resolve(base, name)\n\t\tif (!(await lstat(directory)).isDirectory())\n\t\t\tthrow new Error(`Representative is not a directory: ${name}.`)\n\t\tfound.add(directory)\n\t}\n\tif (!found.size)\n\t\tthrow new Error(\n\t\t\t`No representative directories matched the configured globs.`,\n\t\t)\n\treturn [...found].sort()\n}\n\n/** A freshly created ignored stage is also the exclusive ownership lock. */\nexport async function withStage<T>(\n\tdirectory: string,\n\taction: (stage: string) => Promise<T>,\n): Promise<T> {\n\tconst stage = path.join(directory, `test`)\n\tconst git = simpleGit(directory)\n\tconst root = await git.revparse([`--show-toplevel`])\n\tif (!within(await realpath(root), await realpath(directory)))\n\t\tthrow new Error(`Representative escapes the repository: ${directory}.`)\n\tif (\n\t\t!(await git.raw([`check-ignore`, `--`, `${stage}/`])).trim() ||\n\t\t(await git.raw([`ls-files`, `--`, stage])).trim()\n\t) {\n\t\tthrow new Error(\n\t\t\t`Representative test/ must be gitignored and contain no tracked files: ${stage}.`,\n\t\t)\n\t}\n\ttry {\n\t\tawait mkdir(stage)\n\t} catch (cause) {\n\t\tthrow new Error(\n\t\t\t`Cannot own ${stage}; another run or preexisting files may be present. Remove it only after checking ownership.`,\n\t\t\t{ cause },\n\t\t)\n\t}\n\ttry {\n\t\treturn await action(stage)\n\t} finally {\n\t\tawait rm(stage, { recursive: true, force: true })\n\t}\n}\n\nasync function installed(\n\tdirectory: string,\n\tpeer: string,\n): Promise<NpmPeerEvidence> {\n\tconst location = path.join(directory, `node_modules`, peer)\n\tconst physical = await realpath(location)\n\t// Support pnpm's store links, while rejecting arbitrary workspace source links.\n\tif (!physical.split(path.sep).includes(`node_modules`))\n\t\tthrow new Error(`Peer ${peer} resolves to workspace source: ${physical}.`)\n\tconst manifest = await readManifest(path.join(physical, `package.json`))\n\tif (manifest.name !== peer)\n\t\tthrow new Error(`Expected ${peer}, found ${manifest.name} in ${location}.`)\n\treturn { version: manifest.version, path: physical, source: `installed` }\n}\n\nfunction representativeDeclarations(\n\tmanifest: Manifest,\n): Record<string, string> {\n\tfor (const field of [\n\t\t`dependencies`,\n\t\t`devDependencies`,\n\t\t`optionalDependencies`,\n\t\t`peerDependencies`,\n\t] as const) {\n\t\tfor (const [name, specifier] of Object.entries(manifest[field] ?? {})) {\n\t\t\tconst version = semver.parse(specifier)\n\t\t\t// Semver's normalized version omits build metadata; exact pins retain it.\n\t\t\tconst exact =\n\t\t\t\tversion &&\n\t\t\t\t`${version.version}${version.build.length ? `+${version.build.join(`.`)}` : ``}`\n\t\t\tif (!exact || specifier !== exact)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Representative ${manifest.name} must pin ${field}.${name} to an exact version, such as 1.0.0; received ${JSON.stringify(specifier)}. Declare support ranges in the package under test, and use breakage.candidates for coordinated local releases.`,\n\t\t\t\t)\n\t\t}\n\t}\n\tfor (const [peer, development] of Object.entries(\n\t\tmanifest.devDependencies ?? {},\n\t)) {\n\t\tfor (const field of [`dependencies`, `optionalDependencies`] as const) {\n\t\t\tconst runtime = manifest[field]?.[peer]\n\t\t\tif (runtime !== undefined && runtime !== development)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Conflicting representative declarations for ${peer}: devDependencies has ${development}, but ${field} has ${runtime}. Use one consistent requirement.`,\n\t\t\t\t)\n\t\t}\n\t}\n\t// Optional runtime declarations retain npm's override of required ones.\n\treturn {\n\t\t...manifest.devDependencies,\n\t\t...manifest.dependencies,\n\t\t...manifest.optionalDependencies,\n\t}\n}\n\n/** Select exact pins without acquiring or preparing their stages. */\nexport async function maySelectEnvironment(\n\tconfig: NpmConfig,\n\tbase: string,\n\tdirectory: string,\n\tpackageManifest: Manifest,\n\tselection: { peer: string; range: string },\n): Promise<boolean> {\n\tconst manifest = await readManifest(path.join(directory, `package.json`))\n\tconst declarations = representativeDeclarations(manifest)\n\tconst { peer, range } = selection\n\tif (peer === packageManifest.name)\n\t\treturn matches(packageManifest.version, range)\n\tif (manifest.breakage?.candidates?.includes(peer)) {\n\t\tconst local = config.localPeers?.[peer]\n\t\tif (!local)\n\t\t\tthrow new Error(`Candidate ${peer} has no localPeers configuration.`)\n\t\tconst packageDirectory = path.resolve(base, local.directory)\n\t\tconst current = await readManifest(\n\t\t\tpath.join(packageDirectory, `package.json`),\n\t\t)\n\t\tif (current.name !== peer)\n\t\t\tthrow new Error(`Local peer identity mismatch for ${peer}.`)\n\t\tconst release = await intent(config, {\n\t\t\tpackageName: peer,\n\t\t\tpackageDirectory,\n\t\t\tcurrentVersion: current.version,\n\t\t})\n\t\tif (release.status === `none`)\n\t\t\tthrow new Error(`Candidate ${peer} has no certified release intent.`)\n\t\treturn matches(release.version, range)\n\t}\n\tconst declared = declarations[peer]\n\treturn declared !== undefined && matches(declared, range)\n}\n\nexport async function prepareEnvironment(\n\tconfig: NpmConfig,\n\tbase: string,\n\tdirectory: string,\n\tstage: string,\n\tpackageManifest: Manifest,\n): Promise<Environment> {\n\tconst peerNames = Object.keys(packageManifest.peerDependencies ?? {})\n\tconst filename = path.join(directory, `package.json`)\n\tconst lockfile = path.join(directory, config.lockfile)\n\tfor (const input of [filename, lockfile]) {\n\t\tif (\n\t\t\t!(await lstat(input)).isFile() ||\n\t\t\t!within(directory, await realpath(input))\n\t\t)\n\t\t\tthrow new Error(\n\t\t\t\t`Installation inputs must be regular files inside the representative: ${input}.`,\n\t\t\t)\n\t}\n\tconst inputs = await Promise.all([readFile(filename), readFile(lockfile)])\n\tconst manifest = await readManifest(filename)\n\tconst declarations = representativeDeclarations(manifest)\n\tconst candidates: Environment[`candidates`] = {}\n\tfor (const peer of manifest.breakage?.candidates ?? []) {\n\t\tif (!peerNames.includes(peer))\n\t\t\tthrow new Error(\n\t\t\t\t`Candidate ${peer} is not a declared peer of the package under test.`,\n\t\t\t)\n\t\tconst local = config.localPeers?.[peer]\n\t\tif (!local)\n\t\t\tthrow new Error(`Candidate ${peer} has no localPeers configuration.`)\n\t\tconst localDirectory = path.resolve(base, local.directory)\n\t\tconst localManifest = await normalizeWorkspacePeers(\n\t\t\tawait readManifest(path.join(localDirectory, `package.json`)),\n\t\t)\n\t\tif (localManifest.name !== peer)\n\t\t\tthrow new Error(`Local peer identity mismatch for ${peer}.`)\n\t\tvalidatePeerRanges(localManifest.peerDependencies ?? {})\n\t\tconst evidence = await intent(config, {\n\t\t\tpackageName: peer,\n\t\t\tpackageDirectory: localDirectory,\n\t\t\tcurrentVersion: localManifest.version,\n\t\t})\n\t\tif (evidence.status === `none`)\n\t\t\tthrow new Error(`Candidate ${peer} has no certified release intent.`)\n\t\tcandidates[peer] = {\n\t\t\tdirectory: localDirectory,\n\t\t\tartifact: path.resolve(base, local.artifact),\n\t\t\tcurrentVersion: localManifest.version,\n\t\t\tversion: evidence.version,\n\t\t\tmanifest: localManifest,\n\t\t}\n\t}\n\tconst relevant = [\n\t\t...new Set([\n\t\t\t...peerNames,\n\t\t\t...Object.values(candidates).flatMap((candidate) =>\n\t\t\t\tObject.keys(candidate.manifest.peerDependencies ?? {}),\n\t\t\t),\n\t\t]),\n\t].filter(\n\t\t(peer) =>\n\t\t\tpeer === packageManifest.name ||\n\t\t\tdeclarations[peer] !== undefined ||\n\t\t\tcandidates[peer] !== undefined,\n\t)\n\tconst before: Record<string, string> = {}\n\tfor (const peer of relevant) {\n\t\tif (\n\t\t\tpeer !== packageManifest.name &&\n\t\t\t!candidates[peer] &&\n\t\t\t(await exists(path.join(directory, `node_modules`, peer)))\n\t\t)\n\t\t\tbefore[peer] = (await installed(directory, peer)).version\n\t}\n\tconst preparation = await prepare(config.prepareCommand, directory).then(\n\t\t() => ({ ok: true as const }),\n\t\t(error: unknown) => ({ ok: false as const, error }),\n\t)\n\tconst after = await Promise.all(\n\t\t[filename, lockfile].map((input) =>\n\t\t\treadFile(input).catch(() => Buffer.alloc(0)),\n\t\t),\n\t)\n\tif (inputs.some((input, index) => !input.equals(after[index]!))) {\n\t\tawait Promise.all(\n\t\t\t[filename, lockfile].map(async (input, index) => {\n\t\t\t\t// Recreate an input rather than writing through a link introduced by a command.\n\t\t\t\tawait rm(input, { force: true })\n\t\t\t\tawait writeFile(input, inputs[index]!, { flag: `wx` })\n\t\t\t}),\n\t\t)\n\t\tthrow new Error(\n\t\t\t`Frozen preparation changed the manifest or lockfile in ${directory}; restored the original inputs.`,\n\t\t\t{ cause: preparation.ok ? undefined : preparation.error },\n\t\t)\n\t}\n\tif (!preparation.ok) throw preparation.error\n\tconst peers: Environment[`peers`] = {}\n\tfor (const peer of relevant) {\n\t\tconst candidate = candidates[peer]\n\t\tconst staged = candidate !== undefined || peer === packageManifest.name\n\t\tif (\n\t\t\t!staged &&\n\t\t\tObject.hasOwn(manifest.optionalDependencies ?? {}, peer) &&\n\t\t\t!(await exists(path.join(directory, `node_modules`, peer)))\n\t\t)\n\t\t\tcontinue\n\t\tconst evidence: NpmPeerEvidence = staged\n\t\t\t? {\n\t\t\t\t\tversion: candidate?.version ?? packageManifest.version,\n\t\t\t\t\tpath: path.join(stage, `node_modules`, peer),\n\t\t\t\t\tsource: `candidate`,\n\t\t\t\t}\n\t\t\t: await installed(directory, peer)\n\t\tconst specifier = declarations[peer]\n\t\tif (\n\t\t\t!(staged && specifier === undefined) &&\n\t\t\tevidence.version !== specifier\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t`Representative ${peer}@${evidence.version} does not match its manifest pin ${specifier ?? `(missing)`}.`,\n\t\t\t)\n\t\t}\n\t\tif (before[peer] && before[peer] !== evidence.version)\n\t\t\tthrow new Error(\n\t\t\t\t`Stale installed ${peer}: frozen preparation changed ${before[peer]} to ${evidence.version}.`,\n\t\t\t)\n\t\tfor (const [localPeer, local] of Object.entries(config.localPeers ?? {})) {\n\t\t\tif (staged) continue\n\t\t\tconst localDirectory = path.resolve(base, local.directory)\n\t\t\t// Historical-only registrations need not exist in today's checkout.\n\t\t\tif (\n\t\t\t\t!peerNames.includes(localPeer) &&\n\t\t\t\t!relevant.includes(localPeer) &&\n\t\t\t\t!(await exists(localDirectory))\n\t\t\t)\n\t\t\t\tcontinue\n\t\t\tif (within(await realpath(localDirectory), evidence.path))\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Released peer ${peer} resolves into a local workspace package.`,\n\t\t\t\t)\n\t\t}\n\t\tpeers[peer] = evidence\n\t}\n\treturn { directory, stage, manifest, peers, candidates }\n}\n\n/** Validate the complete coordinated formulation before an audit or execution. */\nexport function checkCandidatePeers(\n\tenvironment: Environment,\n\tfocused: boolean,\n): string[] {\n\tconst conflicts: string[] = []\n\tfor (const [name, candidate] of Object.entries(environment.candidates)) {\n\t\tfor (const [peer, range] of Object.entries(\n\t\t\tcandidate.manifest.peerDependencies ?? {},\n\t\t)) {\n\t\t\tconst evidence = environment.peers[peer]\n\t\t\tif (!evidence) {\n\t\t\t\tif (candidate.manifest.peerDependenciesMeta?.[peer]?.optional) continue\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Complete representative is missing required peer ${peer}: ${range} of coordinated candidate ${name}@${candidate.version}.`,\n\t\t\t\t)\n\t\t\t}\n\t\t\t// This is declaration membership; exact-preview coverage is audited separately.\n\t\t\tif (!semver.satisfies(evidence.version, range))\n\t\t\t\tconflicts.push(\n\t\t\t\t\t`Coordinated candidate ${name}@${candidate.version} requires ${peer}: ${range}, but the representative provides ${peer}@${evidence.version}.`,\n\t\t\t\t)\n\t\t}\n\t}\n\tif (conflicts.length && !focused) throw new Error(conflicts.join(`\\n`))\n\treturn conflicts.map(\n\t\t(conflict) =>\n\t\t\t`${conflict} Running focused exploration outside declared support.`,\n\t)\n}\n\nasync function copySuite(\n\tbase: string,\n\tstage: string,\n\tsuite: NpmSuite,\n): Promise<void> {\n\tfor (const pattern of suite.files) {\n\t\tif (path.isAbsolute(pattern) || pattern.split(/[\\\\/]/).includes(`..`))\n\t\t\tthrow new Error(`Suite pattern must stay inside the package: ${pattern}.`)\n\t\tlet count = 0\n\t\tfor await (const filename of fs.glob(pattern, {\n\t\t\tcwd: base,\n\t\t\texclude: [\n\t\t\t\t`**/node_modules/**`,\n\t\t\t\t`**/.git/**`,\n\t\t\t\tpath.relative(base, stage),\n\t\t\t\t`${path.relative(base, stage)}/**`,\n\t\t\t],\n\t\t})) {\n\t\t\tconst source = path.resolve(base, filename)\n\t\t\tconst stat = await lstat(source)\n\t\t\tif (stat.isDirectory()) continue\n\t\t\tif (\n\t\t\t\t!stat.isFile() ||\n\t\t\t\t!within(await realpath(base), await realpath(source))\n\t\t\t)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Suite inputs must be regular package files: ${filename}.`,\n\t\t\t\t)\n\t\t\t// Refuse a symlink anywhere in the source path, even if its target is internal.\n\t\t\tlet segment = base\n\t\t\tfor (const part of filename.split(path.sep)) {\n\t\t\t\tsegment = path.join(segment, part)\n\t\t\t\tif ((await lstat(segment)).isSymbolicLink())\n\t\t\t\t\tthrow new Error(`Suite inputs cannot follow symlinks: ${filename}.`)\n\t\t\t}\n\t\t\tif (\n\t\t\t\t[\n\t\t\t\t\t`package.json`,\n\t\t\t\t\t`package-lock.json`,\n\t\t\t\t\t`npm-shrinkwrap.json`,\n\t\t\t\t\t`.npmrc`,\n\t\t\t\t].includes(filename) ||\n\t\t\t\tfilename.split(path.sep).includes(`node_modules`)\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Suite input collides with the consumer installation: ${filename}.`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tconst destination = path.resolve(stage, filename)\n\t\t\tif (!within(stage, destination))\n\t\t\t\tthrow new Error(`Suite path escapes its stage: ${filename}.`)\n\t\t\tawait mkdir(path.dirname(destination), { recursive: true })\n\t\t\tawait copyFile(source, destination)\n\t\t\tcount++\n\t\t}\n\t\tif (!count) throw new Error(`Suite pattern matched no files: ${pattern}.`)\n\t}\n}\n\nasync function findPackage(\n\tfrom: string,\n\tname: string,\n\tinstallation: string,\n): Promise<string | undefined> {\n\tconst origin = await realpath(from)\n\t// A linked store package may resolve siblings in its own installation namespace.\n\t// Never grant access to the store's or checkout's unrelated ancestor installs.\n\tconst parts = origin.split(path.sep)\n\tconst modules = parts.lastIndexOf(`node_modules`)\n\tconst boundary = within(installation, origin)\n\t\t? installation\n\t\t: modules < 0\n\t\t\t? origin\n\t\t\t: parts.slice(0, modules + 1).join(path.sep)\n\tconst lookup =\n\t\tcreateRequire(path.join(origin, `__breakage_probe__.ts`)).resolve.paths(\n\t\t\tname,\n\t\t) ?? []\n\tfor (const directory of lookup) {\n\t\tconst location = path.join(directory, name)\n\t\t// An installed but broken package must fail verification, not look absent.\n\t\tif (await exists(location)) {\n\t\t\tif (!within(installation, directory) && !within(boundary, directory))\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Dependency ${name} resolves outside the representative installation: ${location}.`,\n\t\t\t\t)\n\t\t\treturn await realpath(location)\n\t\t}\n\t}\n\treturn undefined\n}\n\nasync function resolvePackage(\n\tfrom: string,\n\tname: string,\n\tinstallation: string,\n): Promise<string> {\n\tconst location = await findPackage(from, name, installation)\n\tif (location !== undefined) return location\n\tthrow new Error(`Cannot resolve ${name} from ${from}.`)\n}\n\nexport async function stageCandidate(\n\tconfig: NpmConfig,\n\tbase: string,\n\tmanifest: Manifest,\n\tenvironment: Environment,\n\tsuites: NpmSuite[],\n): Promise<void> {\n\tconst { stage, candidates } = environment\n\tconst artifacts = {\n\t\t[manifest.name]: path.resolve(base, config.artifact),\n\t\t...Object.fromEntries(\n\t\t\tObject.entries(candidates).map(([name, entry]) => [name, entry.artifact]),\n\t\t),\n\t}\n\tif (candidates[manifest.name])\n\t\tthrow new Error(\n\t\t\t`The package under test cannot also be its own candidate peer.`,\n\t\t)\n\tfor (const artifact of Object.values(artifacts)) {\n\t\tif (!(await lstat(artifact)).isFile())\n\t\t\tthrow new Error(`Candidate artifact must be a packed file: ${artifact}.`)\n\t}\n\tawait writeFile(\n\t\tpath.join(stage, `package.json`),\n\t\tJSON.stringify({\n\t\t\tname: `breakage-consumer`,\n\t\t\tversion: `0.0.0`,\n\t\t\tprivate: true,\n\t\t\ttype: environment.manifest.type ?? `module`,\n\t\t\tdependencies: Object.fromEntries(\n\t\t\t\tObject.entries(artifacts).map(([name, artifact]) => [\n\t\t\t\t\tname,\n\t\t\t\t\t`file:${artifact}`,\n\t\t\t\t]),\n\t\t\t),\n\t\t}),\n\t)\n\tawait prepare(\n\t\tconfig.installCommand ??\n\t\t\t`npm install --prefix . --workspaces=false --ignore-scripts --legacy-peer-deps --package-lock=false --no-audit --no-fund`,\n\t\tstage,\n\t)\n\tfor (const [name] of Object.entries(artifacts)) {\n\t\tconst directory = path.join(stage, `node_modules`, name)\n\t\tif (!within(stage, await realpath(directory)))\n\t\t\tthrow new Error(\n\t\t\t\t`Candidate ${name} must be installed inside the test stage.`,\n\t\t\t)\n\t\tconst filename = path.join(directory, `package.json`)\n\t\tconst packed = await readManifest(filename)\n\t\tconst candidate = candidates[name]\n\t\tif (\n\t\t\tpacked.name !== name ||\n\t\t\t(candidate\n\t\t\t\t? ![candidate.currentVersion, candidate.version].includes(\n\t\t\t\t\t\tpacked.version,\n\t\t\t\t\t)\n\t\t\t\t: packed.version !== manifest.version)\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t`Candidate archive identity/version mismatch for ${name}@${packed.version}.`,\n\t\t\t)\n\t\t}\n\t\tconst expectedManifest = candidate?.manifest ?? manifest\n\t\tif (\n\t\t\tObject.keys({\n\t\t\t\t...packed.peerDependencies,\n\t\t\t\t...expectedManifest.peerDependencies,\n\t\t\t}).some(\n\t\t\t\t(peer) =>\n\t\t\t\t\tpacked.peerDependencies?.[peer] !==\n\t\t\t\t\t\texpectedManifest.peerDependencies?.[peer] ||\n\t\t\t\t\tBoolean(packed.peerDependenciesMeta?.[peer]?.optional) !==\n\t\t\t\t\t\tBoolean(expectedManifest.peerDependenciesMeta?.[peer]?.optional),\n\t\t\t)\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t`Candidate archive has stale peer declarations; rebuild and pack ${name}.`,\n\t\t\t)\n\t\t}\n\t\tif (candidate) {\n\t\t\tconst evidence = environment.peers[name]\n\t\t\tif (evidence) evidence.archiveVersion = packed.version\n\t\t\tif (packed.version !== candidate.version) {\n\t\t\t\t// Replace the entry: installed files may share an inode with a cache.\n\t\t\t\tconst raw = JSON.parse(await readFile(filename, `utf8`)) as Record<\n\t\t\t\t\tstring,\n\t\t\t\t\tunknown\n\t\t\t\t>\n\t\t\t\tconst temporary = path.join(\n\t\t\t\t\tpath.dirname(filename),\n\t\t\t\t\t`.breakage-${randomUUID()}.json`,\n\t\t\t\t)\n\t\t\t\tawait writeFile(\n\t\t\t\t\ttemporary,\n\t\t\t\t\tJSON.stringify({ ...raw, version: candidate.version }),\n\t\t\t\t\t{ flag: `wx` },\n\t\t\t\t)\n\t\t\t\ttry {\n\t\t\t\t\tawait rename(temporary, filename)\n\t\t\t\t} finally {\n\t\t\t\t\tawait rm(temporary, { force: true })\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfor (const suite of suites) await copySuite(base, stage, suite)\n\tawait verifyResolution(manifest, environment)\n}\n\nexport async function verifyResolution(\n\tmanifest: Manifest,\n\tenvironment: Environment,\n): Promise<void> {\n\tconst { stage, peers } = environment\n\tconst installation = await realpath(environment.directory)\n\tconst packages = [manifest.name, ...Object.keys(environment.candidates)]\n\tfor (const [peer, evidence] of Object.entries(peers)) {\n\t\tconst expected = await realpath(evidence.path)\n\t\tif ((await resolvePackage(stage, peer, installation)) !== expected)\n\t\t\tthrow new Error(`Tests resolve a shadow copy of ${peer}.`)\n\t\tfor (const name of packages) {\n\t\t\tif (name === peer) continue\n\t\t\tconst origin = path.join(stage, `node_modules`, name)\n\t\t\tif ((await resolvePackage(origin, peer, installation)) !== expected)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Candidate ${name} resolves a different instance of ${peer} than its tests.`,\n\t\t\t\t)\n\t\t}\n\t\tconst actual = await readManifest(path.join(expected, `package.json`))\n\t\tif (actual.name !== peer || actual.version !== evidence.version)\n\t\t\tthrow new Error(`Peer identity changed during execution: ${peer}.`)\n\t}\n\t// Runtime dependency peers can be singletons too (for example a React helper).\n\tconst visited = new Set<string>()\n\tconst pending = packages.map((name) => path.join(stage, `node_modules`, name))\n\twhile (pending.length) {\n\t\tconst directory = await realpath(pending.pop()!)\n\t\tif (visited.has(directory)) continue\n\t\tif (!directory.split(path.sep).includes(`node_modules`))\n\t\t\tthrow new Error(\n\t\t\t\t`Runtime dependency resolves to workspace source: ${directory}.`,\n\t\t\t)\n\t\tvisited.add(directory)\n\t\tconst installedManifest = await readManifest(\n\t\t\tpath.join(directory, `package.json`),\n\t\t)\n\t\tfor (const peer of Object.keys(installedManifest.peerDependencies ?? {})) {\n\t\t\tconst evidence = peers[peer]\n\t\t\tif (\n\t\t\t\tevidence &&\n\t\t\t\t(await resolvePackage(directory, peer, installation)) !==\n\t\t\t\t\t(await realpath(evidence.path))\n\t\t\t)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Runtime dependency ${installedManifest.name} resolves a different instance of ${peer}.`,\n\t\t\t\t)\n\t\t}\n\t\tconst optional = installedManifest.optionalDependencies ?? {}\n\t\tfor (const dependency of Object.keys({\n\t\t\t...installedManifest.dependencies,\n\t\t\t...optional,\n\t\t})) {\n\t\t\t// npm lets optionalDependencies override dependencies of the same name.\n\t\t\tif (Object.hasOwn(optional, dependency)) {\n\t\t\t\tconst location = await findPackage(directory, dependency, installation)\n\t\t\t\tif (location !== undefined) pending.push(location)\n\t\t\t} else {\n\t\t\t\tpending.push(await resolvePackage(directory, dependency, installation))\n\t\t\t}\n\t\t}\n\t}\n}\n","import path from \"node:path\"\n\nimport semver from \"semver\"\n\nimport { command, errorMessage } from \"./command.ts\"\nimport { validateConfig, validatePeerRanges } from \"./config.ts\"\nimport {\n\tcheckCandidatePeers,\n\tdiscover,\n\tmaySelectEnvironment,\n\tprepareEnvironment,\n\tstageCandidate,\n\tverifyResolution,\n\twithStage,\n} from \"./environment.ts\"\nimport type { Manifest } from \"./manifest.ts\"\nimport {\n\teras,\n\tmatches,\n\tnormalizeWorkspacePeers,\n\treadManifest,\n} from \"./manifest.ts\"\nimport { intent, previousManifest, supportChanges } from \"./release.ts\"\nimport type {\n\tNpmConfig,\n\tNpmReport,\n\tNpmRepresentativeResult,\n\tNpmTestSelection,\n\tReleaseIntent,\n} from \"./types.ts\"\n\nasync function checkSupport(\n\tconfig: NpmConfig,\n\tbase: string,\n\tmanifest: Manifest,\n): Promise<NpmReport[`support`]> {\n\ttry {\n\t\tconst previous = await previousManifest(config, base)\n\t\tif (!previous) return { status: `first-release`, changes: [] }\n\t\tif (previous.name !== manifest.name)\n\t\t\tthrow new Error(\n\t\t\t\t`Release baseline belongs to ${previous.name}, not ${manifest.name}.`,\n\t\t\t)\n\t\tconst changes = supportChanges(previous, manifest)\n\t\tif (!changes.length)\n\t\t\treturn { status: `unchanged`, previousVersion: previous.version, changes }\n\t\tconst evidence = await intent(config, {\n\t\t\tpackageName: manifest.name,\n\t\t\tpackageDirectory: base,\n\t\t\tcurrentVersion: manifest.version,\n\t\t})\n\t\tif (evidence.status === `none`)\n\t\t\treturn {\n\t\t\t\tstatus: `end-of-support`,\n\t\t\t\tpreviousVersion: previous.version,\n\t\t\t\tchanges,\n\t\t\t}\n\t\tif (!semver.gt(evidence.version, previous.version))\n\t\t\tthrow new Error(\n\t\t\t\t`The intended release must be newer than baseline ${previous.version}.`,\n\t\t\t)\n\t\tconst release = {\n\t\t\tversion: evidence.version,\n\t\t\tdelta: semver.diff(previous.version, evidence.version) ?? `none`,\n\t\t}\n\t\tconst certified = config.certifyBreaking\n\t\t\t? await config.certifyBreaking({\n\t\t\t\t\tpreviousVersion: previous.version,\n\t\t\t\t\trelease,\n\t\t\t\t\tchanges,\n\t\t\t\t})\n\t\t\t: false\n\t\tif (typeof certified !== `boolean`)\n\t\t\tthrow new Error(`certifyBreaking must return a boolean.`)\n\t\treturn {\n\t\t\tstatus: certified ? `certified` : `end-of-support`,\n\t\t\tpreviousVersion: previous.version,\n\t\t\tchanges,\n\t\t\trelease,\n\t\t}\n\t} catch (error) {\n\t\treturn { status: `setup-error`, changes: [], error: errorMessage(error) }\n\t}\n}\n\nasync function checkLocalReleases(\n\tconfig: NpmConfig,\n\tbase: string,\n\tmanifest: Manifest,\n\trepresentatives: NpmRepresentativeResult[],\n): Promise<string[]> {\n\tconst findings = await Promise.all(\n\t\tObject.entries(config.localPeers ?? {}).map(async ([peer, local]) => {\n\t\t\tconst range = manifest.peerDependencies?.[peer]\n\t\t\t// A registration may be retained solely to resolve an older baseline.\n\t\t\tif (range === undefined) return []\n\t\t\ttry {\n\t\t\t\tconst directory = path.resolve(base, local.directory)\n\t\t\t\tconst current = await readManifest(path.join(directory, `package.json`))\n\t\t\t\tif (current.name !== peer)\n\t\t\t\t\tthrow new Error(`Local peer identity mismatch for ${peer}.`)\n\t\t\t\tconst release = await intent(config, {\n\t\t\t\t\tpackageName: peer,\n\t\t\t\t\tpackageDirectory: directory,\n\t\t\t\t\tcurrentVersion: current.version,\n\t\t\t\t})\n\t\t\t\tif (release.status === `none`) return []\n\t\t\t\tif (!matches(release.version, range))\n\t\t\t\t\treturn [\n\t\t\t\t\t\t`Declared support for ${peer}: ${range} does not include its planned local release ${release.version}. Update the peer range to include the intended version.`,\n\t\t\t\t\t]\n\t\t\t\tif (\n\t\t\t\t\t!representatives.some(\n\t\t\t\t\t\t(result) =>\n\t\t\t\t\t\t\tresult.peers[peer]?.source === `candidate` &&\n\t\t\t\t\t\t\tresult.peers[peer]?.version === release.version &&\n\t\t\t\t\t\t\tresult.suites.some((suite) => suite.peer === peer),\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t\treturn [\n\t\t\t\t\t\t`No coordinated representative covers planned local peer ${peer}@${release.version}. Enroll ${peer} with breakage.candidates and configure its relationship suite.`,\n\t\t\t\t\t]\n\t\t\t\treturn []\n\t\t\t} catch (error) {\n\t\t\t\treturn [\n\t\t\t\t\t`Cannot inspect planned local release for ${peer}: ${errorMessage(error)}`,\n\t\t\t\t]\n\t\t\t}\n\t\t}),\n\t)\n\treturn findings.flat()\n}\n\nasync function runRepresentative(\n\tconfig: NpmConfig,\n\tbase: string,\n\tmanifest: Manifest,\n\tdirectory: string,\n\tcoverageOnly: boolean,\n\tselection?: NpmTestSelection,\n): Promise<NpmRepresentativeResult> {\n\tconst label = path.relative(base, directory).split(path.sep).join(`/`)\n\tconst result: NpmRepresentativeResult = {\n\t\tpath: label,\n\t\tstatus: `skipped`,\n\t\tpeers: {},\n\t\tsuites: [],\n\t\twarnings: [],\n\t}\n\tif (\n\t\tselection &&\n\t\t`representative` in selection &&\n\t\tpath.resolve(base, selection.representative) !== directory\n\t)\n\t\treturn result\n\ttry {\n\t\tif (\n\t\t\tselection &&\n\t\t\t`peer` in selection &&\n\t\t\t!(await maySelectEnvironment(\n\t\t\t\tconfig,\n\t\t\t\tbase,\n\t\t\t\tdirectory,\n\t\t\t\tmanifest,\n\t\t\t\tselection,\n\t\t\t))\n\t\t)\n\t\t\treturn result\n\t\treturn await withStage(directory, async (stage) => {\n\t\t\tconst environment = await prepareEnvironment(\n\t\t\t\tconfig,\n\t\t\t\tbase,\n\t\t\t\tdirectory,\n\t\t\t\tstage,\n\t\t\t\tmanifest,\n\t\t\t)\n\t\t\tresult.peers = environment.peers\n\t\t\tfor (const peer of Object.keys(manifest.peerDependencies ?? {})) {\n\t\t\t\tif (\n\t\t\t\t\t!result.peers[peer] &&\n\t\t\t\t\t!manifest.peerDependenciesMeta?.[peer]?.optional\n\t\t\t\t)\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Complete representative is missing required peer ${peer}.`,\n\t\t\t\t\t)\n\t\t\t}\n\t\t\tfor (const [peer, evidence] of Object.entries(result.peers)) {\n\t\t\t\tconst range = manifest.peerDependencies?.[peer]\n\t\t\t\tif (range !== undefined && !matches(evidence.version, range))\n\t\t\t\t\tresult.warnings.push(\n\t\t\t\t\t\t`${peer}@${evidence.version} is outside declared support.`,\n\t\t\t\t\t)\n\t\t\t}\n\t\t\tif (\n\t\t\t\tselection &&\n\t\t\t\t`peer` in selection &&\n\t\t\t\t(!result.peers[selection.peer] ||\n\t\t\t\t\t!matches(result.peers[selection.peer]!.version, selection.range))\n\t\t\t)\n\t\t\t\treturn result\n\t\t\tconst peers = Object.keys(config.suites).filter((peer) => {\n\t\t\t\tconst evidence = result.peers[peer]\n\t\t\t\tif (!evidence) return false\n\t\t\t\tif (selection && `peer` in selection) return peer === selection.peer\n\t\t\t\tif (selection && `representative` in selection) return true\n\t\t\t\treturn matches(evidence.version, manifest.peerDependencies![peer]!)\n\t\t\t})\n\t\t\tresult.suites = peers.map((peer) => ({ peer, status: `not-run` }))\n\t\t\tif (!peers.length) return result\n\t\t\tresult.warnings.push(...checkCandidatePeers(environment, !!selection))\n\t\t\tif (coverageOnly) {\n\t\t\t\tresult.status = `audited`\n\t\t\t\treturn result\n\t\t\t}\n\t\t\tawait stageCandidate(\n\t\t\t\tconfig,\n\t\t\t\tbase,\n\t\t\t\tmanifest,\n\t\t\t\tenvironment,\n\t\t\t\tpeers.map((peer) => config.suites[peer]!),\n\t\t\t)\n\t\t\tfor (const suite of result.suites) {\n\t\t\t\ttry {\n\t\t\t\t\tawait verifyResolution(manifest, environment)\n\t\t\t\t\tconst execution = await command(\n\t\t\t\t\t\tconfig.suites[suite.peer]!.command,\n\t\t\t\t\t\tstage,\n\t\t\t\t\t)\n\t\t\t\t\tawait verifyResolution(manifest, environment)\n\t\t\t\t\tsuite.status =\n\t\t\t\t\t\texecution.code === 0\n\t\t\t\t\t\t\t? `passed`\n\t\t\t\t\t\t\t: execution.code === 1\n\t\t\t\t\t\t\t\t? `compatibility-failure`\n\t\t\t\t\t\t\t\t: `setup-error`\n\t\t\t\t\tif (execution.output) suite.output = execution.output\n\t\t\t\t} catch (error) {\n\t\t\t\t\tsuite.status = `setup-error`\n\t\t\t\t\tsuite.output = errorMessage(error)\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult.status = result.suites.some(\n\t\t\t\t(suite) => suite.status === `setup-error`,\n\t\t\t)\n\t\t\t\t? `setup-error`\n\t\t\t\t: result.suites.some(\n\t\t\t\t\t\t\t(suite) => suite.status === `compatibility-failure`,\n\t\t\t\t\t )\n\t\t\t\t\t? `compatibility-failure`\n\t\t\t\t\t: `passed`\n\t\t\treturn result\n\t\t})\n\t} catch (error) {\n\t\tresult.status = `setup-error`\n\t\tresult.error = errorMessage(error)\n\t\treturn result\n\t}\n}\n\nasync function run(\n\tconfig: NpmConfig,\n\tbaseDirectory: string,\n\tcoverageOnly: boolean,\n\tselection?: NpmTestSelection,\n): Promise<NpmReport> {\n\tconst report: NpmReport = {\n\t\tpackage: { name: `(unresolved)`, version: `(unresolved)` },\n\t\tmode: selection ? `test` : coverageOnly ? `coverage-only` : `check`,\n\t\texitCode: 0,\n\t\trepresentatives: [],\n\t\tcoverage: [],\n\t\tsupport: { status: `not-checked`, changes: [] },\n\t\terrors: [],\n\t}\n\ttry {\n\t\tvalidateConfig(config)\n\t\tconst base = path.resolve(baseDirectory, config.packageDirectory ?? `.`)\n\t\tconst manifest = await normalizeWorkspacePeers(\n\t\t\tawait readManifest(path.join(base, `package.json`)),\n\t\t)\n\t\treport.package = { name: manifest.name, version: manifest.version }\n\t\tvalidatePeerRanges(manifest.peerDependencies ?? {})\n\t\tfor (const peer of Object.keys(config.suites)) {\n\t\t\tif (!manifest.peerDependencies?.[peer])\n\t\t\t\tthrow new Error(`Suite ${peer} has no peerDependencies declaration.`)\n\t\t}\n\t\tfor (const peer of Object.keys(config.localPeers ?? {})) {\n\t\t\tif (manifest.peerDependencies?.[peer] && !config.suites[peer])\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Declared local peer ${peer} needs a relationship suite.`,\n\t\t\t\t)\n\t\t}\n\t\tif (selection && `peer` in selection) {\n\t\t\tif (!config.suites[selection.peer])\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`No relationship suite configured for ${selection.peer}.`,\n\t\t\t\t)\n\t\t\teras(selection.range)\n\t\t}\n\t\t// One piece of release evidence per package per invocation, including failures.\n\t\tconst releases = new Map<string, Promise<ReleaseIntent>>()\n\t\tconst configuredHook = config.releaseIntent\n\t\tconst effective: NpmConfig = {\n\t\t\t...config,\n\t\t\treleaseIntent: (context) => {\n\t\t\t\tlet pending = releases.get(context.packageDirectory)\n\t\t\t\tif (!pending) {\n\t\t\t\t\tpending = Promise.resolve().then(() =>\n\t\t\t\t\t\tconfiguredHook\n\t\t\t\t\t\t\t? configuredHook(context)\n\t\t\t\t\t\t\t: ({ status: `none` } as const),\n\t\t\t\t\t)\n\t\t\t\t\treleases.set(context.packageDirectory, pending)\n\t\t\t\t}\n\t\t\t\treturn pending\n\t\t\t},\n\t\t}\n\t\tconst directories = await discover(config, base)\n\t\tconst [support, representatives] = await Promise.all([\n\t\t\tselection\n\t\t\t\t? Promise.resolve(report.support)\n\t\t\t\t: checkSupport(effective, base, manifest),\n\t\t\tPromise.all(\n\t\t\t\tdirectories.map((directory) =>\n\t\t\t\t\trunRepresentative(\n\t\t\t\t\t\teffective,\n\t\t\t\t\t\tbase,\n\t\t\t\t\t\tmanifest,\n\t\t\t\t\t\tdirectory,\n\t\t\t\t\t\tcoverageOnly,\n\t\t\t\t\t\tselection,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t])\n\t\treport.support = support\n\t\treport.representatives = representatives\n\t\tif (!selection) {\n\t\t\treport.errors.push(\n\t\t\t\t...(await checkLocalReleases(\n\t\t\t\t\teffective,\n\t\t\t\t\tbase,\n\t\t\t\t\tmanifest,\n\t\t\t\t\trepresentatives,\n\t\t\t\t)),\n\t\t\t)\n\t\t\tfor (const peer of Object.keys(config.suites)) {\n\t\t\t\tfor (const era of eras(manifest.peerDependencies![peer]!)) {\n\t\t\t\t\tconst matching = representatives\n\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t(representative) =>\n\t\t\t\t\t\t\t\trepresentative.peers[peer] &&\n\t\t\t\t\t\t\t\tmatches(representative.peers[peer]!.version, era),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.map((representative) => representative.path)\n\t\t\t\t\treport.coverage.push({ peer, era, representatives: matching })\n\t\t\t\t\tif (!matching.length)\n\t\t\t\t\t\treport.errors.push(`No representative covers ${peer}: ${era}.`)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (\n\t\t\t!representatives.some(\n\t\t\t\t(representative) => representative.suites.length > 0,\n\t\t\t)\n\t\t) {\n\t\t\treport.errors.push(\n\t\t\t\t`No representative matched the requested test selection.`,\n\t\t\t)\n\t\t}\n\t\tif (\n\t\t\tsupport.status === `setup-error` ||\n\t\t\treport.errors.length ||\n\t\t\trepresentatives.some((result) => result.status === `setup-error`)\n\t\t)\n\t\t\treport.exitCode = 2\n\t\telse if (\n\t\t\tsupport.status === `end-of-support` ||\n\t\t\trepresentatives.some(\n\t\t\t\t(result) => result.status === `compatibility-failure`,\n\t\t\t)\n\t\t)\n\t\t\treport.exitCode = 1\n\t} catch (error) {\n\t\treport.errors.push(errorMessage(error))\n\t\treport.exitCode = 2\n\t}\n\treturn report\n}\n\nexport async function npmCheck(\n\tconfig: NpmConfig,\n\toptions: { baseDirectory?: string; coverageOnly?: boolean } = {},\n): Promise<NpmReport> {\n\treturn await run(\n\t\tconfig,\n\t\toptions.baseDirectory ?? process.cwd(),\n\t\toptions.coverageOnly ?? false,\n\t)\n}\n\nexport async function npmTest(\n\tconfig: NpmConfig,\n\tselection: NpmTestSelection,\n\toptions: { baseDirectory?: string } = {},\n): Promise<NpmReport> {\n\treturn await run(\n\t\tconfig,\n\t\toptions.baseDirectory ?? process.cwd(),\n\t\tfalse,\n\t\tselection,\n\t)\n}\n\nexport function formatNpmReport(report: NpmReport): string {\n\tconst lines = [\n\t\t`${report.package.name}@${report.package.version} — npm ${report.mode}`,\n\t]\n\tfor (const result of report.representatives) {\n\t\tlines.push(`${result.path}: ${result.status}`)\n\t\tfor (const [peer, evidence] of Object.entries(result.peers)) {\n\t\t\tlines.push(\n\t\t\t\t` ${peer}@${evidence.version}${evidence.source === `candidate` ? ` (conditional on publication)` : ` (installed)`}`,\n\t\t\t)\n\t\t}\n\t\tfor (const suite of result.suites) {\n\t\t\tlines.push(` ${suite.peer}: ${suite.status}`)\n\t\t\tif (suite.status !== `passed` && suite.output) lines.push(suite.output)\n\t\t}\n\t\tfor (const warning of result.warnings) lines.push(` Warning: ${warning}`)\n\t\tif (result.error) lines.push(` ${result.error}`)\n\t}\n\tlines.push(`Support: ${report.support.status}`)\n\tfor (const change of report.support.changes)\n\t\tlines.push(\n\t\t\t` ${change.peer}: ${change.previous ?? `(unrestricted)`} → ${change.current ?? `(unrestricted)`} (${change.reason})`,\n\t\t)\n\tif (report.support.release)\n\t\tlines.push(\n\t\t\t` Intended release: ${report.support.release.version} (${report.support.release.delta})`,\n\t\t)\n\tif (report.support.error) lines.push(report.support.error)\n\tlines.push(...report.errors)\n\tif (report.mode === `coverage-only`)\n\t\tlines.push(\n\t\t\t`Coverage audit only; compatibility assertions were not executed.`,\n\t\t)\n\treturn `${lines.join(`\\n`)}\\n`\n}\n","import { exec } from \"node:child_process\"\nimport path from \"node:path\"\n\nimport { minimatch } from \"minimatch\"\nimport { simpleGit } from \"simple-git\"\nimport type { Chronicle } from \"takua\"\nimport logger from \"takua\"\n\nimport { readBaseline } from \"./baseline.ts\"\nimport { withDirectoryLock } from \"./directory-lock.ts\"\nimport { latestReleaseTag as selectLatestReleaseTag } from \"./release-tag.ts\"\nimport { withTestFileState } from \"./test-file-state.ts\"\n\nexport type { BreakageBaseline, BreakagePreludeOptions } from \"./baseline.ts\"\nexport { breakagePrelude } from \"./baseline.ts\"\nexport { formatNpmReport, npmCheck, npmTest } from \"./npm/check.ts\"\nexport type {\n\tNpmConfig,\n\tNpmPeerEvidence,\n\tNpmReport,\n\tNpmRepresentativeResult,\n\tNpmSuite,\n\tNpmSuiteResult,\n\tNpmTestSelection,\n\tReleaseContext,\n\tReleaseEvidence,\n\tReleaseIntent,\n\tSupportChange,\n} from \"./npm/types.ts\"\n\nexport type BreakageOptions = {\n\ttagPattern?: string | undefined\n\tbaselineFile?: string | undefined\n\ttestPattern: string\n\ttestCommand: string\n\tcertifyCommand: string\n\tbaseDirname?: string\n\tverbose?: boolean | undefined\n}\n\nexport type BreakageOutcome =\n\t| { gitWasClean: false }\n\t| {\n\t\t\tgitWasClean: true\n\t\t\tlastReleaseFound: false\n\t }\n\t| {\n\t\t\tgitWasClean: true\n\t\t\tlastReleaseFound: true\n\t\t\tlastReleaseTag: string\n\t\t\ttestsWereFound: false\n\t }\n\t| {\n\t\t\tgitWasClean: true\n\t\t\tlastReleaseFound: true\n\t\t\tlastReleaseTag: string\n\t\t\ttestsWereFound: true\n\t\t\ttestsFound: string[]\n\t\t\tbreakingChangesFound: false\n\t }\n\t| {\n\t\t\tgitWasClean: true\n\t\t\tlastReleaseFound: true\n\t\t\tlastReleaseTag: string\n\t\t\ttestsWereFound: true\n\t\t\ttestsFound: string[]\n\t\t\tbreakingChangesFound: true\n\t\t\ttestResult: string\n\t\t\tbreakingChangesCertified: boolean\n\t\t\tcertificationStdout: string\n\t\t\tcertificationStderr: string\n\t }\n\nexport async function breakage({\n\ttagPattern,\n\tbaselineFile,\n\ttestPattern,\n\ttestCommand,\n\tcertifyCommand,\n\tbaseDirname = process.cwd(),\n\tverbose = false,\n}: BreakageOptions): Promise<BreakageOutcome & { summary: string }> {\n\tlet mark: Chronicle[`mark`] | undefined\n\tlet logMarks: Chronicle[`logMarks`] | undefined\n\tif (verbose) {\n\t\tconst chronicle = logger.makeChronicle()\n\t\tmark = chronicle.mark\n\t\tlogMarks = chronicle.logMarks\n\t}\n\tmark?.(`breakage`)\n\tconst git = simpleGit(baseDirname)\n\tmark?.(`spawn git`)\n\tconst isGitRepo = await git.checkIsRepo()\n\tmark?.(`is git repository`)\n\tif (!isGitRepo) {\n\t\treturn {\n\t\t\tsummary: `The git repository must be clean to run this command.`,\n\t\t\tgitWasClean: false,\n\t\t}\n\t}\n\tif (\n\t\t!(await withTestFileState(git, baseDirname, (state) => state.isClean()))\n\t) {\n\t\treturn {\n\t\t\tsummary: `The git repository must be clean to run this command.`,\n\t\t\tgitWasClean: false,\n\t\t}\n\t}\n\tlet latestReleaseTag: string | undefined\n\tlet releaseCommit: string\n\tif (baselineFile !== undefined) {\n\t\tconst baseline = await readBaseline(\n\t\t\tgit,\n\t\t\tpath.resolve(baseDirname, baselineFile),\n\t\t\t{ tagPattern },\n\t\t)\n\t\tlatestReleaseTag = baseline.ref\n\t\treleaseCommit = baseline.commit\n\t\tmark?.(`read pinned release baseline`)\n\t} else {\n\t\tconst tagsRemote = await git.listRemote([`--tags`, `origin`])\n\n\t\tmark?.(`list remote tags`)\n\t\tlatestReleaseTag = selectLatestReleaseTag(tagsRemote, tagPattern)\n\t\tmark?.(`found latest release tag`)\n\t\tif (!latestReleaseTag) {\n\t\t\treturn {\n\t\t\t\tsummary: `No tags found matching the pattern \"${tagPattern}\".`,\n\t\t\t\tgitWasClean: true,\n\t\t\t\tlastReleaseFound: false,\n\t\t\t} as const\n\t\t}\n\t\tconst commonGitDirectory = await git.revparse([\n\t\t\t`--path-format=absolute`,\n\t\t\t`--git-common-dir`,\n\t\t])\n\t\tawait withDirectoryLock(\n\t\t\tpath.join(commonGitDirectory, `breakage-fetch.lock`),\n\t\t\t() =>\n\t\t\t\tgit.fetch([\n\t\t\t\t\t`origin`,\n\t\t\t\t\t`${latestReleaseTag}:${latestReleaseTag}`,\n\t\t\t\t\t`--no-tags`,\n\t\t\t\t\t`--no-write-fetch-head`,\n\t\t\t\t]),\n\t\t)\n\n\t\treleaseCommit = await git.revparse([`${latestReleaseTag}^{commit}`])\n\t\tmark?.(`fetched latest release tag`)\n\t}\n\n\tlet productionFiles: string[]\n\ttry {\n\t\tproductionFiles = (\n\t\t\tawait git.raw([`ls-tree`, `-r`, `--name-only`, `-z`, releaseCommit])\n\t\t)\n\t\t\t.split(`\\0`)\n\t\t\t.filter(Boolean)\n\t} catch (thrown) {\n\t\tmark?.(`failed to list production files`)\n\t\tconst message =\n\t\t\tthrown instanceof Error\n\t\t\t\t? thrown.message\n\t\t\t\t: typeof thrown === `string`\n\t\t\t\t\t? thrown\n\t\t\t\t\t: undefined\n\t\tconst summary = `Failed to list production files${\n\t\t\tmessage ? `: ${message}` : `.`\n\t\t}`\n\t\treturn {\n\t\t\tsummary,\n\t\t\tgitWasClean: true,\n\t\t\tlastReleaseFound: true,\n\t\t\tlastReleaseTag: latestReleaseTag,\n\t\t\ttestsWereFound: false,\n\t\t} as const\n\t}\n\tmark?.(`listed all files checked into git`)\n\tconst productionTestFiles = productionFiles.filter((file) =>\n\t\tminimatch(file, testPattern),\n\t)\n\tmark?.(`filtered to public test files`)\n\n\tconst prepared = await withTestFileState(git, baseDirname, async (state) => {\n\t\tif (!(await state.isClean())) {\n\t\t\treturn {\n\t\t\t\tsummary: `The git repository must be clean to run this command.`,\n\t\t\t\tgitWasClean: false,\n\t\t\t} as const\n\t\t}\n\n\t\tif (productionTestFiles.length === 0) {\n\t\t\treturn {\n\t\t\t\tsummary: `No tests were found matching the pattern \"${testPattern}\".`,\n\t\t\t\tgitWasClean: true,\n\t\t\t\tlastReleaseFound: true,\n\t\t\t\tlastReleaseTag: latestReleaseTag,\n\t\t\t\ttestsWereFound: false,\n\t\t\t} as const\n\t\t}\n\t\tconst restore = await state.replaceTests(releaseCommit, productionTestFiles)\n\t\tmark?.(`restored public tests from latest release tag`)\n\t\treturn { latestReleaseTag, productionTestFiles, restore }\n\t})\n\tif (prepared.summary !== undefined) return prepared\n\tconst { restore } = prepared\n\n\ttry {\n\t\tconst noBreakingChangesDetected = await new Promise<\n\t\t\tBreakageOutcome & { summary: string }\n\t\t>((resolve, reject) => {\n\t\t\tconst result = exec(\n\t\t\t\ttestCommand,\n\t\t\t\t{ cwd: baseDirname },\n\t\t\t\t(_, __, stderr) => {\n\t\t\t\t\tif (result.exitCode === 0) {\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tsummary: `No breaking changes were detected.`,\n\t\t\t\t\t\t\tgitWasClean: true,\n\t\t\t\t\t\t\tlastReleaseFound: true,\n\t\t\t\t\t\t\tlastReleaseTag: latestReleaseTag,\n\t\t\t\t\t\t\ttestsWereFound: true,\n\t\t\t\t\t\t\ttestsFound: productionTestFiles,\n\t\t\t\t\t\t\tbreakingChangesFound: false,\n\t\t\t\t\t\t})\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(stderr)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t)\n\t\t})\n\t\tmark?.(`passed tests`)\n\t\treturn noBreakingChangesDetected\n\t} catch (thrown) {\n\t\tmark?.(`failed tests`)\n\t\tconst breakingChangesCertified = await new Promise<\n\t\t\tBreakageOutcome & { summary: string }\n\t\t>((resolve) => {\n\t\t\tconst result = exec(\n\t\t\t\tcertifyCommand,\n\t\t\t\t{ cwd: baseDirname },\n\t\t\t\t(_, stdout, stderr) => {\n\t\t\t\t\tconst wereCertified = result.exitCode === 0\n\t\t\t\t\tmark?.(`${wereCertified ? `passed` : `failed`} certification`)\n\t\t\t\t\tresolve({\n\t\t\t\t\t\tsummary: wereCertified\n\t\t\t\t\t\t\t? `Breaking changes were found and certified.`\n\t\t\t\t\t\t\t: `Breaking changes were found, but not certified.`,\n\t\t\t\t\t\tgitWasClean: true,\n\t\t\t\t\t\tlastReleaseFound: true,\n\t\t\t\t\t\tlastReleaseTag: latestReleaseTag,\n\t\t\t\t\t\ttestsWereFound: true,\n\t\t\t\t\t\ttestsFound: productionTestFiles,\n\t\t\t\t\t\tbreakingChangesFound: true,\n\t\t\t\t\t\ttestResult: thrown as string,\n\t\t\t\t\t\tbreakingChangesCertified: wereCertified,\n\t\t\t\t\t\tcertificationStdout: stdout,\n\t\t\t\t\t\tcertificationStderr: stderr,\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t)\n\t\t})\n\t\treturn breakingChangesCertified\n\t} finally {\n\t\tawait restore()\n\t\tmark?.(`restored original public tests`)\n\t\tlogMarks?.()\n\t}\n}\n"],"mappings":"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"}
|
package/dist/breakage.d.ts
CHANGED
|
@@ -17,6 +17,118 @@ type BreakageBaseline = {
|
|
|
17
17
|
/** Resolve and fetch a release without running tests or changing the worktree. */
|
|
18
18
|
export declare function breakagePrelude({ out, tagPattern, baseDirname }: BreakagePreludeOptions): Promise<BreakageBaseline>;
|
|
19
19
|
//#endregion
|
|
20
|
+
//#region src/npm/types.d.ts
|
|
21
|
+
type ReleaseIntent = {
|
|
22
|
+
status: `none`;
|
|
23
|
+
} | {
|
|
24
|
+
status: `release`;
|
|
25
|
+
version: string;
|
|
26
|
+
};
|
|
27
|
+
type ReleaseContext = {
|
|
28
|
+
packageName: string;
|
|
29
|
+
packageDirectory: string;
|
|
30
|
+
currentVersion: string;
|
|
31
|
+
};
|
|
32
|
+
type SupportChange = {
|
|
33
|
+
peer: string;
|
|
34
|
+
reason: `narrowed-range` | `required-peer`;
|
|
35
|
+
previous: string | null;
|
|
36
|
+
current: string | null;
|
|
37
|
+
};
|
|
38
|
+
type ReleaseEvidence = {
|
|
39
|
+
version: string;
|
|
40
|
+
delta: string;
|
|
41
|
+
};
|
|
42
|
+
type NpmSuite = {
|
|
43
|
+
/** Package-relative globs; preserve relative paths inside the stage. */
|
|
44
|
+
files: string[];
|
|
45
|
+
/** Run once; 1 means assertion failure, other nonzero codes mean setup failure. */
|
|
46
|
+
command: string;
|
|
47
|
+
};
|
|
48
|
+
type NpmConfig = {
|
|
49
|
+
packageDirectory?: string;
|
|
50
|
+
artifact: string;
|
|
51
|
+
representatives: string | string[];
|
|
52
|
+
lockfile: string;
|
|
53
|
+
prepareCommand: string;
|
|
54
|
+
installCommand?: string;
|
|
55
|
+
suites: Record<string, NpmSuite>;
|
|
56
|
+
/** Currently declared local peers must support and exercise each planned release. */
|
|
57
|
+
localPeers?: Record<string, {
|
|
58
|
+
directory: string;
|
|
59
|
+
artifact: string;
|
|
60
|
+
}>;
|
|
61
|
+
baseline: {
|
|
62
|
+
firstRelease: true;
|
|
63
|
+
} | {
|
|
64
|
+
tagPattern?: string;
|
|
65
|
+
baselineFile?: string;
|
|
66
|
+
};
|
|
67
|
+
releaseIntent?: (context: ReleaseContext) => ReleaseIntent | Promise<ReleaseIntent>;
|
|
68
|
+
certifyBreaking?: (context: {
|
|
69
|
+
previousVersion: string;
|
|
70
|
+
release: ReleaseEvidence;
|
|
71
|
+
changes: SupportChange[];
|
|
72
|
+
}) => boolean | Promise<boolean>;
|
|
73
|
+
};
|
|
74
|
+
type NpmTestSelection = {
|
|
75
|
+
peer: string;
|
|
76
|
+
range: string;
|
|
77
|
+
} | {
|
|
78
|
+
representative: string;
|
|
79
|
+
};
|
|
80
|
+
type NpmPeerEvidence = {
|
|
81
|
+
version: string;
|
|
82
|
+
path: string;
|
|
83
|
+
source: `installed` | `candidate`;
|
|
84
|
+
archiveVersion?: string;
|
|
85
|
+
};
|
|
86
|
+
type NpmSuiteResult = {
|
|
87
|
+
peer: string;
|
|
88
|
+
status: `passed` | `compatibility-failure` | `setup-error` | `not-run`;
|
|
89
|
+
output?: string;
|
|
90
|
+
};
|
|
91
|
+
type NpmRepresentativeResult = {
|
|
92
|
+
path: string;
|
|
93
|
+
status: `passed` | `audited` | `skipped` | `compatibility-failure` | `setup-error`;
|
|
94
|
+
peers: Record<string, NpmPeerEvidence>;
|
|
95
|
+
suites: NpmSuiteResult[];
|
|
96
|
+
warnings: string[];
|
|
97
|
+
error?: string;
|
|
98
|
+
};
|
|
99
|
+
type NpmReport = {
|
|
100
|
+
package: {
|
|
101
|
+
name: string;
|
|
102
|
+
version: string;
|
|
103
|
+
};
|
|
104
|
+
mode: `check` | `coverage-only` | `test`;
|
|
105
|
+
exitCode: 0 | 1 | 2;
|
|
106
|
+
representatives: NpmRepresentativeResult[];
|
|
107
|
+
coverage: {
|
|
108
|
+
peer: string;
|
|
109
|
+
era: string;
|
|
110
|
+
representatives: string[];
|
|
111
|
+
}[];
|
|
112
|
+
support: {
|
|
113
|
+
status: `unchanged` | `certified` | `end-of-support` | `first-release` | `not-checked` | `setup-error`;
|
|
114
|
+
changes: SupportChange[];
|
|
115
|
+
previousVersion?: string;
|
|
116
|
+
release?: ReleaseEvidence;
|
|
117
|
+
error?: string;
|
|
118
|
+
};
|
|
119
|
+
errors: string[];
|
|
120
|
+
};
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/npm/check.d.ts
|
|
123
|
+
export declare function npmCheck(config: NpmConfig, options?: {
|
|
124
|
+
baseDirectory?: string;
|
|
125
|
+
coverageOnly?: boolean;
|
|
126
|
+
}): Promise<NpmReport>;
|
|
127
|
+
export declare function npmTest(config: NpmConfig, selection: NpmTestSelection, options?: {
|
|
128
|
+
baseDirectory?: string;
|
|
129
|
+
}): Promise<NpmReport>;
|
|
130
|
+
export declare function formatNpmReport(report: NpmReport): string;
|
|
131
|
+
//#endregion
|
|
20
132
|
//#region src/breakage.d.ts
|
|
21
133
|
export type BreakageOptions = {
|
|
22
134
|
tagPattern?: string | undefined;
|
|
@@ -60,5 +172,5 @@ export declare function breakage({ tagPattern, baselineFile, testPattern, testCo
|
|
|
60
172
|
summary: string;
|
|
61
173
|
}>;
|
|
62
174
|
//#endregion
|
|
63
|
-
export type { BreakageBaseline, BreakagePreludeOptions };
|
|
175
|
+
export type { BreakageBaseline, BreakagePreludeOptions, NpmConfig, NpmPeerEvidence, NpmReport, NpmRepresentativeResult, NpmSuite, NpmSuiteResult, NpmTestSelection, ReleaseContext, ReleaseEvidence, ReleaseIntent, SupportChange };
|
|
64
176
|
//# sourceMappingURL=breakage.d.ts.map
|
package/dist/breakage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"breakage.d.ts","names":[],"sources":["../src/baseline.ts","../src/breakage.ts"],"mappings":";;KAUY;EACX;EACA;;KAGW,yBAAyB;EAAoB;;KAE7C;EACX;EACA;EACA;EACA;EACA;;;wBAoBqB,kBACrB,KACA,YACA,eACE,yBAAyB,QAAQ;;;
|
|
1
|
+
{"version":3,"file":"breakage.d.ts","names":[],"sources":["../src/baseline.ts","../src/npm/types.ts","../src/npm/check.ts","../src/breakage.ts"],"mappings":";;KAUY;EACX;EACA;;KAGW,yBAAyB;EAAoB;;KAE7C;EACX;EACA;EACA;EACA;EACA;;;wBAoBqB,kBACrB,KACA,YACA,eACE,yBAAyB,QAAQ;;;KC9CxB;EACP;;EACA;EAAmB;;KAEZ;EACX;EACA;EACA;;KAGW;EACX;EACA;EACA;EACA;;KAGW;EACX;EACA;;KAGW;;EAEX;;EAEA;;KAGW;EACX;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ,eAAe;;EAEvB,aAAa;IAAiB;IAAmB;;EACjD;IACK;;IACA;IAAqB;;EAC1B,iBACC,SAAS,mBACL,gBAAgB,QAAQ;EAC7B,mBAAmB;IAClB;IACA,SAAS;IACT,SAAS;kBACM;;KAGL;EACP;EAAc;;EACd;;KAEO;EACX;EACA;EACA;EACA;;KAGW;EACX;EACA;EACA;;KAGW;EACX;EACA;EAMA,OAAO,eAAe;EACtB,QAAQ;EACR;EACA;;KAGW;EACX;IAAW;IAAc;;EACzB;EACA;EACA,iBAAiB;EACjB;IAAY;IAAc;IAAa;;EACvC;IACC;IAOA,SAAS;IACT;IACA,UAAU;IACV;;EAED;;;;wBC+RqB,SACrB,QAAQ,WACR;EAAW;EAAwB;IACjC,QAAQ;wBAQW,QACrB,QAAQ,WACR,WAAW,kBACX;EAAW;IACT,QAAQ;wBASK,gBAAgB,QAAQ;;;YC/X5B;EACX;EACA;EACA;EACA;EACA;EACA;EACA;;YAGW;EACP;;EAEF;EACA;;EAGA;EACA;EACA;EACA;;EAGA;EACA;EACA;EACA;EACA;EACA;;EAGA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;wBAGmB,WACrB,YACA,cACA,aACA,aACA,gBACA,aACA,WACE,kBAAkB,QAAQ;EAAoB"}
|
package/dist/breakage.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as breakage,
|
|
1
|
+
export { t as breakage, c as breakagePrelude, n as formatNpmReport, r as npmCheck, i as npmTest } from "./breakage-B7dJsgcu.js";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"additionalProperties": false,
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"config": {
|
|
7
|
+
"type": "string"
|
|
8
|
+
},
|
|
9
|
+
"coverageOnly": {
|
|
10
|
+
"type": "boolean"
|
|
11
|
+
},
|
|
12
|
+
"json": {
|
|
13
|
+
"type": "boolean"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"additionalProperties": false,
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"config": {
|
|
7
|
+
"type": "string"
|
|
8
|
+
},
|
|
9
|
+
"json": {
|
|
10
|
+
"type": "boolean"
|
|
11
|
+
},
|
|
12
|
+
"representative": {
|
|
13
|
+
"type": "string"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"additionalProperties": false,
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"config": {
|
|
7
|
+
"type": "string"
|
|
8
|
+
},
|
|
9
|
+
"json": {
|
|
10
|
+
"type": "boolean"
|
|
11
|
+
},
|
|
12
|
+
"representative": {
|
|
13
|
+
"type": "string"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
package/dist/breakage.x.js
CHANGED
|
@@ -1,10 +1,93 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import { a as validateConfig, c as breakagePrelude, i as npmTest, n as formatNpmReport, o as record, r as npmCheck, s as errorMessage, t as breakage } from "./breakage-B7dJsgcu.js";
|
|
3
|
+
import path from "node:path";
|
|
4
4
|
import logger from "takua";
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
5
6
|
import { inspect } from "node:util";
|
|
6
7
|
import { type } from "arktype";
|
|
7
|
-
import { cli, completionResponse, encapsulate, help, logWarnings, noOptions, optional, options, parseBooleanOption } from "comline";
|
|
8
|
+
import { cli, completionResponse, encapsulate, help, logWarnings, noOptions, optional, options, parseBooleanOption, required } from "comline";
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { pathToFileURL } from "node:url";
|
|
11
|
+
//#region src/npm/cli.ts
|
|
12
|
+
const common = {
|
|
13
|
+
config: {
|
|
14
|
+
required: false,
|
|
15
|
+
description: `Configuration file (defaults to breakage.config.ts, then .json).`,
|
|
16
|
+
example: `--config ./breakage.config.ts`,
|
|
17
|
+
completion: {
|
|
18
|
+
fileSystem: `files`,
|
|
19
|
+
repeatable: false
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
json: {
|
|
23
|
+
required: false,
|
|
24
|
+
description: `Emit the structured result.`,
|
|
25
|
+
example: `--json`,
|
|
26
|
+
parse: parseBooleanOption
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const npmCheckManual = options(`Check npm peer compatibility and changes in declared support.`, type({
|
|
30
|
+
"config?": `string`,
|
|
31
|
+
"json?": `boolean`,
|
|
32
|
+
"coverageOnly?": `boolean`
|
|
33
|
+
}), {
|
|
34
|
+
...common,
|
|
35
|
+
coverageOnly: {
|
|
36
|
+
aliases: [`coverage-only`],
|
|
37
|
+
required: false,
|
|
38
|
+
description: `Audit coverage and support changes without executing assertions.`,
|
|
39
|
+
example: `--coverage-only`,
|
|
40
|
+
parse: parseBooleanOption
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
const npmTestManual = options(`Run current contracts in matching complete peer environments.`, type({
|
|
44
|
+
"config?": `string`,
|
|
45
|
+
"json?": `boolean`,
|
|
46
|
+
"representative?": `string`
|
|
47
|
+
}), {
|
|
48
|
+
...common,
|
|
49
|
+
representative: {
|
|
50
|
+
required: false,
|
|
51
|
+
description: `Select an exact configured representative path relative to the package.`,
|
|
52
|
+
example: `--representative peer-environments/react-19`,
|
|
53
|
+
completion: {
|
|
54
|
+
fileSystem: `directories`,
|
|
55
|
+
repeatable: false
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
function defaultConfig(directory) {
|
|
60
|
+
return path.join(directory, existsSync(path.join(directory, `breakage.config.ts`)) ? `breakage.config.ts` : `breakage.config.json`);
|
|
61
|
+
}
|
|
62
|
+
async function runNpmCli(action, opts, peerSelection) {
|
|
63
|
+
try {
|
|
64
|
+
const filename = path.resolve(opts.config ?? defaultConfig(process.cwd()));
|
|
65
|
+
const loaded = filename.endsWith(`.json`) ? JSON.parse(await readFile(filename, `utf8`)) : (await import(pathToFileURL(filename).href)).default;
|
|
66
|
+
const config = record(loaded) ? loaded.npm : void 0;
|
|
67
|
+
validateConfig(config);
|
|
68
|
+
let selection;
|
|
69
|
+
if (action === `test`) {
|
|
70
|
+
if (peerSelection && opts.representative) throw new Error(`Choose a peer range or a representative, not both.`);
|
|
71
|
+
selection = peerSelection ?? (opts.representative ? { representative: opts.representative } : void 0);
|
|
72
|
+
if (!selection) throw new Error(`Use npm test <peer> <range> or npm test --representative <path>.`);
|
|
73
|
+
}
|
|
74
|
+
const options = {
|
|
75
|
+
baseDirectory: path.dirname(filename),
|
|
76
|
+
coverageOnly: opts.coverageOnly ?? false
|
|
77
|
+
};
|
|
78
|
+
const report = selection ? await npmTest(config, selection, options) : await npmCheck(config, options);
|
|
79
|
+
process.stdout.write(opts.json ? `${JSON.stringify(report, null, 2)}\n` : formatNpmReport(report));
|
|
80
|
+
return report.exitCode;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
const message = errorMessage(error);
|
|
83
|
+
process.stdout.write(opts.json ? `${JSON.stringify({
|
|
84
|
+
exitCode: 2,
|
|
85
|
+
errors: [message]
|
|
86
|
+
})}\n` : `npm setup error: ${message}\n`);
|
|
87
|
+
return 2;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
8
91
|
//#region src/breakage.x.ts
|
|
9
92
|
const BREAKAGE_MANUAL = options(`Check for breaking changes in a package.`, type({
|
|
10
93
|
"tagPattern?": `string`,
|
|
@@ -126,6 +209,11 @@ const parse = cli({
|
|
|
126
209
|
routes: optional({
|
|
127
210
|
help: null,
|
|
128
211
|
schema: null,
|
|
212
|
+
npm: optional({
|
|
213
|
+
help: null,
|
|
214
|
+
check: null,
|
|
215
|
+
test: optional({ $peer: required({ $range: null }) })
|
|
216
|
+
}),
|
|
129
217
|
prelude: optional({ $configPath: null }),
|
|
130
218
|
$configPath: null
|
|
131
219
|
}),
|
|
@@ -134,6 +222,11 @@ const parse = cli({
|
|
|
134
222
|
$configPath: BREAKAGE_MANUAL,
|
|
135
223
|
help: noOptions(`Show usage.`),
|
|
136
224
|
schema: SCHEMA_MANUAL,
|
|
225
|
+
npm: noOptions(`Show npm compatibility commands.`),
|
|
226
|
+
"npm/help": noOptions(`Show npm compatibility commands.`),
|
|
227
|
+
"npm/check": npmCheckManual,
|
|
228
|
+
"npm/test": npmTestManual,
|
|
229
|
+
"npm/test/$peer/$range": npmTestManual,
|
|
137
230
|
prelude: PRELUDE_MANUAL,
|
|
138
231
|
"prelude/$configPath": PRELUDE_MANUAL
|
|
139
232
|
},
|
|
@@ -142,8 +235,8 @@ const parse = cli({
|
|
|
142
235
|
"prelude/$configPath": { fileSystem: `files` }
|
|
143
236
|
},
|
|
144
237
|
discoverConfigPath: (args) => {
|
|
145
|
-
if (args[0] === `help` || args[0] === `schema`) return;
|
|
146
|
-
return (args[0] === `prelude` ? args[1] : args[0]) ??
|
|
238
|
+
if (args[0] === `help` || args[0] === `schema` || args[0] === `npm`) return;
|
|
239
|
+
return (args[0] === `prelude` ? args[1] : args[0]) ?? defaultConfig(process.cwd());
|
|
147
240
|
}
|
|
148
241
|
}, {
|
|
149
242
|
info: (message, ...data) => logger.info(`breakage`, message, data),
|
|
@@ -155,9 +248,20 @@ else {
|
|
|
155
248
|
const { inputs, warnings, writeJsonSchema } = parse(process.argv);
|
|
156
249
|
logWarnings(warnings);
|
|
157
250
|
switch (inputs.case) {
|
|
251
|
+
case `npm`:
|
|
252
|
+
case `npm/help`:
|
|
158
253
|
case `help`:
|
|
159
254
|
console.log(help(parse.definition));
|
|
160
255
|
break;
|
|
256
|
+
case `npm/check`:
|
|
257
|
+
process.exitCode = await runNpmCli(`check`, inputs.opts);
|
|
258
|
+
break;
|
|
259
|
+
case `npm/test`:
|
|
260
|
+
process.exitCode = await runNpmCli(`test`, inputs.opts);
|
|
261
|
+
break;
|
|
262
|
+
case `npm/test/$peer/$range`:
|
|
263
|
+
process.exitCode = await runNpmCli(`test`, inputs.opts, inputs.params);
|
|
264
|
+
break;
|
|
161
265
|
case `schema`:
|
|
162
266
|
{
|
|
163
267
|
const { outdir } = inputs.opts;
|