@ai-hero/sandcastle 0.6.6 → 0.7.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.
- package/README.md +14 -8
- package/dist/{chunk-Q5W3WQVU.js → chunk-52CIJF45.js} +3 -3
- package/dist/{chunk-Q5W3WQVU.js.map → chunk-52CIJF45.js.map} +1 -1
- package/dist/{chunk-Z7O2WNRU.js → chunk-5VM5QZ26.js} +59 -5
- package/dist/{chunk-Z7O2WNRU.js.map → chunk-5VM5QZ26.js.map} +1 -1
- package/dist/{chunk-UPDEQ2U7.js → chunk-NSFQW6ML.js} +3 -3
- package/dist/{chunk-UPDEQ2U7.js.map → chunk-NSFQW6ML.js.map} +1 -1
- package/dist/index.js +2 -2
- package/dist/main.js +122 -29
- package/dist/main.js.map +1 -1
- package/dist/sandboxes/docker.js +2 -2
- package/dist/sandboxes/podman.js +2 -2
- package/dist/templates/sequential-reviewer/implement-prompt.md +2 -2
- package/dist/templates/simple-loop/prompt.md +2 -2
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
|
-
import { Effect_exports, resolveUserMounts, processFileMountParents, defaultImageName, registerShutdown, DockerError, formatVolumeMount } from './chunk-
|
|
2
|
+
import { Effect_exports, resolveUserMounts, processFileMountParents, defaultImageName, registerShutdown, DockerError, formatVolumeMount } from './chunk-5VM5QZ26.js';
|
|
3
3
|
import { createBindMountSandboxProvider } from './chunk-BIWNFKGV.js';
|
|
4
4
|
import { MAX_TAIL_CHARS, BoundedTail } from './chunk-NGBM7T3E.js';
|
|
5
5
|
import { execFile, execFileSync, spawn } from 'child_process';
|
|
@@ -358,5 +358,5 @@ var checkImageUid = (imageName, expectedUid) => new Promise((resolve2, reject) =
|
|
|
358
358
|
});
|
|
359
359
|
|
|
360
360
|
export { buildImage, docker, removeImage };
|
|
361
|
-
//# sourceMappingURL=chunk-
|
|
362
|
-
//# sourceMappingURL=chunk-
|
|
361
|
+
//# sourceMappingURL=chunk-NSFQW6ML.js.map
|
|
362
|
+
//# sourceMappingURL=chunk-NSFQW6ML.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/DockerLifecycle.ts","../src/sandboxes/docker.ts"],"names":["resolve","execFile"],"mappings":"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","file":"chunk-UPDEQ2U7.js","sourcesContent":["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 sandcastle 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 .sandcastle/ 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 /**\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\n yield* dockerExec([\n \"run\",\n \"-d\",\n \"--name\",\n containerName,\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","/**\n * Docker sandbox provider — wraps DockerLifecycle into a SandboxProvider.\n *\n * Usage:\n * import { docker } from \"sandcastle/sandboxes/docker\";\n * await run({ agent: claudeCode(\"claude-opus-4-7\"), 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 { createInterface } from \"node:readline\";\nimport { Effect } from \"effect\";\nimport { startContainer, removeContainer } from \"../DockerLifecycle.js\";\nimport {\n createBindMountSandboxProvider,\n type SandboxProvider,\n type BindMountCreateOptions,\n type BindMountSandboxHandle,\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 processFileMountParents,\n} from \"../mountUtils.js\";\nimport { BoundedTail, MAX_TAIL_CHARS } from \"../boundedTail.js\";\nimport { registerShutdown } from \"../shutdownRegistry.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 bind-mounts\n * for the worktree and git directories.\n */\nexport const docker = (options?: DockerOptions): SandboxProvider => {\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 // 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 createBindMountSandboxProvider({\n name: \"docker\",\n env: options?.env,\n sandboxHomedir,\n create: async (\n createOptions: BindMountCreateOptions,\n ): Promise<BindMountSandboxHandle> => {\n const containerName = `sandcastle-${randomUUID()}`;\n\n const worktreePath =\n createOptions.mounts.find(\n (m) => m.hostPath === createOptions.worktreePath,\n )?.sandboxPath ?? \"/home/agent/workspace\";\n\n // Build volume mount list (internal mounts + user-provided mounts)\n const allMounts = [...createOptions.mounts, ...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 ?? defaultImageName(createOptions.hostRepoPath);\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 },\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: BindMountSandboxHandle = {\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 },\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 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 if (opts?.onLine) {\n const onLine = opts.onLine;\n const stdoutTail = new BoundedTail(maxOutputTailChars, \"\\n\");\n const stderrTail = new BoundedTail(maxOutputTailChars, \"\");\n const rl = createInterface({ input: proc.stdout! });\n rl.on(\"line\", (line) => {\n stdoutTail.push(line);\n onLine(line);\n });\n proc.stderr!.on(\"data\", (chunk: Buffer) => {\n stderrTail.push(chunk.toString());\n });\n proc.on(\"close\", (code) => {\n resolve({\n stdout: stdoutTail.toString(),\n stderr: stderrTail.toString(),\n exitCode: code ?? 0,\n });\n });\n } else {\n const stdoutChunks: string[] = [];\n const stderrChunks: string[] = [];\n proc.stdout!.on(\"data\", (chunk: Buffer) => {\n stdoutChunks.push(chunk.toString());\n });\n proc.stderr!.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk.toString());\n });\n proc.on(\"close\", (code) => {\n resolve({\n stdout: stdoutChunks.join(\"\"),\n stderr: stderrChunks.join(\"\"),\n exitCode: code ?? 0,\n });\n });\n }\n });\n },\n\n interactiveExec: (\n args: string[],\n opts: InteractiveExecOptions,\n ): Promise<{ exitCode: number }> => {\n return new Promise((resolve, reject) => {\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(containerName, ...args);\n\n const proc = spawn(\"docker\", dockerArgs, {\n stdio: [opts.stdin, opts.stdout, opts.stderr] as StdioOptions,\n });\n\n proc.on(\"error\", (error: Error) => {\n reject(new Error(`docker exec failed: ${error.message}`));\n });\n\n proc.on(\"close\", (code: number | null) => {\n resolve({ exitCode: code ?? 0 });\n });\n });\n },\n\n copyFileIn: (hostPath: string, sandboxPath: string): Promise<void> =>\n new Promise((resolve, reject) => {\n execFile(\n \"docker\",\n [\"cp\", hostPath, `${containerName}:${sandboxPath}`],\n (error) => {\n if (error) {\n reject(new Error(`docker cp (in) failed: ${error.message}`));\n } else {\n resolve();\n }\n },\n );\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 'sandcastle 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 'sandcastle 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/DockerLifecycle.ts","../src/sandboxes/docker.ts"],"names":["resolve","execFile"],"mappings":"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","file":"chunk-NSFQW6ML.js","sourcesContent":["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 sandcastle 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 .sandcastle/ 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 /**\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\n yield* dockerExec([\n \"run\",\n \"-d\",\n \"--name\",\n containerName,\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","/**\n * Docker sandbox provider — wraps DockerLifecycle into a SandboxProvider.\n *\n * Usage:\n * import { docker } from \"sandcastle/sandboxes/docker\";\n * await run({ agent: claudeCode(\"claude-opus-4-7\"), 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 { createInterface } from \"node:readline\";\nimport { Effect } from \"effect\";\nimport { startContainer, removeContainer } from \"../DockerLifecycle.js\";\nimport {\n createBindMountSandboxProvider,\n type SandboxProvider,\n type BindMountCreateOptions,\n type BindMountSandboxHandle,\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 processFileMountParents,\n} from \"../mountUtils.js\";\nimport { BoundedTail, MAX_TAIL_CHARS } from \"../boundedTail.js\";\nimport { registerShutdown } from \"../shutdownRegistry.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 bind-mounts\n * for the worktree and git directories.\n */\nexport const docker = (options?: DockerOptions): SandboxProvider => {\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 // 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 createBindMountSandboxProvider({\n name: \"docker\",\n env: options?.env,\n sandboxHomedir,\n create: async (\n createOptions: BindMountCreateOptions,\n ): Promise<BindMountSandboxHandle> => {\n const containerName = `sandcastle-${randomUUID()}`;\n\n const worktreePath =\n createOptions.mounts.find(\n (m) => m.hostPath === createOptions.worktreePath,\n )?.sandboxPath ?? \"/home/agent/workspace\";\n\n // Build volume mount list (internal mounts + user-provided mounts)\n const allMounts = [...createOptions.mounts, ...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 ?? defaultImageName(createOptions.hostRepoPath);\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 },\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: BindMountSandboxHandle = {\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 },\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 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 if (opts?.onLine) {\n const onLine = opts.onLine;\n const stdoutTail = new BoundedTail(maxOutputTailChars, \"\\n\");\n const stderrTail = new BoundedTail(maxOutputTailChars, \"\");\n const rl = createInterface({ input: proc.stdout! });\n rl.on(\"line\", (line) => {\n stdoutTail.push(line);\n onLine(line);\n });\n proc.stderr!.on(\"data\", (chunk: Buffer) => {\n stderrTail.push(chunk.toString());\n });\n proc.on(\"close\", (code) => {\n resolve({\n stdout: stdoutTail.toString(),\n stderr: stderrTail.toString(),\n exitCode: code ?? 0,\n });\n });\n } else {\n const stdoutChunks: string[] = [];\n const stderrChunks: string[] = [];\n proc.stdout!.on(\"data\", (chunk: Buffer) => {\n stdoutChunks.push(chunk.toString());\n });\n proc.stderr!.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk.toString());\n });\n proc.on(\"close\", (code) => {\n resolve({\n stdout: stdoutChunks.join(\"\"),\n stderr: stderrChunks.join(\"\"),\n exitCode: code ?? 0,\n });\n });\n }\n });\n },\n\n interactiveExec: (\n args: string[],\n opts: InteractiveExecOptions,\n ): Promise<{ exitCode: number }> => {\n return new Promise((resolve, reject) => {\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(containerName, ...args);\n\n const proc = spawn(\"docker\", dockerArgs, {\n stdio: [opts.stdin, opts.stdout, opts.stderr] as StdioOptions,\n });\n\n proc.on(\"error\", (error: Error) => {\n reject(new Error(`docker exec failed: ${error.message}`));\n });\n\n proc.on(\"close\", (code: number | null) => {\n resolve({ exitCode: code ?? 0 });\n });\n });\n },\n\n copyFileIn: (hostPath: string, sandboxPath: string): Promise<void> =>\n new Promise((resolve, reject) => {\n execFile(\n \"docker\",\n [\"cp\", hostPath, `${containerName}:${sandboxPath}`],\n (error) => {\n if (error) {\n reject(new Error(`docker cp (in) failed: ${error.message}`));\n } else {\n resolve();\n }\n },\n );\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 'sandcastle 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 'sandcastle 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.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
|
-
import { NodeContext_exports, NodeFileSystem_exports, formatErrorMessage } from './chunk-
|
|
3
|
-
import { Context_exports, CwdError, Effect_exports, resolveCwd, getCurrentBranch, generateTempBranchName, Layer_exports, FileDisplay, ClackDisplay, WorktreeDockerSandboxFactory, SandboxConfig, Display, pruneStale, create, copyToWorktree, runHostHooks, startSandbox, resolveGitMounts, SANDBOX_REPO_DIR, remove, makeSandboxFromHandle, syncOut, withSandboxLifecycle, hasUncommittedChanges, patchGitMountsForWindows, registerShutdown, SandboxFactory, PromptError, FileSystem_exports, SessionCaptureError, Clock_exports, Duration_exports, Option_exports, PromptExpansionTimeoutError, Deferred_exports, AgentError, Ref_exports, SilentDisplay, AgentIdleTimeoutError, Fiber_exports } from './chunk-
|
|
2
|
+
import { NodeContext_exports, NodeFileSystem_exports, formatErrorMessage } from './chunk-52CIJF45.js';
|
|
3
|
+
import { Context_exports, CwdError, Effect_exports, resolveCwd, getCurrentBranch, generateTempBranchName, Layer_exports, FileDisplay, ClackDisplay, WorktreeDockerSandboxFactory, SandboxConfig, Display, pruneStale, create, copyToWorktree, runHostHooks, startSandbox, resolveGitMounts, SANDBOX_REPO_DIR, remove, makeSandboxFromHandle, syncOut, withSandboxLifecycle, hasUncommittedChanges, patchGitMountsForWindows, registerShutdown, SandboxFactory, PromptError, FileSystem_exports, SessionCaptureError, Clock_exports, Duration_exports, Option_exports, PromptExpansionTimeoutError, Deferred_exports, AgentError, Ref_exports, SilentDisplay, AgentIdleTimeoutError, Fiber_exports } from './chunk-5VM5QZ26.js';
|
|
4
4
|
export { createBindMountSandboxProvider, createIsolatedSandboxProvider } from './chunk-BIWNFKGV.js';
|
|
5
5
|
import { noSandbox } from './chunk-72UVAC7B.js';
|
|
6
6
|
import './chunk-NGBM7T3E.js';
|
package/dist/main.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { NodeContext_exports, withFriendlyErrors, NodeRuntime_exports } from './chunk-
|
|
4
|
-
import { buildImage, removeImage } from './chunk-
|
|
5
|
-
import { CommitPrototype, dual, GenericTag, fromIterable, failSync, map2, reduce, Effect_exports, Display, InitError, Layer_exports, ClackDisplay, decode, mapError, TreeFormatter, empty, none, flatMap3, catchAll, match, fail2 as fail2$1, map3, merge, some, right, left, isNonEmptyReadonlyArray, headNonEmpty, tailNonEmpty, isArray, identity, fromIterable2, fromIterable3, globalValue, contextWithEffect, getOrElse, getOption, appendAll, matchEffect, unify, catchSome, zipRight, matchLeft, defaultImageName, SANDBOX_REPO_DIR, FileSystem_exports, ConfigDirError, pipe, zipLeft, log, succeed, isOption, make4, update, repeatN, get2, getSomes, map, zipWith, make3, as, prepend, make, isEmpty, empty2, isEmptyReadonlyArray, of, catchTag, isTagged, die, isConfigError, isMissingDataOnly, filterMap, get, every, mapBoth, zip, forEach, _void, orElse, match2, join as join$1, isConfig, isObject, toStringUnknown, isSome, getOrThrow, FileSystem, try_, flatMap2, unsafeGet, drop, splitAt, tap, take, isQuitException, reduceRight, withMinimumLogLevel, error, PodmanError, mapInput, boolean, sort, contains, append, fromNullable, catchTags, when, set, pipeArguments, head, make10 as make10$1, suspend, get4, allocate, gen, updateAndGet, span, some2, sync, orElse2, has, filter, is, decodeUnknown, String$, fromString, make7 as make7$1, orElseFail, orDie, compose, NumberFromString, Int, Date$, findFirst, allLevels, updateEffect, flatten, fnUntraced, Terminal, QuitException, scoped, isNone, Literal, unlessEffect, asVoid, catchIf, runSync, of2, match3, filterOrDieMessage, Path, filter2, isEffect, taggedEnum, round, ensuring, cons, dieMessage, value, when2, orElse3, isNil, matchRight, symbol2, symbol, cached, findFirstIndex, flatMap, findLast, equals, combine, hash, string, string2, provide, provideServiceEffect, provideService, int } from './chunk-
|
|
3
|
+
import { NodeContext_exports, withFriendlyErrors, NodeRuntime_exports } from './chunk-52CIJF45.js';
|
|
4
|
+
import { buildImage, removeImage } from './chunk-NSFQW6ML.js';
|
|
5
|
+
import { CommitPrototype, dual, GenericTag, fromIterable, failSync, map2, reduce, Effect_exports, Display, InitError, Layer_exports, ClackDisplay, decode, mapError, TreeFormatter, empty, none, flatMap3, catchAll, match, fail2 as fail2$1, map3, merge, some, right, left, isNonEmptyReadonlyArray, headNonEmpty, tailNonEmpty, isArray, identity, fromIterable2, fromIterable3, globalValue, contextWithEffect, getOrElse, getOption, appendAll, matchEffect, unify, catchSome, zipRight, matchLeft, defaultImageName, Option_exports, SANDBOX_REPO_DIR, FileSystem_exports, ConfigDirError, pipe, zipLeft, log, succeed, isOption, make4, update, repeatN, get2, getSomes, map, zipWith, make3, as, prepend, make, isEmpty, empty2, isEmptyReadonlyArray, of, catchTag, isTagged, die, isConfigError, isMissingDataOnly, filterMap, get, every, mapBoth, zip, forEach, _void, orElse, match2, join as join$1, isConfig, isObject, toStringUnknown, isSome, getOrThrow, FileSystem, try_, flatMap2, unsafeGet, drop, splitAt, tap, take, isQuitException, reduceRight, withMinimumLogLevel, error, PodmanError, mapInput, boolean, sort, contains, append, fromNullable, catchTags, when, set, pipeArguments, head, make10 as make10$1, suspend, get4, allocate, gen, updateAndGet, span, some2, sync, orElse2, has, filter, is, decodeUnknown, String$, fromString, make7 as make7$1, orElseFail, orDie, compose, NumberFromString, Int, Date$, findFirst, allLevels, updateEffect, flatten, fnUntraced, Terminal, QuitException, scoped, isNone, Literal, unlessEffect, asVoid, catchIf, runSync, of2, match3, filterOrDieMessage, Path, filter2, isEffect, taggedEnum, round, ensuring, cons, dieMessage, value, when2, orElse3, isNil, matchRight, symbol2, symbol, cached, findFirstIndex, flatMap, findLast, equals, combine, hash, string, string2, provide, provideServiceEffect, provideService, int } from './chunk-5VM5QZ26.js';
|
|
6
6
|
import './chunk-BIWNFKGV.js';
|
|
7
7
|
import { __commonJS, __require, __toESM, __export } from './chunk-NGBM7T3E.js';
|
|
8
8
|
import * as clack from '@clack/prompts';
|
|
@@ -18799,7 +18799,7 @@ var scaffold = (repoDir, options3) => Effect_exports.gen(function* () {
|
|
|
18799
18799
|
}
|
|
18800
18800
|
return { mainFilename };
|
|
18801
18801
|
});
|
|
18802
|
-
var VERSION = "0.
|
|
18802
|
+
var VERSION = "0.7.0" ;
|
|
18803
18803
|
|
|
18804
18804
|
// src/cli.ts
|
|
18805
18805
|
var imageNameOption = Options_exports.text("image-name").pipe(
|
|
@@ -18847,6 +18847,37 @@ var sandboxOption = Options_exports.text("sandbox").pipe(
|
|
|
18847
18847
|
Options_exports.withDescription("Sandbox provider to use (e.g. docker, podman)"),
|
|
18848
18848
|
Options_exports.optional
|
|
18849
18849
|
);
|
|
18850
|
+
var issueTrackerOption = Options_exports.text("issue-tracker").pipe(
|
|
18851
|
+
Options_exports.withDescription(
|
|
18852
|
+
"Issue tracker to use (e.g. github-issues, beads, custom)"
|
|
18853
|
+
),
|
|
18854
|
+
Options_exports.optional
|
|
18855
|
+
);
|
|
18856
|
+
var createLabelOption = Options_exports.choice("create-label", [
|
|
18857
|
+
"true",
|
|
18858
|
+
"false"
|
|
18859
|
+
]).pipe(
|
|
18860
|
+
Options_exports.withDescription(
|
|
18861
|
+
'Whether to create the "Sandcastle" GitHub label (only meaningful with --issue-tracker github-issues)'
|
|
18862
|
+
),
|
|
18863
|
+
Options_exports.optional
|
|
18864
|
+
);
|
|
18865
|
+
var buildImageOption = Options_exports.choice("build-image", ["true", "false"]).pipe(
|
|
18866
|
+
Options_exports.withDescription(
|
|
18867
|
+
"Whether to build the sandbox image now (ignored when --issue-tracker custom is selected)"
|
|
18868
|
+
),
|
|
18869
|
+
Options_exports.optional
|
|
18870
|
+
);
|
|
18871
|
+
var installTemplateDepsOption = Options_exports.choice("install-template-deps", [
|
|
18872
|
+
"true",
|
|
18873
|
+
"false"
|
|
18874
|
+
]).pipe(
|
|
18875
|
+
Options_exports.withDescription(
|
|
18876
|
+
"Whether to install the template's host dependencies (e.g. zod for the planner templates)"
|
|
18877
|
+
),
|
|
18878
|
+
Options_exports.optional
|
|
18879
|
+
);
|
|
18880
|
+
var choiceToTriBool = (opt) => opt._tag === "Some" ? Option_exports.some(opt.value === "true") : Option_exports.none();
|
|
18850
18881
|
var initCommand = Command_exports.make(
|
|
18851
18882
|
"init",
|
|
18852
18883
|
{
|
|
@@ -18854,14 +18885,22 @@ var initCommand = Command_exports.make(
|
|
|
18854
18885
|
template: templateOption,
|
|
18855
18886
|
agent: agentOption,
|
|
18856
18887
|
model: initModelOption,
|
|
18857
|
-
sandbox: sandboxOption
|
|
18888
|
+
sandbox: sandboxOption,
|
|
18889
|
+
issueTracker: issueTrackerOption,
|
|
18890
|
+
createLabel: createLabelOption,
|
|
18891
|
+
buildImage: buildImageOption,
|
|
18892
|
+
installTemplateDeps: installTemplateDepsOption
|
|
18858
18893
|
},
|
|
18859
18894
|
({
|
|
18860
18895
|
imageName: imageNameFlag,
|
|
18861
18896
|
template,
|
|
18862
18897
|
agent: agentFlag,
|
|
18863
18898
|
model: modelFlag,
|
|
18864
|
-
sandbox: sandboxFlag
|
|
18899
|
+
sandbox: sandboxFlag,
|
|
18900
|
+
issueTracker: issueTrackerFlag,
|
|
18901
|
+
createLabel: createLabelFlag,
|
|
18902
|
+
buildImage: buildImageFlag,
|
|
18903
|
+
installTemplateDeps: installTemplateDepsFlag
|
|
18865
18904
|
}) => Effect_exports.gen(function* () {
|
|
18866
18905
|
const d = yield* Display;
|
|
18867
18906
|
const cwd = process.cwd();
|
|
@@ -18889,6 +18928,46 @@ var initCommand = Command_exports.make(
|
|
|
18889
18928
|
);
|
|
18890
18929
|
}
|
|
18891
18930
|
}
|
|
18931
|
+
if (issueTrackerFlag._tag === "Some") {
|
|
18932
|
+
const valid = getIssueTracker(issueTrackerFlag.value);
|
|
18933
|
+
if (!valid) {
|
|
18934
|
+
const names = listIssueTrackers().map((t) => t.name).join(", ");
|
|
18935
|
+
yield* Effect_exports.fail(
|
|
18936
|
+
new InitError({
|
|
18937
|
+
message: `Unknown issue tracker "${issueTrackerFlag.value}". Available: ${names}`
|
|
18938
|
+
})
|
|
18939
|
+
);
|
|
18940
|
+
}
|
|
18941
|
+
}
|
|
18942
|
+
const createLabelChoice = choiceToTriBool(createLabelFlag);
|
|
18943
|
+
const buildImageChoice = choiceToTriBool(buildImageFlag);
|
|
18944
|
+
const installTemplateDepsChoice = choiceToTriBool(
|
|
18945
|
+
installTemplateDepsFlag
|
|
18946
|
+
);
|
|
18947
|
+
const isInteractive = process.stdin.isTTY === true;
|
|
18948
|
+
const failIfNonInteractive = (flag) => Effect_exports.fail(
|
|
18949
|
+
new InitError({
|
|
18950
|
+
message: `${flag} is required in non-interactive mode (no TTY detected).`
|
|
18951
|
+
})
|
|
18952
|
+
);
|
|
18953
|
+
const resolveConfirmFlag = (params) => Effect_exports.gen(function* () {
|
|
18954
|
+
if (params.choice._tag === "Some") return params.choice.value;
|
|
18955
|
+
if (!isInteractive) {
|
|
18956
|
+
yield* failIfNonInteractive(params.flag);
|
|
18957
|
+
}
|
|
18958
|
+
const confirmed = yield* Effect_exports.promise(
|
|
18959
|
+
() => clack.confirm({
|
|
18960
|
+
message: params.promptMessage,
|
|
18961
|
+
initialValue: true
|
|
18962
|
+
})
|
|
18963
|
+
);
|
|
18964
|
+
if (clack.isCancel(confirmed)) {
|
|
18965
|
+
yield* Effect_exports.fail(
|
|
18966
|
+
new InitError({ message: params.cancelMessage })
|
|
18967
|
+
);
|
|
18968
|
+
}
|
|
18969
|
+
return confirmed === true;
|
|
18970
|
+
});
|
|
18892
18971
|
const agents = listAgents();
|
|
18893
18972
|
let selectedAgent;
|
|
18894
18973
|
if (agentFlag._tag === "Some") {
|
|
@@ -18903,6 +18982,9 @@ var initCommand = Command_exports.make(
|
|
|
18903
18982
|
}
|
|
18904
18983
|
selectedAgent = entry;
|
|
18905
18984
|
} else {
|
|
18985
|
+
if (!isInteractive) {
|
|
18986
|
+
yield* failIfNonInteractive("--agent");
|
|
18987
|
+
}
|
|
18906
18988
|
const selected = yield* Effect_exports.promise(
|
|
18907
18989
|
() => clack.select({
|
|
18908
18990
|
message: "Select an agent:",
|
|
@@ -18927,6 +19009,9 @@ var initCommand = Command_exports.make(
|
|
|
18927
19009
|
if (sandboxFlag._tag === "Some") {
|
|
18928
19010
|
selectedSandboxProvider = getSandboxProvider(sandboxFlag.value);
|
|
18929
19011
|
} else {
|
|
19012
|
+
if (!isInteractive) {
|
|
19013
|
+
yield* failIfNonInteractive("--sandbox");
|
|
19014
|
+
}
|
|
18930
19015
|
const selected = yield* Effect_exports.promise(
|
|
18931
19016
|
() => clack.select({
|
|
18932
19017
|
message: "Select a sandbox provider:",
|
|
@@ -18947,7 +19032,12 @@ var initCommand = Command_exports.make(
|
|
|
18947
19032
|
}
|
|
18948
19033
|
const issueTrackers = listIssueTrackers();
|
|
18949
19034
|
let selectedIssueTracker;
|
|
18950
|
-
{
|
|
19035
|
+
if (issueTrackerFlag._tag === "Some") {
|
|
19036
|
+
selectedIssueTracker = getIssueTracker(issueTrackerFlag.value);
|
|
19037
|
+
} else {
|
|
19038
|
+
if (!isInteractive) {
|
|
19039
|
+
yield* failIfNonInteractive("--issue-tracker");
|
|
19040
|
+
}
|
|
18951
19041
|
const selected = yield* Effect_exports.promise(
|
|
18952
19042
|
() => clack.select({
|
|
18953
19043
|
message: "Select an issue tracker:",
|
|
@@ -18971,6 +19061,9 @@ var initCommand = Command_exports.make(
|
|
|
18971
19061
|
if (template._tag === "Some") {
|
|
18972
19062
|
selectedTemplate = template.value;
|
|
18973
19063
|
} else {
|
|
19064
|
+
if (!isInteractive) {
|
|
19065
|
+
yield* failIfNonInteractive("--template");
|
|
19066
|
+
}
|
|
18974
19067
|
const selected = yield* Effect_exports.promise(
|
|
18975
19068
|
() => clack.select({
|
|
18976
19069
|
message: "Select a template:",
|
|
@@ -18991,13 +19084,13 @@ var initCommand = Command_exports.make(
|
|
|
18991
19084
|
}
|
|
18992
19085
|
let shouldCreateLabel = false;
|
|
18993
19086
|
if (selectedIssueTracker.name === "github-issues") {
|
|
18994
|
-
shouldCreateLabel = yield*
|
|
18995
|
-
|
|
18996
|
-
|
|
18997
|
-
|
|
18998
|
-
|
|
18999
|
-
);
|
|
19000
|
-
if (shouldCreateLabel
|
|
19087
|
+
shouldCreateLabel = yield* resolveConfirmFlag({
|
|
19088
|
+
choice: createLabelChoice,
|
|
19089
|
+
flag: "--create-label",
|
|
19090
|
+
promptMessage: 'Create a "Sandcastle" GitHub label? (Templates filter issues by this label)',
|
|
19091
|
+
cancelMessage: "Label selection cancelled."
|
|
19092
|
+
});
|
|
19093
|
+
if (shouldCreateLabel) {
|
|
19001
19094
|
yield* Effect_exports.try({
|
|
19002
19095
|
try: () => execSync(
|
|
19003
19096
|
'gh label create "Sandcastle" --description "Issues for Sandcastle to work on" --color "F9A825" 2>/dev/null',
|
|
@@ -19013,7 +19106,7 @@ var initCommand = Command_exports.make(
|
|
|
19013
19106
|
agent: selectedAgent,
|
|
19014
19107
|
model: selectedModel,
|
|
19015
19108
|
templateName: selectedTemplate,
|
|
19016
|
-
createLabel: shouldCreateLabel
|
|
19109
|
+
createLabel: shouldCreateLabel,
|
|
19017
19110
|
issueTracker: selectedIssueTracker,
|
|
19018
19111
|
sandboxProvider: selectedSandboxProvider
|
|
19019
19112
|
}).pipe(
|
|
@@ -19029,13 +19122,13 @@ var initCommand = Command_exports.make(
|
|
|
19029
19122
|
const alreadyInstalled = yield* hostHasDependency(cwd, "zod");
|
|
19030
19123
|
if (!alreadyInstalled) {
|
|
19031
19124
|
const installCmd = addDependencyCommand(packageManager, "zod");
|
|
19032
|
-
const shouldInstall = yield*
|
|
19033
|
-
|
|
19034
|
-
|
|
19035
|
-
|
|
19036
|
-
|
|
19037
|
-
);
|
|
19038
|
-
if (shouldInstall
|
|
19125
|
+
const shouldInstall = yield* resolveConfirmFlag({
|
|
19126
|
+
choice: installTemplateDepsChoice,
|
|
19127
|
+
flag: "--install-template-deps",
|
|
19128
|
+
promptMessage: `The ${selectedTemplate} template needs a schema validator. Install zod now (\`${installCmd}\`)?`,
|
|
19129
|
+
cancelMessage: "Install-template-deps selection cancelled."
|
|
19130
|
+
});
|
|
19131
|
+
if (shouldInstall) {
|
|
19039
19132
|
const installed = yield* Effect_exports.sync(() => {
|
|
19040
19133
|
try {
|
|
19041
19134
|
execSync(installCmd, { cwd, stdio: "ignore" });
|
|
@@ -19058,13 +19151,13 @@ var initCommand = Command_exports.make(
|
|
|
19058
19151
|
"success"
|
|
19059
19152
|
);
|
|
19060
19153
|
} else {
|
|
19061
|
-
const shouldBuild = yield*
|
|
19062
|
-
|
|
19063
|
-
|
|
19064
|
-
|
|
19065
|
-
|
|
19066
|
-
);
|
|
19067
|
-
if (shouldBuild
|
|
19154
|
+
const shouldBuild = yield* resolveConfirmFlag({
|
|
19155
|
+
choice: buildImageChoice,
|
|
19156
|
+
flag: "--build-image",
|
|
19157
|
+
promptMessage: `Build the default ${providerLabel} image now?`,
|
|
19158
|
+
cancelMessage: "Build-image selection cancelled."
|
|
19159
|
+
});
|
|
19160
|
+
if (shouldBuild) {
|
|
19068
19161
|
const containerfileDir = join(cwd, CONFIG_DIR);
|
|
19069
19162
|
if (selectedSandboxProvider.name === "podman") {
|
|
19070
19163
|
yield* d.spinner(
|