@snappedly-tools/shipyard 0.4.4 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sandboxes/copyIntoContainer.ts","../src/DockerLifecycle.ts","../src/RepositoryRunnerLifecycle.ts","../src/sandboxes/docker.ts"],"names":["execFile","promisify","resolve","Effect"],"mappings":"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","file":"chunk-WAXEMZUV.js","sourcesContent":["import { execFile } from \"node:child_process\";\nimport { posix } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst exec = promisify(execFile);\n\n/** Container cp creates root-owned files; session files may have mode 0600. */\nexport const copyIntoContainer = async (\n engine: \"docker\",\n container: string,\n owner: string,\n hostPath: string,\n sandboxPath: string,\n): Promise<void> => {\n try {\n await exec(engine, [\n \"exec\",\n container,\n \"mkdir\",\n \"-p\",\n \"--\",\n posix.dirname(sandboxPath),\n ]);\n await exec(engine, [\"cp\", hostPath, `${container}:${sandboxPath}`]);\n await exec(engine, [\n \"exec\",\n \"--user\",\n \"0:0\",\n container,\n \"chown\",\n \"-hR\",\n \"--\",\n owner,\n sandboxPath,\n ]);\n } catch (error) {\n throw new Error(\n `${engine} cp (in) failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n};\n","import { Effect } from \"effect\";\nimport { execFile } from \"node:child_process\";\nimport { resolve } from \"node:path\";\nimport { DockerError } from \"./errors.js\";\nimport { formatVolumeMount, type SelinuxLabel } from \"./mountUtils.js\";\n\nconst dockerExec = (args: string[]): Effect.Effect<string, DockerError> =>\n Effect.async((resume) => {\n execFile(\n \"docker\",\n args,\n { maxBuffer: 10 * 1024 * 1024 },\n (error, stdout, stderr) => {\n if (error) {\n resume(\n Effect.fail(\n new DockerError({\n message: `docker ${args[0]} failed: ${stderr?.toString() || error.message}`,\n }),\n ),\n );\n } else {\n resume(Effect.succeed(stdout.toString()));\n }\n },\n );\n });\n\n/**\n * Build the shipyard Docker image.\n *\n * When `dockerfile` is provided, uses `docker build -f <dockerfile> <cwd>`\n * so COPY instructions resolve relative to the current working directory.\n * Otherwise, uses `docker build <dockerfileDir>` (the default .shipyard/ directory).\n */\nexport const buildImage = (\n imageName: string,\n dockerfileDir: string,\n options?: {\n readonly dockerfile?: string;\n readonly buildArgs?: Record<string, string>;\n },\n): Effect.Effect<void, DockerError> =>\n Effect.gen(function* () {\n const buildArgFlags = Object.entries(options?.buildArgs ?? {}).flatMap(\n ([k, v]) => [\"--build-arg\", `${k}=${v}`],\n );\n if (options?.dockerfile) {\n yield* dockerExec([\n \"build\",\n \"-t\",\n imageName,\n ...buildArgFlags,\n \"-f\",\n resolve(options.dockerfile),\n process.cwd(),\n ]);\n } else {\n yield* dockerExec([\n \"build\",\n \"-t\",\n imageName,\n ...buildArgFlags,\n resolve(dockerfileDir),\n ]);\n }\n });\n\nexport interface VolumeMount {\n readonly hostPath: string;\n readonly sandboxPath: string;\n readonly readonly?: boolean;\n}\n\nexport interface StartContainerOptions {\n readonly volumeMounts?: readonly VolumeMount[];\n readonly workdir?: string;\n /** Run the container as this uid:gid instead of the Dockerfile's USER. */\n readonly user?: string;\n /** Docker network(s) to attach the container to. Passed as `--network` flags. */\n readonly network?: string | readonly string[];\n /** Supplementary groups to add the container user to. Passed as `--group-add` flags. */\n readonly groups?: readonly (string | number)[];\n /** Host devices to expose to the container. Passed as `--device` flags. */\n readonly devices?: readonly string[];\n /** Limit CPU resources via `--cpus` (e.g. `1.5`). Fractional values allowed. */\n readonly cpus?: number;\n /** Docker labels used to scope repository-runner crash recovery. */\n readonly labels?: Readonly<Record<string, string>>;\n /**\n * SELinux volume label suffix applied to bind mounts (default `\"z\"`).\n *\n * - `\"z\"` — shared label. No-op on non-SELinux systems.\n * - `\"Z\"` — private label; only this container can access the mount.\n * - `false` — disable labeling entirely.\n */\n readonly selinuxLabel?: SelinuxLabel;\n}\n\n/**\n * Start a new container with environment variables injected.\n */\nexport const startContainer = (\n containerName: string,\n imageName: string,\n env: Record<string, string>,\n options?: StartContainerOptions,\n): Effect.Effect<void, DockerError> =>\n Effect.gen(function* () {\n // Check if container already exists\n const existing = yield* dockerExec([\n \"ps\",\n \"-a\",\n \"--filter\",\n `name=^${containerName}$`,\n \"--format\",\n \"{{.Names}}\",\n ]);\n\n if (existing.trim() === containerName) {\n yield* Effect.fail(\n new DockerError({\n message: `Container '${containerName}' already exists. Run cleanup first.`,\n }),\n );\n }\n\n const envFlags = Object.entries(env).flatMap(([k, v]) => [\n \"-e\",\n `${k}=${v}`,\n ]);\n\n const selinuxLabel = options?.selinuxLabel ?? \"z\";\n const volumeFlags = (options?.volumeMounts ?? []).flatMap((mount) => [\n \"-v\",\n formatVolumeMount(mount, selinuxLabel),\n ]);\n\n const workdirFlags = options?.workdir ? [\"-w\", options.workdir] : [];\n const userFlags = options?.user ? [\"--user\", options.user] : [];\n const networks = options?.network\n ? Array.isArray(options.network)\n ? options.network\n : [options.network]\n : [];\n const networkFlags = networks.flatMap((n) => [\"--network\", n]);\n const groupAddFlags = (options?.groups ?? []).flatMap((g) => [\n \"--group-add\",\n String(g),\n ]);\n const deviceFlags = (options?.devices ?? []).flatMap((d) => [\n \"--device\",\n d,\n ]);\n const cpusFlags =\n options?.cpus !== undefined ? [\"--cpus\", String(options.cpus)] : [];\n const labelFlags = Object.entries(options?.labels ?? {}).flatMap(\n ([key, value]) => [\"--label\", `${key}=${value}`],\n );\n\n yield* dockerExec([\n \"run\",\n \"-d\",\n \"--init\",\n \"--name\",\n containerName,\n ...labelFlags,\n ...envFlags,\n ...volumeFlags,\n ...workdirFlags,\n ...userFlags,\n ...networkFlags,\n ...groupAddFlags,\n ...deviceFlags,\n ...cpusFlags,\n imageName,\n ]);\n });\n\n/**\n * Stop and remove a container without removing the image.\n */\nexport const removeContainer = (\n containerName: string,\n): Effect.Effect<void, DockerError> =>\n Effect.gen(function* () {\n // Stop container (ignore errors if already stopped)\n yield* Effect.ignore(dockerExec([\"stop\", containerName]));\n // Remove container (ignore errors if not found)\n yield* Effect.ignore(dockerExec([\"rm\", containerName]));\n });\n\n/**\n * Remove a Docker image.\n */\nexport const removeImage = (\n imageName: string,\n): Effect.Effect<void, DockerError> =>\n Effect.gen(function* () {\n yield* dockerExec([\"rmi\", imageName]);\n });\n","import { execFile } from \"node:child_process\";\nimport { constants } from \"node:fs\";\nimport { access, lstat, mkdir, readFile, realpath, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport {\n ACTIVATION_LABEL,\n CONFIG_DIR,\n RUNNER_DIR,\n RUNNER_SANDBOX_MASK_DIR,\n} from \"./runtimeNames.js\";\nimport {\n assertProtectedDirectoryIdentities,\n repositoryRunnerEnvironment,\n type ProtectedDirectoryIdentity,\n} from \"./runnerSecurity.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport const RUNNER_INSTALL_METADATA = \".shipyard-install.json\";\nexport const RUNNER_CONTROLLER_LOCK = \".shipyard-controller.lock\";\nexport const RUNNER_WORK_DIR = \"_work\";\nexport const REPOSITORY_RUNNER_OWNER_LABEL =\n \"com.snappedly.shipyard.repository-runner-owner\";\nexport const REPOSITORY_RUNNER_OWNER_ENV = \"SHIPYARD_RUNNER_OWNER\";\nconst REGISTRATION_FILES = [\n \".credentials\",\n \".credentials_rsaparams\",\n \".runner\",\n] as const;\n\ninterface CommandResult {\n readonly stdout: string;\n readonly stderr: string;\n}\n\ninterface CommandOptions {\n readonly cwd: string;\n readonly env: NodeJS.ProcessEnv;\n}\n\nexport interface RunnerInstallMetadata {\n readonly schemaVersion: 1;\n readonly repository: string;\n readonly repositoryUrl: string;\n readonly name: string;\n readonly label: string;\n readonly version: string;\n}\n\ninterface RunnerControllerLock {\n readonly schemaVersion: 1;\n readonly pid: number;\n readonly repository: string;\n readonly processStartedAt: string;\n}\n\nexport class RunnerLifecycleError extends Error {\n readonly name = \"RunnerLifecycleError\";\n}\n\n/** Internal seams for validating an existing runner installation. */\nexport interface RunnerInstallValidationAdapters {\n readonly environment: () => NodeJS.ProcessEnv;\n readonly exists: (path: string) => Promise<boolean>;\n readonly readText: (path: string) => Promise<string>;\n readonly makeDirectory: (path: string) => Promise<void>;\n readonly inspectDirectory?: (\n path: string,\n ) => Promise<ProtectedDirectoryIdentity>;\n readonly run: (\n command: string,\n args: readonly string[],\n options: CommandOptions,\n ) => Promise<CommandResult>;\n}\n\n/** Internal seams for runner registration, filesystem cleanup, and process control. */\nexport interface RunnerLifecycleAdapters extends RunnerInstallValidationAdapters {\n readonly remove: (path: string) => Promise<void>;\n readonly isProcessRunning: (pid: number) => boolean;\n readonly signalProcess: (pid: number, signal: NodeJS.Signals) => void;\n readonly pause: (milliseconds: number) => Promise<void>;\n readonly processIdentity: (pid: number) => Promise<string | undefined>;\n}\n\nconst defaultAdapters: RunnerLifecycleAdapters = {\n environment: () => process.env,\n exists: async (path) => {\n try {\n await access(path, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n },\n readText: (path) => readFile(path, \"utf8\"),\n makeDirectory: async (path) => {\n await mkdir(path, { recursive: true, mode: 0o700 });\n },\n inspectDirectory: async (path) => {\n const [stat, resolved] = await Promise.all([lstat(path), realpath(path)]);\n return {\n realPath: resolved,\n directory: stat.isDirectory(),\n symbolicLink: stat.isSymbolicLink(),\n };\n },\n remove: (path) => rm(path, { recursive: true, force: true }),\n run: async (command, args, options) => {\n const result = await execFileAsync(command, [...args], {\n cwd: options.cwd,\n env: options.env,\n maxBuffer: 10 * 1024 * 1024,\n });\n return { stdout: result.stdout, stderr: result.stderr };\n },\n processIdentity: async (pid) => {\n try {\n const result = await execFileAsync(\"ps\", [\n \"-p\",\n String(pid),\n \"-o\",\n \"lstart=\",\n ]);\n const identity = result.stdout.trim().replace(/\\s+/g, \" \");\n return identity.length > 0 ? identity : undefined;\n } catch {\n return undefined;\n }\n },\n isProcessRunning: (pid) => {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n },\n signalProcess: (pid, signal) => process.kill(pid, signal),\n pause: (milliseconds) =>\n new Promise((resolve) => setTimeout(resolve, milliseconds)),\n};\n\nconst lockOwnsProcess = async (\n lock: RunnerControllerLock | undefined,\n adapters: Pick<\n RunnerLifecycleAdapters,\n \"isProcessRunning\" | \"processIdentity\"\n >,\n): Promise<boolean> =>\n lock !== undefined &&\n Number.isInteger(lock.pid) &&\n typeof lock.processStartedAt === \"string\" &&\n lock.processStartedAt.length > 0 &&\n adapters.isProcessRunning(lock.pid) &&\n (await adapters.processIdentity(lock.pid)) === lock.processStartedAt;\n\nconst lifecycleFailure = (\n purpose: string,\n error: unknown,\n): RunnerLifecycleError =>\n error instanceof RunnerLifecycleError\n ? error\n : new RunnerLifecycleError(\n `${purpose} failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n\nconst runCommand = async (\n adapters: Pick<RunnerInstallValidationAdapters, \"run\">,\n purpose: string,\n command: string,\n args: readonly string[],\n options: CommandOptions,\n): Promise<CommandResult> => {\n try {\n return await adapters.run(command, args, options);\n } catch (error) {\n throw lifecycleFailure(purpose, error);\n }\n};\n\nconst readJson = async <T>(\n path: string,\n adapters: Pick<RunnerInstallValidationAdapters, \"exists\" | \"readText\">,\n): Promise<T | undefined> => {\n if (!(await adapters.exists(path))) return undefined;\n try {\n return JSON.parse(await adapters.readText(path)) as T;\n } catch (error) {\n throw lifecycleFailure(`Reading repository runner state at ${path}`, error);\n }\n};\n\nconst requireInstallMetadata = async (\n runnerDir: string,\n adapters: Pick<RunnerInstallValidationAdapters, \"exists\" | \"readText\">,\n): Promise<RunnerInstallMetadata> => {\n const metadata = await readJson<RunnerInstallMetadata>(\n join(runnerDir, RUNNER_INSTALL_METADATA),\n adapters,\n );\n if (\n metadata?.schemaVersion !== 1 ||\n typeof metadata.repository !== \"string\" ||\n typeof metadata.repositoryUrl !== \"string\" ||\n typeof metadata.name !== \"string\" ||\n metadata.label !== ACTIVATION_LABEL ||\n typeof metadata.version !== \"string\"\n ) {\n throw new RunnerLifecycleError(\n `The existing directory at ${runnerDir} is not a valid Shipyard repository runner installation. Refusing to replace it.`,\n );\n }\n return metadata;\n};\n\ninterface RemoteRunner {\n readonly name: string;\n readonly status: string;\n readonly labels: ReadonlySet<string>;\n}\n\nconst parseRemoteRunners = (stdout: string): readonly RemoteRunner[] =>\n stdout\n .split(/\\r?\\n/)\n .filter((line) => line.length > 0)\n .map((line) => {\n const [name = \"\", status = \"\", labels = \"\"] = line.split(\"\\t\");\n return {\n name,\n status,\n labels: new Set(labels.split(\",\").filter(Boolean)),\n };\n });\n\nconst listRemoteRunners = async (\n repository: string,\n repoDir: string,\n environment: NodeJS.ProcessEnv,\n adapters: RunnerInstallValidationAdapters,\n): Promise<readonly RemoteRunner[]> => {\n const response = await runCommand(\n adapters,\n \"Checking registered GitHub repository runners\",\n \"gh\",\n [\n \"api\",\n \"--paginate\",\n `repos/${repository}/actions/runners`,\n \"--jq\",\n '.runners[] | [.name, .status, ([.labels[].name] | join(\",\"))] | @tsv',\n ],\n { cwd: repoDir, env: environment },\n );\n return parseRemoteRunners(response.stdout);\n};\n\nexport const validateExistingRepositoryRunner = async (\n options: {\n readonly repoDir: string;\n readonly runnerDir: string;\n readonly maskDir: string;\n readonly repository: string;\n readonly runnerName: string;\n },\n adapters: RunnerInstallValidationAdapters = defaultAdapters,\n): Promise<RunnerInstallMetadata> => {\n if (!(await adapters.exists(options.maskDir))) {\n await adapters.makeDirectory(options.maskDir);\n }\n await assertProtectedDirectoryIdentities(\n options.runnerDir,\n options.maskDir,\n adapters.inspectDirectory,\n ).catch((error) => {\n throw lifecycleFailure(\"Validating protected runner directories\", error);\n });\n const metadata = await requireInstallMetadata(options.runnerDir, adapters);\n if (metadata.repository !== options.repository) {\n throw new RunnerLifecycleError(\n `The existing repository runner belongs to ${metadata.repository}, not ${options.repository}. Refusing to replace it.`,\n );\n }\n if (metadata.name !== options.runnerName) {\n throw new RunnerLifecycleError(\n `The existing installation belongs to runner ${metadata.name}, not ${options.runnerName}. A Mac rename does not rename a registered runner; remove and reinstall it explicitly.`,\n );\n }\n for (const required of [\".credentials\", \"run.sh\"] as const) {\n if (!(await adapters.exists(join(options.runnerDir, required)))) {\n throw new RunnerLifecycleError(\n `The existing repository runner is missing ${required}. Refusing to replace its registration; remove it explicitly first.`,\n );\n }\n }\n\n const remoteRunners = await listRemoteRunners(\n options.repository,\n options.repoDir,\n adapters.environment(),\n adapters,\n );\n const labelled = remoteRunners.filter(({ labels }) =>\n labels.has(ACTIVATION_LABEL),\n );\n if (labelled.length > 1) {\n throw new RunnerLifecycleError(\n `Multiple repository runners carry the ${ACTIVATION_LABEL} label (${labelled.map(({ name }) => name).join(\", \")}). Remove duplicates before continuing.`,\n );\n }\n const matching = remoteRunners.find(({ name }) => name === metadata.name);\n if (!matching) {\n throw new RunnerLifecycleError(\n `Runner ${metadata.name} is installed locally but is no longer registered with GitHub. Run \\`shipyard runner start\\` to repair it, or remove it explicitly.`,\n );\n }\n if (!matching.labels.has(ACTIVATION_LABEL)) {\n throw new RunnerLifecycleError(\n `Registered runner ${metadata.name} does not carry the ${ACTIVATION_LABEL} label. Refusing to replace a customized registration.`,\n );\n }\n\n return metadata;\n};\n\nconst removeRegistrationFiles = async (\n runnerDir: string,\n adapters: RunnerLifecycleAdapters,\n): Promise<void> => {\n for (const name of REGISTRATION_FILES) {\n const path = join(runnerDir, name);\n if (await adapters.exists(path)) await adapters.remove(path);\n }\n};\n\nconst readOneTimeToken = (stdout: string, purpose: string): string => {\n try {\n const parsed = JSON.parse(stdout) as { token?: unknown };\n if (typeof parsed.token !== \"string\" || parsed.token.length === 0) {\n throw new Error(\"response did not contain a token\");\n }\n return parsed.token;\n } catch (error) {\n throw lifecycleFailure(purpose, error);\n }\n};\n\nconst requestRegistrationToken = async (\n repository: string,\n repoDir: string,\n environment: NodeJS.ProcessEnv,\n adapters: RunnerLifecycleAdapters,\n): Promise<string> => {\n await runCommand(\n adapters,\n \"Checking current administrative GitHub authorization\",\n \"gh\",\n [\"auth\", \"status\", \"--hostname\", \"github.com\"],\n { cwd: repoDir, env: environment },\n );\n const response = await runCommand(\n adapters,\n \"Requesting a one-time repository runner registration token\",\n \"gh\",\n [\n \"api\",\n \"--method\",\n \"POST\",\n `repos/${repository}/actions/runners/registration-token`,\n ],\n { cwd: repoDir, env: environment },\n );\n return readOneTimeToken(response.stdout, \"Reading the registration token\");\n};\n\nexport const recoverRepositoryRunner = async (\n options: {\n readonly repoDir: string;\n readonly runnerDir: string;\n readonly maskDir: string;\n readonly metadata: RunnerInstallMetadata;\n readonly runnerEnvironment: NodeJS.ProcessEnv;\n readonly dockerEnvironment?: NodeJS.ProcessEnv;\n },\n adapters: RunnerLifecycleAdapters = defaultAdapters,\n): Promise<{ readonly reRegistered: boolean }> => {\n const lockPath = join(options.runnerDir, RUNNER_CONTROLLER_LOCK);\n const lock = await readJson<RunnerControllerLock>(lockPath, adapters);\n if (await lockOwnsProcess(lock, adapters)) {\n throw new RunnerLifecycleError(\n `The repository runner is already running with process ${lock!.pid}.`,\n );\n }\n if (lock) await adapters.remove(lockPath);\n\n const workDir = join(options.runnerDir, RUNNER_WORK_DIR);\n if (await adapters.exists(workDir)) await adapters.remove(workDir);\n if (await adapters.exists(options.maskDir))\n await adapters.remove(options.maskDir);\n await adapters.makeDirectory(options.maskDir);\n await assertProtectedDirectoryIdentities(\n options.runnerDir,\n options.maskDir,\n adapters.inspectDirectory,\n ).catch((error) => {\n throw lifecycleFailure(\"Validating protected runner directories\", error);\n });\n\n await removeOwnedRepositoryRunnerContainers(\n {\n repoDir: options.repoDir,\n repository: options.metadata.repository,\n environment: options.dockerEnvironment ?? options.runnerEnvironment,\n },\n adapters,\n );\n\n const adminEnvironment = adapters.environment();\n const remoteRunners = await listRemoteRunners(\n options.metadata.repository,\n options.repoDir,\n adminEnvironment,\n adapters,\n );\n const labelled = remoteRunners.filter(({ labels }) =>\n labels.has(ACTIVATION_LABEL),\n );\n if (labelled.length > 1) {\n throw new RunnerLifecycleError(\n `Multiple repository runners carry the ${ACTIVATION_LABEL} label (${labelled.map(({ name }) => name).join(\", \")}). Remove duplicates before continuing.`,\n );\n }\n const matching = remoteRunners.find(\n ({ name }) => name === options.metadata.name,\n );\n if (matching) {\n if (!matching.labels.has(ACTIVATION_LABEL)) {\n throw new RunnerLifecycleError(\n `Registered runner ${matching.name} does not carry the ${ACTIVATION_LABEL} label. Refusing to replace a customized registration.`,\n );\n }\n if (!(await adapters.exists(join(options.runnerDir, \".credentials\")))) {\n throw new RunnerLifecycleError(\n `Registered runner ${matching.name} is missing local credentials. Remove and reinstall it explicitly.`,\n );\n }\n return { reRegistered: false };\n }\n\n const collision = labelled[0];\n if (collision) {\n throw new RunnerLifecycleError(\n `Repository runner ${collision.name} already carries the ${ACTIVATION_LABEL} label. Refusing to create a conflicting registration.`,\n );\n }\n\n const registrationToken = await requestRegistrationToken(\n options.metadata.repository,\n options.repoDir,\n adminEnvironment,\n adapters,\n );\n await removeRegistrationFiles(options.runnerDir, adapters);\n try {\n await adapters.run(\n \"./config.sh\",\n [\n \"--url\",\n options.metadata.repositoryUrl,\n \"--token\",\n registrationToken,\n \"--name\",\n options.metadata.name,\n \"--labels\",\n ACTIVATION_LABEL,\n \"--work\",\n RUNNER_WORK_DIR,\n \"--unattended\",\n ],\n { cwd: options.runnerDir, env: options.runnerEnvironment },\n );\n } catch {\n await removeRegistrationFiles(options.runnerDir, adapters);\n throw new RunnerLifecycleError(\n `Re-registering ${options.metadata.name} failed. Partial local registration files were removed; check GitHub Settings > Actions > Runners for an orphan registration, then retry \\`shipyard runner start\\`. The one-time token was not stored.`,\n );\n }\n return { reRegistered: true };\n};\n\nexport const removeOwnedRepositoryRunnerContainers = async (\n options: {\n readonly repoDir: string;\n readonly repository: string;\n readonly environment: NodeJS.ProcessEnv;\n },\n adapters: Pick<RunnerLifecycleAdapters, \"run\"> = defaultAdapters,\n): Promise<void> => {\n const ownedContainers = await runCommand(\n adapters,\n \"Finding stale repository-runner containers\",\n \"docker\",\n [\n \"ps\",\n \"-aq\",\n \"--filter\",\n `label=${REPOSITORY_RUNNER_OWNER_LABEL}=${options.repository}`,\n ],\n { cwd: options.repoDir, env: options.environment },\n );\n const containerIds = ownedContainers.stdout.split(/\\s+/).filter(Boolean);\n if (containerIds.length === 0) return;\n await runCommand(\n adapters,\n \"Removing stale repository-runner containers\",\n \"docker\",\n [\"rm\", \"-f\", ...containerIds],\n { cwd: options.repoDir, env: options.environment },\n );\n};\n\nconst waitForProcessToStop = async (\n pid: number,\n adapters: RunnerLifecycleAdapters,\n): Promise<void> => {\n adapters.signalProcess(pid, \"SIGTERM\");\n for (let attempt = 0; attempt < 50; attempt += 1) {\n if (!adapters.isProcessRunning(pid)) return;\n await adapters.pause(100);\n }\n throw new RunnerLifecycleError(\n `Repository runner process ${pid} did not stop within 5 seconds. Local runner files were preserved.`,\n );\n};\n\nconst unregisterRepositoryRunner = async (\n metadata: RunnerInstallMetadata,\n repoDir: string,\n runnerDir: string,\n environment: NodeJS.ProcessEnv,\n adapters: RunnerLifecycleAdapters,\n): Promise<void> => {\n await runCommand(\n adapters,\n \"Checking current administrative GitHub authorization\",\n \"gh\",\n [\"auth\", \"status\", \"--hostname\", \"github.com\"],\n { cwd: repoDir, env: environment },\n );\n const response = await runCommand(\n adapters,\n \"Requesting a one-time repository runner removal token\",\n \"gh\",\n [\n \"api\",\n \"--method\",\n \"POST\",\n `repos/${metadata.repository}/actions/runners/remove-token`,\n ],\n { cwd: repoDir, env: environment },\n );\n const token = readOneTimeToken(response.stdout, \"Reading the removal token\");\n try {\n await adapters.run(\n \"./config.sh\",\n [\"remove\", \"--token\", token, \"--unattended\"],\n { cwd: runnerDir, env: repositoryRunnerEnvironment(environment) },\n );\n } catch {\n throw new RunnerLifecycleError(\n `Unregistering ${metadata.name} from GitHub failed. Local runner files were preserved; retry after restoring repository administration access.`,\n );\n }\n};\n\nexport interface RepositoryRunnerRemoveResult {\n readonly removed: true;\n readonly forced: boolean;\n readonly manualCleanup?: string;\n}\n\nexport const removeRepositoryRunner = async (\n options: { readonly repoDir: string; readonly force?: boolean },\n adapters: RunnerLifecycleAdapters = defaultAdapters,\n): Promise<RepositoryRunnerRemoveResult> => {\n const configDir = join(options.repoDir, CONFIG_DIR);\n const runnerDir = join(configDir, RUNNER_DIR);\n const maskDir = join(configDir, RUNNER_SANDBOX_MASK_DIR);\n if (!(await adapters.exists(runnerDir))) {\n throw new RunnerLifecycleError(\n `No repository runner is installed at ${runnerDir}.`,\n );\n }\n let metadata: RunnerInstallMetadata;\n try {\n metadata = await requireInstallMetadata(runnerDir, adapters);\n } catch (error) {\n if (!options.force) throw error;\n await adapters.remove(runnerDir);\n if (await adapters.exists(maskDir)) await adapters.remove(maskDir);\n return {\n removed: true,\n forced: true,\n manualCleanup:\n \"Check GitHub Settings > Actions > Runners and manually remove any orphan repository runner registration.\",\n };\n }\n const lock = await readJson<RunnerControllerLock>(\n join(runnerDir, RUNNER_CONTROLLER_LOCK),\n adapters,\n );\n if (await lockOwnsProcess(lock, adapters)) {\n await waitForProcessToStop(lock!.pid, adapters);\n }\n\n try {\n await unregisterRepositoryRunner(\n metadata,\n options.repoDir,\n runnerDir,\n adapters.environment(),\n adapters,\n );\n } catch (error) {\n if (!options.force) {\n const failure = lifecycleFailure(\"Removing the repository runner\", error);\n throw new RunnerLifecycleError(\n `${failure.message} Local runner files were preserved.`,\n );\n }\n await adapters.remove(runnerDir);\n if (await adapters.exists(maskDir)) await adapters.remove(maskDir);\n return {\n removed: true,\n forced: true,\n manualCleanup: `Remove runner ${metadata.name} from ${metadata.repository} in GitHub Settings > Actions > Runners.`,\n };\n }\n\n if (await adapters.exists(maskDir)) await adapters.remove(maskDir);\n await adapters.remove(runnerDir);\n return { removed: true, forced: false };\n};\n","import { copyIntoContainer } from \"./copyIntoContainer.js\";\n/**\n * Docker sandbox provider — wraps DockerLifecycle into a SandboxProvider.\n *\n * Usage:\n * import { docker } from \"@snappedly-tools/shipyard/sandboxes/docker\";\n * await run({ agent: codex(CODEX_MODELS.routine), sandbox: docker() });\n */\n\nimport {\n execFile,\n execFileSync,\n spawn,\n type StdioOptions,\n} from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { Effect } from \"effect\";\nimport { startContainer, removeContainer } from \"../DockerLifecycle.js\";\nimport {\n createIsolatedSandboxProvider,\n type IsolatedSandboxProvider,\n type IsolatedCreateOptions,\n type IsolatedSandboxHandle,\n type ExecResult,\n type InteractiveExecOptions,\n} from \"../SandboxProvider.js\";\nimport type { MountConfig } from \"../MountConfig.js\";\nimport type { SelinuxLabel } from \"../mountUtils.js\";\nimport {\n defaultImageName,\n resolveUserMounts,\n assertIsolatedWorkspaceMounts,\n processFileMountParents,\n} from \"../mountUtils.js\";\nimport { MAX_TAIL_CHARS } from \"../boundedTail.js\";\nimport { collectProcessOutput } from \"../processOutput.js\";\nimport { registerShutdown } from \"../shutdownRegistry.js\";\nimport {\n REPOSITORY_RUNNER_OWNER_ENV,\n REPOSITORY_RUNNER_OWNER_LABEL,\n} from \"../RepositoryRunnerLifecycle.js\";\n\nexport interface DockerOptions {\n /** Docker image name (default: derived from repo directory name). */\n readonly imageName?: string;\n /**\n * The UID of the `agent` user inside the container image (default: host UID via `process.getuid()`, or 1000).\n *\n * Must match the UID baked into the image at build time. Used as the `--user` flag value\n * and checked against the image's configured UID in the pre-flight diagnostic.\n */\n readonly containerUid?: number;\n /**\n * The GID of the `agent` user inside the container image (default: host GID via `process.getgid()`, or 1000).\n *\n * Must match the GID baked into the image at build time. Used as the `--user` flag value.\n */\n readonly containerGid?: number;\n /**\n * SELinux volume label suffix applied to bind mounts.\n *\n * - `\"z\"` — shared label (default). No-op on non-SELinux systems.\n * - `\"Z\"` — private label; only this container can access the mount.\n * - `false` — disable labeling entirely.\n */\n readonly selinuxLabel?: SelinuxLabel;\n /**\n * Additional host directories to bind-mount into the sandbox.\n *\n * Each entry specifies a `hostPath` (tilde-expanded) and `sandboxPath`.\n * If `hostPath` does not exist, sandbox creation fails with a clear error.\n */\n readonly mounts?: readonly MountConfig[];\n /** Environment variables injected by this provider. Merged at launch time with env resolver and agent provider env. */\n readonly env?: Record<string, string>;\n /**\n * Docker network(s) to attach the container to.\n *\n * - `\"my-network\"` → `--network my-network`\n * - `[\"net1\", \"net2\"]` → `--network net1 --network net2`\n *\n * When omitted, Docker's default bridge network is used.\n */\n readonly network?: string | readonly string[];\n /**\n * Supplementary groups to add the container user to, via `--group-add`.\n *\n * Accepts group names or numeric GIDs:\n *\n * - `[\"docker\"]` → `--group-add docker`\n * - `[999]` → `--group-add 999`\n * - `[\"docker\", 999]` → `--group-add docker --group-add 999`\n *\n * Useful for granting access to a bind-mounted Docker socket (Docker-outside-of-Docker).\n * When omitted, no `--group-add` flags are added.\n */\n readonly groups?: readonly (string | number)[];\n /**\n * Host devices to expose to the container, via `--device`.\n *\n * Each entry is a full device spec in `host[:container[:permissions]]` form:\n *\n * - `[\"/dev/kvm\"]` → `--device /dev/kvm`\n * - `[\"/dev/sda:/dev/xvda:rwm\"]` → `--device /dev/sda:/dev/xvda:rwm`\n * - `[\"/dev/kvm\", \"/dev/fuse\"]` → `--device /dev/kvm --device /dev/fuse`\n *\n * When omitted, no `--device` flags are added.\n */\n readonly devices?: readonly string[];\n /**\n * Maximum number of characters of streamed `exec` output retained per stream\n * (stdout and stderr) when an `onLine` callback is supplied (default: 64KiB).\n *\n * Output is delivered live to `onLine` regardless; this only bounds the tail\n * returned in `ExecResult`, preventing a long-running agent's output from\n * overflowing V8's max string length and crashing the run.\n */\n readonly maxOutputTailChars?: number;\n /**\n * Limit the CPU resources available to the container, via `--cpus`.\n *\n * Maps directly to `docker run --cpus`. Accepts fractional values:\n *\n * - `2` → `--cpus 2` (at most 2 CPUs)\n * - `1.5` → `--cpus 1.5` (at most 1.5 CPUs)\n *\n * When omitted, no `--cpus` flag is added and the container is unconstrained.\n */\n readonly cpus?: number;\n}\n\n/**\n * Create a Docker sandbox provider.\n *\n * The returned provider creates Docker containers with isolated repository and Git storage.\n * Changes are transferred through git bundle and validated sync-out.\n */\nexport const docker = (options?: DockerOptions): IsolatedSandboxProvider => {\n const configuredImageName = options?.imageName;\n const selinuxLabel = options?.selinuxLabel ?? \"z\";\n const maxOutputTailChars = options?.maxOutputTailChars ?? MAX_TAIL_CHARS;\n const sandboxHomedir = \"/home/agent\";\n const userMounts = options?.mounts\n ? resolveUserMounts(options.mounts, sandboxHomedir)\n : [];\n assertIsolatedWorkspaceMounts(userMounts);\n // Validate file mounts and collect parent dirs to create at container start.\n // Throws at construction time if any file mount parent is outside sandboxHomedir.\n const parentDirsToCreate = processFileMountParents(\n userMounts,\n sandboxHomedir,\n );\n\n return createIsolatedSandboxProvider({\n name: \"docker\",\n env: options?.env,\n create: async (\n createOptions: IsolatedCreateOptions,\n ): Promise<IsolatedSandboxHandle> => {\n const containerName = `shipyard-${randomUUID()}`;\n\n const worktreePath = \"/home/agent/workspace\";\n\n // Repository and Git storage are container-owned. Only explicitly\n // configured mounts cross the host boundary.\n const allMounts = userMounts;\n const volumeMounts = allMounts.map((m) => ({\n hostPath: m.hostPath,\n sandboxPath: m.sandboxPath,\n readonly: m.readonly,\n }));\n\n // Resolve image name\n const imageName =\n configuredImageName ??\n defaultImageName(createOptions.hostRepoPath ?? process.cwd());\n\n const containerUid = options?.containerUid ?? process.getuid?.() ?? 1000;\n const containerGid = options?.containerGid ?? process.getgid?.() ?? 1000;\n\n // Pre-flight: verify image exists and UID matches\n await checkImageUid(imageName, containerUid);\n\n // Start container\n await Effect.runPromise(\n startContainer(\n containerName,\n imageName,\n {\n ...createOptions.env,\n HOME: \"/home/agent\",\n },\n {\n volumeMounts,\n workdir: worktreePath,\n user: `${containerUid}:${containerGid}`,\n network: options?.network,\n groups: options?.groups,\n devices: options?.devices,\n cpus: options?.cpus,\n selinuxLabel,\n labels: process.env[REPOSITORY_RUNNER_OWNER_ENV]\n ? {\n [REPOSITORY_RUNNER_OWNER_LABEL]:\n process.env[REPOSITORY_RUNNER_OWNER_ENV],\n }\n : undefined,\n },\n ),\n );\n\n // Create parent directories for file mounts and chown to the container user\n for (const dir of parentDirsToCreate) {\n await new Promise<void>((resolve, reject) => {\n execFile(\n \"docker\",\n [\n \"exec\",\n \"--user\",\n \"0:0\",\n containerName,\n \"sh\",\n \"-c\",\n `mkdir -p \"$1\" && chown \"$2\" \"$1\"`,\n \"sh\",\n dir,\n `${containerUid}:${containerGid}`,\n ],\n (error) => {\n if (error) {\n reject(\n new Error(\n `Failed to create parent directory '${dir}' in container: ${error.message}`,\n ),\n );\n } else {\n resolve();\n }\n },\n );\n });\n }\n\n // Register synchronous container cleanup via the shared shutdown registry\n // so concurrent sandboxes share a single exit/SIGINT/SIGTERM listener\n // instead of tripping Node's MaxListenersExceededWarning.\n const removeContainerSync = () => {\n try {\n execFileSync(\"docker\", [\"rm\", \"-f\", containerName], {\n stdio: \"ignore\",\n });\n } catch {\n /* best-effort */\n }\n };\n const unregisterShutdown = registerShutdown(removeContainerSync);\n\n const handle: IsolatedSandboxHandle = {\n worktreePath,\n\n exec: (\n command: string,\n opts?: {\n onLine?: (line: string) => void;\n cwd?: string;\n sudo?: boolean;\n stdin?: string;\n signal?: AbortSignal;\n maxOutputBytes?: number;\n },\n ): Promise<ExecResult> => {\n const effectiveCommand = opts?.sudo ? `sudo ${command}` : command;\n const args = [\"exec\"];\n if (opts?.stdin !== undefined) args.push(\"-i\");\n if (opts?.cwd) args.push(\"-w\", opts.cwd);\n args.push(containerName, \"sh\", \"-c\", effectiveCommand);\n\n return new Promise((resolve, reject) => {\n const proc = spawn(\"docker\", args, {\n signal: opts?.signal,\n stdio: [\n opts?.stdin !== undefined ? \"pipe\" : \"ignore\",\n \"pipe\",\n \"pipe\",\n ],\n });\n\n if (opts?.stdin !== undefined) {\n proc.stdin!.write(opts.stdin);\n proc.stdin!.end();\n }\n\n proc.on(\"error\", (error) => {\n reject(new Error(`docker exec failed: ${error.message}`));\n });\n\n collectProcessOutput(\n {\n stdout: proc.stdout!,\n stderr: proc.stderr!,\n kill: () => proc.kill(\"SIGKILL\"),\n onClose: (listener) => proc.on(\"close\", listener),\n },\n { ...opts, maxOutputTailChars },\n resolve,\n reject,\n );\n });\n },\n\n interactiveExec: (\n args: string[],\n opts: InteractiveExecOptions,\n ): Promise<{ exitCode: number }> => {\n return new Promise((resolve, reject) => {\n opts.signal?.throwIfAborted();\n const executionId = randomUUID();\n const pidFile = `/tmp/shipyard-interactive-${executionId}.pid`;\n const cancelFile = `/tmp/shipyard-interactive-${executionId}.cancel`;\n const dockerArgs = [\"exec\"];\n // Allocate a pseudo-terminal when stdin looks like a TTY\n if (\n \"isTTY\" in opts.stdin &&\n (opts.stdin as { isTTY?: boolean }).isTTY\n ) {\n dockerArgs.push(\"-it\");\n } else {\n dockerArgs.push(\"-i\");\n }\n if (opts.cwd) dockerArgs.push(\"-w\", opts.cwd);\n dockerArgs.push(\n containerName,\n \"sh\",\n \"-c\",\n 'pid_file=$1; cancel_file=$2; shift 2; command -v setsid >/dev/null 2>&1 && command -v ps >/dev/null 2>&1 && command -v awk >/dev/null 2>&1 || { printf \"%s\\\\n\" \"setsid, ps, and awk are required for cancellable interactive execution\" >&2; exit 127; }; if [ -e \"$cancel_file\" ]; then rm -f \"$pid_file\" \"$cancel_file\"; exit 130; fi; setsid \"$@\" & child=$!; printf \"%s\\\\n\" \"$child\" > \"$pid_file\"; wait \"$child\"; status=$?; rm -f \"$pid_file\" \"$cancel_file\"; exit \"$status\"',\n \"shipyard-interactive\",\n pidFile,\n cancelFile,\n ...args,\n );\n\n const proc = spawn(\"docker\", dockerArgs, {\n stdio: [opts.stdin, opts.stdout, opts.stderr] as StdioOptions,\n });\n\n let settled = false;\n let cancelling = false;\n const finish = (\n result:\n | { readonly exitCode: number }\n | { readonly error: unknown },\n ): void => {\n if (settled) return;\n settled = true;\n opts.signal?.removeEventListener(\"abort\", onAbort);\n if (\"error\" in result) reject(result.error);\n else resolve(result);\n };\n\n const onAbort = (): void => {\n if (cancelling || settled) return;\n cancelling = true;\n const cancellationScript =\n 'touch \"$1\"; attempts=0; while [ ! -s \"$2\" ] && [ \"$attempts\" -lt 50 ]; do sleep 0.1; attempts=$((attempts + 1)); done; if [ -s \"$2\" ]; then pid=$(cat \"$2\"); group_running() { ps -eo pgid=,stat= | awk -v pg=\"$pid\" \\'$1 == pg && $2 !~ /^Z/ { found=1 } END { exit found ? 0 : 1 }\\'; }; kill -TERM \"-$pid\" 2>/dev/null || true; attempts=0; while group_running && [ \"$attempts\" -lt 20 ]; do sleep 0.1; attempts=$((attempts + 1)); done; kill -KILL \"-$pid\" 2>/dev/null || true; attempts=0; while group_running && [ \"$attempts\" -lt 20 ]; do sleep 0.1; attempts=$((attempts + 1)); done; if group_running; then exit 1; fi; rm -f \"$1\" \"$2\"; fi';\n execFile(\n \"docker\",\n [\n \"exec\",\n containerName,\n \"sh\",\n \"-c\",\n cancellationScript,\n \"shipyard-cancel\",\n cancelFile,\n pidFile,\n ],\n { timeout: 7_000 },\n (error) => {\n proc.kill(\"SIGKILL\");\n if (error) {\n finish({\n error: new Error(\n `Failed to terminate interactive process in Docker sandbox: ${error.message}`,\n ),\n });\n return;\n }\n finish({\n error:\n opts.signal?.reason ??\n new Error(\"Interactive execution aborted\"),\n });\n },\n );\n };\n\n opts.signal?.addEventListener(\"abort\", onAbort, { once: true });\n if (opts.signal?.aborted) onAbort();\n\n proc.on(\"error\", (error: Error) => {\n if (!cancelling) {\n finish({\n error: new Error(`docker exec failed: ${error.message}`),\n });\n }\n });\n\n proc.on(\"close\", (code: number | null) => {\n if (cancelling) return;\n execFile(\n \"docker\",\n [\"exec\", containerName, \"rm\", \"-f\", pidFile, cancelFile],\n () => {},\n );\n finish({ exitCode: code ?? 0 });\n });\n });\n },\n\n copyIn: (hostPath, sandboxPath) =>\n copyIntoContainer(\n \"docker\",\n containerName,\n `${containerUid}:${containerGid}`,\n hostPath,\n sandboxPath,\n ),\n\n copyFileOut: (sandboxPath: string, hostPath: string): Promise<void> =>\n new Promise((resolve, reject) => {\n execFile(\n \"docker\",\n [\"cp\", `${containerName}:${sandboxPath}`, hostPath],\n (error) => {\n if (error) {\n reject(new Error(`docker cp (out) failed: ${error.message}`));\n } else {\n resolve();\n }\n },\n );\n }),\n\n close: async (): Promise<void> => {\n unregisterShutdown();\n await Effect.runPromise(removeContainer(containerName));\n },\n };\n\n return handle;\n },\n });\n};\n\n// Re-export for backwards compatibility\nexport { defaultImageName };\n\nconst checkImageUid = (imageName: string, expectedUid: number): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n execFile(\n \"docker\",\n [\"image\", \"inspect\", imageName, \"--format\", \"{{.Config.User}}\"],\n (error, stdout) => {\n if (error) {\n reject(\n new Error(\n `Image '${imageName}' not found locally. Build it first with 'shipyard docker build-image'.`,\n ),\n );\n return;\n }\n const imageUser = (stdout ?? \"\").toString().trim();\n if (!imageUser) {\n // No USER directive in image — skip check\n resolve();\n return;\n }\n const uidPart = imageUser.split(\":\")[0]!;\n const imageUid = parseInt(uidPart, 10);\n if (isNaN(imageUid)) {\n // Non-numeric user (e.g. \"agent\") — can't compare, skip check\n resolve();\n return;\n }\n if (imageUid !== expectedUid) {\n reject(\n new Error(\n `UID mismatch: image '${imageName}' was built with UID ${imageUid}, ` +\n `but the expected UID is ${expectedUid}. ` +\n `Rebuild the image with 'shipyard docker build-image', ` +\n `or pass containerUid: ${imageUid} to docker() to match the image.`,\n ),\n );\n } else {\n resolve();\n }\n },\n );\n });\n"]}
package/dist/index.d.ts CHANGED
@@ -484,7 +484,7 @@ interface RunOptions<A extends AgentProvider = AgentProvider> {
484
484
  readonly sandbox: SandboxProvider;
485
485
  /**
486
486
  * Host repo directory. Replaces `process.cwd()` as the anchor for
487
- * `.shipyard/worktrees/`, `.shipyard/.env`, `.shipyard/logs/`,
487
+ * `.shipyard/worktrees/`, `.shipyard/.env`, `.shipyard/logs/YYYY-MM-DD/`,
488
488
  * `.shipyard/patches/`, and git operations.
489
489
  *
490
490
  * - Relative paths are resolved against `process.cwd()`.
@@ -508,7 +508,7 @@ interface RunOptions<A extends AgentProvider = AgentProvider> {
508
508
  readonly hooks?: SandboxHooks;
509
509
  /** Key-value map for {{KEY}} placeholder substitution in prompts */
510
510
  readonly promptArgs?: PromptArgs;
511
- /** Logging mode (default: { type: 'file' } with auto-generated path under .shipyard/logs/) */
511
+ /** Logging mode (default: { type: 'file' } with auto-generated path under .shipyard/logs/YYYY-MM-DD/) */
512
512
  readonly logging?: LoggingOption;
513
513
  /** Substring(s) the agent emits to stop the iteration loop early. Matched via `includes` against agent output. (default: `"<promise>COMPLETE</promise>"`) */
514
514
  readonly completionSignal?: string | string[];
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import { CODEX_MODELS, formatErrorMessage } from './chunk-VDHZO5PP.js';
2
- export { CODEX_MODELS, CODEX_REASONING_EFFORTS } from './chunk-VDHZO5PP.js';
3
- import { CwdError, resolveCwd, getCurrentBranch, generateTempBranchName, CONFIG_DIR, LOGS_DIR, assertNoSymlinkComponents, FileDisplay, ClackDisplay, WorktreeDockerSandboxFactory, SandboxConfig, Display, CLI_NAME, PRODUCT_NAME, pruneStale, create, copyToWorktree, runHostHooks, startSandbox, resolveGitMounts, patchGitMountsForWindows, SANDBOX_REPO_DIR, remove, makeSandboxFromHandle, syncOut, withSandboxLifecycle, hasUncommittedChanges, registerShutdown, SandboxFactory, PromptError, ConfigDirError, AgentError, SessionCaptureError, PromptExpansionTimeoutError, SilentDisplay, AgentIdleTimeoutError } from './chunk-2GT3OPO5.js';
1
+ import { CODEX_MODELS, resolveEnv, formatErrorMessage, buildLogDirectoryName } from './chunk-56TDSWFU.js';
2
+ export { CODEX_MODELS, CODEX_REASONING_EFFORTS } from './chunk-56TDSWFU.js';
3
+ import { CwdError, resolveCwd, getCurrentBranch, generateTempBranchName, assertNoSymlinkComponents, FileDisplay, ClackDisplay, WorktreeDockerSandboxFactory, SandboxConfig, Display, CLI_NAME, PRODUCT_NAME, pruneStale, create, copyToWorktree, runHostHooks, startSandbox, resolveGitMounts, patchGitMountsForWindows, SANDBOX_REPO_DIR, remove, makeSandboxFromHandle, syncOut, withSandboxLifecycle, hasUncommittedChanges, registerShutdown, SandboxFactory, PromptError, CONFIG_DIR, LOGS_DIR, AgentError, SessionCaptureError, PromptExpansionTimeoutError, SilentDisplay, AgentIdleTimeoutError } from './chunk-FDYOTN55.js';
4
4
  import { shellQuote, toSessionTransferHandle } from './chunk-KMGNFXKN.js';
5
5
  export { createBindMountSandboxProvider, createIsolatedSandboxProvider } from './chunk-KMGNFXKN.js';
6
- import { noSandbox } from './chunk-VW4MI5GJ.js';
7
- import './chunk-WA7QPAXO.js';
6
+ import { noSandbox } from './chunk-SOJTAJTF.js';
7
+ import './chunk-ACD46ZM4.js';
8
8
  import { NodeContext, NodeFileSystem } from '@effect/platform-node';
9
9
  import { mkdirSync, chmodSync, appendFileSync, constants } from 'fs';
10
10
  import path, { join, posix, dirname, relative } from 'path';
@@ -652,62 +652,6 @@ var resolvePrompt = (options) => {
652
652
  return { text: text2, source: "template" };
653
653
  });
654
654
  };
655
- var parseEnvFile = (filePath) => Effect.gen(function* () {
656
- const fs = yield* FileSystem.FileSystem;
657
- const symlink = yield* fs.readLink(filePath).pipe(
658
- Effect.map(() => true),
659
- Effect.catchAll(() => Effect.succeed(false))
660
- );
661
- if (symlink) return {};
662
- const content = yield* fs.readFileString(filePath).pipe(Effect.catchAll(() => Effect.succeed(null)));
663
- if (content === null) return {};
664
- const vars = {};
665
- for (const line of content.split("\n")) {
666
- const trimmed = line.trim();
667
- if (!trimmed || trimmed.startsWith("#")) continue;
668
- const eqIndex = trimmed.indexOf("=");
669
- if (eqIndex === -1) continue;
670
- const key = trimmed.slice(0, eqIndex).trim();
671
- let value = trimmed.slice(eqIndex + 1).trim();
672
- const isDoubleQuoted = value.length >= 2 && value[0] === '"' && value[value.length - 1] === '"';
673
- const isSingleQuoted = value.length >= 2 && value[0] === "'" && value[value.length - 1] === "'";
674
- if (isDoubleQuoted || isSingleQuoted) {
675
- value = value.slice(1, -1);
676
- }
677
- if (isDoubleQuoted) {
678
- value = value.replace(/\\([nrt\\])/g, (_, ch) => {
679
- const escapes = {
680
- n: "\n",
681
- r: "\r",
682
- t: " ",
683
- "\\": "\\"
684
- };
685
- return escapes[ch] ?? ch;
686
- });
687
- }
688
- vars[key] = value;
689
- }
690
- return vars;
691
- });
692
- var resolveEnv = (repoDir) => Effect.gen(function* () {
693
- const configDir = join(repoDir, CONFIG_DIR);
694
- const envPath = join(configDir, ".env");
695
- yield* Effect.tryPromise({
696
- try: () => assertNoSymlinkComponents(repoDir, envPath, "environment file"),
697
- catch: (e) => new ConfigDirError({
698
- message: `Refusing symlinked environment path: ${e instanceof Error ? e.message : String(e)}`
699
- })
700
- });
701
- const shipyardEnv = yield* parseEnvFile(envPath);
702
- const result3 = {};
703
- for (const key of Object.keys(shipyardEnv)) {
704
- const value = shipyardEnv[key] || process.env[key];
705
- if (value) {
706
- result3[key] = value;
707
- }
708
- }
709
- return result3;
710
- });
711
655
 
712
656
  // src/mergeProviderEnv.ts
713
657
  var mergeProviderEnv = (options) => {
@@ -996,6 +940,13 @@ var buildLogFilename = (resolvedBranch, targetBranch, name) => {
996
940
  }
997
941
  return `${sanitized}${nameSuffix}.log`;
998
942
  };
943
+ var buildDefaultLogPath = (hostRepoDir, resolvedBranch, targetBranch, name, date = /* @__PURE__ */ new Date()) => join(
944
+ hostRepoDir,
945
+ CONFIG_DIR,
946
+ LOGS_DIR,
947
+ buildLogDirectoryName(date),
948
+ buildLogFilename(resolvedBranch, targetBranch, name)
949
+ );
999
950
  var buildRunSummaryRows = (options) => ({
1000
951
  Agent: options.name ?? options.agentName,
1001
952
  Sandbox: options.sandboxName,
@@ -1149,11 +1100,11 @@ async function run(options) {
1149
1100
  const targetBranch = effectiveBranchType === "merge-to-head" ? currentHostBranch : void 0;
1150
1101
  const resolvedLogging = options.logging ?? {
1151
1102
  type: "file",
1152
- path: join(
1103
+ path: buildDefaultLogPath(
1153
1104
  hostRepoDir,
1154
- CONFIG_DIR,
1155
- LOGS_DIR,
1156
- buildLogFilename(resolvedBranch, targetBranch, options.name)
1105
+ resolvedBranch,
1106
+ targetBranch,
1107
+ options.name
1157
1108
  )
1158
1109
  };
1159
1110
  if (options.logging === void 0 && resolvedLogging.type === "file") {
@@ -1724,11 +1675,11 @@ var buildSandboxHandle = (ctx, close) => {
1724
1675
  );
1725
1676
  const resolvedLogging = runOptions.logging ?? {
1726
1677
  type: "file",
1727
- path: join(
1678
+ path: buildDefaultLogPath(
1728
1679
  hostRepoDir,
1729
- CONFIG_DIR,
1730
- LOGS_DIR,
1731
- buildLogFilename(branch, void 0, runOptions.name)
1680
+ branch,
1681
+ void 0,
1682
+ runOptions.name
1732
1683
  )
1733
1684
  };
1734
1685
  if (runOptions.logging === void 0 && resolvedLogging.type === "file") {
@@ -2565,11 +2516,11 @@ var createWorktree = async (options) => {
2565
2516
  const applyToHost = sandboxProvider.tag === "isolated" ? () => syncOut(worktreeInfo.path, handle) : () => Effect.void;
2566
2517
  const resolvedLogging = opts.logging ?? {
2567
2518
  type: "file",
2568
- path: join(
2519
+ path: buildDefaultLogPath(
2569
2520
  hostRepoDir,
2570
- CONFIG_DIR,
2571
- LOGS_DIR,
2572
- buildLogFilename(worktreeInfo.branch, void 0, opts.name)
2521
+ worktreeInfo.branch,
2522
+ void 0,
2523
+ opts.name
2573
2524
  )
2574
2525
  };
2575
2526
  if (opts.logging === void 0 && resolvedLogging.type === "file") {
@@ -2879,7 +2830,6 @@ var writePrivateFile = async (path2, content) => {
2879
2830
  await writeFile(path2, content, { mode: 384 });
2880
2831
  await chmod(path2, 384);
2881
2832
  };
2882
- var shellEscape = (s) => "'" + s.replace(/'/g, "'\\''") + "'";
2883
2833
  var TOOL_ARG_FIELDS = {
2884
2834
  Bash: "command",
2885
2835
  WebSearch: "query",
@@ -2970,7 +2920,7 @@ var writeSandboxFile = async (handle, sandboxPath, content, tag) => {
2970
2920
  const tmpPath = join(tempDir, "session.jsonl");
2971
2921
  try {
2972
2922
  await writeFile(tmpPath, content, { mode: 384 });
2973
- await handle.exec(`mkdir -p ${shellEscape(posix.dirname(sandboxPath))}`);
2923
+ await handle.exec(`mkdir -p ${shellQuote(posix.dirname(sandboxPath))}`);
2974
2924
  await handle.copyFileIn(tmpPath, sandboxPath);
2975
2925
  } finally {
2976
2926
  await rm(tempDir, { recursive: true, force: true }).catch(() => {
@@ -3157,19 +3107,19 @@ var codex = (model, options) => {
3157
3107
  resumeSession,
3158
3108
  forkSession
3159
3109
  }) {
3160
- const effortFlag = effort ? ` -c ${shellEscape(`model_reasoning_effort="${effort}"`)}` : "";
3161
- const approvalsFlags = options?.approvalsReviewer === "auto_review" ? ` -a on-request -s danger-full-access -c ${shellEscape(`approvals_reviewer="auto_review"`)}` : " --dangerously-bypass-approvals-and-sandbox";
3110
+ const effortFlag = effort ? ` -c ${shellQuote(`model_reasoning_effort="${effort}"`)}` : "";
3111
+ const approvalsFlags = options?.approvalsReviewer === "auto_review" ? ` -a on-request -s danger-full-access -c ${shellQuote(`approvals_reviewer="auto_review"`)}` : " --dangerously-bypass-approvals-and-sandbox";
3162
3112
  let base;
3163
3113
  if (resumeSession && forkSession) {
3164
- base = `codex exec fork ${shellEscape(resumeSession)}`;
3114
+ base = `codex exec fork ${shellQuote(resumeSession)}`;
3165
3115
  } else if (resumeSession) {
3166
- base = `codex exec resume ${shellEscape(resumeSession)}`;
3116
+ base = `codex exec resume ${shellQuote(resumeSession)}`;
3167
3117
  } else {
3168
3118
  base = "codex exec";
3169
3119
  }
3170
3120
  const stdinArg = resumeSession ? " -" : "";
3171
3121
  return {
3172
- command: `${base} --json${approvalsFlags} -m ${shellEscape(modelId)}${effortFlag}${stdinArg}`,
3122
+ command: `${base} --json${approvalsFlags} -m ${shellQuote(modelId)}${effortFlag}${stdinArg}`,
3173
3123
  stdin: prompt
3174
3124
  };
3175
3125
  },
@@ -3199,10 +3149,10 @@ var claudeCode = (model, options) => ({
3199
3149
  }) {
3200
3150
  const permissionFlag = options?.permissionMode ? ` --permission-mode ${options.permissionMode}` : dangerouslySkipPermissions ? " --dangerously-skip-permissions" : "";
3201
3151
  const effortFlag = options?.effort ? ` --effort ${options.effort}` : "";
3202
- const resumeFlag = resumeSession ? ` --resume ${shellEscape(resumeSession)}` : "";
3152
+ const resumeFlag = resumeSession ? ` --resume ${shellQuote(resumeSession)}` : "";
3203
3153
  const forkFlag = resumeSession && forkSession ? " --fork-session" : "";
3204
3154
  return {
3205
- command: `claude --print --verbose${permissionFlag} --output-format stream-json --model ${shellEscape(model)}${effortFlag}${resumeFlag}${forkFlag} -p -`,
3155
+ command: `claude --print --verbose${permissionFlag} --output-format stream-json --model ${shellQuote(model)}${effortFlag}${resumeFlag}${forkFlag} -p -`,
3206
3156
  stdin: prompt
3207
3157
  };
3208
3158
  },
@@ -3851,6 +3801,16 @@ var parseFinding = (value) => {
3851
3801
  };
3852
3802
  };
3853
3803
 
3804
+ // src/workflow/shared.ts
3805
+ var sameRevision = (left, right) => left.branch === right.branch && left.sha === right.sha;
3806
+ var deepFreeze = (value) => {
3807
+ if (typeof value !== "object" || value === null) return value;
3808
+ for (const child of Object.values(value)) {
3809
+ deepFreeze(child);
3810
+ }
3811
+ return Object.freeze(value);
3812
+ };
3813
+
3854
3814
  // src/workflow/coordinator/in-memory-storage.ts
3855
3815
  var clone = (value) => structuredClone(value);
3856
3816
  var cloneState = (state2) => ({
@@ -4880,7 +4840,6 @@ var eventKey = (input) => ({
4880
4840
  });
4881
4841
  var isAuthorized = (brief, policy) => isAuthorizationAllowed(brief, policy);
4882
4842
  var sameIdentity3 = (left, right) => left.repository === right.repository && left.itemId === right.itemId && left.kind === right.kind;
4883
- var sameRevision = (left, right) => left.branch === right.branch && left.sha === right.sha;
4884
4843
  var isSameEventRevision = (current, incoming) => current.brief.hash === incoming.brief.hash && current.key.phase === incoming.phase && current.key.relevantRevision === incoming.relevantRevision;
4885
4844
  var errorMessage = (error) => error instanceof Error ? error.message : String(error);
4886
4845
  var LeaseLostError = class extends Error {
@@ -5942,13 +5901,6 @@ var createFakePhaseEngineAdapter = (options) => ({
5942
5901
  throw new Error("Fake phase engine has no response");
5943
5902
  }
5944
5903
  });
5945
- var deepFreeze = (value) => {
5946
- if (typeof value !== "object" || value === null) return value;
5947
- for (const child of Object.values(value)) {
5948
- deepFreeze(child);
5949
- }
5950
- return Object.freeze(value);
5951
- };
5952
5904
  var normalizeCommits = (commits) => commits.map((commit) => typeof commit === "string" ? commit : commit.sha);
5953
5905
  var reviewBranch = (assignment) => `shipyard/review/${assignment.id.replace(/[^a-zA-Z0-9._-]+/g, "-")}`;
5954
5906
  var failureMessage = (error) => error instanceof Error ? error.message : String(error);
@@ -6402,8 +6354,7 @@ var sandboxResultToResponse = (result3, branch) => {
6402
6354
  artifacts: [],
6403
6355
  questions: [],
6404
6356
  findings: []
6405
- },
6406
- logFilePath: result3.logFilePath
6357
+ }
6407
6358
  };
6408
6359
  };
6409
6360
  var createCreateSandboxPhaseEngineAdapter = (options) => ({
@@ -6434,7 +6385,6 @@ var createCreateSandboxPhaseEngineAdapter = (options) => ({
6434
6385
 
6435
6386
  // src/workflow/handoff/index.ts
6436
6387
  var defaultAxes = ["standards", "spec"];
6437
- var sameRevision2 = (left, right) => left.branch === right.branch && left.sha === right.sha;
6438
6388
  var isFreshTimestamp = (value, now, freshnessWindowSeconds) => {
6439
6389
  const timestamp2 = Date.parse(value);
6440
6390
  const current = Date.parse(now);
@@ -6443,7 +6393,7 @@ var isFreshTimestamp = (value, now, freshnessWindowSeconds) => {
6443
6393
  var requiredChecks = (policy) => policy.checks.filter((check) => check.required).map((check) => check.name);
6444
6394
  var blockingFinding = (finding) => finding.severity !== "info" && (finding.disposition === "open" || finding.disposition === "deferred");
6445
6395
  var implementationEvidence = (job, candidate) => [...job.phaseResults].reverse().find(
6446
- (result3) => result3.outcome === "completed" && (result3.phase === "implementation" || result3.phase === "repair") && result3.base !== void 0 && result3.head !== void 0 && sameRevision2(result3.base, candidate.base) && sameRevision2(result3.head, candidate.head) && result3.briefHash === candidate.briefHash
6396
+ (result3) => result3.outcome === "completed" && (result3.phase === "implementation" || result3.phase === "repair") && result3.base !== void 0 && result3.head !== void 0 && sameRevision(result3.base, candidate.base) && sameRevision(result3.head, candidate.head) && result3.briefHash === candidate.briefHash
6447
6397
  )?.evidence ?? [];
6448
6398
  var allRequiredChecksPassed2 = (policy, checks, expected) => {
6449
6399
  const reasons = [];
@@ -6484,7 +6434,7 @@ var candidateReasons = (job, candidate, review, requiredAxes) => {
6484
6434
  reasons.push("Workflow policy repository does not match the brief");
6485
6435
  }
6486
6436
  if (job.control !== "active") reasons.push(`Workflow job is ${job.control}`);
6487
- if (!sameRevision2(brief.base, candidate.base)) {
6437
+ if (!sameRevision(brief.base, candidate.base)) {
6488
6438
  reasons.push("Candidate base does not match the brief base");
6489
6439
  }
6490
6440
  if (review.baseSha !== candidate.base.sha) {
@@ -6499,7 +6449,7 @@ var candidateReasons = (job, candidate, review, requiredAxes) => {
6499
6449
  const implementationHead = [...job.phaseResults].reverse().find(
6500
6450
  (result3) => result3.phase === "implementation" || result3.phase === "repair"
6501
6451
  )?.head;
6502
- if (implementationHead !== void 0 && !sameRevision2(implementationHead, candidate.head)) {
6452
+ if (implementationHead !== void 0 && !sameRevision(implementationHead, candidate.head)) {
6503
6453
  reasons.push("Candidate head does not match the implementation result");
6504
6454
  }
6505
6455
  if (review.outcome !== "passed") {
@@ -6611,7 +6561,7 @@ var prepareHumanHandoff = async (input) => {
6611
6561
  }
6612
6562
  };
6613
6563
  }
6614
- if (!sameRevision2(current.base, input.candidate.base) || !sameRevision2(current.head, input.candidate.head) || current.briefHash !== input.candidate.briefHash) {
6564
+ if (!sameRevision(current.base, input.candidate.base) || !sameRevision(current.head, input.candidate.head) || current.briefHash !== input.candidate.briefHash) {
6615
6565
  const brief = parseWorkBrief(input.job.brief);
6616
6566
  return {
6617
6567
  outcome: "blocked",
@@ -6692,7 +6642,7 @@ var processHumanReviewDecision = async (input) => {
6692
6642
  pullRequestNumber: input.pullRequestNumber
6693
6643
  };
6694
6644
  }
6695
- if (!sameRevision2(current.base, input.candidate.base) || !sameRevision2(current.head, input.candidate.head) || current.briefHash !== input.candidate.briefHash) {
6645
+ if (!sameRevision(current.base, input.candidate.base) || !sameRevision(current.head, input.candidate.head) || current.briefHash !== input.candidate.briefHash) {
6696
6646
  return {
6697
6647
  outcome: "blocked",
6698
6648
  reason: "Human review decision is stale for the current candidate",
@@ -6735,7 +6685,7 @@ var mergeProtectedCandidate = async (input) => {
6735
6685
  reason: `Could not validate the current candidate: ${error instanceof Error ? error.message : String(error)}`
6736
6686
  };
6737
6687
  }
6738
- if (!sameRevision2(current.base, input.candidate.base) || !sameRevision2(current.head, input.candidate.head) || current.briefHash !== input.candidate.briefHash) {
6688
+ if (!sameRevision(current.base, input.candidate.base) || !sameRevision(current.head, input.candidate.head) || current.briefHash !== input.candidate.briefHash) {
6739
6689
  return {
6740
6690
  outcome: "blocked",
6741
6691
  reason: "current candidate changed before protected merge"
@@ -6875,7 +6825,6 @@ var closeSourceIssue = async (input) => {
6875
6825
 
6876
6826
  // src/workflow/implementation/index.ts
6877
6827
  var defaultNow = () => (/* @__PURE__ */ new Date()).toISOString();
6878
- var sameRevision3 = (left, right) => left.branch === right.branch && left.sha === right.sha;
6879
6828
  var branchPart = (value) => value.toLowerCase().replace(/[^a-z0-9._/-]+/g, "-").replace(/^[./-]+|[./-]+$/g, "").slice(0, 80) || "work";
6880
6829
  var defaultBranch = (brief) => `shipyard/${branchPart(brief.identity.itemId)}-${branchPart(brief.identity.kind)}`;
6881
6830
  var phaseResultFor = (job, phase2) => [...job.phaseResults].reverse().find((result3) => result3.phase === phase2);
@@ -6988,7 +6937,7 @@ var prepareIndependentReview = (input) => {
6988
6937
  if (brief.policyRevision !== policy.revision) {
6989
6938
  reasons.push("Review candidate uses a stale policy revision");
6990
6939
  }
6991
- if (!sameRevision3(brief.base, input.base)) {
6940
+ if (!sameRevision(brief.base, input.base)) {
6992
6941
  reasons.push("Review base does not match the brief base");
6993
6942
  }
6994
6943
  for (const check of policy.checks) {
@@ -7041,7 +6990,7 @@ var runAuthorizedImplementation = async (options) => {
7041
6990
  `Could not validate the current candidate: ${error instanceof Error ? error.message : String(error)}`
7042
6991
  );
7043
6992
  }
7044
- if (!sameRevision3(current.base, brief.base)) {
6993
+ if (!sameRevision(current.base, brief.base)) {
7045
6994
  return blocked("The configured base revision is stale");
7046
6995
  }
7047
6996
  if (current.briefHash !== brief.hash) {
@@ -7188,7 +7137,7 @@ var runAuthorizedImplementation = async (options) => {
7188
7137
  { job, dispatch, assignment, lease, phaseResult, execution }
7189
7138
  );
7190
7139
  }
7191
- if (!sameRevision3(current.base, brief.base) || current.briefHash !== brief.hash) {
7140
+ if (!sameRevision(current.base, brief.base) || current.briefHash !== brief.hash) {
7192
7141
  return blocked(
7193
7142
  "The implementation candidate became stale before publication",
7194
7143
  {
@@ -7471,7 +7420,6 @@ var InMemoryRepairBatchStore = class {
7471
7420
  };
7472
7421
  var defaultNow3 = () => (/* @__PURE__ */ new Date()).toISOString();
7473
7422
  var clone2 = (value) => JSON.parse(JSON.stringify(value));
7474
- var sameRevision4 = (left, right) => left.branch === right.branch && left.sha === right.sha;
7475
7423
  var actionable = (finding) => finding.severity !== "info" && (finding.disposition === "open" || finding.disposition === "deferred");
7476
7424
  var normalizedFindings = (findings) => {
7477
7425
  const byKey = /* @__PURE__ */ new Map();
@@ -7583,7 +7531,7 @@ var scheduleBoundedRepair = async (input) => {
7583
7531
  }
7584
7532
  if (input.readCurrent !== void 0) {
7585
7533
  const current = await input.readCurrent();
7586
- if (!sameRevision4(current.base, input.candidate.base) || !sameRevision4(current.head, input.candidate.head) || current.briefHash !== brief.hash) {
7534
+ if (!sameRevision(current.base, input.candidate.base) || !sameRevision(current.head, input.candidate.head) || current.briefHash !== brief.hash) {
7587
7535
  return blocked2(batch, "Repair candidate became stale before scheduling", {
7588
7536
  job
7589
7537
  });
@@ -7741,7 +7689,7 @@ var runBoundedRepair = async (input) => {
7741
7689
  phaseResult
7742
7690
  };
7743
7691
  }
7744
- if (!sameRevision4(current.base, input.candidate.base) || !sameRevision4(current.head, phaseResult.head) || current.briefHash !== input.brief.hash) {
7692
+ if (!sameRevision(current.base, input.candidate.base) || !sameRevision(current.head, phaseResult.head) || current.briefHash !== input.brief.hash) {
7745
7693
  return {
7746
7694
  outcome: "blocked",
7747
7695
  reason: "Repair candidate changed while the repair was running",
@@ -7824,14 +7772,6 @@ var uniqueAxes = (values, path2) => {
7824
7772
  }
7825
7773
  return axes;
7826
7774
  };
7827
- var sameRevision5 = (left, right) => left.branch === right.branch && left.sha === right.sha;
7828
- var deepFreeze2 = (value) => {
7829
- if (typeof value !== "object" || value === null) return value;
7830
- for (const child of Object.values(value)) {
7831
- deepFreeze2(child);
7832
- }
7833
- return Object.freeze(value);
7834
- };
7835
7775
  var normalizeFinding = (value, index) => ({
7836
7776
  id: nonEmpty(value.id, `findings[${index}].id`),
7837
7777
  severity: enumValue2(
@@ -7871,7 +7811,7 @@ var deduplicateFindings = (findings) => {
7871
7811
  return [...byKey.values()];
7872
7812
  };
7873
7813
  var blockingFinding2 = (finding) => finding.severity !== "info" && (finding.disposition === "open" || finding.disposition === "deferred");
7874
- var candidateIsStale = (expected, current) => !sameRevision5(expected.base, current.base) || !sameRevision5(expected.head, current.head) || expected.brief.hash !== current.briefHash;
7814
+ var candidateIsStale = (expected, current) => !sameRevision(expected.base, current.base) || !sameRevision(expected.head, current.head) || expected.brief.hash !== current.briefHash;
7875
7815
  var reviewEvidence = (candidate, outcome, axes, findings) => ({
7876
7816
  outcome,
7877
7817
  axes,
@@ -7906,10 +7846,10 @@ var runIndependentReview = async (options) => {
7906
7846
  if (policy.repository !== brief.identity.repository) {
7907
7847
  throw new Error("Review policy repository does not match the brief");
7908
7848
  }
7909
- if (!sameRevision5(brief.base, options.candidate.base)) {
7849
+ if (!sameRevision(brief.base, options.candidate.base)) {
7910
7850
  throw new Error("Review base does not match the brief base");
7911
7851
  }
7912
- candidate = deepFreeze2({
7852
+ candidate = deepFreeze({
7913
7853
  ...options.candidate,
7914
7854
  brief,
7915
7855
  policy
@@ -7958,7 +7898,7 @@ var runIndependentReview = async (options) => {
7958
7898
  let response;
7959
7899
  try {
7960
7900
  response = await options.provider.review(
7961
- deepFreeze2({
7901
+ deepFreeze({
7962
7902
  candidate,
7963
7903
  checkout: {
7964
7904
  base: candidate.base,