/** * Sandbox image build and status support. * * The image is built on demand via /sandbox-build from a bundled Dockerfile. * No automatic build during install; publishing a prebuilt OCI image can be * added later without redesigning the extension. */ import path from "node:path"; import { fileURLToPath } from "node:url"; import { checkDockerAvailable, dockerCommand, imageExists } from "./docker.ts"; import { IMAGE_TAG } from "./types.ts"; /** Resolve the bundled Dockerfile directory (image/ next to this package). */ export function resolveDockerfileDir(): string { const thisFile = fileURLToPath(import.meta.url); // .../extensions/docker-sandbox/image.ts -> package root image/ return path.resolve(path.dirname(thisFile), "..", "..", "image"); } /** Build (or rebuild) the sandbox image from the bundled Dockerfile. */ export async function buildSandboxImage( options: { tag?: string; signal?: AbortSignal; onStatus?: (line: string) => void }, ): Promise<{ tag: string }> { const tag = options.tag ?? IMAGE_TAG; const dockerfileDir = resolveDockerfileDir(); const args = ["build", "-t", tag, dockerfileDir]; await dockerCommand(args, { signal: options.signal, timeoutMs: 600_000 }); options.onStatus?.(`Built ${tag}`); return { tag }; } /** Full status report for /sandbox-status. */ export interface SandboxStatus { cliAvailable: boolean; daemonAvailable: boolean; dockerVersion?: string; imageExists: boolean; imageTag: string; ready: boolean; } /** Produce a status report and a remediation message when not ready. */ export async function getSandboxStatus(): Promise { const docker = await checkDockerAvailable(); const image = docker.daemon ? await imageExists(IMAGE_TAG) : false; const ready = docker.cli && docker.daemon && image; return { cliAvailable: docker.cli, daemonAvailable: docker.daemon, dockerVersion: docker.version, imageExists: image, imageTag: IMAGE_TAG, ready, }; } /** Build a human-readable status block for /sandbox-status. */ export function formatStatus(status: SandboxStatus): string { const lines: string[] = []; lines.push(`Docker CLI: ${status.cliAvailable ? "OK" : "MISSING"}`); lines.push(`Docker daemon: ${status.daemonAvailable ? "OK" : "NOT REACHABLE"}`); if (status.dockerVersion) lines.push(`Docker server version: ${status.dockerVersion}`); lines.push(`Sandbox image (${status.imageTag}): ${status.imageExists ? "present" : "missing"}`); if (!status.ready) { lines.push(""); lines.push("Not ready. To fix:"); if (!status.cliAvailable) { lines.push(" - Install Docker CLI and make sure `docker` is on PATH."); } if (status.cliAvailable && !status.daemonAvailable) { lines.push(" - Start the Docker daemon (Docker Desktop / dockerd) and check permissions."); } if (status.daemonAvailable && !status.imageExists) { lines.push(` - Run /sandbox-build to build the ${status.imageTag} image.`); } } return lines.join("\n"); }