#!/usr/bin/env node /** * @license * Copyright 2026 Qwen Team * SPDX-License-Identifier: Apache-2.0 */ /** * Local preflight for a `/verify-pr` maintainer round. * * The CI lane supplies three things a workstation does not: the PR metadata * snapshot (`$QWEN_VERIFY_CONTEXT`), a clone holding both the base and the head * OID, and the artifact directory the publication step globs. Resolving them by * hand is the part of the local path that fails silently — a snapshot from the * wrong repository, `HEAD^1` mistaken for the base on a plain PR-head checkout, * or a directory named without the `-verify-` infix all produce a round whose * report is about another PR or is discarded outright. * * This script resolves those coordinates and checks the tree the round will * reuse; it does not checkout a worktree, build, or execute PR code. The tree * check exists because the round runs the head side of its A/B in the current * tree: prepare refuses a HEAD other than the PR head or any uncommitted * change, and never stashes for the maintainer. It also cannot gate on * isolation: resolving the coordinates needs `gh`, and `gh` and the boundary * are mutually exclusive, so this path always runs on the host. The gate is * the separate `--require-isolation` mode, meant to run inside the boundary * before the round executes anything. * * Usage: * node scripts/verify-pr-prepare.mjs --repo / * node scripts/verify-pr-prepare.mjs --require-isolation * * Options: * --repo / required for the coordinate path: never inferred * from `origin`, because a fork's `origin` resolves the * same PR number to an unrelated PR * --require-isolation check the process this runs in and exit 4 when no * boundary is detected; run it inside the boundary * * Exit codes: * 0 coordinates resolved, or the boundary check passed * 2 usage error * 3 metadata, OID, tree-state, or filesystem failure * 4 --require-isolation found no boundary — do not run PR code here */ import { spawnSync } from 'node:child_process'; import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from 'node:fs'; import { homedir } from 'node:os'; import { join } from 'node:path'; import { isEntryPoint } from './lib/entry-point.js'; const OID = /^[0-9a-f]{40}$/; const REPO = /^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/; const FIELDS = [ 'number', 'title', 'body', 'author', 'baseRefName', 'baseRefOid', 'headRefOid', 'commits', ].join(','); const HELP = `Usage: node scripts/verify-pr-prepare.mjs --repo / node scripts/verify-pr-prepare.mjs --require-isolation Resolves the coordinates a local /verify-pr round needs and writes the metadata snapshot the round reads as $QWEN_VERIFY_CONTEXT: - fetches the PR snapshot with gh, from the repository you name - verifies the base and head OIDs exist in this clone - refuses a tree that is not a clean checkout of the PR head, so the round can reuse the current tree as the head side of the A/B; the gitignored install/build still needs a freshness check before it is reused - creates tmp/pr-verify-/ with an evidence/ subdirectory and a context.json holding repo, pr, baseRefOid and headRefOid - snapshots the PR's review threads and standing change requests beside the metadata, as the CI lane does; best-effort, so a failed fetch leaves no file and the round lists that review state as not covered - reports the isolation signals this process can observe The coordinate path runs on the host by construction: it needs gh, and gh and the boundary are mutually exclusive. Run --require-isolation inside the boundary, as the round's first command; exit 4 means this process is not isolated and must not execute PR code. A container marker alone does not pass: the CLI's own Docker/Podman launcher mounts ~/.config/gcloud and the ADC file and copies model API keys, so the check also requires the credential-free attestation and refuses when a known credential signal is visible. The built-in macOS sandbox (SANDBOX=sandbox-exec) never counts. `; /** Returns `{owner, name}` for a GitHub repository slug, or null. */ export function parseRepo(value) { const match = REPO.exec(String(value ?? '').trim()); if (!match) return null; return { owner: match[1], name: match[2] }; } /** * Returns the artifact directory name the publication step globs. The * `-verify-` infix is part of that contract, not decoration. */ export function artifactDirName(pr, now = new Date()) { const pad = (value) => String(value).padStart(2, '0'); const stamp = [ now.getFullYear(), pad(now.getMonth() + 1), pad(now.getDate()), ].join(''); const clock = [ pad(now.getHours()), pad(now.getMinutes()), pad(now.getSeconds()), ].join(''); return `pr${pr}-verify-${stamp}-${clock}`; } /** * The built-in macOS sandbox announces itself with this value while its * default `permissive-open` profile still lets the process read host files, so * it is not the credential-free boundary the round needs. */ export const SEATBELT = 'sandbox-exec'; /** * Set this only after confirming the boundary mounts no host credentials. A * marker says a container exists; it cannot say the container is clean, and * the CLI's own Docker/Podman launcher mounts `~/.config/gcloud`, the ADC file * and every model API key it can see, so the two questions are separate. */ export const CREDENTIAL_FREE_ATTESTATION = 'QWEN_VERIFY_CREDENTIAL_FREE'; const CREDENTIAL_ENV = [ 'GOOGLE_APPLICATION_CREDENTIALS', 'GEMINI_API_KEY', 'GOOGLE_API_KEY', 'OPENAI_API_KEY', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_SESSION_TOKEN', 'AZURE_CLIENT_SECRET', 'SSH_AUTH_SOCK', 'GH_TOKEN', 'GITHUB_TOKEN', 'KUBECONFIG', // An arbitrary mount list can carry anything, so it cannot be attested to. 'SANDBOX_MOUNTS', ]; const CREDENTIAL_PATHS = [ ['.config/gcloud', '~/.config/gcloud'], ['.aws', '~/.aws'], ['.azure', '~/.azure'], ['.ssh', '~/.ssh'], ['.kube/config', '~/.kube/config'], ['.git-credentials', '~/.git-credentials'], ['.netrc', '~/.netrc'], ['.docker/config.json', '~/.docker/config.json'], // The persistent form of GH_TOKEN/GITHUB_TOKEN and a registry token. ['.config/gh', '~/.config/gh'], ['.npmrc', '~/.npmrc'], ]; /** * Known credential signals. An empty list is not proof of a clean boundary — * it is what the process can see — which is why the gate also needs the * attestation below rather than treating the absence as a pass. */ export function detectCredentialSignals( env = process.env, exists = existsSync, home = homedir(), ) { const signals = []; for (const name of CREDENTIAL_ENV) { if (env[name]) signals.push(name); } for (const [relative, label] of CREDENTIAL_PATHS) { if (exists(join(home, relative))) signals.push(label); } return signals; } /** * Reports the isolation signals this process can observe. Only a * container-backed signal counts: a VM carries none of them, which is why the * caller decides what a missing signal means, and why the seatbelt flag is * reported separately rather than folded into `isolated`. */ export function detectIsolation(env = process.env, exists = existsSync) { const signals = []; if (env.container) signals.push(`container=${env.container}`); if (exists('/.dockerenv')) signals.push('/.dockerenv'); if (exists('/run/.containerenv')) signals.push('/run/.containerenv'); // A boolean-looking value reads as "sandbox disabled"; the CLI's transport // writes a container name or `sandbox-exec`, neither of which is a marker. const sandbox = (env.SANDBOX ?? '').trim(); if (sandbox && !['false', 'true', '0', '1'].includes(sandbox)) { if (sandbox !== SEATBELT) signals.push(`SANDBOX=${sandbox}`); } return { isolated: signals.length > 0, signals, seatbelt: sandbox === SEATBELT, }; } /** Returns the normalized snapshot fields, or null when the shape is wrong. */ export function validateContext(json) { if (!json || typeof json !== 'object') return null; const pr = json.number; const base = json.baseRefOid; const head = json.headRefOid; if (!Number.isInteger(pr) || pr <= 0) return null; if (typeof base !== 'string' || !OID.test(base)) return null; if (typeof head !== 'string' || !OID.test(head)) return null; return { pr, base, head, baseRefName: typeof json.baseRefName === 'string' ? json.baseRefName : '', title: typeof json.title === 'string' ? json.title : '', }; } // The CI lane's verify job runs this query and reshapes it with jq into the // same review-threads.json; a test runs both over the same pages. export const REVIEW_STATE_QUERY = 'query($owner: String!, $name: String!, $number: Int!, $endCursor: String) { repository(owner: $owner, name: $name) { pullRequest(number: $number) { latestOpinionatedReviews(first: 100) { nodes { state submittedAt url body author { login } authorAssociation commit { oid } } } reviewThreads(first: 50, after: $endCursor) { pageInfo { hasNextPage endCursor } nodes { isResolved isOutdated path line originalLine comments(first: 50) { totalCount nodes { createdAt url body author { login } authorAssociation originalCommit { oid } pullRequestReview { url } } } } } } } }'; /** * Reshapes `gh api graphql --paginate --slurp` pages of REVIEW_STATE_QUERY into * the review state a round reads: every review thread, resolved ones included * (resolving is the author's claim, not a measurement), and each reviewer's * standing CHANGES_REQUESTED review. Null when the pages are not that query's * answer. */ export function reviewState(pages) { if (!Array.isArray(pages) || pages.length === 0) return null; const isObject = (value) => value !== null && typeof value === 'object'; const pulls = pages.map((page) => page?.data?.repository?.pullRequest); if ( pulls.some( (pull) => !Array.isArray(pull?.reviewThreads?.nodes) || !Array.isArray(pull?.latestOpinionatedReviews?.nodes) || !pull.latestOpinionatedReviews.nodes.every(isObject) || !pull.reviewThreads.nodes.every( (thread) => isObject(thread) && Array.isArray(thread.comments?.nodes) && thread.comments.nodes.every(isObject), ), ) ) { return null; } const who = (node) => ({ author: node.author?.login ?? null, association: node.authorAssociation ?? null, }); return { threads: pulls .flatMap((pull) => pull.reviewThreads.nodes) .map((thread) => ({ resolved: thread.isResolved ?? null, outdated: thread.isOutdated ?? null, path: thread.path ?? null, line: thread.line ?? null, originalLine: thread.originalLine ?? null, commentCount: thread.comments.totalCount ?? null, comments: thread.comments.nodes.map((comment) => ({ ...who(comment), createdAt: comment.createdAt ?? null, url: comment.url ?? null, review: comment.pullRequestReview?.url ?? null, commit: comment.originalCommit?.oid ?? null, body: comment.body ?? null, })), })), changeRequests: pulls[0].latestOpinionatedReviews.nodes .filter((review) => review.state === 'CHANGES_REQUESTED') .map((review) => ({ ...who(review), submittedAt: review.submittedAt ?? null, commit: review.commit?.oid ?? null, url: review.url ?? null, body: review.body ?? null, })), }; } /** Drops C0/C1 control characters, which a terminal would interpret. */ export function printable(text) { return [...String(text ?? '')] .filter((char) => { const code = char.codePointAt(0); return code > 0x1f && (code < 0x7f || code > 0x9f); }) .join(''); } /** Parses argv into options, or `{error}` for a usage failure. */ export function parseArgs(argv) { const options = { pr: null, repo: null, requireIsolation: false, help: false, }; for (let index = 0; index < argv.length; index += 1) { const arg = argv[index]; if (arg === '--help' || arg === '-h') { options.help = true; } else if (arg === '--require-isolation') { options.requireIsolation = true; } else if (arg === '--repo') { options.repo = argv[(index += 1)] ?? null; if (!options.repo) return { error: '--repo needs /' }; } else if (arg.startsWith('--repo=')) { options.repo = arg.slice('--repo='.length); } else if (/^\d+$/.test(arg) && options.pr === null) { options.pr = Number(arg); } else { return { error: `unexpected argument: ${arg}` }; } } if (options.help || options.requireIsolation) return options; if (!Number.isInteger(options.pr) || options.pr <= 0) { return { error: 'a PR number is required' }; } if (!parseRepo(options.repo)) { return { error: '--repo / is required' }; } return options; } function run(command, args, options = {}) { return spawnSync(command, args, { encoding: 'utf8', ...options }); } /** `{state}` on success, `{error}` naming why the review state is unknown. */ function fetchReviewState(owner, name, pr) { const view = run( 'gh', [ 'api', 'graphql', '--paginate', '--slurp', '-f', `owner=${owner}`, '-f', `name=${name}`, '-F', `number=${pr}`, '-f', `query=${REVIEW_STATE_QUERY}`, ], // Every thread's comment bodies, resolved ones included, arrive before // the filter: one busy PR's pages measured 790 KB, near spawnSync's 1 MB // default. { maxBuffer: 256 * 1024 * 1024 }, ); if (view.status !== 0) { const detail = (view.stderr || '').trim().split('\n')[0] || view.error?.message || `exit ${view.status}`; return { error: `gh api graphql failed: ${detail}` }; } let pages; try { pages = JSON.parse(view.stdout); } catch { return { error: 'gh api graphql returned output that is not JSON' }; } const state = reviewState(pages); return state ? { state } : { error: 'gh api graphql returned pages without review threads' }; } // The tree under inspection is PR-controlled and can persist hostile git // config in .git/config: fsmonitor, hooks and clean/smudge/process filters all // execute on an ordinary `git status`. On the host these run as the maintainer, // outside the boundary, so every git command disables the fixed vectors and // empties every locally defined filter before reading the tree. The fixed // vectors come LAST in every argument list: git applies the last `-c` for a // key, so an enumerated entry must never be able to outrank them. export const GIT_HARDENING = [ '-c', 'core.fsmonitor=false', '-c', 'core.hooksPath=/dev/null', '-c', 'credential.helper=', '-c', 'core.excludesFile=/dev/null', ]; const FILTER_NAME = /^filter\..+\.(clean|smudge|process)$/; /** * A filter name git allows (e.g. `filter.a=b.clean`) but `-c key=value` * cannot represent: git splits the argument at the FIRST `=`, so emitting an * override would set a different key and leave the real filter armed. The * gate refuses such names instead, with their own remedy. */ export class UnsafeFilterNameError extends Error { constructor(name) { super( `filter name ${name} contains '=' and cannot be safely disabled with -c — remove the filter from the tree's git config, or re-clone, then re-run prepare`, ); this.name = 'UnsafeFilterNameError'; } } /** * Empty `-c` overrides for every locally defined filter command. The filter * name is attacker-chosen, so the override set has to be enumerated from the * tree's own config instead of hardcoded. Three properties are load-bearing: * `--includes` follows `include.path` the way the config parsing `git status` * uses does; `--null --name-only` frames KEY NAMES only, because a filter * VALUE may contain newlines that would forge extra entries if the rendered * `key value` output were parsed; and each name is re-validated before it * becomes a `-c` argument. When `extensions.worktreeConfig` is set, * `git status` also reads `.git/config.worktree`, so that scope is enumerated * too. Names containing `=` throw UnsafeFilterNameError — no override can * represent them. */ export function localFilterOverrides(root) { const prefix = root ? ['-C', root] : []; const scopes = ['--local']; const worktreeConfig = run('git', [ ...prefix, 'config', '--local', '--includes', '--bool', 'extensions.worktreeConfig', ]); if (worktreeConfig.status === 0 && worktreeConfig.stdout.trim() === 'true') { scopes.push('--worktree'); } const overrides = []; for (const scope of scopes) { const result = run('git', [ ...prefix, 'config', scope, '--includes', '--null', '--name-only', '--get-regexp', '^filter\\..*\\.(clean|smudge|process)$', ]); if (result.status === 1) continue; if (result.status !== 0) { throw new Error('could not enumerate local git filters'); } for (const name of result.stdout.split('\0')) { if (!name || !FILTER_NAME.test(name)) continue; if (name.includes('=')) throw new UnsafeFilterNameError(name); overrides.push('-c', `${name}=`); } } return overrides; } export function gitStatusArgs(root) { return [ ...localFilterOverrides(root), ...GIT_HARDENING, '-C', root, 'status', '--porcelain', '--untracked-files=normal', ]; } function runGit(args) { return run('git', [...localFilterOverrides(), ...GIT_HARDENING, ...args]); } /** * True when `.git/info/exclude` carries active patterns. A fresh clone has * only git's commented default there; patterns hide untracked files from the * clean-tree check, and unlike core.excludesFile no `-c` can neutralize this * file, so the gate refuses it instead of reading a steered status. */ export function hasHostileInfoExclude(root) { const path = join(root, '.git', 'info', 'exclude'); if (!existsSync(path)) return false; return readFileSync(path, 'utf8') .split('\n') .some((line) => { const trimmed = line.trim(); return trimmed !== '' && !trimmed.startsWith('#'); }); } function report(lines) { process.stdout.write(`${lines.join('\n')}\n`); } function fail(code, message) { process.stderr.write(`verify-pr prepare: ${message}\n`); return code; } function main(argv) { const options = parseArgs(argv); if (options.error) { process.stderr.write(`verify-pr prepare: ${options.error}\n\n${HELP}`); return 2; } if (options.help) { process.stdout.write(HELP); return 0; } if (options.requireIsolation) return requireBoundary(); const { owner, name } = parseRepo(options.repo); const slug = `${owner}/${name}`; let toplevel; try { toplevel = runGit(['rev-parse', '--show-toplevel']); } catch (error) { // A hostile filter name is a refusal with its own remedy, not a missing // worktree; it must surface before any guarded status could run it. if (error instanceof UnsafeFilterNameError) { return fail(3, error.message); } return fail(3, 'not inside a git worktree — run this from the clone'); } if (toplevel.status !== 0) { return fail(3, 'not inside a git worktree — run this from the clone'); } const root = toplevel.stdout.trim(); const view = run('gh', [ 'pr', 'view', String(options.pr), '--repo', slug, '--json', FIELDS, ]); if (view.status !== 0) { const detail = (view.stderr || '').trim() || view.error?.message || `exit ${view.status}`; return fail(3, `gh pr view failed: ${detail}`); } let snapshot; try { snapshot = JSON.parse(view.stdout); } catch { return fail(3, 'gh pr view returned output that is not JSON'); } const context = validateContext(snapshot); if (!context) { return fail( 3, 'gh returned a snapshot without a numeric PR and two 40-character OIDs', ); } const probes = [ ['base', context.base, context.baseRefName || context.base], ['head', context.head, `pull/${context.pr}/head`], ]; for (const [label, oid, ref] of probes) { if ( runGit(['-C', root, 'cat-file', '-e', `${oid}^{commit}`]).status !== 0 ) { return fail( 3, `${label} ${oid} is not in this clone — run: git fetch https://github.com/${slug}.git ${ref}`, ); } } // The round runs the head side of its A/B in this tree, so a HEAD other // than the PR head or an uncommitted change would measure code the report // does not name. Checked before the artifact directory exists, so a refusal // leaves nothing behind. const treeHead = runGit(['-C', root, 'rev-parse', 'HEAD']); if (treeHead.status !== 0) { return fail(3, 'could not read HEAD in this clone'); } if (treeHead.stdout.trim() !== context.head) { return fail( 3, `current tree is at ${treeHead.stdout.trim()}, not PR head ${context.head} — run: git checkout ${context.head}, then re-run prepare`, ); } // The ignore channel is steerable from the same PR-controlled .git: // core.excludesFile is neutralized by GIT_HARDENING, but .git/info/exclude // has no `-c` override, so active patterns there are refused outright // rather than read through. if (hasHostileInfoExclude(root)) { return fail( 3, '.git/info/exclude carries local exclude patterns, which can hide untracked files from the clean-tree check — re-clone (a fresh clone has only the commented default), or clear the file, then re-run prepare', ); } // Explicit mode: a maintainer's status.showUntrackedFiles=no would otherwise // hide the untracked files this check exists to refuse. const dirty = run('git', gitStatusArgs(root)); if (dirty.status !== 0) { const detail = (dirty.stderr || '').trim() || `exit ${dirty.status}`; return fail(3, `could not read the working tree status: ${detail}`); } if (dirty.stdout.trim() !== '') { // Name the entries and a remedy that actually clears them: a plain // `git stash` leaves untracked files behind, so the advice would loop. const entries = dirty.stdout.trim().split('\n'); const shown = entries.slice(0, 5).map(printable).join(', '); return fail( 3, `working tree has uncommitted changes (${shown}${entries.length > 5 ? ', …' : ''}) — commit them, or run \`git stash push --include-untracked\` (a plain \`git stash\` leaves untracked files behind), or remove them, then re-run prepare; this script never stashes for you`, ); } // git status trusts the index: skip-worktree / assume-unchanged entries // (a sparse checkout sets them en masse) hide tracked divergence from it, // so refuse anything that is not a plain cached 'H' entry. const flagged = runGit(['-C', root, 'ls-files', '-v']); if (flagged.status !== 0) { const detail = (flagged.stderr || '').trim() || `exit ${flagged.status}`; return fail(3, `could not read the index flags: ${detail}`); } const opaque = flagged.stdout .split('\n') .filter((line) => line && !line.startsWith('H ')); if (opaque.length > 0) { const shown = opaque.slice(0, 5).map(printable).join(', '); return fail( 3, `tracked entries hide their worktree state (${shown}${opaque.length > 5 ? ', …' : ''}) — re-clone without a sparse checkout, or clear the index flags, then re-run prepare`, ); } const contextDir = join(root, 'tmp', 'verify-context'); const contextPath = join(contextDir, `pr${context.pr}.json`); const artifacts = join(root, 'tmp', artifactDirName(context.pr)); try { mkdirSync(contextDir, { recursive: true }); // Recursive, so a retry within the same second lands in the directory this // script just made instead of failing on it. mkdirSync(artifacts, { recursive: true }); mkdirSync(join(artifacts, 'evidence'), { recursive: true }); } catch (error) { return fail(3, `could not create the artifact directory: ${error.message}`); } writeFileSync(contextPath, `${JSON.stringify(snapshot, null, 2)}\n`); // Best-effort, like the lane: the round reads a missing file as "review // state unknown", so an earlier prepare's copy must not outlive a failed // fetch. const reviewPath = join(contextDir, `pr${context.pr}-review-threads.json`); rmSync(reviewPath, { force: true }); const review = fetchReviewState(owner, name, context.pr); if (review.state) { writeFileSync(reviewPath, `${JSON.stringify(review.state, null, 2)}\n`); } writeFileSync( join(artifacts, 'context.json'), `${JSON.stringify({ repo: slug, pr: context.pr, baseRefOid: context.base, headRefOid: context.head, })}\n`, ); const isolation = detectIsolation(); // The title comes from an untrusted fork, and a control character would reach // the maintainer's terminal from a tool whose job is to protect it. const title = printable(context.title).replace(/\s+/g, ' ').trim(); report([ 'verify-pr prepare', ` repo ${slug}`, ` pr #${context.pr}${title ? ` ${title}` : ''}`, ` base ${context.base}`, ` head ${context.head}`, ' tree at PR head, clean — reuse this tree; verify or refresh its install/build first', ` context ${contextPath}`, review.state ? ` review ${reviewPath} (${review.state.threads.filter((thread) => !thread.resolved).length} of ${review.state.threads.length} threads unresolved, ${review.state.changeRequests.length} change requests)` : ` review not written — ${printable(review.error)}; the round lists review findings as not covered`, ` artifacts ${artifacts}`, ` isolation ${isolation.isolated ? isolation.signals.join(', ') : 'none detected'}`, ]); if (isolation.seatbelt) { report([ ' seatbelt SANDBOX=sandbox-exec (default profile allows host reads —', ' not a boundary)', ]); } report([ '', `Next: build the round in ${artifacts}. This preflight ran on the host,`, 'because resolving the coordinates needs `gh` and `gh` is mutually', 'exclusive with the boundary. Before executing PR code, run inside it:', '', ' node scripts/verify-pr-prepare.mjs --require-isolation', ]); return 0; } /** * The in-boundary check, and the only place its answer means anything: the * coordinate path necessarily runs on the host, so a gate there would fire * every round and teach the maintainer to ignore it. */ function requireBoundary() { const isolation = detectIsolation(); const credentials = detectCredentialSignals(); const attested = process.env[CREDENTIAL_FREE_ATTESTATION] === '1'; if (!isolation.isolated) { const detail = isolation.seatbelt ? 'SANDBOX=sandbox-exec is the built-in macOS sandbox, whose default profile still reads host files' : 'no container marker was found'; process.stderr.write( `verify-pr boundary: ${detail} — do not execute PR code in this process\n`, ); return 4; } const refusals = []; if (!attested) { refusals.push( `${CREDENTIAL_FREE_ATTESTATION}=1 is not set: a marker says a container exists, not that it carries no host credentials`, ); } if (credentials.length > 0) { refusals.push( `credential signals contradict a credential-free boundary: ${credentials.join(', ')}`, ); } if (refusals.length > 0) { process.stderr.write( `verify-pr boundary: ${isolation.signals.join(', ')} but ${refusals.join('; ')} — do not execute PR code here\n`, ); return 4; } report([ `verify-pr boundary: ${isolation.signals.join(', ')}; credential-free per attestation, no known credential signal`, ]); return 0; } if (isEntryPoint(import.meta.url, process.argv[1])) { process.exitCode = main(process.argv.slice(2)); }