The harness packages declare the vendored framework as a peer, so installing only the dsh tarballs left npm resolving @deepseek-ai/cordis from a private registry the credential-free pack job cannot reach. The verification now takes several pack directories and installs every tarball in them, and the dsh workflow packs the vendored family for that purpose while still publishing only its own set. The verification also reads what each tarball declares instead of what the checkout says, which is what let the process and tarball helpers become one home each - the three copies of a spawn wrapper were a duplication finding.
66 lines
2.6 KiB
TypeScript
66 lines
2.6 KiB
TypeScript
/**
|
|
* Process helpers shared by the release scripts: the release steps drive `git`,
|
|
* `pnpm`, `npm`, and `tar`, and each needs one of three failure behaviours.
|
|
*/
|
|
|
|
import { spawnSync } from 'node:child_process'
|
|
|
|
/** Where and with what environment a release step runs a command. */
|
|
export interface RunOptions {
|
|
/** Working directory; defaults to the current one. */
|
|
readonly cwd?: string
|
|
/** Child environment; defaults to this process's. */
|
|
readonly env?: NodeJS.ProcessEnv
|
|
}
|
|
|
|
/** What a command produced, for a caller that decides what a failure means. */
|
|
export interface CommandResult {
|
|
/** Exit status, or null when a signal ended the process. */
|
|
readonly status: number | null
|
|
/** Captured standard output. */
|
|
readonly stdout: string
|
|
/** Captured standard error. */
|
|
readonly stderr: string
|
|
}
|
|
|
|
/**
|
|
* Run a command and capture its output without judging the exit status.
|
|
* @param command - executable name.
|
|
* @param args - command arguments.
|
|
* @param options - working directory and environment.
|
|
* @returns The exit status and captured streams.
|
|
*/
|
|
export function attempt(command: string, args: readonly string[], options: RunOptions = {}): CommandResult {
|
|
const result = spawnSync(command, [...args], { cwd: options.cwd, env: options.env, encoding: 'utf8' })
|
|
if (result.error !== undefined) throw result.error
|
|
return { status: result.status, stdout: result.stdout, stderr: result.stderr }
|
|
}
|
|
|
|
/**
|
|
* Run a command, capture its standard output, and fail on a non-zero exit.
|
|
* @param command - executable name.
|
|
* @param args - command arguments.
|
|
* @param options - working directory and environment.
|
|
* @returns The trimmed standard output.
|
|
*/
|
|
export function capture(command: string, args: readonly string[], options: RunOptions = {}): string {
|
|
const result = attempt(command, args, options)
|
|
if (result.status !== 0) {
|
|
throw new Error(`${command} ${args.join(' ')} exited with ${String(result.status)}:\n${result.stdout}\n${result.stderr}`)
|
|
}
|
|
return result.stdout.trim()
|
|
}
|
|
|
|
/**
|
|
* Run a command with inherited streams, so its progress reaches the log, and
|
|
* fail on a non-zero exit.
|
|
* @param command - executable name.
|
|
* @param args - command arguments.
|
|
* @param options - working directory and environment.
|
|
*/
|
|
export function run(command: string, args: readonly string[], options: RunOptions = {}): void {
|
|
const result = spawnSync(command, [...args], { cwd: options.cwd, env: options.env, stdio: 'inherit' })
|
|
if (result.error !== undefined) throw result.error
|
|
if (result.status !== 0) throw new Error(`${command} ${args.join(' ')} exited with ${String(result.status)}`)
|
|
}
|