@anvia/sandbox 1.1.4 → 1.1.6

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 CHANGED
@@ -32,6 +32,18 @@ Networking is explicit. Use `{ mode: "none" }` or `{ mode: "bridge", ports: [...
32
32
  bind only to `127.0.0.1`. Runtime methods use object arguments, propagate abort signals, and expose
33
33
  command and process output as bytes. Tool wrappers decode UTF-8 strictly and return structured values.
34
34
 
35
+ `exec_command` accepts a complete shell command line in `command`, including pipes, redirects, and
36
+ multiline scripts. For exact argv execution without shell parsing, provide the executable in
37
+ `command` and its arguments in `args`. Command policies apply to the implicit `sh` executable when a
38
+ shell command line is used. Natural command lines are rejected with block-mode command policies
39
+ because arbitrary shell syntax cannot be checked safely against an executable block list; use exact
40
+ `command` and `args` input in that configuration.
41
+
42
+ File paths and command working directories passed to agent tools may be workspace-relative (for
43
+ example `notes/result.txt`) or absolute paths inside the sandbox workdir (for example
44
+ `/workspace/notes/result.txt` with the default workdir). Paths outside the sandbox workdir are
45
+ rejected.
46
+
35
47
  With `exec.commands.mode: "allow"`, both `exec_command` and `start_process` reject known shell
36
48
  executables by default, including path-qualified names such as `/bin/sh`. To permit an allowlisted
37
49
  shell, set `exec.commands.allowShellInterpreters` to the boolean `true`. Omitted or `false` keeps the
package/dist/cli.d.ts CHANGED
@@ -58,5 +58,6 @@ interface SandboxImageCliDependencies {
58
58
  }) => Promise<void>;
59
59
  }
60
60
  declare function runCli(argv?: string[], cwd?: string, io?: SandboxImageCliIo, dependencies?: SandboxImageCliDependencies): Promise<number>;
61
+ declare function isCliEntryPoint(moduleUrl: string, invokedPath: string | undefined): boolean;
61
62
 
62
- export { type SandboxImageCliDependencies, type SandboxImageCliIo, type SandboxImagePromptResult, runCli };
63
+ export { type SandboxImageCliDependencies, type SandboxImageCliIo, type SandboxImagePromptResult, isCliEntryPoint, runCli };
package/dist/cli.js CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  } from "./chunk-D5XZQ2ES.js";
5
5
 
6
6
  // src/cli.ts
7
+ import { realpathSync } from "fs";
7
8
  import { lstat, mkdir, readFile, rm, writeFile } from "fs/promises";
8
9
  import path from "path";
9
10
  import { fileURLToPath } from "url";
@@ -831,13 +832,21 @@ Examples:
831
832
  pnpm dlx @anvia/sandbox create-image --name reports --feature artifacts
832
833
  pnpm dlx @anvia/sandbox create-image --name browser --runtime bun --feature playwright`;
833
834
  }
834
- var invokedPath = process.argv[1] === void 0 ? void 0 : path.resolve(process.argv[1]);
835
- if (invokedPath !== void 0 && invokedPath === fileURLToPath(import.meta.url)) {
835
+ function isCliEntryPoint(moduleUrl, invokedPath) {
836
+ if (invokedPath === void 0) return false;
837
+ try {
838
+ return realpathSync(path.resolve(invokedPath)) === realpathSync(fileURLToPath(moduleUrl));
839
+ } catch {
840
+ return false;
841
+ }
842
+ }
843
+ if (isCliEntryPoint(import.meta.url, process.argv[1])) {
836
844
  runCli().then((code) => {
837
845
  process.exitCode = code;
838
846
  });
839
847
  }
840
848
  export {
849
+ isCliEntryPoint,
841
850
  runCli
842
851
  };
843
852
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/image-builder.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { lstat, mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { assertDockerCli } from \"./docker-cli\";\nimport {\n renderSandboxImageContext,\n resolveSandboxImageSpec,\n type SandboxImageFeature,\n type SandboxImageInput,\n type SandboxImageManifest,\n type SandboxImageRuntime,\n type SandboxImageVersions,\n unpinnedSandboxImagePackages,\n} from \"./image-builder\";\n\ninterface CliOptions {\n command?: string;\n name?: string;\n tag?: string;\n output?: string;\n runtimes: SandboxImageRuntime[];\n features: SandboxImageFeature[];\n apt: string[];\n npm: string[];\n uv: string[];\n versions: Partial<SandboxImageVersions>;\n dockerPath: string;\n build: boolean;\n buildExplicit: boolean;\n dryRun: boolean;\n force: boolean;\n help: boolean;\n}\n\nexport interface SandboxImageCliIo {\n log(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n stdout(chunk: Uint8Array): void;\n stderr(chunk: Uint8Array): void;\n}\n\nexport interface SandboxImagePromptResult {\n name: string;\n runtimes: SandboxImageRuntime[];\n features: SandboxImageFeature[];\n apt: string[];\n npm: string[];\n uv: string[];\n tag?: string;\n output?: string;\n build: boolean;\n}\n\nexport interface SandboxImageCliDependencies {\n isTTY?: boolean;\n packageVersion?: string;\n prompt?: (options: Readonly<CliOptions>) => Promise<SandboxImagePromptResult | undefined>;\n buildImage?: (input: {\n contextPath: string;\n tag: string;\n dockerPath: string;\n io: SandboxImageCliIo;\n }) => Promise<void>;\n}\n\nconst generatedFileNames = new Set([\n \".dockerignore\",\n \"Dockerfile\",\n \"anvia-sandbox.json\",\n \"package.json\",\n \"pyproject.toml\",\n]);\n\nconst commonAptPackages = [\n { value: \"git\", label: \"Git\", hint: \"Source control and repository operations\" },\n { value: \"curl\", label: \"curl\", hint: \"HTTP downloads and API debugging\" },\n { value: \"jq\", label: \"jq\", hint: \"JSON processing from the shell\" },\n { value: \"ffmpeg\", label: \"FFmpeg\", hint: \"Audio and video processing\" },\n { value: \"imagemagick\", label: \"ImageMagick\", hint: \"Image conversion and editing\" },\n { value: \"poppler-utils\", label: \"Poppler tools\", hint: \"PDF inspection and conversion\" },\n { value: \"libreoffice\", label: \"LibreOffice\", hint: \"Large; office document conversion\" },\n] as const;\n\nconst commonNpmPackages = [\n { value: \"pdfkit@0.19.1\", label: \"PDFKit\", hint: \"Generate PDF documents\" },\n { value: \"sharp@0.35.3\", label: \"Sharp\", hint: \"Resize and transform images\" },\n { value: \"exceljs@4.4.0\", label: \"ExcelJS\", hint: \"Read and write Excel workbooks\" },\n { value: \"docx@9.7.1\", label: \"docx\", hint: \"Generate Word documents\" },\n { value: \"pptxgenjs@4.0.1\", label: \"PptxGenJS\", hint: \"Generate PowerPoint presentations\" },\n] as const;\n\nconst commonUvPackages = [\n { value: \"httpx==0.28.1\", label: \"HTTPX\", hint: \"Modern HTTP client\" },\n { value: \"beautifulsoup4==4.15.0\", label: \"Beautiful Soup\", hint: \"HTML and XML parsing\" },\n { value: \"scipy==1.18.0\", label: \"SciPy\", hint: \"Scientific computing\" },\n { value: \"scikit-learn==1.9.0\", label: \"scikit-learn\", hint: \"Machine learning utilities\" },\n { value: \"polars==1.42.1\", label: \"Polars\", hint: \"Fast dataframe processing\" },\n] as const;\n\nconst defaultIo: SandboxImageCliIo = {\n log: console.log,\n warn: console.warn,\n error: console.error,\n stdout: (chunk) => process.stdout.write(chunk),\n stderr: (chunk) => process.stderr.write(chunk),\n};\n\nexport async function runCli(\n argv: string[] = process.argv.slice(2),\n cwd = process.cwd(),\n io: SandboxImageCliIo = defaultIo,\n dependencies: SandboxImageCliDependencies = {},\n): Promise<number> {\n let options: CliOptions;\n try {\n options = parseArgs(argv);\n } catch (error) {\n io.error(errorMessage(error));\n io.log(helpText());\n return 1;\n }\n\n if (options.help || options.command === undefined) {\n io.log(helpText());\n return 0;\n }\n if (options.command !== \"create-image\") {\n io.error(`Unknown command: ${options.command}`);\n io.log(helpText());\n return 1;\n }\n\n try {\n const shouldPrompt =\n options.name === undefined ||\n (options.runtimes.length === 0 &&\n options.features.length === 0 &&\n options.npm.length === 0 &&\n options.uv.length === 0);\n if (shouldPrompt) {\n const isTTY = dependencies.isTTY ?? (process.stdin.isTTY && process.stdout.isTTY);\n if (!isTTY) {\n throw new Error(\n \"Non-interactive create-image requires --name and at least one --runtime or --feature.\",\n );\n }\n const prompt = dependencies.prompt ?? promptForImage;\n const result = await prompt(options);\n if (result === undefined) return 130;\n options = applyPromptResult(options, result);\n }\n\n const input: SandboxImageInput = {\n name: required(options.name, \"Image name is required.\"),\n runtimes: options.runtimes,\n features: options.features,\n packages: {\n apt: options.apt,\n npm: options.npm,\n uv: options.uv,\n },\n versions: options.versions,\n };\n if (options.tag !== undefined) input.tag = options.tag;\n\n const spec = resolveSandboxImageSpec(input);\n const packageVersion = dependencies.packageVersion ?? (await readPackageVersion());\n const context = renderSandboxImageContext(spec, packageVersion);\n const outputPath = path.resolve(\n cwd,\n options.output ?? path.join(\".anvia\", \"sandbox-images\", spec.name),\n );\n const displayPath = relativeDisplayPath(cwd, outputPath);\n const unpinned = unpinnedSandboxImagePackages(spec);\n if (unpinned.length > 0) {\n io.warn(`Unpinned custom packages may change on rebuild: ${unpinned.join(\", \")}`);\n }\n\n if (options.dryRun) {\n printDryRun(context.files, displayPath, spec.tag, io);\n return 0;\n }\n\n await writeImageContext(outputPath, context.manifest, context.files, options.force);\n io.log(`Created ${displayPath}`);\n\n if (!options.build) {\n io.log(\"\");\n io.log(\"Build later:\");\n io.log(` ${shellCommand([options.dockerPath, \"build\", \"--tag\", spec.tag, displayPath])}`);\n printUsageSnippet(spec.tag, io);\n return 0;\n }\n\n const buildImage = dependencies.buildImage ?? buildDockerImage;\n await buildImage({\n contextPath: outputPath,\n tag: spec.tag,\n dockerPath: options.dockerPath,\n io,\n });\n io.log(`Built ${spec.tag}`);\n printUsageSnippet(spec.tag, io);\n return 0;\n } catch (error) {\n io.error(errorMessage(error));\n return 1;\n }\n}\n\nasync function promptForImage(\n options: Readonly<CliOptions>,\n): Promise<SandboxImagePromptResult | undefined> {\n assertInteractiveNodeVersion();\n const prompts = await import(\"@clack/prompts\");\n prompts.intro(\"Create an Anvia sandbox image\");\n\n const nameResult =\n options.name ??\n (await prompts.text({\n message: \"Image name\",\n placeholder: \"reports\",\n validate: (value) =>\n /^[a-z0-9][a-z0-9-]{0,62}$/.test(value ?? \"\")\n ? undefined\n : \"Use 1-63 lowercase letters, numbers, or hyphens.\",\n }));\n if (prompts.isCancel(nameResult)) return cancelPrompt(prompts);\n const name = promptString(nameResult, \"Image name\");\n\n let runtimes = [...options.runtimes];\n let features = [...options.features];\n if (\n runtimes.length === 0 &&\n features.length === 0 &&\n options.npm.length === 0 &&\n options.uv.length === 0\n ) {\n const capabilities = await prompts.multiselect<SandboxImageRuntime | SandboxImageFeature>({\n message: \"Select runtimes and features\",\n required: true,\n options: [\n { value: \"node\", label: \"Node.js\", hint: \"Includes npm and pnpm\" },\n { value: \"bun\", label: \"Bun\", hint: \"Includes bun and bunx\" },\n { value: \"python\", label: \"Python\", hint: \"Includes uv and uvx\" },\n { value: \"artifacts\", label: \"Reporting and artifacts\", hint: \"Adds Python automatically\" },\n { value: \"playwright\", label: \"Playwright + Chromium\", hint: \"Adds Node.js automatically\" },\n ],\n });\n if (prompts.isCancel(capabilities)) return cancelPrompt(prompts);\n runtimes = capabilities.filter(isRuntime);\n features = capabilities.filter(isFeature);\n }\n\n const aptResult = await selectCommonPackages(\n prompts,\n \"Select common apt tools (optional)\",\n commonAptPackages,\n options.apt,\n );\n if (aptResult === undefined) return cancelPrompt(prompts);\n const npmResult = await selectCommonPackages(\n prompts,\n \"Select common npm libraries (optional)\",\n commonNpmPackages,\n options.npm,\n );\n if (npmResult === undefined) return cancelPrompt(prompts);\n const uvResult = await selectCommonPackages(\n prompts,\n \"Select common Python libraries with uv (optional)\",\n commonUvPackages,\n options.uv,\n );\n if (uvResult === undefined) return cancelPrompt(prompts);\n\n const tagResult =\n options.tag ??\n (await prompts.text({\n message: \"Docker image tag\",\n initialValue: `anvia-sandbox-${name}:latest`,\n }));\n if (prompts.isCancel(tagResult)) return cancelPrompt(prompts);\n const outputResult =\n options.output ??\n (await prompts.text({\n message: \"Generated source directory\",\n initialValue: path.join(\".anvia\", \"sandbox-images\", name),\n }));\n if (prompts.isCancel(outputResult)) return cancelPrompt(prompts);\n\n const buildResult = options.buildExplicit\n ? options.build\n : await prompts.confirm({ message: \"Build the image now?\", initialValue: true });\n if (prompts.isCancel(buildResult)) return cancelPrompt(prompts);\n const confirmed = await prompts.confirm({\n message: \"Create this sandbox image?\",\n initialValue: true,\n });\n if (prompts.isCancel(confirmed) || !confirmed) return cancelPrompt(prompts);\n\n prompts.outro(\"Configuration ready\");\n return {\n name,\n runtimes,\n features,\n apt: aptResult,\n npm: npmResult,\n uv: uvResult,\n tag: promptString(tagResult, \"Docker image tag\"),\n output: promptString(outputResult, \"Generated source directory\"),\n build: promptBoolean(buildResult, \"Build selection\"),\n };\n}\n\nasync function selectCommonPackages(\n prompts: typeof import(\"@clack/prompts\"),\n message: string,\n options: readonly { value: string; label: string; hint: string }[],\n existing: readonly string[],\n): Promise<string[] | undefined> {\n const commonValues = new Set(options.map((option) => option.value));\n const result = await prompts.multiselect<string>({\n message,\n required: false,\n options: [...options],\n initialValues: existing.filter((value) => commonValues.has(value)),\n });\n if (prompts.isCancel(result)) return undefined;\n return [...new Set([...existing, ...result])];\n}\n\nfunction cancelPrompt(prompts: typeof import(\"@clack/prompts\")): undefined {\n prompts.cancel(\"Image creation cancelled.\");\n return undefined;\n}\n\nasync function buildDockerImage(input: {\n contextPath: string;\n tag: string;\n dockerPath: string;\n io: SandboxImageCliIo;\n}): Promise<void> {\n await assertDockerCli([\"build\", \"--tag\", input.tag, input.contextPath], {\n dockerPath: input.dockerPath,\n onStdout: input.io.stdout,\n onStderr: input.io.stderr,\n });\n}\n\nasync function writeImageContext(\n outputPath: string,\n manifest: SandboxImageManifest,\n files: ReadonlyMap<string, string>,\n force: boolean,\n): Promise<void> {\n const outputStat = await safeLstat(outputPath);\n if (outputStat?.isSymbolicLink()) {\n throw new Error(`Refusing to write through symlink: ${outputPath}`);\n }\n\n if (outputStat !== undefined) {\n if (!outputStat.isDirectory()) throw new Error(`Output path is not a directory: ${outputPath}`);\n const previousManifest = await readGeneratedManifest(outputPath);\n if (previousManifest === undefined) {\n throw new Error(\n `Output directory already exists but was not generated by @anvia/sandbox: ${outputPath}`,\n );\n }\n if (!force) throw new Error(`Output directory already exists. Use --force to regenerate it.`);\n\n for (const filename of previousManifest.generatedFiles) {\n const target = path.join(outputPath, filename);\n const targetStat = await safeLstat(target);\n if (targetStat?.isSymbolicLink()) throw new Error(`Refusing to replace symlink: ${target}`);\n if (targetStat !== undefined) await rm(target);\n }\n } else {\n await mkdir(outputPath, { recursive: true });\n }\n\n for (const [filename, content] of files) {\n if (!generatedFileNames.has(filename))\n throw new Error(`Unexpected generated filename: ${filename}`);\n const target = path.join(outputPath, filename);\n const targetStat = await safeLstat(target);\n if (targetStat?.isSymbolicLink()) throw new Error(`Refusing to replace symlink: ${target}`);\n await writeFile(target, content, \"utf8\");\n }\n\n if (!files.has(\"anvia-sandbox.json\") || manifest.generatedFiles.length !== files.size) {\n throw new Error(\"Generated image context manifest is inconsistent.\");\n }\n}\n\nasync function readGeneratedManifest(\n outputPath: string,\n): Promise<SandboxImageManifest | undefined> {\n const manifestPath = path.join(outputPath, \"anvia-sandbox.json\");\n const stat = await safeLstat(manifestPath);\n if (stat === undefined) return undefined;\n if (stat.isSymbolicLink() || !stat.isFile()) {\n throw new Error(`Invalid generated manifest: ${manifestPath}`);\n }\n\n let value: unknown;\n try {\n value = JSON.parse(await readFile(manifestPath, \"utf8\"));\n } catch (error) {\n throw new Error(`Unable to read generated manifest: ${manifestPath}`, { cause: error });\n }\n if (!isGeneratedManifest(value)) {\n throw new Error(\n `Output manifest is not recognized as an @anvia/sandbox manifest: ${manifestPath}`,\n );\n }\n return value;\n}\n\nfunction isGeneratedManifest(value: unknown): value is SandboxImageManifest {\n if (typeof value !== \"object\" || value === null) return false;\n const record = value as Record<string, unknown>;\n const generatedBy = record.generatedBy as Record<string, unknown> | undefined;\n const files = record.generatedFiles;\n return (\n record.schemaVersion === 1 &&\n generatedBy?.package === \"@anvia/sandbox\" &&\n Array.isArray(files) &&\n files.every((file) => typeof file === \"string\" && generatedFileNames.has(file))\n );\n}\n\nasync function safeLstat(target: string) {\n try {\n return await lstat(target);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw error;\n }\n}\n\nfunction printDryRun(\n files: ReadonlyMap<string, string>,\n outputPath: string,\n tag: string,\n io: SandboxImageCliIo,\n): void {\n io.log(`Would create ${outputPath}`);\n for (const [filename, content] of files) {\n io.log(\"\");\n io.log(`--- ${filename}`);\n io.log(content.trimEnd());\n }\n io.log(\"\");\n io.log(`Would build ${tag}`);\n}\n\nfunction printUsageSnippet(tag: string, io: SandboxImageCliIo): void {\n io.log(\"\");\n io.log(\"Use with @anvia/sandbox:\");\n io.log(' import { DockerSandboxClient } from \"@anvia/sandbox\";');\n io.log(\"\");\n io.log(\" const client = new DockerSandboxClient();\");\n io.log(\" await using sandbox = await client.createSandbox({\");\n io.log(` image: ${JSON.stringify(tag)},`);\n io.log(' workspace: { type: \"ephemeral\" },');\n io.log(' network: { mode: \"none\" },');\n io.log(\" });\");\n}\n\nfunction applyPromptResult(options: CliOptions, result: SandboxImagePromptResult): CliOptions {\n const next: CliOptions = {\n ...options,\n name: result.name,\n runtimes: result.runtimes,\n features: result.features,\n apt: result.apt,\n npm: result.npm,\n uv: result.uv,\n build: result.build,\n buildExplicit: true,\n };\n if (result.tag !== undefined) next.tag = result.tag;\n if (result.output !== undefined) next.output = result.output;\n return next;\n}\n\nfunction parseArgs(argv: string[]): CliOptions {\n const options: CliOptions = {\n runtimes: [],\n features: [],\n apt: [],\n npm: [],\n uv: [],\n versions: {},\n dockerPath: \"docker\",\n build: true,\n buildExplicit: false,\n dryRun: false,\n force: false,\n help: false,\n };\n\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index] ?? \"\";\n if (!argument.startsWith(\"-\")) {\n if (options.command !== undefined) throw new Error(`Unexpected argument: ${argument}`);\n options.command = argument;\n continue;\n }\n\n const [flag, inlineValue] = splitFlag(argument);\n const value = () => inlineValue ?? required(argv[++index], `${flag} requires a value.`);\n switch (flag) {\n case \"-h\":\n case \"--help\":\n options.help = true;\n break;\n case \"--name\":\n options.name = value();\n break;\n case \"--tag\":\n options.tag = value();\n break;\n case \"--output\":\n options.output = value();\n break;\n case \"--runtime\":\n options.runtimes.push(parseRuntime(value()));\n break;\n case \"--feature\":\n options.features.push(parseFeature(value()));\n break;\n case \"--apt\":\n options.apt.push(value());\n break;\n case \"--npm\":\n options.npm.push(value());\n break;\n case \"--uv\":\n options.uv.push(value());\n break;\n case \"--node-version\":\n options.versions.node = value();\n break;\n case \"--pnpm-version\":\n options.versions.pnpm = value();\n break;\n case \"--bun-version\":\n options.versions.bun = value();\n break;\n case \"--python-version\":\n options.versions.python = value();\n break;\n case \"--uv-version\":\n options.versions.uv = value();\n break;\n case \"--playwright-version\":\n options.versions.playwright = value();\n break;\n case \"--docker-path\":\n options.dockerPath = value();\n break;\n case \"--no-build\":\n rejectInlineValue(flag, inlineValue);\n options.build = false;\n options.buildExplicit = true;\n break;\n case \"--dry-run\":\n rejectInlineValue(flag, inlineValue);\n options.dryRun = true;\n break;\n case \"--force\":\n rejectInlineValue(flag, inlineValue);\n options.force = true;\n break;\n default:\n throw new Error(`Unknown option: ${flag}`);\n }\n }\n return options;\n}\n\nfunction splitFlag(argument: string): [string, string | undefined] {\n const separator = argument.indexOf(\"=\");\n return separator === -1\n ? [argument, undefined]\n : [argument.slice(0, separator), argument.slice(separator + 1)];\n}\n\nfunction rejectInlineValue(flag: string, value: string | undefined): void {\n if (value !== undefined) throw new Error(`${flag} does not accept a value.`);\n}\n\nfunction parseRuntime(value: string): SandboxImageRuntime {\n if (isRuntime(value)) return value;\n throw new Error(`Unknown runtime: ${value}. Expected node, bun, or python.`);\n}\n\nfunction parseFeature(value: string): SandboxImageFeature {\n if (isFeature(value)) return value;\n throw new Error(`Unknown feature: ${value}. Expected artifacts or playwright.`);\n}\n\nfunction isRuntime(value: string): value is SandboxImageRuntime {\n return value === \"node\" || value === \"bun\" || value === \"python\";\n}\n\nfunction isFeature(value: string): value is SandboxImageFeature {\n return value === \"artifacts\" || value === \"playwright\";\n}\n\nfunction assertInteractiveNodeVersion(): void {\n const [major = 0, minor = 0] = process.versions.node.split(\".\").map(Number);\n if (major < 20 || (major === 20 && minor < 12)) {\n throw new Error(\"The interactive create-image wizard requires Node.js 20.12 or newer.\");\n }\n}\n\nasync function readPackageVersion(): Promise<string> {\n const packageJson = JSON.parse(\n await readFile(new URL(\"../package.json\", import.meta.url), \"utf8\"),\n ) as {\n version?: unknown;\n };\n return typeof packageJson.version === \"string\" ? packageJson.version : \"unknown\";\n}\n\nfunction relativeDisplayPath(cwd: string, target: string): string {\n const relative = path.relative(cwd, target);\n return relative && !relative.startsWith(\"..\") ? relative : target;\n}\n\nfunction shellCommand(args: readonly string[]): string {\n return args.map(shellArgument).join(\" \");\n}\n\nfunction shellArgument(value: string): string {\n if (/^[a-zA-Z0-9_./:@+-]+$/.test(value)) return value;\n return `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n\nfunction required<T>(value: T | undefined, message: string): T {\n if (value === undefined || value === \"\") throw new Error(message);\n return value;\n}\n\nfunction promptString(value: unknown, name: string): string {\n if (typeof value !== \"string\") throw new TypeError(`${name} must be a string.`);\n return value;\n}\n\nfunction promptBoolean(value: unknown, name: string): boolean {\n if (typeof value !== \"boolean\") throw new TypeError(`${name} must be a boolean.`);\n return value;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : \"Unknown sandbox CLI error\";\n}\n\nfunction helpText(): string {\n return `Usage:\n pnpm dlx @anvia/sandbox create-image [options]\n\nOptions:\n --name <slug> Image profile name\n --runtime <node|bun|python> Runtime to include; repeatable\n --feature <artifacts|playwright>\n Curated feature to include; repeatable\n --apt <package> Additional apt package; repeatable\n --npm <package[@version]> Additional npm package; repeatable\n --uv <requirement> Additional Python package installed with uv; repeatable\n --tag <tag> Local image tag\n --output <directory> Generated context directory\n --node-version <version> Override Node.js version\n --pnpm-version <version> Override pnpm version\n --bun-version <version> Override Bun version\n --python-version <version> Override Python version\n --uv-version <version> Override uv version\n --playwright-version <version> Override Playwright and browser image version\n --docker-path <path> Docker CLI path (default: docker)\n --no-build Generate files without building\n --dry-run Print generated files without writing or building\n --force Regenerate a context previously created by this CLI\n -h, --help Show this help\n\nExamples:\n pnpm dlx @anvia/sandbox create-image\n pnpm dlx @anvia/sandbox create-image --name reports --feature artifacts\n pnpm dlx @anvia/sandbox create-image --name browser --runtime bun --feature playwright`;\n}\n\nconst invokedPath = process.argv[1] === undefined ? undefined : path.resolve(process.argv[1]);\nif (invokedPath !== undefined && invokedPath === fileURLToPath(import.meta.url)) {\n runCli().then((code) => {\n process.exitCode = code;\n });\n}\n","export type SandboxImageRuntime = \"node\" | \"bun\" | \"python\";\nexport type SandboxImageFeature = \"artifacts\" | \"playwright\";\n\nexport interface SandboxImageVersions {\n node: string;\n pnpm: string;\n bun: string;\n python: string;\n uv: string;\n playwright: string;\n}\n\nexport interface SandboxImagePackages {\n apt: string[];\n npm: string[];\n uv: string[];\n}\n\nexport interface SandboxImageInput {\n name: string;\n tag?: string;\n runtimes?: readonly SandboxImageRuntime[];\n features?: readonly SandboxImageFeature[];\n packages?: Partial<SandboxImagePackages>;\n versions?: Partial<SandboxImageVersions>;\n}\n\nexport interface SandboxImageSpec {\n name: string;\n tag: string;\n runtimes: SandboxImageRuntime[];\n features: SandboxImageFeature[];\n packages: SandboxImagePackages;\n versions: SandboxImageVersions;\n}\n\nexport interface SandboxImageManifest extends SandboxImageSpec {\n schemaVersion: 1;\n generatedBy: {\n package: \"@anvia/sandbox\";\n version: string;\n };\n generatedFiles: string[];\n}\n\nexport interface SandboxImageContext {\n manifest: SandboxImageManifest;\n files: ReadonlyMap<string, string>;\n}\n\nexport const defaultSandboxImageVersions: Readonly<SandboxImageVersions> = {\n node: \"24.18.0\",\n pnpm: \"11.0.4\",\n bun: \"1.3.14\",\n python: \"3.13.14\",\n uv: \"0.11.29\",\n playwright: \"1.62.1\",\n};\n\nexport const artifactPythonPackages = [\n \"matplotlib==3.11.1\",\n \"seaborn==0.13.2\",\n \"Pillow==12.3.0\",\n \"ReportLab==5.0.0\",\n \"pypdf==6.14.2\",\n \"pandas==3.0.3\",\n \"openpyxl==3.1.5\",\n \"XlsxWriter==3.2.9\",\n \"python-docx==1.2.0\",\n] as const;\n\nconst runtimeOrder: SandboxImageRuntime[] = [\"node\", \"bun\", \"python\"];\nconst featureOrder: SandboxImageFeature[] = [\"artifacts\", \"playwright\"];\nconst commonAptPackages = [\"bash\", \"ca-certificates\", \"findutils\", \"libstdc++6\", \"procps\"];\n\nexport function resolveSandboxImageSpec(input: SandboxImageInput): SandboxImageSpec {\n validateName(input.name);\n\n const runtimes = new Set(input.runtimes ?? []);\n const features = new Set(input.features ?? []);\n const packages: SandboxImagePackages = {\n apt: unique(input.packages?.apt ?? []),\n npm: unique(input.packages?.npm ?? []),\n uv: unique(input.packages?.uv ?? []),\n };\n\n for (const runtime of runtimes) validateRuntime(runtime);\n for (const feature of features) validateFeature(feature);\n for (const packageName of packages.apt) validateAptPackage(packageName);\n for (const packageSpec of packages.npm) parseNpmPackageSpec(packageSpec);\n for (const requirement of packages.uv) validateUvRequirement(requirement);\n\n if (features.has(\"artifacts\") || packages.uv.length > 0) runtimes.add(\"python\");\n if (features.has(\"playwright\")) runtimes.add(\"node\");\n if (packages.npm.length > 0 && !runtimes.has(\"node\") && !runtimes.has(\"bun\")) {\n runtimes.add(\"node\");\n }\n\n if (runtimes.size === 0) {\n throw new Error(\"Select at least one runtime or feature.\");\n }\n\n const versions = { ...defaultSandboxImageVersions, ...input.versions };\n for (const [name, version] of Object.entries(versions)) validateVersion(name, version);\n\n const tag = input.tag ?? `anvia-sandbox-${input.name}:latest`;\n validateImageTag(tag);\n\n return {\n name: input.name,\n tag,\n runtimes: runtimeOrder.filter((runtime) => runtimes.has(runtime)),\n features: featureOrder.filter((feature) => features.has(feature)),\n packages,\n versions,\n };\n}\n\nexport function renderSandboxImageContext(\n spec: SandboxImageSpec,\n generatorVersion: string,\n): SandboxImageContext {\n const files = new Map<string, string>();\n const pythonRequirements = [...spec.packages.uv];\n if (spec.features.includes(\"artifacts\")) {\n pythonRequirements.unshift(...artifactPythonPackages);\n }\n const npmDependencies = npmDependenciesFor(spec);\n\n files.set(\"Dockerfile\", `${renderDockerfile(spec, pythonRequirements, npmDependencies)}\\n`);\n files.set(\n \".dockerignore\",\n renderDockerignore(pythonRequirements.length > 0, npmDependencies.size > 0),\n );\n\n if (pythonRequirements.length > 0) {\n files.set(\"pyproject.toml\", renderPythonProject(spec, unique(pythonRequirements)));\n }\n if (npmDependencies.size > 0) {\n files.set(\n \"package.json\",\n `${JSON.stringify(\n {\n private: true,\n description: `Generated dependencies for ${spec.name}`,\n dependencies: Object.fromEntries(npmDependencies),\n },\n null,\n 2,\n )}\\n`,\n );\n }\n\n const generatedFiles = [...files.keys(), \"anvia-sandbox.json\"].sort();\n const manifest: SandboxImageManifest = {\n schemaVersion: 1,\n generatedBy: {\n package: \"@anvia/sandbox\",\n version: generatorVersion,\n },\n ...spec,\n generatedFiles,\n };\n files.set(\"anvia-sandbox.json\", `${JSON.stringify(manifest, null, 2)}\\n`);\n\n return { manifest, files };\n}\n\nexport function unpinnedSandboxImagePackages(spec: SandboxImageSpec): string[] {\n const unpinned: string[] = [];\n for (const value of spec.packages.npm) {\n if (parseNpmPackageSpec(value).version === \"latest\") unpinned.push(value);\n }\n for (const value of spec.packages.uv) {\n if (!/===|==|@\\s*https?:/i.test(value)) unpinned.push(value);\n }\n return unpinned;\n}\n\nfunction renderDockerfile(\n spec: SandboxImageSpec,\n pythonRequirements: readonly string[],\n npmDependencies: ReadonlyMap<string, string>,\n): string {\n const hasNode = spec.runtimes.includes(\"node\");\n const hasBun = spec.runtimes.includes(\"bun\");\n const hasPython = spec.runtimes.includes(\"python\");\n const hasPlaywright = spec.features.includes(\"playwright\");\n const lines = [\n \"# Generated by @anvia/sandbox. Edit the manifest and regenerate instead of editing this file.\",\n ];\n\n if (hasNode) lines.push(`FROM node:${spec.versions.node}-bookworm-slim AS node-runtime`);\n if (hasPython) lines.push(`FROM python:${spec.versions.python}-slim-bookworm AS python-runtime`);\n if (hasBun) lines.push(`FROM oven/bun:${spec.versions.bun}-slim AS bun-runtime`);\n if (hasPython) lines.push(`FROM ghcr.io/astral-sh/uv:${spec.versions.uv} AS uv-runtime`);\n\n if (hasPlaywright) {\n lines.push(`FROM mcr.microsoft.com/playwright:v${spec.versions.playwright}-noble AS final`);\n } else if (hasPython) {\n lines.push(\"FROM python-runtime AS final\");\n } else if (hasNode) {\n lines.push(\"FROM node-runtime AS final\");\n } else {\n lines.push(\"FROM bun-runtime AS final\");\n }\n\n lines.push(\"\", \"USER root\");\n\n if (hasPython && (hasPlaywright || !isFinalRuntime(spec, \"python\"))) {\n lines.push(\"COPY --from=python-runtime /usr/local/ /usr/local/\");\n }\n if (hasNode && (hasPlaywright || !isFinalRuntime(spec, \"node\"))) {\n lines.push(\"COPY --from=node-runtime /usr/local/bin/ /usr/local/bin/\");\n lines.push(\n \"COPY --from=node-runtime /usr/local/lib/node_modules/ /usr/local/lib/node_modules/\",\n );\n }\n if (hasBun && !isFinalRuntime(spec, \"bun\")) {\n lines.push(\"COPY --from=bun-runtime /usr/local/bin/bun /usr/local/bin/bun\");\n lines.push(\"RUN ln -sf /usr/local/bin/bun /usr/local/bin/bunx\");\n }\n if (hasPython) {\n lines.push(\"COPY --from=uv-runtime /uv /uvx /usr/local/bin/\");\n }\n\n const requestedAptPackages = [...commonAptPackages];\n if (spec.features.includes(\"artifacts\")) requestedAptPackages.push(\"fonts-dejavu-core\");\n requestedAptPackages.push(...spec.packages.apt);\n const aptPackages = unique(requestedAptPackages).sort();\n lines.push(\n \"\",\n \"RUN apt-get update \\\\\",\n ` && apt-get install -y --no-install-recommends ${aptPackages.map(shellQuote).join(\" \")} \\\\`,\n \" && rm -rf /var/lib/apt/lists/*\",\n );\n\n if (hasNode) {\n lines.push(\n \"\",\n `RUN npm install --global ${shellQuote(`pnpm@${spec.versions.pnpm}`)} --no-audit --no-fund \\\\`,\n \" && npm cache clean --force\",\n );\n }\n\n if (pythonRequirements.length > 0) {\n lines.push(\n \"\",\n \"COPY pyproject.toml /opt/anvia-python/pyproject.toml\",\n \"RUN cd /opt/anvia-python \\\\\",\n \" && uv sync --no-dev --no-cache --no-install-project\",\n \"ENV VIRTUAL_ENV=/opt/anvia-python/.venv\",\n \"ENV PATH=/opt/anvia-python/.venv/bin:$PATH\",\n );\n }\n\n if (npmDependencies.size > 0) {\n lines.push(\"\", \"COPY package.json /opt/anvia-js/package.json\");\n if (hasNode) {\n lines.push(\n \"RUN npm install --prefix /opt/anvia-js --omit=dev --no-audit --no-fund \\\\\",\n \" && ln -s /opt/anvia-js/node_modules /node_modules \\\\\",\n \" && npm cache clean --force\",\n );\n } else {\n lines.push(\n \"RUN cd /opt/anvia-js \\\\\",\n \" && bun install --production --no-save \\\\\",\n \" && ln -s /opt/anvia-js/node_modules /node_modules\",\n );\n }\n lines.push(\"ENV NODE_PATH=/opt/anvia-js/node_modules\");\n lines.push(\"ENV PATH=/opt/anvia-js/node_modules/.bin:$PATH\");\n }\n\n lines.push(\"\");\n if (hasPlaywright) lines.push(\"ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright\");\n lines.push(\n \"RUN mkdir -p /workspace\",\n \"WORKDIR /workspace\",\n \"ENTRYPOINT []\",\n 'CMD [\"sh\", \"-c\", \"trap \\'exit 0\\' TERM INT; while :; do sleep 3600 & wait $!; done\"]',\n );\n\n return lines.join(\"\\n\");\n}\n\nfunction renderDockerignore(hasPython: boolean, hasNpm: boolean): string {\n const lines = [\"**\", \"!Dockerfile\", \"!.dockerignore\", \"!anvia-sandbox.json\"];\n if (hasPython) lines.push(\"!pyproject.toml\");\n if (hasNpm) lines.push(\"!package.json\");\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n\nfunction renderPythonProject(spec: SandboxImageSpec, requirements: readonly string[]): string {\n const [major, minor] = spec.versions.python.split(\".\");\n return [\n \"[project]\",\n `name = ${JSON.stringify(`anvia-sandbox-${spec.name}`)}`,\n 'version = \"0.0.0\"',\n `requires-python = ${JSON.stringify(`>=${major}.${minor}`)}`,\n \"dependencies = [\",\n ...requirements.map((requirement) => ` ${JSON.stringify(requirement)},`),\n \"]\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction npmDependenciesFor(spec: SandboxImageSpec): Map<string, string> {\n const dependencies = new Map<string, string>();\n if (spec.features.includes(\"playwright\")) {\n dependencies.set(\"playwright\", spec.versions.playwright);\n }\n for (const packageSpec of spec.packages.npm) {\n const parsed = parseNpmPackageSpec(packageSpec);\n if (dependencies.has(parsed.name)) {\n throw new Error(`Duplicate npm package: ${parsed.name}`);\n }\n dependencies.set(parsed.name, parsed.version);\n }\n return new Map([...dependencies.entries()].sort(([left], [right]) => left.localeCompare(right)));\n}\n\nfunction isFinalRuntime(spec: SandboxImageSpec, runtime: SandboxImageRuntime): boolean {\n if (spec.features.includes(\"playwright\")) return false;\n if (spec.runtimes.includes(\"python\")) return runtime === \"python\";\n if (spec.runtimes.includes(\"node\")) return runtime === \"node\";\n return runtime === \"bun\";\n}\n\nfunction validateName(name: string): void {\n if (!/^[a-z0-9][a-z0-9-]{0,62}$/.test(name)) {\n throw new Error(\n \"Image name must be 1-63 lowercase letters, numbers, or hyphens and cannot start with a hyphen.\",\n );\n }\n}\n\nfunction validateRuntime(runtime: string): asserts runtime is SandboxImageRuntime {\n if (!runtimeOrder.includes(runtime as SandboxImageRuntime)) {\n throw new Error(`Unknown runtime: ${runtime}. Expected node, bun, or python.`);\n }\n}\n\nfunction validateFeature(feature: string): asserts feature is SandboxImageFeature {\n if (!featureOrder.includes(feature as SandboxImageFeature)) {\n throw new Error(`Unknown feature: ${feature}. Expected artifacts or playwright.`);\n }\n}\n\nfunction validateAptPackage(packageName: string): void {\n if (!/^[a-zA-Z0-9][a-zA-Z0-9.+:~=-]*$/.test(packageName)) {\n throw new Error(`Invalid apt package: ${packageName}`);\n }\n}\n\nfunction parseNpmPackageSpec(packageSpec: string): { name: string; version: string } {\n if (/\\s/.test(packageSpec) || hasControlCharacter(packageSpec)) {\n throw new Error(`Invalid npm package spec: ${packageSpec}`);\n }\n\n const separator = packageSpec.startsWith(\"@\")\n ? packageSpec.indexOf(\"@\", packageSpec.indexOf(\"/\") + 1)\n : packageSpec.indexOf(\"@\");\n const name = separator === -1 ? packageSpec : packageSpec.slice(0, separator);\n const version = separator === -1 ? \"latest\" : packageSpec.slice(separator + 1);\n\n if (!/^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/i.test(name) || !version) {\n throw new Error(`Invalid npm package spec: ${packageSpec}`);\n }\n if (/[\\s'\"`$;&|<>\\\\]/.test(version) || hasControlCharacter(version)) {\n throw new Error(`Invalid npm package version in: ${packageSpec}`);\n }\n return { name, version };\n}\n\nfunction validateUvRequirement(requirement: string): void {\n if (!requirement || requirement.startsWith(\"-\") || hasControlCharacter(requirement)) {\n throw new Error(`Invalid uv package requirement: ${requirement}`);\n }\n}\n\nfunction validateVersion(name: string, version: string): void {\n if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(version)) {\n throw new Error(`Invalid ${name} version: ${version}`);\n }\n}\n\nfunction validateImageTag(tag: string): void {\n if (\n !tag ||\n tag.startsWith(\"-\") ||\n tag.includes(\"@\") ||\n /\\s/.test(tag) ||\n hasControlCharacter(tag)\n ) {\n throw new Error(`Invalid Docker image tag: ${tag}`);\n }\n}\n\nfunction unique(values: readonly string[]): string[] {\n return [...new Set(values)];\n}\n\nfunction hasControlCharacter(value: string): boolean {\n return [...value].some((character) => character.charCodeAt(0) < 32);\n}\n\nfunction shellQuote(value: string): string {\n return `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n"],"mappings":"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","names":["commonAptPackages"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/image-builder.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { realpathSync } from \"node:fs\";\nimport { lstat, mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { assertDockerCli } from \"./docker-cli\";\nimport {\n renderSandboxImageContext,\n resolveSandboxImageSpec,\n type SandboxImageFeature,\n type SandboxImageInput,\n type SandboxImageManifest,\n type SandboxImageRuntime,\n type SandboxImageVersions,\n unpinnedSandboxImagePackages,\n} from \"./image-builder\";\n\ninterface CliOptions {\n command?: string;\n name?: string;\n tag?: string;\n output?: string;\n runtimes: SandboxImageRuntime[];\n features: SandboxImageFeature[];\n apt: string[];\n npm: string[];\n uv: string[];\n versions: Partial<SandboxImageVersions>;\n dockerPath: string;\n build: boolean;\n buildExplicit: boolean;\n dryRun: boolean;\n force: boolean;\n help: boolean;\n}\n\nexport interface SandboxImageCliIo {\n log(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n stdout(chunk: Uint8Array): void;\n stderr(chunk: Uint8Array): void;\n}\n\nexport interface SandboxImagePromptResult {\n name: string;\n runtimes: SandboxImageRuntime[];\n features: SandboxImageFeature[];\n apt: string[];\n npm: string[];\n uv: string[];\n tag?: string;\n output?: string;\n build: boolean;\n}\n\nexport interface SandboxImageCliDependencies {\n isTTY?: boolean;\n packageVersion?: string;\n prompt?: (options: Readonly<CliOptions>) => Promise<SandboxImagePromptResult | undefined>;\n buildImage?: (input: {\n contextPath: string;\n tag: string;\n dockerPath: string;\n io: SandboxImageCliIo;\n }) => Promise<void>;\n}\n\nconst generatedFileNames = new Set([\n \".dockerignore\",\n \"Dockerfile\",\n \"anvia-sandbox.json\",\n \"package.json\",\n \"pyproject.toml\",\n]);\n\nconst commonAptPackages = [\n { value: \"git\", label: \"Git\", hint: \"Source control and repository operations\" },\n { value: \"curl\", label: \"curl\", hint: \"HTTP downloads and API debugging\" },\n { value: \"jq\", label: \"jq\", hint: \"JSON processing from the shell\" },\n { value: \"ffmpeg\", label: \"FFmpeg\", hint: \"Audio and video processing\" },\n { value: \"imagemagick\", label: \"ImageMagick\", hint: \"Image conversion and editing\" },\n { value: \"poppler-utils\", label: \"Poppler tools\", hint: \"PDF inspection and conversion\" },\n { value: \"libreoffice\", label: \"LibreOffice\", hint: \"Large; office document conversion\" },\n] as const;\n\nconst commonNpmPackages = [\n { value: \"pdfkit@0.19.1\", label: \"PDFKit\", hint: \"Generate PDF documents\" },\n { value: \"sharp@0.35.3\", label: \"Sharp\", hint: \"Resize and transform images\" },\n { value: \"exceljs@4.4.0\", label: \"ExcelJS\", hint: \"Read and write Excel workbooks\" },\n { value: \"docx@9.7.1\", label: \"docx\", hint: \"Generate Word documents\" },\n { value: \"pptxgenjs@4.0.1\", label: \"PptxGenJS\", hint: \"Generate PowerPoint presentations\" },\n] as const;\n\nconst commonUvPackages = [\n { value: \"httpx==0.28.1\", label: \"HTTPX\", hint: \"Modern HTTP client\" },\n { value: \"beautifulsoup4==4.15.0\", label: \"Beautiful Soup\", hint: \"HTML and XML parsing\" },\n { value: \"scipy==1.18.0\", label: \"SciPy\", hint: \"Scientific computing\" },\n { value: \"scikit-learn==1.9.0\", label: \"scikit-learn\", hint: \"Machine learning utilities\" },\n { value: \"polars==1.42.1\", label: \"Polars\", hint: \"Fast dataframe processing\" },\n] as const;\n\nconst defaultIo: SandboxImageCliIo = {\n log: console.log,\n warn: console.warn,\n error: console.error,\n stdout: (chunk) => process.stdout.write(chunk),\n stderr: (chunk) => process.stderr.write(chunk),\n};\n\nexport async function runCli(\n argv: string[] = process.argv.slice(2),\n cwd = process.cwd(),\n io: SandboxImageCliIo = defaultIo,\n dependencies: SandboxImageCliDependencies = {},\n): Promise<number> {\n let options: CliOptions;\n try {\n options = parseArgs(argv);\n } catch (error) {\n io.error(errorMessage(error));\n io.log(helpText());\n return 1;\n }\n\n if (options.help || options.command === undefined) {\n io.log(helpText());\n return 0;\n }\n if (options.command !== \"create-image\") {\n io.error(`Unknown command: ${options.command}`);\n io.log(helpText());\n return 1;\n }\n\n try {\n const shouldPrompt =\n options.name === undefined ||\n (options.runtimes.length === 0 &&\n options.features.length === 0 &&\n options.npm.length === 0 &&\n options.uv.length === 0);\n if (shouldPrompt) {\n const isTTY = dependencies.isTTY ?? (process.stdin.isTTY && process.stdout.isTTY);\n if (!isTTY) {\n throw new Error(\n \"Non-interactive create-image requires --name and at least one --runtime or --feature.\",\n );\n }\n const prompt = dependencies.prompt ?? promptForImage;\n const result = await prompt(options);\n if (result === undefined) return 130;\n options = applyPromptResult(options, result);\n }\n\n const input: SandboxImageInput = {\n name: required(options.name, \"Image name is required.\"),\n runtimes: options.runtimes,\n features: options.features,\n packages: {\n apt: options.apt,\n npm: options.npm,\n uv: options.uv,\n },\n versions: options.versions,\n };\n if (options.tag !== undefined) input.tag = options.tag;\n\n const spec = resolveSandboxImageSpec(input);\n const packageVersion = dependencies.packageVersion ?? (await readPackageVersion());\n const context = renderSandboxImageContext(spec, packageVersion);\n const outputPath = path.resolve(\n cwd,\n options.output ?? path.join(\".anvia\", \"sandbox-images\", spec.name),\n );\n const displayPath = relativeDisplayPath(cwd, outputPath);\n const unpinned = unpinnedSandboxImagePackages(spec);\n if (unpinned.length > 0) {\n io.warn(`Unpinned custom packages may change on rebuild: ${unpinned.join(\", \")}`);\n }\n\n if (options.dryRun) {\n printDryRun(context.files, displayPath, spec.tag, io);\n return 0;\n }\n\n await writeImageContext(outputPath, context.manifest, context.files, options.force);\n io.log(`Created ${displayPath}`);\n\n if (!options.build) {\n io.log(\"\");\n io.log(\"Build later:\");\n io.log(` ${shellCommand([options.dockerPath, \"build\", \"--tag\", spec.tag, displayPath])}`);\n printUsageSnippet(spec.tag, io);\n return 0;\n }\n\n const buildImage = dependencies.buildImage ?? buildDockerImage;\n await buildImage({\n contextPath: outputPath,\n tag: spec.tag,\n dockerPath: options.dockerPath,\n io,\n });\n io.log(`Built ${spec.tag}`);\n printUsageSnippet(spec.tag, io);\n return 0;\n } catch (error) {\n io.error(errorMessage(error));\n return 1;\n }\n}\n\nasync function promptForImage(\n options: Readonly<CliOptions>,\n): Promise<SandboxImagePromptResult | undefined> {\n assertInteractiveNodeVersion();\n const prompts = await import(\"@clack/prompts\");\n prompts.intro(\"Create an Anvia sandbox image\");\n\n const nameResult =\n options.name ??\n (await prompts.text({\n message: \"Image name\",\n placeholder: \"reports\",\n validate: (value) =>\n /^[a-z0-9][a-z0-9-]{0,62}$/.test(value ?? \"\")\n ? undefined\n : \"Use 1-63 lowercase letters, numbers, or hyphens.\",\n }));\n if (prompts.isCancel(nameResult)) return cancelPrompt(prompts);\n const name = promptString(nameResult, \"Image name\");\n\n let runtimes = [...options.runtimes];\n let features = [...options.features];\n if (\n runtimes.length === 0 &&\n features.length === 0 &&\n options.npm.length === 0 &&\n options.uv.length === 0\n ) {\n const capabilities = await prompts.multiselect<SandboxImageRuntime | SandboxImageFeature>({\n message: \"Select runtimes and features\",\n required: true,\n options: [\n { value: \"node\", label: \"Node.js\", hint: \"Includes npm and pnpm\" },\n { value: \"bun\", label: \"Bun\", hint: \"Includes bun and bunx\" },\n { value: \"python\", label: \"Python\", hint: \"Includes uv and uvx\" },\n { value: \"artifacts\", label: \"Reporting and artifacts\", hint: \"Adds Python automatically\" },\n { value: \"playwright\", label: \"Playwright + Chromium\", hint: \"Adds Node.js automatically\" },\n ],\n });\n if (prompts.isCancel(capabilities)) return cancelPrompt(prompts);\n runtimes = capabilities.filter(isRuntime);\n features = capabilities.filter(isFeature);\n }\n\n const aptResult = await selectCommonPackages(\n prompts,\n \"Select common apt tools (optional)\",\n commonAptPackages,\n options.apt,\n );\n if (aptResult === undefined) return cancelPrompt(prompts);\n const npmResult = await selectCommonPackages(\n prompts,\n \"Select common npm libraries (optional)\",\n commonNpmPackages,\n options.npm,\n );\n if (npmResult === undefined) return cancelPrompt(prompts);\n const uvResult = await selectCommonPackages(\n prompts,\n \"Select common Python libraries with uv (optional)\",\n commonUvPackages,\n options.uv,\n );\n if (uvResult === undefined) return cancelPrompt(prompts);\n\n const tagResult =\n options.tag ??\n (await prompts.text({\n message: \"Docker image tag\",\n initialValue: `anvia-sandbox-${name}:latest`,\n }));\n if (prompts.isCancel(tagResult)) return cancelPrompt(prompts);\n const outputResult =\n options.output ??\n (await prompts.text({\n message: \"Generated source directory\",\n initialValue: path.join(\".anvia\", \"sandbox-images\", name),\n }));\n if (prompts.isCancel(outputResult)) return cancelPrompt(prompts);\n\n const buildResult = options.buildExplicit\n ? options.build\n : await prompts.confirm({ message: \"Build the image now?\", initialValue: true });\n if (prompts.isCancel(buildResult)) return cancelPrompt(prompts);\n const confirmed = await prompts.confirm({\n message: \"Create this sandbox image?\",\n initialValue: true,\n });\n if (prompts.isCancel(confirmed) || !confirmed) return cancelPrompt(prompts);\n\n prompts.outro(\"Configuration ready\");\n return {\n name,\n runtimes,\n features,\n apt: aptResult,\n npm: npmResult,\n uv: uvResult,\n tag: promptString(tagResult, \"Docker image tag\"),\n output: promptString(outputResult, \"Generated source directory\"),\n build: promptBoolean(buildResult, \"Build selection\"),\n };\n}\n\nasync function selectCommonPackages(\n prompts: typeof import(\"@clack/prompts\"),\n message: string,\n options: readonly { value: string; label: string; hint: string }[],\n existing: readonly string[],\n): Promise<string[] | undefined> {\n const commonValues = new Set(options.map((option) => option.value));\n const result = await prompts.multiselect<string>({\n message,\n required: false,\n options: [...options],\n initialValues: existing.filter((value) => commonValues.has(value)),\n });\n if (prompts.isCancel(result)) return undefined;\n return [...new Set([...existing, ...result])];\n}\n\nfunction cancelPrompt(prompts: typeof import(\"@clack/prompts\")): undefined {\n prompts.cancel(\"Image creation cancelled.\");\n return undefined;\n}\n\nasync function buildDockerImage(input: {\n contextPath: string;\n tag: string;\n dockerPath: string;\n io: SandboxImageCliIo;\n}): Promise<void> {\n await assertDockerCli([\"build\", \"--tag\", input.tag, input.contextPath], {\n dockerPath: input.dockerPath,\n onStdout: input.io.stdout,\n onStderr: input.io.stderr,\n });\n}\n\nasync function writeImageContext(\n outputPath: string,\n manifest: SandboxImageManifest,\n files: ReadonlyMap<string, string>,\n force: boolean,\n): Promise<void> {\n const outputStat = await safeLstat(outputPath);\n if (outputStat?.isSymbolicLink()) {\n throw new Error(`Refusing to write through symlink: ${outputPath}`);\n }\n\n if (outputStat !== undefined) {\n if (!outputStat.isDirectory()) throw new Error(`Output path is not a directory: ${outputPath}`);\n const previousManifest = await readGeneratedManifest(outputPath);\n if (previousManifest === undefined) {\n throw new Error(\n `Output directory already exists but was not generated by @anvia/sandbox: ${outputPath}`,\n );\n }\n if (!force) throw new Error(`Output directory already exists. Use --force to regenerate it.`);\n\n for (const filename of previousManifest.generatedFiles) {\n const target = path.join(outputPath, filename);\n const targetStat = await safeLstat(target);\n if (targetStat?.isSymbolicLink()) throw new Error(`Refusing to replace symlink: ${target}`);\n if (targetStat !== undefined) await rm(target);\n }\n } else {\n await mkdir(outputPath, { recursive: true });\n }\n\n for (const [filename, content] of files) {\n if (!generatedFileNames.has(filename))\n throw new Error(`Unexpected generated filename: ${filename}`);\n const target = path.join(outputPath, filename);\n const targetStat = await safeLstat(target);\n if (targetStat?.isSymbolicLink()) throw new Error(`Refusing to replace symlink: ${target}`);\n await writeFile(target, content, \"utf8\");\n }\n\n if (!files.has(\"anvia-sandbox.json\") || manifest.generatedFiles.length !== files.size) {\n throw new Error(\"Generated image context manifest is inconsistent.\");\n }\n}\n\nasync function readGeneratedManifest(\n outputPath: string,\n): Promise<SandboxImageManifest | undefined> {\n const manifestPath = path.join(outputPath, \"anvia-sandbox.json\");\n const stat = await safeLstat(manifestPath);\n if (stat === undefined) return undefined;\n if (stat.isSymbolicLink() || !stat.isFile()) {\n throw new Error(`Invalid generated manifest: ${manifestPath}`);\n }\n\n let value: unknown;\n try {\n value = JSON.parse(await readFile(manifestPath, \"utf8\"));\n } catch (error) {\n throw new Error(`Unable to read generated manifest: ${manifestPath}`, { cause: error });\n }\n if (!isGeneratedManifest(value)) {\n throw new Error(\n `Output manifest is not recognized as an @anvia/sandbox manifest: ${manifestPath}`,\n );\n }\n return value;\n}\n\nfunction isGeneratedManifest(value: unknown): value is SandboxImageManifest {\n if (typeof value !== \"object\" || value === null) return false;\n const record = value as Record<string, unknown>;\n const generatedBy = record.generatedBy as Record<string, unknown> | undefined;\n const files = record.generatedFiles;\n return (\n record.schemaVersion === 1 &&\n generatedBy?.package === \"@anvia/sandbox\" &&\n Array.isArray(files) &&\n files.every((file) => typeof file === \"string\" && generatedFileNames.has(file))\n );\n}\n\nasync function safeLstat(target: string) {\n try {\n return await lstat(target);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw error;\n }\n}\n\nfunction printDryRun(\n files: ReadonlyMap<string, string>,\n outputPath: string,\n tag: string,\n io: SandboxImageCliIo,\n): void {\n io.log(`Would create ${outputPath}`);\n for (const [filename, content] of files) {\n io.log(\"\");\n io.log(`--- ${filename}`);\n io.log(content.trimEnd());\n }\n io.log(\"\");\n io.log(`Would build ${tag}`);\n}\n\nfunction printUsageSnippet(tag: string, io: SandboxImageCliIo): void {\n io.log(\"\");\n io.log(\"Use with @anvia/sandbox:\");\n io.log(' import { DockerSandboxClient } from \"@anvia/sandbox\";');\n io.log(\"\");\n io.log(\" const client = new DockerSandboxClient();\");\n io.log(\" await using sandbox = await client.createSandbox({\");\n io.log(` image: ${JSON.stringify(tag)},`);\n io.log(' workspace: { type: \"ephemeral\" },');\n io.log(' network: { mode: \"none\" },');\n io.log(\" });\");\n}\n\nfunction applyPromptResult(options: CliOptions, result: SandboxImagePromptResult): CliOptions {\n const next: CliOptions = {\n ...options,\n name: result.name,\n runtimes: result.runtimes,\n features: result.features,\n apt: result.apt,\n npm: result.npm,\n uv: result.uv,\n build: result.build,\n buildExplicit: true,\n };\n if (result.tag !== undefined) next.tag = result.tag;\n if (result.output !== undefined) next.output = result.output;\n return next;\n}\n\nfunction parseArgs(argv: string[]): CliOptions {\n const options: CliOptions = {\n runtimes: [],\n features: [],\n apt: [],\n npm: [],\n uv: [],\n versions: {},\n dockerPath: \"docker\",\n build: true,\n buildExplicit: false,\n dryRun: false,\n force: false,\n help: false,\n };\n\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index] ?? \"\";\n if (!argument.startsWith(\"-\")) {\n if (options.command !== undefined) throw new Error(`Unexpected argument: ${argument}`);\n options.command = argument;\n continue;\n }\n\n const [flag, inlineValue] = splitFlag(argument);\n const value = () => inlineValue ?? required(argv[++index], `${flag} requires a value.`);\n switch (flag) {\n case \"-h\":\n case \"--help\":\n options.help = true;\n break;\n case \"--name\":\n options.name = value();\n break;\n case \"--tag\":\n options.tag = value();\n break;\n case \"--output\":\n options.output = value();\n break;\n case \"--runtime\":\n options.runtimes.push(parseRuntime(value()));\n break;\n case \"--feature\":\n options.features.push(parseFeature(value()));\n break;\n case \"--apt\":\n options.apt.push(value());\n break;\n case \"--npm\":\n options.npm.push(value());\n break;\n case \"--uv\":\n options.uv.push(value());\n break;\n case \"--node-version\":\n options.versions.node = value();\n break;\n case \"--pnpm-version\":\n options.versions.pnpm = value();\n break;\n case \"--bun-version\":\n options.versions.bun = value();\n break;\n case \"--python-version\":\n options.versions.python = value();\n break;\n case \"--uv-version\":\n options.versions.uv = value();\n break;\n case \"--playwright-version\":\n options.versions.playwright = value();\n break;\n case \"--docker-path\":\n options.dockerPath = value();\n break;\n case \"--no-build\":\n rejectInlineValue(flag, inlineValue);\n options.build = false;\n options.buildExplicit = true;\n break;\n case \"--dry-run\":\n rejectInlineValue(flag, inlineValue);\n options.dryRun = true;\n break;\n case \"--force\":\n rejectInlineValue(flag, inlineValue);\n options.force = true;\n break;\n default:\n throw new Error(`Unknown option: ${flag}`);\n }\n }\n return options;\n}\n\nfunction splitFlag(argument: string): [string, string | undefined] {\n const separator = argument.indexOf(\"=\");\n return separator === -1\n ? [argument, undefined]\n : [argument.slice(0, separator), argument.slice(separator + 1)];\n}\n\nfunction rejectInlineValue(flag: string, value: string | undefined): void {\n if (value !== undefined) throw new Error(`${flag} does not accept a value.`);\n}\n\nfunction parseRuntime(value: string): SandboxImageRuntime {\n if (isRuntime(value)) return value;\n throw new Error(`Unknown runtime: ${value}. Expected node, bun, or python.`);\n}\n\nfunction parseFeature(value: string): SandboxImageFeature {\n if (isFeature(value)) return value;\n throw new Error(`Unknown feature: ${value}. Expected artifacts or playwright.`);\n}\n\nfunction isRuntime(value: string): value is SandboxImageRuntime {\n return value === \"node\" || value === \"bun\" || value === \"python\";\n}\n\nfunction isFeature(value: string): value is SandboxImageFeature {\n return value === \"artifacts\" || value === \"playwright\";\n}\n\nfunction assertInteractiveNodeVersion(): void {\n const [major = 0, minor = 0] = process.versions.node.split(\".\").map(Number);\n if (major < 20 || (major === 20 && minor < 12)) {\n throw new Error(\"The interactive create-image wizard requires Node.js 20.12 or newer.\");\n }\n}\n\nasync function readPackageVersion(): Promise<string> {\n const packageJson = JSON.parse(\n await readFile(new URL(\"../package.json\", import.meta.url), \"utf8\"),\n ) as {\n version?: unknown;\n };\n return typeof packageJson.version === \"string\" ? packageJson.version : \"unknown\";\n}\n\nfunction relativeDisplayPath(cwd: string, target: string): string {\n const relative = path.relative(cwd, target);\n return relative && !relative.startsWith(\"..\") ? relative : target;\n}\n\nfunction shellCommand(args: readonly string[]): string {\n return args.map(shellArgument).join(\" \");\n}\n\nfunction shellArgument(value: string): string {\n if (/^[a-zA-Z0-9_./:@+-]+$/.test(value)) return value;\n return `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n\nfunction required<T>(value: T | undefined, message: string): T {\n if (value === undefined || value === \"\") throw new Error(message);\n return value;\n}\n\nfunction promptString(value: unknown, name: string): string {\n if (typeof value !== \"string\") throw new TypeError(`${name} must be a string.`);\n return value;\n}\n\nfunction promptBoolean(value: unknown, name: string): boolean {\n if (typeof value !== \"boolean\") throw new TypeError(`${name} must be a boolean.`);\n return value;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : \"Unknown sandbox CLI error\";\n}\n\nfunction helpText(): string {\n return `Usage:\n pnpm dlx @anvia/sandbox create-image [options]\n\nOptions:\n --name <slug> Image profile name\n --runtime <node|bun|python> Runtime to include; repeatable\n --feature <artifacts|playwright>\n Curated feature to include; repeatable\n --apt <package> Additional apt package; repeatable\n --npm <package[@version]> Additional npm package; repeatable\n --uv <requirement> Additional Python package installed with uv; repeatable\n --tag <tag> Local image tag\n --output <directory> Generated context directory\n --node-version <version> Override Node.js version\n --pnpm-version <version> Override pnpm version\n --bun-version <version> Override Bun version\n --python-version <version> Override Python version\n --uv-version <version> Override uv version\n --playwright-version <version> Override Playwright and browser image version\n --docker-path <path> Docker CLI path (default: docker)\n --no-build Generate files without building\n --dry-run Print generated files without writing or building\n --force Regenerate a context previously created by this CLI\n -h, --help Show this help\n\nExamples:\n pnpm dlx @anvia/sandbox create-image\n pnpm dlx @anvia/sandbox create-image --name reports --feature artifacts\n pnpm dlx @anvia/sandbox create-image --name browser --runtime bun --feature playwright`;\n}\n\nexport function isCliEntryPoint(moduleUrl: string, invokedPath: string | undefined): boolean {\n if (invokedPath === undefined) return false;\n try {\n return realpathSync(path.resolve(invokedPath)) === realpathSync(fileURLToPath(moduleUrl));\n } catch {\n return false;\n }\n}\n\nif (isCliEntryPoint(import.meta.url, process.argv[1])) {\n runCli().then((code) => {\n process.exitCode = code;\n });\n}\n","export type SandboxImageRuntime = \"node\" | \"bun\" | \"python\";\nexport type SandboxImageFeature = \"artifacts\" | \"playwright\";\n\nexport interface SandboxImageVersions {\n node: string;\n pnpm: string;\n bun: string;\n python: string;\n uv: string;\n playwright: string;\n}\n\nexport interface SandboxImagePackages {\n apt: string[];\n npm: string[];\n uv: string[];\n}\n\nexport interface SandboxImageInput {\n name: string;\n tag?: string;\n runtimes?: readonly SandboxImageRuntime[];\n features?: readonly SandboxImageFeature[];\n packages?: Partial<SandboxImagePackages>;\n versions?: Partial<SandboxImageVersions>;\n}\n\nexport interface SandboxImageSpec {\n name: string;\n tag: string;\n runtimes: SandboxImageRuntime[];\n features: SandboxImageFeature[];\n packages: SandboxImagePackages;\n versions: SandboxImageVersions;\n}\n\nexport interface SandboxImageManifest extends SandboxImageSpec {\n schemaVersion: 1;\n generatedBy: {\n package: \"@anvia/sandbox\";\n version: string;\n };\n generatedFiles: string[];\n}\n\nexport interface SandboxImageContext {\n manifest: SandboxImageManifest;\n files: ReadonlyMap<string, string>;\n}\n\nexport const defaultSandboxImageVersions: Readonly<SandboxImageVersions> = {\n node: \"24.18.0\",\n pnpm: \"11.0.4\",\n bun: \"1.3.14\",\n python: \"3.13.14\",\n uv: \"0.11.29\",\n playwright: \"1.62.1\",\n};\n\nexport const artifactPythonPackages = [\n \"matplotlib==3.11.1\",\n \"seaborn==0.13.2\",\n \"Pillow==12.3.0\",\n \"ReportLab==5.0.0\",\n \"pypdf==6.14.2\",\n \"pandas==3.0.3\",\n \"openpyxl==3.1.5\",\n \"XlsxWriter==3.2.9\",\n \"python-docx==1.2.0\",\n] as const;\n\nconst runtimeOrder: SandboxImageRuntime[] = [\"node\", \"bun\", \"python\"];\nconst featureOrder: SandboxImageFeature[] = [\"artifacts\", \"playwright\"];\nconst commonAptPackages = [\"bash\", \"ca-certificates\", \"findutils\", \"libstdc++6\", \"procps\"];\n\nexport function resolveSandboxImageSpec(input: SandboxImageInput): SandboxImageSpec {\n validateName(input.name);\n\n const runtimes = new Set(input.runtimes ?? []);\n const features = new Set(input.features ?? []);\n const packages: SandboxImagePackages = {\n apt: unique(input.packages?.apt ?? []),\n npm: unique(input.packages?.npm ?? []),\n uv: unique(input.packages?.uv ?? []),\n };\n\n for (const runtime of runtimes) validateRuntime(runtime);\n for (const feature of features) validateFeature(feature);\n for (const packageName of packages.apt) validateAptPackage(packageName);\n for (const packageSpec of packages.npm) parseNpmPackageSpec(packageSpec);\n for (const requirement of packages.uv) validateUvRequirement(requirement);\n\n if (features.has(\"artifacts\") || packages.uv.length > 0) runtimes.add(\"python\");\n if (features.has(\"playwright\")) runtimes.add(\"node\");\n if (packages.npm.length > 0 && !runtimes.has(\"node\") && !runtimes.has(\"bun\")) {\n runtimes.add(\"node\");\n }\n\n if (runtimes.size === 0) {\n throw new Error(\"Select at least one runtime or feature.\");\n }\n\n const versions = { ...defaultSandboxImageVersions, ...input.versions };\n for (const [name, version] of Object.entries(versions)) validateVersion(name, version);\n\n const tag = input.tag ?? `anvia-sandbox-${input.name}:latest`;\n validateImageTag(tag);\n\n return {\n name: input.name,\n tag,\n runtimes: runtimeOrder.filter((runtime) => runtimes.has(runtime)),\n features: featureOrder.filter((feature) => features.has(feature)),\n packages,\n versions,\n };\n}\n\nexport function renderSandboxImageContext(\n spec: SandboxImageSpec,\n generatorVersion: string,\n): SandboxImageContext {\n const files = new Map<string, string>();\n const pythonRequirements = [...spec.packages.uv];\n if (spec.features.includes(\"artifacts\")) {\n pythonRequirements.unshift(...artifactPythonPackages);\n }\n const npmDependencies = npmDependenciesFor(spec);\n\n files.set(\"Dockerfile\", `${renderDockerfile(spec, pythonRequirements, npmDependencies)}\\n`);\n files.set(\n \".dockerignore\",\n renderDockerignore(pythonRequirements.length > 0, npmDependencies.size > 0),\n );\n\n if (pythonRequirements.length > 0) {\n files.set(\"pyproject.toml\", renderPythonProject(spec, unique(pythonRequirements)));\n }\n if (npmDependencies.size > 0) {\n files.set(\n \"package.json\",\n `${JSON.stringify(\n {\n private: true,\n description: `Generated dependencies for ${spec.name}`,\n dependencies: Object.fromEntries(npmDependencies),\n },\n null,\n 2,\n )}\\n`,\n );\n }\n\n const generatedFiles = [...files.keys(), \"anvia-sandbox.json\"].sort();\n const manifest: SandboxImageManifest = {\n schemaVersion: 1,\n generatedBy: {\n package: \"@anvia/sandbox\",\n version: generatorVersion,\n },\n ...spec,\n generatedFiles,\n };\n files.set(\"anvia-sandbox.json\", `${JSON.stringify(manifest, null, 2)}\\n`);\n\n return { manifest, files };\n}\n\nexport function unpinnedSandboxImagePackages(spec: SandboxImageSpec): string[] {\n const unpinned: string[] = [];\n for (const value of spec.packages.npm) {\n if (parseNpmPackageSpec(value).version === \"latest\") unpinned.push(value);\n }\n for (const value of spec.packages.uv) {\n if (!/===|==|@\\s*https?:/i.test(value)) unpinned.push(value);\n }\n return unpinned;\n}\n\nfunction renderDockerfile(\n spec: SandboxImageSpec,\n pythonRequirements: readonly string[],\n npmDependencies: ReadonlyMap<string, string>,\n): string {\n const hasNode = spec.runtimes.includes(\"node\");\n const hasBun = spec.runtimes.includes(\"bun\");\n const hasPython = spec.runtimes.includes(\"python\");\n const hasPlaywright = spec.features.includes(\"playwright\");\n const lines = [\n \"# Generated by @anvia/sandbox. Edit the manifest and regenerate instead of editing this file.\",\n ];\n\n if (hasNode) lines.push(`FROM node:${spec.versions.node}-bookworm-slim AS node-runtime`);\n if (hasPython) lines.push(`FROM python:${spec.versions.python}-slim-bookworm AS python-runtime`);\n if (hasBun) lines.push(`FROM oven/bun:${spec.versions.bun}-slim AS bun-runtime`);\n if (hasPython) lines.push(`FROM ghcr.io/astral-sh/uv:${spec.versions.uv} AS uv-runtime`);\n\n if (hasPlaywright) {\n lines.push(`FROM mcr.microsoft.com/playwright:v${spec.versions.playwright}-noble AS final`);\n } else if (hasPython) {\n lines.push(\"FROM python-runtime AS final\");\n } else if (hasNode) {\n lines.push(\"FROM node-runtime AS final\");\n } else {\n lines.push(\"FROM bun-runtime AS final\");\n }\n\n lines.push(\"\", \"USER root\");\n\n if (hasPython && (hasPlaywright || !isFinalRuntime(spec, \"python\"))) {\n lines.push(\"COPY --from=python-runtime /usr/local/ /usr/local/\");\n }\n if (hasNode && (hasPlaywright || !isFinalRuntime(spec, \"node\"))) {\n lines.push(\"COPY --from=node-runtime /usr/local/bin/ /usr/local/bin/\");\n lines.push(\n \"COPY --from=node-runtime /usr/local/lib/node_modules/ /usr/local/lib/node_modules/\",\n );\n }\n if (hasBun && !isFinalRuntime(spec, \"bun\")) {\n lines.push(\"COPY --from=bun-runtime /usr/local/bin/bun /usr/local/bin/bun\");\n lines.push(\"RUN ln -sf /usr/local/bin/bun /usr/local/bin/bunx\");\n }\n if (hasPython) {\n lines.push(\"COPY --from=uv-runtime /uv /uvx /usr/local/bin/\");\n }\n\n const requestedAptPackages = [...commonAptPackages];\n if (spec.features.includes(\"artifacts\")) requestedAptPackages.push(\"fonts-dejavu-core\");\n requestedAptPackages.push(...spec.packages.apt);\n const aptPackages = unique(requestedAptPackages).sort();\n lines.push(\n \"\",\n \"RUN apt-get update \\\\\",\n ` && apt-get install -y --no-install-recommends ${aptPackages.map(shellQuote).join(\" \")} \\\\`,\n \" && rm -rf /var/lib/apt/lists/*\",\n );\n\n if (hasNode) {\n lines.push(\n \"\",\n `RUN npm install --global ${shellQuote(`pnpm@${spec.versions.pnpm}`)} --no-audit --no-fund \\\\`,\n \" && npm cache clean --force\",\n );\n }\n\n if (pythonRequirements.length > 0) {\n lines.push(\n \"\",\n \"COPY pyproject.toml /opt/anvia-python/pyproject.toml\",\n \"RUN cd /opt/anvia-python \\\\\",\n \" && uv sync --no-dev --no-cache --no-install-project\",\n \"ENV VIRTUAL_ENV=/opt/anvia-python/.venv\",\n \"ENV PATH=/opt/anvia-python/.venv/bin:$PATH\",\n );\n }\n\n if (npmDependencies.size > 0) {\n lines.push(\"\", \"COPY package.json /opt/anvia-js/package.json\");\n if (hasNode) {\n lines.push(\n \"RUN npm install --prefix /opt/anvia-js --omit=dev --no-audit --no-fund \\\\\",\n \" && ln -s /opt/anvia-js/node_modules /node_modules \\\\\",\n \" && npm cache clean --force\",\n );\n } else {\n lines.push(\n \"RUN cd /opt/anvia-js \\\\\",\n \" && bun install --production --no-save \\\\\",\n \" && ln -s /opt/anvia-js/node_modules /node_modules\",\n );\n }\n lines.push(\"ENV NODE_PATH=/opt/anvia-js/node_modules\");\n lines.push(\"ENV PATH=/opt/anvia-js/node_modules/.bin:$PATH\");\n }\n\n lines.push(\"\");\n if (hasPlaywright) lines.push(\"ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright\");\n lines.push(\n \"RUN mkdir -p /workspace\",\n \"WORKDIR /workspace\",\n \"ENTRYPOINT []\",\n 'CMD [\"sh\", \"-c\", \"trap \\'exit 0\\' TERM INT; while :; do sleep 3600 & wait $!; done\"]',\n );\n\n return lines.join(\"\\n\");\n}\n\nfunction renderDockerignore(hasPython: boolean, hasNpm: boolean): string {\n const lines = [\"**\", \"!Dockerfile\", \"!.dockerignore\", \"!anvia-sandbox.json\"];\n if (hasPython) lines.push(\"!pyproject.toml\");\n if (hasNpm) lines.push(\"!package.json\");\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n\nfunction renderPythonProject(spec: SandboxImageSpec, requirements: readonly string[]): string {\n const [major, minor] = spec.versions.python.split(\".\");\n return [\n \"[project]\",\n `name = ${JSON.stringify(`anvia-sandbox-${spec.name}`)}`,\n 'version = \"0.0.0\"',\n `requires-python = ${JSON.stringify(`>=${major}.${minor}`)}`,\n \"dependencies = [\",\n ...requirements.map((requirement) => ` ${JSON.stringify(requirement)},`),\n \"]\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction npmDependenciesFor(spec: SandboxImageSpec): Map<string, string> {\n const dependencies = new Map<string, string>();\n if (spec.features.includes(\"playwright\")) {\n dependencies.set(\"playwright\", spec.versions.playwright);\n }\n for (const packageSpec of spec.packages.npm) {\n const parsed = parseNpmPackageSpec(packageSpec);\n if (dependencies.has(parsed.name)) {\n throw new Error(`Duplicate npm package: ${parsed.name}`);\n }\n dependencies.set(parsed.name, parsed.version);\n }\n return new Map([...dependencies.entries()].sort(([left], [right]) => left.localeCompare(right)));\n}\n\nfunction isFinalRuntime(spec: SandboxImageSpec, runtime: SandboxImageRuntime): boolean {\n if (spec.features.includes(\"playwright\")) return false;\n if (spec.runtimes.includes(\"python\")) return runtime === \"python\";\n if (spec.runtimes.includes(\"node\")) return runtime === \"node\";\n return runtime === \"bun\";\n}\n\nfunction validateName(name: string): void {\n if (!/^[a-z0-9][a-z0-9-]{0,62}$/.test(name)) {\n throw new Error(\n \"Image name must be 1-63 lowercase letters, numbers, or hyphens and cannot start with a hyphen.\",\n );\n }\n}\n\nfunction validateRuntime(runtime: string): asserts runtime is SandboxImageRuntime {\n if (!runtimeOrder.includes(runtime as SandboxImageRuntime)) {\n throw new Error(`Unknown runtime: ${runtime}. Expected node, bun, or python.`);\n }\n}\n\nfunction validateFeature(feature: string): asserts feature is SandboxImageFeature {\n if (!featureOrder.includes(feature as SandboxImageFeature)) {\n throw new Error(`Unknown feature: ${feature}. Expected artifacts or playwright.`);\n }\n}\n\nfunction validateAptPackage(packageName: string): void {\n if (!/^[a-zA-Z0-9][a-zA-Z0-9.+:~=-]*$/.test(packageName)) {\n throw new Error(`Invalid apt package: ${packageName}`);\n }\n}\n\nfunction parseNpmPackageSpec(packageSpec: string): { name: string; version: string } {\n if (/\\s/.test(packageSpec) || hasControlCharacter(packageSpec)) {\n throw new Error(`Invalid npm package spec: ${packageSpec}`);\n }\n\n const separator = packageSpec.startsWith(\"@\")\n ? packageSpec.indexOf(\"@\", packageSpec.indexOf(\"/\") + 1)\n : packageSpec.indexOf(\"@\");\n const name = separator === -1 ? packageSpec : packageSpec.slice(0, separator);\n const version = separator === -1 ? \"latest\" : packageSpec.slice(separator + 1);\n\n if (!/^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/i.test(name) || !version) {\n throw new Error(`Invalid npm package spec: ${packageSpec}`);\n }\n if (/[\\s'\"`$;&|<>\\\\]/.test(version) || hasControlCharacter(version)) {\n throw new Error(`Invalid npm package version in: ${packageSpec}`);\n }\n return { name, version };\n}\n\nfunction validateUvRequirement(requirement: string): void {\n if (!requirement || requirement.startsWith(\"-\") || hasControlCharacter(requirement)) {\n throw new Error(`Invalid uv package requirement: ${requirement}`);\n }\n}\n\nfunction validateVersion(name: string, version: string): void {\n if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(version)) {\n throw new Error(`Invalid ${name} version: ${version}`);\n }\n}\n\nfunction validateImageTag(tag: string): void {\n if (\n !tag ||\n tag.startsWith(\"-\") ||\n tag.includes(\"@\") ||\n /\\s/.test(tag) ||\n hasControlCharacter(tag)\n ) {\n throw new Error(`Invalid Docker image tag: ${tag}`);\n }\n}\n\nfunction unique(values: readonly string[]): string[] {\n return [...new Set(values)];\n}\n\nfunction hasControlCharacter(value: string): boolean {\n return [...value].some((character) => character.charCodeAt(0) < 32);\n}\n\nfunction shellQuote(value: string): string {\n return `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n"],"mappings":"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","names":["commonAptPackages"]}
package/dist/index.js CHANGED
@@ -24,9 +24,13 @@ function normalizeSandboxPath(input, options = {}) {
24
24
  if (input.includes("\0")) {
25
25
  throw new DockerSandboxError("Sandbox path cannot contain null bytes.", "invalid_path");
26
26
  }
27
- const normalized = path.posix.normalize(input.replaceAll("\\", "/"));
27
+ let normalized = path.posix.normalize(input.replaceAll("\\", "/"));
28
28
  if (path.posix.isAbsolute(normalized)) {
29
- throw new DockerSandboxError(`Sandbox path must be relative: ${input}`, "invalid_path");
29
+ const workdir = options.workdir;
30
+ if (workdir === void 0 || !path.posix.isAbsolute(workdir)) {
31
+ throw new DockerSandboxError(`Sandbox path must be relative: ${input}`, "invalid_path");
32
+ }
33
+ normalized = path.posix.relative(path.posix.normalize(workdir), normalized) || ".";
30
34
  }
31
35
  if (normalized === ".." || normalized.startsWith("../")) {
32
36
  throw new DockerSandboxError(
@@ -1205,15 +1209,19 @@ var DockerSandboxRuntimeImpl = class {
1205
1209
  "1",
1206
1210
  "-maxdepth",
1207
1211
  "1",
1208
- "-printf",
1209
- "%p %y %s\n"
1212
+ "-exec",
1213
+ "stat",
1214
+ "-c",
1215
+ "%n %f %s",
1216
+ "{}",
1217
+ "+"
1210
1218
  ]
1211
1219
  },
1212
1220
  abortSignal
1213
1221
  );
1214
1222
  if (result.status !== "exited" || result.exitCode !== 0) {
1215
1223
  throw new DockerSandboxError(
1216
- "Unable to list sandbox files.",
1224
+ dockerExecFailureMessage("Unable to list sandbox files", result),
1217
1225
  "docker_command_failed",
1218
1226
  result
1219
1227
  );
@@ -1816,8 +1824,11 @@ async function assertCopiedRegularFile(temporaryDirectory, target, sandboxPath)
1816
1824
  "invalid_path"
1817
1825
  );
1818
1826
  }
1819
- const resolvedTarget = await realpath(target);
1820
- const relativeTarget = path2.relative(temporaryDirectory, resolvedTarget);
1827
+ const [resolvedDirectory, resolvedTarget] = await Promise.all([
1828
+ realpath(temporaryDirectory),
1829
+ realpath(target)
1830
+ ]);
1831
+ const relativeTarget = path2.relative(resolvedDirectory, resolvedTarget);
1821
1832
  if (relativeTarget === "" || relativeTarget === ".." || relativeTarget.startsWith(`..${path2.sep}`) || path2.isAbsolute(relativeTarget)) {
1822
1833
  throw new DockerSandboxError(
1823
1834
  `Sandbox file escaped its temporary read boundary: ${sandboxPath}`,
@@ -1840,13 +1851,14 @@ async function removeVolume(dockerPath, volumeName) {
1840
1851
  );
1841
1852
  }
1842
1853
  function parseFindEntry(line, workdir) {
1843
- const [absolutePath, rawType, rawSize] = line.split(" ");
1844
- if (absolutePath === void 0 || rawType === void 0 || rawSize === void 0) {
1854
+ const [absolutePath, rawMode, rawSize] = line.split(" ");
1855
+ const mode = rawMode === void 0 ? Number.NaN : Number.parseInt(rawMode, 16);
1856
+ if (absolutePath === void 0 || rawSize === void 0 || !Number.isSafeInteger(mode)) {
1845
1857
  throw new DockerSandboxError("Docker returned invalid file metadata.", "docker_command_failed");
1846
1858
  }
1847
1859
  const relativePath = path2.posix.relative(workdir, absolutePath);
1848
1860
  const size = Number(rawSize);
1849
- const type = mapFindType(rawType);
1861
+ const type = mapFileMode(mode);
1850
1862
  let entry = {
1851
1863
  path: normalizeSandboxPath(relativePath),
1852
1864
  type
@@ -1856,12 +1868,21 @@ function parseFindEntry(line, workdir) {
1856
1868
  }
1857
1869
  return entry;
1858
1870
  }
1859
- function mapFindType(value) {
1860
- if (value === "f") return "file";
1861
- if (value === "d") return "directory";
1862
- if (value === "l") return "symlink";
1871
+ function mapFileMode(mode) {
1872
+ const type = mode & 61440;
1873
+ if (type === 32768) return "file";
1874
+ if (type === 16384) return "directory";
1875
+ if (type === 40960) return "symlink";
1863
1876
  return "other";
1864
1877
  }
1878
+ function dockerExecFailureMessage(prefix, result) {
1879
+ const detail = (safeDecode(result.stderr).trim() || safeDecode(result.stdout).trim()).slice(
1880
+ 0,
1881
+ 500
1882
+ );
1883
+ if (detail.length > 0) return `${prefix}: ${detail}`;
1884
+ return result.status === "exited" ? `${prefix}: command exited with code ${result.exitCode}.` : `${prefix}: command timed out.`;
1885
+ }
1865
1886
  function toExecResult(result) {
1866
1887
  const common = {
1867
1888
  stdout: result.stdout.slice(),
@@ -2014,9 +2035,11 @@ var allToolNames = [
2014
2035
  "wait_for_port"
2015
2036
  ];
2016
2037
  var execCommandInput = z.object({
2017
- command: z.string().min(1),
2018
- args: z.array(z.string()).optional(),
2019
- cwd: z.string().optional(),
2038
+ command: z.string().min(1).describe(
2039
+ "Command to run. Complete shell command lines are supported; use args for exact argv execution."
2040
+ ),
2041
+ args: z.array(z.string()).describe("Optional exact arguments. Omit when command contains the complete command line.").optional(),
2042
+ cwd: z.string().describe("Workspace-relative directory or an absolute directory inside the sandbox workdir.").optional(),
2020
2043
  env: z.record(z.string(), z.string()).optional(),
2021
2044
  timeoutMs: z.number().int().positive().max(3e5).optional(),
2022
2045
  input: z.string().optional()
@@ -2041,7 +2064,7 @@ var execResultOutput = z.discriminatedUnion("status", [
2041
2064
  })
2042
2065
  ]);
2043
2066
  var readFileInput = z.object({
2044
- path: z.string().min(1),
2067
+ path: z.string().min(1).describe("Workspace-relative path or an absolute path inside the sandbox workdir."),
2045
2068
  startLine: z.number().int().positive().optional(),
2046
2069
  lineCount: z.number().int().positive().max(1e4).optional()
2047
2070
  });
@@ -2054,14 +2077,16 @@ var readFileOutput = z.object({
2054
2077
  truncatedBy: z.enum(["lines", "bytes"]).nullable()
2055
2078
  });
2056
2079
  var writeFileInput = z.object({
2057
- path: z.string().min(1),
2080
+ path: z.string().min(1).describe("Workspace-relative path or an absolute path inside the sandbox workdir."),
2058
2081
  content: z.string()
2059
2082
  });
2060
2083
  var writeFileOutput = z.object({
2061
2084
  path: z.string(),
2062
2085
  bytesWritten: z.number().int().nonnegative()
2063
2086
  });
2064
- var listFilesInput = z.object({ path: z.string().optional() });
2087
+ var listFilesInput = z.object({
2088
+ path: z.string().describe("Workspace-relative directory or an absolute directory inside the sandbox workdir.").optional()
2089
+ });
2065
2090
  var fileEntryOutput = z.object({
2066
2091
  path: z.string(),
2067
2092
  type: z.enum(["file", "directory", "symlink", "other"]),
@@ -2082,7 +2107,7 @@ var listPortsOutput = z.object({ ports: z.array(publishedPortOutput) });
2082
2107
  var startProcessInput = z.object({
2083
2108
  command: z.string().min(1),
2084
2109
  args: z.array(z.string()).optional(),
2085
- cwd: z.string().optional(),
2110
+ cwd: z.string().describe("Workspace-relative directory or an absolute directory inside the sandbox workdir.").optional(),
2086
2111
  env: z.record(z.string(), z.string()).optional()
2087
2112
  });
2088
2113
  var processInfoOutput = z.object({
@@ -2143,18 +2168,20 @@ function createDockerSandboxTools(options) {
2143
2168
  function createExecCommandTool(options) {
2144
2169
  return createTool({
2145
2170
  name: "exec_command",
2146
- description: "Run one executable inside the sandbox with structured arguments.",
2171
+ description: "Run a command inside the sandbox, including natural shell command lines.",
2147
2172
  inputSchema: execCommandInput,
2148
2173
  outputSchema: execResultOutput,
2149
2174
  execute: async ({ command, args, cwd, env, timeoutMs, input }, context) => {
2150
- assertCommandAllowed(command, options.exec?.commands);
2175
+ const invocation = resolveExecInvocation(command, args, options.exec?.commands);
2151
2176
  const effectiveTimeoutMs = timeoutMs ?? options.exec?.defaultTimeoutMs;
2152
2177
  assertTimeoutAllowed(effectiveTimeoutMs, options.exec?.maxTimeoutMs);
2153
2178
  let execOptions = {
2154
- command
2179
+ command: invocation.command
2155
2180
  };
2156
- if (args !== void 0) execOptions = { ...execOptions, args };
2157
- if (cwd !== void 0) execOptions = { ...execOptions, cwd };
2181
+ if (invocation.args !== void 0) execOptions = { ...execOptions, args: invocation.args };
2182
+ if (cwd !== void 0) {
2183
+ execOptions = { ...execOptions, cwd: normalizeToolPath(options.sandbox, cwd, true) };
2184
+ }
2158
2185
  if (env !== void 0) execOptions = { ...execOptions, env };
2159
2186
  if (effectiveTimeoutMs !== void 0) {
2160
2187
  execOptions = { ...execOptions, timeoutMs: effectiveTimeoutMs };
@@ -2182,7 +2209,7 @@ function createReadFileTool(options) {
2182
2209
  );
2183
2210
  }
2184
2211
  let readOptions = {
2185
- path: path3,
2212
+ path: normalizeToolPath(options.sandbox, path3),
2186
2213
  startLine: startLine ?? 1,
2187
2214
  lineCount: effectiveLineCount,
2188
2215
  maxBytes: limits.maxBytes
@@ -2206,15 +2233,16 @@ function createWriteFileTool(options) {
2206
2233
  if (maxBytes !== void 0 && bytesWritten > maxBytes) {
2207
2234
  throw toolPolicyError(`File content exceeds policy (${bytesWritten} > ${maxBytes}).`);
2208
2235
  }
2236
+ const normalizedPath = normalizeToolPath(options.sandbox, path3);
2209
2237
  let writeOptions = {
2210
- path: path3,
2238
+ path: normalizedPath,
2211
2239
  text: content
2212
2240
  };
2213
2241
  if (context.abortSignal !== void 0) {
2214
2242
  writeOptions = { ...writeOptions, abortSignal: context.abortSignal };
2215
2243
  }
2216
2244
  await options.sandbox.writeTextFile(writeOptions);
2217
- return { path: path3, bytesWritten };
2245
+ return { path: normalizedPath, bytesWritten };
2218
2246
  }
2219
2247
  });
2220
2248
  }
@@ -2225,12 +2253,13 @@ function createListFilesTool(sandbox) {
2225
2253
  inputSchema: listFilesInput,
2226
2254
  outputSchema: listFilesOutput,
2227
2255
  execute: async ({ path: path3 }, context) => {
2256
+ const normalizedPath = path3 === void 0 ? "." : normalizeToolPath(sandbox, path3, true);
2228
2257
  let listOptions = {};
2229
- if (path3 !== void 0) listOptions = { ...listOptions, path: path3 };
2258
+ if (path3 !== void 0) listOptions = { ...listOptions, path: normalizedPath };
2230
2259
  if (context.abortSignal !== void 0) {
2231
2260
  listOptions = { ...listOptions, abortSignal: context.abortSignal };
2232
2261
  }
2233
- return { path: path3 ?? ".", entries: [...await sandbox.listFiles(listOptions)] };
2262
+ return { path: normalizedPath, entries: [...await sandbox.listFiles(listOptions)] };
2234
2263
  }
2235
2264
  });
2236
2265
  }
@@ -2253,7 +2282,9 @@ function createStartProcessTool(options) {
2253
2282
  assertCommandAllowed(command, options.exec?.commands);
2254
2283
  let startOptions = { command };
2255
2284
  if (args !== void 0) startOptions = { ...startOptions, args };
2256
- if (cwd !== void 0) startOptions = { ...startOptions, cwd };
2285
+ if (cwd !== void 0) {
2286
+ startOptions = { ...startOptions, cwd: normalizeToolPath(options.sandbox, cwd, true) };
2287
+ }
2257
2288
  if (env !== void 0) startOptions = { ...startOptions, env };
2258
2289
  if (context.abortSignal !== void 0) {
2259
2290
  startOptions = { ...startOptions, abortSignal: context.abortSignal };
@@ -2376,6 +2407,9 @@ function serializeProcessInfo(process) {
2376
2407
  if (process.endedAt !== void 0) serialized = { ...serialized, endedAt: process.endedAt };
2377
2408
  return serialized;
2378
2409
  }
2410
+ function normalizeToolPath(sandbox, input, allowRoot = false) {
2411
+ return normalizeSandboxPath(input, { allowRoot, workdir: sandbox.workdir });
2412
+ }
2379
2413
  function validateFactoryOptions(options) {
2380
2414
  if (!isRecord2(options)) {
2381
2415
  throw new TypeError("options must be an object.");
@@ -2504,6 +2538,22 @@ function assertCommandAllowed(command, policy) {
2504
2538
  }
2505
2539
  }
2506
2540
  }
2541
+ function resolveExecInvocation(command, args, policy) {
2542
+ if (args === void 0 && requiresShell(command)) {
2543
+ if (policy?.mode === "block") {
2544
+ throw toolPolicyError(
2545
+ "Natural command lines cannot be used with block-mode command policies. Use command and args instead."
2546
+ );
2547
+ }
2548
+ assertCommandAllowed("sh", policy);
2549
+ return { command: "sh", args: ["-c", command] };
2550
+ }
2551
+ assertCommandAllowed(command, policy);
2552
+ return args === void 0 ? { command } : { command, args };
2553
+ }
2554
+ function requiresShell(command) {
2555
+ return /[\s|&;<>()$`'"*?[\]{}!#~=]/u.test(command);
2556
+ }
2507
2557
  function assertTimeoutAllowed(timeoutMs, maxTimeoutMs) {
2508
2558
  if (timeoutMs !== void 0 && maxTimeoutMs !== void 0 && timeoutMs > maxTimeoutMs) {
2509
2559
  throw toolPolicyError(`Command timeout exceeds policy (${timeoutMs} > ${maxTimeoutMs}).`);